通过了 Schema 验证的虚假工具参数
Agent 调用 fetch_order,参数为 order_id: "ORD-739241"。Schema 接受了它 —— 三个字母、一个连字符、六位数字,完全符合模式。工具返回了 404。Agent 开始含糊其辞,生成了 "ORD-739242" 并再次调用,又得到一个 404,接着又生成了 "ORD-739243"。你的仪表盘记录了三次成功的工具调用和三次干净的 Schema 校验。客户在等待。在追踪记录的某个地方,安全栈的每一层都报告为绿色,而模型正在全速虚构标识符。
团队认为 Schema 拦截了错误。Schema 确实拦截了它能拦截的东西:形状(shape)。它检查了参数是否为字符串,是否匹配正则表达式,以及必填字段是否存在。Schema 无法检查 ORD-739241 是否对应数据库中的真实订单,因为 Schema 根本不知道数据库的存在。这种差距 —— 句法上的合理性与语义上的正确性之间 —— 正是大多数生产环境工具调用 bug 的所在地,而且这种失败非常隐蔽,唯一的信号就是客户的困惑。
这不是模型的问题。这是一个早于模型出现的架构错误。将 JSON Schema 视为安全层,与将电子邮件字段的正则表达式视为可送达性检查属于同类错误:格式是必要的,但格式并不是你关心的属性。模型的工作是提议一个句法有效的调用。你的工作是在工具运行之前,决定该调用是否指向真实存在的东西。
形状不代表真实
严格的结构化输出和受限解码使得强制模型工具调用符合正确形状几乎变得零成本。提供商基于语法的解码器在每一步都会屏蔽无效标记,因此从结构上讲,输出是一个格式良好的 JSON 对象,必填字段齐全,枚举值属于列表之一,整数在声明范围内。这是一个极具意义的保证 —— 就在一年前,生产栈的一半还是用于修复无效 JSON 的字符串修复代码 —— 这种解放使得团队经常高估它的作用。
这种保证仅限于形状。字面字符串 "ORD-999999999" 与真实 ID 一样,都能完美满足模式 ^ORD-\d{6}$。1812 年的 ISO 日期可以通过日期格式检查。属于不同租户的用户 UUID 也能通过 UUID 格式校验。Schema 说明模型返回了正确类型的对象,但它并没有说明该对象指向了任何实际存在的东西。
反方向亦然。失败的 Schema 检查并不能说明底层意图是否合理;模型可能幻觉出了一个不存在的 priority 字段,Schema 理所当然地拒绝了它,但 Schema 无法告诉你该请求是否试图表达一些你的工具界面尚不支持的正当需求。结构化输出让形状错误变得明显,却让引用错误变得悄无声息。
