跳到主要内容

让输出能被程序接住 — 列表、JSON、YAML 与把模型当控制流(程序流程往哪走的方向盘)

这一章讲三件事: 为什么「让它给个清单」这件小事,放进程序里处处是坑; 从自由文本到被校验的结构化数据,中间要升级几次; 以及一个越界但极有用的玩法:让模型替你的程序做一部分判断。 对应原书第 3 章前半,是五原则里「定格式」的全部展开。

1. 这一章讲什么

第 01 章把「定格式」作为五原则之一立了起来:输出不是给人看的,是给程序读进代码的。这一章回答的是工程问题:到底怎么定,程序才接得住?

主走查:让模型给一份迪士尼角色清单。 需求简单到近乎无聊——但这正是好走查该有的样子:我们会看着它从一份「读起来挺好」的自由文本,一步步变成一份程序敢直接消费、且能被自动校验的数据。每一次升级都解决上一次的某一种崩溃方式。

2. 顶层全景:四级台阶

第 0 级 自由文本:读起来好,程序读不了
│ 毛病:数量随机、带开场白、格式漂移
第 1 级 受控列表:条数、符号、内容都钉死
│ 毛病:嵌套结构表达不了,还得靠正则硬抠
第 2 级 JSON:程序原生可读,错一个字就解析失败(=免费报警)
│ 毛病:转义噪音多,写提示时不直观
第 3 级 YAML + 校验器:人能读、程序能验,模型还能兼职做判断

└─ 再往外一步:它还能当任意格式之间的转换器(翻译/摘要/风格)

图说:每一级台阶都是被上一级的崩溃方式逼出来的。

3. 核心原理

3.1 第 0 级:一份「读起来挺好」的清单,程序为什么接不住

从随手提示开始:

输入:生成一份迪士尼角色的清单。

输出:好的,这里有一些受欢迎的迪士尼角色:
1. Mickey Mouse
2. Minnie Mouse
……
30. Bagheera(The Jungle Book)

书里逐条列了这份输出的四个毛病1:它自作主张给了 30 条,用的是编号而不是你下游代码要的符号;开头夹了一句「好的,这里是……」的开场白;有的角色后面带着电影名括号、有的不带;整条清单没有任何筛选——它给的是「有名的」,不一定是「你要的」。

人读这份清单毫无障碍,程序读它处处是雷:按符号切分会错位,删开场白要多写一步,括号里的电影名混进了角色名。自由文本的信息是溢出的,程序要的是不多不少。

3.2 第 1 级:把清单钉死——以及一个必须知道的警告

升级后的提示把四个窟窿逐一堵上2:

输入:生成一份 5 个男性迪士尼角色的项目符号清单。
每行只写角色名。
永远不要在角色后面带电影名。
只返回角色,不要任何评论。
示例清单如下:
* Aladdin
* Simba
* Beast
* Hercules
* Tarzan

输出:* Woody
* Buzz Lightyear
* Stitch
* Jack Sparrow
* Prince Charming

对照第 01 章:这是「定格式」和「给例子」两条原则的直接组合——数量、符号、内容范围、示例,四样全钉死。

但书里有一个必须记住的警告:让它给固定条数,它并不保证照办。 你说 10 个小标题,它可能给 8 个。所以下游代码要么校验条数,要么容忍变长——「说了」不等于「会做到」,程序要自己兜底3

清单再复杂一点(比如文章大纲:标题下有子标题),就超出平铺列表的能力了。书里的做法是先让模型产出带缩进的层级文本,再用正则表达式(regular expression——一种用模式串在文本里做匹配提取的工具,比如 \* (.+) 表示「星号开头的那一行,把后面的内容抓出来」)逐行抠出标题和子标题,组装成字典4。这条路走通是走通了,但模式规则越写越繁琐,而且格式稍一变就全线失效——这正好把我们逼向下一级。

3.3 第 2 级:JSON——让「解析失败」替你报警

JSON 第 01 章见过:程序间交换数据的通用文本格式。书里给的三条提示军规,值得原文照背5:

你必须遵守以下原则:
* 只返回合法 JSON
* 永远不要带反引号 `
* 你的输出会被 json.loads() 解析,因此必须是合法 JSON

为什么值得这样三令五申?因为最常见的两种翻车书里都演示了:输出被包在一对三反引号里(```json ……),或者前面夹一句「Sure here's the JSON:」——两种都会让直接解析当场报错6。把「会被 json.loads() 解析」这句话写进提示,等于告诉模型它面对的是一个不留情面的读者。

