跳到主要内容

工具输出 Schema 设计:你的工具响应如何塑造智能体推理

· 阅读需 9 分钟
Tian Pan
Software Engineer

大多数团队在设计 LLM 智能体时,会花大量精力在工具选择和系统提示措辞上。而几乎没有人认真思考工具返回什么内容。这是一个后果不断叠加的错误——因为工具响应的结构决定了智能体能否有效推理、消耗多少上下文窗口,以及产生幻觉解读的频率。

工具输出 schema 设计是基础设施,而非管道细节。设计失误,你的智能体将以表面上像推理问题的方式失败,而根源其实是 schema 问题。

好坏 Schema 之间的推理鸿沟

2026 年初发表的一项对照研究发现,与散文文档相比,基于 schema 的工具接口能减少接口格式错误。但研究同时发现,语义动作质量和超时敏感任务仍是主要失败模式——这意味着良好的 schema 设计不能保证推理成功,但糟糕的 schema 设计会让推理成功成为不可能。

机制很直接:LLM 是在人类可读文本上训练的下一词预测器。当工具返回 {"uuid": "d3fa...", "mime_type": "image/png"} 时,模型必须在上下文中推断这些值的含义。当返回 {"name": "profile-photo.png", "image_url": "https://..."} 时,模型可以直接推理。这种认知开销差异在多步智能体循环中会不断累积。

字段命名单独来看就比大多数工程师预期的更重要。叫 ts 的字段需要推断,叫 created_at 的字段一目了然。同一个工具的两个响应中,一个用 urgency,另一个用 priority,会打破智能体对第一个响应建立的任何推理模式。

破坏智能体推理的六种反模式

没有语义标签的裸 JSON 对象。 返回原始内部 ID、不透明类型字符串和数据库 UUID 的 API 是为提前知道 schema 的代码设计的,而非为智能体设计。智能体从字段名推断含义,字段名不透明时就会猜测——这些猜测会以幻觉解读的形式出现在下游。

成功响应中隐藏错误。 返回 HTTP 200 但响应体包含 {"status": "error", "message": "Invalid parameter"} 违反了 HTTP 语义,让智能体和处理失败的包装代码都感到困惑。智能体看到工具调用成功,读取响应体,然后卡在调和"调用成功"和"出了什么问题"之间。设计良好的工具响应在结构上不可能混淆成功与失败:正确使用 HTTP 状态码,永远不要把错误信号埋在成功形态的响应中。

模糊的可空性。 字段缺失(不适用)、字段存在且为 null(适用但未知)、字段有值,这三者之间有本质区别。当你的 schema 混淆了这些情况——有时省略字段,有时设为 null,没有文档说明的约定——智能体只能猜测语义,而且在生产中猜错的频率足以造成影响。

过于冗长的响应。 在大多数托管模型上,输出 token 的成本是输入 token 的 4–6 倍,在多轮智能体循环中,上下文成本大致以 n(n+1)/2 增长——而非线性增长。工具响应中每个不必要的字段都是占用推理空间的 token。一个有 20 个工具的服务器,在每次请求时注入 2000–4000 token 的 schema 开销,不管实际调用了哪些工具,都在悄悄降低每个下游推理步骤的质量。分页默认值同样重要:当智能体只需要 5 条结果时,返回 500 条的工具在浪费上下文预算并稀释信号。

信息量不足的响应。 相反的失败同样有害。当智能体需要推理资源状态时,只返回主键的工具要么迫使额外的工具调用(更多延迟、更多 token),要么导致幻觉假设(更多错误)。目标是智能体完成下一推理步骤所需的最少信息——不多不少。

跨响应字段类型不一致。 当某个字段有时是字符串有时是整数,或有时是列表有时是单个值时,智能体为该工具建立的推理模式会不可预测地失效。生产 CRM 集成正是以这种方式失败的:响应形态之间的 schema 漂移在测试中看起来一致,但在真实流量模式下却出现了分歧。

优秀工具输出设计的样貌

良好的工具输出设计遵循几个持久的原则。

只返回智能体下一步推理所需的内容。 这不是为了极简而极简——而是关于信噪比。响应中的每个字段都是对智能体上下文预算的索取,也是被误解的机会。如果某个字段不影响下游推理,它就不应该存在。

使用稳定的语义标识符。 在实际可行时,优先使用人类可读的 slug 而非不透明的 UUID。当必须返回内部 ID 时,在旁边加上实体名称。{"ticket_id": "T-4821", "title": "Payment timeout in checkout"} 让智能体无需单独查询 ticket 就能推理。

