拿 TaoToken Key 接 SkillOpt 优化器模型,轨迹打分后再编辑。
2026/9/18 14:42:55 网站建设 项目流程

1. 先把账单算清楚:烧 Token 的不是目标模型,而是优化器与评审

给 AI Agent 写 skill 早已不是新鲜事:一段自然语言说明书,告诉模型某类任务该怎么做,人读得懂、改起来也方便。真正棘手的是"怎么改"。手写靠经验,让强模型一次性生成靠运气,让 Agent 反复自我修改则几乎没有可控性——改到第五轮,技能文档可能比第一轮还差,而且没人能指出是哪一步把它带偏了。

SkillOpt 把这件事重新定义了一遍:目标 Agent 完全冻结,模型权重一个都不动,被视为"可训练状态"的是那份技能文档本身。它借用了神经网络训练里那套熟悉纪律——epoch、batch size、学习率、验证集门禁——只不过"梯度"变成了自然语言的增删改,"优化器"换成了一个独立的大模型。默认论文路径下,一次候选编辑只有在留出的验证集上把分数严格抬高,才会被写入技能文档;没通过就进拒绝缓冲区,等下一轮再议。

这个设计对复现者有非常直接的后果:你的 API 账单几乎全部压在两个角色上——把 rollout 转成有界编辑的优化器模型,以及给轨迹打分的评审模型。被冻结的目标模型反而花不了多少,因为它每一轮跑的都是同一份技能、同一套 prompt。所以想跑通 SkillOpt,第一件事不是调参,而是给这两个模型找一个稳定、可编程、Base URL 固定的入口。我这次用的是 TaoToken(https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=skillopt_intro),OpenAI 兼容接口,后面所有配置都围绕https://taotoken.net/api这个 Base URL 展开。

本文不讨论论文结论,只解决一件事:从零把 SkillOpt 的优化器链路接起来,准备轨迹、跑反思聚合、最后打开best_skill.md看编辑结果。中间涉及 Claude Code、Codex、CC Switch 三套客户端的写法,我会分别给配置,不要互相套用。

2. 环境落地:pip 装完之后,先把 Key 和 Base URL 固化下来

SkillOpt 已经发布在 PyPI 上,安装本身没什么坑。建议用独立虚拟环境,避免和你机器上已有的 torch / openai SDK 版本打架。

# 建议 Python 3.10+,先建隔离环境 python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate python -m pip install -U pip pip install skillopt # 需要 WebUI 监控面板时再装可选依赖 pip install -e ".[webui]"

装完之后先别急着跑训练,第一步是确认 CLI 可用并看清子命令,因为不同小版本的子命令命名会有差异,以本机输出为准:

skillopt --help

接下来是凭据。SkillOpt 支持多种后端(OpenAI 兼容、Azure、Claude、Qwen、MiniMax 等),但它们的共同点是都需要一个 base_url 和一个 api_key。这两样东西建议只在一个地方维护:项目根目录的.env(记得写进.gitignore)。

# .env —— 只放凭据,不要提交到仓库 OPTIMIZER_API_KEY=YOUR_API_KEY OPTIMIZER_BASE_URL=https://taotoken.net/api JUDGE_API_KEY=YOUR_API_KEY JUDGE_BASE_URL=https://taotoken.net/api

Key 从哪里来?去 TaoToken 官网(https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=skillopt_env)注册并登录,在控制台里创建,创建时挑一个你容易识别的名字,比如skillopt-optimizer。这里有个习惯值得养成:优化器和评审用两把不同的 Key。原因很实在——优化器是长上下文、低频次、贵;评审是短上下文、高频次、便宜。分开之后,前面做成本分析、后面做限额控制,都不会串。

拿到 Key 后,别写死在 YAML 里。用环境变量注入,配置文件只引用变量名,这样换 Key 不用改代码,也不容易把密钥误传到版本库。

# 本地校验一下变量是否生效 python - <<'PY' import os print("base_url =", os.getenv("OPTIMIZER_BASE_URL")) print("key set =", bool(os.getenv("OPTIMIZER_API_KEY"))) PY

输出里 key 只打印布尔值,不要 echo 完整明文,这是最小化的安全习惯。

3. 把优化器后端指向 https://taotoken.net/api:配置文件怎么写

SkillOpt 的配置体系以仓库 docs 为准,字段名在不同版本间可能有调整,但结构是稳定的:一个 provider 块描述"怎么连",一个 model 块描述"用哪个模型",再加一组训练超参。下面是一份结构对照示例,你在自己仓库的示例配置上照着改即可。

