跳到主要内容

智能体 — 观察、思考、行动的循环

这一章讲三件事: 智能体(agent)不是魔法,是「输入、目标、可用动作」三件套加一个循环; LLM 版智能体的最小实现(ReAct)到底有哪几个零件——少到你可以手写; 以及三件配套工程:工具怎么选、记忆怎么外挂、账单怎么算。 对应原书第 6 章全章。

1. 这一章讲什么

到第 09 章为止,模型都是「被问才答」。这一章让它自己决定下一步做什么:查不查、查什么、查完要不要算、什么时候算完。书里先给智能体一个冷静的定义:在特定环境里行动、感知、决策,以达成预定目标的东西1。拆开是三件套2:

  • 输入(Inputs):从环境收到的数据——对 LLM 来说就是文本;
  • 目标或奖励(Goal or reward):什么叫「做成了」——书里举例:特斯拉用「无人工干预行驶的里程数」当自动驾驶的奖励函数3;
  • 可用动作(Available actions):它能对世界做什么——对 LLM 来说就是工具。

主走查:一个两跳的问题。 「查一下 James Phoenix(本书作者之一)的年龄,然后平方。」这个问题单次调用答不了:先得搜出 31,再算 31²=961。我们跟着这个任务走完观察→思考→行动的整个循环。

2. 顶层全景:一个循环,四个零件

┌──────────────────────────────────────────┐
│ │
▼ │
观察(observation:现状是什么) │
→ 思考(thought:下一步该干什么) │
→ 行动(action:调哪个工具,参数是什么) │
→ 工具返回结果(tool_result)──────────────────────┘
……循环,直到输出「Final Answer」或撞上限(max_iterations)

图说:LLM 每轮只干一件事:根据写下来的全部历史,决定下一行写什么。
历史里先写「观察」再写「思考」再写「行动」——顺序就是推理的脚手架。

这个框架叫 ReAct(Reason and Act,边推理边行动),是对思维链(Chain-of-Thought,先一步步写出推理再给答案——第 06 章的「思考时间」就是它的零成本版)的改进:推理过程中可以真的动手查,查到的结果再变成下一轮的观察4

3. 核心原理

3.1 思维链:先把推理写下来

一切从一句咒语开始。书里的对照:让 GPT-4 给一款软件产品写营销计划,朴素提示得到泛泛而谈;加上「预算 $20,000」和「step-by-step(一步步来)」,计划立刻有了结构和针对性5。书里点名:step-by-step 这个短语是关键元素——它逼模型把中间步骤写出来再下结论,而不是直接跳到答案5

机理在第 06 章讲过:模型逐标记往下写,先写出来的字就是后面字的依据。「思考时间」让推理先于评判;智能体要更进一步:推理中间还要夹进外部世界的真实数据——那是工具的事。

3.2 ReAct:观察、思考、行动,不许猜

ReAct 把「一步步想」和「动手查」编进同一个循环。书里给了完整的提示模板,骨架是三条纪律6:

  1. 每轮先写观察(observation:现在的局面是什么),再写思考(thought:下一步该干什么),再写行动(action:工具名)和动作输入(action_input:参数);
  2. 不许猜或假设工具的结果——行动之后必须停,等程序把真实结果以 tool_result 填回来7;
  3. 循环终止于两种信号:模型自己写出 Final Answer,或者撞上限。

第 2 条是这个框架的命门。没有它,模型会一气呵成地把「搜索结果」也编出来——它本来就只会续写,编造一个看起来像真的结果毫不费力。

3.3 手写 ReAct:正则 + stop 序列就是全部

书里把这个循环亲手实现了一遍,零件少得惊人8:

  • 模型输出按约定格式写字(action: search_on_google / action_input: Jason Derulo partner…),程序用正则表达式把 action 和 action_input 两行抠出来——取最后出现的那一对;
  • 调对应的真函数,拿到真实结果;
  • 把结果以 tool_result: … 追加进对话历史,再调模型;
  • 关键配置:stop=["tool_result:"]——stop 序列(stop sequence:模型一旦写出这个字符串就立刻停止生成的开关)。它保证模型写到「等结果」的位置就闭嘴,绝不允许它自己编造 tool_result 那一行——书里明说,这就是防工具使用幻觉的机关9

