調用通義千問大模型 Function Calling 實現實時天氣查詢
OpenAI 在它的多個版本的模型裏提供了一個非常有用的功能叫 Function Calling,就是你傳遞一些方法的信息給到大模型,大模型根據用戶的提問選擇合適的方法 Function,然後輸出給你,你再來決定是否執行。
之所以需要 Function Calling,通俗來講就是大模型不具備實時性。因爲模型是基於之前的數據訓練出來的。而 Function Calling 具備實時性的優勢,比如調用第三方 API、或者 Database 來獲取實時數據。這樣結合 2 者的優勢就能給到用戶最正確最合理的反饋結果。
Function Calling 流程
實現 Function Calling 需要以下幾步:
-
預定義需要調用的 Function 函數
-
將定義好的 Function 以及需要的 Parameter 傳入大模型
-
解析大模型返回結果,調用相應的 Function 獲取實時結果
-
將 Function 返回的結果重新傳給大模型,返回統一的 NLG 結果
具體的流程如下圖所示:
接下來我們用查詢實時天氣爲例,將這 4 步依次完成。
- 定義獲取實時天氣 Function
首先需要查詢實時天氣的接口 API,我使用的是免費的 心知天氣 API ,返回的 JSON 合適如下:
{
'results': [
{
'location': {
'id': 'WTW3SJ5ZBJUY',
'name': '上海',
'country': 'CN',
'path': '上海,上海,中國',
'timezone': 'Asia/Shanghai',
'timezone_offset': '+08:00'
},
'now': {
'text': '多雲',
'code': '4',
'temperature': '22'
}
}
]
}
可以看出需要解析出 now 字段中的 text 和 temperature 值,具體實現代碼如下:
import json
import requests
def get_current_weather(location):
url = "https://api.seniverse.com/v3/weather/now.json?key=你的心知天氣API Key&location=" + location + "&language=zh-Hans&unit=c"
response = requests.get(url)
if response.status_code == 200:
data = response.json()
weather = data['results'][0]['now']['text']
temp = data['results'][0]['now']['temperature']
return json.dumps({"location": location, "weather": weather, "temperature": temp})
else:
return json.dumps({"location": location, "error": "獲取實時天氣數據失敗!"})
上述代碼中的 key 需要使用你自己申請的 API Key。
- 將 Function 傳入大模型
2.1 聲明大模型 function list
功能函數 Function 定義好之後,就需要通過 function list 將其傳給大模型。function list 的具體格式根據你所選擇的大模型的不同,可能會有所差異。具體需要按照各自大模型的官方文檔來集成。這篇文章我使用的是通義千問大模型,格式如下:
functions = [
# 獲取指定城市的天氣
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "當你想查詢指定城市的天氣時非常有用。",
"parameters": { # 查詢天氣時需要提供位置,因此參數設置爲location
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市或縣區,比如北京市、杭州市、餘杭區等。"
}
}
},
"required": [
"location"
]
}
}
]
上述代碼中我們定義了一個 functions 數組,在這個數組中有一個結構體 type 類型爲 function。然後在這個 function 中有 2 項內容很重要:name 和 description。
name 代表函數 Function 的名字;description 是告訴大模型什麼時候需要返回需要調用當前 function 的結果。
另外,因爲我們定義的 get_current_weather 函數需要傳入參數 location,所以在上述代碼中我們還需要聲明一下 parameters。這樣大模型就可以根據上下文返回給調用方合理的參數。
2.2 聲明大模型接口調用的函數
然後調用相應大模型的接口,傳入上述格式代碼。根據通義千問官方文檔具體傳入方式如下:
import dashscope
from dashscope import Generation
import json
import requests
# 調用通義千問接口
def query_from_qwen(messages):
response = Generation.call(
api_key="你的通義千問API Key",
model='qwen-plus',
messages=messages,
tools=functions,
seed=random.randint(1, 10000), # 設置隨機數種子seed,如果沒有設置,則隨機數種子默認爲1234
result_format='message' # 將輸出設置爲message形式
)
return response
2.3 構建 messages 執行 query_from_qwen
代碼如下:
# 模擬用戶輸入:青島天氣
messages = [
{"content": "青島天氣", "role": "user"}
]
# 執行query_from_qwen,打印結果
llm_response = query_from_qwen(messages)
print(llm_response)
大模型返回結果
上圖中可以看出,大模型返回了 tool_calls
字段。說明針對用戶輸入 "青島天氣",已經正確理解出需要調用 get_current_weather
function,並且正確提取出參數是 青島市
。
- 解析大模型結果調用 Function
接下來就是解析上圖中的 tool_calls
信息,並手動調用 get_current_weather
函數。
def parse_llm_response(llm_response):
assistant_output = llm_response.output.choices[0].message
if 'tool_calls' not in assistant_output: # 如果模型判斷無需調用工具,則將assistant的回覆直接打印出來,無需進行模型的第二輪調用
print(f"最終答案:{assistant_output.content}")
return
# 如果模型選擇的工具是get_current_weather
elif assistant_output.tool_calls[0]['function']['name'] == 'get_current_weather':
tool_info = {"name": "get_current_weather", "role": "tool"}
location = json.loads(assistant_output.tool_calls[0]['function']['arguments'])['location']
tool_info['content'] = get_current_weather(location)
return tool_info
將 get_current_weather
函數返回的數據包裝到 tool_info 中,tool_info 結果如下:
{
"name": "get_current_weather",
"role": "tool",
"content": {
"location": "青島",
"weather": "多雲",
"temperature": "12"
}
最後一步就是將此 tool_info 重新返回給大模型,並返回最終結果。
- 大模型返回最終 NLG 結果
將第 3 步返回的 tool_info 信息重新添加到 messages
中,並重新調用 query_from_qwen
messages.append(tool_info)
llm_final_response = query_from_qwen(messages)
print(f"\n大模型最終輸出信息:{llm_final_response}\n")
最終打印結果如下:
最終大模型根據上下文理解以及傳入的天氣信息,返回了最合適的 NLG 結果。只需要將 output 中的 content 值解析出來並反饋給用戶即可。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Cz1hEaxk32AUg89UukectQ