💊 Static Skill Capsule

决策级程序蒸馏(LoRA「技能胶囊」)能否替代长文本技能提示?——从 mock 管线到真实任务、 从单次训练到门控持续学习的完整研究弧线。九个版本、8 次门控判定(5 升 3 拒),每一步的进步与问题都有真实样例。 基座:Qwen2.5-7B-Instruct;所有数字来自盘上评测记录,无挑选。

100 / 99%capsule 在 mock test/OOD(v1 阶段)
100% vs 12%工具 API 演化下 capsule+binder vs 具体调用微调
23.8→50.8%真实指令任务:迁移起点 → 最终 v009
8 判定门控升降全审计(5 promote / 3 reject)

v0–v1 蒸馏起步:胶囊、raw-state、工具演化

把「文档文本修订」技能蒸馏成 5MB 的 LoRA:模型每步吐一个抽象决策 (LOCATE_TARGET → APPLY_MODIFICATION → VALIDATE_RESULT → STOP), 不带任何技能提示文本。主设定 raw-state:模型只看原始可见对象+上一步反馈。

问题实例7B 基座 + 完整技能提示:协议崩溃
任务 textrev_test_000001 (mixed_relation)
full_skill_prompt → actions: [STOP]   parse_failures: 1   ✗ 失败
# 基座模型撑不住 raw-state 长输入下的 JSON 协议:test 集 91% 解析失败,成功率 14%
进步实例同一任务,蒸馏胶囊(零技能文本)
skill_capsule_lora → [LOCATE_TARGET → APPLY_MODIFICATION → VALIDATE_RESULT → STOP]  ✓
# capsule:test 100%,OOD 99%;解析失败 0。蒸馏买到的是「可靠性」
v1 头条工具 API 演化:抽象动作 + 规则 binder 全免疫
同一个抽象动作 LOCATE_TARGET{content:"DN100", region:…}
tool v1 → query_text(page, content, region)          capsule+binder: 100%
tool v2 → search_text(page_id, text_equals, area)    capsule+binder: 100%
tool v3 → list_text + filter_text_by_content + …     capsule+binder: 100%

对照:把具体 v1 调用蒸进权重的 toolcall_lora,
tool v2 下 schema error 1.07 个/任务 → 成功率 12%(残余=恰好该 no-op 的任务)
诚实的问题「省上下文」主张被撤回

raw-state 下胶囊每步重发可见对象,上下文 ~4k>fulltraj 单次 ~2.5k——v0 的「省上下文」 是 oracle 摘要造成的假象。胶囊的真优势是鲁棒性(OOD +22pt)与可靠性(0 解析失败),不是成本。

B6 公平对照:主流多步 Agent(OpenClaw)

方法论质疑:「主流 agent 就是多步的,得和它比」。于是把同一任务塞进真实框架 OpenClaw(ReAct 运行时 + MCP 工具),同一个 Qwen2.5-7B、greedy 解码——只有运行时不同。

系统testOOD上下文 tok/任务(中位)
capsule(蒸馏)100%99%~4k
B6 zero-shot57%45%~46k
B6 few-shot53%38%~57k(OOD 空转时中位 77 万)
问题实例幻觉成功:一次工具没调,却报告完成
任务 textrev_test_000046   tool_log = ['query_text'](从未调用 modify_text)
B6 回复:"No matches found … Therefore, no modifications were made.
         The operation has completed successfully without any changes."
# 文档里目标就在区域内;ground-truth 判失败。7B 的典型模式:定位后不跟进(test 上 31/60 停在 query)
问题实例OOD 失控空转
34/60 个 OOD 任务:模型始终发不出合法工具调用,循环到框架轮次上限
中位 32 次模型调用/任务,烧掉中位 ~77 万 token 后放弃

结论:框架给了脚手架(B6 远好于会崩的裸提示基线),但蒸馏才带来可靠性—— 准确率与成本双输给胶囊。few-shot 修不动(噪声内)。

v2 门控持续蒸馏:经验 → 候选 → 闸门 → 升/拒

循环:跑任务流 → 外部验证轨迹 → 经验缓冲 → 确定性回放编译训练样本 → 训候选 → 四闸门(老任务保持/新任务提升/工具/成本)→ 升级或拒绝。v001 刻意用受限课程训练,留出提升空间。

