现在市面上的 Agent 教程太多了,要么太浅要么太碎。
之前一直关注的博主三元同学最近出了吃透 AI Agent 开发,这门课从「底层实现级」角度拆解真实产品的工程决策,帮你建立完整的 Agent 知识体系,覆盖六大方向。
这门课学习下来让我对 Agent 有了全面的认知,下面是我的学习笔记
前言
当你对 Claude Code 说「帮我把这个项目的 moment 全部替换成 dayjs,200 多个文件」,从按下回车到任务完成,中间发生了什么?
它不是魔法,也不是一个庞然大物一次性算完的。它是一圈一圈、一步一喘地「循环」过来的------每个循环都在做三件事:观察、判断、决定。这就是 Agent 最核心的骨架:Agent Loop。
理解了这个骨架之后,你会发现最近铺天盖地的 Manus、OpenClaw、CrewAI、LangGraph 这些产品和技术,表面上形态各异,底层全在解决同一组问题。而且这组问题的数量,远比你想象的少------六大支柱。
六大支柱全景
| 支柱 | 核心职责 | 人体类比 |
|---|---|---|
| Agent Loop | 决策循环的闭环与自适应 | 心跳 |
| Tool System | 工具调用与结果验证 | 手脚 |
| Context Engineering | 窗口内信息的管理与筛选 | 供血 |
| Memory | 跨越会话的持久化知识 | 海马体 |
| Multi-Agent | 通过隔离对抗上下文熵增 | 社交系统 |
| Harness Engineering | 评测体系与工程基建 | 骨架 |
一、Agent Loop:智能体的心跳
什么是 Agent Loop
Agent Loop 是 Agent 运行的最小单元,它不是简单的 while 循环,而是一个不断重新评估局势的动态决策过程。这个循环包含四个阶段:
接收 → 思考(理解需求、制定计划)→ 行动(调用工具)→ 观察结果 → 再思考 → 再行动......直到任务完成。
但真正重要的不是「执行」,而是 观察 → 判断 → 决定 三步。Agent 在每次行动后都会观察结果,根据结果重新判断局势,然后决定下一步行动。这使得 Agent 能够在执行中学习,而不是盲目执行完再承受后果。
实战场景:moment → dayjs 替换
以「替换 moment 为 dayjs」为例。当 Agent 搜索到一个 analytics.ts 文件时,它观察到了三件事:
moment().format('YYYY-MM-DD')可以直接替换为dayjs().format('YYYY-MM-DD')- 文件中存在
moment-timezone的引用 - dayjs 需要安装
dayjs/plugin/timezone才能等效替换,但项目中没有安装
这意味着原计划的「直接替换」行不通了。Agent 必须重新判断:
- 选项A:做简单替换,但功能会损坏
- 选项B:补上插件安装加上完整替换(增加副作用风险)
- 选项C:跳过此文件,标记需要人工审查
每一次循环都是「做一步、看一眼、再决定下一步」。Agent Loop 的精髓正在于此:它不是流水线,而是一个不断重新评估局势的过程。
Human-in-the-Loop
Agent Loop 还有一个重要分支:Human-in-the-Loop(暂停并询问)。在关键决策点,Agent 可以停下来等人类确认再继续。这种「暂停并询问」的模式是心跳不一定完全自主的体现。
Agent Loop 的工程挑战
最简单的 Agent Loop 10 行代码就能写出来,但实际跑起来会面临一堆工程问题:
- 截断恢复:模型说到一半被截断了怎么办?Claude Code 用 3 次递进恢复
- 死循环检测:Agent 陷入死循环怎么办?OpenClaw 设计了 4 种检测器
- 降级策略:API 挂了怎么办?三层重试------API 级 → 流式降级 → 模式降级
二、Tool System:智能体的手脚
工具调用 ≠ 程序调用函数
Tool System 解决的是「用什么动」的问题。Agent Loop 告诉你什么时候该动,但至于用什么动,是 Tool System 要解决的。
但这里有一个极其关键的区别:Agent 调用工具 ≠ 程序调用函数 。函数调用是确定性的------你传 add(1, 2),它一定返回 3。但 Agent 调用工具时,中间多了一层模型生成的调用意图。
换句话说:Agent 先要「说出」它想调什么工具、传什么参数------这个「说」的过程本身就可能出错。
「嘴炮」风险
文章里对这种错误有一个非常形象的叫法:「嘴炮」。模型生成了一段看起来像工具调用的文本,但实际上根本没有执行任何东西。
模型在输出工具调用时,它的本质是在做「文本预测」,而不是真的在「操作工具」。它只是生成了一个符合 JSON 格式、看起来像函数调用的字符串。至于这个字符串能不能跑、参数对不对,模型自己并不真正「知道」。
调用链的典型错误
1. 说的时候出错(嘴炮)
- 调用了不存在的工具名
- 参数名和实际注册的不一致
- 参数值错误(文件路径、ID 等)
2. 执行的时候出错
- 权限问题
- 网络/IO 失败
- 超时中断
3. 结果返回时出错
- 格式错误(raw text vs 结构化 JSON)
- 只返回了部分结果
- 模型误解结果
核心设计原则
模型负责「表达意图」,工具负责「校验」。 权限检查必须放在工具侧,因为模型不可信------它不知道能不能写 /etc/hosts,它只是「说」要写。安全决策不下放给模型,所有安全、权限、参数合法性的验证必须在执行侧完成。
工具侧不仅要校验输入,还要保证输出是可观察的。如果工具返回的是一个混乱的非结构化文本(比如 shell 命令的原始输出),会导致:
- 关键信息被淹没
- 语义丢失(表格对齐错乱、没有换行符)
- 无法判断成功/失败
- 下游工具调用受影响------模型没有看懂上一个工具返回的结果,下一个工具的调用就要靠猜了
工具越多越不准
10 个工具以内,模型选择准确率 > 95%;30 个工具,降到 ~85%;50 个以上,不做特殊处理就是灾难。
解决方案有两种代表性思路:
- Claude Code 的 Deferred Tool Loading:初始 prompt 只放工具名和一句话描述,按需加载完整定义
- Manus 的原子化策略:只保留不到 20 个原子工具,复杂操作全部通过写脚本放 sandbox 里跑
三、Context Engineering:最被低估的支柱
供血系统
Context Engineering 被比作大脑的供血系统:不是把全身的血都泵到脑子里,而是精准地把氧气送到最需要的区域。
模型对上下文头部和尾部的信息注意力最强,中间的内容会被逐渐忽略。你往上下文里塞的东西越多,模型对中间信息的「记忆力」就越差。所以上下文管理的核心不是「怎么塞更多」,而是怎么让模型在有限的注意力预算内看到最关键的信息。
这就是著名的「Lost in the Middle」现象。很多人以为上下文窗口从 4K 涨到 128K 甚至 1M,Agent 就自动变强了------但实际上,窗口越大,中间信息被忽略的风险越大。
为什么直接堆历史行不通
量的问题:
- 注意力稀释:模型对中间信息记忆力最差
- 成本爆炸:token 消耗和延迟随上下文增长
- 信息覆盖:早期关键信息被挤出窗口
质的问题更致命:
- 自循环幻觉:模型把第三轮生成的错误当作事实复诵,到第五轮调用时发现不对但无法撤回
- 矛盾信号:第二轮说工具不存在,第四轮工具创建好了,模型不知道哪个是真的
- 错误驱逐:噪音信息消耗注意力,挤掉正确的判断空间
Context Engineering 的核心工作不是「塞得更多」,而是:你手里有一个 128K 的窗口,但 Agent 运行了几十轮,累积了几十万字,你必须在每轮做筛选、压缩、重新组织。
四大操作维度
| 维度 | 做什么 |
|---|---|
| Offload(卸载) | 把信息搬到上下文之外------文件系统、sandbox |
| Reduce(压缩) | 就地缩小(Compaction)或用摘要替换(Summarization) |
| Retrieve(检索) | 从外部按需取回------RAG、文件读取、ToolSearch |
| Isolate(隔离) | 拆成多个独立上下文------Multi-Agent |
如何判断信息该保留还是丢弃
- 看是否在「推理链」上:一条信息是否是模型下一步决策的前提?约束条件需要记忆,操作步骤做完就没意义
- 看信息来源:工具返回的结果 > 模型生成的总结;用户明确说出的偏好 > 模型推测的用户意图
- 看可恢复性:随时能从工具重新获取的,优先级低
- 看语义冗余度:有摘要则细节可删,但压缩不等于删除,要保留对细节的恢复能力
Context Engineering 与 Memory 的边界
Context Engineering 管的是「此刻上下文窗口里有什么」,Memory 管的是「信息怎么持久化」。两者是互补的:Memory 提供 offload 的底层支持,Context Engineering 决定什么时候把信息卸载,什么时候把信息从 Memory 中加载进来。
Context Engineering 卸载信息,其实是把暂时不要的信息移动到 Memory 中。 Context Engineering 是管窗口内的,Memory 是管窗口外的。
四、Memory:跨越对话的记忆
什么是 Agent 的 Memory
如果 Memory 只是存东西,那跟一个数据库有什么区别?
数据库存的是「原始数据」,像是一个死板的仓库。而 Agent 的 Memory 在存入和取出时,多了一个大模型的语义加工。
数据库是「存入 A,取出 A」。但在 Agent 的 Memory 里,存入的可能是一段 5000 字的凌乱对话,存入时模型会先做一次总结和提取 ;取出的也不是原始记录,而是模型根据当前问题检索并重构后的关键信息。
事实 vs 事件
Memory 的灵魂是存「学到的事实」,不是「事件的原始记录」。
| 类型 | 说明 | 示例 |
|---|---|---|
| 事实(Fact) | 从具体事件抽象出的原则 | 「用户偏好 pnpm」 |
| 事件(Event) | 原始记录,往往只是噪音 | 「用户上周二下午三点输入了 pnpm install」 |
Claude Code 用 MEMORY.md 中写下的是「用户偏好是 pnpm」而不是「用户上周三下午三点在终端里输入了 pnpm install dayjs」。这就像人类的记忆------你可能不记得五年前的某个周二下午三点你具体写了哪行代码,但你记住了「我以后写并发程序一定要加锁」。
存太细的问题
如果存得太细(连用户中午吃了什么都存),会发生什么?
- 噪音多,检索会失效
- 上下文污染:会取出一些当前不需要的内容,污染了上下文
- 模型会混淆:太多无用的信息会干扰模型的判断
- 自维护成本上升:每次都要判断这条和现有的有没有冲突
冲突时的演进设计
当新事实与旧记忆发生冲突时(比如用户说「以后改用 yarn 了」),不是简单地覆盖,而是保留「认知演进」:
- 新事实优先(时间戳更新)
- 覆盖时做语义转换,保留历史轨迹:
用户切换到了 yarn(之前偏好 pnpm)
这样 Agent 在做决策时,不仅知道「用户现在在用什么」,还知道「用户为什么会切换」、「用户之前用什么」。这能帮助 Agent 在遇到新工具选型时提出更合理的建议。
五、Multi-Agent:隔离的力量
不是角色扮演,是上下文隔离
很多人一听到 Multi-Agent,脑子里浮现的是一个 Agent 扮演「产品经理」,一个扮演「程序员」,大家聚在一起开会聊天。但在实际的 Agent 系统设计中,这种「角色扮演」反而是最不重要、甚至是有误导性的。
Multi-Agent 的核心价值是分隔上下文------让每个子 Agent 在干净的窗口里工作。
隔离的必要性
如果一个任务非常复杂(比如要写一个包含 10 个模块的复杂系统),让一个全能的 Agent 在一个对话窗口里从头干到尾会遇到:
- Context 溢出:第 1 个模块的决策被后面的信息淹没了
- Lost in the Middle 更严重:10 个模块的信息都挤在了一起,中间部分是模型注意力最差的------可能正好是最关键的系统架构决策
- 工具调用争抢窗口空间:上下文满了,模型不知道优先看哪个
解决方案是让主 Agent 把任务拆成子任务,每个子任务在自己干净的上下文里工作。子 Agent 探索完,返回的是压缩后的摘要(比如 10K 探索,1-2K 的结论),主 Agent 的窗口始终保持干净。
为什么不直接扩大窗口
把上下文窗口做得无限大(比如 100 万 token)能不能解决问题?不能。
- Lost in the Middle 不随窗口变大而消失
- 模型不知道该看哪里------模型不是搜索引擎,你让它在 100w 字里找重点和在 10w 字里找重点肯定是不一样的
- 成本和延迟会爆炸
隔离的价值不是腾空间,而是上下文干净的问题。 子 Agent 在自己的上下文里全力思考,不用担心被其他任务的信息干扰,父 Agent 收到的永远是一个干净的结论,而不是过程日志。
通信契约:只传产出,不传过程
子 Agent 完成任务后,应该给主 Agent 返回:
- 任务完成状态(成功/失败/部分完成)
- 关键结论(测试覆盖率、发现的 bug、改了哪些文件)
- 对父 Agent 后续决策有影响的信息(依赖的变更、接口修改、风险点)
- 必要时附带原始日志的位置
Multi-Agent 的通信契约本质上是:每个 Agent 只传「自己的产出」,不传「自己的过程」。 父 Agent 用结论做决策,需要细节时再按需去子 Agent 那里查。
逻辑防火墙
Multi-Agent 还提供了一层 逻辑防火墙:如果一个子 Agent 在执行任务时遇到了严重的「幻觉」或者逻辑死循环,这种错误会被限制在它的局部上下文里,而不会直接污染主 Agent 的决策链。
设计示例:自动写小说并配图
如果要用 Multi-Agent 架构做「自动写小说并配图」:
- Agent A - 剧情构思:专注人物关系、情节线、世界观设定
- Agent B - 文字写作:基于剧情结论写小说正文
- Agent C - 画图提示词:从文字中提取视觉场景,生成配图 Prompt
如果用单 Agent,「构思剧情」时产生的大量中间状态会干扰「画图提示词生成」------模型可能会无意识地把「叙事」相关的上下文带到「视觉描述」里,导致画图 Prompt 风格不一致。
Multi-Agent 隔离的价值在于:每个子 Agent 拿到的是前一个环节的「结论」,不是「过程」。Agent B 拿到的是干净的剧情梗概,不包含 Agent A 构思时的来回折腾。
六、Harness Engineering:从 Demo 到产品
什么是 Harness
Harness 的原意是「马厩」或「安全带」,在 Agent 系统里,它是保护你的 Agent 不会在升级和迭代中崩溃的那套评测工具链。
文章里有一个观点:「Agent 的上限由模型决定,但下限由 Harness 决定。」
很多人在做 Agent 时,觉得「跑通一个 Demo」就算做成了。但在真实产品中,你会发现 Agent 极不稳定------今天能跑通,明天改了一个 Prompt 甚至只是换了个模型,它就罢工了。
拍脑袋式评估的风险
如果你只是人工点点鼠标测几个 case,你会面临最大的风险:永远不知道没测到的 case 长什么样。
- 覆盖不了长尾:你测了 10 封正常的邮件,但用户发了一份不正常的邮件
- 改 Prompt,你以为变好了,其实某个你没测过的场景变差了
- 无法量化质量:人工无法覆盖概率性的失败
因为 Agent 的行为空间是海量的,而人工测试的速度远远跟不上。你可以测 10 个 case,但线上可能有 10000 个 case。
评测指标体系
| 维度 | 指标 |
|---|---|
| 功能性 | 任务完成率、准确性 |
| 性能 | 工具延迟、端到端延迟、Token 消耗 |
| 鲁棒性 | 一致性(Stability)、边界处理、错误恢复 |
| 质量 | 幻觉率、指令遵循度、上下文污染 |
| 回归 | Prompt 改动后的 delta、模型升级影响 |
关键指标说明:
- 一致性(Stability):同样的问题问十次有几次出错?如果有三次出错,那它在产品端就是不可用的
- 幻觉率:需要设计 ground truth 对比,准备一批「已知正确答案」的测试用例
- 延迟 SLA:工具慢需要在 Harness 里埋入 latency SLA,超过阈值算失败
为什么 Harness 是闭环
前五个支柱造的是一辆车,但不知道它能跑多远、能承受什么路况、哪个零件坏了会不会散架。Harness 就是那套量化体系:告诉你车现在能跑多快、油耗多少、哪个零件有问题。没有它,你每次改装都是在拍脑袋。
Harness 的核心价值不是「测」,而是「让你敢改」。
在 Agent 开发中,最让人痛苦的不是代码写不出来,而是「不敢动 Prompt」。因为你不知道改了这一个形容词,会导致之前明明能跑通的某个长尾 case 突然崩掉。
Harness 提供的不仅仅是数据,更是一种工程自信心。它让你从「炼丹师」变成了「工程师」。
早期引入 Harness 的价值
对 Context Engineering 迭代的帮助:
- 调整了上下文压缩的策略,可以跑一套回归测试,立刻看到这次改动在各项指标上是变好还是变差
- 迭代速度提升一个数量级,不再是拆盲盒
对 Tool System 迭代的帮助:
- 给 Tool System 加了一个新工具,可以跑一套回归测试,看有没有引入新的错误
对跨模型升级的帮助:
- 换了个新模型,跑一套评测套件,哪个指标掉了、掉了多少、需不需要回退,清清楚楚
学习路径:六大支柱的依赖关系
六个支柱不是平行的,它们之间有严格的依赖关系:
- Agent Loop(心跳):先理解 Agent 的最小可运行单元
- Tool System(手脚):Agent 能「做事」了,你才能观察后面的问题
- Context Engineering(供血):Agent 跑起来之后,上下文爆了怎么办?这是深水区的入口
- Memory(记忆):单次会话、跨会话,上下文记忆怎么来管理?
- Multi-Agent(协作):一个 Agent 不够用,怎么拆成多个?
- Harness Engineering(骨架):上面都搞定了,怎么包成一个生产级系统?
如果你先理解 Agent Loop 的「接收→思考→行动→观察」节奏,你自然就会发现每次循环的「接收」和「观察」都在往上下文里写入新信息,而每次「思考」都在消耗上下文窗口里的注意力------这时候 Context Engineering 就变成了为了解决一个你真实感受到的瓶颈。
反过来,如果先理解 Context Engineering 再理解 Agent Loop,就会出问题:Context Engineering 的各种技术(压缩、分层、调度)必须附着在 Agent Loop 的运行时上才有意义。不知道 Agent 什么时候读上下文、什么时候写上下文、什么时候上下文被消费掉,就去学「怎么管理上下文」,就像不知道血液循环路径就去学「怎么给器官供血」。
学习评分总览
| 支柱 | 核心收获 |
|---|---|
| Agent Loop | 观察→判断→决定是决策框架,不是执行框架 |
| Tool System | 嘴炮风险、校验下沉、输出规范化 |
| Context Engineering | 质的问题比量的问题更致命 |
| Memory | 存事实不存事件,语义压缩与演进管理 |
| Multi-Agent | 隔离优于角色分配,只传产出不传过程 |
| Harness Engineering | 「敢改」的工程信心,让迭代有数据支撑 |
最重要的深坑警告
如果一个开发者只懂怎么调用模型 API,却完全不理解这六大支柱,他在从「Demo」走向「商业化产品」的过程中,最容易掉的深坑是 Context Engineering。
其他支柱的问题,要么直接报错,要么表现一致性的差,容易被发现。只有 Context Engineering 是隐性的,是慢性中毒的:
- 你可能跑了一个星期没发现问题,因为每次任务好像都能完成
- 但实际上 Agent 在某些场景下莫名其妙地变差了,你不知道为什么
- 模型换了个版本,同样的 Prompt 效果突然下降了,你以为是模型不行,其实是上下文里积累了污染
- 一个任务本来能跑通,偶尔崩了,你以为是玄学,其实是中间某次循环时上下文被噪声干扰了
Context Engineering 缺失的坑最深的原因:它的症状不会直接报错------不是代码报错,而是「行为不稳定」。你很难复现、很难 debug、很难量化。
这就是为什么说 Context Engineering 是最被低估的。
结语
当你理解了 Agent 的六大支柱之后,无论后续是学习具体的框架(如 LangGraph, CrewAI),还是研究最新的论文,你都能一眼看穿其背后的设计意图。
这些产品表面上形态各异------Manus、OpenClaw、Claude Code、CrewAI------但拆开来看,它们全都在解决这六个问题。你的 Agent 开发能力,不再取决于你用了哪个框架或哪个模型,而取决于你对这个六大支柱体系的理解深度。
Agent Loop 告诉你什么时候该动,Tool System 解决用什么动,Context Engineering 管理窗口内的注意力分配,Memory 沉淀跨越时间的知识,Multi-Agent 通过隔离对抗熵增,Harness Engineering 用科学评测为产品保驾护航。
理解了这套骨架,你就从单纯的 LLM 用户,进化到了具备系统化架构视角的 Agent 开发者。
学习完成于 2026-05-09