点击↑上方↑蓝色“编了个程”关注我~
这是Yasin的第 94 篇原创文章
最近AI大模型火出了圈,很多人惊叹它的智能程度。但大多数人都以为它的能力主要在“聊天”、“写文案”这方面。然而实际它能做的远远更多。
Chat GPT是当今世界上最智能的模型,它前段时间推出了“插件”的概念,其实就是AI工程化的一个基础能力。配合AI的能力,可以通过自然语言来搜索、购物、预定等等,AI从此不止局限于聊聊天。只是“插件”只能构建和运行在官网上,无法在更大范围的场景落地。
于是很多人加入了探索基于AI构建工程化的思路,笔者本人也是其中之一。最近GPT又开放了一个叫Function Calling的新能力,这篇文章主要介绍工程化的整体思路和Function Calling的一些调研、测试。
AI工程基于JSON的思路
在Function Calling出现之前,一般是使用Prompt来让Chat GPT返回JSON内容供下游工程消费。核心的思路如图:
比如auto-gpt的prompt
You should only respond in JSON format as described below
RESPONSE FORMAT:
{
"thoughts":
{
"text": "thought",
"reasoning": "reasoning",
"plan": "- short bulleted\
list that conveys\
long-term plan",
"criticism": "constructive self-criticism",
"speak": "thoughts summary to say to user"
},
"command": {
"name": "command name",
"args":{
"arg name": "value"
}
}
}
Ensure the response can be parsed by Python json.loads
langchian的prompt:
response_schemas = [
ResponseSchema(name="answer", description="answer to the user's question"),
ResponseSchema(name="source", description="source used to answer the user's question, should be a website.")
]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(
template="answer the users question as best as possible.\n{format_instructions}\n{question}",
input_variables=["question"],
partial_variables={"format_instructions": format_instructions}
)
def get_format_instructions(self) -> str:
schema_str = "\n".join(
[_get_sub_string(schema) for schema in self.response_schemas]
)
return STRUCTURED_FORMAT_INSTRUCTIONS.format(format=schema_str)
def _get_sub_string(schema: ResponseSchema) -> str:
return line_template.format(
name=schema.name, description=schema.description, type="string"
)
STRUCTURED_FORMAT_INSTRUCTIONS = """The output should be a markdown code snippet formatted in the following schema:
```json
{{
{format}
}}
```"""
然而,Chat GPT返回的JSON内容并不稳定,「存在很多问题,需要工程化的思路去解决」。
典型的几个case:
返回的json有json以外的内容,如中文解释 + json输出
返回的json有注释(偶现),不是合法的json
返回的json格式不对(偶现),比如两个json,但不是json数组
返回的json内容不对
意图识别失败,无法返回我们需要的json,返回的是自然语言
Function Calling介绍
基本介绍
最近OPENAI推出了Function Calling的功能,
官方文档:https://platform.openai.com/docs/guides/gpt/function-calling
API文档:https://platform.openai.com/docs/api-reference/chat/create#chat/create-functions
简单来讲,最新的模型(gpt-3.5-turbo-0613和gpt-4-0613)经过了官方的fine-tune优化,「既能检测输入时何时应调用函数,又能以符合函数签名的方式响应JSON」。
这里有两个要点:
自动检测何时响应,如果参数没有解析出来,是可以通过上下文对话补全信息来响应的。
以符合函数签名的方式来响应JSON。代表了返回的响应是一种固定的格式,一定是合法的JSON。
能力和API要点总结
经过阅读一些材料,总结一下FunctionCalling的能力和API调用的要点:
可以一次定义多个function
params是json schema的形式。https://json-schema.apifox.cn/
可以配合system prompt
可以理解上下文连续对话
function_call
参数说明:当设置为“none”时,模型不会调用任何函数,而是直接响应给最终用户。当设置为“auto”时,模型可以自行选择是向最终用户响应还是调用一个函数。通过指定一个具体的函数(如{"name":"my_function"}),则强制模型调用该函数。当没有函数存在时,默认值为“none”。当存在函数时,默认值为“auto”。
Function Calling 测试
Case 1 基础测试:查询天气
入参:
出参:
Case 2 上下文
这里官方参考prompt:
->Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous.
<-
推测必填参数:
description设置默认值:
prompt让gpt引导用户补充信息澄清:
上下文获取最终解析信息
Case 3 嵌套参数对象
根据官方的说法,parameters只要符合json schema规范就行,那我们可以用嵌套的形式来定义一个对象参数。
函数定义:
入参:
出参:
看起来很ok!
Case 4 返回IDL
官方是给DB表schema,返回sql的例子。这里我测试一下返回IDL的case。
入参:
输出:
解析一下,看起来也很ok:
局限性
1 准确率还是依赖模型本身
参数推理还是依赖模型本身的能力,有时候会推理错误。比如下图,就把“今天”推测到了location参数里面。
2 Prompt并不是完全有效,有时候会推测默认值
期望是让用户上下文沟通补全。但有时候chat gpt还是会自作主张,推测默认值:
3 function_call为none的时候不生效
按照官方文档的说法,function_call设置为none的时候应该不调用function,但实际测试下来不是这样的。这块有知道原因的朋友可以留言交流一下。
4 无法使用示例对话提升准确率
在之前我们使用Prompt + JSON输出的方式的时候,可以使用一些示例对话来增加AI输出的准确率,但现在改成了function calling的话,输出就不是assistent 的文本内容了,而是在单独的字段里面,所以few shot也就不那么好使了。
使用技巧
function_calling有其规定的出入参,如何和我们的代码更好地结合起来?
对于function定义,它是一个json schema定义,我们可以使用AI辅助我们来快速生成符合条件的json schema,类似这样:
另一方面,我们还可以使用反射等方式,来自动根据代码生成json schema,类似这样:
->这种方式不能自动转换出description这个带有语义的内容。所以其实还是更推荐上面那种方式,产出后自己根据需要修改,然后存库,调用的时候json反序列化填充到api接口里。
<-
同样的道理,我们也可以把Chat GPT的出参,利用反射来执行对应的方法调用:
function calling调研结论
1 更方便
因为产出一定是一个合法的json,不用自己处理很多异常情况,不用裁剪不要的自然语言。
2 更稳定
大多数时候比Prompt更稳定,尤其是在需要多轮上下文对话的时候,Prompt在多轮上下文之后准确率会明显降低,除非手动在最新的调用补充JSON定义。但function_calling是放在函数调用里面的,每次都会传入,所以整体上会更稳定。
可以说在大多数情况下,使用function calling来实现工程化的能力是一个最优的选择。它也降低了AI工程化的门槛,可以预料到在未来不远的一段时间内,基于AI构建的工程应用将迎来一个爆发期。
广告时间
这里给自己搭建的一个AI对话网站AiChatRoom(地址https://bot.aichatroom.cn)打个广告,可以国内直接使用Chat GPT,无需梯子,无需注册Chat GPT账号。支持的模型很多,包括最新的3.5-0613和3.5-16k,还支持GPT 4、AI绘画等。直接打开网站注册就能免费试用,感兴趣的朋友可以点进去看看~
关于作者
我是Yasin,一个爱写博客的技术人
微信公众号:编了个程(blgcheng)
个人网站:https://yasinshaw.com
不用魔法和GPT账号的AI聊天机器人:
bot.aichatroom.com
欢迎关注这个公众号