Harness Engineering 02|Repo Harness:让仓库对 Agent 可读
activity-dev-harness 第一次接入真实仓库时,Developer Agent 的表现让人意外:在 playground 里能写出 90% 正确的 Lua 代码,但进入真实项目后,35 个 case 只通过了 12 个。
逐个 case 排查后发现,失败的 23 个 case 里:
失败原因分布(23 个失败 case):
原因 数量 占比
──────────────────────── ──── ────
找错了参考文件 8 35% ← 仓库导航问题
改到了不该改的目录 5 22% ← 边界信号缺失
没找到测试入口,跳过验证 4 17% ← 验证路径不清
引用了废弃的旧版函数签名 3 13% ← 历史遗留噪声
代码逻辑确实写错了 3 13% ← 真正的模型能力问题
结论:87% 的失败不是"不会写",而是"在仓库里迷路了"。
这让我形成了一个判断:Coding Agent 的第一道瓶颈不是生成能力,而是仓库可读性。对人类可维护的仓库,不等于对 Agent 可读。
人读仓库 vs Agent 读仓库
人和 Agent 的仓库阅读方式有根本差异:
人类工程师 Agent
────────── ──────
靠经验猜目录职责 靠显式信号定位
"src/core 大概是核心逻辑" "CLAUDE.md 说入口在 src/core/main.lua"
模糊搜索 + 上下文理解 精确搜索 + 结果排序
"这个 export 函数看着像老的" 搜到 3 个 export 函数,不知道哪个是现行的
问同事确认 没有人可以问
"这个目录能不能动?""不能,那是生成物" 搜到 generated/,命名不含任何"禁止修改"信号
长期记忆补足上下文 每次任务从零开始
"上次改这块出过 bug,这里有坑" 无历史记忆,每次都可能踩同一个坑
不确定时会停下来 不确定时会猜一个然后继续
"我先不动这块,等确认了再说" "看起来应该改这个文件"→ 改了
核心差异:人类用背景知识弥补仓库的信号缺失,Agent 用猜测弥补------猜测就是不稳定的来源。
四类 Repo 工程问题
Agent 在仓库里碰到的问题可以归为四类,每一类对应一种 Harness 缺失:
┌──────────────────────────────────────────────────────────────────┐
│ Repo Harness 四层问题 │
├────────────┬─────────────────────────┬───────────────────────────┤
│ 问题层 │ 表现 │ Harness 缺失 │
├────────────┼─────────────────────────┼───────────────────────────┤
│ 导航 │ Agent 不知道先看哪里 │ 缺稳定入口 │
│ 定位 │ 改到了错误的位置 │ 缺模块边界信号 │
│ 约束 │ 动了不该动的区域 │ 缺显式"禁区"标记 │
│ 验证 │ 改完说"已修复"但没跑测试 │ 缺标准化验证路径 │
└────────────┴─────────────────────────┴───────────────────────────┘
错误示范 vs 正确示范:activity-dev-harness 仓库改造
❌ 改造前的仓库结构
activity-dev-harness/
├── src/
│ ├── agents/ # Agent 代码
│ ├── tools/ # 工具实现
│ ├── templates/ # Prompt 模板
│ └── utils/ # 公共函数
├── cases/ # 测试 case
├── scripts/ # 各种脚本(功能不明)
│ ├── run.py
│ ├── run_all.py
│ ├── test.py
│ ├── test_v2.py # 到底跑哪个?
│ └── old_runner.py # 还在用吗?
├── output/ # 生成物(但没标记)
├── docs/ # 过时文档
└── README.md # 只讲项目背景,不讲工程入口
Agent 的典型迷路路径:
1. 读 README → 没找到有用的工程信息
2. 搜索 "test" → 找到 test.py 和 test_v2.py,选了 test.py(旧版)
3. 搜索目标函数 → 在 utils/ 和 templates/ 都找到了,改了 utils/(错)
4. 跑 test.py → 报错,以为是自己改错了(其实是脚本过时)
5. 放弃验证,直接输出"已修复"
✅ 改造后的仓库结构
activity-dev-harness/
├── CLAUDE.md # ← Agent 入口文件(最关键的改动)
├── src/
│ ├── controller/ # 任务编排
│ ├── developer/ # 代码生成 Agent
│ ├── reviewer/ # 代码审查 Agent
│ ├── tools/ # 工具实现
│ │ ├── READ_ONLY/ # ← 显式标记:Reviewer 可用
│ │ └── READ_WRITE/ # ← 显式标记:Developer 可用
│ └── prompts/ # Prompt 模板
├── cases/
│ ├── gold/ # ← 基准 case,不允许修改
│ └── regression/ # 回归 case
├── tests/
│ └── run_eval.py # ← 唯一验证入口
├── _generated/ # ← 命名标记:生成物,禁止修改
└── _archive/ # ← 命名标记:废弃代码
改造核心不是"目录更整齐",而是每个结构变化都在向 Agent 发射信号。
CLAUDE.md:Agent 的仓库入口文件
改造中最有效的单一动作,是增加 CLAUDE.md。这个文件不是给人看的 README,是给 Agent 看的导航手册:
# CLAUDE.md 核心结构(activity-dev-harness 真实版本简化)
## 项目概述
多 Agent 协作系统:Controller 编排任务 → Developer 生成代码 →
Reviewer 审查代码 → 循环最多 3 轮
## 目录职责
src/controller/ 任务编排和循环控制
src/developer/ 代码生成 Agent,有读写权限
src/reviewer/ 代码审查 Agent,只有读权限
src/tools/ 工具实现,按权限分 READ_ONLY 和 READ_WRITE
cases/gold/ 基准测试 case,禁止修改
_generated/ 构建产物,禁止修改
_archive/ 废弃代码,禁止引用
## 常见任务
修改 Developer 行为 → 改 src/developer/prompts/ 下的模板
修改 Review 规则 → 改 src/reviewer/checks/ 下的检查脚本
添加新工具 → 在 src/tools/ 对应权限目录下添加
跑单个 case 验证 → python tests/run_eval.py --case <name>
跑全量回归 → python tests/run_eval.py --all
## 约束
- Developer 不允许调用 READ_ONLY 工具
- Reviewer 不允许调用 READ_WRITE 工具
- 单个 case 最多 3 轮循环
- 所有修改必须通过 run_eval.py 验证
改造前后的数据对比
指标 改造前 改造后 变化
──────────────────── ──────── ──────── ──────
35-case 通过率 34% 71% +37pp
Agent 找错文件的比例 35% 8% -27pp
跳过验证直接输出的比例 17% 2% -15pp
修改超出目标目录的比例 22% 5% -17pp
平均任务完成时间 48s 35s -27%
改动内容:
模型:没换(同一个 Sonnet 3.5)
Prompt:没改(同一份 system prompt)
改了什么:仓库结构 + CLAUDE.md + 目录命名规范 + 统一验证入口
通过率从 34% 到 71%,全部靠仓库改造,零模型改动。 这就是 Repo Harness 的价值------环境质量直接决定 Agent 表现的下限。
Agent 导航路径:有 Repo Harness vs 没有
没有 Repo Harness 时的 Agent 导航路径:
任务:"修复 case-017 的暴击伤害计算"
┌──────────┐
│ 读README │ → 没找到有用信息
└────┬─────┘
▼
┌──────────────┐
│ 搜索 "damage" │ → 找到 6 个文件
└────┬─────────┘
▼
┌──────────────────┐
│ 逐个读 6 个文件 │ → 消耗 12K tokens
└────┬─────────────┘
▼
┌────────────────────────┐
│ 猜测修改 utils/calc.lua │ → 改错了(应该改 combat/damage.lua)
└────┬───────────────────┘
▼
┌──────────────────┐
│ 搜索测试命令 │ → 找到 test.py 和 test_v2.py,选了旧版
└────┬─────────────┘
▼
┌──────────────┐
│ 测试失败,放弃 │ → 输出"已修复"
└──────────────┘
总消耗:18K tokens,48s,结果错误
有 Repo Harness 时的 Agent 导航路径:
任务:"修复 case-017 的暴击伤害计算"
┌────────────┐
│ 读CLAUDE.md │ → 知道目录职责、验证命令、约束规则
└────┬───────┘
▼
┌─────────────────────────┐
│ 根据 CLAUDE.md 定位目标 │ → combat/ 目录
└────┬────────────────────┘
▼
┌──────────────────────────┐
│ 修改 combat/damage.lua │ → 正确位置
└────┬─────────────────────┘
▼
┌────────────────────────────────────┐
│ 跑 run_eval.py --case case-017 │ → 标准验证路径
└────┬───────────────────────────────┘
▼
┌──────────┐
│ PASS ✓ │
└──────────┘
总消耗:6K tokens,22s,结果正确
token 消耗降低 67%,时间缩短 54%,正确率从 0 到 1。
五类改造优先级
优先级 改造动作 成本 收益
──────── ──────────────────────── ────── ──────
P0 添加 CLAUDE.md(Agent 入口) 半天 导航效率 +300%
P0 统一验证命令(一条命令跑所有检查) 2小时 跳过验证率 → 0
P1 目录命名加显式信号 2小时 找错文件率 -70%
(_generated/, _archive/,
READ_ONLY/, READ_WRITE/)
P1 标记禁止修改区域 1小时 越界修改率 -80%
P2 清理历史遗留脚本 半天 搜索噪声 -50%
P3 添加模块依赖说明 1天 复杂任务定位提升
投入产出比最高的单一动作:写 CLAUDE.md。半天工作量,解决 35% 的导航失败。
不同项目的 Repo Harness 需求差异
不是每个项目都需要同样的 Repo Harness。核心区别在于 Agent 和仓库的交互深度:
项目 Agent 与仓库交互 Repo Harness 重点
──────────── ────────────── ──────────────────────────────
activity-dev 深度交互 目录职责 + 可编辑范围 + 验证入口
harness (读、写、测试) (Agent 需要在仓库里导航和修改)
AIReview 只读 规则文件索引 + 版本标记
(读代码做审查) (Agent 需要找到正确的审查规则)
配置表风险 不直接交互 N/A
评估 (通过 API 获取数据) (配表数据通过结构化接口传入)
Crashsight 只读 crash 日志结构 + 历史记录索引
(读日志做分析) (Agent 需要导航大量历史数据)
Repo Harness 的投入应该和 Agent 的仓库交互深度成正比。 如果 Agent 只通过 API 获取结构化数据(像配置表风险评估),仓库可读性就不是瓶颈。
仓库可读性自查清单
维度 检查项 你的仓库
────── ──────────────────────────── ────────
导航 有没有 Agent 入口文件(CLAUDE.md)? □
核心模块的职责是否一句话能说清? □
常见任务是否有标准启动路径? □
定位 目录命名是否反映职责? □
历史遗留 vs 现行代码是否有区分标记? □
同一逻辑是否只在一个地方实现? □
约束 禁止修改的区域是否有显式标记? □
生成物目录是否和源码目录分开? □
不同角色的可操作范围是否定义清楚? □
验证 是否有统一的验证命令? □
验证命令是否能在无人值守下运行? □
验证结果是否有明确的 PASS/FAIL 判定? □
通过 8 项以上 → 仓库基本 Agent 可读
通过 5-7 项 → 需要补关键信号
通过 4 项以下 → Agent 在里面基本靠猜
Repo Harness 的核心判断:Agent 在仓库里的表现上限,不是由模型能力决定的,而是由仓库结构信号的质量决定的。仓库本身就是 Agent 执行环境的一部分------环境不改造,Agent 再强也在噪声里导航。