--- title: "Harness 工程 14 步路线图:从单 Agent 到自改进系统" source_url: https://mp.weixin.qq.com/s/p1OeUgazStV_LL56zUfRfA ingested: 2026-06-18 type: raw source: wechat sha256: a0bb7e112ef4c507e9ae0ce0647baad52cc49898c99dd5ba65dd695ac4ba0a73 --- 所有人都在谈论循环,但几乎没人关注循环底下那一层。绝大多数开发者在默认 harness 上运行 Claude Code,没有规则、没有子 Agent、没有钩子、没有记忆。 然后困惑于为什么循环产出质量很差。道理很简单:循环的上限取决于底下的 harness。这是一份 harness 的 14 步路线图,从单个 Agent 到一个能自我改进的系统。 Loop engineering(构建一个按计划自动 prompt Agent 的系统)这个月成了焦点。但写了 loop engineering 长文的 Addy Osmani 明确指出了循环下面那一层: "Loop engineering 位于 harness 的上一层。harness 是单个 Agent 运行的环境。循环就是 harness 加上定时器、辅助进程和自我反馈。" Harness 工程就是设计这个环境:模型、工具、权限、上下文、记忆。 这是不起眼的一层,却决定了上面所有东西能不能用。一个好循环配上差的 harness,只会更快地产出低质量结果。 14 步,3 个层级。一切的地基。 第一部分:什么是 harness 01. harness 是单个 Agent 运行的环境 去掉术语,harness 就是四样东西:做推理的模型、它能调用的工具、这些工具的权限、以及每次运行开始时它读取的上下文。 这就是 harness 的全部组成。其他部分(子 Agent、钩子、记忆)都是在塑造这四者之一。 harness 之所以比人们以为的更重要:Agent 本质上是一个 while True 循环,选一个工具、执行、看结果、决定下一步。 harness 定义了有哪些工具可用、Agent 被允许做什么、以及它启动时知道什么。同一个模型,不同的 harness,完全不同的 Agent。 02. 整个 harness 就在一个文件夹里:.claude/ 塑造 Agent 的一切都在项目根目录的一个文件夹里。了解这个布局,你就能一眼看懂任何人的 harness: .claude/ ├─ CLAUDE.md # 常驻事实,每次会话都读 ├─ settings.json # 权限、模型、钩子 ├─ .mcp.json # 外部工具连接 ├─ rules/ # 按路径生效的行为规则 │ ├─ tests.md │ └─ python-types.md ├─ agents/ # 子 Agent 定义(每个约 30 行) │ ├─ reviewer.md │ └─ eval-runner.md ├─ skills/ # 可复用的工作流 │ └─ pr-checklist/ │ └─ SKILL.md └─ agent-memory/ # 跨运行存活的内容 └─ STATE.md 区分干净 harness 和混乱 harness 的原则:保持它小到你能解释每个文件为什么存在。如果你说不出某条规则、钩子或子 Agent 的用途,就删掉它。 03. harness vs 循环 vs 系统,三层楼,不要混淆 大多数"我的 Agent 配置一团糟"的问题,都来自混淆了这三层。理清它们: Harness 是单个 Agent 运行的环境。静态配置:模型、工具、权限、上下文。 循环 按定时器 prompt Agent、派生辅助 Agent、将结果反馈给自身。它运行在 harness 之上。 自改进系统 是循环加上能复利积累的记忆,每次运行都让下次运行更精准。 实操版本:常驻事实放上下文,强制规则放钩子,流程放技能,隔离放子 Agent。 把这些搞混(强制规则写在 CLAUDE.md 里、流程挤在上下文里)是 Agent 表现不稳定、成本高的根本原因。 04. 默认 harness:开箱即用你得到什么 安装 Claude Code,打开一个文件夹,你就已经有了一个 harness,只不过是空的。默认配置给你一个能力强的模型、内置工具(读、写、bash、搜索),以及对所有风险操作的审批提示。没有项目上下文,没有自定义子 Agent,没有记忆。 对于一次性任务,默认配置没问题。但对于你重复做的事情,默认配置意味着 Agent 每次会话都要从头推导你的项目、对安全操作反复请求权限、关掉终端就忘掉一切。 接下来十步就是为了解决这个问题。 第二部分:配置 harness 05. CLAUDE.md:常驻事实,保持精简 CLAUDE.md 在每次会话开始时被读取。它是 Agent 对你项目的常驻认知:规范、架构、"我们不这样做因为之前出过事"。 最常见的错误:让它膨胀成一份巨大的流程文档,撑大每次会话的上下文。 日常使用者的经验法则:主记忆文件保持在 500 token 以内。常驻事实放这里。 多步骤流程放技能(第 8 步)。特定路径的行为放 rules/ 文件,作用域限定在它适用的地方。如果 CLAUDE.md 中的某个部分已经变成了流程而非事实,它就该挪到别处。 把你的 CLAUDE.md 念出来。每一行都应该是 Agent 在每次会话中都需要的事实("我们用 pnpm,不用 npm")。如果某行是流程("要添加功能,先……"),把它移到技能里。如果是某个文件夹专属的规则,移到 rules/ 里。 06. settings.json:权限和模型,设置一次 默认 harness 在每个风险操作前都会询问。你在看着的时候这是对的,不看着的时候就不对了。settings.json 是你预批准安全操作、拒绝危险操作、选择运行模型的地方。 { "model": "claude-sonnet-4-6", "permissions": { "autoApprove": [ "Read(*)", "Grep(*)", "Bash(npm test)", "Bash(git status)" ], "deny": [ "Bash(rm -rf*)", "Bash(git push*)", "Edit(.env*)", "Edit(secrets/*)" ] } } 判断什么该自动批准的标准:如果出了问题,撤回有多难?容易撤回→自动批准。难以撤回(force-push、删文件、碰密钥)→始终拒绝或提示。中间地带如果有日志记录,也可以自动批准。 07. 子 Agent:为繁重任务提供隔离上下文 子 Agent 是从主会话启动的独立 Claude 会话,有自己的上下文窗口和工具列表。重点不是为了并行而并行,而是把噪音隔离在主上下文之外。 一个读 40 个文件的调研任务、一个需要全新视角的审查、一次产生大量日志的评估运行,这些应该放在子 Agent 中,避免污染主线程。 任何 harness 中最有价值的子 Agent,是那个检查主 Agent 工作的。模型审查自己的输出时容易对自己太宽容;一个拥有全新上下文窗口的独立审查者,能发现写作者自己看不到的问题。这就是让 harness 之上每一层循环都值得信赖的"写作者 vs 检查者"分离。 08. 技能:Agent 复用的流程 技能是一个 SKILL.md 文件,Agent 运行它,可以通过 /skill-name 手动调用,也可以在任务匹配其描述时自动触发。 与子 Agent 不同,技能在同一个上下文窗口中运行。它只是可复用的指令,成为会话的一部分。 创建技能的信号:你发现自己在每次新对话中粘贴同样的指令。那就是一个等待被创建的技能。PR 检查清单、评估流程、发布流程,写一次,永远可调用。 而且因为技能是可复用单元,它们是 harness 随时间改进的关键:每次流程以新方式失败,你把经验加入技能,下次运行就继承了它。 09. 钩子:模型无法绕过的确定性规则 前面的一切都依赖模型理解你的指令。钩子不同。 钩子是在 Agent 生命周期固定节点触发的 shell 命令(工具运行前、文件修改后、会话结束时),它的退出码可以阻止操作。钩子是强制执行,CLAUDE.md 是建议。 两个钩子几乎在任何 harness 中都值得保留: PreToolUse 门控:确定性地阻止危险命令,如 rm -rf、读 .env、推到 main。退出码 2 在调用发生前就拦截它。模型无法绕过。 PostToolUse 格式化:每次编辑后运行 linter 或格式化工具。Agent 永远不会提交未格式化的代码,因为 harness 自动格式化了。 "hooks": { "PreToolUse": [{ "matcher": "Bash", "command": "./.claude/hooks/block-dangerous.sh" }], "PostToolUse": [{ "matcher": "Edit|Write", "command": "prettier --write \"$CLAUDE_FILE_PATH\"" }] } 对必须发生或绝不能发生的事情用钩子:安全、格式化、审计日志。不要用它来做判断性的决策,那是模型的职责。好的 harness 有一两个精准的钩子,而不是二十个。 第三部分:让它复利增长 10. 加上循环,harness 现在按定时器运行 配置好的 harness 仍然等着你输入。循环让它自己运行。最简单的版本是 Claude Code 中的 /loop,按节奏执行的循环 prompt。 配合 /goal,循环会一直运行直到目标条件为真,由独立评分器(而非 Agent 自己)来判断。 > /loop 30m /goal All tests pass and lint is clean. Triage new failures, draft fixes in claude/ branches. ▲ Claude 使用你构建的 harness: - rules/ 定义规范 - reviewer 子 Agent 检查每个修复 - PreToolUse 钩子阻止推送到 main ✓ 循环中。独立评分器决定"完成"。 注意这里发生了什么:循环没有增加智能,它复用了 harness 中的一切(规则、审查子 Agent、安全钩子)。好的 harness 让循环变得简单。这就是先建地基的全部意义。 11. 加上动态工作流,harness 自己编写编排逻辑 对于单循环处理不了的任务(大规模并行、高度结构化、对抗性验证),Claude 可以即时编写自己的 JavaScript 编排逻辑。 这就是动态工作流:agent() 生成子进程、parallel() 扇出、pipeline() 流式处理。它将你 harness 中定义的子 Agent 组合成扇出-合成或对抗性验证等模式。 与 harness 工程的关系:动态工作流的质量取决于它能调用的子 Agent 和技能。 如果你的 harness 有一个精准的审查子 Agent 和一个写得好的评估技能,工作流就有好的组件可以编排。如果 harness 是空的,工作流就无米下锅。 工作流是指挥,你的 harness 是乐团。 12. 加上记忆,Agent 忘掉的,harness 替它记住 这一步把配置好的 harness 变成一个真正能改进的系统。Agent 在运行之间会忘掉一切,但 harness 不必如此。 一个状态文件(agent-memory/ 中的 markdown 文件,或者一个 Linear 看板)记录做过什么尝试、什么有效、什么失败、哪些规则经受住了考验。 让记忆产生复利的模式,来自实践中表现最好的 Agent: 走之前先写。 每次运行结束时更新状态文件:学到的教训、验证过的事实、下一步做什么。 启动时先读。 每次运行开始时读取状态文件和相关技能,这样是在续写而不是重启。 提炼为技能。 当一条教训具有普遍性("Windows runner 需要用 bash,不能用 PowerShell"),它就从状态文件毕业进入技能,适用于未来每个项目。 # 项目记忆 ## 已验证事实 - prc 单位是美元,不是美分(通过 SELECT MIN/MAX 验证) - auth 中间件顺序:rate_limit -> jwt -> rbac ## 经验教训 - Windows CI runner 的 PowerShell 会 TLS 1.2 失败,用 bash - 超过 100 万行的表做迁移必须按 1 万条分批 ## 上次会话 2026-06-11 · 3 个修复已合并,2 个已升级。下一步:验证限流修复。 13. 闭合循环:输出 → 教训 → 技能 → 更好的输出 三层在这里合为一个能自我改进的整体。每次运行产出结果,审查子 Agent(第 7 步)检查它。 结果(通过了什么、失败了什么、学到了什么)写入记忆(第 12 步)。通用的教训被提炼为技能(第 8 步)。 下次运行继承更精准的技能和更丰富的记忆。 这就是整个自改进循环,注意它完全由 harness 的部件构成: 子 Agent 评判工作:客观检查,全新上下文。 记忆记录结论:跨运行存活。 技能承载改进:带着上次运行学到的一切。 循环再次执行:现在拥有上次运行积累的所有经验。 模型从未改变。围绕它的 harness 变得更精准了。这就是"自改进"的真实含义:不是模型在学习,而是 harness 在积累。 14. 交付 harness:打包、分享、复用 一个在单项目上有效的 harness 是一项资产。 把技能、子 Agent 和规则打包为插件,你的整个团队一步安装同样的配置:相同的规范、相同的安全钩子、相同的审查者。 harness 不再是你的个人配置,而是变成了共享基础设施。 构建顺序,最后再强调一次:先在干净 harness 上让一次手动运行可靠。加上下文和权限。加审查子 Agent。加记忆。然后,只有在那之后,再套上循环。好 harness 上的循环会复利增长。差 harness 上的循环只会更快地消耗资源。 常见 harness 错误 用默认配置运行。 没有上下文、没有规则、没有记忆,Agent 每次会话都从头推导你的项目。 CLAUDE.md 臃肿。 流程塞进常驻上下文,撑大每次运行。把它们移到技能里。 把强制规则写在 CLAUDE.md 而不是钩子里。 模型可以忽略建议,但无法忽略退出码为 2 的钩子。 一个 Agent 既写又评。 加一个拥有全新上下文窗口的审查子 Agent。 没有记忆。 每次运行从零开始。状态文件是让明天能续写的关键。 给差 harness 套循环。 循环只会更快地产出低质量结果。先打好地基。 二十个钩子。 一两个精准的钩子胜过一堆没人理解的。 不扫描就发布 harness。 泄露的密钥和过宽的权限会扩散给所有安装者。 结论 循环得到了光环,harness 完成了工作。 Loop engineering 是令人兴奋的部分:Agent 自己 prompt 自己,你睡觉时它在运行。但循环不过是 harness 加上定时器。 决定输出质量好坏的一切,都在下面一层:你选的模型、你开放的工具、你写的上下文、你添加的审查者、你保留的记忆。 把这一层建好,上面的一切就会复利增长:循环复用你的子 Agent,工作流编排你的技能,记忆让每次运行都比上次更精准。 自改进从来不是模型的属性。它是你围绕模型构建的 harness 的属性。 挑一件你还没做的事(大概率是审查子 Agent、安全钩子或状态文件),今天就加上。让 harness 小到你能解释清楚。然后在上面套一个循环,看地基如何替你完成工作。