获取结构化输出
为什么开发者需要结构化输出
LLM 默认输出自然语言——一段段的文字。但作为开发者,你通常需要的是程序能解析的数据:JSON、XML、或特定格式的文本。
❌ 模型回答:"根据分析,这段代码有三个问题。第一个是..."
✅ 模型回答:{"issues": [{"line": 15, "severity": "high", "message": "..."}]}
第一种你需要自己解析自然语言(痛苦且不可靠),第二种直接 JSON.parse() 就能用。
在 Prompt 中指定 JSON 格式
最基础的方式:在 Prompt 中明确告诉模型你要 JSON。
分析以下代码的问题,以 JSON 格式输出。
格式要求:
{
"issues": [
{
"line": <行号>,
"severity": "high" | "medium" | "low",
"description": "<问题描述>",
"fix": "<修复建议>"
}
],
"summary": "<总结>"
}
代码:
```python
def divide(a, b):
return a / b
关键技巧:
1. **给出完整的 JSON schema 示例**——不要只说"输出 JSON",要展示具体结构
2. **使用占位符说明每个字段**——`<行号>` 比直接写个数字更清晰
3. **限定枚举值**——`"high" | "medium" | "low"` 比"严重程度"更精确
## API 级别的 JSON Mode
主流 API 都提供了原生的 JSON 模式,比 Prompt 层面的要求更可靠:
### OpenAI
```python
response = client.chat.completions.create(
model="gpt-4o",
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": "你是一个输出 JSON 的助手。"},
{"role": "user", "content": "分析这段代码..."}
]
)
Claude
response = client.messages.create(
model="claude-sonnet-4-6",
messages=[...],
# Claude 通过 tool_use 或 prompt 指导实现结构化输出
)
Ollama(本地模型)
response = client.chat.completions.create(
model="llama3.1:8b",
response_format={"type": "json_object"},
messages=[...]
)
使用 JSON Mode 时,模型保证输出有效的 JSON。但 JSON Mode 不保证 schema 正确——它只保证语法有效,不保证字段和结构符合你的要求。所以你仍然需要在 Prompt 中指定 schema。
用 XML 作为输出格式
对于某些场景,XML 或类 XML 标签比 JSON 更实用:
请分析以下文本,用标签标注实体:
文本:张三在北京的字节跳动工作。
<analysis>
<person>张三</person>
<location>北京</location>
<organization>字节跳动</organization>
</analysis>
XML 风格的优点:
- 标签名本身就是语义,更直观
- 嵌套内容可读性好
- Claude 等模型对 XML 标签有很好的理解
Tool Use / Function Calling
最可靠的结构化输出方式是 Tool Use(工具调用)。你定义一个函数的参数 schema,模型的输出会严格遵循这个 schema:
tools = [{
"type": "function",
"function": {
"name": "report_code_issues",
"description": "报告代码中发现的问题",
"parameters": {
"type": "object",
"properties": {
"issues": {
"type": "array",
"items": {
"type": "object",
"properties": {
"line": {"type": "integer"},
"severity": {"type": "string", "enum": ["high", "medium", "low"]},
"description": {"type": "string"}
},
"required": ["line", "severity", "description"]
}
}
},
"required": ["issues"]
}
}
}]
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "分析这段代码..."}],
tools=tools,
tool_choice={"type": "function", "function": {"name": "report_code_issues"}}
)
Tool Use 的优势:
- Schema 验证:输出严格符合你定义的类型和结构
- 枚举约束:
enum字段限制了可选值 - 必填字段:
required保证关键字段不会缺失
Markdown 作为轻量级结构
不需要程序解析时,Markdown 是很好的"半结构化"格式:
请以如下 Markdown 格式输出分析结果:
## 概述
(一句话总结)
## 发现的问题
| # | 严重程度 | 描述 | 建议 |
|---|---|---|---|
| 1 | ... | ... | ... |
## 下一步行动
- [ ] 行动项 1
- [ ] 行动项 2
Markdown 表格和列表既方便人阅读,也相对容易用正则解析。
提高结构化输出可靠性的技巧
- 给完整示例:不要只描述格式,给一个完整的输出示例
- 在 System Prompt 中强调:
"你必须只输出 JSON,不要包含其他文字" - 使用 temperature=0:减少随机性,提高格式一致性
- 后处理:即使用了 JSON Mode,代码中也应该有错误处理——
try/catch解析失败的情况 - schema 验证:用 Zod(TypeScript)或 Pydantic(Python)验证输出是否符合预期
要点总结
- 结构化输出是 LLM 集成到应用的关键。 自然语言回复对程序没用,你需要 JSON、XML 或其他可解析的格式。
- 三种方式按可靠性排序:Tool Use > JSON Mode > Prompt 指令。 优先使用 Tool Use。
- 总是在 Prompt 中给出完整的 schema 和示例——即使使用了 JSON Mode。
- 加上错误处理。 结构化输出不是 100% 可靠的,代码中要有解析失败的 fallback。