知识点思维导图
29 个知识节点
Prompt Engineering(07) - 结构化输出与格式约束
读完后,你应能完成以下任务:
- 绘制“Prompt Engineering(07) - 结构化输出与格式约束 / 为什么格式控制这么重要”的关键对象与数据流,解释“内容没问题,但你的程序根本没法用——它要的是 {"情感": "正面", "关键词": ["服务", "价格"]} 这种能直接 json.loads 的东西,结果拿到一段大白话,还得自己写一堆字符串处理去抠。”,并用源码位置、日志或 Trace 标注证据。
- 为“Prompt Engineering(07) - 结构化输出与格式约束 / 核心思路:说明 + 示例,双管齐下”设计正常与异常输入,验证“明确的格式说明:用文字把你要的格式、字段、类型讲清楚。 -> 一个具体的格式示例:直接给一个长成什么样的样例(这就是第 05 章的 few-shot)。”,输出首个偏差位置与回归测试结果。
- 实现“Prompt Engineering(07) - 结构化输出与格式约束 / 让它「只输出 JSON,别说废话」的技巧”的最小代码或配置,检验“给纯净示例:示例里就只有 JSON,不带任何多余文字,模型会模仿。 -> 兜底——代码侧别全信:即便如此,模型偶尔仍会加东西。”,输出命令、结果与 Diff,并说明不适用边界。
本章目标:让模型稳定输出 JSON、表格、Markdown 等指定格式,方便你直接复制使用、或让程序解析。
一、为什么格式控制这么重要
你写了个小程序,想让模型帮你把用户评论分析成结构化数据,再存进数据库。你这样问:
分析这条评论的情感和关键词:这家店服务很好,就是有点贵。
模型回你:
这条评论整体偏正面。用户对服务表示满意("服务很好"),但对价格有些不满("有点贵")。
关键词包括:服务、价格。情感倾向为正面偏中性。
内容没问题,但你的程序根本没法用——它要的是 {"情感": "正面", "关键词": ["服务", "价格"]} 这种能直接 json.loads 的东西,结果拿到一段大白话,还得自己写一堆字符串处理去抠。
只要输出要给程序用、要批量处理、要填进表格,你就必须控制格式。 这一章讲的就是怎么让模型「按规矩出牌」。
二、核心思路:说明 + 示例,双管齐下
让格式稳定,靠两件事配合:
- 明确的格式说明:用文字把你要的格式、字段、类型讲清楚。
- 一个具体的格式示例:直接给一个长成什么样的样例(这就是第 05 章的 few-shot)。
文字说明负责讲规则,示例负责「锁死」长相。 两个一起上,比单用任何一个都稳。
来改造上面的例子:
分析下面这条评论,输出 JSON,包含三个字段:
- sentiment:情感,取值只能是 "正面"/"负面"/"中性" 之一
- keywords:关键词数组,字符串列表
- summary:一句话总结,不超过 20 字
输出格式示例:
{"sentiment": "正面", "keywords": ["质量", "物流"], "summary": "整体满意,物流给力"}
评论:这家店服务很好,就是有点贵。
模型这次会稳定输出:
{"sentiment": "正面", "keywords": ["服务", "价格"], "summary": "服务好但价格偏贵"}
字段、类型、取值范围全都对齐了。
三、让它「只输出 JSON,别说废话」的技巧
模型有个老毛病:爱在 JSON 前后加客套话,比如:
好的,这是您要的 JSON:
```json
{"sentiment": "正面"}
```text
希望对您有帮助!
这些多余文字会让 json.loads 直接报错。怎么治?几招叠加用:
- 明确下命令:
只输出 JSON,不要任何解释、前言或结尾文字,不要用 markdown 代码块包裹。 - 指定第一个字符:
你的回复必须以 { 开头,以 } 结尾。 - 给纯净示例:示例里就只有 JSON,不带任何多余文字,模型会模仿。
- 兜底——代码侧别全信:即便如此,模型偶尔仍会加东西。正确做法是程序里也做一层提取容错(本章 Demo 演示的就是这个),而不是指望提示词 100% 干净。
记住:提示词能把「翻车概率」降到很低,但要彻底稳,得「提示词约束 + 代码侧容错」两头都做。
四、其它常用格式怎么要
4.1 要表格(Markdown)
请用 Markdown 表格输出,包含「城市、人口、特色」三列,不要表格以外的任何文字。
4.2 要固定结构的 Markdown 报告
请按以下结构输出,每部分用二级标题:
## 摘要
(一段话)
## 关键发现
(3 条要点)
## 建议
(2-3 条)
4.3 要 CSV
输出 CSV,第一行为表头:name,age,city。用英文逗号分隔,不要多余空格,不要其它说明文字。
通用心法:你越是把「要什么、不要什么」说死,结果越稳。 尤其要主动声明「不要 XX」(不要解释、不要代码块、不要前言),模型很吃这套。
五、常见翻车与修复
| 翻车现象 | 原因 | 修复方法 |
|---|---|---|
| JSON 前后多了解释文字 | 没禁止,或模型习惯性客套 | 加「只输出 JSON,不要任何其它文字」+ 代码侧提取 |
被 \`\`\`json 代码块包裹 |
模型默认习惯 | 加「不要用 markdown 代码块包裹」+ 代码侧剥离 |
| JSON 不合法(缺引号、多逗号、中文引号) | 模型生成失误 | 给清晰示例;代码侧 try/except 捕获并重试 |
| 字段名/结构每次不一样 | 没给明确示例 | 给一个完整的格式示例锁定结构 |
| 字段值类型不对(数字变字符串) | 没说明类型 | 在说明里写清每个字段的类型和取值范围 |
| 中文标点混进 JSON("" 、) | 模型中文语境下手滑 | 明确要求「所有标点用英文半角」 |
最关键的一条:对 JSON 这种要程序解析的输出,永远在代码侧再做一层提取和容错。 提示词负责降低翻车率,代码负责兜底,缺一不可。
六、一个可稳定解析的 JSON 提示词范例
把前面所有技巧整合,做一个「从简历文本抽取结构化信息」的完整范例:
你是简历信息抽取助手。从下面的简历文本中抽取信息,严格按要求输出 JSON。
字段要求:
- name:姓名,字符串
- years_experience:工作年限,整数(无法确定填 0)
- skills:技能,字符串数组
- highest_education:最高学历,取值 "高中"/"大专"/"本科"/"硕士"/"博士" 之一
输出要求:
- 只输出一个 JSON 对象,以 { 开头、} 结尾。
- 不要任何解释、前言、结尾文字,不要用代码块包裹。
- 所有标点使用英文半角。
输出示例(仅示意格式):
{"name": "张三", "years_experience": 5, "skills": ["Java", "MySQL"], "highest_education": "本科"}
简历文本:
李四,硕士毕业,从事后端开发 3 年,熟悉 Python、Go 和 Docker。
模型会稳定输出:
{"name": "李四", "years_experience": 3, "skills": ["Python", "Go", "Docker"], "highest_education": "硕士"}
这个范例同时用上了:字段说明(含类型和取值范围)、缺省值规则、明确的「只输出 JSON」约束、纯净示例。这是生产环境里抽取任务的典型写法。
七、常见错误
- 只用文字描述格式,不给示例:模型对「长什么样」理解不一,结构容易飘。
- 没说「不要多余文字」:模型默认爱加客套话和代码块,把 JSON 包起来。
- 字段类型/取值没说清:年限一会儿是数字一会儿是字符串,枚举值五花八门。
- 完全指望提示词,代码侧不做容错:偶尔一次格式翻车就让整个程序崩。
- 示例里带了多余文字:示例不纯净,模型有样学样也跟着加废话。
- JSON 里混了中文标点:没要求英文半角,模型在中文语境下写出全角引号导致解析失败。
八、最佳实践
- 说明 + 示例双管齐下:文字讲规则,示例锁长相。
- 把字段定义写死:每个字段的名字、类型、取值范围、缺省值都交代清楚。
- 主动声明「不要什么」:不要解释、不要前言、不要代码块——模型很听这种话。
- 示例保持纯净:示例里只放目标格式,不带任何多余文字。
- 代码侧永远兜底:要程序解析的输出,一定加提取 + try/except 容错,必要时重试。
- JSON 强制英文半角标点:避免全角符号导致解析失败。
九、本章小结
- 只要输出要给程序用或批量处理,就必须控制格式。
- 稳定格式靠两件事:明确的格式说明 + 一个具体示例,双管齐下。
- 想要纯净 JSON:明确「只输出 JSON、不要多余文字、不要代码块」,并指定以
{开头。 - 提示词能大幅降低翻车率,但代码侧的提取与容错是必须的兜底。
- 核心心法:把「要什么、不要什么」说到死,再给个示例锁住——剩下的交给代码兜底。
下一章我们讲迭代与调试——当提示词没达到预期时,怎么科学地一步步把它「改」好,而不是靠玄学瞎试。
十、配套 Demo
见 提示词工程-demo/07-demo/:一个纯 Python 标准库脚本 parse_demo.py,演示当模型返回「带多余文字的 JSON」时,代码侧如何稳健地提取并解析(含异常处理),直接 python3 parse_demo.py 即可运行。README 里还给出了「能稳定产出可解析 JSON」的提示词写法。
十一、动手实践:demo:代码侧稳健解析模型返回的 JSON
这个 Demo 有一个可直接运行的 Python 脚本,演示第 07 章的核心兜底思想: 别指望提示词 100% 产出干净 JSON,代码侧一定要做提取 + 容错。
11.1 直接运行
python3 parse_demo.py
只用 Python 标准库(json + re),不联网、不装包。
11.2 脚本干了什么
parse_demo.py 内置了 5 段「模型可能返回的、不干净的响应」,逐个演示如何救回来:
| 样例 | 模拟的翻车情况 | 处理结果 |
|---|---|---|
| 1 | JSON 前后裹着客套话 | ✅ 成功提取 |
| 2 | 被 \`\`\`json 代码块包裹 |
✅ 剥离后成功 |
| 3 | 干净 JSON(理想情况) | ✅ 正常解析 |
| 4 | 混了中文全角标点 “”,: |
✅ 清洗后成功 |
| 5 | 根本没有 JSON | ✅ 优雅报错,不崩溃 |
核心步骤(见脚本注释):
- 剥代码块:正则去掉
\`\`\`json/ ``` 围栏。 - 定位 JSON:靠花括号计数找出最外层
{...}(比简单截取更稳,能正确处理嵌套)。 - 清洗标点:把全角
“”,:换成半角,救回中文语境下的手滑。 - 解析 + 兜底:
json.loads包在try/except里,失败也返回清晰原因而不是直接崩。
配套:能稳定产出可解析 JSON 的提示词写法
代码兜底是「下半场」,提示词约束是「上半场」,两头都做才最稳。下面这个提示词把第 07 章的技巧都用上了,可直接复制:
你是信息抽取助手。从下面的文本中抽取信息,严格按要求输出 JSON。
字段要求:
- sentiment:情感,取值只能是 "正面"/"负面"/"中性" 之一
- keywords:关键词数组,字符串列表
- summary:一句话总结,不超过 20 字
输出要求:
- 只输出一个 JSON 对象,以 { 开头、以 } 结尾。
- 不要任何解释、前言、结尾文字。
- 不要用 markdown 代码块包裹。
- 所有标点使用英文半角。
输出示例(仅示意格式):
{"sentiment": "正面", "keywords": ["质量", "物流"], "summary": "整体满意物流给力"}
文本:
这家店服务很好,就是有点贵。
这套写法做了四件事,正好对应第 07 章:
- 字段定义写死(名字、类型、取值范围);
- 明确「只输出 JSON、不要多余文字、不要代码块」;
- 强制英文半角标点;
- 给一个纯净示例锁住格式。
11.3 你应该带走的结论
- 提示词约束能把翻车概率压到很低,但不能保证 100%。
- 所以代码侧的提取 + 容错是必须的,就像本脚本演示的那样。
- 上半场(提示词)+ 下半场(代码兜底),才是生产环境里稳定拿到结构化数据的正确姿势。
十二、总结
- 为什么格式控制这么重要:内容没问题,但你的程序根本没法用——它要的是 {"情感": "正面", "关键词": ["服务", "价格"]} 这种能直接 json.loads 的东西,结果拿到一段大白话,还得自己写一堆字符串处理去抠。
- 核心思路:说明 + 示例,双管齐下:明确的格式说明:用文字把你要的格式、字段、类型讲清楚。 -> 一个具体的格式示例:直接给一个长成什么样的样例(这就是第 05 章的 few-shot)。
- 让它「只输出 JSON,别说废话」的技巧:明确下命令: -> 指定第一个字符: -> 给纯净示例:示例里就只有 JSON,不带任何多余文字,模型会模仿。 -> 兜底——代码侧别全信:即便如此,模型偶尔仍会加东西。
- 其它常用格式怎么要:通用心法:你越是把「要什么、不要什么」说死,结果越稳。
- 常见翻车与修复:| JSON 前后多了解释文字 | 没禁止,或模型习惯性客套 | 加「只输出 JSON,不要任何其它文字」+ 代码侧提取 |
- 一个可稳定解析的 JSON 提示词范例:这个范例同时用上了:字段说明(含类型和取值范围)、缺省值规则、明确的「只输出 JSON」约束、纯净示例。
学完自测
选择所有正确答案;提交后逐项核对判断依据。