书里拿「Jason Derulo 现在有伴侣吗?」走了真实的一轮:观察原问题 → 思考「我不知道,得搜」→ 行动 search_on_google → 工具返回「他没有妻子或伴侣」→ 模型给出 Final Answer10。看懂了这一轮,就看懂了 ReAct:框架的全部工作,是维护那份不断变长的文本历史

3.4 工具:从字符串数到 34

工具从哪来?三条路:自己写函数、用现成的(搜索、计算器)、或拿打包好的工具包。书里演示了自己写:一个数字符串长度的函数,挂上 Tool.from_function——函数名和描述不是注释,是给模型选路用的路标11。测试问题:「supercalifragilisticexpialidocious 有几个字符?」——这种题模型自己数必错,agent 选择调用工具,返回 34,答对11

主走查的两跳问题在同一节:配两个工具(Google 搜索 + 计算器),agent 第一轮(循环的一圈)搜出「James Phoenix is 31 years old」,第二圈调计算器算 31²,输出 96112

两条边界书里写明了:工具不是越多越好——工具太多,模型会在每一步困惑该用哪个13;以及函数调用(第 08 章)与 ReAct 的选型——书里给了对照表,压成一行:函数调用适合「一次调用、可能并行调几个函数」,ReAct 适合「多轮(多个回合)、每一轮都依赖前面那一轮结果」的任务14

3.5 记忆:模型不记得,你来替它记

模型本身没有记忆:每次调用都是全新的一次,「上一轮说过什么」只存在于你发去的提示里(第 02 章的结构性事实)。所以记忆是外挂的——书里的分工:长期记忆(LTM)是图书馆(向量库、自反思、自定义检索),短期记忆(STM)是对话历史本身15。LangChain 的记忆机制固定两步:执行前读、完成后写16

书里给了五种短期记忆方案,账单各不相同17:

方案怎么存适合代价
Buffer全存,不限制短对话长了必爆窗口
BufferWindow只留最近 k 条(k=1 就是只记一轮)只在乎就近上下文旧事全忘
Summary让模型把历史滚动摘要长对话要点摘要丢细节
SummaryBuffer混合:近期原文 + 远期摘要,超标记上限就把老的压成摘要大多数人实现最复杂
TokenBuffer按标记数冲刷旧消息预算卡得死同样丢旧事

(这张表是书里五个同名小节的压缩17。)注意 SummaryBuffer 就是第 08 章主走查里「前一场摘要喂下一场」的通用化。另外书里提醒:默认记忆存在内存里,进程一停就没——生产环境要落数据库(书里演示了存 MongoDB,按 session_id 区分会话(一段段对话))18

3.6 规划与思维树:想一条道,还是探一片林

ReAct 是「边走边想」。还有两种更重的结构:

规划—执行(plan-and-execute):把「定计划」和「干活」分给两个模型——规划器拿着目标、当前任务、已完成任务列表,排出任务清单;执行器逐个完成。书里的两个代表:BabyAGI(执行→造任务→排优先级三个角色循环,配向量库存结果)和 AutoGPT;LangChain 里有,但还是实验性的19

思维树(Tree of Thoughts, ToT):思维链是一条道走到黑;思维树在每个岔口同时探多条路,自己给每条路打分,走不通就回溯。书里给的硬数字:24 点游戏(用四个数和四则运算凑 24),GPT-4 用思维链成功率 4%,换思维树达到 74%20。书里的演示题是数独:把 * 通配符替换成满足规则的数字20

3.7 回调与算钱:循环必须有仪表盘

循环一旦跑起来,两件事立刻变成刚需:看见它在干什么、知道它花了多少钱。

回调(callback:事件发生时自动执行的钩子函数,第 08 章六模块之一)管第一件:LangChain 在每个节点(模型开始、吐新标记、结束、出错、工具被调、agent 行动)都会触发事件,你挂一个处理器就能观测21。挂在哪有两种:构造时挂(这个实例的每次调用都触发)和调用时挂(只这一次)22

