前两节解决了"怎么把指令说清楚"和"怎么管理上下文",本节解决第三个核心问题:怎么让模型稳定地输出你想要的格式。
实际开发中,格式不稳定是最常见的落地障碍:
1.,有时用 -,下游解析直接崩溃格式问题的本质:模型的默认目标是"自然表达",而工程系统的目标是"可解析的确定性"。输出格式化技术就是弥合这两者的桥梁。
在提示词中明确、具体、带示例地声明格式。三个要点:
1. 格式声明要"封闭"——不只说要什么,还要说不要什么:
请严格按以下JSON格式输出,不要输出任何JSON以外的内容, 包括解释、前言、markdown代码块标记: {"summary": "一句话总结", "sentiment": "正面|负面|中性", "confidence": 0.0-1.0}
2. 用示例锚定格式——一个格式示例胜过十句格式描述(few-shot的格式变体):
输入:这家店服务太差了 输出:{"sentiment": "负面", "keyword": "服务"} 现在处理:输入:物流速度快,包装也很用心 输出:
3. 分隔符隔离输出区——用明确的起止标记圈定解析范围:
将结果写在 <answer> 和 </answer> 标签之间。
下游即使遇到前言废话,也可以用正则直接提取标签内容。
主流推理服务提供了比提示词更强的硬约束:
| 能力 | 原理 | 适用 |
|---|---|---|
| JSON Mode | 强制输出合法JSON | 只需"是JSON"的场景 |
| Function Calling / Tool Use | 按函数签名生成参数 | 结构固定的工具调用 |
| 结构化输出(Schema约束) | 按JSON Schema逐token约束解码 | 字段、类型、枚举都要锁死 |
from pydantic import BaseModel class Analysis(BaseModel): summary: str sentiment: str # 要求枚举时用Literal["正面","负面","中性"] confidence: float resp = client.chat.completions.create( model="...", messages=[...], response_format={"type": "json_schema", "json_schema": {"schema": Analysis.model_json_schema()}})
Schema约束在解码层面保证合法,是生产系统首选;提示词约束作为兜底与补充(部分模型/服务不支持时)。
即便有前两层,生产系统仍要在解析端做防御:
import json, re def robust_parse(text: str) -> dict: # 1) 剥离代码块标记与前后噪音 m = re.search(r"\{.*\}", text, re.S) if not m: raise ParseError("未找到JSON结构") # 2) 尝试解析,失败则修复常见问题后重试 try: return json.loads(m.group()) except json.JSONDecodeError: fixed = m.group().replace("'", '"').rstrip(",\n }") + "}" return json.loads(fixed) # 3) 仍失败 → 触发重试请求或降级路径
三层的分工哲学:指令层降低错误率,Schema层消除结构错误,解析层兜住最后的意外。缺任何一层,系统都会在某个流量峰值下雪崩。
表格是最容易走形的格式——列对不齐、行数漂移。稳定技巧:
输出一个markdown表格,恰好包含4列:指标、当前值、目标值、差距。 共5行数据行,不要合计行。表头固定为:| 指标 | 当前值 | 目标值 | 差距 |
关键是把表头直接写进提示词,模型只需填行,不做结构决策。
要求模型产出带层级的大纲时,先让它输出大纲、确认后再展开(两步法),比一次性生成全文的结构稳定得多:
第一步提示:只输出文章大纲(H2/H3两级),共5个H2,每个H2下2-3个H3。 第二步提示:基于以下已确认大纲,仅展开第2节正文,600字。
一个常被忽视的真相:过强的格式约束会轻微损失内容质量——模型的注意力被格式占据后,思考空间被压缩。化解方法:
Q1:模型总是加"好的,以下是……"的前言怎么办?
三招叠加:提示词写明"直接输出结果,不要任何前言后语";system消息而非user消息承载格式要求;解析层用分隔符提取。单独任何一招都不完全可靠。
Q2:JSON里出现注释或尾逗号导致解析失败?
这是模型常见习惯(训练语料里代码常带注释)。解析层做修复(删注释、去尾逗号)是标准做法;Schema约束下则不会发生。
Q3:要求输出恰好N条,模型经常给N±1条?
显式编号:"输出恰好3条,编号1. 2. 3.",并在解析层校验数量,不足则补发请求、超出则截断。数量越精确要求越要在提示词中重复强调。
Q4:结构化输出和Function Calling用哪个?
目的决定选择:要调用工具/函数 → Function Calling;只要结构化数据 → Schema约束。两者底层机制相似,混用会让代码更难维护。
Q5:为什么同一个提示词,不同模型格式表现差异巨大?
格式遵循能力是模型训练重点之一,各模型差异客观存在。换模型后必须回归测试格式稳定性,不能假设提示词可移植。
本节建立了输出格式化的三层防御体系:指令层用封闭声明、示例锚定与分隔符降低错误率;能力层用JSON Mode/Schema约束从解码机制上保证合法;解析层用容错提取兜住意外。同时要记得格式与质量的权衡——"先自由思考、再格式封装"的两步法是高级用法。至此,第2章的指令、上下文、格式三大核心技术讲完,下一章进入真实应用场景的实战。
📌 实践建议:找一段你正在使用的"要求输出JSON"的提示词,按本节三层体系改造一遍,用30条真实输入对比改造前后的解析成功率。