这里要引入本章的一个承重词:解析(parse),就是把一段文本按格式规则拆开、变成程序里的数据结构的过程。JSON 的价值不止「程序好读」,更在于它的失败是响亮的:少个引号、多个逗号,解析立刻报错,程序捕获异常就知道该重试——格式错误不再能悄无声息地流进下游7

3.4 第 3 级:YAML——顺手把「判断」也外包给它

YAML 是另一种结构化文本格式:用缩进表达层级,不要引号和括号,还支持 # 开头的注释。书里给的对比很实际:写提示、存提示时它比 JSON 易读,也不容易因为括号不配套而出错8

但真正有意思的是书里把 YAML 玩出的花样:拿模型当程序里的判断逻辑。 场景:你维护着一份杂货库存清单(schema,即数据该长什么样的规定),用户随口说「5 份苹果片,再来 2 打鸡蛋」——让模型按库存过滤这句话,把匹配的条目按 YAML 格式返回;库存里没有的(香蕉),整条过滤掉;一条都不剩,就回 No Items9

输入(节选):
# 库存:
- item: Apple Slices
quantity: 5
- item: Eggs
quantity: 1
unit: dozen
……
用户说:"5 apple slices, and 2 dozen eggs."
只返回匹配库存的合法 YAML;没有匹配就返回 "No Items",不要任何评论。

输出:- item: Apple Slices
quantity: 5
unit: pieces
- item: Eggs
quantity: 2
unit: dozen

注意这一步发生了什么:「匹配吗?剩几条?怎么答?」这些本该写 if-else 的判断,全被一句话委托给了模型。 程序里这种「根据情况走哪条路」的逻辑,正式名字叫控制流(control flow)——书里这张图的名字就叫「用 LLM 决定应用的控制流,而不是用代码」10

当然,把判断外包出去,就得把校验留在手里。书里的配套做法:模型返回的 YAML 先经一个校验函数,对应六种自定义异常——不是列表、条目不是字典、缺键、名字不在库存里、数量超上限、单位不合法——逐条检查,不过就拒收11模型负责灵活,程序负责把关,这个分工是这一级台阶的精髓。

3.5 再往外一步:万能转换器

