第 8 章:结构化输出:让 AI 返回稳定 JSON
本章目标
这一章解决一个常见问题:模型输出是自然语言,但应用经常需要稳定的结构化数据。
本章效果
右侧“结构化分析”面板展示了 /api/analyze-question 的结果。真实模型模式下,这部分由 withStructuredOutput 和 Zod Schema 约束。

为什么需要结构化输出
比如我们想让模型判断用户问题类型:
{
"intent": "policy_question",
"keywords": ["报销", "发票"],
"needHuman": false
}
如果只靠 Prompt 让模型“请返回 JSON”,很容易出现:
- JSON 外面多一句解释
- 字段缺失
- 字段类型错误
- 逗号或引号不合法
结构化输出就是为了解决这个问题。
用 Zod 定义输出 Schema
import * as z from "zod";
export const QuestionAnalysisSchema = z.object({
intent: z.enum(["policy_question", "how_to", "troubleshooting", "other"]),
keywords: z.array(z.string()),
needHuman: z.boolean(),
reason: z.string()
});
export type QuestionAnalysis = z.infer<typeof QuestionAnalysisSchema>;
绑定结构化输出
不同模型供应商对结构化输出支持程度不同。LangChain.js 提供统一能力时,可以这样组织:
const model = await createChatModel();
const structuredModel = model.withStructuredOutput(QuestionAnalysisSchema);
const analysis = await structuredModel.invoke([
{
role: "system",
content: "你负责分析用户问题类型,并返回结构化结果。"
},
{
role: "user",
content: "报销需要什么发票?"
}
]);
console.log(analysis.intent);
在知识库项目中的用途
结构化输出可以用在很多地方:
- 判断问题意图
- 提取关键词
- 判断是否需要人工客服
- 生成文档标签
- 识别用户是否在要求越权信息
- 判断答案是否足够可信
例如:
export const AnswerQualitySchema = z.object({
supportedByContext: z.boolean(),
confidence: z.enum(["low", "medium", "high"]),
missingInfo: z.array(z.string()),
suggestedFollowUp: z.string().optional()
});
前端渲染
结构化输出不一定直接展示给用户,但可以驱动 UI:
{analysis.needHuman && (
<button>转人工处理</button>
)}
{analysis.keywords.map((keyword) => (
<span key={keyword}>{keyword}</span>
))}
实战任务
完成:
- 定义
QuestionAnalysisSchema - 创建
/api/analyze-question - 输入用户问题,返回意图、关键词、是否需要人工
- 在 Chat 页面发送前调用一次分析接口
常见坑
不要把结构化输出当成绝对可靠。它比普通文本稳定,但仍然要做 Zod 校验、异常处理和兜底。
不要让结构化输出字段太复杂。字段越多,越容易错。
不要为了所有回答都强行 JSON 化。面向用户的长回答仍然适合自然语言。
本章小结
结构化输出让模型结果可以被程序消费。下一章进入工具调用,让模型开始调用真实函数。