jiechenjiechen

The world is quiet here.

© jiechen

Rebuild in 2023   |   Start in 2021
Total View 0 Site Visitors 0

Harness Engineering:驾驭 Coding Agent 的工程实践

2026年5月7日tech

2025 年下半年开始,Coding Agent 的能力边界快速扩张

  • Claude Code、Codex、Cursor、Windsurf 等工具让长时运行、多文件修改、子代理派发和 MCP 调用成为常见能力。
  • 社区的讨论随之出现一种层级错位:有人在讨论 Agent 内部怎么构成,有人在讨论开发流程怎么设计,有人在比较哪个第三方套件更强——三组人各有道理,但很难对齐。

2026 年初,OpenAI 在一篇关于 Codex 的文章里首次使用 Harness Engineering 这个组合词,把 harness 从 Agent 构件的语境推进到使用者侧的工程实践。随后几周内,Anthropic 发表了长时运行 Agent 的 harness 设计指南,LangChain 做了 Agent Harness 的构件解剖;Linux.DO 上一个持续数月的长帖则把这些概念带进了真实项目的实操验证。

这篇文章综合了上述材料和社区实践,围绕五个问题展开:Harness Engineering 是什么,它怎样运行,它解决什么问题,怎样优化它的成本,以及如何落地。

概念与边界

harness 这个词被用得很泛,接近"模型之外的一切"。拆开看,它指向两层不同的问题。

LangChain 给出的公式最简洁:

Agent = Model + Harness

模型提供语言与推理,harness 提供状态、工具、执行路径、沙箱、上下文管理和反馈机制。

LangChain 的文章把这些构件分为六类:文件系统、bash 执行、沙箱与验证工具、记忆与搜索、上下文腐败对抗、长程自主执行所需的规划和自验证循环[1]

OpenAI 的文章把这个词推到使用者侧之后,Harness Engineering 成了一个独立的工程范式,关注 Coding Agent 怎样被组织进一个可以稳定产出可验收变更的开发流程。

维度 Agent Harnesses Harness Engineering
关注对象 Agent 的构件 使用 Agent 的工程系统
核心问题 它由什么组成 它如何被驾驭成开发流程
典型材料 system prompts、tools、MCP、memory、sandbox、subagents AGENTS.md、spec、runbook、tracker、门禁、审查
成熟标志 Agent 具备工具和约束 开发过程具备控制面、验证闭环和验收标准
Harness Engineering 分层模型 展示 Agent Harnesses 的构件层、Harness Engineering 的工程控制层,以及从工具层到交付层的成熟度推进。 Harness Engineering 分层模型 构件层回答 Agent 由什么组成;控制层回答这些能力如何进入可验收的开发流程。 构件层 Agent Harnesses 让模型变成能执行任务的 Agent 内置能力 tools / memory 外部增强 skills / hooks 包裹系统 team / workspace 给 Agent 状态、工具、权限、上下文和反馈机制 工程控制层 Harness Engineering 让 Agent 在项目规则里稳定交付 规则 AGENTS / docs 流程 spec / plan 门禁 test / review 给开发过程边界、状态、验证、审查和纠偏 组合进入 成熟度推进 从工具补丁到项目级交付系统,逐层补齐当前最大痛点。 工具层 prompt / skill 流程层 spec / plan 状态层 tracker / handoff 控制层 gates / worktree 交付层 feature / debt 采用顺序:先判断项目缺什么,再选择外部 harness 如何补位。
Harness Engineering 分层模型

开发者与模型交互的粒度至少经历了三次跳跃:

阶段 交互尺度 主要失败来源 核心工程动作
Prompt Engineering 单次交互 prompt 模糊、上下文缺失 改提示词
Context Engineering 会话级 上下文污染、记忆断裂 管理文件选择与压缩
Harness Engineering 项目级 控制面失真、任务漂移、验证不足 设计规则、门禁、反馈回路

这个边界直接影响诊断方向:Agent 产出不稳定时,先判断缺的是构件能力还是流程设计——缺构件补 MCP、skill、hook;缺流程补任务边界、质量门禁、runbook 和控制面纪律。

很多"为什么套件功能很多、结果仍然不稳"的困惑,根源在于把两类问题混在一起。

运行结构

把开发流程当作工程对象之后,核心结构是三层工作面:

  • 控制面:orchestration、tracker、prompts、交接文档、任务依赖与阻塞状态。
  • 执行面:每个任务从集成面切出的 worktree/branch,承载本次修改与定向验证。
  • 集成面:本地真实代码状态,所有任务完成后的合并目标。
