资料范围。本文固定在仓库的一个公开源码快照上阅读。链接到文件或函数的结论属于“已验证源码”;从多个可见约束推导出的判断会明确写成“工程推论”;性能数字只复述项目 README 与技术报告,本文没有重跑基准。

阅读目标。我们会一直跟着一个形状级例子:SpreadsheetBench 的一批任务里,多个 Agent 都在写回工作簿时破坏公式或选错 sheet。这个例子来自优化 prompt 明示的 failure buckets,但不虚构项目未公开的具体样本计数。读完后,你应该能回答:谁触发优化、它读取哪些文件、允许改什么、哪次跑分决定保留,以及结果何时才可以部署。

Question 01到底是谁在学习?

模型参数保持冻结,变化落在 skill.md 或受限的 harness 文件上。

Question 02失败怎样变成改动?

轨迹先文件化,再跨样本找共性,并用 passed 轨迹反证。

Question 03谁决定接受改动?

优化 Agent 只生产 candidate;validation 的分数和阈值决定保留还是回滚。

Question 04公开实现走通了吗?

控制逻辑清楚,但当前 HEAD 的脚本、数据口径和 HarnessOpt 命令仍有断点。

一、先把“自进化”翻译成一轮可以重跑的修改

最容易误读的地方,是把 SkillOpt-Lite 想成一种在线微调。它没有计算梯度,也不改模型参数。更准确的说法是:自然语言 skill 是待修改的程序,Coding Agent 生成补丁,evaluator 用跑分决定补丁是否留下。模型 M 和 harness H 在一次 skill 优化实验里保持不变,真正被搜索的是文本工件 skill.md。

技术报告把目标写成在任务分布上最大化 H(M, z, s) 的奖励,其中 s 是 skill 文本。由于文本空间离散、harness 和环境不可微,项目不去近似数值梯度,而是利用 rollout 里已经可读的错误、工具调用和执行轨迹。于是优化从“盲试一个方向”变成“像调试程序一样读失败,再写出一个更好的说明文件”。这就是报告所说的 language-mediated program compilation 在 Lite 版里的具体含义。

1.1 五个参与者分别保存什么、能改什么

参与者读取或保存什么允许做什么不能做什么
目标模型 M本轮输入与生成轨迹按当前 skill 完成任务不会自动改写自己的 weights
Harness H工具、循环、超时、环境执行把任务跑成可评分结果在 SkillOpt-Lite 轮次里默认不改自身
skill.md可复用的领域规则与操作范式被小补丁改写、快照和回滚不证明改动有效
Coding Agent当前 skill、失败/成功轨迹、源码工具诊断共性并生成 candidate不能自己宣布 candidate 是 best
Evaluator / gatesplit、评分、current/best 记录接受、拒绝、恢复与最终报告不负责提出补丁内容

1.2 真正的 trainer 是一份 prompt 文件

在 Lite 路径里,训练循环不是由一个新的优化器服务常驻执行,而是由 Coding Agent 读取并执行 skillopt-loop.prompt.md。README 也明确要求:把仓库放进能读 prompt 文件的 Coding Agent,命令要发在 Agent chat 里,而不是普通 shell。换句话说,文件系统不仅保存数据,也保存优化器的控制程序。

这带来一个很实际的优点:循环策略可读、可 diff、可按 benchmark 调整。代价也同样直接:prompt 对工作目录、宿主工具、长命令恢复和文件约定非常敏感;文字里的一处路径错误就可能让“算法”在执行前停住。

二、一轮优化到底发生什么

现在跟着那批 spreadsheet 任务走一轮。前台产品请求并不会自动触发进化;用户先显式调用 slash command,优化才作为一段离线/维护工作开始。它看到的是固定的当前 skill 和本轮 train rollout,不应该读取 val/test 的任务内容来写补丁。

latest train samples→snapshot→diagnose→small patch→val gate→next train

2.1 从 snapshot 到下一批样本

