如何让 AI 输出指定格式的内容,比如 JSON、表格、Markdown?
- 标签:Prompt、格式控制
🏛 业务架构师
让 AI 稳定输出指定格式(JSON/表格/Markdown),我按"四层保障"讲,从软到硬:
第一层·提示词约束(基础):
- 明确给出格式模板与字段定义("输出 JSON,字段:summary 字符串、score 数字 0~100");
- 给 1~2 个标准输出示例(Few-shot 锁格式比文字描述有效得多);
- 声明"不要输出任何格式外的内容(包括解释性文字和 markdown 代码块标记)"——高频坑:模型喜欢把 JSON 包在代码块标记里输出,要显式禁止。
第二层·结构化输出能力(机制保证):
- 主流模型已支持约束解码(JSON Schema / Structured Outputs)——解码层面保证 100% 合法,2026 年生产系统的默认选择;
- Function Calling 天然返回 JSON——把内容生成封装成"工具参数生成"是曲线救国的稳定方案。
第三层·解析校验+重试(工程闭环):Pydantic/JSON Schema 校验输出——不合法就带着具体错误信息("字段 score 缺失")自动重试一次,模型的自纠错成功率很高;最终失败走兜底(默认值/转人工)。
第四层·业务规则校验:格式合法≠内容合理——枚举值、数值区间、必填逻辑再校验一层;表格类检查列完整性,Markdown 检查标题层级。
成本提醒:格式约束会增加少量 token(Schema 描述),但相比"解析失败重跑全链路"便宜得多。我的团队规范:一切对接程序的输出必须走"结构化输出+校验重试"双保险——纯提示词约定格式的方案不允许进生产,这条纪律消灭了 90% 的解析类线上事故。
🏗 系统架构师
让 AI 稳定输出指定格式(JSON/表格/Markdown),我按可靠度递增给四层方案:
1. Prompt 约束(基础层,~90% 合规):
- 明确格式说明 + 严格一致的示例(示例的约束力 > 文字描述);
- "只输出 JSON,不要 markdown 代码块包裹、不要解释文字"——负向排除高频杂症;
- 结构简单时够用,复杂结构仍会漂移。
2. 结构化输出 API(根治层,~100% 合法):
- OpenAI Structured Outputs / 各家
response_format+ JSON Schema:受限解码保证语法合法与 Schema 符合; - 开源自托管等价物:vLLM guided decoding / outlines——生产默认。
3. 输出解析与修复(防御层):
- Pydantic/JSONSchema 校验失败 → auto-fix:原输出 + 错误信息回喂重生成(限 2~3 次);
- 宽容解析:剥代码块围栏、修复尾逗号/单引号等常见瑕疵后重试解析;
- 仍失败 → 降级(默认值结构 / 兜底响应 / 人工队列)。
4. 架构层设计(上游减负):
- 复杂任务拆两步:自由生成内容(质量优先)→ 单独一轮"格式化"调用(格式优先)——两阶段比一步到位稳定得多;
- 温度调低(0~0.3);字段设计避免过深嵌套与强枚举(约束越死模型越拧巴);
- 表格类输出:Markdown 表格比 JSON 更符合模型先验(训练语料里海量 Markdown 表)——选模型擅长的格式,而不是你顺手的格式。
一句话:格式稳定 = 受限解码保合法 + 校验重试保符合 + 两阶段生成保复杂结构——三层叠加才是生产级。
💻 全栈开发专家
让 AI 稳定输出指定格式(JSON/表格/Markdown),按可靠度递减五招:
1. 结构化输出 API(首选,治本):
- OpenAI Structured Outputs / 各家 json_schema 模式:解码层约束,100% 合法 JSON;
- LangChain:
with_structured_output(PydanticModel);Spring AI:.call().entity(Order.class)。
java
record Answer(String conclusion, List<String> reasons) {}
Answer a = chatClient.prompt().user(q).call().entity(Answer.class);2. 格式模板 + 少量示例:给字面模板而非描述,配 1~2 个输出示例:
严格按以下 Markdown 输出:
## 结论
(一句话)
## 明细
| 项目 | 结果 |
|---|---|
(行数按数据而定)
模板之外不要输出任何文字。3. 温度与提示强化:temperature=0;「只输出 JSON,不要 markdown 代码块、不要解释」这类显式排除(模型爱给 JSON 套围栏、加前后废话,明说要禁止)。
4. 解析容错与重试(兜底层):
python
text = resp.content
m = re.search(r'\{.*\}', text, re.S) # 抽首个JSON块,剥离围栏和废话
try: return json.loads(m.group())
except JSONDecodeError:
return fix_chain.invoke({"bad": text, "error": "invalid json"}) # 报错回喂重生成5. 事后校验:schema 校验(字段/类型/枚举)+ 业务规则(范围/引用存在),不合格打回重生成或人工。
格式专项经验:表格要给列名和示例行(列名模型会自由发挥);Markdown 层级用示例锁定;JSON 日期/数字格式在 schema description 里写死(「yyyy-MM-dd」);嵌套深的 schema 拆两次调用,小模型一次吃不下。