背景
CAR-bench:车载语音 Agent 基准。
- CAR-bench 简介
- Challenge 最终排行榜
- 254 个任务、58 个工具、19 条车载策略
- 用户、环境、工具调用:评测器控制
- 每题独立运行 3 次;
Pass³要求 3 次全过 - 一次错误调用、一次漏读前置状态、一次不合规回复:该 trial 归零
三类任务:
| 类型 | 额外困难 | 正确行为 |
|---|---|---|
| Base | 多轮工具操作、策略级联 | 先读状态,再按顺序执行 |
| Hallucination | 工具、参数或返回字段被移除 | 承认能力缺失;不盲调、不编造、不承诺完成 |
| Disambiguation | 用户没有给全取值 | 能内部消解则内部消解;需要时读取偏好;不猜 |
这个基准测的不是“偶尔能不能做成”,而是“能不能每次都守住边界”。
我的方案:Ground, then Act
模型:DeepSeek V4 Flash;官方隐藏集 Pass³ 53.3%,$0.0055 per trial,打败 GPT-5.6 Sol baseline 中成本最低方案 (其他队伍方案成本的 1~3%)。
目标:不靠更大的模型;在工具调用前,把高确定性的错误拦在 harness 中。
其他过半队伍的方案也是做 guardrail, 就不赘述.
结构
用户消息 + 工具
↓
ReAct 模型提出调用
↓
schema / 偏好 / policy 三道门
↓
放行原调用 | 扣留、反馈、重提议 | 诚实拒答
- Owned prompt:能力缺失时承认,不强行完成
- Schema gate:参数必须符合实际工具接口
- 偏好判别器:对用户未明说的写入值,区分“有依据”与“猜测”;猜测则先读
get_user_preferences - Policy gate:确定性检查策略、顺序和级联后的预测状态
- Unknown disclosure:返回字段未知时,强制在下一句说明
- 至多 3 次重提议:仍失败则无工具诚实说明;绝不把已拦截的调用再放出去
关键原则:
- 策略、schema、状态约束:代码
- 语义边界:小范围 LLM 判别
- 被拦截的调用:只存在于内部上下文,绝不 dispatch
- 跨轮状态:仅从已执行调用和真实工具结果重放
效果与成本
公共训练集,同一 DeepSeek V4 Flash、不开推理:
| 配置 | Pass³ | Base | Hallucination | Disambiguation |
|---|---|---|---|---|
| 官方 baseline | 47.7% | 66% | 42% | 35% |
| 三门 harness | 60.4% | 66% | 67% | 48% |
- 总体:
+12.7pp - Hallucination:
+25pp;核心收益 - Disambiguation:
+13pp - 着重优化这两类任务的原因是最终评分算三类任务 macro-avg, 先优化分数低的任务性价比高
- Base:持平;守卫没有牺牲常规任务
- 延迟:
12.4s → 13.2s,1.06× - 成本:约
$0.0011 / trial;提示缓存命中94.7% - 开启高推理:训练集
68.3%,隐藏测试62.0%;成本约$0.0042 / trial
创新点不在“又加了一个 prompt”,而在把失败会造成不可逆扣分的动作,改成:
提出 → 可验证 → 放行
└→ 不可验证 / 不合规 → 不执行
得失
有效:
- 缺失参数、未知结果字段:从盲调/沉默变为诚实披露
- 偏好相关写入:从猜值变为先读偏好
- 级联策略:从“调用过工具”升级为“预测后的状态满足约束”
仍然困难:
- 被删的导航编辑工具:评测期望承认缺失,静默绕路也可能失败
- 消歧中的“该内部判断还是该问用户”:纯规则很难完整覆盖
- 个别题目的参考解存在合理解释空间
冠军方案:TRACE
冠军:Darwin Agent;GPT-5.6 Sol,隐藏集 Pass³ 70.0%,$0.27 per trial。
核心不是运行时叠更多 guardrail,而是离线从评测轨迹中蒸馏一组可检索技能,再在每一轮按对话状态注入相关技能。
- 冠军:单次成功
70.0%;Pass@3 83.3%;Pass³ 70.0% - 我的方案:单次成功
66.7%;Pass@3 83.3%;Pass³ 53.3% - 不是“冠军有更多偶发成功”;两者至少成功一次的题数相同
- 冠军优势:consistency 更强, 无法判断是否为模型本身强度所致
方案上其实和我类似都是用个 meta agent 去分析 trace 改进 harness. 不过 Darwin Agent 六个人一整个团队, 加上之前做过类似的 HarnessX, 方法可能更成熟一些. 叫 Darwin 应该是因为这套范式通常叫自进化 agent.
机制
冠军提交的技术报告:TRACE。源码尚未公开;以下是报告明确写出的流程。
离线:多轮评测轨迹 → 初始化 skill bank → 反复对比改写
在线:当前对话 + skill 描述索引 → 自选少量 skill → 注入正文 → 工具动作
两个角色:
- Actor:运行时的普通 tool agent;选 skill、对话、调用工具
- Curator:离线读评测轨迹;创建、改写、拆分 skill
每条 skill 有两部分:
| 字段 | 放什么 | 运行时作用 |
|---|---|---|
| 描述 | 一行说明;触发短语、适用操作 | 常驻 prompt;组成轻量索引 |
| 正文 | 工具规则、决策准则、常见失败、流程 | 选中后才注入当前回合 prompt |
关键不是“把所有经验写进一个长 prompt”,而是让每条 skill 足够窄、可被当前回合重新选中。
1. 冷启动 skill bank
先在训练集上对每题运行多轮。Curator 对同题的成功与失败轨迹做 task-level 蒸馏;再连续抽象:
同一 task 的多条轨迹
↓ 去掉偶发路径,保留成功行为 + 常见错误
task skill
↓ 合并同一 task type,移除 task 专属细节
type skill
↓ 跨 type 按底层操作合并
operation skill
↓ 拆开过宽 skill
初始 skill bank
- task-level:记录某一任务怎样成功、怎样失败
- type-level:只保留同类任务共有的行为
- operation-level:把表面目标不同、底层操作相同的经验合并
- decomposition:大而模糊的 skill 拆成单一能力;提高检索精度
报告没有公开实际 skill 文本或数量;能确认的是它们以 Markdown SKILL.md 保存。
2. 进化:按“实际命中的 skill”归因
每一轮先用当前 skill bank 跑评测,再根据轨迹更新 skill bank。
| 步骤 | 实际做法 | 要解决的问题 |
|---|---|---|
| Skill-aware grouping | 按轨迹各回合真正选中的 skill 分组 | 不把失败笼统归给整个 agent |
| Runtime-faithful reconstruction | 重建 Actor 当时能看到的上下文;把离线特权信息单独标注 | 不把答案或不可见环境信息写进 skill |
| Contrastive refinement | 对同一 skill 的成功 / 失败轨迹做对比,直接改写该 skill | 让规则同时包含“该做什么”和“为何会错” |
| Split / discover | skill 太宽就拆;无 skill 命中的重复模式则新增 skill | 控制粒度,补齐覆盖空洞 |
重建时,共享的基础 prompt、工具列表只写一次;每道题只附相对 baseline 的 capability changes。离线分析能看到奖励、期望动作等诊断信息,但 skill 只能依赖 Actor 运行时可见的内容。
3. 部署:逐回合自选择,而不是常驻全文
常驻:所有 skill 的描述
↓ Actor 根据当前对话自选相关 skill
选中:对应正文注入 prompt
↓ Actor 产生本回合动作
下一回合:丢弃本回合正文;重新从描述索引选择
- 不需要额外 retriever;报告中的选择器就是 Actor 自己
- 每回合可选多个 skill;选中正文不跨回合累积
- 对话从“明确请求”变成“发现能力缺失 / 需要消歧”时,下一回合可切换 skill
- 代价:skill bank 变大后,LLM 自选描述的检索可能扩展性变差
4. 两条防过拟合约束
- operation-level organization:技能写“怎样执行一类操作”,不写某个 task 的答案
- de-hardcoding:禁止 task id、环境专属取值、记忆答案;只保留可迁移的工具与决策原则
这解释了为何同一 skill bank 在 GPT-5.5 轨迹上进化后,还能原样放到 GLM-5.2 上评测。
5. 报告的实验边界
- skill bank:先用训练集冷启动,再用测试集轨迹扩展覆盖
- 结果:训练与测试合并后的完整 CAR-bench 自测
- 模型:GPT-5.5 medium 上进化 skill bank;原样迁移到 GLM-5.2 high
- 因而
94.5% Pass³/84.8% Pass³说明方法很强,但不是严格 held-out 泛化估计 (过拟合嫌疑) - 官方隐藏榜的冠军配置:GPT-5.6 Sol,
Pass³ 70.0%;与上述自测不能直接横比
HarnessX on τ²-bench
因为冠军方案没开源, 但是 darwin agent 团队有个开源的 HarnessX, 以及 car-bench 本身也是模仿 tau-bench 的, 所以看下这块代码.
相关源码:
以下按 bf5f199(2026-07-29)源码核对。
TRACE 产出的是 skill bank;HarnessX 的 meta-harness 产出的是下一版 harness。
Meta-agent:一个有严格交付契约的简单 loop
是 HarnessX 自己的单 agent loop,默认模型为 Claude Opus 4.6 + extended thinking。
读本轮任务说明、历史 memo、轨迹
↓
找跨任务模式;写 candidate 假设
↓
写下一版 config / processor / prompt
↓
自检 + 记录 journal
↓
外层 runner 真实评测;保留或回退
没有 planner / executor 多角色编排。复杂性在输入、输出、验证、跨轮记忆的文件契约:
- 只写本轮
output_dir与 journal;不能改框架源码 - 必须写出可加载的
config.yaml;无改动也要复制旧 config - 每个非空改动先写
Candidate C-NNN:失败模式、受影响任务、为什么选这个 lever、不选相邻 lever 的理由、收益/回归/成本预测 - runner 回填上一轮的 accepted / reverted 与逐题归因;下一轮不应重试已失败的同一假设
它实际读到的 prompt
不是一份巨型 prompt;由一份角色说明、每轮文件和按需 skill 组成。
| 层 | 内容 |
|---|---|
SOUL.md |
身份:从轨迹交付新 HarnessConfig;七步 loop;Pareto 规则;硬约束 |
TASK.md |
本轮 config、轨迹目录、输出目录、预算、路径 |
memo_path + CONTEXT.md |
过往假设、接受/回退结果、lever scoreboard |
analyze skill |
用 failure / capability-gap / success 三种 lens 读轨迹;在 configuration / control / action / instruction 四种 lever 中选修复方式 |
tau2-playbook |
τ² 特有失败模式、已有可用 processor、策略与 tool 约束 |
reference skill |
YAML schema、hook 表、MultiHookProcessor / Jinja 的编写方式 |
validate skill |
canonicalize、dry-fire、hook contract、literal scan |
journal skill |
跨轮记录格式;下一轮的唯一持久记忆 |
SOUL.md 的核心要求:
- 修 harness deficiency;不把 model capability gap 伪装成 prompt 补丁
- passing trace 和 failing trace 同样重要;修失败时要保护已成功模式
- 目标是全局净收益;单题收益但有回归风险,默认不做
- 禁止把任务 id、答案、环境专属常量塞进产物
SOUL.md:不是“帮我调参”,而是一套决策规程
| 阶段 | SOUL 强制行为 |
|---|---|
| 读历史 | 先看 memo、已接受/回退假设与 lever scoreboard;跳过已证伪方案 |
| 读轨迹 | 先扫 frontmatter;某模式占主导时,再读代表性对话正文 |
| 写候选 | 每个改动写 Candidate C-NNN;附收益、回归风险、成本变化与 rollback trigger |
| 写产物 | config.yaml 必须存在;可写 processor、tool、template |
| 自检 | canonicalize;写了代码再 dry-fire / contract check;literal scan 只告警 |
| 留记忆 | journal 追加本轮假设;外层评测填 accepted / reverted / 逐题归因 |
先判断:
- Harness deficiency:动态信息缺失、重复的危险动作、工具结果难用 → 可以改 harness
- Model capability gap:缺领域知识、某类推理能力不足 → 记录后跳过;不能靠塞题目知识假装修好
两道刹车:保护成功模式;预先声明回退条件。
analyze skill:把 trace 变成可证伪的改动
输入:每题一份 Markdown 轨迹。
- frontmatter:
eval_passed、reward、退出原因、步骤数、工具/错误计数、成本 - body:决定性回合真正看到了什么、调用了什么、为何失败
eval_*是正确性真值;LLM judge 只用于解释失败形状
两个轴给候选定位:
| 轴 | 选项 | 作用 |
|---|---|---|
| Lens | failure / capability gap / success | 不只修失败;成功轨迹也可锁定或迁移 |
| Lever | configuration / control / action / instruction | 调参数、写 hook、加 tool、改提示 |
候选至少覆盖两个任务;还要通过反事实检查:
- corrective:这个修复早存在,失败题会过吗?
- preservative-lock:去掉成功习惯,已通过题会挂吗?
- preservative-transfer:把成功习惯施加到失败题,能在关键回合解锁吗?
analyze 的实际工作单元
它不输出“失败原因总结”;输出可交给下一步实现的 candidates.md。
## Candidate C-001
[lens: failure | lever: control | intent: corrective]
- Tasks affected: task-011, task-042, task-108
- Signal: 三题均在同一 tool 输出后失败;`tool_error_counts = 0`
- Verified: 正文显示 tool 已取到数据,但输出格式无法被 agent 使用
- Why Control not Action: 信息已返回;缺的是后处理,不是再发明一个 fetch tool
- Retroactive check: 有解析后的结果,关键回合可继续
- expected_global_gain / regression_risk / cost_shift / rollback_trigger
因此它在强迫 meta-agent 回答四个常被跳过的问题:
| 问题 | 防止什么 |
|---|---|
| 为什么是这个 lever,不是相邻 lever? | 用 prompt 逃避真正的工具/控制缺口 |
| 是否有至少两个不同输入的任务? | 为单题 hardcode |
| 轨迹正文是否支持根因? | 只看计数和 reward 的事后猜测 |
| 改动先前存在时真能改变关键回合吗? | 修下游症状,不修上游原因 |
典型判别:
| 轨迹证据 | analyze 倾向的 lever |
|---|---|
budget_exceeded,但最后几步仍在有效推进 |
Configuration:提高 CostGuard 上限 |
| tool 返回二进制/重定向页面,agent 无法消费 | Control:on_after_tool 规范化结果 |
| 已有数据和推理正确,只是输出格式被 judge 判错 | Instruction:加明确输出规则 |
| 三题都缺同一种、现有工具无法取得的信息 | Action:新增窄工具 |
| 成功题都先列计划,失败题直接工具乱撞 | Instruction / Control:把计划习惯锁定或迁移 |
刻意限制:capability gap 不等于 prompt 问题。现有工具没有某能力时,增加一句“请仔细思考”不算修复。
tau2-playbook:把抽象 loop 接到具体 benchmark
它不是答案库;是 τ² 的任务模型与 failure map:
- reward = DB 状态 × action checks × NL assertion;任一为零,全题零
- 标准节奏:读状态 → 诊断 → 用户确认 → 写工具 → 收尾
- retail:订单状态决定 modify / exchange;退货不能换支付方式
- airline:basic-economy 不可改;必须取得用户与 reservation id
- telecom:用户侧开关要先指导用户操作、等确认、再读取状态
| 轨迹形状 | 首选修改 |
|---|---|
| 首轮就写、未读状态 | 上调 PhaseAwareToolFilter.read_only_steps |
| 同一调用反复循环 | 调整 / 加入 loop detection |
| 工具输出类型或参数不稳 | parse retry、type correction、tool-failure guard |
| 策略顺序错 | SystemAppendProcessor 追加 domain guidance / 决策树 |
| telecom 状态满足某条件 | 启用 PolicyHintProcessor 注入 remediation hint |
| 每回合都漏相关策略 | 新 on_before_model IRMA processor |
Playbook 的完整技术清单
已在 harness_config.yaml 接入:
| 技术 | 作用 | 可调项 |
|---|---|---|
| Phase-aware tool gate | 强制先读后写 | read_only_steps |
| Loop detection | 阻断重复 tool call / confirmation loop | 阈值 |
| Parse retry | 模型输出不符合工具格式时重试 | 重试次数 |
| Tool-call correction | 修正 bool / int / float 等常见类型错配 | 启用 / 规则 |
| Tool-failure guard | 连续工具错误后尽早停止 | 错误上限 |
| Token budget | 上下文超窗时截断 | 上下文比例 |
| SystemAppendProcessor | 原始 τ² policy 后追加领域指导 | guidance 文件 |
| PolicyHintProcessor | telecom 条件命中时注入正向提示 | 按域启用 |
| Extended Thinking | 任务 agent 增加推理 token | thinking budget |
| StopGuard | 确认消息中移除过早 ###STOP### |
--stop-guard |
Playbook 建议 meta-agent 视轨迹新增:
| 技术 | 对应产物 | 适用迹象 |
|---|---|---|
| Policy → decision tree | guidance_<domain>.md |
反复错过政策分支或顺序 |
| IRMA input reformulation | on_before_model processor |
规则已在 prompt,却未在当前回合激活 |
| Plan-confirm-execute | plan guidance + 写前 gate | 不可逆写、幻觉 ID、漏确认 |
| Trust-score revision | on_after_model processor |
输出偶发不可信、可局部重写 |
| Dependency-aware reordering | guidance / planner control | 用户给的顺序违反策略前置条件 |
| Case-specific guard | on_before_tool processor |
同一状态—动词错配跨任务复发 |
后半是候选库,不等于每轮都会启用;其论文中的 lift 引用也不是 HarnessX 自身的端到端 ablation。
tau2-playbook 如何指导一次真实诊断
它给每份轨迹一个 domain-specific 检查顺序:
| 领域 | 先看什么 | 常见“看似合理、实际零分” |
|---|---|---|
| Retail | order status、产品/支付限制、是否已经确认 | 对 delivered order 调 modify_pending…;退货时换支付方式;只处理用户多请求的一半 |
| Airline | cabin、reservation / user id、用户隐藏约束 | 修改 basic-economy;猜 ID;没问清 EWR vs JFK 这类约束 |
| Telecom | issue hierarchy、用户侧还是 agent 侧操作、确认后的状态 | agent 直接“打开”用户手机设置;未等确认就继续;未 re-read 结果 |
它要求从 τ² evaluator 的三块结果反推,而不是只看最终 reward=0:
| evaluator 信号 | 应检查的根因 | 常见配置方向 |
|---|---|---|
db_match=false |
写工具、参数、执行顺序、过早停止 | phase gate、policy guidance、on_before_tool guard |
| action check 缺失 / 多余 | 漏确认、重复写、选错工具 | loop guard、顺序提醒、状态—工具映射 |
nl_assertion 失败,DB 正确 |
过度承诺、遗漏解释、编造限制 | system append guidance / response-side control |
它也区分两种性质不同的修复:
- Harness 问题:前两步就写、循环、类型错误、确认消息被
###STOP###吃掉。可由 gate、retry、StopGuard 修。 - 策略表达问题:模型读到完整 policy 仍没在当前回合激活正确分支。可用
SystemAppendProcessor把规则压成触发条件 → 检查 → 动作的 guidance。
IRMA 是更动态的一层:不永久增加整份 prompt;每次 on_before_model 从当前轨迹中挑相关 policy、候选工具和顺序提醒,插到该回合上下文。它适合“规则存在但经常没被激活”,不适合“工具本身不存在”。
它到底改什么
不改:任务 Agent 的模型权重;τ² 的环境、评测器、原始工具和原始系统策略。
它改的是 HarnessConfig:一份声明“这个 Agent loop 装哪些部件、按什么参数运行”的 YAML。
| 配置面 | 真实改动 | τ² 例子 |
|---|---|---|
| Processor 列表 | 添加、删除、排序、传 constructor 参数 | LoopDetectionProcessor、ParseRetryProcessor、ToolCallCorrectionLayer |
| 既有 processor 参数 | 改现有组件的阈值 / 预算 / 行为 | read_only_steps: 2 → 3;token 或 cost guard 阈值 |
| 自定义 control | YAML 用绝对 file://...py::Class 引入新 MultiHookProcessor |
on_before_model 插入 policy reminder;on_before_tool 阻止状态不匹配的写操作 |
| Prompt builder | TemplateSystemPromptBuilder 指向新 .j2;或用 overlay processor |
普通 benchmark 可替换 template;τ² 只能在保留原策略 prompt 的前提下追加 guidance |
| Tool registry | 增删 builtin / custom @tool |
真正缺少某一类能力时才加;不是默认方案 |
| 运行槽位 | tracer、workspace、sandbox 等声明配置 | 记录 trajectory,供下一轮读取 |
τ² 的特殊点:系统 prompt 由 benchmark 注入,NullSystemPromptBuilder 会原样通过。直接换成 Jinja template 会丢掉完整 policy 与工具说明。因此 prompt 改动通常是:
原 τ² system prompt
+
domain guidance Markdown
↓
SystemAppendProcessor 在 on_task_start 合并
↓
每轮模型调用看到合并后的 prompt
一个最小的自定义 processor 接入形状:
processors:
- _target_: file:///abs/output/processors/irma.py::IrmaProcessor
max_hint_chars: 600
IrmaProcessor 是一个 MultiHookProcessor 子类;它实现 on_before_model / on_before_tool / on_after_tool 等 hook,把 event 原样放行、替换字段,或在明确规则下拦截。YAML kwargs 直接传给它的 __init__。
τ² 的 hardened baseline 本身已有:
- 前两步只暴露 read tool 的 phase-aware filter
- loop detection、工具调用解析重试、参数类型纠正、连续工具失败保护
- StopGuard:用户在确认语中夹带
###STOP###时,移除过早停止标记;避免写操作尚未执行就结束
meta-harness 的输入与产物
R0:基线 config 跑 τ² 任务
↓
每题 reward + 对话/工具轨迹 + 当前 config
↓
Meta-agent(默认 Claude Opus 4.6)读失败模式
↓
R1:config.yaml + processors/*.py + templates/*.j2
↓
重新评测;回退明显退化的 config
- 普通多轮:在固定任务集上反复“评测 → 改 config → 评测”
- badcase loop:后一轮只看前一轮仍失败的任务;产出一串针对残余失败的 config
- 当前代码的保留线:平均 reward 不得比历史最优低超过
2pp - 验证:config canonicalize、合成任务 replay、processor hook contract;并记录证据与变更集
实际常见改动不是重写工具逻辑,而是运行时消息增强(IRMA):
- “还没有查完所有订单”
- “先修改地址,再修改商品”
- “策略未明确禁止时,尝试调用工具,不要编造限制”
它产出的结果
先区分两类数字:
| 结果 | 设置 | 含义 |
|---|---|---|
| HarnessX adapter | Sonnet 4.5 + Extended Thinking;GPT-5.2 user simulator;1 trial | telecom 86.0% vs leaderboard 84.9%;airline 74.0% vs 72.0%;retail 71.1% vs 72.4% |
| meta-harness badcase loop | Qwen 3.5 27B;retail 114 题 | 文档示例:92/114 = 80.7% 起步;22 个失败中修复 18 个;推算 110/114 ≈ 96.5% |
96.5% 的具体算法:
C1:全量 114 题 → 92 通过,B1 = 22 失败
C2:只在 B1 上进化 / 评测 → 修复 11,B2 = 11
C3:只在 B2 上进化 / 评测 → 再修复 4,B3 = 7
C4:只在 B3 上进化 / 评测 → 再修复 2,B4 = 5
C6:只在 B4 残余上进化 / 评测 → 再修复 1,B6 = 4
估算:原 92 + 累计修复 18 = 110;110 / 114 = 96.5%
C{k}从C{k-1}继续修改;不是给每个 task 单独写 agent- 每轮只喂仍失败的 task trace;让 meta-agent 专注 hard residual
- 最终仍有 4 题未解:79、100、105、112
- 没有重新运行 114 题验证最后的
C6;96.5%假设此前 92 个成功 task 永不回归 - 文档也明确要求:正式结论前应全量 rerun final config
第二行更接近“meta-harness 进化”的结果,但不能当严格最终榜分:
- 后续轮只评上一轮失败子集
96.5%假设已通过的题不回归;文档明确建议最后重跑全量验证- 默认
num_trials=1 - 仓库未提交该实验的逐题运行产物;目前只能复核代码和文档中的汇总/示例
论文中的详细 case analysis
HarnessX 技术报告 的详细个案主要来自 GAIA、ALFWorld、WebShop、τ³-bench;不是 τ² recipe 的实际运行产物。
GAIA / Sonnet 4.6 / Round 10:一次完整的“发现 → 修改 → 验证”
| 阶段 | 证据与动作 |
|---|---|
| R9 状态 | 通过率 74.8%;此前峰值 77.7%,已有回归 |
| Trace 信号 | 23 个失败中,Wikipedia WebFetch 多次返回 0 字符;两个代表性任务累计 10 次空响应 |
| 根因 | Wikipedia 新前端使 browser-style fetch 超时或得到空 body;不是模型不知道该查什么 |
| Planner 目标 | 修复持续存在的 source-access 问题;撤销 R9 中造成回归的 prompt / budget 改动 |
最终只批准候选 C-R10-02:
工具:新增 WikiTextFetch,绕过浏览器,调用 MediaWiki API
提示:查 Wikipedia 时优先用 WikiTextFetch
配置:回到 R8 基线;注册新工具;移除有问题的 budget processor
Critic 不是直接相信代码:
- API 真实返回文章全文:示例分别为
10,529与80,028字符 - 长工具结果能经 provider 序列化后完整到达模型上下文
- 新候选包含“回退 R9”的效果;因此拒绝只回退、不修检索的竞争候选
- 预注册:预期解锁 5 题、稳定 2 题;至少要观察到一次
WikiTextFetch调用
结果:
74.8% → 79.6%,+4.9pp;该 run 最大单轮提升- 预期受影响 7 题中 5 题翻转成功;hit rate
0.71 - 提升主要发生在 GAIA Level 2 / 3
但它没有把这轮当作“问题解决”:
R10:新工具修复真实检索失败;分数上升
R11:trace 发现少数通过来自 verifier 的格式规律,而非真实检索
R12:加 guard;只有能被第二条检索路径交叉验证时才允许该工具
这个案例展示的重点:HarnessX 不是自动加 prompt。它同时改工具、prompt、config;再用 trace 检查分数提升是否来自真正能力,而不是评分漏洞。
另外三种失败病理
| 病理 | 论文案例 | 发生了什么 | 后果 / 修正 |
|---|---|---|---|
| Reward hacking | GAIA R10–R12 | 新检索工具既修复空响应,也让少数任务利用 verifier 格式通过 | R11 trace 发现;R12 要求第二检索源交叉验证 |
| Catastrophic forgetting | τ³ Telecom,Sonnet 4.6,R2–R9 | 连续 5 轮叠加同类 reminder;89.5% → 100% → 94.7%,第 6 条规则使其跌至 80.7% |
R8–R9 以结构化 edit 替换冲突 rule stack,恢复到 99.1% |
| Under-exploration | ALFWorld,Sonnet 4.6,R4–R7 | 长期只探索 prompt edit;每轮增益 <1%;预测翻转命中率 80% → 0% |
识别 prompt 空间耗尽;但唯一一次 processor edit 也仅命中 1/7,最终停在 94.8% |
论文给出的反面结论也重要:每轮 gate 能挡住明显坏改动,却未必能发现多个“单独无害”的 rule 逐步耦合;GAIA 的 variant isolation 是他们针对这种全局遗忘提出的补救。
附录:HarnessX Meta-Agent 原始 SOUL.md
来源:HarnessX@bf5f199。
# HarnessX Meta-Agent
You analyze trajectories from a HarnessX agent's last benchmark round
and ship an evolved `HarnessConfig` that should close one or more
capability gaps.
## Loop
Skill-reading is lazy — read each skill the first time you need
its content, not preemptively. The arrows below mark where each
skill becomes relevant.
1. `Read _meta_scratch/TASK.md` — paths, memo, budgets, journal
context (if prior rounds exist).
2. `Read memo_path` and `_meta_scratch/CONTEXT.md` (when present)
— prior rounds' accepted/reverted hypotheses, lever scoreboard.
Skip doomed bets.
3. Read trajectories (frontmatter sweep first; bodies of
representative tasks when a pattern dominates).
→ `Read analyze` for the lens × lever × intent framework, the
three retroactive-check variants, `spawn_reflect_worker` usage.
→ `Read <bench>-playbook` if mounted — benchmark-specific
patterns and capability classes.
4. Draft candidates under `_meta_scratch/candidates.md` (required
whenever the round changes the config). Each section header is
`## Candidate C-NNN`. Schema, three-axis tag (lens / lever /
intent), retroactive-check variants, `Tasks affected` rules
by intent — all live in the `analyze` skill you just read.
5. Write `output_dir/config.yaml` and any authored files.
→ `Read reference` for authoring mechanics: YAML shape, `@tool`
signature, `MultiHookProcessor` contract, Jinja template swaps,
Configuration knob guide.
6. Self-validate before `end_turn`.
→ `Read validate` for the CLI commands and the validity /
policy / advisory categories. Minimum: `canonicalize`; plus
`dry_fire` / `contract` when you authored anything. `literals`
is advisory — fix what it finds but it doesn't block the round.
7. Append to `memo_path`.
→ `Read journal` for the entry schema and required frontmatter.
## Pareto thinking rule
Do not chase single-task wins that weaken the overall benchmark.
Prioritize interventions that improve a failing cluster while keeping
already-passing clusters stable. Treat each candidate as a three-way
tradeoff:
- **Global gain** — how many failures can plausibly flip.
- **Regression risk** — what likely breaks outside `predicted_affected`.
- **Cost shift** — expected token/cost movement if the change lands.
When two candidates have similar local upside, prefer the one with
lower regression risk and smaller cost inflation. If a candidate is
"high local gain, high collateral damage", ship only with strong
evidence and an explicit rollback trigger in the journal.
## What you ship
| Path | Purpose |
| --------------------------------- | ------------------------------------------------ |
| `output_dir/config.yaml` | The evolved HarnessConfig (required) |
| `output_dir/tools/<name>.py` | Optional new `@tool` modules |
| `output_dir/processors/<name>.py` | Optional new `MultiHookProcessor` classes |
| `output_dir/templates/<name>.j2` | Optional new system-prompt templates |
| `memo_path` (journal) | One appended entry per evolve (required) |
All file refs in `config.yaml` use **absolute** `file://` paths.
## Evolution philosophy
Your job is to improve **harness mechanisms**, not inject task-specific knowledge
into the system prompt.
For every trajectory — passing or failing — first ask: **"Is this a harness
deficiency or a model capability gap?"** Passing trajectories are as valuable
as failing ones: they reveal habits worth preserving or generalizing, and
often expose token or cost inefficiencies that a better harness mechanism
could eliminate while keeping the task passing.
**Harness deficiencies** — fix with a new processor or tool:
- Agent fails to detect a failure state it cannot recover from →
`MultiHookProcessor` that intercepts and blocks/redirects
- Agent lacks dynamic context it needs → processor that injects it at runtime
- Agent repeats a destructive pattern → processor that intercepts before execution
**Model capability gaps** — NOT the harness's job:
- Agent lacks domain knowledge required to solve a class of tasks
- Agent makes reasoning errors specific to one task type
For model capability gaps: write one line in `memo_path`:
`"<task>: requires <capability X>; no harness fix — skip."` Then move on.
Do **not** patch capability gaps by embedding domain knowledge in the system prompt.
**System-prompt template rules**:
- Strategy descriptions, not solutions: describe *how to approach* a class of problems,
never embed task-specific code, constants, or algorithms.
- **No "MANDATORY: Copy this code" / "copy-paste" directives.**
- **No literals extracted from trajectories** (variable names, numeric constants,
identifiers, file paths that only appear in the training tasks).
- Generalization test: *"Would this guidance help an agent solving a task it has
never seen before?"* If no → rewrite as general strategy or delete.
## Hard invariants
These cause the round to fail if violated. No retry.
1. **Deliverable exists and canonicalizes.** If you stop without
writing `output_dir/config.yaml`, or the YAML fails
`HarnessConfig.from_yaml_file(...).canonicalize()`, the round
fails. When no change is warranted, copy the current config byte-
for-byte to `output_dir/config.yaml` — that's the explicit no-op.
2. **Writes only to `output_dir/` and `memo_path`.** Everything
else (`harnessx/**`, `recipe/**`, `benchmarks/**`, the target's
`workspace/**`) is read-only. If you need something outside this
scope, note it in `output_dir/_meta_scratch/NEEDS_FROM_HUMAN.md`
and stop.
3. **Absolute `file://` paths for authored files.** Relative paths
are rejected by the loader.
4. **Authored code serves a class of tasks, not one.** Hardcoded
task IDs, dataset UUIDs, or one-question regexes are flagged
by the `literals` advisory (non-blocking). Not fatal on their
own, but such components almost never survive the next
benchmark round because they only work on the one task the
author memorised — fix when you see the warning.
5. **Post-flight replay.** After you stop, the orchestrator runs
a synthetic-task smoke gate through the real run loop. Any
crash, upstream 400, timeout, or `exit_reason=error` fails
the round. The oracle is the run loop itself — you do not
write assertions.
6. **No local-only optimization.** A change that helps one corner case
but likely harms global pass-rate should be rejected by default;
document why global net benefit still holds if you keep it.
## Ambition
"Barely-changed config that tweaks one threshold" is often the wrong
answer. Regressions auto-revert, so big bets that fail cost one
round's compute; timid bets that "succeed" waste the round entirely.
When the evidence supports a larger intervention (new processor
cluster, fresh template, a genuine new capability), ship it.
## Skill pointers
- `reference` — mechanics of writing `@tool`, `MultiHookProcessor`,
Jinja templates, `config.yaml` shape, and the signal→knob guide
for the Configuration lever.
- `analyze` — how to read trajectories and frame gaps.
- `validate` — the CLI self-check suite.
- `journal` — schema and conventions for the cross-round memo.
- `<bench>-playbook` — benchmark-specific patterns (failure modes
to close, success habits worth preserving / generalizing) and
techniques (when loaded).
Think, design, ship. The scaffolding is minimal; the judgment is
yours.
原文较长,保留源码链接而不全文贴入:
analyzeskill:601 行tau2-playbook:275 行