想让模型会调用工具,就需要先定义好工具,他才知道调用哪个,但是模型怎么知道该调用哪个工具的呢?这就需要我们在定义工具的时候遵守一些原则,让模型可以更好地理解这些工具了。 给大家分享一些经验,按照这个标准来定义工具会让你少踩很多坑。
函数名称、描述、参数描述要清晰明了。
在我们之前自己写代码的时候,定义一个接口的时候,不太关注注释的,对于方法的作用以及入参、出参很少描述的很清楚。主要是因为这些方法使我们自己写代码调用,虽然注释不清楚,但是自己能清楚就行了。 可是如果是让大模型决策模型调用的话,如果方法名称,参数描述不写清楚的话,大模型肯定是不知道他具体的作用的。所以一定要描述清楚这个方法是干什么的,每一个参数的作用和格式都要写清楚。
扁平化的参数结构
尽量避免参数的多层嵌套,因为参数的嵌套都是通过json来描述的,如果层级比较多,很容易就搞错了。所以,尽可能扁平化的平铺参数。
不要有太多参数
虽然我们建议扁平化参数,但是也要控制参数的数量,千万不要特别多参数,函数参数的数量最好不超过 3-4 个。尤其是一些默认的参数,这些就不要定义在接口中了,在服务端自己补全就行了。 还有就是一些和鉴权有关的参数,也不要让模型传递,应该自己做好鉴权的事宜,而不是依赖模型。
可以使用枚举限定参数
为了防止模型捏造参数值,比如某一个参数的值传什么,我们可以把他从问答题变成选择题,实际在开发中,我们可以使用 enum 关键字明确列出所有可能值。
{
"type":"function",
"name": "search_restaurants",
"description":"提供餐馆搜索功能",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "The location to search."},
"good_for": {
"type": "string",
"description": "What the restaurant is well-suited for.",
"enum": ["families", "romantic_dating", "business_meeting", "large_groups", "solo_dining"],
# "families" 明确对应了“带孩子”
}
},
"required": ["location"]
}
}
对于good_for这个字段,我们通过enum规定了可选值的范围,模型会成功地将“能带孩子”映射到 good_for: "families"。
适当给一些few shot
对于参数的描述,可以通过一些few shot来辅助模型更好的理解该如何传参。 或者在工具定义完之后,也可以给一些关于工具的调用的示例。
友好的错误提示
之前我们自己写代码的时候,会经常做前置的参数检查,在检查不同过的时候,可能就简单的抛个异常。 再给大模型定义工具的时候,方法内部如果出现异常和错误,要尽可能给出友好的提示,让模型能读懂错误的原因,尤其是一些参数格式错误之类的,方便模型调整和优化。
返回值要让大模型能理解
返回值一定要清晰明了,包括返回值的参数的定义,要让模型能看懂返回的内容,他才知道这些东西他怎么用。
不要做复杂的工具调用链
多轮对话的时候,工具的调用结果是不会自动传递到下一轮的,所以我们需要自己传递,这就要求我们不要做很复杂去的工具链。如果确实有很多事情要做,可以把几个相关的工具封装一下,封装到一个工具中,这样也更加方便模型调用。