Harness Engineering 控制回路 控制面、执行面、集成面和验证反馈构成 Coding Agent 开发闭环。 Harness Engineering 控制回路 控制面定义事实和规则,执行面完成切片,集成面承载可验证代码,验证反馈回到控制面。 控制面 执行面 集成与验证 读取真相 orchestration / tracker 选择任务切片 unlocked / blocked 更新控制面 handoff / next task 派发实现 worktree / subagent 修复问题 失败分支回流 合入集成面 latest code truth 验证与审查 test / build / review 通过验证:吸收事实 验证失败:返回修复 完成标准来自真实命令输出、diff、审查结果和人工决策点。
Harness Engineering 控制回路

分离的核心目的是把"应当如何推进"和"代码实际是什么"拆开。

Agent 可以读控制面决定下一步做什么,但判断完成必须回到集成面看真实 diff、真实测试输出、真实构建结果——社区把这条纪律称为 Truth-first。

它反制的是一类具体失败:Agent 把 tracker 标记当成完成状态继续推进,旧 diff 被带入后续切片,错误在几轮交接后才暴露。

引导与检测

三层工作面定义了结构骨架,填充它的机制是引导和检测。Böckeler 在 Martin Fowler 站上用控制论框架对 harness 做了正交分解[2]

第一个维度是方向:

  • guides / 引导在 Agent 行动前指明正确方向:AGENTS.mdarchitecture.md、skill 指令、LSP 集成、runbook。
  • sensors / 反馈在 Agent 行动后检测和修正偏差:测试、lint、typecheck、code review、构建结果。

第二个维度是执行方式:

  • computational / 计算型是确定性的 CPU 执行,成本低、结果可靠:lint、typecheck、ArchUnit、覆盖率检查。
  • inferential / 推理型是 LLM/GPU 执行,成本高、非确定性,但能处理语义判断:AGENTS.md 指令、code review skill、AI judge。
引导(行动前) 反馈(行动后检测)
计算型 LSP、bootstrap 脚本、OpenRewrite lint、typecheck、ArchUnit、覆盖率
推理型 AGENTS.md、architecture skill、API 文档 code review skill、AI judge、日志异常检测

引导和反馈相互配合:

  • 只有反馈的系统让 Agent “反复犯同样的错误”——测试告诉它错了,但它不知道正确方向。
  • 只有引导的系统"编码了规则却永远不知道规则是否生效"——AGENTS.md 写得再好,没有测试就无法闭环。
  • harness 的设计工作就是沿着四个象限逐一补齐,并通过转向循环(steering loop)持续迭代。

文档作为模型间的 API

多模型协作时,不同模型的上下文容量、推理强度和响应形态各不相同。直接互读原始执行日志会造成上下文膨胀和判断污染。

解决方式是把文档当作模型间的 API:

文档类型 生产者 消费者 接口职责
历史大纲摘要 压缩模型 / 整理 Agent 高阶决策模型 去噪、保留状态
AGENTS.md 人类 / 高阶模型 执行 Agent 固化规则与边界
版本开发报告 执行 Agent 人类 + 其他模型 固化踩坑和未完成项
进度文件 每轮 Agent 下一轮 Agent 跨上下文窗口的连续记忆

Anthropic 的指南把这个模式具象化:claude-progress.txt 跨会话维护,配合 feature_list.json 和 git log 构成启动信息。

每轮 Agent 的固定启动序列:pwd → 读进度文件 → 读功能清单 → git log --oneline -20 → 运行 init.sh → 跑冒烟测试确认基线 → 开始工作。

LangChain 把 AGENTS.md 定义为一种持续学习机制——短期记忆固化为长期记忆的通道。

这是 harness 与传统 README 的实质分歧:harness 文档面向机器消费,字段稳定度和术语一致性比文笔重要。

tracker.md 里一个字段从 blocked 改成 waiting 可能让下游 Agent 判断逻辑失效——这是 API 层面的破坏性变更。

人类作为隐式 harness

Böckeler 指出:人类本身就是一种隐式 harness。人类开发者自带被吸收的编码规范、对复杂度的审美厌恶(“一个 300 行的函数看着就不对”)、社会问责(名字挂在 commit 上)、组织记忆,以及对"承重约定"与"习惯约定"的直觉区分。

