你让模型”从这封客户邮件里抽出关键事实并总结”,结果收到 600 字散文。订单号埋在第 2 段,SLA 违约时长在第 4 段还带着含糊措辞,问题类别是暗示而非明说。你的工单系统一个字段都消化不了。你追问”给我一个 JSON 对象”,2 秒就拿回干净的 JSON。模型一直能做结构化输出——你没要求,它就走默认散文,因为它的训练数据把这种回答标成”认真应答”。
最快修复:在 prompt 末尾加一个显式的 ## Output format 区块,放一份字面 schema,再写一条规则”只返回这个,不要散文”。如果输出要喂给代码,别再用纯 prompt 请求,直接用 API 的结构化输出模式(OpenAI 的 response_format 配 strict: true、Anthropic Structured Outputs、或 Gemini 的 responseSchema),这样模型是按你的 schema 解码的,根本产不出非法 JSON。
本文讲为什么显式格式规范是收益最高的 prompt 改动之一,以及怎么写出跨次稳定的 schema 块。
先对号入座
| 症状 | 最可能原因 | 跳到 |
|---|---|---|
| prompt 里完全没有格式区块 | 没写输出规范 | Step 1 |
| 你说”给个总结”,结果是散文 | 顺嘴提了格式,不是 schema | Step 1 + 2 |
| 输出”差不多结构化”,但 key 每次都变 | 给了示例,没写规则 | Step 4 |
| 拿到合法 JSON,外面套着”以下是您的 JSON:“ | 没有禁止开场白的规则 | Step 2 |
| 第 1 轮是 JSON,第 4 轮漂回散文 | 格式在上下文里漏掉了 | Step 5 |
| 语气和格式打架(“温暖” + “返回 JSON”) | 冲突线索 | Step 2 + 语气提示 |
| 代码解析你的 JSON,偶尔还是会挂 | prompt 级格式没有强制力 | Step 6 |
常见原因
1. 完全没有”输出格式”区块
你没提格式,就拿到默认——五段散文。模型没有任何反向信号。如何判断:你的 prompt 里没有 ## Output 区块、没有 schema 块、没有”按 … 返回”。
2. 顺嘴提了格式,不是 schema
“给个简短总结”不是格式。“返回 3 条 bullet、每条带粗体字段名”才是。如何判断:格式指令是一个短语,不是结构化规范。
3. 只给了示例,没写规则
你展示了一个结构化示例,指望模型照搬形状。它可能照搬,也可能”差不多结构”却不完全一致。如何判断:有示例,但没明写”严格按此形态”。
4. 冲突线索把它推向散文
“温暖、口语化”加上”返回 JSON”把模型往两个方向拉;它会偏向散文,因为温暖只能寄生在散文里。如何判断:语气和格式方向相反。
5. 后续轮次忘了格式
第 1 轮你写了 JSON。到第 4 轮模型漂回散文,因为你不再重复。对话越长,格式越容易从上下文里漏出去。如何判断:第 1 轮对,后面回退。
动手前先确认
- 想清楚下游消费者:人读、JSON 解析、数据库行、工单字段。
- 草拟理想形状:字段、顺序、类型、允许的取值。
- 机器消费就定一份严格 schema。
- 人读就定一个结构模板(标题、bullet 数量、最长字数)。
- 计划每轮都强制格式,不只是第 1 轮。
要收集的信息:当前 prompt 含任何格式暗示、你拿到的散文输出、你真正想要的格式样例、下游约束(必填 JSON key、长度上限、允许的枚举值),以及模型和任何 system prompt。
最短修复路径
Step 1:加一个显式的”输出格式”块
在 prompt 末尾加一个 ## Output format 标题,写上”只返回此 JSON(不要散文、不要解释)“,再贴一份带栅栏的 schema:
{
"order_number": "string, format ORD-XXXXX",
"issue_category": "billing | shipping | refund | other",
"sla_breach_minutes": "integer or null",
"customer_sentiment": "positive | neutral | negative"
}
显式块主导输出形状。把类型和允许取值写进每个字段里。"billing | shipping | refund | other" 对模型的约束远比光秃秃的 "category" 强。
Step 2:禁止格式外的散文
Output rules:
- Return only the JSON block. No prefix, no suffix.
- No "Here is your output:" preamble.
- No commentary after the closing brace.
- If the input is unparseable, return the schema with every field set to null.
这能挡掉”以下是您的 JSON:……”这种包装——正是它把解析器搞挂。“所有字段设为 null”那条规则能防止模型不返回形状、改成道歉一通。
Step 3:用代码栅栏加明确的语言标签
JSON、YAML、SQL 或代码,都用带语言标签的栅栏包起来(比如 ```json)。很多解析器,连模型自己,都把栅栏块当成受保护区,这能减少散文混进块里。
Step 4:人读输出给一个结构模板加一个示例
Output format:
- 3 bullets, each starting with **<field>:** in bold.
- Field names: Cause, Fix, Verify.
- Each bullet under 25 words.
- No introduction, no conclusion.
Example:
- **Cause:** Stripe webhook secret expired on Friday.
- **Fix:** Rotate in Stripe dashboard, paste into Vercel env var.
- **Verify:** Send a test webhook and confirm 200 in logs.
结构加一个示例,锚定形状比单独任何一个都稳。示例钉住确切字段名和 bullet 风格;规则钉住数量和长度。
Step 5:每一轮都钉住格式
聊天工作流里,把格式块在每个 prompt 末尾重贴一遍,或挪进 system prompt / 项目指令(ChatGPT 的自定义指令、Claude 的 Project、保存好的 system prompt)。近期性很关键:最新一轮说了算,所以只在第 1 轮写的格式,随着线程变长就会淡掉。
Step 6:API 工作流用结构化输出模式(不要只靠 prompt)
如果输出要喂给代码,prompt 级请求是最弱的一招。现在每个主流 API 都有一种模式,让模型按你的 schema 解码,于是它产不出非法 JSON。截至 2026 年 6 月:
- OpenAI Structured Outputs。 传
response_format: { type: "json_schema", json_schema: { name, schema, strict: true } }(Responses API 用text.format,字段相同)。配上strict: true,解码器在物理上就吐不出违反 schema 的 token。这是生产默认。更老的 JSON mode(response_format: { type: "json_object" })只保证 JSON 语法合法,不保证你的 key 或类型,OpenAI 现在把它当遗留功能。优先用json_schema严格模式。 - Anthropic Structured Outputs。 Claude Developer Platform 加了 Structured Outputs,可以要求响应符合一份 JSON schema,外加严格 tool use,让工具入参精确匹配 schema。在这个功能之前,标准技巧是强制调用一个唯一工具、把 schema 作为它的入参;那招仍能用,但原生 Structured Outputs 更干净。Claude Opus 4.7 和 Sonnet 4.6 都支持。
- Gemini。 在 generation config 里设
responseMimeType: "application/json",把 schema 传进responseSchema。如果是一组固定选项,用responseMimeType: "text/x.enum"配 enum schema。Gemini 3.1 Pro 支持。
机械强制远比任何 prompt 措辞都强,因为它作用在采样层,而不是事后的一条指令。
怎么确认已经修好
- 输出不用改就能被下游系统解析。
- schema 块外面没有散文。
- 同一个 prompt 跑 3 次,3 个输出形态完全一致。
- 程序化校验(JSON schema 校验器、Pydantic 模型、
JSON.parse)一次过。 - 同事看一个输出就能描述出格式。
如果还是没修好
- 切到结构化输出模式(Step 6),让 schema 被机械强制,而不是靠请求。
- 程序化校验输出,不合就把 schema 连同确切的校验错误一起重新 prompt;模型修一个具名错误,远比修一句含糊的”刚才不对”靠谱。
- 降低 temperature。格式稳定性会提升,因为模型会锁定最可能的 token 形态。
- 换一个模型。指令服从性各有差异,更小、更便宜的模型有时比为丰富 prose 调校过的大模型更能守住固定格式。
预防建议
- 默认规则:每个 prompt 都以一个显式的输出格式块结尾。
- 机器消费:在 API 层用结构化输出模式(严格
json_schema、Anthropic Structured Outputs、GeminiresponseSchema),别用 prompt 请求。 - 程序化校验输出;不通过就快速重 prompt,别事后解析再修补。
- 只在真正对话型任务里用 prose。
- 聊天工作流里,把格式钉进 system prompt / 项目指令。
- 审计生产 prompt:任何没有显式输出格式块的,都算风险。
常见问题
为什么模型无视”用 JSON 回答”,却服从一整块 schema? “用 JSON 回答”是个暗示;一份带字段名、类型和允许取值的字面 schema 是个目标。模型有了可对照的具体形状,你也有了可校验的具体对象。再加一条”只返回 JSON,不要散文”,它就不会把块包在一通评论里。
JSON mode 和 Structured Outputs 该用哪个?
在 OpenAI 上优先用 Structured Outputs(json_schema 配 strict: true)。遗留的 JSON mode(json_object)只保证 JSON 语法合法,不保证你的 key、类型或枚举被遵守,所以你还得校验加重试。截至 2026 年 6 月,严格 Structured Outputs 在解码时就保证符合 schema。
Claude 或 Gemini 能像 OpenAI 那样保证 schema 吗?
能。Anthropic 在 Claude Developer Platform 上线了 Structured Outputs,可让响应符合 JSON schema、并支持严格 tool use,Opus 4.7 和 Sonnet 4.6 都支持。Gemini 通过 responseMimeType: "application/json" 加 responseSchema(固定选项用 text/x.enum)强制 schema,Gemini 3.1 Pro 支持。
第 1 轮格式完美,后面漂回散文,为什么? 对话越长,格式越容易从上下文漏出去,最初那条指令的权重也越低。把格式块在每个 prompt 末尾重述,或挪进 system prompt / 项目指令,让它对每一轮都生效,而不是只对第一轮。
我的 JSON 是合法的,但模型总在前面加”以下是您的输出:”。 那种开场白会搞挂朴素解析器。加上明确规则:“只返回 JSON 块。无前缀、无后缀。闭括号后无评论。” 如果是 API 工作流,结构化输出模式会直接消掉开场白,因为只会吐出符合 schema 的 token。
为了格式更稳,该降 temperature 吗? 当格式稳定性比多样性更重要时,该降。低 temperature 会让模型锁定最可能的 token 形态,跨次保持结构一致。再配上结构化输出模式,保证最强。