跳到主要内容

工具与推理 — 让模型出手与出声

这一章讲三件事: 工具调用在底层到底是什么(答案还是那句:续写); 设计工具时哪些规矩是拿教训换的;以及怎么让模型「把思考喊出来」—— 这是提升正确率最便宜的一招。 原书第 8 章是全书最长章,我们拆成两章:本章管「能力」, 第 11 章管「组装成 agent」。

1. 这一章讲什么

到第 09 章为止,模型再强也只是「纸上谈兵」: 它不知道训练集之外的事,算大数会错,而且什么都不能做—— 它买不了机票、发不了邮件、调不了你家空调。

这一章给它装两样东西:(工具)和出声思考的能力(推理技巧)。

主走查是书里那个恒温器对话:「能帮我把温度调高两度吗?」—— 从 API 调用一路钻到内部提示词,看那十几个 token 里发生了什么。

2. 顶层全景:三个死角,一味药

先立三个死角,它们全从第 01 章的「模仿者」身份推出来1:

  1. 不知道训练集之外的事:你公司的文档、上周的新闻、此刻的航班余票;
  2. 算术不可靠:简单的靠背,数一大就「自信地估错」;
  3. 不能行动:它唯一能影响世界的方式,是求用户替它动手。

工具调用——模型在输出里写出「请调用某个函数、带这些参数」, 由你的应用真的去执行、再把结果塞回对话——一味药治三个死角: 查资料、用真计算器/真程序算、真动手2

用户 → 应用 → 模型(读到工具清单)
│ 输出:「调用 get_room_temp,参数 {}」
应用 ←─────────┘ 应用真的去调,拿到「74」
应用 → 模型(结果塞回:「74」)
│ 输出:「调用 set_room_temp,参数 {temp: 76}」
应用执行 → 模型 → 输出给人看的答案:「已从 74°F 调到 76°F」

图说:主走查全景。模型从头到尾只做「写文字」;
「执行」永远发生在应用层。agent(智能体)——
能自己决定下一步动作、并通过工具实际执行它们的系统——就是
把这个圈自动转起来的东西,第 11 章正式造它。

2023 年 6 月,OpenAI 推出了专为工具调用微调的模型,各家随后跟上3

3. 核心原理

3.1 主走查(API 面):三轮,调了两度

主走查开始。 两个工具:get_room_temp()(读室温)和 set_room_temp(temp)(设室温)。系统消息:「You are HomeBoy, a happy, helpful home assistant.」用户说:「能暖和两度吗?」

应用的 process_messages 每跑一轮做五步:发消息(带工具定义)→ 把模型的回复追加进对话 → 检查它有没有要调工具 → 有就真调、 结果也追加进对话 → 返回。连跑三轮4:

第 1 轮:模型 → 调 get_room_temp {} 应用执行,塞回 "74"
第 2 轮:模型 → 调 set_room_temp {"temp": 76} 应用执行,塞回 "DONE"
第 3 轮:模型 → "The room temperature was 74ºF and has been
increased to 76°F."

图说:它先查了温,才设了 76 = 74 + 2——「调高两度」是算术,
它把算术拆成了「先读再加」。最后一句是给人看的,不是给程序的。

注意两点:一轮里模型可以一次发多个调用(每个带 ID,结果按 ID 配对); 以及那句「76」是它算出来的——读回 74,加 2,写进参数5

3.2 揭开引擎盖:还是那份文档

工具调用感觉是「新能力」。但和第 04 章的聊天一样: 微调过的模型 + API 层的语法糖,底层还是续写一份文档

厂商没有公开内部提示词格式——以下是作者「拷问模型」还原出来的, 他们自己声明了这一点6。工具定义被放在系统消息尾部, 用 Markdown 组织,写成 TypeScript 函数的样子:

<|im_start|>system
You are HomeBoy, a happy, helpful home assistant.

# Tools

## functions

namespace functions {

// Set the ambient room temperature in Fahrenheit
type set_room_temp = (_: {
// The desired room temperature in ºF
temp: number,
}) => any;

} // namespace functions
<|im_end|>

