如何使用 OpenAI Chat Completions API 新参数 functions

488 阅读2分钟

背景

OpenAI 在模型 gpt-4-0613 和 gpt-3.5-turbo-0613 开始支持 function calling,开发者可以通过描述函数,让模型输出被选择的函数以及包含参数的JSON对象,这样就可以将 GPT 与外部工具和 API 连接起来,扩展 GPT 的能力。 可以使用的场景包括:

  1. 通过调用外部工具创建回答问题的聊天机器人: 例如将提问”今天杭州天气如何“转换成函数 get_current_weather(location)
  2. 将自然语言转换成 API 调用或者数据库查询: 例如将提问”获取本月客户列表“转换成函数 get_customers(start_date, end_date)
  3. 从文本中提取结构化数据: 例如将任务”给张三买一斤荔枝,手机号是13400000000,地址是火炬动力港“ 转换成函数 create_order(orders)

如何使用

使用 HTTP API

  1. 在请求模型时添加 functions 描述

请求:

curl https://api.openai.com/v1/chat/completions -u :$OPENAI_API_KEY -H 'Content-Type: application/json' -d '{
  "model": "gpt-3.5-turbo-0613",
  "messages": [
    {"role": "user", "content": "What is the weather like in Boston?"}
  ],
  "functions": [
    {
      "name": "get_current_weather",
      "description": "Get the current weather in a given location",
      "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"]
      }
    }
  ]
}'
  • functions: 模型可以选择的函数列表,生成包含参数的 JSON 对象。
  • functions.name: 函数名称
  • functions.description: 函数描述
  • functions.parameters: 参数,被描述为 JSON Schema object.

响应:

{
  "id": "chatcmpl-123",
  ...
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": null,
      "function_call": {
        "name": "get_current_weather",
        "arguments": "{ \"location\": \"Boston, MA\"}"
      }
    },
    "finish_reason": "function_call"
  }]
}
  • function_call: 包含选中的函数名称和可以使用的参数对象
  • finish_reason: 包括 stop 和 function_call,如果是 stop 则说明已经返回全部的内容,如果是 function_call 则说明返回的是函数调用
  1. 执行模型返回的函数,该函数由本地实现
function get_current_weather({location}){
    return { "temperature": 22, "unit": "celsius", "description": "Sunny" }
}
get_current_weather({ "location": "Boston, MA"})
  1. 将响应再次发送给模型,让其进行总结

请求:

curl https://api.openai.com/v1/chat/completions -u :$OPENAI_API_KEY -H 'Content-Type: application/json' -d '{
  "model": "gpt-3.5-turbo-0613",
  "messages": [
    {"role": "user", "content": "What is the weather like in Boston?"},
    {"role": "assistant", "content": null, "function_call": {"name": "get_current_weather", "arguments": "{ \"location\": \"Boston, MA\"}"}},
    {"role": "function", "name": "get_current_weather", "content": "{\"temperature\": "22", \"unit\": \"celsius\", \"description\": \"Sunny\"}"}
  ],
  "functions": [
    {
      "name": "get_current_weather",
      "description": "Get the current weather in a given location",
      "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"]
      }
    }
  ]
}'

将第一次 GPT 的返回和本地执行函数后的结果拼接之后都发送给模型,详见参数 messages

响应:

{
  "id": "chatcmpl-123",
  ...
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "The weather in Boston is currently sunny with a temperature of 22 degrees Celsius.",
    },
    "finish_reason": "stop"
  }]
}

最后获得回复:

The weather in Boston is currently sunny with a temperature of 22 degrees Celsius.

使用 openai

import os
import openai

GPT_MODEL = "gpt-3.5-turbo-0613"

function_descriptions = [
    {
      "name": "get_current_weather",
      "description": "Get the current weather in a given location",
      "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"]
      }
    }
  ]

user_query = "What is the weather like in Boston?"

# 把问题与函数定义交给 function call,自动选择合适的函数
response = openai.ChatCompletion.create(
    model=GPT_MODEL,
    messages=[{"role": "user", "content": user_query}],
    functions=function_descriptions,
    function_call="auto",
)
response_message = response["choices"][0]["message"]

# 调用 function call 选择的函数,得到返回值
import json
import inspect

def get_function_parameter_names(function):
  if function is not None and inspect.isfunction(function):
      parameter_names = inspect.signature(function).parameters.keys()
      return list(parameter_names)
  else:
      return None

# Locate the function and make the call
def cal_function(_function_name, _arguments):
    the_function = globals().get(_function_name)
    parameter_names = get_function_parameter_names(the_function)
    parameter_values = []
    for parameter_name in parameter_names:
      parameter_values.append(_arguments[parameter_name])
    return the_function(*parameter_values)

def get_current_weather(location):
    return json.dumps({ "temperature": 22, "unit": "celsius", "description": "Sunny", "location": location })

function_name = response_message["function_call"]["name"]
arguments = json.loads(response_message["function_call"]["arguments"])
returned_value = cal_function(function_name, arguments)

# 将响应再次发送给模型,让其进行总结
second_response = openai.ChatCompletion.create(
    model=GPT_MODEL,
    messages=[
        {"role": "user", "content": user_query},
        response_message,
        {
            "role": "function",
            "name": "get_current_weather",
            "content": returned_value,
        },
    ],
)

使用 LangChain Agent

from langchain.chat_models import ChatOpenAI
from langchain.tools import tool

# 在 function description 中描述参数结构,LLM 可能会自动识别,但最好还是配置 args_schema
@tool("get_current_weather")
def get_current_weather(location):
    """Get the current weather in a given location"""
    return json.dumps({ "temperature": 22, "unit": "celsius", "description": "Sunny", "location": location })

# 工具是给 agent 自动分析使用
tools = [get_current_weather]

question_format_str = "What is the weather like in Boston?"

from langchain.agents import initialize_agent
from langchain.agents import AgentType

llm = ChatOpenAI(model_name=GPT_MODEL, temperature=0)

agent = initialize_agent(tools, llm, agent=AgentType.OPENAI_MULTI_FUNCTIONS, verbose=True)
agent_response = agent.run(question_format_str)
print(agent_response)

参考源码

资料