EvoCUA 实战:用可扩展合成经验训练 Computer Use Agents 的配置大纲
工试云启 考证服务中心整理

1. 从静态模仿到合成经验EvoCUA 要解决的真实痛点如果你最近在折腾 Computer Use Agents大概率会遇到一个很尴尬的局面模型在 demo 里点得挺准一旦换到 OSWorld 这种长程任务基准上成功率就掉得厉害。我一开始以为是模型不够大后来把 OpenCUA 的轨迹数据翻出来看才发现问题不在参数量而在训练范式本身——静态数据集里的轨迹是「死」的它记录的是别人怎么操作却没有记录「为什么这么操作」以及「操作错了之后环境怎么反馈」。EvoCUA 这篇论文的核心洞察就在这里。它把传统「收集轨迹 → 模仿学习」的流程换成了「合成任务 → 并行交互 → 从成功和失败里进化」的闭环。用一句话概括它不再让模型背操作步骤而是让模型在成千上万个可验证的合成任务里自己试错再把试错经验蒸馏回策略里。这对开发者意味着什么意味着你不需要先攒一个几十万条的高质量轨迹库才能开始训 CUA。你可以先搭一个能自动生成任务、自动判定对错的合成引擎让 Agent 在沙箱里跑跑完把成功轨迹和失败轨迹都收回来用拒绝采样和偏好优化去更新模型。OSWorld 上 EvoCUA-32B 拿到 56.7%超过 OpenCUA-72B 的 45.0%这个差距很大程度上就来自「经验是可扩展的」而不是「数据是堆出来的」。适合谁跟做如果你已经在用 OpenCUA、UI-TARS 这类模型做 GUI Agent或者你手上有 OSWorld 环境想复现论文里的训练闭环这篇的配置大纲可以直接拿去改。如果你只是想让模型帮你点网页那可能用不上这么重的流程。下面我会按「合成经验生成 → 训练数据构造 → OSWorld 验证」三段来拆每一段都给可复制的配置和排障点。2. TaoToken 前置给合成引擎和验证环节接上稳定模型入口EvoCUA 的合成引擎本身要调用一个强 VLM 来生成任务描述和验证器代码OSWorld 验证阶段也要用模型做动作预测。这两个环节对 API 的稳定性和模型 ID 的准确性要求很高——合成引擎如果因为 401 或超时中断整个任务批次就废了验证阶段如果模型 ID 写错跑出来的成功率根本没意义。我自己的做法是先把模型入口统一到一个兼容 OpenAI 协议的服务上这样合成脚本、训练数据构造脚本、OSWorld 的 agent wrapper 可以共用同一套 Base URL 和 Key不用每个环节单独配。TaoToken 的 API 地址是https://taotoken.net/api兼容 OpenAI 的/v1/chat/completions格式模型对话入口在https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content你可以先去那里确认当前可用的模型 ID别直接抄论文里的模型名因为论文用的基础模型和你实际能调到的往往不是同一个。拿 Key 的流程不复杂进控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content在 API Keys 页面https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content创建一个新 Key复制出来存到环境变量里。注意别把 Key 硬编码进合成脚本后面你要跑几万个沙箱任务Key 泄露或者轮换会很麻烦。这里有个容易踩的坑EvoCUA 的合成引擎需要模型输出结构化的任务定义和验证器代码所以你在调用时要显式要求 JSON 输出并且把 temperature 压低。如果你用的模型对 JSON mode 支持不好可以在 prompt 里加 few-shot 示例别指望模型自己稳定输出可解析的结构。我试过用高 temperature 让模型「发挥创意」生成任务结果验证器代码里一半是语法错误清洗成本比重新生成还高。另外如果你打算长期跑训练闭环建议看一下 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content它更适合这种持续调用、批量生成的场景比按次计费省心。接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content里面有完整的请求示例和错误码说明排障时对着看比瞎猜快。3. 可复制配置合成引擎与训练数据构造的 settings 片段这一节是整篇的核心我会给三份可直接落地的配置合成引擎的模型调用配置、任务与验证器的 JSON schema、以及训练数据构造的 TOML 片段。你不需要完全照抄但路径和字段名要对齐否则后面 OSWorld 验证阶段会接不上。先说合成引擎的模型调用配置。EvoCUA 论文里强调「生成即验证」也就是任务描述和可执行验证器要同步生成。我的做法是让模型一次输出一个 JSON 对象包含task_instruction、verifier_code、initial_state三个字段。下面是我实际在用的synthesizer_config.json{ base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model_id: your-verified-model-id, temperature: 0.2, max_tokens: 4096, response_format: { type: json_object }, system_prompt: You are a task synthesizer for Computer Use Agents. Generate a self-contained GUI task with an executable verifier. Output JSON only., task_schema: { task_instruction: string, natural language task for the agent, verifier_code: string, python code that returns True/False, initial_state: string, description of starting app state, atomic_skills: [click, type, scroll, drag] } }注意model_id我写的是占位符你要去模型对话页面确认实际可用的 ID 再填。api_key_env指向环境变量别直接写 Key。response_format用 JSON object 能大幅降低解析失败率但如果你的模型不支持就删掉这行在 system prompt 里加「Output valid JSON only, no markdown fences」。然后是训练数据构造的 TOML 片段。EvoCUA 的迭代进化学习分三阶段监督冷启动、拒绝采样微调、强化学习纠错。我在数据构造阶段用 TOML 管理每个阶段的采样比例和过滤阈值这样改参数不用动代码[data_construction] output_dir ./evocua_data trajectory_format sharegpt [cold_start] source synthetic_success_only max_samples 50000 min_verifier_pass_rate 0.95 [rejection_sampling] source mixed_success_failure success_ratio 0.7 failure_ratio 0.3 min_trajectory_length 5 max_trajectory_length 50 [preference_optimization] source failure_branching branch_point_detection first_divergence pair_construction chosen_rejected chosen_from successful_retry rejected_from original_failure这里的关键是branch_point_detection。论文里提到要分析失败轨迹的关键分叉点构建偏好对。我的实现方式是对每条失败轨迹找到第一个导致验证器返回 False 的动作然后从那个状态开始用模型重新采样若干次如果某次重采样最终成功就把「成功重采样轨迹」作为 chosen「原始失败轨迹」作为 rejected组成一个偏好对。这样失败经验就变成了监督信号而不是直接丢掉。如果你用 Cline MCP 或者 Claude Code 来辅助写合成脚本记得把 Base URL、Key、Model ID 三件套配全。Cline 的 MCP 配置里 Base URL 填https://taotoken.net/apiKey 填你创建的那个Model ID 填你验证过的。Claude Code 的接入类似Anthropic 兼容端点也在同一个文档里配置时别把 Base URL 写成带/v1的完整路径有些客户端会自动拼写重了会 404。4. 验证请求与成功结果在 OSWorld 里跑通一次闭环配置写完下一步是验证整条链路能不能跑通。我建议不要一上来就跑全量 OSWorld先用一个最小任务集验证「合成 → 交互 → 验证 → 记录」四个环节都正常。第一步验证合成引擎能产出可执行验证器。写一个test_synthesizer.py调用一次合成接口把返回的verifier_code写进临时文件然后用exec跑一遍看它能不能在给定初始状态下返回布尔值。如果验证器代码报SyntaxError或者NameError说明模型输出的代码不可执行需要回到 prompt 里加约束比如「verifier_code must only use standard library and predefined state dict」。第二步验证 OSWorld 环境能接收合成任务。OSWorld 的任务格式通常是 JSON包含instruction、setup、evaluator三部分。你要写一个 adapter把合成引擎输出的task_instruction映射到instruction把initial_state映射到setup把verifier_code包装成evaluator。下面是一个最小 adapter 示例import json def to_osworld_task(synth_task): return { instruction: synth_task[task_instruction], setup: synth_task[initial_state], evaluator: { type: python, code: synth_task[verifier_code] } } with open(synth_batch.jsonl) as f: tasks [to_osworld_task(json.loads(line)) for line in f] with open(osworld_tasks.json, w) as f: json.dump(tasks, f, indent2)第三步跑一次 OSWorld 验证。OSWorld 的启动命令通常是python run.py --task_file osworld_tasks.json --agent your_agent。你的 agent wrapper 里要调用模型做动作预测请求体里带上截图和任务指令。跑完后 OSWorld 会输出每个任务的成功与否你要把这些结果和合成时的任务 ID 关联起来存成trajectory_results.jsonl每行包含task_id、success、trajectory、verifier_output。成功结果长什么样如果你跑 10 个合成任务至少应该有 6 到 7 个能正常执行完并返回明确的 True/False而不是中途报环境错误。如果成功率低于 5 个先别急着调模型去检查验证器代码是不是太严格或者初始状态描述和 OSWorld 实际环境对不上。我踩过的坑是合成引擎生成的initial_state写的是「打开浏览器到某页面」但 OSWorld 沙箱里浏览器默认没启动导致任务一开始就失败。后来我在 adapter 里加了一个setup预处理步骤先确保基础应用处于可用状态。指标记录方式建议用 JSONL每行一个任务字段包括task_id、synthesized_at、verifier_pass、agent_success、steps、failure_branch。这样后面做拒绝采样时直接按agent_success过滤就行不用再解析轨迹文本。5. 本篇常见错排查401、local proxy failed 与 reading choices 报错跑 EvoCUA 闭环时报错基本集中在三类认证失败、网络代理问题、响应解析失败。我按真实遇到的顺序列一下。401 Unauthorized最常见的原因是 Key 没读到或者 Base URL 写错。检查TAOTOKEN_API_KEY环境变量是否在当前 shell 生效echo $TAOTOKEN_API_KEY看有没有值。如果用的是 Cline 或 Claude Code检查配置文件里的 Base URL 是不是https://taotoken.net/api别多写/v1。还有一种情况是 Key 创建后没复制全尾部少了几个字符重新去 API Keys 页面生成一个。local proxy failed这个报错通常出现在你本地配了代理但代理没启动或者代理规则把taotoken.net也拦了。EvoCUA 的合成引擎要跑几万个请求如果代理不稳定会大量超时。我的建议是合成和验证环节直连不要走本地代理如果你所在网络环境必须走代理确保代理规则里把 API 域名加白名单。注意这里说的代理是网络层代理不是模型代理别混淆。Error reading choices / reading choices failed这是响应解析阶段的报错说明模型返回的内容不是合法 JSON或者返回了 markdown 代码块包裹的 JSON。解决办法有两个一是在请求里加response_format: {type: json_object}二是在解析前做一次清洗把json 和去掉再json.loads。如果模型返回的是多个 JSON 对象拼接那说明 max_tokens 设太大或者 prompt 没约束好改成一次只生成一个任务。OAuth 相关报错如果你用 Claude Code 接入可能会遇到 OAuth token 过期。Claude Code 的 Anthropic 兼容配置在文档里有说明重新走一遍授权流程即可。注意别把 OAuth token 和 API Key 混用两者认证路径不同。验证器代码执行超时合成引擎生成的验证器如果包含死循环或者等待网络请求会在 OSWorld 里卡住。建议在 adapter 里给验证器加一个 5 秒超时超时直接判 False并记录verifier_timeout标记这些样本在拒绝采样阶段可以单独处理。排障时如果拿不准先去接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content对错误码再去 API Keys 页面确认 Key 状态。别在报错时反复重试同一个请求先定位是认证、网络还是解析问题再针对性修。6. 把闭环跑起来从一次验证到持续迭代到这一步你应该已经能用合成引擎产出任务、用 OSWorld 跑出成功和失败轨迹、并把结果存成结构化 JSONL 了。接下来要做的不是马上扩大规模而是先确认「失败轨迹能变成监督信号」这条路径是通的。具体做法从trajectory_results.jsonl里筛出agent_successfalse的样本对每条失败轨迹找到第一个验证器返回 False 的动作从那个状态开始用模型重新采样 3 到 5 次。如果某次重采样最终成功就把成功轨迹和原始失败轨迹组成偏好对写进preference_pairs.jsonl。然后用这些偏好对做一轮 DPO 或者拒绝采样微调再回到 OSWorld 验证。如果成功率有提升说明闭环有效可以逐步放大合成任务量和沙箱并发数。长期跑的话建议把 Coding Plan 用起来因为合成引擎和验证环节的调用量会持续增长按次计费在批量场景下不划算。模型对话入口可以用来快速验证某个模型 ID 是否可用接入文档用来查参数和错误码。整个流程里最耗时的不是训练而是合成任务的质量控制——验证器写得太松模型会学到错误行为写得太紧大量任务被判失败浪费算力。我的经验是先用小批量人工抽查 50 个合成任务确认验证器逻辑合理后再放量。最后提醒一点OSWorld 的成功率受环境影响很大同一套模型在不同沙箱配置下可能差好几个点。记录指标时一定要把环境版本、应用版本、屏幕分辨率一起存下来否则你没法判断提升是来自模型还是来自环境变化。