# Agentic Harness Engineering:以可观测性驱动的编码 Agent Harness 自动演化

Paper PDF Blog License: MIT Python Managed with uv

Agentic Harness Engineering

English | 简体中文

> 本文档为英文 [README.md](README.md) 的中文翻译,可能略有滞后;如有冲突以英文版为准。 --- ## 📰 动态 - **[2026-05-14]** 🏆 AHE(基于 GPT-5.5)以 **84.7%** 登上 [Terminal-Bench 2.0 榜单](https://www.tbench.ai/leaderboard/terminal-bench/2.0),位列**第 3 名**(榜单排名截至 2026-05-15) - **[2026-04-30]** ✍️ Dawning Road 上的博客(英文 & 中文)—— 关于 AHE 探索过程的更详细记述:[Agentic Harness Engineering](https://dawning-road.github.io/blog/agentic-harness-engineering) - **[2026-04-28]** 📄 论文已在 arXiv 发布:[Agentic Harness Engineering: Observability-Driven Automatic Evolution of Coding-Agent Harnesses](https://arxiv.org/abs/2604.25850) - **[2026-04]** 🎉 框架开源 --- ## 🎯 概览 **AHE (Agentic Harness Engineering)** 是一个开放的**可观测性系统**,用于自动演化围绕在编码 agent 周围的 harness。基础模型保持不变,演化的是 harness 的各个组件——系统提示词、工具描述、工具实现、中间件、skill、子 agent、以及长期记忆。 AHE 建立在三层可观测性之上: - **组件可观测性 (Component observability)** —— [**NexAU**](https://github.com/nex-agi/NexAU.git) 把 harness 拆分为七个正交的文件级组件,每一项都纳入 git 追踪,因此每次修改都可审计、可回退。 - **经验可观测性 (Experience observability)** —— *Agent Debugger* 把 ~10M-token 的原始 trace 蒸馏成分层、可溯源的报告;优化器默认读 digest,但任何论断都可以下钻回某次 rollout 的原始 trace。 - **决策可观测性 (Decision observability)** —— *Evolve Agent* 提出有证据支撑的修改、预测其影响,并由下一轮迭代中翻转的任务自动证伪。 经过十轮 `评估 → 分析 → 改进` 迭代,**AHE** 在 GPT-5.4 上把 Terminal-Bench 2 的 pass@1 从 **69.7% 提升到 77.0%**,超过手写的 Codex (71.9%) 以及自演化的 ACE 与 TF-GRPO 基线;同时产出了一个无需重新演化即可迁移到 SWE-bench-verified 以及四个其他基础模型上的"冻结 harness",表明被演化出的组件编码的是通用工程经验,而非针对单一 benchmark 的调优。

Cross-Model Transfer Case Study Training Curve

