CLI-Universe 实战:为 Terminal Agents 构建可验证任务合成引擎的 config.toml 骨架

发布时间:2026/9/25 7:45:47
CLI-Universe 实战:为 Terminal Agents 构建可验证任务合成引擎的 config.toml 骨架 1. 为什么终端代理需要“可验证”的任务合成如果你正在做 Terminal Agents 的训练数据或评测集大概率遇到过这种尴尬让模型跑一条命令行任务它输出了看似合理的日志脚本也返回 0但目标状态根本没达成。CLI-Universe 这篇工作把问题说得很直白——现有合成流程大多是在“扩展任务来源”把代码库、文档、issue 直接改造成任务结果就是指令模糊、执行路径浅、测试脆弱学习信号很弱。CLI-Universe 的思路是“由内而外”先从能力分类法领域、技能类型、能力、工程支柱采样出任务锚点再用研究代理去真实技术材料里做证据驱动的深化最后把蓝图实例化成 Docker 环境经过基于量规的测试构建、基于提示的条件过滤和“失败-通过”检查端到端只保留约 33.6% 的候选。它用 6K 轨迹微调 Qwen3-32B在 Terminal-Bench 2.0 上拿到 33.4%超过了一批规模大一个数量级的开源模型。这套流程落到工程上最容易被忽略的一环是配置骨架任务合成引擎、执行器、校验器三者之间的契约必须写死在一个可复现的配置文件里否则“可验证”就只是口号。这篇就围绕config.toml骨架展开把任务合成→执行→校验的链路跑通同时用 TaoToken 的统一 Key/API 通道把模型调用收敛到一处避免每个子代理各配一套密钥。适合谁看需要批量生成可复现终端任务的开发者、在做 Agent 数据管线的同学、以及想把“失败-通过”这类可执行校验接进自己 CI 的人。下面所有配置都可以直接复制改路径使用。2. TaoToken 前置统一 Key 与 API 通道CLI-Universe 的流程里有多个角色分离的代理研究代理、测试代理、解决方案代理、无提示求解代理。如果每个代理都单独配一套模型供应商的密钥和 base_url配置会迅速失控而且复现时很难保证大家用的是同一条通道。我的做法是把它们全部指向 TaoToken 的统一入口用同一个 Key 管理。TaoToken 在这里扮演的是统一模型调用通道你拿到一个 Key就能通过兼容 OpenAI 风格的接口访问不同模型配置里只需要维护一个base_url和一个api_key环境变量。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 这个地址不加 UTM 参数直接写进配置。先做两件事。第一去控制台创建 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 写进环境变量不要硬编码进config.tomlexport TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你要确认某个模型名是否可用可以直接在模型对话页面试一条最小请求地址是 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。长期跑编码类或 Agent 类任务、调用量比较大的话可以看下 Coding Plan地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 它更适合这种多代理反复调用的场景。接入细节和参数说明在文档里地址是 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。注意config.toml里只写${TAOTOKEN_API_KEY}这种占位引用真正的密钥留在环境变量或密钥管理服务里。这样你把配置提交到仓库时不会泄露也方便在 CI 里注入。3. config.toml 骨架任务合成→执行→校验下面这份骨架对应 CLI-Universe 的三阶段蓝图构建、环境实现、测试构建与可执行过滤。我把它拆成[engine]、[model]、[synthesis]、[environment]、[verification]、[tasks]六块每块都对应流程里的一个可验证动作。# config.toml —— CLI-Universe 风格任务合成引擎骨架 [engine] name cli-universe-lite workdir ./runs seed 20240601 # 端到端留存率参考值仅用于统计不强制 target_keep_ratio 0.336 [model] # 统一走 TaoToken 通道所有子代理共用 base_url https://taotoken.net/api api_key ${TAOTOKEN_API_KEY} # 研究/测试/解决方案代理可分别指定模型 research_model claude-sonnet-4-5 test_model gpt-4.1 solution_model claude-sonnet-4-5 solver_model qwen3-32b timeout_seconds 120 max_retries 3 [synthesis] # 阶段一任务蓝图构建 domains [software_engineering, system_administration, data_processing] skill_types [algorithmic, configuration, shell_scripting] capabilities [exploration, error_recovery, long_horizon_planning] pillars [new_feature, debugging, devops] # 每个锚点采样的候选数 candidates_per_anchor 4 # 基于证据的深化研究代理最多迭代轮数 research_max_rounds 8 # 蓝图量规审查阈值0-1 blueprint_accept_threshold 0.85 [environment] # 阶段二环境实现 base_image ubuntu:22.04 pin_versions true smoke_test true smoke_timeout_seconds 60 # 资产物化策略fetch 优先失败则 synthesize asset_strategy fetch_then_synthesize [verification] # 阶段三测试构建与可执行过滤 build_tests true test_rubric [correctness, determinism, edge_coverage] # 基于提示的条件过滤无提示必须失败有提示必须成功 prompt_conditioned_filter true # 失败-通过检查初始环境失败执行解决方案后通过 fail_to_pass true # 测试在初始环境上的期望退出码 expected_initial_exit_code 1 expected_final_exit_code 0 [tasks] # 任务清单每条对应一个可验证链路 [[tasks.items]] id task-001 domain software_engineering skill_type algorithmic capability error_recovery pillar debugging query 修复 /app/parser.py 中处理嵌套括号时的栈溢出并保证 tests/ 全部通过 internal_hint 问题出在递归深度未设上限改用显式栈即可 test_cmd pytest tests/ -q solution_cmd python -m patch_parser [[tasks.items]] id task-002 domain system_administration skill_type configuration capability exploration pillar devops query 让 /etc/nginx/nginx.conf 支持 8080 端口并重载服务curl 返回 200 internal_hint server 块里 listen 指令需要新增一行 test_cmd curl -s -o /dev/null -w %{http_code} http://localhost:8080 solution_cmd nginx -s reload几个关键点解释一下。[model]里所有子代理共用base_url和api_key这是把多代理调用收敛到 TaoToken 通道的核心不同角色可以指定不同模型比如研究代理用长上下文模型求解代理用便宜的小模型。[verification]里的prompt_conditioned_filter和fail_to_pass对应论文里的两个过滤动作前者保证任务不是“随便就能解”后者保证任务实现了从“未解决”到“已验证”的状态转换。[tasks.items]里每条任务都带test_cmd和solution_cmd这就是可验证性的落点——没有可执行命令的任务不进清单。4. 跑通一条可验证链路合成→执行→校验配置写好后用一个最小 Python 驱动把链路串起来。它做三件事读config.toml、对每条任务调用模型生成/执行、跑失败-通过校验。下面这段可以直接存成run_engine.py。import os import subprocess import tomllib from openai import OpenAI with open(config.toml, rb) as f: cfg tomllib.load(f) client OpenAI( base_urlcfg[model][base_url], api_keyos.environ[TAOTOKEN_API_KEY], ) def call_model(model: str, prompt: str) - str: resp client.chat.completions.create( modelmodel, messages[{role: user, content: prompt}], timeoutcfg[model][timeout_seconds], ) return resp.choices[0].message.content def run_cmd(cmd: str, timeout: int 60): proc subprocess.run( cmd, shellTrue, capture_outputTrue, textTrue, timeouttimeout ) return proc.returncode, proc.stdout, proc.stderr def verify_task(task: dict) - dict: # 1) 初始环境上测试必须失败 code0, _, _ run_cmd(task[test_cmd]) # 2) 无提示求解必须失败 no_hint call_model(cfg[model][solver_model], task[query]) # 3) 有提示求解必须成功 with_hint call_model( cfg[model][solution_model], f{task[query]}\n内部提示{task[internal_hint]}, ) # 4) 执行解决方案后测试必须通过 run_cmd(task[solution_cmd]) code1, out1, _ run_cmd(task[test_cmd]) return { id: task[id], initial_failed: code0 ! 0, no_hint_failed: bool(no_hint), with_hint_ok: bool(with_hint), final_passed: code1 0, final_output: out1.strip()[:120], } for task in cfg[tasks][items]: result verify_task(task) print(result)跑之前确认环境里有openai和tomllibPython 3.11 自带。执行pip install openai python run_engine.py预期输出类似{id: task-001, initial_failed: True, no_hint_failed: True, with_hint_ok: True, final_passed: True, final_output: 5 passed in 0.42s} {id: task-002, initial_failed: True, no_hint_failed: True, with_hint_ok: True, final_passed: True, final_output: 200}四个布尔值全为True这条任务才算通过可执行过滤。initial_failed对应“失败-通过”里的失败侧final_passed对应通过侧no_hint_failed和with_hint_ok对应基于提示的条件过滤。任何一项为False这条任务就应该被丢弃而不是硬塞进训练集——这正是 CLI-Universe 端到端只留 33.6% 的原因。如果你想把合成阶段也接上可以在verify_task之前加一步用research_model根据[synthesis]里的维度采样生成候选任务再让test_model按test_rubric生成测试套件。测试套件生成后同样要过一遍上面的校验不通过就回炉。5. 本篇常见错排查报错一tomllib.TOMLDecodeError或读取不到[tasks.items]。多半是 TOML 里数组表写法不对。[[tasks.items]]是数组表每条任务一个块不能写成[tasks.items]再塞多个id。另外api_key ${TAOTOKEN_API_KEY}在 TOML 里是普通字符串不会自动展开展开逻辑在 Python 侧做别指望 TOML 自己替换。报错二openai.AuthenticationError401。检查TAOTOKEN_API_KEY是否真的导出到了当前 shellecho $TAOTOKEN_API_KEY确认一下。如果是在 CI 里跑注意环境变量注入的时机要在python run_engine.py之前。base_url 必须是https://taotoken.net/api不要带多余路径。报错三initial_failed为False。说明测试在初始环境上就通过了这条任务是“空洞任务”没有状态转换。常见原因是测试命令写得太宽松比如只检查文件存在而不检查内容。把test_cmd改成能真正区分“未解决”和“已解决”的命令比如从ls /app/out改成python check_output.py。报错四final_passed为False但模型说“已完成”。这是论文里“弱验证/过早终止”的典型表现。模型执行了命令、输出了合理日志但目标状态没达成。解决办法是让test_cmd直接检查目标状态而不是检查命令退出码。比如任务要求生成 CSV就断言 CSV 的行数和列名而不是只看python gen.py返回 0。报错五subprocess.TimeoutExpired。终端任务里有些命令会挂起比如等待交互输入或网络超时。给run_cmd加timeout参数上面代码里已经加了并在config.toml的[environment]里把smoke_timeout_seconds调小让挂起的任务尽早被丢弃而不是拖垮整条流水线。报错六模型名 404。不同通道支持的模型名不一样先在模型对话页面确认你要用的模型名可用再写进config.toml。如果某个角色模型不可用先换成确认可用的模型跑通链路再逐个替换。6. 把可验证链路接进你的工作流跑通上面这条链路后你可以把它接进 CI每次提交config.toml和任务清单CI 里跑python run_engine.py只有全部任务四项校验通过才允许合并。这样任务集的质量就有了可执行的守门人而不是靠人工抽查。如果后面要批量扩任务建议把[synthesis]的采样和[verification]的过滤做成两个独立阶段中间产物落盘成 JSON方便复现和审计。模型调用继续走 TaoToken 的统一通道Key 和 base_url 只维护一份换模型时只改config.toml里的模型名不用动代码。需要看接入参数就去文档页 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 要管理多个 Key 就去 API Keys 页 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 长期跑 Agent 任务可以看 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。先把task-001这条跑通再往里加任务比一上来铺大摊子稳得多。