驯服输出 — 格式、停顿与模型的「语气」
这一章讲三件事: 补全到手,怎么解剖(前奏、头尾、刹车); 文字之外还有一层信息(logprobs)能拿来干什么; 以及两个绕不开的工程决策:用哪个模型、要不要微调。 这是原书「核心技术」部分的收官——读完,原书说你就可以自称提示词工程师了。
1. 这一章讲什么
第 05–08 章把提示词造好发出去。这一章管回来的一半: 补全不是拿来就用的,是要解剖的。
主走查是一个「暴躁邮件审核」场景:让模型判断邮件是否得体—— 从「怎么让它只答 Yes/No」一路走到「它的判断标准和你不 一样,怎么校准」。 辅走查是书里那组真实概率:两个以 North 开头的选项, 是怎么把一个其实更高的答案挤下台的。
2. 顶层全景:一份补全的解剖图
┌ 前奏(preamble) 三种:结构性的 / 推理性的 / 废话
│ ── 可识别的开头 ── 答案从这里开始(比如「1.」)
│ 主答案 你要的货
│ ── 可识别的结尾 ── 刹车点(比如「\n#」)
└ 附笔(postscript) 解释、免责声明、背景——可以留,但要留得能剥掉
图说:补全的五段。每一段都有对应的处置手法,见 3.1–3.3。
3. 核心原理
3.1 前奏三种:该省的省、该留的留
一,结构性样板。 提示词结尾和答案开头之间的过渡文字
(比如对话里的 Assistant:)。能放提示词里的就别让它生成——
确定的东西由你写,又稳又省。
二,推理性的长前奏。 2023 年底起,ChatGPT 开始先复述一遍问题再答; 思维链(第 10 章)也长在这。这种前奏是美德: 书里的对照显示,同一道题,长前奏后答对了,短前奏后答错了。 它费 token,但买的是正确率1。
三,废话(fluff)。 RLHF 模型尤其爱产:客套、免责声明、「作为 AI 我……」。 程序用它就是纯成本。处置办法:格式上把「主答案」和「杂项」分开—— 让它把主答案放第一,所有杂项归并到后面某一项里, 程序一刀切掉后半截即可。书里那个实例:让它用编号列表, 把评论、免责、背景全赶进「第 2 点」,主答案独占「第 1 点」2。
3.2 可识别的头与尾
要把主答案从补全里挑出来,头尾必须可被程序认出。 书里那张表值得记住规律,不必背3:
| 文档结构 | 头 | 尾 | 能用「包含某子串」判断吗 |
|---|---|---|---|
| Markdown | 预期的章节标题 | 下一个章节标题 | 能 |
| 三反引号代码块 | ```python | ``` | 能 |
| 编号列表首项 | 1. | 2. | 能 |
| YAML | 预期的键 | 更低缩进的行 | 不能 |
| JSON | 预期的键 | 未转义的引号 | 不能 |
| 花括号语言(Java 等) | { | 配平的 } | 不能 |
「能不能用子串判断」决定了你的解析器是一行还是一个状态机。 设计提示词时,优先选「能」的那类格式——这就是第 08 章 说「结构化文档好解析」的落点。
3.3 让它停:stop 参数与流式取消
结尾可识别,不只是为了解析——每多生成一个 token 都是钱和时间, 到了结尾就该立刻刹车。两条路4:
- stop 参数:给 API 一张字符串清单,模型一旦生成其中任何一条, 服务端立刻停——最省,连那部分 token 的钱都不用付;
- 流式(stream)边收边取消:token 逐批发给你,认出结尾就掐。 省,但没 stop 省——网络有延迟,取消信号到之前它又吐了几个。
经验:能写进 stop 清单的优先 stop;结尾标志不固定时,才靠流式掐。
两个实战细节:停止串通常以换行开头——\n# 而不是 #,
否则代码注释、电话号码都能误触发;生成 Python 类时可以用
\nclass、\n\def、\nif 当停止串——类体内的方法是 \n\tdef,不会误伤5。
3.4 logprobs 用法一:模型的「语气」
第 02 章说过,模型每个 token 都算了一整张家底清单(logprobs),可以要回来。 这层信息是文字之外的第二通道6。
先立一个直觉。作者 Albert 的邻居是天体物理学家,问她 「光从太阳到火星要几分钟」,她秒答「13」; 问他十岁的女儿,她迟疑着猜「也许……30?」—— 答案的可靠性写在语气里。logprobs 就是模型的语气7。
怎么把「语气」变成「质量分」?把整段补全的 logprobs 加起来? 不行——同一个意思有一百种说法,「for example」和「for instance」 就能让概率差一半,长文本的总分会系统性偏低。 书给的办法是平均;而 Albert 在 Copilot 开发中的实操发现是: 补全前几个 token 的概率(不是 logprob,是 exp 还原后的概率)取平均, 对整体质量最有预测力8。
有了质量分,就能做五种产品决策:没把握就不给建议、 超常挣扎就告警、挣扎就加料重试、换更贵更聪明的模型、 没十足必要就别打扰用户——还记得 Clippy 吗?别当 Clippy9。 想再进一步:调高温度生成 n 份,按 logprobs 挑最好的 (经验法则:temperature = sqrt(n) / 10,作者自己注明「完全不科学」)10。
3.5 用法二:分类、合并陷阱与校准
让模型做分类(正面/负面/中性;Yes/No),难点不在问,在于让它只选一个。 手法就是第 08 章的可识别开头:「Please answer in the format:
- [negative | positive | neutral], 2. [explanation]」——
1.后面紧跟的就是答案11。
辅走查:首 token 合并陷阱,这是真实概率。 让 gpt-3.5-turbo-instruct
在三个选项里挑:North America、Northeast Asia、Europe。
模型的真实计算是:第一步只在 North 和 Europe 两个 token 之间选——
Europe: 44%
North(两个选项共享): 55%
└ 然后才是 North 内部: Northeast Asia 76% / North America 24%
它实际输出的: Northeast Asia
它心里概率最高的: Europe(44% > 55% × 76% = 42%)
图说:辅走查。共享首 token 的两个选项把概率并在一起,
挤掉了它其实更看好的 Europe。
规矩:让每个选项的首 token 都独一无二(比如用字母编号 A/B/C)12。
主走查:暴躁邮件审核,一路走到校准。 你想做个应用: 用户写的邮件太冲就拦下来让他重写。问模型: 「Is this a professionally written email? 1. Yes / No. 2. Explanation.」 它能答——但它的「得体线」和你的不一样:也许它放行太多,你想让它更严。
这时 logprobs 第三次出场。模型说 Yes/No 时各带一个 logprob, 校准——把整条判定线平移一个常数,让模型的标准贴合你的标准: 比如「No 的 logprob 至少要比 Yes 高 0.3,才判不合格」。 常数怎么定?做实验,或者逻辑回归——拿一批你已判定对错的样本, 拟合出让错误最少的那个偏移常数——这类经典方法。 定好之后连算都不用自己算:很多 API 提供 logit_bias 参数, 把常数直接下发给模型生效13。
3.6 用法三:echo,找出文本里的「意外点」
把 echo 参数打开,API 连提示词部分的 logprobs 也返回——
一个 token 都不用生成,就能扫描任何一段文字。
书里的演示自带彩蛋:那一页正文里故意埋了个拼写错误(complution),
模型给它打的 logprob 低于 -13——满页一位数负分里,它像警报器一样响
(它切出的根本不是 completion,而是 compl + ution)。
一般规律:负的个位数是常态,负的双位数是「这里不对劲」;
但没有通用阈值——同一段文字,开头的分数普遍比结尾低
(题材和风格要读一阵子才明朗)14。
写这类代码的单测时注意:logprobs 受浮点影响会漂,±1 都正常, 断言别写死15。
3.7 用哪个模型:六项准则与「最小够用」
模型每周都在变,书不点名推荐,只给准则(按重要性排)16:
-
智能:答得离「领域专家」多近;
-
速度:用户等得起吗(回看第 06 章的三档紧迫度);
-
成本:按 token 计价,高频应用最先撞墙;
-
省心:GPU(跑模型的显卡硬件)部署、崩溃重启、路由 缓存,谁替你干;
-
功能:会不会聊天/工具,给不给 logprobs,看不看得懂图;
-
特殊要求:开源(代码公开、可自己下载部署)、数据驻留、不出内网……像饮食禁忌,有的人是硬约束。
口诀:能可靠完成任务的最小模型。 原型期可以故意用稍大的——旗舰一出,老款就降价, 等你的应用公测时,当初「用不起」的那个可能已经够得着了17。 另外别把模型选择焊死在代码里(LiteLLM 这类库提供统一接口:同一套调用姿势打不同家的服务)18。
3.8 微调三档,与小红帽的两条路
提示词压到极限还不够,就轮到微调。三档,按「要教的东西多新」选19:
最重的一档是全量微调(continued pre-training):全新领域的新东西、全部参数都动,数万份文档、周到月。
轻一点的是 LoRA——低秩(只动一小部分参数的自由度)适配:给几个关键矩阵学一个「差分补丁」,在已有本领里做选择(格式、风格、先验分布),数百到数千份文档、小时到天。
再轻的 是软提示(soft prompting)——不挑词,直接用自动调参的办法找一段「模型状态」,只动提示词那点信息,数百份文档、小时。
| 档位 | 它学什么 | 数据量级 | 耗时 |
|---|---|---|---|
| 全量微调(continued pre-training) | 全新领域的新东西——全部参数都动 | 数万份文档 | 周到月 |
| LoRA | 在已有本领里做选择:格式、风格、先验分布 | 数百到数千份 | 小时到天 |
| 软提示(soft prompting) | 提示词里那点信息本身 | 数百份 | 小时 |
两个关键直觉,都来自作者的实践:20
- LoRA 不教新把戏,只教它「在你的场景该用哪个已有把戏」—— 格式、风格一学就会;还有「先验分布」:你的用户全是欧洲学生, 推荐摩纳哥被点踩、推荐布拉格就出票——这类你说不清、但数据里有的分布, LoRA 学得最快;
- 微调是「用别的方式继续的提示工程」——微调到位后, 静态指令、少样本示例都可以从提示词里撤了,它们被烤进了参数。
微调后,小红帽原则裂成两条路:提示词像微调用的文档,它就走新路; 像原始训练文档,它就「忘了微调」走回旧路—— 旧路只是长了点草,并没有消失21。
(还有一个实用细节:有的框架支持损失(训练时衡量「答得有多差」的那个分数)掩码——只对文档里「答案部分」算,提示部分不学—— 你要的是它会答题,不是会出题。)22
4. 作者的判断与证据
有硬证据的:
- 合并陷阱的概率(44% vs 55%×76%)是 gpt-3.5-turbo-instruct 的真实返回12;
- 「OpenAI 1106 之后的模型,JSON schema 的部分修饰符不进提示词」 是作者探查出来的口径23;
- 「前几个 token 概率平均预测质量」是 Albert 在 Copilot 开发期用的方法8。
作者标明是经验法则的:
- temperature = sqrt(n)/10——原文:「a rough (and completely unscientific) rule of thumb we like to use」10;
- 「logprob 负双位数 = 异常」没有通用阈值,因模型、文体而异14;
- 供应商格局(Anthropic/Mistral/Cohere/Google/Meta 的画像)是 2024 年快照16。
判断(我们的,不是书里的): 这一章真正的分水岭是「把 logprobs 当一等公民」。 只会读文字,你只有一个黑盒;会读 logprobs,你有了一个带气压计的黑盒—— 质量信号、分类校准、文本体检,全是从这层「语气」里榨出来的。 但要补一句 2026 年的现状(补充(不在书里,来自通用知识):推理系模型——先思考再作答的那类——普遍不返回 logprobs,常规文本接口仍返回;「怕被逆向」是我们的猜测,原书只说过「有些厂商关闭 logprobs 防逆向」是一种存在,不是趋势。 如果错,会错在: 如果主流 API 全面关闭 logprobs,这章一半的技巧 只剩开源自托管一条路;选型时「给不给 logprobs」已经从「功能」升级成「门槛」。
5. 边界与局限
- logprobs 不是所有模型都给,用本章技巧前先确认你的供应商开放;
- 「前几个 token 概率平均」是单一团队的经验,不是普适指标—— 用之前拿自己的数据验一遍;
- 校准的常数绑死你的数据分布——用户群变了,常数要重拟合;
- 微调三档的数字(数百/数万份、小时/月)是量级指引,不是承诺;
- 软提示很多框架不支持,书里也提醒了「先查你的框架给不给这个选项」 。
6. 可带走的
主走查一行回顾:「这封邮件得体吗?」→ 格式 1. Yes/No 收住答案 →
比 Yes/No 的 logprob 发现它放行太多 → 加 0.3 的偏移(或下发 logit_bias)→
2. 出现时 stop 刹车——从「能答」到「按你的标准答」,走了五步,每步都有名字。
- 前奏三种:结构性(替你写)、推理性(留着买正确率)、废话(赶到后半截切掉);
- 格式优先选「子串可判」的:Markdown 标题、代码围栏、编号列表;
- 停止:stop 参数最省,流式取消兜底;停止串带换行防误伤;
- logprobs 是模型的语气:平均能当质量分,前缀平均更灵(Albert 的 Copilot 经验);
- 分类:选项首 token 必须唯一——不然概率被合并,次优答案上台;
- 校准 = 平移阈值:Yes/No 各加一个常数,或直接下发 logit_bias;
- echo 扫提示词:负双位数是意外点;单测容忍 ±1 的漂移;
- 选型:六项准则,最小够用,别焊死;
- 微调三档:全量教新领域、LoRA 教取舍、软提示烤提示词;
- 微调后小红帽有两条路:提示词像微调文档,别像原始文档。
7. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 前奏三种 | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:29(搜「three different types of preambles」) · :71(搜「banishing most fluff」) |
| 可识别头尾表 | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:86(搜「presence of a substring」) |
| stop 与流式 | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:124(搜「Stop sequences」) · :142(搜「typical stop sequence」) · :156(搜「\n\tdef」) |
| 语气与质量 | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:188(搜「astrophysicist」) · :204(搜「averaging the probabilities」) · :224(搜「sqrt(n)」) |
| 合并陷阱 | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:266(搜「44% versus」) |
| 校准与 logit_bias | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:283(搜「Calibration means」) · :298(搜「logit bias」) |
| echo 找意外 | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:303(搜「echo」) · :330(搜「± 1」) |
| 选型准则 | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:347(搜「order of importance」) · :434(搜「smallest model」) |
| 微调三档 | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:475(搜「continued pre-training」) · :486(搜「Low-rank adaptation」) · :523(搜「soft prompting」) |
| 小红帽两条路 | Chapter 7 | text/10-ch07-chapter-7-taming-the-model.txt:545(搜「two kinds of paths」) |