第 14 章 AI AgentAgentic Patterns结构化输出

第 14 章 结构化输出与契约:让 Agent 的输出能接住

输出是自由文本,下游要的是数据

第三部分讲完了"让 Agent 动手"。从这一章开始,进入第四部分"让它可靠"。前面几部分解决"能不能干",这部分解决"干得稳不稳"。

最基础也最烦人的可靠性问题,是输出。Agent 天然输出自由文本,但下游系统要的是可解析的数据:数据库要结构化记录,下一个 Agent 要能交接,自动化工作流要能判断"这是合格还是不合格"。自由文本一旦往下游走,就是一场灾难:

  • 输出格式不可预测,要写一堆解析逻辑。
  • 校验和错误处理无从下手。
  • 接自动化工作流极其脆弱。
  • 分类结果不稳定。
  • 还得人工后处理,从文本里抠结构化数据。

一个 Agent 的输出要喂给另一个系统,自由文本根本接不住。

这一章讲两个模式,从"定义契约"到"让契约不破":

  1. Structured Output Specification(结构化输出规范):用确定性 schema 约束 Agent 输出。
  2. Schema Validation Retry(schema 校验重试):输出不合规就重试,还要跨步骤学习。

模式一:结构化输出规范(Structured Output Specification)

问题

如开头所说:自由文本输出没法校验、没法解析、没法接下游。更麻烦的是多阶段工作流,一个 Agent 的输出是下一个 Agent 或系统的输入,文本输出直接让整条链路崩掉。

方案

用确定性 schema 约束 Agent 的输出。不让模型自由发挥文本,而是用类型系统、JSON Schema 或框架自带的结构化输出 API,规定精确的输出格式。

三个核心动作:

1. 定义显式输出 schema:

  • 用 TypeScript 接口、JSON Schema 或 Pydantic 模型。
  • 规定必填字段、类型、约束。
  • 为分类输出定义枚举。
  • 写清字段语义和校验规则。

2. 用框架的结构化输出能力:

  • OpenAI 的结构化输出(JSON schema 约束解码)。
  • Anthropic 的 tool use 返回结构化结果。
  • Vercel AI SDK 的 generateObject
  • LangChain 的输出解析器、LlamaIndex 的 Pydantic programs、Instructor 的重试包装。

3. 在生成时校验:

  • 框架保证 LLM 遵守 schema。
  • 类型错误在进入应用代码之前就被抓住。
  • 输出保证可解析。
import { generateObject } from 'ai';
import { z } from 'zod';

// 定义严格的输出 schema
const LeadQualificationSchema = z.object({
  qualification: z.enum(['qualified', 'unqualified', 'needs_review']),
  confidence: z.number().min(0).max(1),
  companySize: z.enum(['enterprise', 'mid-market', 'smb', 'unknown']),
  estimatedBudget: z.string().optional(),
  nextSteps: z.array(z.string()),
  reasoning: z.string()
});

// Agent 返回结构化、已验证的输出
const result = await generateObject({
  model: openai('gpt-4'),
  schema: LeadQualificationSchema,
  prompt: `分析这条线索: ${leadData}`
});

// TypeScript 知道确切结构,可以直接按字段判断
if (result.object.qualification === 'qualified') {
  await sendToSalesTeam(result.object);
}

另一个例子:内容审核分析。用 Pydantic 定义 AbuseAnalysis,字段全是枚举 + 置信度 + 证据列表 + 是否要人工复核。生成后直接判断:要人工就 send_to_human,否则 auto_executeschema 把"输出"变成了"可执行的决策结构"

证据

  • 来自 Vercel AI 团队(established,成熟),他们在构建 Agent 时用结构化分类做线索资格评估。
  • JSONformer(Billings 等人,2023):约束解码能从根本上消除重试循环。
  • OpenAI / Anthropic 都把结构化输出做成官方能力,已经是行业标准做法。

怎么用

什么时候用:

  • 多阶段工作流,需要结构化交接。
  • 分类和归类任务。
  • 数据提取和转换。
  • 接数据库或 API。
  • 合规和审计要求。
  • 质量保证和校验。

实施步骤:

  1. 明确输出需求:Agent 做什么决策?要提取什么数据?下游系统消费什么?
  2. 设计 schema:必填字段、枚举、约束都要定义清楚。
  3. 接框架:用框架的结构化输出能力,保证生成即合规。
  4. 处理校验失败:带澄清提示重试(行业惯例 3 次);失败回退人工复核;记录 schema 违规,用于改进提示词。

缓解策略: schema 别定太死。留一个 additional_context 可选字段装自由文本备注;schema 要版本化,支持平滑降级;分类在演进时用联合类型;必填/可选字段平衡好。

