1.2 Agent 的最小内核:LLM + 上下文 + 工具 + 循环
一句话结论:上一篇给了你直觉,这一篇把它拆成零件。一个 Agent 由四个模块组成、跑一个四步闭环——任何一个零件缺失,它就不再是 Agent,而退化成别的东西。
读这篇之前
需要先读 1.1,特别是「一次性调用只能基于已有信息回答」那一段。
一、四个零件,缺一不可
先把零件摆出来:
| 模块 | 别称 | 负责什么 | 缺了会退化成 |
|---|---|---|---|
| LLM | 大脑 | 理解意图、推理、决定下一步 | 固定流程脚本 |
| 记忆(Memory) | 上下文 | 短期:本次对话;长期:跨会话的知识库 | 每一次都是无状态单次调用 |
| 规划(Planning) | —— | 把复杂任务拆成子任务、排出顺序 | 只会一步一动,遇复杂任务就崩 |
| 工具(Tools) | 手脚 | 调 API、查库、执行代码 | 只能"说",不能"做" |
这是原文给出的四大核心模块表述。[原文 705]
注意它和 1.1 里的「四件套」有一处不同:这里把「规划」单列出来了。原因很实际——规划和循环是两件事:
- 循环解决「要不要再来一轮」
- 规划解决「这一轮该干哪件事、先后顺序是什么」
一个只有循环没有规划的 Agent,会在原地打转:每轮都做一步,但不知道自己在走向哪。这也是为什么后面第 2 章要专门讲 ReAct 与 Plan-and-Execute 两种模式——它们就是两种不同的规划策略。
汇总一下:把两种说法合起来,Agent 的完整零件是 LLM + 记忆 + 规划 + 工具,外面套一个循环,循环里带终止条件。
二、四步闭环:感知 → 决策 → 行动 → 反馈
零件齐了,它们怎么转起来?
一个任务从进入到完成,走的是一条固定的路:
① 感知(Perceive) 看懂用户要什么
② 决策(Decide) 判断下一步该做什么
③ 行动(Act) 调用工具,改变外部状态
④ 反馈(Observe) 拿到结果,回到 ①
这四步会反复转,直到任务完成。
这个闭环不是拍脑袋想出来的,它源自控制论里的 OODA 循环(Observe–Orient–Decide–Act)——由军事战略家博伊德提出,用来描述飞行员在空战中的决策过程。核心洞察是:谁能更快地完成这个循环,谁就占优势。[原文 705]
这个来源值得琢磨,因为它解释了 Agent 设计里一个常被忽略的点:速度不是附加项,而是能力本身。同样一个任务,循环转十圈花费十秒还是十毫秒,决定了你能不能用它做实时的事情。这也是原文 4577 提到「第一朵乌云」时,把「快慢分离」和「把推理做快」并列的原因。
闭环的关键在那条"回边"
四步里最容易被忽视的是第 ④ 步——反馈回到感知。
如果没有这一步,系统就是一个「开环」的自动机:它按预设执行,但不知道执行的结果如何。开环系统在稳定环境里能跑,一旦环境变化就会错得离谱。
Agent 之所以能处理"没预料到的情况",全靠这条回边:上一轮行动的结果,成为下一轮判断的依据。 这条回边也解释了为什么 Agent 必须"多次调用模型"——见 1.3。
三、为什么是这四个,而不是三个或五个
零件数量看着像拍脑袋定的,其实每个都有明确的必要性。用「去掉它还能不能完成任务」来检验:
| 去掉谁 | 会发生什么 | 结论 |
|---|---|---|
| 去掉 LLM | 没有判断力,只能按 if-else 走 | 那是 Workflow |
| 去掉记忆 | 每轮都从零开始,无法利用上轮结果 | 那是单次调用 |
| 去掉规划 | 只会一步一动,复杂任务无法拆解 | 能跑,但很笨 |
| 去掉工具 | 只能说不能做 | 那是 Chatbot |
四个模块的作用就是四条边界:每去掉一个,你就退化成一种更简单、更弱的东西。 反过来看,这也给了一个判断「我的系统够不够格叫 Agent」的清单——顺着这四项自查即可。
四、一个具体的例子:从「顾问」到「员工」
原文里有一个对照很能说明问题。同样一句需求:「帮我查一下明天北京的天气」。[原文 705]
ChatBot 的实际对话:
用户:明天北京天气怎么样?
Bot:我无法实时查询天气,但你可以访问天气预报网站……
用户:那帮我订个提醒?
Bot:抱歉,我没有这个能力。
Agent 的实际过程:
用户:明天北京天气怎么样?
Agent:[思考] 需要调用天气接口
Agent:[调用] weather_api("北京", 明天)
Agent:[观察] 晴,最高 28°C
Agent:明天北京晴,最高 28°C。需要我设个提醒吗?
差别不在「回答得好不好」,而在闭环是否完整:
- ChatBot 的闭环止步于「生成文本」——它告诉你该去查,但查的动作要你自己做。
- Agent 的闭环延伸到「改变外部状态」——它真的调用了接口、拿到了数据,甚至能顺手把提醒设了。
用一句话概括这种转变:
ChatBot 回答问题,Agent 解决问题。
ChatBot 时代的 AI 是「顾问」,Agent 时代的 AI 是「员工」——你交代目标,它自己规划步骤、调用工具、交付结果。[原文 705]
从「给你建议」到「替你完成」,中间隔着的就是与真实世界交互的能力。这是理解整个系列的钥匙。
五、拆开看:每个零件的最小实现
光知道"有四个零件"没用,真正动手时你会立刻遇到"这个零件该做成什么样"的问题。下面给出每个零件的最小可行实现和它的升级方向。
LLM:从"选模型"到"理解它的计量方式"
选模型只是第一步。你还需要理解一件事,否则调优会完全失去方向:模型是按 Token 计量的,不是按字。
Token 是模型处理文本的基本单位,它既不是一个字也不是一个词,而是介于两者之间——由分词器按 BPE(Byte Pair Encoding)算法自动切分,粒度取决于模型的词表。[原文 704]
这带来两个直接影响 Agent 成本的推论:
- 同样的内容,不同模型的 Token 数不同。 同一句「我爱学习人工智能」,不同模型可能切成 4 个或 6 个 Token。
- 中文比英文贵。 主流词表以英文为核心,一个英文单词约 1~1.3 个 Token,而一个中文字符约 1.5~2 个 Token。同样 1000 字的内容,中文的 Token 密度更高。[原文 704]
所以当你在第 5 章考虑"上下文压缩"时,压缩中文带来的收益会比压缩英文更明显。
记忆:短期与长期,是两种不同的技术
- 短期记忆就是上下文窗口本身——本次对话里模型能看到的一切。它的上限由模型决定,装不下就得压缩(第 5 章)。
- 长期记忆存在模型外面,常见形态有向量库(按语义检索)、键值存储(按键精确取)、文件(人可读、易调试)。
判断用哪种很简单:你要"找意思相近的"就用向量;你要"取回某条具体记录"就用键值。 混用会导致检索效果莫名其妙(第 6 章细讲)。
规划:让模型拆,还是让代码拆
两种做法各有明确的适用面:
| 做法 | 什么时候用 | 代价 |
|---|---|---|
| 代码预先拆分 | 子任务数量与顺序可枚举 | 遇到没预料的任务就失效 |
| 模型动态规划 | 子任务数量事先不知道 | 不可预测、成本不可控 |
实际系统常常是混合的:外层代码定阶段,内层模型定动作(这就是 1.1 里那条编排光谱)。
工具:Agent 与外部世界的唯一接口
工具是唯一能"改变外部状态"的零件,所以也是风险最集中的地方。两个原则从第一天就该守住:
- 工具的输出是不可信输入——文件内容、网页正文、API 返回值里都可能藏着误导模型的文字(第 14 章的提示注入)。
- 不可逆动作要单独把关——删库、发邮件、部署上线,这类工具必须有人或额外校验介入(第 14 章的 HITL)。
六、从"能跑"到"能变好":这个内核的天花板在哪
四模块 + 闭环能跑通任务,但它还有三件事做不到,值得提前知道,因为它们决定了后面几部的存在理由:[原文 4577]
第一,它不会从经验里学习。
每次任务结束,那些踩过的坑、试出来的窍门,大多随着上下文一起被丢掉。下次遇到同类任务,它还是会踩。这不是实现缺陷,而是架构决定的——要让它"变好",需要评估(第 13 章)与后训练(第 18 章)。
第二,它的交互是回合制的。
绝大多数 Agent 仍是"你说完一句,它想一整段,再一次性吐出结果"。真实世界不会停下来等它想完——话会被打断、画面在变、邮件在来。走向实时性有两条路:架构上做快慢分离(前台快模型维持节奏、后台慢模型深度思考),或者把推理本身做快(当 decode 速度足够高,轮次等待就短到近乎消失)。[原文 4577]
第三,它的知识是静态的。
模型训练完成后知识就冻结了。这就是为什么需要检索(第 7 章 RAG)——不是为了让它更聪明,而是让它能查到训练时没有的东西。
这里提前点一句第 7 章的关键:RAG 为什么要先做 Embedding,而不是把全文塞进上下文? 因为上下文窗口有硬上限,把几十万字的资料全塞进去既装不下也贵得离谱。Embedding 的作用是把"文本"变成"可以比较远近的向量",从而能先只挑出最相关的几段再放进去。[原文 704]
之所以用"向量距离"来代表"语义相近",是因为模型把语义相近的文本映射到向量空间里彼此靠近的位置;这样"找相关内容"就变成了"找最近的向量"——一个可以被高效计算的问题。【推导】
换句话说:这个内核让你能造出一个能干活的 Agent,但"能干活"和"干得好、越干越好"之间,隔着评估、记忆、检索、工程化这四道坎。这也是本系列后面七部的内容。
七、把这四个零件落到代码里
概念懂了,动手时的第一个问题是"这四个零件具体是什么类的对象"。
一个最小映射
| 零件 | 代码里通常是什么 |
|---|---|
| LLM | 一个 chat(messages, tools) 函数 |
| 记忆 | 一个 messages 列表(+ 可选的外部存储) |
| 规划 | 不是一个类,而是提示词里的一段指令 + 循环里的判断 |
| 工具 | 一个 {name: callable} 字典 |
注意第三行——这是最反直觉的。
规划通常不是独立模块,而是:
① 提示词里写「先列步骤,再执行」(3.3 的 CoT)
② 循环里判断「计划完成了没有」
只有当规划复杂到需要单独一次模型调用时(12.5 的编排者-工作者),它才成为独立组件。
一个常见的过度设计
错:
class MemoryManager
class PlanningEngine
class ToolRegistry
class ContextBuilder
class LoopController
... 15 个类、2000 行,还没跑通一次
对:
def run(task):
messages = [{"role":"user","content":task}]
for _ in range(N):
r = llm.chat(messages, tools)
...
后者先能跑,再按需要拆。 这是复杂度阶梯(1.4)的又一次应用。
八、四步闭环与 OODA 的实际差异
原文说闭环源自 OODA(观察-判断-决策-行动)。但 Agent 的实际四步是"感知-决策-行动-反馈"。
顺序与环节都不同:
| OODA(军事) | Agent(实现) |
|---|---|
| Observe 观察 | 感知 Perceive |
| Orient 判断(结合经验与情境) | —— Agent 里没有这一步 |
| Decide 决策 | 决策 Decide |
| Act 行动 | 行动 Act |
| —— | 反馈 Observe(写回上下文) |
差异在两点:
- Agent 缺「Orient」:人类会把观察结合经验做"定向",模型没有这个独立环节——它的定向隐含在推理里。
- Agent 多「反馈」:把行动结果写回上下文,作为下一轮输入。
这个差异的实际含义:因为缺 Orient,Agent 更容易"看到什么就信什么"——这直接导致幻觉(2.3)与提示注入(14.2)。
所以工程上必须补三样:来源标记、输出校验、权限限制。
理论对照的价值就在这:它指出了模型的薄弱环节在哪。
九、常见误区
误区一:模块越多越强。
不是。四个是必要,不是充分。一个装了 20 个工具的 Agent 可能比装了 3 个的更容易出错(见 4.5「工具爆炸」)。
误区二:记忆就是向量数据库。
向量库只是长期记忆的一种实现。短期记忆是上下文本身;长期记忆可以是向量库、键值存储、甚至一个 Markdown 文件。选哪种取决于你要「按语义找」还是「按键精确取」。
误区三:规划一定要让模型做。
不一定。很多场景里,外层用代码规划阶段、内层让模型决定动作会更稳(见 1.1 的编排光谱)。让模型做规划的价值在于处理「拆几个子任务事先不知道」的情况。
误区四:闭环转得越多越好。
每转一圈都是一次完整的模型推理,成本与延迟线性增长。能一轮解决就别两轮。 这也是为什么 1.4 要讲「大多数场景根本不需要 Agent」。
误区五:OODA 只是理论,跟写代码没关系。
它的直接推论是:优化 Agent 性能时,减少循环次数和降低单轮延迟是两条独立的路径,都值得投入。
十、下一篇
零件和闭环都有了。但有一件事我们还没深究:为什么这个循环必须依赖「多次调用模型」? 难道不能在一次调用里把所有事都做完吗?
下一篇解答这个问题——答案藏在「模型只能看到上下文里有的东西」这条硬约束里。