TL;DR
ChatGPT已经自带函数调用能力了,本文给了一个简单的示例。
回顾
笔者曾经在LangChain系列文章里交代利用LangChain赋予ChatGPT上网的能力。
然而OpenAI官方在June 13, 2023的更新里提出了function calling的能力,可以说在这个方向上直接灭掉了LangChain。
先看一下官方有哪些更新。
- 在Chat Completions API中提供了新的函数调用能力
gpt-4
和 gpt-3.5-turbo
模型的小版本迭代
gpt-3.5-turbo
扩展到了4倍(16k)的上下文的能力
- SOTA embeddings 模型降价 75%
gpt-3.5-turbo
降价25%
gpt-3.5-turbo-0301
和 gpt-4-0314
的退役时间
而最令人激动的,实属 function calling
一个示范
如下图,依然是用人话要股票信息,能够直接给出df数据(完成函数调用)。
如何实现
简单到令人发指。
首先,只需定义functions manifest,如下示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| functions = [ { "name": "get_stock_a", "description": "获取指定A股股票一段时间内的量价信息", "parameters": { "type": "object", "properties": { "stock_name": { "type": "string", "description": "具体的股票名称或代号,如贵州茅台、中国移动", }, "start_date": { "type": "string", "description": "开始日期,格式为2023-01-01", }, "end_date": { "type": "string", "description": "结束日期,格式为2023-01-01", }, }, "required": ["stock_name", "start_date", "end_date"], }, } ]
|
当然这个是不能乱来的,需要遵循一定的规则,具体需要参考官方specification
然后,实现你的自定义方法,这个示例就是实现 get_stock_a
方法,以获取指定A股股票的量价数据。这里我不给出具体实现,有兴趣私聊。
1 2 3
| def get_stock_a(stock_name, start_date, end_date): """ 获取指定A股股票的量价数据 """ print(f"stock_name: {stock_name}, start_date: {start_date}, end_date: {end_date}")
|
接着,只需在调用Chat Completions API时候,把functions带上。
1 2 3 4 5 6 7
| requests.post(f"{openai.api_base}/chat/completions", headers=headers, json={ "model": GPT_MODEL, "messages": messages, "functions": functions }, )
|
最后,你会看到类似下面这样的返回,完成一点解析和调用的动作,这个事就成了。
1 2 3 4 5 6 7 8
| { "role": "assistant", "content": null, "function_call": { "name": "get_stock_a", "arguments": "{\n \"stock_name\": \"招商银行\",\n \"start_date\": \"2023-05-01\",\n \"end_date\": \"2023-06-01\"\n}" } }
|
完整示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| import json import openai import requests
GPT_MODEL = "gpt-3.5-turbo-0613"
openai.api_key = "" openai.api_base = "https://api.openai.com/v1"
def call(messages, functions): headers = {"Content-Type": "application/json", "Authorization": f"Bearer {openai.api_key}"} try: response = requests.post(f"{openai.api_base}/chat/completions", headers=headers, json={ "model": GPT_MODEL, "messages": messages, "functions": functions }, ) return response.json()["choices"][0]["message"] except Exception as e: print("Unable to generate ChatCompletion response") print(f"Exception: {e}")
functions = [ { "name": "get_stock_a", "description": "获取指定A股股票一段时间内的量价信息", "parameters": { "type": "object", "properties": { "stock_name": { "type": "string", "description": "具体的股票名称或代号,如贵州茅台、中国移动", }, "start_date": { "type": "string", "description": "开始日期,格式为2023-01-01", }, "end_date": { "type": "string", "description": "结束日期,格式为2023-01-01", }, }, "required": ["stock_name", "start_date", "end_date"], }, } ]
def get_stock_a(stock_name, start_date, end_date): print(f"stock_name: {stock_name}, start_date: {start_date}, end_date: {end_date}")
def chat_call(message): messages = [{"role": "system", "content": "不要对函数中应该填入的数值作出自作主张的假设。如果用户的要求不够明确,要求澄清。"}] messages.append({"role": "user", "content": message}) r = call(messages, functions)
fcall = r["function_call"] return eval(fcall["name"])(**json.loads(fcall["arguments"]))
chat_call("2023年5月1日到6月1日,招商银行的A股量价给我一份")
|
如果你足够幸运,你将看到这样一串文本: “stock_name: 招商银行, start_date: 2023-05-01, end_date: 2023-06-01”
Ending
不多说了,黄老板已经说过了,“跑起来掠食,或是努力奔跑免得成为掠食者的食物”。