本文是增強型語言模型(LLM)的實作系列文章的第一篇,主要介紹如何讓語言模型透過函式呼叫(Function Calling)使用外部工具,進而完成使用者的目標。
什麼是函式呼叫?
根據 Open AI 官方技術文件的定義,函式呼叫是讓語言模型可以擷取資料和採取行動去完成使用者的請求。函式呼叫可以分為兩個部分:
- 擷取資料:搜尋特定的知識庫或獲得即時資料(例如:天氣數據)。
- 採取行動:呼叫外部 API 或操作外部應用程式。
函式呼叫流程
使用 Open AI 提供的 Python 函式庫 openai 時,開發者可以透過加入 tools
參數,讓語言模型知道有新的工具可以使用,以便更有效地解決使用者的需求。以下是 LLM 呼叫函式的流程:
- 定義函式並發出請求:開發者設定一組函式,並要求模型執行特定的任務。
- 選擇函式:模型回傳訊息,內含選擇的函式名稱和對應的參數。
- 執行函式:開發者執行模型所選擇的函式呼叫。
- 返回結果:開發者將函式執行的結果回傳給模型。
- 描述結果:模型使用自然語言來解釋函式執行的結果,提供給使用者一個易於理解的答案或解釋。
範例:查詢加密貨幣價格
現在,我們將實現讓語言模型可以查詢即時的加密貨幣價格,讓使用者可以與模型討論各種加密貨幣的價格波動,甚至是投資的意見。請注意,模型的回應不應作為真實的財務建議。
為了實現這個功能,我們將使用託管在 Groq 的 Llama 3.3 70B 模型。在運行程式碼之前,請先在 Groq 申請免費的 API 金鑰,並在 Google Colab 中定義 API_KEY
環境參數。完整的程式碼可以在這裡查看。
import json
import requests
from google.colab import userdata
from openai import OpenAI
client = OpenAI(
base_url="https://api.groq.com/openai/v1",
api_key=userdata.get("API_KEY"),
)
為了獲得語言模型處理使用者需求的結果,我們需要實作一個名為 get_completion
的函式。這個函式將負責向模型提交使用者的需求,並接收模型的回應,而獲得最終的結果。
def get_completion(messages, model="llama-3.3-70b-specdec", max_tokens=300, tools=None, tool_choice="auto"):
response = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
tools=tools,
tool_choice=tool_choice
)
return response.choices[0].message
定義函式並發送請求
為了讓語言模型可以查詢加密貨幣的即時價格,我們需要實作一個名為 get_crypto_price
的函式。這個函式將使用 CoinCap API 來獲得加密貨幣的最新價格。
首先,我們需要在 tools
變數中宣告 get_crypto_price
函式,讓 LLM 知道這個函式的功能和如何使用它,包括需要傳入的參數。接著,我們需要在 messages
中寫入對 LLM 的請求,例如:“What is the current price of bitcoin?”,以便模型知道我們想要查詢比特幣的當前價格。
def get_crypto_price(symbol):
url = f"https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest?symbol={symbol}"
try:
headers = {"X-CMC_PRO_API_KEY": userdata.get("CMC_PRO_API_KEY")}
response = requests.get(url, headers=headers)
data = response.json()
price = data["data"][symbol][0]["quote"]["USD"]["price"]
return price if price is not None else -1
except Exception as e:
print(f"An unexpected error occurred: {e}")
return -1
tools = [{
"type": "function",
"function": {
"name": "get_crypto_price",
"description": "Get the current price of the given crypto symbol in USD",
"parameters": {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "The symbol of a particular cryptocurrency, e.g. BTC",
},
},
},
},
}]
messages = [{
"role": "user",
"content": "What is the current price of bitcoin?"
}]
completion = get_completion(messages=messages, tools=tools)
選擇函式
查看 completion.tool_calls
物件的內容,可以獲得模型回傳的函式呼叫結果,內容如下:
[{
"id": "call_123xyz",
"type": "function",
"function": {
"name": "get_crypto_price",
"arguments": "{\"symbol\": \"BTC\"}"
}
}]
執行函式
接下來,我們需要將 arguments
字串轉換成 JSON 物件,並使用它來執行 get_crypto_price
函式,以獲得比特幣(bitcoin)的即時價格。值得注意的是,語言模型會自動將請求訊息中的 bitcoin
轉換成 get_crypto_price
函式可以處理的 BTC
代號,這是一個非常方便的功能。這樣一來,我們就可以使用這個轉換後的代號來查詢比特幣的價格。
例如,若要查詢比特幣的價格,LLM 會將 bitcoin
轉換成 BTC
,然後使用 get_crypto_price
函式來查詢其價格。結果,result
的值為 95549.09
,代表比特幣的即時價格為 95,549.09 美元。
tool_call = completion.tool_calls[0]
args = json.loads(tool_call.function.arguments)
result = get_crypto_price(args["symbol"])
返回結果
將工具選擇的訊息和函式執行的結果加入 messages
物件中,讓語言模型可以使用自然語言來總結最後的回應。這個步驟使得模型可以根據執行結果生成一個清晰、易於理解的回應,提供給使用者最終的答案。
messages.append(completion)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": str(result)
})
completion_2 = get_completion(messages=messages, tools=tools)
描述結果
檢視 completion_2.content
物件的內容,會顯示出類似的訊息:
The current price of Bitcoin is $95,549.09 USD.
總結
- LLM 的函式呼叫功能允許開發者定義自訂函式,以便語言模型可以截取資料和採取行動。
- 透過在
tools
參數中定義開發者自訂的函式,LLM 可以了解如何使用這些函式。 - 將函式執行結果傳回給 LLM,然後它可以使用自然語言來描述結果,提供給使用者一個清晰易懂的答案或解釋。