从实现逻辑出发,搭一个能干活的 Agent
TL;DR Agent = LLM + 上下文 + 工具。最小实现是一个 ReAct 循环;真正的工程量在模型之外:上下文的缓存约束与状态栏、双层记忆、工具描述与沙盒安全、评估先行、SFT 立形 RL 泛化。本文按实现顺序把这些问题和核心思路串起来。
从实现逻辑出发,搭一个能干活的 Agent
背景:这篇是读《深入理解 AI Agent:设计原理与工程实践》(李博杰,Apache 2.0 开源,GitHub: bojieli/ai-agent-book)的整理笔记。全书十章,从原理讲到工程实战,配 88 个可跑的实验。下面不按章节复述,而是按”实现一个 Agent 要解决哪些问题”重排,每个模块只讲两件事:要解决什么问题,核心思路是什么。细节和数据留给原书。
一、Agent 的本质:一个公式和一个循环
问题:Agent 到底由什么构成,最小可运行形态长什么样?
思路:Agent = LLM + 上下文 + 工具。直觉说法是”大脑 + 眼睛 + 手脚”,学术说法是策略 + 观察空间 + 动作空间。
最小实现只有一个 while 循环:把消息列表发给模型,返回工具调用就执行并把结果追加进去,没有工具调用就输出退出。这个循环叫 ReAct(思考 → 行动 → 观察)。支撑它的三条性质必须理解到位:
- 每次调用无状态,模型要的一切必须完整出现在消息列表里;
- 模型只决策,执行在框架侧——模型说调什么、传什么参,真正跑代码的是你的代码;
- 上下文 = 静态前缀 + 轨迹,前缀是系统提示词加工具定义,轨迹是随交互增长的消息历史。后面所有的优化都建立在这个切分上。
消融实验给出了各组件的必要性:缺工具定义彻底不能动,缺工具结果会反复调同一个工具直到卡死,缺思考过程前后决策矛盾,缺历史消息等于失忆。
工具不必多。七个就够了:代码解释器、Bash、读/写/编辑文件、Glob、Grep。这不是简化,而是主流通用 Agent 的真实配置——开放任务型 Agent 的内核就是一个 Coding Agent 加一个文件系统,因为代码是唯一能”创造新能力”的元能力。
二、Harness:模型之外的竞争力
问题:同样的模型,为什么有的 Agent 稳定可靠,有的一跑就崩?
思路:把公式扩展成 Agent = Model + Harness。Harness 是围绕模型搭的全部支撑代码,除上下文和工具外,还包括约束(能做什么、不能做什么)、验证(结果对不对)、纠正(错了怎么补救)。
一句话区分:上下文和工具让 Agent 能做事,约束、验证、纠正让 Agent 不做错事。生产级系统里,绝大部分代码属于后者——权限分类、上下文压缩、熔断器、错误恢复。
范式是层层包含的:软件工程 ⊂ 提示工程 ⊂ 上下文工程 ⊂ Harness 工程 ⊂ Loop 工程(跨轮次的持续自主运转)。当各家模型能力趋近,竞争优势就转移到这一层。
关于模型和 Harness 的消长,务实的立场是:模型还做不稳的,Harness 先补上;模型每内化一层,Harness 就卸下一层,去兜底新的能力前沿。
三、上下文工程:能力上限的真正决定因素
问题:模型够聪明,为什么在具体业务上还是不好用?
思路:模型智力是基础,上下文质量才是上限。一个中等模型配上组织好的上下文,常常胜过顶级模型在信息匮乏下摸索。
KV Cache 是硬约束,不是优化项。 前缀里有一个字符变化,整条缓存作废。所以三条铁律:系统提示词和工具定义定稿后不改;所有动态信息(时间、状态、计数)追加到末尾;永远用标准 API 消息格式(自己拼文本会偏离训练格式,削弱多步思考能力)。有团队在系统提示词里塞了一行当前时间,首 token 延迟从 0.5 秒涨到 3–5 秒,账单几乎翻倍。
提示词写 SOP 而不是规则堆砌。 内容不变、只打乱组织结构,任务成功率能掉 30% 以上。业务规则要细到可执行,模糊规则会让同一个任务在不同时间得到不同分类。
提示词太长就按需加载,这就是 Skills。 三层渐进式披露:元数据常驻(几百 token)→ 核心流程按需加载 → 细则引用子文档。关键是 description 写成路由条件(Use when / Don’t use when 加反例),”何时该用我”比”我能做什么”重要得多。
把隐式状态显式化,这就是 Agent 状态栏。 上下文窗口是一台只有一半的检索引擎:检索极强,但没有”提炼层”。所以模型数不清自己打过几次电话——解法是在工具结果里直接写”本次是第 3 次”。状态栏用一条追加在末尾的消息承载任务进度、环境状态、工具计数。两条经验:用代码维护而不是让模型去总结(模型批量统计长历史反而不如 20 行正则);光给读数不够,必须连”读数该怎么用”的策略一起给。
膨胀了就压缩,但更该隔离。 压缩不只是省长度,更是把需要思考才能得到的结论变成可直接检索的知识;生产上是分层的(大输出落盘、噪声直接删、归档式摘要、最后才是全量压缩),且必须显式定义保留优先级——最容易丢的是早期架构决策和失败路径。更釜底抽薪的是隔离:让子 Agent 去翻十几个文件,只回传一句结论,几万 token 根本不进主上下文。
四、记忆与知识库
问题:会话结束后,怎么让 Agent 记住用户、接上外部知识?
思路:两个尺度——用户记忆(个体)和知识库(群体),共用底层技术(检索、压缩),面临同样的麻烦(冲突、过期、检索不准)。
记忆设计有三套正交分类:存在哪里(轨迹 / 长期记忆 / 业务状态)、怎么存(从极简的 Simple Notes 到带来源背景和关系的 Advanced JSON Cards)、存什么(情景 / 语义 / 程序记忆)。取舍在简单性与表达力之间,成熟系统混合使用。再往外一步是”用户即代码”:把记忆变成带类型的可执行对象,能做聚合统计、冲突发现、约束执行这三件文本记忆做不了的事。
检索是稠密 + 稀疏 + 重排序三件套。 稠密懂语义但会漏精确关键词,稀疏精确但读不懂同义表达,两路融合后再用跨编码器精排。索引前给每个文本块加”出自哪里”的前缀(上下文感知检索),检索失败率能降近一半。
扁平检索不够时要结构化:RAPTOR 建知识树适合由宏观到微观,GraphRAG 建实体关系图擅长多跳推理和消歧。代价不小,只在确实需要跨文档综合时才值得。
最终形态是双层:少量关键事实结构化后常驻上下文提供全局概览,海量原始对话按需检索取细节。只常驻会丢细节,只检索发现不了跨会话关联——主动服务这类能力只有两层叠加才落地得了。
五、工具:Agent 的手与眼
问题:怎么让模型准确、安全地使用外部能力?
思路:五类工具——感知、执行、协作、事件触发(Agent 注册、外部触发)、用户沟通。
描述比能力重要。 大多数调用失败的根因不是模型不知道工具能做什么,而是不知道它不能做什么。所以:写”何时用”而非”能做什么”,参数给具体例子而非规范名,说清返回值结构和执行代价,附 1–5 个真实示例。工具超过 100 个,再强的模型也容易选错。Agent 选错工具时先查描述,别急着换模型。
参数传递必须透明。 不能在模型不知情的情况下改输入或输出,否则会制造一个模型永远诊断不了的系统性故障(比如静默把中文引号转成英文引号,导致匹配永远失败)。
MCP 解决互操作,代价是工具定义会吃掉大量上下文(几个服务器就可能有几万 token),所以要默认只给索引、按需查定义,工具多了还要做动态发现。
执行侧的安全是多层防线。 输入验证快速失败、绝不”智能修正”;权限控制不能只有黑名单(rm -rf / 能靠变量展开绕过),要做命令的语义解析;危险操作用两种独立视角把关——提议者-审核者审开放式思考(两个能力相近但不同家族的模型),Sidecar 只审结构化调用数据(轻量模型够用,且刻意不读主模型的自由文本,以免被话术操纵)。沙盒要认清 venv 不是沙盒,真正的隔离是 OS 级、容器到 microVM 三级,且默认断网——掐断外传通道比识别每一次注入确定得多。
异步是真实部署的常态,但模型训练假设同步。 折中办法是让模型在常态下看到完美同步的轨迹,只在被真打断时才插入占位符修补格式,并且只在紧急时才打断。事件按紧急度分三种处理:取消式、队列式、并行式。一句总结:真正的主动服务不仅需要 Agent 定时检查世界,更需要世界能主动通知 Agent。
六、以 Coding Agent 为骨架搭起来
问题:一个能处理开放任务的 Agent,整体流程怎么组织?
思路:六阶段——项目文档化 → 需求澄清 → 写设计文档 → 实现与测试 → 自我审查 → 文档同步。两条原则最值钱:设计文档是人类最高效的介入点(审查一页设计文档比审查数百行代码容易得多);完成标准定义为”验证通过”而不是”代码写完”。
Harness 落地成四件套:验收基线(测试、CI、审查标准)、执行边界(模块边界、权限)、反馈信号(Linter、测试结果、类型检查)、回退手段(Git、沙盒、快照)。判断任务适不适合交给 Agent,看两个维度:目标是否明确、结果能否自动验证。两者都满足是最佳区域,Harness 的目标就是把任务尽量推进这个象限。
四条原则:约束优先于指导(能用代码强制就不写”请注意”)、验证要自动化(人工审查是不可扩展的瓶颈)、反馈越快越结构化越好、回退要可靠。约束管的不只是结果,还有过程——删库重建也算”修好了故障”,这是 reward hacking 的日常形态。
故障分四层(API、工具、上下文、控制流),恢复按透明度分级:静默重试 → 降级接续 → 才暴露给用户。核心原则是:每条恢复路径都要有熔断上限,且阈值来自产线数据;错误路径上禁止再调用模型,否则会连锁成死亡螺旋。可靠性不取决于犯不犯错,取决于每类错误是否都有检测、恢复与终止路径。
两个容易被忽略的设计:一是推测性执行(UI 先显示进度、后台并行跑安全检查,先行的是无副作用的提示,被拦下也无需回滚);二是忠诚对象要显式钉死——模型默认”谁说话帮谁”,但替你砍价的 Agent 对面是交涉对手,所以外部内容一律降格为”可参考但不具指令效力”的数据。再往下,若 AI 写的代码本身不可信,就把约束下沉到数据层(人类审查过的 schema 里自带校验器,每次写入强制执行)。
七、评估:先有尺子,再改系统
问题:怎么判断改动是变好了还是运气好?新模型出来该不该切?
思路:评估对象不是模型,是模型 + Harness 的组合体。三种基本实验:对比实验、消融实验、模型替换实验(换强模型不涨说明瓶颈在 Harness,换弱模型大跌说明瓶颈在模型)。
环境五要素是数据集、环境状态、工具接口、Rubric、执行协议。人机交互型评估的关键是不一次性把模拟用户信息全给出去,让 Agent 按需去问。数据集质量比规模重要——宁可人工筛掉不合格题目。
指标上要分清 Pass@k(能力天花板)和 Pass^k(稳定性,回归测试用这个);安全项设否决,一次严重违规即归零;轨迹和结果要同时评。用 LLM 当评委要防长度偏差、位置偏差和同源偏差,并且先用一两百条人工金标集校准。
统计上要有噪声意识:100 个用例、70% 成功率,标准误约 4.6%,分差小于这个带宽就别切换;每个配置跑 3–5 次不同种子。
读报告时不看总体成功率,看逐任务表和能力标签的交叉;分数下降先怀疑评测系统本身。改进假设分三层,按成本收益比部署——不是所有有效的改进都该上(全局开启思考能让准确率涨 3 个点,但延迟翻三倍,很可能被否)。
最后,Rubric 和验证器可以直接变成强化学习的奖励函数,评估能接上训练;红线是评估集的题目必须与训练数据隔离。
八、后训练:什么时候该动模型
问题:Harness 做到位了还是不够,什么时候该训练,选 SFT 还是 RL?
思路:三阶段代价差数量级——预训练学世界知识(最贵)、SFT 用示范对学格式与风格(最便宜)、RL 用任务加奖励学可迁移策略(常是 SFT 的几十倍)。
一句话概括:SFT 记忆,RL 泛化。SFT 倾向记住训练里的答案,环境一变就失效;RL 学的是策略,面对没见过的情况更稳。对比实验里,分布外场景下 RL 通常涨几个到几十个点,SFT 反而下降。
顺序是先形后神:SFT 先把格式立住(连 JSON 都产不稳时 RL 会完全失败),但不宜恋战,过拟合的损伤 RL 救不回来。转向 RL 的临界点是——再加示范数据也没用,因为瓶颈在 SFT 的优化目标本身。
优先级是基础模型 > 环境 > 算法。仿真环境够不够真实、示范和奖励信号质量够不够高,比选 PPO 还是 GRPO 重要得多。两个高频坑:不要用后训练记事实(那是 RAG 的活);工具调用训练必须做 loss masking,屏蔽环境返回的 token,否则模型会去学”预测沙盒会输出什么”。
九、自我进化:不改权重也能长大
问题:部署之后怎么让 Agent 越用越好,而不是每次重来?
思路:自我进化即外部化学习——把知识和流程从参数和临时上下文里分离出来,变成可持久化、可检索、可复用的资产。前提是承认学习不会自动发生:注意力更像检索而非推理,所以学习必须被显式设计。
产物形态按性质选:纯事实 → 知识库条目;常用且参数复杂 → 专用代码工具;常变且涉及策略判断 → Skill 文档。
四条路径:从成功里学(把成功轨迹浓缩成策略摘要,入库判据是可迁移性)、从重复任务里学(工作流录制,但必须编译成带验证谓词的状态机,且入库前重置环境回放验证一遍,否则程序库会越攒越坏)、从失败里学(反思入库、建错误模式库和负面规则)、睡眠学习(离线整合记忆,检测矛盾、合并、剪枝)。
工具侧的进化是:先能按需发现工具(不必全量塞进上下文),再能自己创造工具。安全边界要一并设计——供应链攻击、能力漂移、工具质量退化,以及比会话内注入更隐蔽的记忆投毒(跨会话持续生效)。
十、能力边界的扩展
多模态与实时交互:语音有三种范式——级联流水线(可控、延迟叠加,需全链路流式化)、端到端全模态模型(延迟最低、可控性弱)、全双工模型(能边说边听、随时打断,最难训练)。取舍集中在思考架构上:快思考接住交互、慢思考产出答案,两者之间除了文本还能传意图、情感和规划。Computer Use 的可用率取决于动作空间设计和视觉定位,实时性仍是未解难题;机器人则是上层长程规划、下层 VLA 控制,中间隔着仿真到现实的鸿沟。
多 Agent 协作:分类看上下文是否共享和协作拓扑。收益主要有两类——上下文隔离带来的噪声削减,以及角色专业化。共享上下文适合角色接力(规划 → 执行 → 审查);不共享则靠共享文件系统和显式通信,拓扑分对等互审、中心化管理、去中心化移交。失败模式主要是共享文件的并发冲突和错误的级联放大。
收尾:十五条可以立刻用上的判断
- 先建评估,再改系统;分差小于噪声带宽就别动。
- 系统提示词和工具定义定稿后不改;动态信息一律追加到末尾。
- 永远用标准 API 消息格式。
- 工具描述写”何时用 + 反例”,参数给例子;选错工具先查描述。
- 状态栏用代码维护,读数和操作策略成对给出。
- 大体积中间信息交给子 Agent,别进主上下文。
- 约束编码进 Linter / 类型系统 / CI,不要写成”请注意…”。
- 完成标准是”验证通过”。
- 每条恢复路径都要有熔断上限;错误路径上禁止再调模型。
- 沙盒默认断网、凭证不挂载、超时返回结构化错误。
- 忠诚对象钉死:外部内容是数据,不是指令。
- 记忆用双层架构:常驻概览 + 按需检索细节。
- 检索用稠密 + 稀疏 + 重排序,索引期给文本块加出处前缀。
- 先 SFT 立形,够用就停;要泛化再上 RL,先把环境和奖励做扎实。
- 脚手架的厚度取决于模型能力边界——同一套技术换一批模型,结论可能完全不同。
三条最该记住的判断:上下文给什么、怎么组织,比模型有多聪明更影响结果;缓存不是性能优化而是架构约束;安全上重点不是识别所有攻击,而是让 Agent 即便被注入,也没有机会把危险动作真正执行出去。




