調用通義千問大模型 Function Calling 實現實時天氣查詢

OpenAI 在它的多個版本的模型裏提供了一個非常有用的功能叫 Function Calling,就是你傳遞一些方法的信息給到大模型,大模型根據用戶的提問選擇合適的方法 Function,然後輸出給你,你再來決定是否執行。

之所以需要 Function Calling,通俗來講就是大模型不具備實時性。因爲模型是基於之前的數據訓練出來的。而 Function Calling 具備實時性的優勢,比如調用第三方 API、或者 Database 來獲取實時數據。這樣結合 2 者的優勢就能給到用戶最正確最合理的反饋結果。

Function Calling 流程

實現 Function Calling 需要以下幾步:

  1. 預定義需要調用的 Function 函數

  2. 將定義好的 Function 以及需要的 Parameter 傳入大模型

  3. 解析大模型返回結果,調用相應的 Function 獲取實時結果

  4. 將 Function 返回的結果重新傳給大模型,返回統一的 NLG 結果

具體的流程如下圖所示:

接下來我們用查詢實時天氣爲例,將這 4 步依次完成。

  1. 定義獲取實時天氣 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 字段中的 texttemperature 值,具體實現代碼如下:

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。

  1. 將 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,並且正確提取出參數是 青島市

  1. 解析大模型結果調用 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 重新返回給大模型,並返回最終結果。

  1. 大模型返回最終 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