结构化输出OutputParser和Tool
大模型默认输出自然语言,但经常需要结构化 JSON。两种方式:Output Parser(在 prompt 加格式说明 + 解析响应)和 Tool Call(绑定工具 schema,模型返回结构化 args)。推荐用 withStructuredOutput(schema),它底层自动选最可靠的方案(大多用 tool call)。两个不适合的场景:流式打印(需要 Output Parser 的 stream + parse)和非 JSON 格式(XML/YAML 用 XMLOutputParser)。Tool Call 的流式可以通过 tool_call_chunks 实现逐字打印。
# 结构化大模型输出:Output Parser 还是 Tool?
大模型默认输出自然语言,但很多场景需要结构化 JSON。两种方式实现:Output Parser 和 Tool Call。
# 方式一:Output Parser
原理:在 prompt 里加入格式说明,然后解析响应。
# JsonOutputParser
最简单,解析 JSON 格式。
import { JsonOutputParser } from '@langchain/core/output_parsers';
const parser = new JsonOutputParser();
// prompt 里加上格式说明
const question = `请介绍爱因斯坦的信息,以 JSON 格式返回。
${parser.getFormatInstructions()}`;
const response = await model.invoke(question);
const result = await parser.parse(response.content);
# StructuredOutputParser
可以定义具体字段和描述。
import { StructuredOutputParser } from '@langchain/core/output_parsers';
// 方式 1:用字段名和描述
const parser = StructuredOutputParser.fromNamesAndDescriptions({
name: '姓名',
birth_year: '出生年份',
nationality: '国籍',
famous_theory: '著名理论',
});
// 方式 2:用 Zod schema(支持复杂嵌套结构)
const schema = z.object({
name: z.string().describe('姓名'),
birth_year: z.number().describe('出生年份'),
awards: z.array(z.object({
name: z.string().describe('奖项名称'),
year: z.number().describe('获奖年份'),
})).describe('获得的奖项'),
});
const parser = StructuredOutputParser.fromZodSchema(schema);
# XMLOutputParser
非 JSON 格式,用专门的 parser。
import { XMLOutputParser } from '@langchain/core/output_parsers';
const parser = new XMLOutputParser();
const question = `请提取人物信息。\n${parser.getFormatInstructions()}`;
const response = await model.invoke(question);
const result = await parser.parse(response.content);
# 方式二:Tool Call
不定义 tool 的实现,只定义 schema,模型返回结构化 args。
const scientistSchema = z.object({
name: z.string().describe('科学家的全名'),
birth_year: z.number().describe('出生年份'),
nationality: z.string().describe('国籍'),
fields: z.array(z.string()).describe('研究领域列表'),
});
const modelWithTool = model.bindTools([{
name: 'extract_scientist_info',
description: '提取和结构化科学家的详细信息',
schema: scientistSchema,
}]);
const response = await modelWithTool.invoke('介绍一下爱因斯坦');
const result = response.tool_calls[0].args; // 结构化数据
# 推荐:withStructuredOutput
底层自动选最可靠的方案(大多用 tool call),直接返回解析好的对象。
const schema = z.object({
name: z.string().describe('姓名'),
birth_year: z.number().describe('出生年份'),
nationality: z.string().describe('国籍'),
fields: z.array(z.string()).describe('研究领域'),
});
const structuredModel = model.withStructuredOutput(schema);
const result = await structuredModel.invoke('介绍一下爱因斯坦');
// result 已经是解析好的对象,不需要再 parse
# 两个不适合 withStructuredOutput 的场景
# 1. 流式打印
withStructuredOutput 的流式是等全部完成再返回,不能逐字打印。
用 Output Parser 实现流式:
const stream = await model.stream(`${prompt}\n${parser.getFormatInstructions()}`);
let fullContent = '';
for await (const chunk of stream) {
process.stdout.write(chunk.content); // 逐字打印
fullContent += chunk.content;
}
const result = await parser.parse(fullContent); // 最后解析
用 Tool Call 也能流式(通过 tool_call_chunks):
const stream = await modelWithTool.stream(prompt);
for await (const chunk of stream) {
if (chunk.tool_call_chunks?.length > 0) {
process.stdout.write(chunk.tool_call_chunks[0].args); // 逐字打印参数
}
}
# 2. 非 JSON 格式(XML / YAML)
Tool Call 只能返回 JSON,XML/YAML 需要用 Output Parser。
# 三种方式对比
Output Parser:prompt 加格式说明 + parse 响应 → 灵活,支持 XML/YAML/JSON
Tool Call:绑定工具 schema,模型返回 args → 可靠,模型训练保证
withStructuredOutput:自动选最优方案 → 推荐,但不支持流式打印和非 JSON
# 要点
- 结构化输出的本质 — 在 prompt 加格式说明,或利用 tool call 的参数约束
- 推荐 withStructuredOutput — 底层自动选最优方案,直接返回解析好的对象
- Output Parser 适合流式场景 —
stream()逐字打印 + 最后parse() - Output Parser 适合非 JSON 格式 — XML/YAML 等用专门的 parser
- Tool Call 的流式 — 通过
tool_call_chunks实现逐字打印效果 - Zod 描述复杂结构 — 和 Tool 的参数描述一样,用 zod schema 定义
编辑 (opens new window)
上次更新: 2026/06/17, 14:57:34