算钱管第二件:get_openai_callback 上下文管理器把一次或一串调用包起来,出来就有 total_tokenstotal_cost(总花费)、提示与补全各多少23。agent 循环动辄十几次调用,逐次记账是控制成本的唯一办法——第 05 章的预算纪律在这里变成了会计纪律。书里还给了另一道保险:max_iterations=15 之类的上限,agent 陷入死循环时止损24

4. 作者的判断与证据

  • ReAct 循环、正则抠动作、stop 序列,全部有书里的可运行代码和真实输出(Jason Derulo、34 个字符、961);
  • 「工具太多会困惑」是经验陈述,没有量化阈值(触发警报的临界值)13;
  • 24 点的 4%→74% 引自思维树的原始论文结果,书里转述20;
  • BabyAGI/AutoGPT 是 2023 年智能体热潮的标志物;书里如实标注 LangChain 的 plan-and-execute「还是实验性的」19

判断(我们的,不是书里的): 这一章的五个主题(循环、工具、记忆、规划、观测)有一个共同来源——它们全在补偿同一个结构缺陷:模型只会「读历史、写下一行」。工具是它的手(历史里写不下真实世界),记忆是它的脑(历史写不下那么长的过去),规划是它的自我分解(一口气想不全),回调与计数是人的眼睛与账本。学 agent 框架时,凡是一个新零件,先问它补的是哪一块。 如果错,会错在: 如果模型的上下文窗口大到「全部历史随便装」且便宜,记忆方案会简化;如果模型内生地学会调用工具而不靠提示格式(2024 年后的函数调用训练正是这个方向),正则抠动作那层会消失——但「历史是唯一通道」这个结构事实不变,零件只会换形态,不会消失。

5. 边界与局限

  • ReAct 依赖提示纪律:模型可能不遵守格式、瞎编 action、或者陷入无效循环——stop 序列和 max_iterations 是止血带,不是治愈;
  • 书里的 agent 生态快照是 2023-2024 年:AutoGPT/BabyAGI 已退烧,OpenAI Functions 已改名 Tools(书里自己标了「已弃」);读法:学结构,不学名号;
  • 思维树的 74% 是论文里的特定任务成绩,不等于普遍收益——多路探索的成本是调用的数倍;
  • 记忆方案的「遗忘」都是静默的:被冲刷、被摘要掉的内容,模型不会告诉你它忘了;
  • 书里没覆盖多智能体(多个智能体分工协作的系统)协作(AutoGen 只在第 01 章点了名)和安全沙箱——agent 能调工具,就意味着能闯祸,这个话题本书基本留白。

6. 可带走的

  1. 智能体 = 输入 + 目标 + 可用动作 + 一个循环;不是魔法,是结构;
  2. ReAct 三行纪律:先观察再思考再行动;不许猜工具结果; Final Answer 或上限终止;
  3. 最小实现 = 正则抠 action + stop=["tool_result:"] 防编造——先手写一遍再用框架;
  4. 工具名和描述是给模型看的路标,当提示写,不当注释写;
  5. 工具别贪多:多了它会在每一步犯迷糊;
  6. 一次调用能办完的事用函数调用;多轮依赖才上 ReAct;
  7. 记忆五选一:短对话全存,长对话「近期原文+远期摘要」最均衡;
  8. 规划与执行分给两个模型;要在岔口探多路,用思维树;
  9. 循环必须配仪表盘:回调看行为,token 计数看钱,max_iterations 防死循环;
  10. 每个 agent 零件都在补「模型只会读历史写下一行」的某一块短板——用这条去拆解任何新框架。

7. 原文地图