取舍

  • 好处:输出保证可解析,解析错误归零;类型安全,编译期检查;接数据库、API、工作流顺畅;内置约束校验;schema 校验还能在执行前挡住提示注入;组件之间是显式契约;容易验证输出正确性。
  • 代价:schema 一改,所有关联方要协调更新;前期设计 schema 要花功夫;可能限制有用的自由文本输出;依赖 LLM 提供商的 schema 支持;schema 太严会导致生成失败;需求变了要跟着改,有演进摩擦。

模式二:schema 校验重试(Schema Validation Retry with Cross-Step Learning)

问题

模式一假设"schema 定了输出就合规"。现实是:LLM 不总能一次生成符合 schema 的 JSON。更糟的是,多步工作流里问题会叠加:

  • schema 违规:生成的 JSON 不匹配预期的 Zod/JSON Schema。
  • 一次失败全盘死:单次失败就终止整个工作流。
  • 不长记性:每一步都独立地重复同样的错误。
  • 白烧 token:失败的响应照样消耗上下文和钱。
  • 链路脆弱:不稳定的 LLM 输出让 Agent 不可靠。

方案

多步重试 + 详细错误反馈 + 跨步骤错误累积。让 Agent 在整个工作流里从自己的校验失败中学习。

三个核心机制:

1. 多次尝试重试 + 详细反馈:

行业实践用 2-3 次重试。研究(Self-Refine,ICLR 2024)显示,带反馈的迭代优化能把输出质量提升 15%-45%。

const maxAttempts = 3;

for (let attempt = 0; attempt < maxAttempts; attempt++) {
  const result = await ctx.llm.invokeStructured({ schema, options }, msgs);

  if (result.parsed) {
    return result.parsed;  // 成功,跳出重试循环
  }

  // 提取详细的 Zod 校验错误
  const validationError = getZodError(result.rawText);

  // 存下来供跨步骤学习
  ctx.schemaErrors?.push({
    stepIndex: currStep,
    error: validationError,
    rawResponse: result.rawText || "",
  });

  // 把错误反馈追加进消息,让模型重试时看到
  msgs = [
    ...msgs,
    { role: "assistant", content: result.rawText },
    { role: "user", content: `校验错误:\n${validationError}\n请修正。` },
  ];
}

// 全失败:带着累积的错误上下文抛异常
throw new SchemaValidationError(`3 次尝试后仍失败`, {
  stepIndex: currStep,
  errors: ctx.schemaErrors?.slice(-3)  // 最近 3 条错误
});

2. 跨步骤错误累积:

Agent 维护一个最近的 schema 错误滚动窗口,在后续 LLM 调用里带上这些错误:

interface AgentContext {
  schemaErrors: Array<{
    stepIndex: number;
    error: string;          // Zod 校验错误
    rawResponse: string;    // LLM 实际输出的内容
    timestamp: number;
  }>;
}

// 每步之前,把最近错误追加进系统提示,引导 LLM 避免重复犯错
const recentErrors = ctx.schemaErrors
  .slice(-3)  // 只保留最近 3 条,避免上下文膨胀
  .map(e => `Step ${e.stepIndex}: ${e.error}`)
  .join('\n');

if (recentErrors) {
  msgs.push({
    role: "system",
    content: `要避免的近期 schema 校验错误:\n${recentErrors}`
  });
}

3. 结构化反馈循环:

每次重试都提供具体、可行动的反馈。getZodError 把校验错误格式化成人能看懂、模型能修正的文本(path: message (received: ...) 这种格式)。替代方案:OpenAI Structured Outputs 和 Anthropic Tool Use 在 API 层强制 schema 合规,可以不做客户端重试循环。

证据

  • 来自 HyperAgent(Hyperbrowser 团队,emerging),生产实现见其 agent.ts
  • Self-Refine(Shinn 等人,ICLR 2024):带反馈的迭代优化提升输出质量 15%-45%。
  • 和模式一的 JSONformer 思路呼应:约束解码从源头消除违规,重试是兜底。

怎么用

  • 用 Zod 定义严格 schema,错误信息要清楚("elementId is required" 这种,别只给"无效")。
  • 实现重试包装:最多 3 次,每次把错误反馈追加进消息。
  • 注入错误上下文:每步之前,把之前步骤的最近 3 条错误放进系统提示。
  • 配置化:maxValidationAttemptserrorHistorySizecrossStepErrorCount 都做成可调。

缓解策略: 跨步骤错误窗口限制在最近 3 条控 token;重复工作流用缓存跳过重试;每步设超时防止重试失控;记录失败用于改进提示词;生产部署加重试退避 + 抖动。

