大模型 Function Call介紹

什么是Function Call

????????簡單來說,就是大模型函數調用,不是你直接調用大模型函數,而是你告訴大模型一個函數,大模型根據你喂給它的數據和參數執行函數調用返回給你想要的函數執行結果。
????????你可以借助大模型的自然語言理解能力實現自然語言的函數調用。大模型這一能力大大增加了私有定制模型的擴展性!

為什么有Function Call

  1. 大模型的缺陷:
  • 有所不知
    a.訓練數據不可能什么都有;垂直、非公開數據必有欠缺。
    b.不知道最新信息;大模型的訓練周期很長,且更新一次耗資巨大,還有越訓越傻的風險。所以它不可能實時訓練。
  • 沒有"真邏輯"
    它表現出的邏輯、推理,是訓練文本的統計規律,而不是真正的邏輯,所以有幻覺。
  1. 大模型的優勢:
  • 強大的語義泛化能力,能根據所說的話,識別出意圖
  • 希望通過大模型來做更多的事,而不僅是簡單的搜索和閑聊

因為:大模型需要連接真實世界,并對接真邏輯系統。
Function Call 技術可以把大模型和業務系統連接,實現更豐富的功能

Function call工作流程

  • 用戶提出functions需求: 用戶用自然語言描述他們想要完成的任務。
  • LLM理解意圖: 大模型分析用戶的語言,理解其意圖,并將其轉化為結構化的請求。
  • 選擇合適的function: 根據用戶的需求,從預先定義好的functions中選擇合適的function。
  • 參數轉換與執行: 將用戶的需求轉化為function能夠理解的參數,并調用外部工具執行操作。
  • 結果處理與呈現: 接收外部工具返回的結果, 由LLM將其轉化為用戶友好的自然語言回應。
Function call.png

對大模型的要求

  • 好的語義理解能力,能夠正確識別是否調用function、調用哪個function 以及對應參數;
  • 對于缺失的參數要能主動提問;

langchain實現

????????當今大部分模型廠商都有支持function call的模型,需要選擇對應的正確模型,定義好模型廠商對應的functions書寫規范,function描述的必備要素:

  • 函數名
  • 函數的功能描述
  • 函數的請求參數說明
  • 函數的響應參數說明(可選)

實例如下:

1. 定義functions

functions = [
    {
        "type":"function",
        "function":{
            "name": "get_current_speed",
            "description": "Gets current speed of a given car",
            "parameters": {
                "type": "object",
                "properties": {
                    "car_name": {
                        "type": "string",
                        "description": "The name of the car"
                    }
                },
                "required": ["car_name"]
            }
        }
       
    },
    {
        "type":"function",
        "function":{
            "name": "get_interior_temperature",
            "description": "Gets the interior temperature of a given car",
            "parameters": {
                "type": "object",
                "properties": {
                    "car_name": {
                        "type": "string",
                        "description": "The name of the car"
                    }
                },
                "required": ["car_name"]
            }
        } 
    },
    {
        "type":"function",
       "function":{
            "name": "get_remaining_battery",
            "description": "Gets the remaining battery of a given car",
            "parameters": {
                "type": "object",
                "properties": {
                    "car_name": {
                        "type": "string",
                        "description": "The name of the car"
                    }
                },
                "required": ["car_name"]
            }
       }
    }
]

2. 創建llm client

import os
import openai
import numpy as np
import json
import tenacity
from openai import OpenAI

client = OpenAI(
    api_key='sk-xxxxxxxxxxxx',
    base_url='https://api.chatanywhere.tech/v1'
)

GPT_MODEL = "gpt-3.5-turbo"

3. 定義Api調用接口

def generate_response_with_function_call(messages):
    try:
        response = client.chat.completions.create(
            model= GPT_MODEL,
            messages= messages,
            max_tokens=100,  # 生成的最大token數
            temperature=0.7,  # 生成的隨機性
            tools=functions,  # 定義的函數調用規范
            tool_choice="auto",
        )
        return response.choices[0].message
           
    except Exception as e:
        print(f"Error generating response: {str(e)}")
        return None

4. 調用函數及結果處理

  • 封裝messages
messages= [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Car A 當前速度是多少"}
]
  • 定義本地function
def get_current_speed(car_name):
   //調用其他接口來獲取speed

def get_interior_temperature(car_name):
     //調用其他接口來獲取interior temperature

def get_remaining_battery(car_name): 
    //調用其他接口來獲取remaining battery
  • 執行Api調用及結果處理
first_response_message = generate_response_with_function_call(messages)

????????第一次請求大模型接口后,會從定義的functions里面輸出對應的function信息:

//獲取function name
response_function_name = first_response_message.tool_calls[0].function.name

//獲取function arguments
response_function_argu = json.loads(first_response_message.tool_calls[0].function.arguments)

????????根據function name及arguments選擇調用對應的本地function來獲取到當前結果:

# 定義一個函數來基于大模型的調用結果,來執行函數
def call_function(function_name, arguments):
        if function_name == "get_interior_temperature":
            car_name = arguments.get("car_name")
            return get_interior_temperature(car_name)
        elif function_name == "get_current_speed":
            car_name = arguments.get("car_name")
            return get_current_speed(car_name)
        elif function_name == "get_remaining_battery":
            car_name = arguments.get("car_name")
            return get_remaining_battery(car_name)
        return "Function not found"

# 執行本地函數
function_response = call_function(response_function_name, response_function_argu)

????????將獲得的函數執行結果補充進messages,再次調用API:

messages.append(first_response_message)
messages.append({
    "role":"tool",
    "content":function_response,
    "tool_call_id":response_message.tool_calls[0].id,
})

second_response = generate_response_with_function_call(messages)

# 讀取二次調用得到的content
final_message = second_response.content
print("最終輸出: " + str(final_message))

最終輸出: Car A當前車速為70.0km/h

????????經過兩次大模型的API調用,得到了合理的結果;

  • 第一次大模型調用:根據用戶的query及定義的functions,得到對應的function name及arguments
  • 第二次大模型調用:結合外部請求結果,大模型進行總結給出合理的回答
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容