主题原书章原文位置
智能体定义与三件套Ch.6 自主智能体text/38-ch06-chapter-6-autonomous-agents-with-memory-and-tool.txt:81(搜「acts, perceives」) · text/38-ch06-chapter-6-autonomous-agents-with-memory-and-tool.txt:95(搜「Inputs」)
特斯拉的奖励函数Ch.6 自主智能体text/38-ch06-chapter-6-autonomous-agents-with-memory-and-tool.txt:115(搜「without an intervention」)
step-by-step 营销计划Ch.6 自主智能体text/38-ch06-chapter-6-autonomous-agents-with-memory-and-tool.txt:75(搜「step-by-step」)
ReAct 框架Ch.6 自主智能体text/39-fm-reason-and-act-react.txt:3(搜「improved version of CoT」)
不许猜工具结果Ch.6 自主智能体text/39-fm-reason-and-act-react.txt:41(搜「Do not guess」)
正则抠动作Ch.6 自主智能体text/40-fm-reason-and-act-implementation.txt:13(搜「regular expressions」)
stop 序列防幻觉Ch.6 自主智能体text/40-fm-reason-and-act-implementation.txt:131(搜「stop sequence」)
Jason Derulo 走查Ch.6 自主智能体text/40-fm-reason-and-act-implementation.txt:138(搜「doesn't have a wife」)
数 34 个字符Ch.6 自主智能体text/41-fm-using-tools.txt:57(搜「34 characters」)
年龄平方 961Ch.6 自主智能体text/41-fm-using-tools.txt:173(搜「31 years old」) · text/41-fm-using-tools.txt:203(搜「961」)
工具太多会困惑Ch.6 自主智能体text/41-fm-using-tools.txt:209(搜「too many tools」)
函数调用 vs ReActCh.6 自主智能体text/41-fm-using-tools.txt:235(搜「Comparing OpenAI Functions and ReAct」)
长期/短期记忆Ch.6 自主智能体text/44-fm-long-term-memory.txt:3(搜「library」) · text/45-fm-short-term-memory.txt:13(搜「STM」)
五种记忆方案Ch.6 自主智能体text/49-fm-conversationbuffermemory.txt:3(搜「no restriction」) · text/50-fm-conversationbufferwindowmemory.txt:11(搜「k=1」) · text/52-fm-conversationsummarybuffermemory.txt:7(搜「token length」)
记忆落数据库Ch.6 自主智能体text/47-fm-preserving-the-state.txt:5(搜「MongoDB」)
规划—执行与 BabyAGICh.6 自主智能体text/54-fm-plan-and-execute-agents.txt:3(搜「two separate modules」) · text/54-fm-plan-and-execute-agents.txt:5(搜「BabyAGI」)
思维树 4%→74%Ch.6 自主智能体text/55-fm-tree-of-thoughts.txt:9(搜「74%」) · text/55-fm-tree-of-thoughts.txt:11(搜「sudoku」)
回调两种挂法Ch.6 自主智能体text/56-fm-global-constructor-callbacks.txt:3(搜「constructor」) · text/57-fm-request-specific-callbacks.txt:3(搜「invoke()」)
token 计数Ch.6 自主智能体text/60-fm-token-counting-with-langchain.txt:8(搜「get_openai_callback」)
死循环上限Ch.6 自主智能体text/43-fm-use-cases-for-react.txt:159(搜「endless loop」)

Footnotes

  1. 出处:「Ch.6 自主智能体」第 81 段(text/38-ch06-chapter-6-autonomous-agents-with-memory-and-tool.txt:81,搜「acts, perceives」)。

  2. 出处:「Ch.6 自主智能体」第 95-117 段(text/38-ch06-chapter-6-autonomous-agents-with-memory-and-tool.txt:95,搜「Inputs」)。LLM 版的三件套映射:文本化一切输入、提示定目标、工具扩动作空间。

  3. 出处:「Ch.6 自主智能体」第 115 段(text/38-ch06-chapter-6-autonomous-agents-with-memory-and-tool.txt:115,搜「without an intervention」)。

  4. 出处:「Ch.6 自主智能体」第 3 段(text/39-fm-reason-and-act-react.txt:3,搜「improved version of CoT」)。

  5. 出处:「Ch.6 自主智能体」第 75 段(text/38-ch06-chapter-6-autonomous-agents-with-memory-and-tool.txt:75,搜「step-by-step」)与第 77 段(text/38-ch06-chapter-6-autonomous-agents-with-memory-and-tool.txt:77,搜「$20,000」)。 2

  6. 出处:「Ch.6 自主智能体」第 33-50 段(text/39-fm-reason-and-act-react.txt:34,搜「observation_text」)。循环终止条件(Final Answer 或最大迭代数)见第 3 段。

  7. 出处:「Ch.6 自主智能体」第 41 段(text/39-fm-reason-and-act-react.txt:41,搜「Do not guess」)。原文:「Do not guess or assume the tool results.」

  8. 出处:「Ch.6 自主智能体」第 13 段(text/40-fm-reason-and-act-implementation.txt:13,搜「regular expressions」)。

  9. 出处:「Ch.6 自主智能体」第 131 段(text/40-fm-reason-and-act-implementation.txt:131,搜「stop sequence」)。原文:强制模型在遇到 "tool_result:" 时停止生成,以此防工具使用的幻觉。

  10. 出处:「Ch.6 自主智能体」第 138 段(text/40-fm-reason-and-act-implementation.txt:138,搜「doesn't have a wife」)与第 221 段(text/40-fm-reason-and-act-implementation.txt:221,搜「Observe the original question」)。

  11. 出处:「Ch.6 自主智能体」第 55-67 段(text/41-fm-using-tools.txt:55,搜「supercalifragilistic」;text/41-fm-using-tools.txt:57,搜「34 characters」)。 2

  12. 出处:「Ch.6 自主智能体」第 173 段(text/41-fm-using-tools.txt:173,搜「31 years old」)与第 203 段(text/41-fm-using-tools.txt:203,搜「961」)。

  13. 出处:「Ch.6 自主智能体」第 209 段(text/41-fm-using-tools.txt:209,搜「too many tools」)。 2

  14. 出处:「Ch.6 自主智能体」第 235 段(text/41-fm-using-tools.txt:235,搜「Comparing OpenAI Functions and ReAct」)。函数调用的优势行:运行时决策、单工具执行、易并入对话 agent、并行调用。

  15. 出处:「Ch.6 自主智能体」第 3 段(text/44-fm-long-term-memory.txt:3,搜「library」)与第 13 段(text/45-fm-short-term-memory.txt:13,搜「STM」)。

  16. 出处:「Ch.6 自主智能体」(text/47-fm-preserving-the-state.txt:5,搜「MongoDB」)。生产环境落库、按 session_id 区分,见同节。

  17. 出处:「Ch.6 自主智能体」第 3 段(text/49-fm-conversationbuffermemory.txt:3,搜「no restriction」)、第 11 段(text/50-fm-conversationbufferwindowmemory.txt:11,搜「k=1」)、第 13 段(text/51-fm-conversationsummarymemory.txt:13,搜「ConversationSummaryMemory」)、第 5-13 段(text/52-fm-conversationsummarybuffermemory.txt:7,搜「token length」)与第 3 段(text/53-fm-conversationtokenbuffermemory.txt:3,搜「flush」)。 2

  18. 出处:「Ch.6 自主智能体」(text/47-fm-preserving-the-state.txt:5,搜「MongoDB」)。

  19. 出处:「Ch.6 自主智能体」第 3 段(text/54-fm-plan-and-execute-agents.txt:3,搜「two separate modules」)、第 5 段(text/54-fm-plan-and-execute-agents.txt:5,搜「BabyAGI」)与第 17 段(text/54-fm-plan-and-execute-agents.txt:17,搜「experimental」)。 2

  20. 出处:「Ch.6 自主智能体」第 9 段(text/55-fm-tree-of-thoughts.txt:9,搜「74%」)与第 11 段(text/55-fm-tree-of-thoughts.txt:11,搜「sudoku」)。ToT 机制(思想=连贯文本块、多路探索+自评+回溯)见第 3 段。 2 3

  21. 出处:「Ch.6 自主智能体」(text/56-fm-global-constructor-callbacks.txt:3,搜「constructor」)。

  22. 出处:「Ch.6 自主智能体」(text/57-fm-request-specific-callbacks.txt:3,搜「invoke()」)。

  23. 出处:「Ch.6 自主智能体」第 8-17 段(text/60-fm-token-counting-with-langchain.txt:8,搜「get_openai_callback」;text/60-fm-token-counting-with-langchain.txt:17,搜「total_tokens」)。

  24. 出处:「Ch.6 自主智能体」第 159 段(text/43-fm-use-cases-for-react.txt:159,搜「endless loop」)与第 172 段(text/43-fm-use-cases-for-react.txt:172,搜「15」)。