乐于分享
好东西不私藏

AI Agent 的工具调用参数校验与修复循环:当模型输出不合法时,谁在修正它

AI Agent 的工具调用参数校验与修复循环:当模型输出不合法时,谁在修正它

Agent 调用工具时最常出问题的环节,不是工具本身跑不通,而是模型生成的参数错了。

类型不对。字段缺失。值超出允许范围。两个参数之间互相矛盾——比如选了"直飞"但目的地经停第三地。这些错误在 Agent 的生产运行中非常常见,但大多数团队的处理方式还停留在"发现错误→让模型重试"的原始阶段。而这个"重试"环节,恰恰是区分一个 Agent 系统是玩具级还是生产级的关键分水岭。

问题的本质:模型不是 API 客户端

LLM 生成工具调用参数的方式,和你写代码调 API 完全不同。你用 IDE 调 API 时有类型系统、自动补全、编译检查,甚至运行时还有参数校验库。模型生成参数时,只有一个工具定义的文本描述——几行 JSON Schema 或一段自然语言说明。

这意味着模型天然会犯三类错误。

第一类是格式错误。参数类型不对、JSON 结构不合法、枚举值拼写偏差。这类错误在结构化输出(Structured Outputs)功能出现后大幅减少,但没有完全消失。当工具定义复杂、嵌套层次深时,模型仍然会在深层字段上出错。

第二类是语义错误。格式对了,但值不对。比如搜索日期填了昨天,城市名填了"New York City"但工具期望的是"NYC"。这类错误比格式错误更难捕获,因为它的"正确性"取决于业务上下文,而不是类型约束。

第三类是跨参数一致性错误。Agent 需要同时调用多个工具,或者单个工具的不同参数之间存在制约关系。比如订机票时选了"靠窗座位"但舱位类型没有靠窗选项。这类错误往往发生在模型没有意识到参数之间的隐含依赖时。

这三类错误的共同点在于:它们都不是工具执行时抛出的异常,而是在参数生成阶段就已经埋下的问题。如果等到工具执行才发现,往往已经浪费了一次 API 调用、消耗了 Token,还增加了响应延迟。

一个简单的重试为什么不够

最直接的做法是让模型重试。把校验错误拼接成一条消息塞回给模型,说"参数有误,请修正"。这确实能解决一部分问题,但生产运行中会发现几个反复出现的陷阱。

第一个陷阱是重试不收敛。模型收到"参数有误"的反馈后,有时会改掉一个错误,引入两个新错误。或者反复在同一个参数上转圈,每次生成的值都不同,但没一个是对的。这种情况在模型不确定参数格式时尤其常见。

第二个陷阱是反馈过于模糊。只说"参数有误"而不明确哪个参数错了、错在哪里、期望什么值,模型只能靠猜来修正。猜对了还好,猜错了又多一轮消耗。

第三个陷阱是局部修正导致全局不一致。模型只改了被指出的错误,但没注意到关联参数也需要同步调整。比如修正了出发日期的格式,但没更新返回日期——两个日期之间原本的逻辑关系因此断裂。

这三个陷阱指向同一个结论:校验与修复不是一行"请重试"能解决的,它需要一个结构化的循环。

分层校验架构

一个生产级的校验体系应该至少分三层,每层捕获一类错误,输出不同粒度的反馈。

第一层是 Schema 校验。这是最基础的防线,检查参数的类型、格式、是否在枚举范围内、必填字段是否齐全。这一层完全可以在没有模型参与的情况下用程序完成。对于大多数框架,这相当于用 JSON Schema 或 Pydantic/Zod 做一次标准校验。Schema 校验的反馈应当精确到字段级别——"参数 'departure_date' 格式应为 YYYY-MM-DD,收到 '2026/08/07'"——而不是笼统地报错。

第二层是语义校验。格式正确了,但值是否合理?比如查询历史数据的时间范围超过了工具允许的最大跨度,或者搜索关键词超过了长度限制。语义校验通常需要结合业务规则,但规则本身是确定的,不需要模型来判断。这层校验的反馈应当包含期望值的范围或约束条件——"参数 'price_max' 不能超过 100000,收到 200000"。

第三层是一致性校验。这是最容易被忽略的一层。当单个工具的参数之间存在依赖关系,或者多个工具的参数需要保持一致时,模型需要跨参数推理。比如一个"创建用户"工具,role 和 permissions 之间的关系——如果 role 选了"guest",permissions 就不应该包含 admin 级别的操作。一致性校验的反馈最复杂,因为它不仅要指出矛盾,还要说明是哪两个参数之间的冲突。

这三层校验在架构上应该独立实现,但串联成一个管道。每一层接收上一层的输出(可能已经包含了修正后的参数),执行自己的检查,然后决定是放行还是反馈给模型。

反馈的结构化设计

校验失败后,发回给模型的消息格式直接影响修正效率。一个设计良好的错误反馈应该包含三个要素。

