Appearance
Structured Output、Schema Validation 与 Tool Calling
前置:模型输入到底是什么:Message、Item、Event 与 Instruction Hierarchy
核心问题:模型返回的 JSON 已经通过 schema,为什么仍然不能直接执行 Tool,结构验证、语义验证和执行授权各挡住什么错误?
模型返回 {action:"transfer", amount:1000} 即使满足 schema,也仍需 domain validation、授权和余额检查后才能执行。日期字段通过 JSON string 校验后仍可能是不存在的日期;工具层可以再用 Pydantic/domain validator 转换并拒绝语义非法值。
Mental Model
一次调用先把 domain request 固定下来,再由 adapter 映射 provider;stream 中的 delta 只作为中间事件,最终 Item/Response 经过 schema/domain validation 后才进入 Runtime。
Structured Output
Structured Output 约束输出形状;JSON Schema/类型验证检查结构。它们都不能证明业务语义正确,因此后面仍需要 domain validation 和 permission。
Structured Output 把模型到程序的接口从自由文本提升为受约束数据,但只解决“形状可解析”,不证明语义正确、权限合法或业务条件成立。
JSON Schema / Validation
JSON Schema/类型验证属于 structural validation:字段、类型、枚举、required 等由程序确定性检查。通过 schema 后仍需 domain validation,例如资源是否存在、金额是否合法、tool 是否允许当前用户执行。
Schema 应描述程序真正需要的字段、类型、枚举和约束,避免巨大 union 与深层 optional 结构。Validation 至少分 provider/parse、schema、domain、policy 四层,错误类型决定能否让模型修正或直接失败。
Function Calling / Tool Calling
Tool Calling 的关键是:模型只提出结构化调用意图,真正的函数调用仍由程序执行。
text
Model → ToolCall{name,args}
↓
Runtime lookup / validate / authorize
↓
Executor 真正调用 Tool
↓
ToolResult → Observation因此“模型输出了 delete_file”不等于文件已经被删除。Runtime 仍要检查 Tool 是否存在、参数是否满足 schema、当前用户是否有权限、是否需要 approval,以及这个动作是否允许在当前 deadline 内执行。
Function Calling 常是 Provider 对这一能力的产品名;在 Harness 里更值得关注的是内部 ToolCall contract,而不是绑定某一家 API 的字段格式。
Failure Modes
只验证“像 JSON”而没有验证 Schema 与领域约束
症状: json.loads 成功后就把字段交给 Planner/ToolExecutor。
为什么危险: 错型、未知枚举、越界值或缺失字段仍可能进入副作用路径;结构可解析不等于语义可执行。
处理: 先做 schema validation,再做 domain validation;危险动作继续经过 permission/policy。
把 ToolCall 当成 Tool 已经执行成功
症状: 模型输出一个 function/tool call 后,RunState 就记录对应业务动作完成。
为什么危险: ToolCall 只证明模型提出意图;真实 I/O 可能被拒绝、超时、失败或等待审批。
处理: ToolCall、Authorization、ToolExecution、ToolResult 分成独立记录,只有执行结果能改变对应系统事实。
如何验证
| Case | 断言 |
|---|---|
| 只验证“像 JSON”而没有验证 Schema 与领域约束 | 提供可解析但违反 enum/range/required 的 JSON,断言下游 Executor 调用次数为 0。 |
| 把 ToolCall 当成 Tool 已经执行成功 | ScriptedModel 产生 ToolCall,但 Executor 返回失败;断言 State 不会进入成功终态。 |
自测
- 模型返回了 schema-valid 的
{"amount": -100},但业务要求金额必须为正。为什么 schema 通过后仍不能进入 Tool Executor? - 把一次 Tool Call 依次经过结构验证、领域验证、权限判断。分别举一种只有该层才能挡住的错误。