# configs/optimizer.yaml(结构示意,字段名请对照本机 docs) optimizer: provider: openai # OpenAI 兼容协议 base_url: https://taotoken.net/api api_key: ${OPTIMIZER_API_KEY} model: <optimizer-model-id> # 优化器:推理强、上下文长 temperature: 0.2 max_tokens: 4096 judge: provider: openai base_url: https://taotoken.net/api api_key: ${JUDGE_API_KEY} model: <judge-model-id> # 评审:快、便宜、输出稳定 temperature: 0.0 train: epochs: 3 batch_size: 8 edit_budget: 3 # 文本版"学习率",单轮允许的有界编辑条数 validation_gate: true # 论文默认路径:验证集不涨就丢弃 reject_buffer: true # 保留被拒编辑,供后续聚合参考 task: target_model: <frozen-model-id> # 被冻结的目标模型,只跑不改 env: chat # chat / codex-cli / claude-code-cli

几个容易踩的点:

第一,base_url不要带多余的路径后缀。统一写https://taotoken.net/api,客户端或 SDK 通常会自己补/v1。如果你手动加了/v1,再叠一层就会变成/v1/v1/chat/completions,典型的 404 来源。

第二,model字段用占位符别乱填。填一个后端不认识的模型名,报错通常不是 404 而是 400 或 403,很容易被误判成 Key 问题。先去模型列表页确认可用 ID,再粘回来。

第三,优化器和评审的模型不要选同一个。优化器要写 diff、要理解轨迹里的失败原因,需要长上下文和较强的指令遵循;评审只需要按 rubric 打分,选便宜快速的即可。把这两个角色拆开,是 SkillOpt 复现里性价比最高的一条实践。

如果你更喜欢用 Python 直接调,也可以在脚本里显式构造两个客户端,而不是走 YAML:

import os from openai import OpenAI optimizer = OpenAI( base_url="https://taotoken.net/api", api_key=os.environ["OPTIMIZER_API_KEY"], ) judge = OpenAI( base_url="https://taotoken.net/api", api_key=os.environ["JUDGE_API_KEY"], ) # 冒烟测试:确认优化器链路通 resp = optimizer.chat.completions.create( model="<optimizer-model-id>", messages=[{"role": "user", "content": "只回一个词:ok"}], ) print(resp.choices[0].message.content)

这一步过了,说明网络、Key、Base URL、模型 ID 四件套都没问题,再往下接轨迹才有意义。

4. Claude Code 与 Codex 的配置要分开写,别把 ANTHROPIC_ 变量塞给 Codex

SkillOpt 的评测环境包含直接对话、Codex CLI、Claude Code CLI 三类。很多人复现时会顺手用 Claude Code 或 Codex 去做轨迹采集,这时候两者的配置写法完全不一样,混用是最常见的翻车点。

Claude Code走的是settings.json+ANTHROPIC_*变量:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "<your-model-id>" } }

注意ANTHROPIC_AUTH_TOKENANTHROPIC_API_KEY在不同版本里行为有差异,以你本地 Claude Code 版本的说明为准;改了settings.json后要重启会话,环境变量不会热加载。

Codex走的是config.toml,用的是model_providers自定义 provider,绝不能把上面那三个ANTHROPIC_*变量搬过来:

# ~/.codex/config.toml model = "<your-model-id>" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY" wire_api = "chat"

对应的环境变量在启动 Codex 的 shell 里导出:

export TAOTOKEN_API_KEY=YOUR_API_KEY

两套配置的差异本质上是协议差异:Claude Code 说的是 Anthropic 的消息协议,Codex 走的是 OpenAI 兼容的 chat 协议。把ANTHROPIC_BASE_URL写进config.toml,Codex 根本不认这个字段;反过来把env_key思路搬到settings.json,Claude Code 也读不到。所以配置完一定要各跑一次最小请求,别等到跑训练时报了一堆 401 才回头查。

CC Switch 三件套指的是它管理的三样东西:provider 列表、当前激活项、以及每个 provider 的base_url+api_key。用 CC Switch 的好处是你可以在"Claude Code 用 A 配置、Codex 用 B 配置"之间一键切换,而不用手动改文件。但要注意两点:其一,切换只影响它管辖的文件,不会自动改写你.env里的OPTIMIZER_*;其二,SkillOpt 自己读的是 YAML / 环境变量,跟 CC Switch 的激活项是两套体系。建议做法是:CC Switch 只管交互式客户端的日常切换,SkillOpt 的训练配置走独立.env,互不干扰。

5. 准备轨迹:JSONL 的字段、打分口径与常见脏数据

SkillOpt 的输入是 rollout,也就是"目标模型跑某条任务时的完整过程 + 一个分数"。这一步做不干净,后面优化器再强也是在拟合噪声。

推荐用 JSONL,一行一条,至少包含任务标识、模型输出、以及一个可比较的标量分数:

