天天看點

ChatGPT重大更新,大殺器函數調用怎麼玩

作者:AIGC研究社
ChatGPT重大更新,大殺器函數調用怎麼玩

前不久 ChatGPT進行了一波重大更新,其中一個殺手級特性就是引入了函數調用功能。

開發者隻需要描述函數功能,函數參數和傳回值,ChatGPT就會根據需要發起調用請求。

目前 gpt-3.5-turbo-0613 和 gpt-4-0613 這兩個模型都支援函數調用,也就是普通使用者也能使用。

我們來仔細看看這個功能是如何使用,能帶來什麼變革?

其工作流程如下:

  1. 程式中實作一系列提供給ChatGPT的函數;
  2. 将這些函數放到一個json數組中,并且描述清楚每個函數的名字、功能、參數、傳回參數等;
  3. 向ChatGPT發起提問,同時将上述函數數組,提供給ChatGPT;
  4. ChatGPT根據問題情況,來決定是否要調用函數。如果需要,則将相應的函數和調用參數傳回給使用者程式;
  5. 使用者程式根據調用請求,執行相應的函數;
  6. 使用者将函數傳回值,添加到消息中,再次調用ChatGPT;
  7. ChatGPT根據這個傳回值,再重新歸納為自然語言,傳回給使用者。

上述過程,其中 3..6 是可以循環的,也就是說,完成一個響應,可能需要多輪的函數調用。

ChatGPT重大更新,大殺器函數調用怎麼玩

以下通過執行個體講解:

import openai
import json

openai.api_key = "sk-[your key]"

# 先實作一個功能函數,此處為虛假函數,固定傳回一個天氣狀況
# 在實際産品中,此處可以使用使用連網功能,調用網絡函數,或者操作具體的硬體裝置
def get_current_weather(location, unit="fahrenheit"):
    """輸入一個地區,傳回當地的天氣"""
    weather_info = {
        "location": location,
        "temperature": "72",
        "unit": unit,
        "forecast": ["sunny", "windy"],
    }
    return json.dumps(weather_info)


def run_conversation():
    # Step 1: 調用chatGPT進行一次對話,并傳入函數描述
    
    # 具體的使用者問題
    messages = [{"role": "user", "content": "What's the weather like in Boston?"}]
    
    # 定義一系列可供chatGPT使用的函數
    functions = [
        {
        
            "name": "get_current_weather", # 函數名
            "description": "Get the current weather in a given location", # 函數描述,chatGPT根據描述判斷,是否要使用此函數幫忙解決問題
            "parameters": { # 調用參數描述
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, e.g. San Francisco, CA",
                    },
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                },
                "required": ["location"],
            },
        }
    ]
    
    # 向chatGPT發起請求
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo-0613", # 使用新的模型
        messages=messages,
        functions=functions,   # 函數清單
        function_call="auto",  # auto is default, but we'll be explicit
    )
    print("first call:")
    print(response)
    
    response_message = response["choices"][0]["message"]
    
    # Step 2: 從傳回的消息中finish_reason的值來判斷,
    #   chatGPT的應答是函數調用請求(function_call),或者是最終結果(stop)
    if response_message.get("function_call"):
        # Step 3: 如果是函數請求,則根據請求參考,調用相應的函數
        # "function_call": {
        #   "name": "get_current_weather",
        #   "arguments": "{\n  \"location\": \"Boston, MA\"\n}"
        # }
        available_functions = {
            "get_current_weather": get_current_weather,
        }  # only one function in this example, but you can have multiple
        
        function_name = response_message["function_call"]["name"]
        fuction_to_call = available_functions[function_name]
        function_args = json.loads(response_message["function_call"]["arguments"])
        
        # 調用本地 get_current_weather 函數
        function_response = fuction_to_call(
            location=function_args.get("location"),
            unit=function_args.get("unit"),
        )

        # Step 4: 将本地函數的傳回值,合并到消息裡,然後再一次調用chatGPT
        messages.append(response_message)  # extend conversation with assistant's reply
        messages.append(
            {
                "role": "function",
                "name": function_name,
                "content": function_response,
            }
        )  # extend conversation with function response
        second_response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-0613",
            messages=messages,
        )  # get a new response from GPT where it can see the function response
        
        # 傳回問題的最終結果
        return second_response

print(run_conversation())           

第一次調用 openai.ChatCompletion.create 傳回的結果:

ChatGPT重大更新,大殺器函數調用怎麼玩

第二次調用 openai.ChatCompletion.create 傳回的結果:

ChatGPT重大更新,大殺器函數調用怎麼玩

在第一次響應資料可以看到,傳回的 finish_reson 值為 function_call,表明這并不是最終結果,而是一個函數調用的請求。這時使用者程式需要主動調用相應的函數。

第二次傳回時, finish_reason 為 stop,表示傳回的是最終結果。

再來看一個例子,讓ChatGPT通過SQL語句,查詢使用者音樂資料:

functions = [
    {
        "name": "ask_database",
        "description": "Use this function to answer user questions about music. Output should be a fully formed SQL query.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": f"""
                            SQL query extracting info to answer the user's question.
                            SQL should be written using this database schema:
                            {database_schema_string}
                            The query should be returned in plain text, not in JSON.
                            """,
                }
            },
            "required": ["query"],
        },
    }
]

def ask_database(conn, query):
    """Function to query SQLite database with a provided SQL query."""
    try:
        results = str(conn.execute(query).fetchall())
    except Exception as e:
        results = f"query failed with error: {e}"
    return results

def execute_function_call(message):
    if message["function_call"]["name"] == "ask_database":
        query = json.loads(message["function_call"]["arguments"])["query"]
        results = ask_database(conn, query)
    else:
        results = f"Error: function {message['function_call']['name']} does not exist"
    return results           

OpenAI提供的這個方式,與目前流行的LangChain其實是相似,隻是經由ChatGPT官方微調後的函數調用功能,會更加穩定。

而由LangChain調用外部tool,則沒那麼穩定,而且還需要花額外的token與ChatGPT描述及溝通,成本相對高一些。

通過函數調用,我們增強了ChatGPT的能力,不僅限于連網能力,還包括數學能力,程式設計能力等。

甚至讓chatGPT通過函數調用,直接控制機器人,是不是很魔幻?

函數調用官方文檔

https://platform.openai.com/docs/guides/gpt/function-calling

更多例子

https://github.com/openai/openai-cookbook/blob/main/examples/How_to_call_functions_with_chat_models.ipynb

最近也看到免費的chatgpt入口推薦給大家,感興趣的拿走:

免費的 chatgpt:https://ai.y-p.cc/chat/

AI工具導航網站:https://ai.y-p.cc

#人工智能##一起來玩chatgpt##AI應用##為什麼chatGPT這麼火爆#