Agent 缺少全部这些能力。harness 外显化了其中一部分。

解决什么问题

Anthropic 的长时运行指南列出了几种具名的失败模式:

  • one-shotting:试图一次性完成所有工作,跑到一半上下文耗尽
  • premature victory declaration:Agent 看到部分进展就宣布完成
  • dirty handoffs:切片结束时留下未文档化的 bug 和半成品状态

这些失败模式都源自 harness 缺失。Anthropic 直接说明,即便是 Opus 4.5 在 Claude Agent SDK 的循环中跨多个上下文窗口运行,缺少 harness 模式的约束就"无法构建出生产级的 Web 应用"[3]

验证质量的天花板

Agent 自生成测试只覆盖模型自身理解到的路径,遗漏真实业务和历史 bug 走过的路径。局部实现里问题不大,重构场景里是系统性漏洞——重构要保持的恰恰是 Agent 没有理解到的行为。

Anthropic 的观察:Agent 会写单元测试、用 curl 打 dev server 端点,但仍然"无法识别端到端功能不工作"。引入浏览器自动化(Puppeteer MCP)做端到端验证后,“Agent 能够识别和修复仅从代码看不出来的 bug”。

Böckeler 的框架把这个问题定位到更大的缺口:行为验证(functional correctness)是当前最难解决的维度。代码风格有 lint,架构约束有 ArchUnit,可维护性有覆盖率——但"功能是否正确"主要依赖 AI 自生成测试和人工验收。

一种有前景但适用范围有限的模式是 approved fixtures——人类审批预期输出后将其固化为回归锚点。

门禁的测试集需要人工参与

  • 关键路径的回归集必须来自既有系统、线上样本或人工定义的验收用例
  • AI 自生成测试补边界,人工定义测试守核心行为。

成本与调优

长时运行 Agent 的典型故障是"跑得动但很贵"。Linux.DO 社区的 OMO 实践数据可以作为机制信号:

  • 某次约 24 小时的运行里,集成面输出约 38 个文件、670 行代码改动;同期控制面产出 17 个文件、约 4933 行记录。控制面产出在行数上是集成面的七倍多[4]
  • 一次 32 小时长跑里,48 个文件产生约 3333 行代码,token 消耗超过 10 亿。追溯发现交接提示词里混入了"最小可执行单元"倾向,每个 worktree 只改 1–3 个文件、几行到几十行 diff。
  • 统一术语、瘦身控制面、调整切片策略之后,9 小时完成 65 个文件、约 1539 行改动,token 约 2.2 亿。时间效率和 token 产出比都改善了一个量级。

贪婪切片

这组数据指向一个反直觉的结论:任务粒度越细,单位产出的固定成本越高。每个切片都要跑 planning、边界确认、handoff、实现、focused test、审查、merge、tracker 更新——这是一组几乎不随切片大小变化的固定开销。

直觉上"小批次、快反馈"在人类协作中成立,因为人类 review 成本近似线性于 diff 大小。Agent 的 review 成本是亚线性的——读 200 行和读 20 行在 token 消耗上量级接近。

最优切片粒度因此从"尽量小"变成"小到能通过验证,同时大到值得跑完整门禁"。社区把这个策略称为贪婪切片

Context rot 对策

与控制面熵增并行的另一个机制是 context rot——LangChain 的术语,指随着上下文窗口填满,模型的推理能力退化。三种对策:

  • compaction:上下文临近容量时智能摘要和卸载
  • tool call offloading:大块工具输出只保留首尾,全文写入文件系统按需读取
  • progressive disclosure:用 skills 机制按需展开能力,启动时不加载全部工具定义[5]

共同思路是把上下文当作稀缺资源管理。

Harnessability

Böckeler 提出的 harnessability 概念:代码库被 harness 的难度差异很大。提升有效性的结构性属性:

  • 强类型语言——类型检查本身就是内置 sensor
  • 清晰的模块边界——支持架构约束规则
  • 抽象框架如 Spring——隐式提高首次正确率

她把这些称为"环境可供性"(ambient affordances),结构性属性让环境本身对 Agent 可读、可导航、可操作。

遗留系统面临一个悖论:最需要 harness 的地方,恰恰是 harness 最难建的地方。

落地路径