版本老任务batch_002(已到 OOD)batch_005(未到)判定
v00110081.774.0promoted(初始)
v00210097.5(+15.8)61.0(−13)PROMOTED
v003 候选10090.8(吐回 6.7)70.0(+9)REJECTED:误改率 0.4→2.6%
进步 一轮门控蒸馏 +15.8(198 条 on-policy 验证轨迹 + 120 个专家验证的定向难例),回放护住老任务零遗忘。
问题 闸门保护不了「还没到达」的分布:batch_005 不在任何闸门里,升级决策依规正确,却发生 −13 负迁移。 恢复轮 v003 又被闸门正确拦下(跷跷板 + 误改率上升)——门控系统第一次真实拦截
问题实例skill.md 文本更新:灾难性失败
v001 裸跑 batch_002:81.7%
v001 + 失败衍生规则块(skillmd_update):11.7%
# 裸训胶囊把任何前置规则文本当分布外输入 → 整体塌掉。
# 六机制对比:权重更新 97.5 ≫ 不更新 81.7 > 记忆检索 78.3 ≫ 文本规则 11.7;工具轴 binder-only 零成本 100%
上界实验 全量联合重训(mock 内)拿到 99.2/88.0——mock 内部的跷跷板是小步序贯更新的样本预算伪影,不是数据冲突。这个结论在 v3 终局被部分推翻(见下)。

v3 真实任务:DrafterBench 指令 × 合成基底

160 条真实 CAD 图纸修订指令(2⁵ 因子设计),ground-truth 代码 160/160 解析成 238 个操作 + 56 个 「指令残缺应弃权」任务;合成与之语义一致的文档基底。模型只看逐字真实指令,必须自己抽取目标。

问题实例(E1 迁移)mock 训练的胶囊,面对真实语言直接放弃
真实指令:"For the file X987Y654.pdf, on page 7, in the second rectangle,
          delete the strings "Draft Copy" and "Preliminary Version" … Align any remaining…"
v002(mock 训练)→ actions: [STOP]   ✗
# E1 迁移墙:最好的 mock 胶囊总体 33%,specific 46%;rule_planner(直读字段)83.7% 证明程序可解——
# 墙在「从真实语言抽槽位」,不在程序
进步实例(E2 蒸馏一轮后)同一条指令,v004 正确抽取
v004 → LOCATE_TARGET{content_constraint: "Draft Copy", …} → … ✓
# 554 条真实样本一轮:specific 18→51,总体 23.8→40.0。
# 但 mock 保持 94%<97% 阈值 → v004 被拒;回放加倍后 v005:真实 38.4 + mock 98.7 → 升级

v6–v7 攻坚:wildcard 与「有原则的弃权」

进步实例wildcard:学会 content_constraint:"*"
真实指令:"…in the first rectangle, replace all horizontal text with "Updated Project Details"…"
v006 → LOCATE_TARGET{content_constraint: "*", spatial_scope: "selected_region"} ✓
# 900 条多措辞合成样本:wildcard 0→49%
问题实例能力越强越敢对诱饵动手
残缺指令(没指定文件):"On page 3, in the first rectangle, replace all horizontal text
                        with "Updated Legend", then delete the string "Outdated"…"
v006 → [LOCATE_TARGET{*} → APPLY_MODIFICATION → VALIDATE_RESULT → STOP]  ✗ 自信的错误执行
# v006 弃权 19 个失败全是这种;真实 Error 象限的破绽是「缺文件名」「不支持的模态(vertical text)」——
# 和最初合成的缺参数类消融不匹配
进步实例v007:显式拒绝(完整性契约学会了)
残缺指令:"For the file Layout789.pdf, in the second rectangle of the page,
          replace all horizontal text with "Updated Layout Details"."   ← 没说第几页
v007 → [REPAIR_SELECTION{failure_type:no_candidate, resolution:abort} → STOP]  ✓ no_op
# 补齐 missing_file/unsupported_modality 消融 + 对比孪生对(同基底:残缺→拒 / 补全→做)+ 真实弃权×6
# 弃权 46→89%,且 31/31 全部是显式拒绝(非蒙对)

v8–v9 终局:全量联合重训与 Pareto 前沿

v007(序贯)v008(联合·自然配比)v009(联合·拒绝×3)
real 总体47.647.050.8(项目最高)
real specific / wildcard31.6 / 45.145.6 / 50.745.6 / 50.7
real 弃权88.642.962.9(91% 有原则)
mock / batch_005 / 工具98.7 / 61 / 99100 / 94 / 100100 / 94 / 100
判定曾升级REJECTEDPROMOTED(现任)
终局发现 联合重训化解除弃权外的一切跷跷板; 弃权崩塌(88.6→42.9)是数据组成冲突: 拒绝信号在自然配比里仅 7.5%,扛不住「永远执行」语料——加权到 13% 只收回到 62.9, v007 与 v009 是弃权↔执行 Pareto 前沿上的两个点; 聚合闸门以总体 +3.2 选了 v009, 尽管弃权切片对 v007 只有 0.71 的保持率——「最好的模型」是闸门粒度的函数,逐切片闸门是 v4 首项。

贯穿全程的工程教训