三个讲究,全是小红帽原则的应用7:

  • Markdown 骨架(# Tools## functions):训练集里最熟的排版;
  • TypeScript:类型词汇丰富(string、number、boolean 之后还有对象结构), 而且文档就写在参数旁边——模型读函数说明的方式和程序员读接口定义一样;
  • 调用必须写成「参数名: 值」的 JSON 对象:模型写 {"temp": 76} 时, 是先念出 temp 这个名字、再填 76——念名字这一步让它很难填错坑。

调用和结果在内部长这样8:

<|im_start|>assistant to=functions.get_room_temp
{}<|im_end|>
<|im_start|>tool
74<|im_end|>

(ID 只存在于 API 层,用来配对;进提示词时已被按顺序摆好。)

主走查最关键一站:把一次调用放到显微镜下。 to=functions.set_room_temp{"temp": 76} 这一小段, 十几个 token,模型完成了五六步分类9:

① 谁说话? API 强制写入 <|im_start|>assistant(不让模型选,更安全)
② 调工具吗? 模型写 to=functions. → 调;写 \n → 普通回话
③ 调哪个? set_room_temp
④ 填哪个参数? {"temp":(多参数时逐个挑)
⑤ 填什么值? 76
⑥ 结束了吗? }<|im_end|>

图说:同一个通用网络,在 10–20 个 token 里跑完了
五六个高度专门化的判断——而且是层层分解的:
调不调 → 调哪个 → 填什么。书作者在这里写了句「Wow...just wow.」

3.3 工具设计:两条直觉与一串规矩

设计工具的两条总直觉10:

  1. 人觉得好懂的,模型也觉得好懂;
  2. 照训练数据里常见的样子写(小红帽原则)。

落成规矩11:

  • 数量:同时给的工具越少越好;工具之间要划分领域,别功能相似; 别把网页 API 原样搬进来——参数几十个、响应一大坨,描述先吃掉你的预算;
  • 命名:自解释;OpenAI 用 camelCase;别用全小写连写(retrieveemail 这种,切词切得稀碎,人和模型都难读);
  • 定义:简短但不留歧义;如果模型本来就熟某个公开 API,就沿用它的命名与风格—— 作者在 Copilot 时发现所用模型对 GitHub 的代码搜索语法「熟到能背文档」, 于是参数名、取值格式全部照抄文档,模型出错率立降;
  • 参数:少而简;enum、default 可用; 但 OpenAI 1106 之后的模型,minItems、uniqueItems、minimum、maximum、 pattern、format 这些修饰符不进提示词——嵌套参数的描述也不进(作者探查所得)12; 长文本参数是雷:塞进 JSON 要转义换行和引号,文本越长越容易漏转义—— Anthropic 用 XML 标签传参数,不用转义,长参数友好; 参数幻觉:对话里没出现过的值,它会编("my-org""my-repo")—— 已知值就从定义里删掉这个参数,或给默认值,或让它「不确定就问」(然后祈祷它真问)13;
  • 输出:让模型能预期将看到什么;别塞「万一有用」的杂料(契诃夫之枪);
  • 错误:报错要对着「它能做什么」写——参数校验失败,就告诉它哪错了, 它会拿着错误信息自我修正14

3.4 危险工具:别信「我在描述里写了要先问」

工具能改真实世界之后,风险升级。书里的警告掷地有声15:

别指望在工具描述里写「执行前先跟用户确认」就安全了。 模型本质上是不可靠的——这么干,我们保证它总有一小撮时候 会照做你明令禁止的事。

正确姿势反直觉:让它随便调——让它尽管发起「把 Bill 的钱全转给他前妻」。 拦截在应用层:危险调用一律拦下,真人签字(人在环—— 危险动作由人来最终拍板的机制)之后才真的执行16

3.5 出声思考:思维链

工具治「不知道、不能算、不能做」。还有第四个毛病,第 03 章埋的: 它没有内心独白——你问「《驱魔人》会刺激边缘系统吗?」, 它先蹦「是/否」,再编一段解释——答案在前,解释只是给答案找补17

2022 年 1 月的思维链论文把顺序倒了过来:先想,后答。 给几个「Q: 问题 A: 一串推理,So the answer is …」的例子,它照样画葫芦:

Q: Will The Exorcist stimulate the limbic system?
A: The Exorcist is a horror movie. Horror movies are scary. The limbic
system is involved in fear. Thus, The Exorcist will stimulate the
limbic system. So the answer is yes.

效果(PaLM 540B):常识问答数据集 StrategyQA,69.4% → 75.6%; 数学应用题数据集 GSM8K,约 20% → 约 60%——同一个模型, 只是被要求「先想清楚」18

两个月后,另一篇论文发现连例子都不用给: 在答案开头放一句「Let's think step-by-step」就行(零样本思维链)19。 2023 年 10 月更怪:一篇论文微调模型学会一个「暂停 token」, 问题后面插 10 个无意义 token,等于给它买几步纯粹的思考时间—— 作者类比:这就是人说「呃」「嗯」20

机制就一句话(第 03 章的结构定律):想法只有被写出来, 才能成为后续 token 的输入——想在前面的答案,会约束后面的答案。

3.6 ReAct:想-做-看,三样轮着来

2022 年 10 月的 ReAct 论文把「出声思考」和「工具」缝在一起, 辅走查就是书从论文里搬来的实例21

问题:「Arthur's Magazine 和 First for Women,哪本杂志创刊更早?」 给它三个工具:Search[实体](查维基)、Lookup[关键词](页内找)、 Finish[答案](交卷)。提示词里先放说明和六个「想-做-看」示范,再上真题:

Thought 1: 我要分别查两本杂志,比较创刊年份。
Action 1: Search[Arthur's Magazine]
Obs 1: Arthur's Magazine (1844–1846), 美国文学期刊……
Thought 2: 它 1844 年创刊。再查另一家。
Action 2: Search[First for Women]
Obs 2: ……1989 年创刊。
Thought 3: 1844 < 1989,所以 Arthur's Magazine 更早。
Action 3: Finish[Arthur's Magazine]

图说:辅走查。想(分解与决策)、做(调工具)、看(读结果),
三轮之后交卷。注意每一步「想」都被写了下来——
这些文字同时是:给用户看的解释、给模型自己看的草稿纸。

成绩单里藏着一个反直觉:不微调时,ReAct 在 HotpotQA 上 比不过普通问法和纯思维链——光看六个示范学不会这套复杂配合。 但拿三千个例子微调之后:ReAct 加持的 8B(80 亿参数)模型, 反超普通问法的 62B(620 亿)模型;62B 的 ReAct 反超 540B 的普通问法22。 决策类任务(ALFWorld,文字版过家家)上,「想+做」(ReAct)71% 成功, 「只做不想」(Act)只有 45%—— 论文把「想」的功能列了五条:拆目标、注常识、提取观察、跟踪进度、处理异常23

3.7 之后:先画图纸、事后复盘、分头再做

ReAct 之后一排改进,各补一块24:

  • plan-and-solve:别上来就干——「先整体理解问题、定出计划, 再一步步执行」,适合工序长的任务;
  • Reflexion(2023):干完复盘——让模型对着失败信息(比如没过的单测) 重写一版。前提是错误可逆(「对不起,钱已转给你前夫」这类不行);
  • branch-solve-merge:派 N 个独立会话分头做(各自换角度), 最后一个「合并 agent」把各家成果并成更完整的解。

4. 作者的判断与证据

有硬证据的:

  • 恒温器对话(74→76、「increased to 76°F」)是真实运行的消息记录4;
  • 思维链与 ReAct 的数字(69.4→75.6、约 20→60、71% vs 45%、8B 反超 62B) 全部出自原论文,书里注明了模型与数据集182223;
  • 「1106 后修饰符不进提示词」「Anthropic 用 XML」「模型能背 GitHub 搜索文档」 是作者的一线探查1213

必须标明的:

  • 内部提示词格式(系统消息尾部的 TypeScript 区块)不是官方文档, 是作者「拷问模型」的还原——他们原话:「our best attempt to reconstruct the internal prompt format based on our interrogations of the model」。 书末还手把手教读者怎么拷问别家模型(埋标记、造怪异函数名、 base64(把文本伪装成乱码的编码术)/ROT13 绕审查、用 assistant 口吻钓续写)6;
  • 「人在环必须拦在应用层」是作者(带着事故经验)的工程主张,不是测量结论15

判断(我们的,不是书里的): 「一次调用 = 十几 token 里的五六步分类」 是理解一切 agent 可靠性的钥匙:每一步分类都有出错率,步数越多、 可选工具越多,整体成功率按乘法衰减。这解释了为什么 「限制工具数量」「参数要少」「危险操作人工兜底」全都指向同一件事—— 把这条乘法链的环节数压下来。 如果错,会错在: 如果未来模型把工具调用做成「内部原生动作」 而不是「写在文档里的文字」,乘法模型会变;但 2024 年所有主流实现 都是「写文字」,作者也以此为准。

5. 边界与局限

  • 内部格式是 OpenAI 2023–24 年的还原,随时会变;方法(拷问)比结论耐用;
  • ReAct 的「不微调反而更差」提醒:复杂配合光靠示范不够, 今天的模型虽然普遍「原生会」工具调用,复杂流程仍要评估;
  • 思维链不是白来的:想的过程也是 token,也要钱和时间—— 简单任务别硬上(第 06 章的「本来就清楚就别加料」同样适用);
  • 暂停 token 这类技巧需要能改模型,API 用户做不到,书里也只当奇闻介绍。

6. 可带走的

主走查一行回顾:「暖和两度」→ 查温(74)→ 设温(76 = 74+2)→ 人话回复——模型全程只写文字,执行的永远是你; 显微镜下,一次调用 = 十几个 token 里的五六步分类。

  1. 工具调用 = 微调模型 + 语法糖,底层还是续写;
  2. 工具定义:Markdown 骨架、TypeScript 形式、文档贴着参数写;
  3. 参数名就是它自己的校验:先念名再填值,不容易填错坑;
  4. 工具要少、要划界、名字自解释、别用全小写连写;
  5. 长参数怕 JSON 转义;没出现过的值它会编(my-org/my-repo);
  6. 危险操作:让它调,在应用层拦,真人签字——描述里写「先问」没用;
  7. 没有内心独白,就让它把思考写出来:思维链,数学 20% → 60%;
  8. 「Let's think step-by-step」是零样本版;推理是花 token 买正确率;
  9. ReAct = 想-做-看循环;微调后 8B 反超 62B;决策任务 71% vs 45%;
  10. 错可逆就复盘(Reflexion),工序长就先计划,拿不准就分头再合并。

7. 原文地图

主题原书章原文位置
三个死角Chapter 8text/11-ch08-chapter-8-conversational-agency.txt:29(搜「hidden」) · :41(搜「math」) · :45(搜「just talk」)
恒温器主走查Chapter 8text/11-ch08-chapter-8-conversational-agency.txt:68(搜「get_room_temp」) · :244(搜「increased to 76」)
内部提示词还原Chapter 8text/11-ch08-chapter-8-conversational-agency.txt:267(搜「interrogations of the model」) · :277(搜「namespace functions」)
六步分解Chapter 8text/11-ch08-chapter-8-conversational-agency.txt:336(搜「classification algorithm」) · :359(搜「10 to 20 tokens」)
工具设计规矩Chapter 8text/11-ch08-chapter-8-conversational-agency.txt:414(搜「Limit the number of tools」) · :428(搜「retrieveemail」) · :451(搜「1106」) · :465(搜「my-org」)
危险工具Chapter 8text/11-ch08-chapter-8-conversational-agency.txt:497(搜「inherently undependable」) · :501(搜「to his ex-wife」)
思维链Chapter 8text/11-ch08-chapter-8-conversational-agency.txt:520(搜「Chain-of-Thought Prompting」) · :550(搜「69.4% to 75.6%」) · :554(搜「GSM8K」)
ReActChapter 8text/11-ch08-chapter-8-conversational-agency.txt:579(搜「ReAct」) · :613(搜「1844」) · :649(搜「8B」) · :673(搜「71%」)
后续三法Chapter 8text/11-ch08-chapter-8-conversational-agency.txt:680(搜「plan-and-solve」) · :694(搜「Reflexion」) · :705(搜「Branch-solve-merge」)

Footnotes

  1. 出处:「Chapter 8. Conversational Agency」第 23-48 段(text/11-ch08-chapter-8-conversational-agency.txt:29,搜「hidden」)。

  2. 出处:「Chapter 8. Conversational Agency」第 49-55 段(text/11-ch08-chapter-8-conversational-agency.txt:52,搜「model about tools it has access to」)。

  3. 出处:「Chapter 8. Conversational Agency」第 57-60 段(text/11-ch08-chapter-8-conversational-agency.txt:58,搜「June of 2023」)。

  4. 出处:「Chapter 8. Conversational Agency」第 62-250 段(text/11-ch08-chapter-8-conversational-agency.txt:68,搜「get_room_temp」)与例 8-1(:115,搜「Algorithm for processing messages」)。「one while loop away from full autonomy」(:248)。 2

  5. 出处:「Chapter 8. Conversational Agency」第 204-238 段(text/11-ch08-chapter-8-conversational-agency.txt:237,搜「2 degrees warmer」)。

  6. 出处:「Chapter 8. Conversational Agency」第 252-267 段(text/11-ch08-chapter-8-conversational-agency.txt:267,搜「interrogations of the model」)。拷问技巧清单见 :375-401(搜「LOGGING」)。 2

  7. 出处:「Chapter 8. Conversational Agency」第 287-309 段(text/11-ch08-chapter-8-conversational-agency.txt:295,搜「TypeScript」)。「The model literally says temp right before it specifies the value」。

  8. 出处:「Chapter 8. Conversational Agency」第 311-373 段(text/11-ch08-chapter-8-conversational-agency.txt:315,搜「to=functions.get_room_temp」)。

  9. 出处:「Chapter 8. Conversational Agency」第 326-364 段(text/11-ch08-chapter-8-conversational-agency.txt:336,搜「classification algorithm」)与(:359,搜「10 to 20 tokens」)。

  10. 出处:「Chapter 8. Conversational Agency」第 403-411 段(text/11-ch08-chapter-8-conversational-agency.txt:408,搜「easier for a human to understand」)。

  11. 出处:「Chapter 8. Conversational Agency」第 413-445 段(text/11-ch08-chapter-8-conversational-agency.txt:414,搜「Limit the number of tools」)与(:443,搜「recite our documentation」)。

  12. 出处:「Chapter 8. Conversational Agency」第 447-462 段(text/11-ch08-chapter-8-conversational-agency.txt:451,搜「1106」)与(:460,搜「XML tags」)。 2

  13. 出处:「Chapter 8. Conversational Agency」第 463-476 段(text/11-ch08-chapter-8-conversational-agency.txt:465,搜「my-org」)。「pray it does, because it often won't」。 2

  14. 出处:「Chapter 8. Conversational Agency」第 477-489 段(text/11-ch08-chapter-8-conversational-agency.txt:483,搜「Dealing with tool errors」)。

  15. 出处:「Chapter 8. Conversational Agency」第 491-504 段(text/11-ch08-chapter-8-conversational-agency.txt:497,搜「inherently undependable」)。原文:「we guarantee that a small portion of the time, the model will do exactly the thing you told it not to do」。 2

  16. 出处:「Chapter 8. Conversational Agency」第 500-504 段(text/11-ch08-chapter-8-conversational-agency.txt:501,搜「to his ex-wife」)。「intercept all such dangerous requests and explicitly get sign-off」。

  17. 出处:「Chapter 8. Conversational Agency」第 506-530 段(text/11-ch08-chapter-8-conversational-agency.txt:524,搜「limbic system」)。「the initial yes or no will be an intuitive guess and the explanation will actually be a rationalization」。

  18. 出处:「Chapter 8. Conversational Agency」第 531-556 段(text/11-ch08-chapter-8-conversational-agency.txt:549,搜「StrategyQA」)与(:554,搜「GSM8K」)。 2

  19. 出处:「Chapter 8. Conversational Agency」第 558-562 段(text/11-ch08-chapter-8-conversational-agency.txt:558,搜「Large Language Models are Zero-Shot」)。

  20. 出处:「Chapter 8. Conversational Agency」第 563-570 段(text/11-ch08-chapter-8-conversational-agency.txt:563,搜「Pause Tokens」)。

  21. 出处:「Chapter 8. Conversational Agency」第 578-639 段(text/11-ch08-chapter-8-conversational-agency.txt:579,搜「ReAct」)与(:613,搜「1844」)。

  22. 出处:「Chapter 8. Conversational Agency」第 640-660 段(text/11-ch08-chapter-8-conversational-agency.txt:646,搜「three thousand examples」)与(:649,搜「8B」)。 2

  23. 出处:「Chapter 8. Conversational Agency」第 661-674 段(text/11-ch08-chapter-8-conversational-agency.txt:661,搜「ALFWorld」)与(:673,搜「71%」)。 2

  24. 出处:「Chapter 8. Conversational Agency」第 677-712 段(text/11-ch08-chapter-8-conversational-agency.txt:680,搜「plan-and-solve」)与(:694,搜「Reflexion」)、(:705,搜「Branch-solve-merge」)。「I'm sorry for transferring your assets to your ex-husband's account. I won't do that again!」(:698)。