阶段输入快照写入推进条件
基线初始 skill.md、完整 valround-0 best 快照记录 baseline 分数
Train rollout当前 skill + train slice + seedresults.jsonl 与逐条样本文件有可读轨迹
Improve当前 skill + latest train samples__before.md 与 candidate skill存在跨样本、可泛化的模式
Val gatecandidate + 完整 valcurrent/best/rollback 状态分数跨过门槛,或被判为 flat/reject
下一轮门控后磁盘上的 skill新 seed 的 train samples下一次 improve 只看与当前工件匹配的轨迹
setup
  -> run baseline val; snapshot initial best
  -> run train(seed = 1); write failed/*.md + passed/*.md
round r
  -> snapshot __before.md
  -> diagnose latest train samples
  -> patch skill.md
  -> run full val
  -> accept | flat | reject
  -> run train(seed = r + 1); replace sample files
final
  -> restore best snapshot
  -> run test exactly once

2.2 允许什么、禁止什么、什么时候可以什么都不做

Improve prompt 把权限收得很窄:必须先完整读 workspace/skill.md,再抽样读 samples/failed/ 与 samples/passed/;只允许改 workspace/ 下的 skill,不碰 baseline。它还要求单例 edge case 跳过,只有至少两个失败支持同一模式才提出修改。没有样本时直接停止;找不到稳定共性时也可以不产生有效 patch。允许 no-op 很重要:每一轮都强行改字,只会制造无依据的漂移。

成功输出会落到三类地方:样本目录保存本轮观察,.skillopt/history/ 保存可回滚快照,workspace/skill.md 保存下一轮真正使用的工件。后续轮次不是读取一份抽象“记忆”,而是直接看到这些文件,以及由当前 skill 重新生成的新轨迹。

三、轨迹文件化:为什么 Coding Agent 能代替一层优化框架

Lite 的关键不是“让 LLM 反思”,而是把反思所需的证据变成 Coding Agent 最擅长处理的对象。row_to_md 把 results.jsonl 的每一行转成独立 Markdown:frontmatter 里有 id、status、score、env 和 tags,正文再放 Input、Expected、Agent output、Trace 与 Notes。失败和成功分别进入两个目录。

results.jsonl 经 row_to_md 拆成逐任务 Markdown,分别进入 failed 和 passed 目录;Coding Agent 比较至少两个重复失败和成功反例后,只对 skill.md 应用不超过四处小改动
文件化让轨迹可列举、可抽样、可搜索、可引用;passed 不是奖励装饰,而是用来推翻过度概括的反例。

3.1 一条样本先解决“它到底看到了什么”

对我们的 spreadsheet 例子,一条样本不只是“失败=0”。它把原始 instruction、期望结果、Agent 输出、末尾 ReAct 轨迹和 fail_reason 放在同一文件里。若是执行阶段失败,prompt 还要求直接读生成的 solution.py;若是 Agent 阶段耗尽 turn,则只追最后几轮它反复卡住的位置。

---
id: task_x
status: failed
score: 0
tags: [sheet_level, exec]
---
## Input
## Expected
## Agent output
## Trace
## Notes
fail_reason: ...

这是形状级例子,不是项目里的某条真实样本。重要的是信息形态变化:原来埋在 evaluator 输出里的 episode,现在成为可以单独引用的文件;Coding Agent 可以先看目录分布,再按需要打开少量高信号文件,而不是把所有长轨迹一次塞进上下文。

3.2 Consensus mining 不是多数投票,而是跨任务不变量

读取预算先按 task_type 分桶,再限制失败/成功样本数与总 trace 文本。诊断规则随后要求:

  • failure-first:失败与成功建议冲突时,优先修复重复失败,但仍检查成功样本是否会被破坏;
  • 至少两个支持:单一任务特例跳过,不把某个 sheet name、列号或 row count 写进 skill;
  • passed 反证:同 task type 至少读一条成功轨迹,确认现有 skill 是否已经覆盖该变体;
  • 最小有效 patch:SpreadsheetBench 最多四处 edit,具体代码范式优先于泛泛提醒。

于是“多个任务破坏公式”不会直接变成“永远不要写公式”这种错误规则。更好的补丁会写清适用条件和具体动作:何时必须使用 openpyxl 保留 workbook 结构,怎样遍历真实行数,什么时候不能依赖 preview。candidate 到这里才算产出,还没有得到有效性证明。

四、Validation 决定补丁保留还是回滚

如果 Coding Agent 能一边诊断、一边宣布自己改对了,整个过程就会退化成自我说服。SkillOpt-Lite 把写补丁与选版本分开:train 负责产生修改信号,val 的汇总分数用于决定保留或回滚,test 按约定在所有选择结束后只运行一次。

4.1 Train、val、test 约定了三种用途

阶段优化器按约定读取什么允许改变什么能回答什么
train任务内容、失败/成功轨迹、生成代码可以驱动 skill.md patch“下一处应该试着改什么?”
val只使用可比较的 aggregate score可以决定接受、flat 或回滚“这个 candidate 值得继续保留吗?”
test循环完成后才打开不再允许影响 candidate 选择“最终 best 对未参与选择的样本怎样?”
cand_acc 进入 val gate 后分为 accept_new_best、accept、flat 与 reject;只有新最佳同时更新 current_acc 和 best_acc,accept 只更新 current,flat 保留 skill 但不更新分数,reject 从 before 快照恢复,最终 best 快照恢复后才运行 test
同一个“保留”有不同语义:保留为 current、写入 best、暂留但不承认分数,或从快照回滚。

4.2 Lite prompt 的 dead band 比纯 evaluate_gate 多一层状态

仓库里的纯函数 evaluate_gate 只有三种结果:超过 current 且超过 best 是 accept_new_best;只超过 current 是 accept;否则 reject。但 SpreadsheetBench 的 Lite prompt 只是参照这套比较规则,由 Coding Agent 执行判断,并非调用这个纯函数;它另外规定了±0.02 dead band 与 flat 状态:

  • Δ ≥ +0.02 才按 improvement 接受;
  • Δ ≤ -0.02 回滚;
  • |Δ| < 0.02 时,candidate 仍留在磁盘成为下一批 train 的起点,但 current_acc 与 best 都不更新;
  • 若 cand_soft − current_soft ≥ 0.05,prompt 允许把 hard-flat 升格为 accept。

这意味着 flat 不是“接受但不叫接受”,也不是纯 no-op。它能影响下一轮看到的行为分布,却不会成为最终恢复目标;循环结束仍以 best snapshot 为准。文章或实现若只引用 gate.py,就会漏掉这个由 prompt 持有的状态语义。

4.3 Val 的读取约定不等于强制隔离

项目把 val 称为 held-out,并要求 Agent 不读取 val item,只用汇总分数做 gate。这是 prompt 规定的读取纪律,不是文件或工具强制执行的访问隔离:按 val 步骤的说明,验证仍会在共享的 samples/ 目录生成逐条样本,随后才由下一批 train 清空并覆盖。能否避免用验证内容写补丁,依赖宿主 Agent 遵守这条约定。

即使严格遵守约定,同一套 val 仍被多轮反复用于选择 candidate,所以从整个优化过程看,它更像search set,而不是一次性、完全未接触的最终估计。工程推论是:轮数、dead band 和 stopping rule 都会间接适配这套 val;按约定留到搜索结束的一次性 test,才用于估计最终 best 在未参与选择的样本上的表现。

状态已经发生仍缺什么
输出已产出Coding Agent 写出 candidate skill.md可比较的独立验证
输出已验证candidate 通过 val gate,最终 best 运行一次 test目标部署的成本、延迟、安全与回滚检查
输出已采用有权限的人或发布流程把 best 设为真实 Agent 工件持续监控与复盘仍不可省略

五、Full SkillOpt 与 Lite:删掉中间优化步骤,保留跑分验证

同一仓库还保留了 Full SkillOpt 的 Python trainer。trainer.py 在文件头列出六阶段:Rollout、Reflect、Aggregate、Select、Update、Evaluate。Lite 没有删掉 rollout 或 evaluation,而是让 Coding Agent 直接在文件系统里承担原来 reflection pooling、patch merge、ranking 和 update orchestration 的大部分工作。

Lite 仓库内附 Full trainer 的 Rollout、Reflect、Aggregate、Select、Update、Evaluate 与 Lite 的轨迹文件、Coding Agent 修改和 val 对照;中间四步由 Coding Agent 承担,Full 的 slow update 仍可 force_accept
Lite 的“少”不是少做验证,而是把可由强 Coding Agent 与文件工具完成的中间层折叠掉。
问题Full SkillOptSkillOpt-Lite
轨迹怎样读minibatch reflection 与结构化 patch逐条 Markdown + Coding Agent 探索
多个建议怎样合并merge_patches 层级聚合Agent 在同一上下文中提取跨任务共性
更新幅度edit budget / schedulerprompt 里的最小修改和 edit 上限
失败历史rejection buffer / step bufferhistory 快照、文件 diff 与下一轮新样本
接受权selection/evaluation gatefull val gate + best snapshot + one-shot test

不要混用两条路径的保证。Full trainer 的默认配置开启 use_slow_update: true;其实现还会把 slow-update guidance 无条件注入 current 与 best,并标记 force_accept。这是 Full SkillOpt 的设计,不是 Lite prompt 的严格 val-gated 规则。仓库里有同名概念,不等于两条路径用相同代码决定保留与回滚。

六、HarnessOpt:当优化对象从说明书扩到执行器

一旦失败不是 skill wording 造成,而是 preview 太小、code extraction 太脆、超时策略不合适或工具缺失,继续改 skill.md 只会把 harness 缺陷包装成更多提示词。HarnessOpt 因此允许搜索 Python harness 的实现;但允许修改的文件一多,风险、验证成本和审批要求也必须同时提高。

两条独立循环的 prompt 约定:SkillOpt-Lite 可改 skill.md 而不改 harness;HarnessOpt 只读 skill.md,允许修改 rollout.py、react_agent.py、codegen_agent.py、executor.py、recalc_harness.py 和 adapter.py;这些约定与 diff 检查不是文件 ACL
当前 prompt 采用顺序优化:skill loop 与 harness loop 分开运行,不是在同一轮同时改文本和执行器。

6.1 Allowlist 明确列出可以修改的六个文件

HarnessOpt prompt 明确只允许编辑 rollout.py、react_agent.py、codegen_agent.py、executor.py、recalc_harness.py 与 adapter.py;skill、evaluator、dataloader、configs 和 prompts 都在 denylist。它还说明 skill-content failure 要路由回独立的 /skillopt-loop。这比 README 表格里“skill.md and agent code”的宽泛描述更具体,因此判断当前实际允许修改什么,应以 prompt 的 allowlist/denylist为准。

6.2 Round 0 先做架构决策,再把后续轮次收窄

Round 0 会跑 baseline val 和完整 train,扫描失败分布,再从 memory、tool、prompt context、loop policy、codegen/executor shape 等角度提出三项决策。新的 tool、memory 或执行方式可能扩大代码能访问的数据和动作,所以 prompt 要求在应用 patch 前打印 brief 并等待用户 approve。Round 1 之后才进入自动化的 surgical edit、diff guard、smoke、full val 和 rollback 循环。

这套设计保护了一个重要不变量:架构性扩大权限必须有人批准,局部修补才可以交给自动 gate。但当前 Round 0 还有一个实现上的空档:bootstrap patch 会先 commit 并打上 round-0-best 标签,只跑 6 条 debug batch;prompt 明说这里不做完整 val,要等 Round 1 才验证。如果后续没有产生新 best,最终恢复逻辑可能把一个只通过 smoke、没有通过完整 gate 的 bootstrap 当成 best。

6.3 Checkpoint 展示了 harness 优化能改出什么

harnessopt_ckpt 不是抽象愿景,它保存了具体代码变化。例如 codegen_agent.py 在启用 SPREADSHEETBENCH_HARNESS_NANO=1 后,把 workbook preview 从 5×20 扩到 15×30,并启用不读取 gold 的输出自检,识别 answer cells 中残留的 formula string。

另一个独立开关 SPREADSHEETBENCH_TIMEOUT_FALLBACK=1 才会启用 reasoning-effort fallback:run_multi 中某轮模型请求的常规重试失败后,若剩余时间足够且当前 effort 允许降级,可用较低 reasoning effort 再尝试一次;它适用于 Chat / Responses 后端,不适用于 exec 后端。两个开关都默认关闭,便于分别回退和做 A/B 对照。

七、读到 HEAD:方法清楚,公开执行路径仍有断点

到这里可以把“设计是否合理”和“fresh clone 是否能照文档跑通”分开。前者有足够源码支撑;后者在当前快照上仍存在几个可复现的断点。按照源码审计常用的三档:有真实入口和副作用才叫 main path;只有文件但未接通叫 disconnected;文档命名的目标链没有完成则叫 target route not demonstrated。

本文源码快照的五项核查:循环说明存在,scripts/eval_only.py 缺失,LiveMath 的 2-1-7 与 2-2-6 口径不一致,round-0-best 先于完整 val,HarnessOpt 的工作目录与 pathspec 不匹配
这些断点限制的是当前公开执行路径,不等于否定“轨迹文件 + 共性提取 + validation 跑分”的方法。

7.1 五个需要在复现前先修正的断点

观察源码证据状态判断实际后果
Prompt 中的循环说明完整可读.github/prompts/*-loop.prompt.md 定义 snapshot、improve、gate、rollback、test主流程说明可见能准确理解预期步骤与权限
当前 HEAD 没有 scripts/run.sh 调 scripts/eval_only.py,pyproject.toml 也注册 scripts entry point;但后续提交删除了整个目录目标路径未证明按 README/run.sh 的 fresh-clone 路径会在 evaluator 入口前失败
LiveMath split 定义不一致config 指向 2-1-7_seed42;download 与 prompt 指向 2-2-6_seed42;prompt 又同时出现 val=35 与 val=18数据口径不一致不同入口可能评估不同样本,指标不可直接横比
Round-0 best 未经过完整 gatetag、smoke 与 best 初始化顺序bootstrap 空档需要先 gate Round 0,再允许它进入 best slot
HarnessOpt pathspec 与 cwd 重复prompt 先 cd harness_example/spreadsheetbench,随后仍把同一路径传给 git status/add命令路径断裂diff guard 可能看到空集合,git add 直接 pathspec 失败
插件覆盖面仍是 roadmapREADME 一边列举多个 host,一边把 Codex CLI 与 Claude Code plugin 标为 TODO宿主适配未交付不能把 VS Code prompt 文件等同于所有 Coding Agent 的即装即用扩展

为什么 pathspec 会失败

cwd = harness_example/spreadsheetbench/
pathspec = harness_example/spreadsheetbench/

resolved intent:
  harness_example/spreadsheetbench/
  + harness_example/spreadsheetbench/

result:
  no tracked files for that doubled relative path

这是确定性的路径解析问题,不需要推测模型行为。更稳妥的写法是在该 cwd 下使用 -- .,或始终在仓库根目录运行并保留完整 pathspec。另一个风险是 prompt 使用 git reset --hard 做回滚;若工作树包含不属于优化轮次的改动,它的影响范围大于单个 harness 目录,因此生产化实现应改成独立 worktree/branch 或精确快照。

7.2 项目报告了什么,本文没有证明什么

项目口径报告值本文的证据级别
LiveMath · GPT-5.4-nano + SkillOpt-Lite比 Full SkillOpt 高 25.4 points项目报告,未复现
LiveMath · GPT-5.5 + SkillOpt-Lite比 Full SkillOpt 高 8.8 points项目报告,未复现
ALFWorld · GPT-5.4-nano81.3,较 SkillOpt +9.5项目报告,未复现
Spreadsheet 平均提升+12.6 points项目报告,未复现
HarnessOpt · SpreadsheetBenchnano 0.7758,对比 GPT-5.5 标准 harness + SkillOpt 0.7620项目报告,未复现;当前复现入口还缺脚本

这些结果足以说明项目值得复现,但还不能把“更少模块”直接推广成普遍定律。缺少独立重跑时,更稳妥的结论是:强 Coding Agent 可能把专用的文本优化拓扑折叠成文件调试;是否更好,仍由目标模型、benchmark、val 复用程度、token 成本与宿主工具决定。

八、什么场景适合借用这套设计

SkillOpt-Lite 最值得迁移的不是 slash command,而是责任划分:把可变工件做成文件,把观察做成逐条证据,把补丁生成与接受权分开,把 test 留到搜索结束。只要这四条成立,实现可以是 Coding Agent、CI job,甚至一个更小的专用服务。

Good fit允许修改的文件清楚

Prompt、skill、policy 或 harness 文件能被精确 allowlist,且每次改动都可 diff、可回滚。

Good fitEvaluator 能重复比较

任务有稳定输入、确定或可校准评分、足够大的 train/val/test,rollout 成本可承担。

Poor fit成功信号只有主观自评

没有独立环境结果时,反思只是 hypothesis;增加轮数只会放大自洽叙事。

Poor fit改动直接触达生产副作用

若 candidate 能改权限、数据、账单或部署,必须先进入隔离环境和人工 adoption gate。

8.1 一套可迁移的最小规则

  1. 先固定比较条件:锁定目标模型、harness、数据版本、seed 策略和 scorer;一次只优化一种工件。
  2. 让每条轨迹有地址:输入、输出、trace、score、failure reason 和生成工件必须能被单独引用。
  3. 只修跨任务模式:至少两个独立失败支持同一规则,并用成功样本或反例尝试推翻它。
  4. 限制补丁范围:allowlist、edit budget、feature flag、snapshot 与 rollback 缺一不可。
  5. Val 决定 retention,test 只做一次:重复看 test 就把它降级成新的 val。
  6. 把 adoption 再设一道门:检查 intended outcome、关键回归、成本/延迟、恢复、权限与人工责任人,不能用 benchmark best 自动替代发布决策。

8.2 最终判断

SkillOpt-Lite 的核心自进化机制是成立的,而且比“让 Agent 自己反思”更严谨:它有显式触发、有固定快照、在 prompt 中约束可读写文件、允许 no-op、有持久历史、有可比较 rerun,也会在最终 test 前恢复 best。它优化的是外部行为文件,不是模型权重。

当前仓库更像一份有实验结果、有 checkpoint、循环说明清楚,但公开复现步骤仍有缺口的研究/工程快照。如果要直接用于现有 Agent,第一步不是复制 prompt,而是先补齐 evaluator 入口、统一 split 定义、修正 HarnessOpt pathspec、让 Round 0 先过完整 validation,并把 destructive git rollback 放进隔离工作树。完成这些后,这套精简流程才从“候选方案”进入“可验证实现”;再经过目标业务的安全、成本与回滚检查,才谈得上采用。

九、延伸阅读与源码索引