{"task_id": "t-0001", "env": "chat", "prompt": "把这份 CSV 里的空值补成 0 并输出新文件", "trajectory": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}], "score": 0.0} {"task_id": "t-0002", "env": "chat", "prompt": "解释这段正则为什么贪婪匹配", "trajectory": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}], "score": 1.0}

如果分数还没算,用评审模型批量打。评审的 prompt 要固定 rubric,别每次换说法,否则分数不可比:

RUBRIC = """你是严格的评分员。只输出一个 0 到 1 之间的小数,不要任何解释。 评分标准: 1.0 = 完全满足任务要求,无事实错误 0.5 = 方向正确但有遗漏或小错 0.0 = 未完成或存在关键错误 """ def score_one(judge, task, trajectory_text): resp = judge.chat.completions.create( model="<judge-model-id>", temperature=0.0, messages=[ {"role": "system", "content": RUBRIC}, {"role": "user", "content": f"任务:{task}\n轨迹:{trajectory_text}"}, ], ) return float(resp.choices[0].message.content.strip())

准备轨迹时优先排查三类脏数据:

  • 分数全一样。全 1.0 或全 0.0 会让验证门失去意义,任何编辑都不能"严格提升",训练会一动不动。先检查 rubric 是否太松或太严。
  • 分数靠长度。如果你的评审潜规则里"写得长 = 写得好",优化器很快会学会把技能文档灌水,产出直奔 2000 token 上限却没什么信息量。用固定长度区间约束输出,或者显式在 rubric 里说明长度不加分。
  • 任务和技能不匹配。技能文档是"某类任务怎么做"的说明书,如果轨迹里的任务跨了三个领域,优化器写出的编辑会互相冲突,最后得到一份四不像。宁可先把任务收窄到一个领域。

分完之后,别忘了留出一份 held-out validation。这部分不能进训练批次,否则验证门就形同虚设。

6. 反思 → 聚合 → 验证门:跑起来之后看什么

配置和轨迹都就位后,就可以跑完整循环了。命令形态以本机--help为准,典型调用如下:

# 先用小样本冒烟,确认链路通、消耗正常 skillopt train --config configs/optimizer.yaml --limit 16 --epochs 1 # 冒烟通过后再放全量 skillopt train --config configs/optimizer.yaml

一轮 epoch 里会发生这些事:目标模型在冻结状态下跑 rollout;评审模型给每条轨迹打分;优化器读"高分轨迹 + 低分轨迹 + 当前技能文档",产出若干条有界编辑(增加 / 删除 / 替换);这些编辑在验证集上评估,只有分数严格提升的才被采纳;被拒的进缓冲区,供后面的聚合阶段参考。每个 epoch 结束还会做一次慢速的元更新。

跑的过程中重点关注这几个信号:

一是采纳率。如果连续几个 epoch 采纳率是 0,先别怀疑优化器能力,去看编辑预算是不是设得太宽。edit_budget太大时,优化器倾向于一次改很多,候选编辑几乎必然在验证集上掉分;调小到 1~3,反而是更稳的起点。

二是被拒编辑的内容。拒绝缓冲区是最好的调试材料。如果被拒的都是同一类修改(比如都在试图往技能里加"如果失败就重试三次"),说明你的验证集对该场景覆盖不足,或者 rubric 的反馈信号太弱。

三是 Token 消耗曲线。优化器每轮要吃下多条轨迹,输入长度随 batch_size 线性增长。如果发现某轮消耗突然翻倍,通常是轨迹里混进了超长输出。给轨迹文本设一个截断上限,超长的先降采样,不要直接喂。

跑完之后,产出是一份紧凑的best_skill.md,一般几百到两千个 token 量级,可以直接配合原封不动的目标模型使用,部署时不增加任何额外推理调用。

7. 打开 best_skill.md 之后,先做这三项检查

很多人跑完训练就结束了,其实最有价值的一步在这里。打开best_skill.md,按顺序看三件事:

# 1. 看它到底改了什么 git diff --no-index skills/skill.md skills/best_skill.md # 2. 量一下体量,别让它悄悄膨胀 wc -c skills/best_skill.md # 字符数 python -c "print(len(open('skills/best_skill.md',encoding='utf-8').read()))" # 3. 扫一遍有没有过拟合痕迹 grep -nE "t-00|task_id|样例|例如输入" skills/best_skill.md

第一项,看编辑是否"有界且可解释"。好的编辑通常是替换某个模糊表述、补充一条判定条件、删掉一条和当前任务无关的步骤。如果你看到整段重写,或者技能文档里出现了具体任务 ID、具体输入样例,那多半是过拟合到验证集了——技能文档本应描述"这类任务怎么做",而不是记住"这个任务答案是什么"。

第二项,看体量。技能文档膨胀的直接成本是每次调用目标模型都要多读这些 token,收益却不随长度增长。如果从 400 token 涨到 1800 token 而验证集分数只动了很小一点,考虑回到更早的 epoch 取版本。

