结构化输出
1. 结构化输出的需求与挑战
为什么需要结构化输出
在生产环境中,大模型的输出需要被下游系统解析和处理:
用户输入 → LLM → 结构化输出 → 下游系统(API、数据库、前端)
↑
必须是可解析的格式
- API 集成:需要 JSON/XML 等标准格式
- 数据提取:需要精确的字段和类型
- 自动化流程:需要可靠的格式保证
- 多模型协作:需要统一的输出协议
QUESTION 面试高频:如何保证大模型输出符合指定格式? 三层保障策略:
- 提示层:在提示中明确格式要求 + 示例
- 约束层:使用 JSON Mode / constrained decoding
- 验证层:输出后用 schema 校验 + 重试
2. 提示层格式控制
格式模板设计
请按以下 JSON 格式输出结果:
{
"summary": "一句话摘要",
"key_points": ["要点1", "要点2"],
"sentiment": "positive/negative/neutral",
"confidence": 0.0-1.0
}
输入文本:{text}
Few-shot 格式示例
输入:今天天气真好,阳光明媚
输出:{"summary": "好天气", "sentiment": "positive", "confidence": 0.95}
输入:这个产品质量太差了
输出:{"summary": "产品质量差", "sentiment": "negative", "confidence": 0.9}
输入:{text}
输出:
格式控制技巧
| 技巧 | 说明 | 示例 |
|---|---|---|
| 明确格式声明 | 在提示中写明期望格式 | "以 JSON 格式输出" |
| 完整示例 | 提供完整的输入-输出对 | Few-shot 示例 |
| 类型约束 | 指定字段类型和范围 | "confidence: 0.0-1.0 的浮点数" |
| 枚举值 | 限制可选值 | "sentiment: positive/negative/neutral" |
| 格式锚点 | 用特殊标记固定格式 | \``json ... ```` |
| 负面示例 | 展示错误格式 | "不要输出:..." |
3. JSON Mode 与约束解码
JSON Mode
OpenAI 等模型提供 JSON Mode,保证输出为合法 JSON:
# OpenAI JSON Mode
response = client.chat.completions.create(
model="gpt-4",
response_format={"type": "json_object"},
messages=[{"role": "user", "content": prompt}]
)
Function Calling / Tool Use
通过函数声明隐式约束输出格式:
tools = [{
"type": "function",
"function": {
"name": "extract_info",
"parameters": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"skills": {"type": "array", "items": {"type": "string"}}
},
"required": ["name", "age"]
}
}
}]
约束解码(Constrained Decoding)
在 Token 生成阶段强制遵守语法约束:
| 方法 | 原理 | 工具 |
|---|---|---|
| JSON Schema | 按 Schema 约束 Token 选择 | Outlines、Guidance |
| 正则约束 | 按正则表达式约束输出 | LMQL |
| CFG 约束 | 按上下文无关文法约束 | Outlines |
| Logits 掩码 | 对不合法 Token 设 -inf | 自定义实现 |
# Outlines 示例
from outlines import models, generate
model = models.transformers("mistral-7b")
generator = generate.json(model, MySchema)
result = generator(prompt)
4. 结构化输出层级
可靠性梯度
纯提示格式要求 ← 最不可靠
↓
Few-shot 格式示例 ← 较可靠
↓
JSON Mode ← 可靠(格式合法,内容不一定)
↓
Function Calling ← 可靠(字段名和类型有保证)
↓
约束解码 (Constrained) ← 最可靠(严格按 Schema)
5. 输出验证与容错
Schema 验证
from pydantic import BaseModel
from typing import List, Optional
class ExtractionResult(BaseModel):
summary: str
key_points: List[str]
sentiment: str # positive/negative/neutral
confidence: float # 0.0-1.0
# 验证 + 自动重试
def safe_extract(text: str, max_retries: int = 3) -> ExtractionResult:
for attempt in range(max_retries):
try:
raw = llm_call(text)
return ExtractionResult.model_validate_json(raw)
except ValidationError:
# 在重试提示中加入错误信息
continue
raise ExtractionError("Failed after max retries")
常见输出问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 格式错误 | 模型未严格遵循 | JSON Mode / 约束解码 |
| 字段缺失 | 模型忽略部分要求 | 设为 required + 重试 |
| 类型错误 | 字符串/数字混淆 | Pydantic 校验 + 类型转换 |
| 幻觉内容 | 模型编造信息 | 约束枚举值 + 校验 |
| 截断输出 | 超出 max_tokens | 增大限制 / 分步输出 |
6. 特定格式输出策略
Markdown 格式
请用 Markdown 格式输出,包含:
- 一级标题作为主题
- 表格展示数据对比
- 代码块展示示例
- 无序列表列出要点
XML 标签格式
<analysis>
<summary>...</summary>
<entities>
<entity type="PERSON">...</entity>
</entities>
</analysis>
表格格式
| 字段 | 类型 | 说明 |
|------|------|------|
| name | string | 名称 |
| ... | ... | ... |