结构化之外,书里收了一组「格式转换」类玩法,都建立在同一个观察上:这类模型是任意两种表示之间的转换器12:

  • ELI5(Explain It Like I'm 5,「把我当五岁小孩讲」):把一篇癌症治疗综述的摘要转成孩子能懂的话——技术文档的人话版;
  • 翻译链:把一段简单英文 → 改写成拗口复杂英文 → 转成简单西班牙语 → 再转回英文。大意保留,细节有损耗。书里给了两条边界:网上资料少的语言效果差;换成代码也一样——主流语言(Python/JavaScript)写得好,新语言、新库就差13;
  • 风格解绑(text style unbundling):给一段范文,让模型抽出一份「风格写作指南」(语气、长度、用词、结构),之后照指南仿写——品牌方统一文风就靠它14;
  • 实体与摘要:从文本里列出涉及的实体;把法律条文摘要成几句话。超长文档放不下时,切块逐段摘要、再把摘要合并成摘要——这条流水线第 05 章讲切块时会再见到15

CSV——一种逗号分隔的纯文本表格格式,Excel 和几乎所有数据分析工具都直接认——也在这一组里:让模型生成「5 个学生的 name, age, grade」假数据,拿到手就是可以直接灌进测试环境的 CSV 文件16

3.6 先要上下文:让它先问你要决策依据

最后一个战术,和格式无关但同属这一章:在模型信息不足时,别让它硬答,让它先问。

书里的对照实验发生在数据库选型上:SQL(Structured Query Language,结构化查询语言——这类数据库共用的查询语言,看见这个缩写知道是数据库就行)一族的 PostgreSQL,对阵文档库的 MongoDB。直接问「我的项目该用 MongoDB 还是 PostgreSQL?」,模型只能给出「看情况」的和稀泥回答。

这两个里,PostgreSQL 是关系型数据库——按表存数据、行与行之间建关联的那类;MongoDB 按文档存,是另一条路线。

改问:「要帮我做这个决定,你需要知道哪些信息?」——它列出 10 条决策依据(数据结构、一致性要求、查询类型、预算……)。你把这 10 条逐条填好再发回去,这次它给出了明确推荐:PostgreSQL,并给出了理由17

书里给了一个可以抄走的默认句式,直接加在提示末尾:「If you need more context, please specify what would help you to make a better decision.」(如果需要更多背景,请说明什么能帮你做更好的决定。)18

4. 作者的判断与证据

  • 四个毛病、三条军规、六种异常、MongoDB 对照实验,全部是书里真实跑过的演示,提示与输出都有原文;
  • 「让它先问上下文」被作者归到更宏观的观察下:这类多步系统(书里举了 AutoGPT)内部都有一个「现有上下文够不够」的自评环节19——这是作者把战术往原则上归的尝试,属于合理外推(从已知往未知谨慎多走一步);
  • 风格解绑、翻译链这些是「能工作」的演示,书里没有给成功率数据。我们自己的经验性提醒:转换类任务每多一跳,信息就损一层(书里对翻译链也如实说了「部分意义丢失是预料中的」)。

判断(我们的,不是书里的): 这一章最值得带走的心智模型是「提示即接口约定」:你给模型的格式军规,和程序员之间约「这个接口传什么、回什么」是同一种活动。所以接口工程的纪律全部适用——版本变化会坏、要写校验、要留「无法处理」的出口(No Items)。 如果错,会错在: 如果模型做到百分百遵守格式(比如强约束解码普及到所有供应商),校验层的必要性会下降;但「先铺出口」的纪律在任何人写的系统里都成立,不受模型进步影响。

5. 边界与局限

  • 正则路线今天已基本被取代。 书里自己都说正则繁琐;2024 年之后,各供应商陆续提供强制 JSON 输出的原生参数,第 08 章的输出解析器也是替代方案之一。正则部分当作「理解为什么需要结构化」的教材读;
  • 模型当控制流要限额。 书里给了数量上限(quantity > 10 拒收)这种硬校验——判断外包不等于免检;
  • 敏感数据警告: 书里在讲用模型筛邮件、筛简历时明确提醒:发给云端模型的内容可能进入未来的训练数据20;
  • 书里的「风格解绑」在版权上同样灰(学谁的文风不构成侵权,但商用场景请自行判断),这与第 12 章图像侧的灰区是同一类问题。

6. 可带走的

  1. 自由文本的四个坑:数量随机、夹带开场白、格式漂移、没有筛选——逐条在提示里堵;
  2. 让它给 N 条,程序里仍要数一遍——「说了」不等于「会做到」;
  3. JSON 三条军规:只回合法 JSON、禁反引号、声明「会被 json.loads() 解析」;
  4. 解析失败是你的朋友:格式错误变成响亮的异常,而不是静默的错误数据;
  5. 写给人改的提示用 YAML,写给人读的注释 YAML 也支持;
  6. 可以把「匹配吗/怎么答」这类判断委托给模型——但出口(No Items)和校验器(六类异常)必须先铺好;
  7. ELI5、翻译、风格解绑、实体提取、摘要:都是同一个「万能转换器」换插头;
  8. 信息不足时,让它先列「我需要知道什么」,再答——比和稀泥的回答值钱得多。

7. 原文地图

主题原书章原文位置
朴素清单的四个毛病Ch.3 标准做法text/06-fm-generating-lists.txt:24(搜「pitfalls」)
钉死格式的清单提示Ch.3 标准做法text/06-fm-generating-lists.txt:40(搜「bullet-point list of 5」)
条数不保证Ch.3 标准做法text/06-fm-generating-lists.txt:131(搜「you might receive only 8」)
层级列表与正则Ch.3 标准做法text/06-fm-generating-lists.txt:135(搜「regular expressions」) · text/06-fm-generating-lists.txt:284(搜「control flow become increasingly complicated」)
JSON 军规与反引号Ch.3 标准做法text/06-fm-generating-lists.txt:343(搜「Never include backtick」) · text/06-fm-generating-lists.txt:327(搜「Sure here's the JSON」)
YAML 对比与库存过滤Ch.3 标准做法text/07-fm-yaml.txt:3(搜「structured data format」) · text/07-fm-yaml.txt:40(搜「5 apple slices」)
模型当控制流Ch.3 标准做法text/07-fm-yaml.txt:96(搜「control flow of an application instead of code」)
六种自定义异常Ch.3 标准做法text/07-fm-yaml.txt:123(搜「six specific errors」)
ELI5、翻译链、风格解绑Ch.3 标准做法text/08-fm-mock-csv-data.txt:27(搜「five-year-old」) · text/08-fm-mock-csv-data.txt:131(搜「part of the meaning is lost」) · text/08-fm-mock-csv-data.txt:249(搜「unbundling」)
CSV 假数据Ch.3 标准做法text/08-fm-mock-csv-data.txt:3(搜「mock CSV data」)
超长文档的摘要流水线Ch.3 标准做法text/08-fm-mock-csv-data.txt:407(搜「chunk the document」)
先要上下文Ch.3 标准做法text/08-fm-mock-csv-data.txt:142(搜「ask for context」) · text/08-fm-mock-csv-data.txt:239(搜「If you need more context」)
敏感数据警告Ch.3 标准做法text/23-fm-self-eval-llm-responses.txt:140(搜「leaked into OpenAI」)

Footnotes

  1. 出处:「Ch.3 标准做法」第 24 段(text/06-fm-generating-lists.txt:24,搜「pitfalls」)。

  2. 出处:「Ch.3 标准做法」第 40 段(text/06-fm-generating-lists.txt:40,搜「bullet-point list of 5」)。

  3. 出处:「Ch.3 标准做法」第 131 段(text/06-fm-generating-lists.txt:131,搜「you might receive only 8」)。原文:「Asking a language model for a fixed number of items doesn't guarantee… your code should either validate that 10 headings exist or be flexible」。

  4. 出处:「Ch.3 标准做法」第 135 段(text/06-fm-generating-lists.txt:135,搜「regular expressions」)(Example 3-1、3-2)与第 284 段(text/06-fm-generating-lists.txt:284,搜「control flow become increasingly complicated」)。

  5. 出处:「Ch.3 标准做法」第 343 段(text/06-fm-generating-lists.txt:343,搜「Never include backtick」)。

  6. 出处:「Ch.3 标准做法」第 323 段(text/06-fm-generating-lists.txt:323,搜「triple backticks」)。

  7. 出处:「Ch.1 五原则」第 353 段(text/04-ch01-chapter-1-the-five-principles-of-prompting.txt:353,搜「parsing error」)。

  8. 出处:「Ch.3 标准做法」第 3 段(text/07-fm-yaml.txt:3,搜「structured data format」)。书里还演示了用 LLM 生成 Mermaid(一种用文本描述流程图的格式),渲染出来就是图(text/07-fm-yaml.txt:259,搜「mermaid」)。

  9. 出处:「Ch.3 标准做法」第 40 段(text/07-fm-yaml.txt:40,搜「5 apple slices」)与第 113 段(text/07-fm-yaml.txt:113,搜「No Items」)。

  10. 出处:「Ch.3 标准做法」第 96 段(text/07-fm-yaml.txt:96,搜「control flow of an application instead of code」),图 3-1 的标题。

  11. 出处:「Ch.3 标准做法」第 123 段(text/07-fm-yaml.txt:123,搜「six specific errors」)。

  12. 出处:「Ch.1 五原则」第 315 段(text/04-ch01-chapter-1-the-five-principles-of-prompting.txt:315,搜「universal translators」)。

  13. 出处:「Ch.3 标准做法」第 131 段(text/08-fm-mock-csv-data.txt:131,搜「part of the meaning is lost」)与第 134 段(text/08-fm-mock-csv-data.txt:134,搜「newer coding languages」)。

  14. 出处:「Ch.3 标准做法」第 249 段(text/08-fm-mock-csv-data.txt:249,搜「unbundling」)。「风格解绑」这个词组第 12 章在图像侧还有一个对应物(meme unbundling),同一思路。

  15. 出处:「Ch.3 标准做法」第 407 段(text/08-fm-mock-csv-data.txt:407,搜「chunk the document」)。

  16. 出处:「Ch.3 标准做法」第 3 段(text/08-fm-mock-csv-data.txt:3,搜「mock CSV data」)。

  17. 出处:「Ch.3 标准做法」第 142 段(text/08-fm-mock-csv-data.txt:142,搜「ask for context」)与第 228 段(text/08-fm-mock-csv-data.txt:228,搜「PostgreSQL seems」)。

  18. 出处:「Ch.3 标准做法」第 239 段(text/08-fm-mock-csv-data.txt:239,搜「If you need more context」)。

  19. 出处:「Ch.3 标准做法」第 245 段(text/08-fm-mock-csv-data.txt:245,搜「actor–critic」)。书里称 AutoGPT 有一个自评步骤,在执行前检查当前上下文能否完成任务。

  20. 出处:「Ch.3 标准做法」第 140 段(text/23-fm-self-eval-llm-responses.txt:140,搜「leaked into OpenAI」)。