让错误状态明确无歧义。 每次工具调用要么明确成功,要么明确失败。正确使用 HTTP 状态码,返回一致的错误 schema(附带可操作的消息,而非需要查找的错误码),永远不要在同一响应形态中混合成功数据和错误信号。

明确记录可空性。 在 schema 中将每个字段标记为必填、可选或可空,并保持一致。读取工具 JSON Schema 的智能体从该 schema 推断 API 契约——schema 中的歧义会变成智能体信念中的歧义。

为 LLM 编写字段描述。 在 OpenAI 函数调用和 Anthropic 工具使用中,字段描述出现在模型的上下文中。这些描述应该解释字段的语义,而不是重复其类型。"订单创建时的 ISO 8601 UTC 时间戳" 有用;"string" 没用。

冗长工具输出的复利成本

在无状态的单轮调用中,冗长的工具输出只是浪费。在多轮智能体循环中,它们是复利计费的。n 轮循环的总 token 成本大致以 n(n+1)/2 增长,因为 LLM API 每次调用都对完整的累积上下文重新计费。第 1 轮工具响应多出的 1000 个不必要 token,会被加到每一后续轮次的输入成本上。

这个数学关系有一个重要的设计含义:单独看起来便宜的工具,在生产循环中可能变得昂贵。一个团队测试单轮交互花费 0.02,看到10轮工作流花费0.02,看到 10 轮工作流花费 2.00,在线性情况下是对的。如果工具输出冗长且累积,同样的工作流实际可能花费 66–10。

缓解措施是工具输出裁剪(默认返回更少,按需提供更丰富的输出)和上下文管理模式的组合——对过时的工具结果进行掩盖或摘要,而不是贯穿整个循环。Google 的生产多智能体框架将上下文分为稳定前缀(系统指令、持久摘要)和可变后缀(最近的工具输出、当前任务状态)——冗长的工具输出会让可变后缀无限增长,破坏这一模式。

输出契约测试

最后一块大多数团队跳过的内容:在工具响应到达生产智能体之前测试其 schema。

Pydantic 模型作为输出 schema 是基准——将期望的响应形态定义为类型化模型,在工具响应进入智能体循环前对其进行验证。这能捕获类型不匹配、缺少必填字段以及 schema 文档与 API 实际返回之间的形态漂移。

AWS 的 ToolSimulator 框架更进一步,提供了一个支架层,在将工具响应传递给智能体之前根据声明的 schema 验证它们,在边界处捕获格式错误的响应,而不是让它们传播成推理失败。无论你使用何种技术栈,同样的原则都适用:在边缘处验证,在智能体之前。

对于端到端测试,DeepEval 等框架提供了智能体工作流的结构化评估——同时测试确定性属性(schema 有效性、格式正确性)和概率性属性(智能体对工具响应的解读是否符合预期语义)。三层递进——自然语言文档、JSON Schema、带字段级诊断注释的 JSON Schema——对应着逐步增强的保障。大多数团队停在第一层,然后疑惑为什么智能体行为不一致。

UC Berkeley 对主流框架 1600+ 次多智能体执行跟踪的失败分类研究发现,schema 问题是最常见的根本原因之一:参数格式错误、类型不匹配、缺少必填字段。这些失败表现为智能体推理失败,但根源在于 schema 设计。独立于智能体测试 schema 可以在智能体发现之前就捕获这些问题。

将工具输出视为智能体推理底层

最有用的重新框架是:工具输出 schema 不是 API 关注点,而是推理底层。每个字段名、每个可空边界情况、响应形态中的每个隐式假设,都会成为智能体推理的材料。设计不良的工具响应不只是浪费 token——它让智能体建立在正常路径下有效、在边界情况下失败的推断。

在生产中构建可靠智能体的团队,对工具设计——输入 schema、输出 schema、错误处理和冗余预算——给予与系统提示和模型选择同等的关注。而不这样做的团队在调试推理失败,而那些失败其实是 schema 失败,追溯根源所花的时间远比一开始就把 schema 设计好更长。

从允许智能体完成下一推理步骤的最小响应开始。为 LLM 命名字段,而不是为代码命名。让成功和失败明确无歧义。在响应进入上下文窗口之前验证输出。然后衡量智能体明显的推理方差中有多少消失了。

Let's stay in touch and Follow me for more thoughts and updates