取舍

  • 好处:3 次重试显著提高结构化输出成功率;跨步骤学习让 Agent 不在整个工作流里重复犯错;详细错误反馈引导模型精准修正;错误历史提供诊断信息;尝试次数 vs 成本/延迟可调。
  • 代价:重试时多次 LLM 调用增加延迟;失败的尝试照样烧 token;错误历史不管控会膨胀上下文;有些模型就是改不对;多一套重试逻辑和错误管理。

两个模式怎么选

场景 推荐模式
输出要接数据库 / API / 下一个 Agent 结构化输出规范
输出总是不合 schema,想让它自己改对 schema 校验重试
用 OpenAI / Anthropic 官方 API 官方结构化输出(API 层强制)

两个模式是同一个契约的两面结构化输出规范定义"契约长什么样",schema 校验重试保证"契约不破"。规范管设计,重试管兜底。上游能约束解码就从源头消除违规,约束不了就靠重试加跨步骤学习把它修回来。

实践清单

  • 输出接下游前,先定义 schema(Zod / Pydantic / JSON Schema)
  • 分类字段用枚举,数值字段加范围约束,决策字段语义写清楚
  • 用框架的结构化输出能力(generateObject / tool use / response_format)
  • schema 校验失败:带详细错误重试 3 次,失败回退人工复核
  • 记录 schema 违规日志,用来改进提示词和 schema
  • 多步工作流:维护跨步骤错误窗口,每步前注入最近 3 条错误
  • 错误反馈要具体(path + message + 收到的值),别只给"无效"
  • schema 别定死:留可选字段、版本化、联合类型应对演进
  • schema 校验拦截提示注入(执行前挡掉恶意内容)

本章小结

  • 结构化输出规范:确定性 schema 约束输出,可解析、类型安全、接得住下游。
  • schema 校验重试:3 次重试 + 详细反馈 + 跨步骤错误累积,输出质量提升 15%-45%。
  • 规范定义契约,重试保证契约不破。
  • 输出稳了,多 Agent 交接和自动化工作流才立得住。

下一章讲验证循环:输出就算符合 schema,内容对不对还得验。确定性评分器、渲染 UI 完成门、子 Agent 编译检查。

📑 Agent 模式实战:生产级 AI Agent 的工程模式

1 第 1 章 什么是 Agent 模式 2 第 2 章 规划-执行-观察:先想清楚,再动手 3 第 3 章 反思闭环:让 Agent 学会检查自己的作业 4 第 4 章 委派:让主 Agent 学会把活分出去 5 第 5 章 上下文预算治理:把 token 当成钱来管 6 第 6 章 上下文压缩与精选:装不下怎么办 7 第 7 章 上下文最小化:别让脏东西留在脑子里 8 第 8 章 记忆体系:让 Agent 记得住过去 9 第 9 章 学习沉淀:让 Agent 和团队一起变聪明 10 第 10 章 工具接口哲学:让 Agent 能用、好用、用得起 11 第 11 章 工具发现:让 Agent 在几百个工具里找到对的 12 第 12 章 执行环境:Agent 在哪动手、怎么动手 13 第 13 章 代码执行与沙箱:先写码,再跑码 14 第 14 章 结构化输出与契约:让 Agent 的输出能接住 15 第 15 章 验证循环:Agent 怎么检查自己的作业 16 第 16 章 评测基建:怎么系统地检验 Agent 17 第 17 章 可观测性:看见 Agent 在想什么、在干嘛 18 第 18 章 韧性工程:扛得住部分失效 19 第 19 章 威胁模型:先看风险长什么样,再谈防御 20 第 20 章 控制流隔离:把"谁做决定"和"谁执行"分开 21 第 21 章 权限与审批:谁有权干什么、谁点头 22 第 22 章 凭据与出口:Agent 手里的钥匙和门 23 第 23 章 多智能体信任:多个 Agent 之间怎么互信、怎么审计 24 第 24 章 反馈信号设计:给 Agent 的是信号,不是更大的提示词 25 第 25 章 评测驱动的改进:让 Agent 在真实使用和对抗测试里变强 26 第 26 章 强化学习:把反馈变成训练信号 27 第 27 章 复合式进化:让 Agent 系统越用越值钱 28 第 28 章 多智能体协调:让一群 Agent 一起干活不掉链子 29 第 29 章 模型路由:谁用哪个模型,怎么用得起 30 第 30 章 推理搜索结构:让 Agent 多想想,而不是一条道走到黑 31 第 31 章 控制谱系:从自动补全到完全自主的滑动条 32 第 32 章 团队与产品:把 Agent 变成团队资产,而不是个人玩具
← 返回本书大纲