tau2-bench 概念 (M2, 2026-03)
B1→B18 的能力曲线在 B10 进入「把模型/agent 当作可测量系统」的工程化阶段。
阶段: B10 · p95/cost 测量 + 成本级联 + tau2-bench(Day 91-100) 标签: #tau2-bench #agent-eval #dual-control #passk
今日导引(由浅入深)
B1→B18 的能力曲线在 B10 进入「把模型/agent 当作可测量系统」的工程化阶段。
B7-B9 我们建了 eval gate、红队、部署韧性;Day 91-93 把延迟/吞吐/$/query 拆成 p95/p99 + 单位成本;Day 94-95 用 cascade 把成本换质量。
昨天(Day 95)锁的是单轮任务上的「省 $% vs pass 掉幅」曲线。
但单轮 eval 测不出真实对话 agent 的稳定性——多轮里 user 会追问、会改主意、工具会改环境状态。
今天切到 tau2-bench:双控制(dual-control)多轮 agent 评测 + pass^k 稳定性口径。
这是 M2(评测能力支柱)从「单次问答打分」升级到「多轮任务稳定通过」的关键一跳。
今天的最小可判定产出:一个 bench/tau2/ retail 单域脚手架 + 1 条可 commit 的完整 transcript(需 key 跑通)。
1. 机理精读
定义。 tau2-bench(τ²-bench,论文 2026-03)是 tau-bench 的第二代。 核心创新是 dual-control(双控制):在一次评测里,user 模拟器和被测 agent 都能调用工具去读写同一个共享的环境状态(environment state)。 这与第一代 tau-bench 的 single-control 不同——v1 里只有 agent 改环境,user 仅在对话层发话。 双控制更贴近真实场景:客户自己也会去后台改资料、取消订单,agent 必须在一个被对方也能改动的世界里完成任务。
为什么这样设计。 真实客服/调查类任务里,「正确答案」不是一句话,而是最终环境状态是否对:订单是否真的退了、余额是否对、合规标记是否写入。 如果只让 agent 单方面操作环境,评测就退化成「agent 自说自话」,测不出它能否在对方也施加副作用的情况下保持目标一致性。 双控制把 user 也变成一个会调工具的 actor,逼出 agent 的鲁棒性——它得处理「我刚说要退货,但 user 自己又把订单改了」这类竞争性状态变更。 换句话说,dual-control 把评测从「对话质量」推进到「在可被对方改动的世界里把事办成」。
pass^k 的引入。 tau2-bench 同时把稳定性口径从 pass^1 提升到 pass^k。 pass^k 指:同一任务用相同配置独立跑 k 次,k 次全部通过才记一次稳定通过。 这是对「不一致性」的直接惩罚——一个 pass^1=0.8 但 pass^3 只有 0.4 的 agent,意味着它通过靠的是采样运气而非可靠能力。 对生产部署,pass^k 比 pass^1 更有决策价值,因为用户不会容忍「同一个问题三次里有一次翻车」。 (pass^k 的具体测量留到 Day 98 做,今天只确立概念。)
关键权衡。 双控制让评测更真实,但代价是环境实现复杂度和不确定性来源增多。 user 模拟器本身是个 LLM,它的行为也有方差,于是评测里既有 agent 的方差也有 user 的方差。 这正是要用 pass^k 而非单跑的原因——只有重复采样才能把这两层方差暴露出来。 另一个权衡是成本:dual-control + 多轮 + k 次重复,token 消耗是单轮 eval 的数倍。 所以本项目先从 retail 单域起步(只一个工具集),把脚手架跑通再谈规模扩展。
与相邻概念的边界。
tau2-bench ≠ 我们已有的 src/agent/eval/tasks.ts(那是单轮、确定性 codeCheck + LLM-judge 的 ~30 题集,测的是 AML/agent 单点失败模式)。
tau2 测的是多轮 + 环境状态 + pass^k,两者互补。
tasks.ts 答「这个模型单点会不会犯错」;tau2 答「这个 agent 在多轮可改世界里能不能稳定办成事」。
今天只搭 retail 单域脚手架,不替换 tasks.ts——两套口径并存,分别回答不同问题。
单域起步的理由。 tau2-bench 官方含 retail/airline/telecom 多域,每域工具集与状态机不同。 本项目先做 retail 单域,是因为多域会让脚手架复杂度与 token 成本同时爆炸,而单域已足以验证 dual-control + pass^k 的全链路。 等单域脚手架 + 验证函数 + pass^k 聚合都跑通、口径对齐,再谈扩域才有意义。 这与 B10 整体「先把可测量管线打通、再谈规模」的节奏一致——脚手架优先于覆盖度。
2. 推导 / 手算 / 代码走读
tau2 脚手架(bench/tau2/)目前未建——bench/ 目录在仓库里不存在(Glob 验证:no files found)。
seed 也诚实标注 "tau2-bench scaffold NOT built (gated)"。
所以今天不是对现有代码走读,而是按仓库已有风格设计脚手架。可复用的真实代码风格如下:
- 工具注册沿用
src/agent/mcp/toolRegistry.ts的形状:McpToolRegistry.register(spec, handler)(toolRegistry.ts:151)声明name / description / inputSchema(JSON-Schema 子集)。 - 校验是注册表的一等公民:
call(name, args)(toolRegistry.ts:183)先用validate()(toolRegistry.ts:112)按 schema 校验入参,失败抛McpCallError(RPC.INVALID_PARAMS, ...)(toolRegistry.ts:187)再进 handler。 - retail 工具集:退货
returnOrder、查单getOrder、改单modifyOrder等,用这一注册/校验/调用三段式,保证 in-process、纯函数式、可单测。 - 校验先于副作用:handler 永远拿到的是已校验入参——这正好是 dual-control 里需要的「工具是受控入口」语义,user 与 agent 都只能经由受校验的工具改环境。
- 环境状态:tau2 需要一个可被 user 与 agent 共同读写的 state 对象(如
{ orders: {...}, balances: {...} })。脚手架把它做成 in-process 可变结构,每次工具调用是对它的确定性 transform。 - transcript:一条 transcript = [user 模拟轮, agent 轮, 工具调用, 环境快照, ...] 的有序记录,今天用
deepseek-v4-flash跑通 1 条并落盘 commit。 - 同源 runner:模型调用走 provider-agnostic runner(默认 deepseek),与 Day 91-95 同源,保证 token/$ 口径一致——这是 Day 99 三表能拼到一起的前提。
一个 dual-control 回合的状态推演(手写示意,便于理解为什么需要双控制):
- 初始 env:
orders={A: {status:'shipped'}},balances={u: 0}。 - user 轮:客户说「我要退订单 A」(对话层意图)。
- agent 轮:调
returnOrder(A)→ env 变orders.A.status='returned'、balances.u += refund。 - user 副作用轮(dual-control 关键):user 模拟器自己调
modifyOrder(A, addr=...),企图在退货后改地址。 - agent 必须识别「A 已 returned,改地址无意义/应拒」——这一步是 single-control 永远测不到的鲁棒性。
- 终态由验证函数(Day 97)断言:
orders.A.status==='returned'且未被错误回滚。
3. 今日实战
可执行步骤(指向真实路径):
- 新建
bench/tau2/目录与 retail 单域骨架:bench/tau2/env.ts(共享环境状态 + 工具集,沿用src/agent/mcp/toolRegistry.ts的 register/validate/call 三段式)。 - 写 1 个 user 模拟 prompt(描述一个退货/查单场景的客户人设、目标与可调工具)。
- 用 provider-agnostic runner(默认 deepseek、模型
deepseek-v4-flash)驱动 agent 与该 user 模拟跑通 1 条完整多轮 transcript。 - 把 transcript 序列化为
bench/tau2/transcripts/retail-001.json并git commit。 - 工具集与环境 transform 用单测断言(纯函数部分,不需 key)先测通,再接模型——确定性部分先绿,gated 部分后跑。
4. 今日实测 / 产出
- tau2-bench scaffold = 待跑(需 key 跑);当前 REPO REALITY 标注 tau2-bench scaffold NOT built (gated)(Glob 确认
bench/不存在)。 - 本日产出 = tau2 retail 脚手架 + 1 条 committed transcript 文件(需 key 跑通)。
- 可立即落地(不需 key)的部分 = 工具集/环境 transform 的纯函数实现 + 其断言单测;模型驱动的真实 transcript 仍 gated。
诚信底线:不把「待建/待跑」升级成「已完成」。脚手架尚未建、transcript 尚未跑出,状态如实保留为 gated。
5. 常见误区 / 陷阱
- 把 tau2 当 tasks.ts 的替代品:它是多轮 + 环境 + pass^k 的补充,不替换单轮 eval;两套口径分别回答不同问题。
- 用旧 tau-bench(v1 单控制) 当主线:v1 只有 agent 改环境,测不出 dual-control 下的鲁棒性;2026-03 后的双控制 + pass^k 才是新口径。
- 只跑 1 次就下结论:单条 transcript 只能验证脚手架打通,不能当能力数字——稳定性要靠 pass^k(Day 98)。
- user 模拟器方差被忽略:user 也是 LLM,它的行为方差会混进结果;不重复采样就分不清是 agent 弱还是 user 模拟抖动。
- 把工具调用顺序当评判依据:dual-control 下应判最终环境状态而非动作顺序,否则 user 的合法副作用会被误判为 agent 失败。
6. 学习资源(每条带 YYYY-MM)
- tau2-bench 论文(dual-control + pass^k 多轮 agent 评测),2026-03。
- tau-bench(v1, single-control)原始工作,作为对照基线,2024(演进史用途)。
- 本仓
src/agent/mcp/toolRegistry.ts(MCP 工具注册/校验/调用教学装置,工具集风格来源),2026-06。 - 本仓
src/agent/eval/tasks.ts(单轮确定性 codeCheck + LLM-judge 题集,与 tau2 互补对照),2026-06。 - Anthropic "Demystifying evals"(评测方法论,pass^k/HITL 视角),2026-01。
SOTA检查 (2026-06 更新)
- 当前主流:tau2-bench(2026-03)是当前 agent 多轮评测主线,双控制 + pass^k 仍 SOTA。
- 是否仍 SOTA:是。dual-control 把「在可改世界里办成事」做成可测量口径,2026 上半年无更主流替代。
- 过时黑名单:旧 tau-bench(v1 单控制) 不得当主线;旧 deepseek-chat/-reasoner id(2026-07-24 退役)不得用于跑 transcript,统一
deepseek-v4-flash/deepseek-v4-pro。 - 下次复查点:tau2-bench 域扩展(airline/telecom 等)与排行榜状态执行当周重验;模型价格/平台 GA 随周波动须查。
衔接
- 昨天:Day 95 — 级联省钱 vs 质量权衡(M6),单轮上的 $-vs-pass 曲线。
- 今天:多轮 dual-control 评测 tau2-bench 概念 + retail 单域脚手架(1 条 transcript,需 key)。
- 明天:Day 97 — held-out 任务设计(M2),用开发期不可见的任务 + 确定性验证函数防过拟合。