第三项,做一次迁移验证。这是 SkillOpt 比较值得关注的地方:优化出的技能文档可以在不改权重的前提下,跨模型规模、跨执行环境复用。所以别只看训练环境里的分数,把同一份best_skill.md拿到另一个目标模型上、或者从直接对话换到 CLI 环境里跑一遍。如果分数掉得很少,说明这份技能学到的是通用方法;如果掉得厉害,说明它只是针对特定 prompt 形态做了局部适配。

顺带一提,新版本里还带了skillopt-sleep这条命令行,对应一个离线自进化机制:在你不用的时候回顾历史会话、重放常见任务,把通过验证的编辑沉淀下来。它不是必须的,但对长期挂着 Agent 的团队来说,是个把"经验"固化下来的低成本方式。

8. 常见报错与排查路径:从 401 到验证门不生效

复现过程中最耗时间的往往不是算法,而是配置。下面这张对照表按症状组织,基本覆盖了新手会遇到的绝大多数情况。

症状高频原因处理方式
401 / invalid api keyKey 未导出到当前 shell,或引用了.env但进程没加载在启动进程的同一个 shell 里echo $OPTIMIZER_API_KEY确认非空;.env需要显式加载
404 / not foundbase_url写成了https://taotoken.net/api/v1,路径重复统一改回https://taotoken.net/api
400 / model not found模型 ID 拼错或该 ID 在这个 Key 下不可用去控制台核对模型 ID,再回填配置
429 / 超时并发打分太多,或轨迹过长给评审打分加并发上限;轨迹文本设截断阈值并重试
验证门永远不通过rubric 太严格导致分数分布极窄;edit_budget过大先把edit_budget降到 1,并检查训练集分数是否有区分度
best_skill.md为空没有编辑通过验证;或输出路径没权限查拒绝缓冲区日志;确认输出目录可写
Codex 报未知字段ANTHROPIC_*写进了config.tomlCodex 只用model_providers+env_key,重写配置
Claude Code 改完配置不生效settings.json需要重启会话退出并重新启动 Claude Code

再补一条经验:先在最小样本上跑通,再放全量。用--limit 16 --epochs 1走一轮,能覆盖"取 Key → 配 Base URL → 准备轨迹 → 评审打分 → 优化器产编辑 → 验证门判定 → 落盘 best_skill.md"整条链路。这一轮成本很低,但能提前暴露 90% 的配置问题。很多人一上来就跑全量,结果在第三个小时才发现 Key 一直是错的。

9. 把 Token 花在刀刃上的几条实践

复盘一下 SkillOpt 复现里的成本结构:目标模型冻结,成本固定且可控;真正会失控的是优化器和评审。几个可以直接落地的做法:

拆分 Key 与限额。优化器和评审用两把 Key,各自设限额。优化器的调用次数少但每次很贵,评审的调用次数多但每次便宜,混在一起做成本归因时你会分不清钱花在哪。

优化器用长上下文强模型,评审用快模型。评审只需要输出一个 0~1 的分数,用最贵的模型纯属浪费;而优化器要读懂失败原因并写出可解释的 diff,能力不足会直接表现为采纳率为零。

给轨迹和技能文档都设长度上限。轨迹超长会导致优化器输入爆炸,技能文档超长会导致部署期成本上涨。两道闸门都加上。

按 epoch 保存快照。不要只留最终的best_skill.md。如果最后一轮过拟合,你还能回退到中间版本;而且对比多个 epoch 的 diff,是判断"编辑方向是否稳定"的最直接方式。

固定 Base URL,减少环境变量漂移。训练脚本、Claude Code、Codex、CC Switch 全指向https://taotoken.net/api,只让 Key 和模型 ID 变化。环境越统一,排查越快。

到这里,SkillOpt 的优化器链路就算接完了:轨迹准备、反思聚合、验证门筛选、best_skill.md检查,每一步都能独立验证。接下来就是选模型和压成本的细活了——如果你还没开始,可以先在模型对话里试一轮优化器与评审的推理效果,确认模型选型;需要长期挂机跑 epoch 的话,Coding Plan 会比按量调用更省心;凭据则统一在控制台创建,优化器与评审各一把。

  • 先试模型效果:https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=skillopt_chat
  • 长期跑训练看套餐:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=skillopt_plan
  • 创建优化器 / 评审两把 Key:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=skillopt_keys
  • Claude Code 接入细节:https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=skillopt_ccdoc

配置就绪后,建议先跑一轮 16 条样本的冒烟训练,确认best_skill.md真的被写出且有非空 diff,再放全量。这一步花不了多少 Token,但能帮你省下后面几个小时的无谓排查。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询