AI工程化的“基座能力”?—— 聊聊GPT Function Calling

点击↑上方↑蓝色“编了个程”关注我~

5f8f8a7aaef9a13a08e4a52a7b25d450.png

这是Yasin的第 94 篇原创文章

89751760317b020894c33b55a67e1f46.png

3fe4b7881e37e32d98b1bf83db137d6f.png

最近AI大模型火出了圈,很多人惊叹它的智能程度。但大多数人都以为它的能力主要在“聊天”、“写文案”这方面。然而实际它能做的远远更多。

Chat GPT是当今世界上最智能的模型,它前段时间推出了“插件”的概念,其实就是AI工程化的一个基础能力。配合AI的能力,可以通过自然语言来搜索、购物、预定等等,AI从此不止局限于聊聊天。只是“插件”只能构建和运行在官网上,无法在更大范围的场景落地。

于是很多人加入了探索基于AI构建工程化的思路,笔者本人也是其中之一。最近GPT又开放了一个叫Function Calling的新能力,这篇文章主要介绍工程化的整体思路和Function Calling的一些调研、测试。

AI工程基于JSON的思路

在Function Calling出现之前,一般是使用Prompt来让Chat GPT返回JSON内容供下游工程消费。核心的思路如图:

06c22fd7562157dcc19c5fcc776c21eb.png

比如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:

  1. 返回的json有json以外的内容,如中文解释 + json输出

  2. 返回的json有注释(偶现),不是合法的json

  3. 返回的json格式不对(偶现),比如两个json,但不是json数组

  4. 返回的json内容不对

  5. 意图识别失败,无法返回我们需要的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」

这里有两个要点:

  1. 自动检测何时响应,如果参数没有解析出来,是可以通过上下文对话补全信息来响应的。

  2. 以符合函数签名的方式来响应JSON。代表了返回的响应是一种固定的格式,一定是合法的JSON。

能力和API要点总结

经过阅读一些材料,总结一下FunctionCalling的能力和API调用的要点:

  1. 可以一次定义多个function

  2. params是json schema的形式。https://json-schema.apifox.cn/

  3. 可以配合system prompt

  4. 可以理解上下文连续对话

  5. function_call参数说明:当设置为“none”时,模型不会调用任何函数,而是直接响应给最终用户。当设置为“auto”时,模型可以自行选择是向最终用户响应还是调用一个函数。通过指定一个具体的函数(如{"name":"my_function"}),则强制模型调用该函数。当没有函数存在时,默认值为“none”。当存在函数时,默认值为“auto”。

Function Calling 测试

Case 1 基础测试:查询天气

入参:7347c420d421fcb94030777fb84372b6.png

出参:ff202f87b5c433f5c0d66e22e3498b58.png

Case 2 上下文

这里官方参考prompt:

->

Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous.

<-

推测必填参数:23f8551157545a1f258c5de82e6bd662.png

description设置默认值:defd59322e3ac645fdd0ab0a76b1ae67.png

prompt让gpt引导用户补充信息澄清:72e32031070497d0130d1f1c994c5ff1.png

上下文获取最终解析信息d1413d52a3e022cd466e3fd3f8df7c52.png

Case 3 嵌套参数对象

根据官方的说法,parameters只要符合json schema规范就行,那我们可以用嵌套的形式来定义一个对象参数。

函数定义:6b660589e7acca0d43326866177a841f.png

入参:ad526f950eb85384361c96e19d7fbcb8.png

出参:abe7f75b67cab88b1a62112c8fdf5637.png

看起来很ok!

Case 4 返回IDL

官方是给DB表schema,返回sql的例子。这里我测试一下返回IDL的case。

入参:0665010d412401074ad4c6b650b90ba6.png

输出:2ff25f9ed8945934261957d3300f61ac.png

解析一下,看起来也很ok:0fd7ed1ac200fba312487f645c380d4b.png

局限性

1 准确率还是依赖模型本身

参数推理还是依赖模型本身的能力,有时候会推理错误。比如下图,就把“今天”推测到了location参数里面。

ad5e8a9577b48a9845e28a60d4514c9e.png

2 Prompt并不是完全有效,有时候会推测默认值

期望是让用户上下文沟通补全。但有时候chat gpt还是会自作主张,推测默认值:e8501cf33dad733b432f2f2c385329bf.png

3 function_call为none的时候不生效

按照官方文档的说法,function_call设置为none的时候应该不调用function,但实际测试下来不是这样的。这块有知道原因的朋友可以留言交流一下。25ce1a94602c9fcf873261c74dd73fec.png

4 无法使用示例对话提升准确率

在之前我们使用Prompt + JSON输出的方式的时候,可以使用一些示例对话来增加AI输出的准确率,但现在改成了function calling的话,输出就不是assistent 的文本内容了,而是在单独的字段里面,所以few shot也就不那么好使了。

使用技巧

function_calling有其规定的出入参,如何和我们的代码更好地结合起来?

对于function定义,它是一个json schema定义,我们可以使用AI辅助我们来快速生成符合条件的json schema,类似这样:598ad319fbdb973d002dbd724b03b577.png

另一方面,我们还可以使用反射等方式,来自动根据代码生成json schema,类似这样:

->

这种方式不能自动转换出description这个带有语义的内容。所以其实还是更推荐上面那种方式,产出后自己根据需要修改,然后存库,调用的时候json反序列化填充到api接口里。

<-
bbc9e25f153674c67eb456a1503bc9a5.png

同样的道理,我们也可以把Chat GPT的出参,利用反射来执行对应的方法调用:443f4aa4a006e50e549b53cd0fe309a6.png

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绘画等。直接打开网站注册就能免费试用,感兴趣的朋友可以点进去看看~

1670dc88a0c5a944d028de615edb98b8.png

98dae067974c9704af36bbbfe1d0503b.png

关于作者

我是Yasin,一个爱写博客的技术人

微信公众号:编了个程(blgcheng)

个人网站:https://yasinshaw.com

不用魔法和GPT账号的AI聊天机器人

bot.aichatroom.com

欢迎关注这个公众号4190a06189c43c4c96d1cc3b4179bcf7.png

ec9c045518c97c73f30b3fd29d4e21d8.png

猜你喜欢

转载自blog.csdn.net/yasinshaw/article/details/131266637