这道题其实是在问,怎么让大模型从一个只会说不会做的聊天机器,变成一个能真正干活的[[智能体]]。核心就是通过工具调用把模型的能力边界扩展到外部世界。
先说工具定义。你不能指望模型凭空知道怎么调用API,必须把每个工具的结构化描述给它。我一般用JSON Schema来描述,包括工具名称、功能描述、参数列表、参数类型和约束,比如枚举值、必填项。注入方式有两种:一种是通过[[系统提示]]直接塞进去,另一种是像OpenAI的tools参数那样用专用字段。系统提示方式对模型理解要求更高,而专用字段方式更结构化、更可靠。实际上落地时我倾向混合使用:系统提示里给个简短说明,专用字段里给完整Schema,这样模型理解更准。
接下来是工具选择和参数生成。模型根据用户查询和工具描述做意图匹配,输出哪个工具和什么参数。参数生成有两种常见做法:约束解码和后处理解析。约束解码是训练模型直接输出结构化格式,比如<tool>{"name":"search","args":{...}}</tool>,这种方式更可控。后处理解析则是让模型自由生成,然后通过正则或JSON解析提取调用结构。我的经验是,约束解码更可靠,但训练成本高;后处理解析灵活但容易出错。 实际项目里,如果工具数量少、参数简单,后处理就够了;工具多了,我会用约束解码加校验重试。
举个例子,一个电商客服系统,用户说“帮我查一下订单OD20240501的物流状态”。模型先识别出需要调用物流查询工具,然后生成参数:订单号是OD20240501。这里有个坑:用户可能说“我的订单”,模型需要从上下文提取具体订单号。所以参数生成时,我会加上上下文补全的逻辑,避免模型直接报参数缺失。
工具执行后,结果要回传给模型。外部执行层实际调用API,返回成功或失败数据。结果需要格式化后重新注入对话上下文,但要注意长度控制,超长结果要截断或摘要化,不然会撑爆上下文窗口。这里有个常见失败场景:工具返回错误时,模型可能不理解错误信息,导致死循环。 所以我会把错误信息也结构化,让模型能根据错误类型自纠正。
整个流程本质上是[[ReAct]]模式:Thought→Action→Observation→Thought。模型根据工具返回决定下一步:是继续调用其他工具,还是整合答案回复用户,或者向用户澄清。说白了,这是一个循环决策过程,模型不是一次就完事,而是像人一样逐步解决问题。
另外,我最近在关注[[MCP]]协议,它试图标准化工具定义和调用流程,让不同模型和工具能互操作。如果工具描述格式不统一,每次对接新工具都要改代码,很麻烦。
总的来说,我会把工具调用看成模型能力的延伸器,但前提是工具描述要清晰、参数生成要可靠、结果处理要鲁棒。上线我会特别关注参数校验失败和上下文膨胀问题,常见失败场景就是模型反复调用同一个错误工具。所以我会在系统层面加一个最大调用轮次限制和错误重试机制。