--- ## 🚀 快速开始 ### 0. 前置依赖 - Python ≥ 3.13 - [uv](https://docs.astral.sh/uv/) - tmux ```bash # macOS brew install uv tmux # Linux curl -LsSf https://astral.sh/uv/install.sh | sh sudo apt install -y tmux ``` ### 1. 克隆 + 安装依赖 ```bash git clone https://github.com/Curry09/agentic-harness-engineering.git cd agentic-harness-engineering uv sync ``` > `uv sync` 会安装 `pyproject.toml` 中声明的所有依赖。 ### 2. 配置环境变量 ```bash cp .env.example .env ``` 编辑 `.env`,至少需要设置: | 变量 | 用途 | |---|---| | `LLM_API_KEY` / `LLM_BASE_URL` | 主 LLM 端点(`code_agent` 与 `evolve_agent` 都消费它) | | `E2B_API_KEY` | [E2B](https://e2b.dev/) 沙箱——SaaS 与自部署的差异详见下一小节 | | `SERPER_API_KEY` | `evolve_agent` 使用的 web 搜索 | `ADB_LLM_*` 与 `GPT54_LLM_*` 是可选项——不设置时回退到 `LLM_*`,或可用它们让 ADB / gpt-5.4 实验指向更强的模型。`LANGFUSE_*`、`BP_HTML_PARSER_*` 与 `FEISHU_WEBHOOK` 全部是可选的可观测性 / 便利性钩子;完整列表见 `.env.example`。 #### E2B 沙箱:SaaS 与自部署 AHE 每一次 rollout 都跑在 E2B 沙箱里,支持两种部署模式: - **SaaS E2B(默认)。** **只**设置 `E2B_API_KEY`,不要设置 `E2B_API_URL` / `E2B_DOMAIN`(注释掉即可)。SDK 会自动连到 `e2b.dev`。 > ⚠️ **并发上限。** SaaS E2B 对每个账号有按 tier 划分的**并发沙箱上限**。如果 harbor 试图启动超出该上限的沙箱,多余的会启动失败,整轮迭代会卡住。在调高 harbor / 实验配置中的并行度之前,请先确认你的 tier 配额并保持安全余量。 - **自部署 E2B 集群。** 设置 `E2B_API_KEY` **并**让 SDK 指向你的集群: ```dotenv E2B_API_KEY="your_e2b_key" E2B_API_URL="https://your-e2b-host.example.com" E2B_DOMAIN="your-e2b-host.example.com" ``` 没有共享并发上限,但仍受集群硬件容量约束。 ### 3. 构建 E2B 模板(每个数据集一次性) 这里使用的数据集来自 [`laude-institute/harbor-datasets`](https://github.com/laude-institute/harbor-datasets) 的子集——克隆你需要的部分,然后让 `--dataset-dir` 指向它的目录。 每次 rollout 都从一个预构建的 E2B 模板里启动沙箱,模板里已经装好了 `uv` 以及位于 `/opt/nexau-venv` 的 NexAU/harbor venv。在启动前一次性构建好这些模板: ```bash # 构建数据集声明的所有模板,并发 16 uv run python scripts/build_templates.py --dataset-dir /path/to/dataset -j 16 # 失败后续跑:仅重试当前 E2B 构建状态为 ERROR 的任务 uv run python scripts/build_templates.py --dataset-dir /path/to/dataset --retry-failed # 只构建某些任务 uv run python scripts/build_templates.py --dataset-dir /path/to/dataset task_a task_b ``` 数据集目录下每个任务必须是一个子目录,里面有声明 `[environment].docker_image` 的 `task.toml`(或 `environment/Dockerfile` 作为 fallback)。每个任务的模板别名是 ``,把 `.` 替换为 `-`。 每个模板默认烤进去的包列表来自 `scripts/build_templates.py:DEFAULT_NEXAU_PACKAGES`(一个公开的 NexAU + 沙箱内部使用的 `NexAU-harbor` 变体,故意区别于 `pyproject.toml` 中宿主侧的 `harbor-LJH`)。如果需要在沙箱里换一个版本,可用一个或多个 `--nexau-package ` 参数覆盖。 如果任务镜像来自私有 Docker registry,调用前还需要 export `DOCKER_REGISTRY_USERNAME` 和 `DOCKER_REGISTRY_PASSWORD`。 ### 4. 启动 ```bash # 通过 tmux 在后台运行单个实验 ./scripts/evolve.sh configs/experiments/exp-003-simple-code-gpt54.yaml # 启动并自动 attach 到日志流 ./scripts/evolve.sh --attach configs/experiments/exp-003-simple-code-gpt54.yaml # 批量:启动 configs/experiments/ 下的所有实验 ./scripts/evolve.sh --batch ``` 启动后常用的 tmux 操作: ```bash tmux ls # 列出会话 tmux attach -t # 接入某个会话 # Ctrl-b d # 分离(会话仍在后台运行) tmux kill-session -t # 终止 ``` --- ## 🔧 工作原理 基础模型保持不变,演化的是**它周围的 harness**。每一轮外层循环都是 `评估 → 分析 → 改进`,构建在概览中介绍的三层可观测性之上。 ### 1. 评估 (Evaluate) —— 输出的不只是分数,更是 trace `harbor` 在隔离的 E2B 沙箱里把当前的 `code_agent` 跑一遍数据集。每个任务会写出: - `agent/nexau_in_memory_tracer.cleaned.json` —— 完整的 step 级 trace(消息、工具调用、中间件事件) - `agent/nexau.txt` —— 运行时日志(中间件错误、崩溃、警告) - `verifier/reward.txt` —— pass / fail 结果 之后所有步骤操作的单位是 **trace,而不是 pass rate**。 ### 2. 分析 (Analyze) —— 把 ~10M-token 的 trace 蒸馏成可溯源证据 *Agent Debugger* 把每一轮迭代的原始 trace(动辄 10M+ token)压缩成分层报告: - `analysis/overview.md` —— 跨任务的根因汇总 - `analysis/detail/{task}.md` —— 每个任务的深度分析 优化器默认读 digest,但每一条结论都能反向链接到原始 trace,因此在落地修改前可以一路下钻。 > **关于 Agent Debugger 的开源说明。** 当前版本中 Agent Debugger 是**部分开源**的;出于公司战略原因,目前无法完全开源。 ### 3. 改进 (Improve) —— 有证据支撑、可证伪的修改 *Evolve Agent* 只能写 `workspace/` 内部,那里暴露了 NexAU 的七个组件:`systemprompt.md`、`code_agent.yaml`、`tool_descriptions/`、`tools/`、`middleware/`、`skills/`、`sub_agents/`(外加 `LongTermMEMORY.md`)。每一次修改必须提交四个字段: 1. **失败证据 (Failure evidence)** —— 触发本次修改的失败任务和 trace 片段 2. **根因 (Root cause)** —— *为什么*失败,而不仅仅是*失败了什么* 3. **针对性修复 (Targeted fix)** —— 直接对准上述根因的改动 4. **预测影响 (Predicted impact)** —— 哪些任务应当翻转为 pass,哪些可能受到风险 ### 4. 循环 (Loop) —— 错峰世代让证伪成为可能 每个 `runs/iteration_NNN/` 同时混着两代:`input/` 是上一轮 `NNN-1` 产出的 workspace(刚被评估完),`evolve/` 是本轮 `NNN` 写出的内容(在下一轮被评估)。下一次评估中出现的翻转(pass↔fail)会在 `change_evaluation.json` 中归因回本轮的修改——预测不成立的会被回滚或修订。循环在达到 `target_pass_rate` 或 `max_iterations` 时终止。 ### 主要组件 | 组件 | 作用 | |---|---| | `evolve.py` | 主循环编排器 | | `agents/code_agent_simple/` | 被评估和被演化的编码 agent | | `agents/evolve_agent/` | 执行改进步骤的元 agent(基于 [NexAU](https://github.com/nex-agi/NexAU.git) 框架构建) | | `agents/explore_agent/` | 上游数据集 / 源码探索 agent | | `configs/` | `base.yaml`(共享默认值)+ `experiments/`(按实验覆盖) | | `scripts/` | tmux 启动脚本(`evolve.sh`、`evolve-resume.sh`) | ### 目录结构 ``` agentic-harness-engineering/ ├── evolve.py # 主循环 ├── trace_converter.py # rollout trace → debugger 友好的 JSON ├── agents/ │ ├── code_agent_simple/ # 被演化的编码 agent │ ├── evolve_agent/ # 演化元 agent │ │ ├── evolve_prompt.md │ │ ├── middleware/ # 上下文压缩 / failover / ralph 循环 … │ │ ├── skills/ # agent-debugger-cli / nexau-evolution-guide │ │ └── tools/ # 文件 / shell / web / 会话工具 │ └── explore_agent/ # 探索 agent(源码 + web) ├── configs/ │ ├── base.yaml # 共享默认值 │ └── experiments/ # 每个实验一个 overlay ├── scripts/ │ ├── evolve.sh # tmux 启动器 │ └── evolve-resume.sh # 续跑辅助 └── .env.example ``` --- ## 配置(base + overlay) `configs/base.yaml` 保存共享默认值。每个 `configs/experiments/exp-*.yaml` 通过开头的 `_base: ../base.yaml` 继承它,并只覆盖需要修改的字段。YAML 中的任何 `${ENV_NAME}` 引用会从 `.env` 中替换。 **`base.yaml` 关键字段:** | 字段 | 描述 | |---|---| | `path` | 数据集路径 | | `target_pass_rate` | 达到后即停(默认 0.95) | | `max_iterations` | 最大迭代轮数(默认 100) | | `harbor_job_timeout_minutes` | 单次 harbor 评测的超时(0 = 不限) | | `experiment_timeout_minutes` | 整个实验的总 wall-clock 预算(0 = 不限) | | `llm.api_key / base_url / model` | 主 LLM 配置(通常保留 `${LLM_*}`) | | `agent_debugger.llm` | 给 ADB 专用的 LLM(debug 时可换更强的模型) | | `notify.feishu_webhook` | 可选:在实验里程碑时推飞书 webhook | ### 数据集配置 实验的数据来源通过 `path` **或** `dataset` 指定——二选一: | 形式 | 含义 | 示例 | |---|---|---| | `path: "./dataset/xxx"` | 本地数据集目录(相对于 AHE 根目录) | `./dataset/terminal-bench-2` | | `path: "/abs/path/xxx"` | 本地数据集目录(绝对路径) | `/root/dataset/terminal-bench-2` | | `dataset: "@"` | 引用 harbor 内置数据集(不需要本地文件) | `terminal-bench@2.0` | 公开的数据集包(按照 AHE 期望的目录结构)发布在 [`laude-institute/harbor-datasets`](https://github.com/laude-institute/harbor-datasets)——克隆或下载你需要的子集,然后让 `path` 指向它。 `base.yaml` 与 `configs/experiments/*.yaml` 中默认的 `path` 值都只是**占位符**——请按你的环境调整,或注释掉 `path`、解开 `dataset` 行以使用 harbor 的内置数据集。 --- ## CLI 参考 ### `python evolve.py` | Flag | 描述 | |---|---| | `--config ` | 配置文件(overlay 优先) | | `--batch [dir\|files...]` | 批量模式;默认扫描 `configs/experiments/` | | `--experiment ` | 续跑某个已有实验(传 `experiments/` 下的目录名) | | `--start-iteration N` | 从第 N 轮开始(默认 1) | | `--skip-eval` | 跳过评估、复用已有 rollout(调试用) | ### `./scripts/evolve.sh` `uv run python evolve.py` + tmux 的轻封装。 | Flag | 描述 | |---|---| | `` | 位置参数:配置文件路径 | | `--experiment ` | 续跑某个已有实验 | | `--start-iteration N` | 起始迭代 | | `--skip-eval` | 跳过评估 | | `--session ` | 自定义 tmux 会话名 | | `--batch` | 在批量模式下启动每个 overlay | | `--attach` | 启动后自动 attach | --- ## 常用场景 **从第 16 轮恢复一次中断的实验:** ```bash ./scripts/evolve.sh \ --experiment 2026-04-10__23-20-14__gpt54 \ --start-iteration 16 \ configs/experiments/exp-003-simple-code-gpt54.yaml ``` **只跑 evolve_agent,不重新评估:** ```bash ./scripts/evolve.sh \ --experiment \ --skip-eval \ configs/experiments/exp-003-simple-code-gpt54.yaml ``` --- ## 许可证 MIT --- ## Star 历史 Star History Chart