Harness Engineering 采用决策流程 从痛点识别、基础条件判断、控制层选择,到执行闭环和度量反馈的流程图。 Harness Engineering 采用决策流程 先确认基础条件,再选择最小控制层,最后用真实验证和反馈数据修正流程。 阅读顺序 痛点识别 基础条件 控制层选择 执行闭环 度量反馈 流程瘦身 识别当前最大痛点 上下文、质量、长任务、token 成本 基础条件清楚? 需求、runbook 测试数据、完成标准 不清楚 先补基础材料 收敛需求,补 runbook 准备真实验收用例 清楚 选择最小控制层 工具层、流程层、状态层、控制层 从当前痛点补一层 进入执行闭环 读事实,改代码,跑验证 修复失败,合入,更新状态 反馈修正 度量是否改善 交付速度、验证通过率、返工率 token 投入产出比 证据不足 执行时守住三条线 1. Truth-first:代码事实以集成面为准 2. 控制面瘦身:只保留当前事实 3. 贪婪切片:同模块同验证路径合并
Harness Engineering 采用决策流程

采用 harness engineering 的判断简化为三步:先看基础条件是否就绪(需求、runbook、测试数据、完成标准),再选择最小控制层补当前最大痛点,最后用真实交付数据修正系统。

个人或小团队起步不需要重型多 Agent 平台。一个可行的最小目录:

1
2
3
4
5
AGENTS.md                   # 项目规则、禁止事项、默认验证命令、完成标准
docs/architecture.md # 模块边界、数据流、外部依赖、高风险区域
docs/runbooks/dev-test.md # 安装、启动、测试、联调、日志收集
docs/plans/current.md # 当前任务目标、非目标、方案、验收标准
docs/tracker.md # 任务状态、依赖、阻塞、完成证据

每轮执行结束只要求一份最小完成证明:改了什么、为什么这样改、跑了什么验证、还剩什么风险、下一步是否需要人类决策。

外部套件的选型应当倒着来——先定位自身痛点,再判断套件补的是哪一层:

痛点 对应的能力层 可参考的套件方向
需求澄清不足 流程层前段 Superpowers 的 brainstorming 和 TDD
长任务无人值守 状态层 + 控制层 OMO 的 orchestration
命令多、难记 流程层 GSD 的命令收敛
需要沉淀团队规则 静态设施 Trellis 的规范积累
控制面成本过高 控制层 CodeStable 的极简理念
跨产品、角色协作 交付层 BMAD、gstack 的产品闭环

什么时候应当按兵不动

三种情况下应先补基础:

  • 需求本身仍然混乱,验收标准没定
  • 关键路径没有可用的回归测试或真实数据
  • 项目规则已经过期,AGENTS.md 和代码事实不一致

在这种状态下加 workflow 会放大噪音,加 agent teams 会放大分歧,加自动化会放大错误传播。更稳的顺序是先把需求、runbook、测试数据和完成标准补齐。

衡量 harness 是否有效只需两个指标:返工率和验证通过率。两个指标持平或倒退,任何套件、角色、编排都只是控制面的装饰。

注释

  1. LangChain 在 Terminal Bench 2.0 上的发现佐证了这一点:同一个 Opus 4.6 模型在不同 harness 中得分差异巨大。LangChain 的 coding agent 仅通过改进 harness(不换模型)就从排行榜第 30 名升至前 5 名。harness 的设计质量对产出的影响不亚于模型本身。
  2. 这个框架的理论根基是控制论。Böckeler 引用了 Ashby 的必要多样性定律(Law of Requisite Variety):调节器需要拥有至少与被调节系统一样多的多样性。Coding Agent 几乎可以生成任何代码——约束拓扑结构(技术栈、模块边界、命名规范)是一种品种削减动作,让 harness 的覆盖变得可行。
  3. Anthropic 为此设计了一套双 Agent 架构:Initializer Agent 在首次会话中建立项目脚手架、生成结构化功能清单(JSON 格式,因为模型"更不容易不恰当地修改 JSON 文件"),Coding Agent 在后续每次会话中读取已有状态、增量完成单个功能、测试并留下干净状态。两个 Agent 共享同一个 system prompt 和工具集——区别只是 user prompt 不同。
  4. 这里的比例来自具体项目和套件,在多轮复盘里一致出现。
  5. 其中 compaction 已被 Claude Agent SDK 内置,但 Anthropic 指出 compaction “并不总是能把足够清晰的指令传递给下一个 Agent”,因此仍需要外部持久化机制(进度文件、git log、结构化功能清单)作为补充。