最近半年一直在被赛马,搞Harness,从记忆到上下文治理到各种自进化卷到飞起,趁着今天台风"白海豚"过境,偷得半日清静,正好输出点东西;
想写自进化,但自进化的盘子又很大,prompt自进化、harness自进化、知识/skill自进化、模型自进化...
还是先限定在 skill 自进化上吧,skill 自进化这几个月可太火了,论文一搜一大把,各个都宣称可以大幅提高效果,但实践下来还是 SkillOpt 比较靠谱,目前已经上线持续运行,下面就说说 SkillOpt 吧;
1. 是什么
SkillOpt 用模型推理,模拟了深度学习的整个优化循环:Skill 文档做权重,跑对话做前向传播,分析失败做反向传播,编辑 Skill 做梯度下降,Gate做验证集,全程不碰模型参数,只改Skill文本;
更详细的讲解可以直接看代码和论文:
- 论文:https://arxiv.org/abs/2605.23904
- github repo:微软 https://github.com/microsoft/SkillOpt
下面开始只说重点;
2. 核心类比
首先整理了一个对照表格,感觉可以比较直观的用深度学习来对SkillOpt进行类比:
| 深度学习 | SkillOpt 对应 |
|---|---|
| 模型权重 | Skill 文档(.md 文件) |
| 前向传播 | Rollout(LLM 执行 Skill 跑对话) |
| Loss | hard accuracy(失败率) |
| 梯度 | Reflect 生成的 patch(编辑建议) |
| 学习率 | edit_budget(每步最多改几条) |
| 梯度裁剪 | Select(LLM 排名,保留 top-L edits) |
| optimizer.step() | Update(把 edit 应用到 Skill 文档) |
| 验证集 | Gate(在 val 集评估,accept/reject) |
| 动量 | Slow Update(epoch 级纵向对比) |
| optimizer 记忆 | Meta Skill(跨 epoch 优化器经验) |
| Checkpoint | skill_v{step:04d}.md |
| Minibatch SGD | minibatch_size 条轨迹一组分析 |
| 梯度累积 | accumulation 个 batch 合并后更新 |
3. 训练过程
3.1 层级
plain
训练全程(total_steps = num_epochs × steps_per_epoch)
└── Epoch 1
│ ├── Step 1 ← 一次完整的 6-stage 循环
│ ├── Step 2
│ └── ...
│ ─── epoch 结束:Slow Update + Meta Skill ───
└── Epoch 2
├── Step N+1
└── ...
核心公式:
plain
steps_per_epoch = ceil(train_size / (batch_size × accumulation))
accumulation=1(默认):一个 step = 一个 batchaccumulation>1:一个 step = N 个 batch 的 patch 合并后再 update 一次,信号更稳
3.2 Stage
每个 step 固定按顺序跑 6 个stage:
3.2.1 Rollout(前向传播)
python
rollout_results = adapter.rollout(train_env, current_skill, rollout_dir)
- 把当前 Skill 注入 prompt,用 target LLM 跑对话
- 每条对话输出:
{"hard": 0/1, "soft": 0.0~1.0, "fail_reason": "..."} - 对话轨迹保存到
predictions/{item_id}/conversation.json
hard vs soft:
hard=1:回复满足所有硬性约束(不暴露隐私、不承诺不确定信息等)soft:细粒度质量分(0~1),表达流畅度、解决完整度
3.2.2 Reflect(反向传播)
python
raw_patches = adapter.reflect(rollout_results, current_skill, ...)
- 按
minibatch_size条分组 - 每组并发调用 optimizer LLM 分析
- 输出:
{"edits": [{"op": "append/replace/delete/insert_after", "content": "...", "target": "..."}]}
3.2.3 Aggregate(梯度聚合)
多个 minibatch 各自产出 patch 进行聚合:
plain
8 个 patch → 分组(merge_batch_size 个一组)→ 并发 LLM merge 调用→ 层次化再 merge → 最终一个 merged_patch
3.2.4 Select(梯度裁剪)
把所有 edit 发给 optimizer,按重要性选 top-K 个
python
ranked_patch = rank_and_select(current_skill, merged_patch, max_edits=edit_budget)
3.2.5 Update(optimizer.step)
apply_patch_with_report 把 edit 逐条应用到 Skill 文档:
| op | 行为 |
|---|---|
append |
在文档末尾追加 |
insert_after |
在 target 文本后插入 |
replace |
替换第一处 target 文本 |
delete |
删除第一处 target 文本 |
3.2.6 Evaluate(Gate)
gate 卡控
python
gate = evaluate_gate(candidate_skill, cand_hard, current_skill, current_score, ...)
纯函数,非常简单直接:
plain
candidate_hard > current_score?
└── YES → accept(更新 current)
└── 同时 > best_score? → accept_new_best(更新 best)
└── NO → reject(current 不变,rejected edits 写入 step_buffer)
4. 三个有趣的 Epoch 层级的机制
上面的 6个 stage 的 step 循环,解决了 "这一批对话失败了怎么改",以下三个机制解决更高层次的问题;
4.1 Step Buffer(epoch 内短期记忆)
解决:同一 epoch 内,optimizer 反复提已被 reject 过的编辑
- 每步结束把
{failure_patterns, rejected_edits}加入 buffer - 下一步 Reflect 时注入 prompt:"上几步试过这些,没用,别再提了"
4.2 Slow Update(动量)
解决:step 级 gate 只看单步进退,发现不了"改 A 让 B 退步"的隐性退化;
epoch 结束时,基于这一轮和上一轮结果,打标签 "两轮都成功、两轮都失败、上轮成功这轮失败、上轮失败这轮成功",供 optimizer 进行分析
4.3 Meta Skill(optimizer 的跨 epoch 记忆)
解决:optimizer 自己在不同 epoch 间反复犯同样的错误;
- epoch 结束时,optimizer 回顾"自己这一轮的操作方向",生成经验摘要
- 下一 epoch 的每次 Reflect/Aggregate 都会读到这段经验
5. 写在最后
上面这一套 把skill文档当做可优化对象、模型自己跑对话、自己看失败、自己改文档、再用gata卡控 闭环流程,目前跑下来最大的感受就是俩字 "可控" ;
比起那些优化模型、把prompt嵌入向量空间的 "隐式梯度更新" 让人放心太多了,也是现阶段比较推荐的方式。