AI Agent Output Schema Validation:构建可靠AI Agent的必备实践
Agent 的输出要喂给下游代码,格式错一次整条链路就断。这篇讲怎么让模型稳定吐 JSON:定义 schema、解析校验、失败重试与降级的具体步骤。
💡 你将学到
Agent 的输出要喂给下游代码,格式错一次整条链路就断。这篇讲怎么让模型稳定吐 JSON:定义 schema、解析校验、失败重试与降级的具体步骤。
📜 目录
AI Agent输出Schema校验:让结构化输出稳定可用的五步流程
为什么 Agent 必须校验输出
Agent 和聊天机器人的分界线就在这里:聊天机器人的输出给人看,格式差一点还能懂;Agent 的输出要喂给代码——写数据库、调接口、发消息。少一个字段、多一层嵌套、值写成"大约 500 元",下游不是报错就是静默写入脏数据。这类故障通常不显眼,等到报表对不上才被发现。
校验的价值不是让模型更聪明,而是把不确定的输出挡在一个可控的边界内:要么是合规的 JSON,要么明确失败并重试,不许有第三种状态。
不校验会出什么故障
| 故障类型 | 具体表现 | 后果 |
|---|---|---|
| 包裹文本 | 返回"好的,结果如下:{...}" | 解析直接抛异常 |
| 字段缺失 | 少 amount 或多 note |
下游 KeyError 或写入空值 |
| 类型漂移 | 数字写成字符串 "500" |
计算或入库类型报错 |
| 枚举越界 | status 返回自造的新词 | 状态机卡住 |
| 嵌套错层 | 数组包成对象 | 批量任务全挂 |
第一步:让模型吐出结构化输出
三种方式,可靠性和兼容性不同:
| 方式 | 原理 | 优点 | 注意 |
|---|---|---|---|
| JSON 模式 | API 层强制输出合法 JSON | 最稳,不用自己清字符串 | 只保证合法 JSON,不保证符合你的字段 |
| 函数调用/工具调用 | 把 schema 作为工具参数声明 | 字段约束一起下达 | 需要模型与 SDK 支持 |
| 纯提示词约束 | 在提示里给格式说明与示例 | 任何模型都能用 | 最不稳,长上下文里容易走样 |
实践顺序:能用 JSON 模式就用,能顺带声明 schema 更好;只有在模型不支持时才退回纯提示词,并且必须配合"只输出 JSON,不要解释"这类硬约束。
第二步:把 schema 写清楚
字段设计有几个原则:字段尽量扁平,嵌套不超过两层;枚举值穷举干净;数字明确单位与量级;对可选的自由文本字段给长度上限。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| action | string | 枚举:query / create / update / delete | 决定下游走哪个分支 |
| target | string | 长度 1-64 | 目标对象标识 |
| amount | number | >=0,保留 2 位小数 | 金额,单位元 |
| reason | string | 长度 0-200,可空 | 给人工复核看 |
| confidence | number | 0-1 | 低于阈值转人工 |
第三步:解析与校验
拿到字符串后不要直接 json.loads 就完事,至少三步:
import json
from pydantic import BaseModel, Field, ValidationError
from typing import Literal
class Action(BaseModel):
action: Literal["query", "create", "update", "delete"]
target: str = Field(min_length=1, max_length=64)
amount: float = Field(ge=0)
reason: str | None = Field(default=None, max_length=200)
confidence: float = Field(ge=0, le=1)
def parse(raw: str) -> Action:
text = raw.strip()
if text.startswith("```"):
text = text.strip("`")
text = text.split("\n", 1)[-1] if text.startswith("json") else text
try:
data = json.loads(text)
except json.JSONDecodeError as e:
raise ValueError(f"not json: {e}")
return Action.model_validate(data)
第四步:失败之后的策略
失败不能只有"报错"这一条路。按代价从低到高:
| 策略 | 做法 | 适用 |
|---|---|---|
| 带错重试 | 把校验错误原文回传,要求只修格式 | 首次失败、错误明确 |
| 换提示模板 | 重试仍失败,换成更严格的分步提示 | 复杂结构 |
| 降级模型 | 换小模型做格式修补 | 成本敏感场景 |
| 转人工/默认值 | 超过重试上限,进人工队列 | 有资金或合规风险的动作 |
重试必须有次数上限(通常 2 次足够)和退避间隔,否则会变成烧钱循环。另外,凡是校验通过但 confidence 低于阈值的结果,建议走人工确认,而不是直接执行。
第五步:把校验结果接进监控
统计三类数字:首次解析成功率、重试后成功率、最终失败率。首次成功率是模型与提示质量的直接指标——它突然下跌,通常意味着模型版本变了、提示被改动,或者上游塞进了新的脏输入。把失败样本存下来,积累成回归测试集,下次改提示词先跑一遍。
常见坑
- 只在开发环境校验,生产环境关掉:等于没有
- 用正则从自然语言里抠字段:脆弱,长文本必翻车
- schema 里到处是可选字段:可选越多,下游分支越乱
常见问题
Q:用函数调用还需要自己校验吗? A:需要。函数调用保证参数按 schema 生成的概率更高,但仍会出现越界值、空字符串或业务上不合法的组合,业务规则必须自己卡。
Q:用哪个库比较省事? A:Python 生态里 Pydantic 最常见,Node/TypeScript 侧常用 Zod 或 JSON Schema 校验器。选择原则是它能否给出可直接回传模型的错误信息。
相关文章
本站文章由编辑人工撰写,收录的工具均经过实测或公开资料核验。文中链接指向工具官网或 GitHub 仓库,仅作信息参考,不构成付费推广。