要素一是错误位置。指出具体是哪个工具的哪个参数出错了。如果模型生成了多个工具调用,还要指明是哪个调用。这听起来简单,但在实际实现中,很多团队省略了这步,导致模型花 Token 去猜测哪个参数有问题。

要素二是错误原因。不仅仅是"不合法",而是"不合法"的具体原因——类型不匹配、值越界、格式错误、或者违反了什么业务规则。原因越具体,模型修正的准确率越高。

要素三是修正建议。告诉模型期望值是什么,或者给出有效的取值范围、格式示例、或者可接受的枚举值列表。这不是替模型做决定,而是缩小它的搜索空间,减少"猜"的成分。

这三个要素组合起来,形成了类似编译器错误消息的结构。模型收到这样的反馈后,不需要推理"这里可能出了什么问题",而是直接定位到问题并修正。

修复循环的工程选择

有了结构化的反馈,接下来要考虑修复循环本身的控制逻辑。这里有三个关键决策点。

第一个决策点是重试的粒度。当模型生成多个工具调用,其中只有部分参数出错时,是让模型重新生成全部参数,还是只修正出错的参数?全部重新生成的路最简单,但会引入一个风险:原本正确的参数可能被改错。只修正出错参数看起来更高效,但在实现上需要维护一个"部分参数状态",而且当模型修正一个参数时,可能连带影响其他参数的一致性。实际项目中,一个合理的折中是先尝试部分修正,如果连续两次修正都引入新错误,就回退到全部重新生成。

第二个决策点是重试次数和退出策略。单纯设一个最大重试次数是最简单的做法,但不一定最优。对于某些错误——比如枚举值拼写错误——模型通常一次就能修正。对于其他错误——比如跨参数依赖——可能需要多轮。更好的做法是结合重试次数和错误类型来判断:Schema 级错误可以设较低的重试上限(因为它们最容易被模型理解),一致性错误的容忍度可以高一些。

第三个决策点是超时控制。当校验循环进入非收敛状态——模型反复在同一个问题上打转——需要有明确的退出机制。除了最大重试次数,还可以引入"不再改善"的检测:如果连续两轮校验反馈的错误集合没有变化,就不再继续重试,而是走降级路径。

在实践中的反馈

这个架构在几个生产项目中验证过,有几个值得分享的观察。

第一个观察是,大多数校验失败发生在 Schema 层,但大多数修复失败发生在一致性层。模型对类型和格式的修正能力已经相当强,尤其在有结构化输出加持的情况下。但涉及跨参数的业务逻辑判断时,模型需要更多上下文才能正确修正。这提示我们:一致性校验的反馈应该附带更充分的上下文,比如相关参数之间的约束关系说明。

第二个观察是,工具定义的清晰度直接影响校验循环的收敛速度。同样的错误,在一个定义清晰、包含使用示例和边界说明的工具上,模型平均修正轮次是 1.2 次;在一个定义模糊的工具上,这个数字是 3.5 次,而且有 15% 的概率重试 5 次以上仍不收敛。这说明校验循环不仅是运行时的防御机制,也是工具定义质量的反馈信号——如果一个工具的校验失败率持续偏高,首先应该检查的不是模型,而是工具定义本身。

第三个观察是,校验循环的日志是改进 Agent 系统最有价值的信号之一。每次校验失败都包含三个信息:模型理解上的盲区、工具定义上的模糊点、以及业务规则中的边界情况。将校验日志归类分析,可以系统性地指导工具定义的优化和模型提示词的调整。

架构上的取舍

实现校验与修复循环时,有一个架构选择值得认真考虑:将校验逻辑放在 Agent 运行时内部,还是独立成一个服务层。

放在内部最直接,实现成本低,但有一个隐患:校验逻辑和 Agent 运行时耦合在一起,修改校验规则时可能影响 Agent 的核心行为。独立成服务层可以解耦,但增加了架构复杂度和调用延迟。

实际项目中,合理的分界线是:Schema 校验和简单的语义校验可以放在 Agent 运行时内部(它们通常由框架内置支持),而复杂的一致性校验和业务规则校验应该独立出去。这样既保留了简单校验的效率,又不让复杂业务规则污染 Agent 运行时。

另一个取舍是同步 vs 异步。校验循环本质上是同步的——模型必须等到校验通过才能继续。但修复过程不必完全同步:如果某个工具调用的一致性校验进入非收敛状态,可以将其标记为"待修复"并暂时跳过,让 Agent 继续执行其他任务,同时异步重试修复。这种"异步修复"模式在复杂工作流中尤其有用,前提是校验逻辑支持状态持久化。

校验与修复循环不是 Agent 系统的附加功能,而是其核心架构的一部分。它的设计质量直接影响 Agent 的可靠性、成本和用户体验。当团队的 Agent 在生产中频繁出现"参数错误→重试→还是错误"的循环时,问题往往不在模型,而在校验循环本身的设计上。从这个角度看,投入精力设计好这个循环,比追求更强大的模型更具性价比。

#AI应用架构 #AI应用开发 #Agent应用架构 #Agent应用开发