skills包管理工具APM

问题:skills 到底该怎么管?

Agent skills(SKILL.md)正在成为 LLM engineering 里越来越重要的基础设施。但它的管理方式仍然非常原始。

很多人的现状就是:

  • 看到一个感兴趣的 skill repo → 手动下载到 ~/.claude/skills/
  • 换一个项目 → 手动挪文件
  • 换一台机器 → 重新折腾一遍
  • 技能越来越多 → context 越来越胖,触发越来越乱

这个问题大家都感觉到了,但"怎么管才对"一直没有共识。

这篇文章记录了我在这件事上探索过的所有路径,以及最终的结论——项目级包管理器是这个问题的唯一正确终局。

“skills装多了会有问题,当 Skill 数量在 20 个以下时,选择准确率保持在 90% 以上,几乎不会选错。超过 30 个之后,准确率开始快速下滑。到了 200 个 Skill 的时候,准确率已经跌到大约 20%。如果你是个人用户、小团队或者 OPC 做日常自动化的活,8 到 15 个 Skill 通常最舒服。” 看来我现在的 skills 仍然是有点多了。但是我想不到

这么多 Skill,真正每天用的到底有几个?SkillsBench:评估代理技能在多样化任务中表现的基准_哔哩哔哩_bilibili

Skills可以无限堆砌么?具备技能的单智能体何时能替代多智能体系统,又在何种场景下失效?_哔哩哔哩_bilibili


阶段一:Imperative CLI

最早我用的是技能社区自带的 CLI(比如 skills-cli),配合 Taskfile 做自动化。

工作流是这样的:

  1. 维护一个 YAML 清单,列出所有需要的 skills 及其来源 repo
  2. 运行 task,CLI 对比本地 lockfile 和 YAML 清单,算出待安装列表
  3. 执行安装

这个方案能跑,但有两个明显问题:

  • 没有强一致性。命令式流程依赖每次执行时的网络状态、repo 可用性、本地缓存。同一份清单在不同时间、不同机器上可能产生不同的结果。
  • 维护成本高。每次新增/删除 skill 要走完整的 改清单 → push → 执行 update 循环,日常迭代太重了。

一个关键的技术细节是 skills-cli 当时不支持基于 lockfile 的全局 install(仅项目级),而且 lockfile 的 key 顺序不稳定导致 diff 混乱。这些细节问题放大了整个方案的不稳定感。

归根到底,命令式的 skill 管理无法做到强一致性。 这是我在当时就意识到的核心矛盾。


阶段二:声明式(Nix)

既然命令式不行,那就上声明式。我把核心 skills 迁移到了 agent-skills-nix(ASN),通过 Nix 做声明式管理。

这一下子解决了一致性问题——Nix 的 store 模型天然保证了确定性和可复现性。同时还解锁了全局配置管理,我可以把 skills 和其他 dotfiles 一起纳入统一的声明式框架。

但这个方案也有明显的代价:

  • 配置成本高。每个 skill repo 都需要在 flake 里手动配置,不能自动扫描子目录。
  • 迭代摩擦大。临时添加或删除一个 skill 需要重新 rebuild,对于"先试试好不好用"的场景太重了。
  • repo 和 skills 的元数据拆到了两个地方,可维护性随着 skill 数量增长而恶化。

为了解决这些问题,我把方案拆成了两层:

CORE skills   → Nix 声明式管理(高确定性,低变更频率)
OPTIONAL      → Taskfile + CLI 管理(低确定性,高变更频率)

这个混合方案在实践上是可工作的,但它本质上是在两个都不完美的抽象之间做妥协。每次新增一个 skill,我都要决策它属于 CORE 还是 OPTIONAL,而这个决策本身没有客观标准。


阶段三:lazyskills——尝试造一个更好的轮子

核心目的还是有效缩减skills

第三方方案探索

在遇到了上面这个问题之后,我就想是否有什么

skillshare 和 skillfile

前者是个 cli+webui,后者是TUI

前者是golang+TS, 后者是rust

二者基本上都能满足我的需求(都是声明式,且支持分发多target),前者的优势在于可以替代实现“enable / disable”,后者优势在于有lockfile

- 维度: 声明式程度
  skillfile: "✅ Skillfile 明确 desired state,`/tmp/skill-manager-eval/skillfile/SPEC.md:1`"
  skillshare: "✅ `config.yaml` / `.skillshare/config.yaml` 明确 target/source/filter"
  skill-flow: "⚠️ 有 `manifest.json/lock.json`,但主要是 `~/.skillflow` 机器状态"
- 维度: "lock / reproducibility"
  skillfile: "✅ Skillfile.lock 精确 SHA pin"
  skillshare: "❌ 无等价 lockfile,更新结果不够可重放"
  skill-flow: "⚠️ 有 `lock.json`,但偏本地状态,不是 repo 可审 reproducibility"
- 维度: "update / outdated"
  skillfile: "✅ `install --update` + `status --check-upstream`"
  skillshare: "✅ `check` / `status` / `update` / `upgrade` 完整"
  skill-flow: "⚠️ update 有,outdated 主要靠 health/list 间接看"
- 维度: "enable / disable"
  skillfile: "❌ 无一等开关,只能删/注释/分文件"
  skillshare: "⚠️ 无简单 disable,但 include/exclude、`.skillignore`、target filter 可安全替代"
  skill-flow: "⚠️ 可通过 selectedLeafIds / enabledTargets 选子集,但偏状态式"
- 维度: "多 target 支持"
  skillfile: "⚠️ 多平台安装有,但基本是同一套内容发往所有 target"
  skillshare: "✅ per-target path/mode/include/exclude 很强"
  skill-flow: "✅ projection/binding 很强"
- 维度: "TUI/CLI 体验"
  skillfile: "✅ CLI-first,add/search 有 TUI"
  skillshare: "✅ CLI-first,TUI 友好,UI 可忽略"
  skill-flow: "✅ TUI 很强,但产品面混入 desktop"
- 维度: 本地目录模型
  skillfile: "⚠️ manifest + cache + deploy,source-of-truth 不是真实技能树"
  skillshare: "✅ 中央 source tree + sync 到 target,模型最直观"
  skill-flow: "⚠️ `~/.skillflow/` 状态根 + projections,较重"
- 维度: "project/global scope"
  skillfile: "✅ install `<local/global>`"
  skillshare: "✅ 全局 `~/.config/skillshare` + 项目 `.skillshare/`"
  skill-flow: "⚠️ 有 project scope 概念,但核心仍是全局 state root"
- 维度: "team workflow"
  skillfile: "✅ Skillfile/Skillfile.lock/patches 最适合进 git"
  skillshare: "✅ `.skillshare/` 配置和 source dir 可进 git"
  skill-flow: "⚠️ 团队协作不自然,状态主要在 home 目录"
- 维度: CI/headless
  skillfile: "✅ 很适合"
  skillshare: "✅ 很适合,还有 GitHub Action"
  skill-flow: "⚠️ 能跑 CLI,但不是最自然的 repo-first CI 模型"
- 维度: "doctor/repair/drift detection"
  skillfile: "⚠️ 有 validate/diff/status,无真正 doctor/repair"
  skillshare: "✅ doctor/diff/sync --dry-run/audit 很实用"
  skill-flow: "✅ 这项最强,doctor/repair-* 完整"
- 维度: "migration risk"
  skillfile: "⚠️ 容易把同一套 skills 过度同步到所有 agent"
  skillshare: "⚠️ 无 lockfile;接管 Nix 目标目录前必须先断旧发布器"
  skill-flow: "❌ 状态化迁移更难审查,也更容易和现有目录模型打架"
- 维度: "long-term maintainability"
  skillfile: "✅ 范围聚焦,小而清晰"
  skillshare: "✅ 功能全,但面更大;仍可控"
  skill-flow: "⚠️ CLI+desktop+bridge 面过宽"
- 维度: "fit for my current setup"
  skillfile: "⚠️ 很适合替代 Taskfile,但不完全贴合你多 target/filter 现实"
  skillshare: "✅ 最贴合你现在“中央源 + 多 agent 同步 + copy/symlink 控制”"
  skill-flow: "❌ 不适合作为你的主力"

分别尝试了一下这两个工具,

• 对,我应该更早把这句话说死:

skillshare 是“声明式的 target/source/sync 配置工具”,但不是“声明式的 skills dependency manifest 工具”。

也就是说,它支持声明式,但不是你要的那种声明式。

具体区别

你要的声明式是这种:

- repo = openai/skills
- skills = [gh-fix-ci]
- group = CANDIDATES
- note = 为什么收、为什么不收、怎么分类
- 最好还能进 git、可 review、可直接作为 source of truth

这其实是一个“依赖清单 / catalog manifest”。

而 skillshare 原生声明的是这些:

- targets
- mode
- include/exclude
- audit
- source 路径
- .skillignore 里的 disable 规则

这是一套“分发/同步配置”。

所以为什么不能直接把 .SKILLS.yml 迁成 skillshare 原生格式?

因为 skillshare 原生没有一个一等 schema 去表达你 .SKILLS.yml 里的核心信息。

缺的不是 YAML 语法,而是语义槽位:

1. 没有原生字段表达“远程 repo catalog”
skillshare 的 config.yaml 不提供一个正式的 repos: / skills: manifest 区块,让你把 vercel-labs/skills
-> [find-skills] 这种关系声明进去。
2. 没有原生字段表达“这个 repo 只选其中几个 skill”
它能 install -s gh-fix-ci,但这是安装命令能力,不是一个被 schema 固化、可长期审查的 manifest 模型。
3. 它的 source of truth 是“安装后的 source tree”
也就是 .skillshare/skills/... 本身,而不是一份 repo 级清单文件。
这和你的 .SKILLS.yml 思路根本不同。
4. CANDIDATES = disabled by default 只能落到 .skillignore
这能表达“禁用”,但不能表达“为什么禁用、这组 repo 的评价、备注、分层意图”。
5. 注释没有原生归宿
你 .SKILLS.yml 里最有价值的恰恰是这些注释和判断。
skillshare 原生模型没有 repo-level note/comment schema 去承接它们。
6. 没有 lockfile 式 manifest 解析结果
所以即使你硬迁,也得靠“安装后的目录状态 + ignore 规则 + 内部 metadata”,不是一份干净的声明式
catalog。

所以准确结论是

- skillshare 支持声明式:sync/targets/filters/audit/source
- skillshare 不支持你要的那种声明式:repo + selected skills + comments + group semantics 的 catalog
manifest

这也是为什么我后来加 catalog.yaml。不是因为我想乱设计,而是因为如果不补这一层,skillshare 原生模型根本
承接不住你 .SKILLS.yml 的信息结构。

但你说得对:
如果你要求“只用 skillshare 原生,不要自造一层”,那就不能无损迁移 .SKILLS.yml。

一句话说透

.SKILLS.yml 是“依赖清单”;skillshare 原生是“已安装 source tree + sync config”。
这两者不是同一个抽象层,所以不能直接一比一迁入。

如果你要严格满足“声明式 repo catalog”这个要求,那结论就很直接了:

- skillshare 不适合作为你这套 .SKILLS.yml 的原生承载层
- skillfile 反而更接近你要的模型

如果你愿意,我下一条就只做一件事:

把这三句话压缩成最终选型判断,直接告诉你:
在“声明式 catalog”这个标准下,skillshare 为什么不够格,skillfile 为什么更对路。

zzz

这时候我决定自己写一个工具。

lazyskills 是一个 Go TUI 应用,核心模型是:

profile(如 "go-dev")→ 关联多个 GitHub repo → 自动扫描 SKILL.md
→ resolve + hash + lockfile → install 到全局 store 目录

我做了很多东西:

  • Profile 管理。把 skills 分组,按需启用/禁用。
  • Concurrent resolve 引擎。从多个 GitHub repo 并发拉取和解析 skills,带 content hashing 和 lockfile 生成。
  • TUI 界面。用 bubbletea 写的终端 UI,支持浏览、搜索、切换 profile。
  • 完整的 install pipeline。resolve → lock → materialize,类似包管理器的标准流程。

从技术上看,lazyskills 做得不算差。它有一套完整的 resolve + lock + install 链路,和包管理器的抽象非常相似。

但问题在于——scope 错了。

Tip

这点是那天中午吃完午饭返程路上,在立交桥下等红绿灯时想到的,当时的想法是,vibe-coding了整整半天,终于弄完了,下午就可以用起来了。然后想到其实仍然很麻烦,切换项目时需要去切换 lazyskills 的 profiles,那我为啥不直接把skills做成项目级呢?然后转念一想,这不就是跟 gomod, pnpm 之类一样的包管理工具吗?

然后再转念一想,是谁把我们带入这种默认就用“全局skills”的思维定势的?太愚蠢了

我的工具是全局的,而问题需要项目级的

lazyskills 的操作链是:

全局 config → 全局 resolve → 全局 lockfile → 全局 install
→ 放到 ~/.lazyskills/store/skills/
→ 需要手动 symlink 到 ~/.claude/skills/

每一步的代码逻辑都是"正确"的。但把 "skills 管理" 放在全局作用域里,无论如何都绕不开几个结构性问题:

  1. 触发污染。全局技能越多,AI 选错技能的概率越大,而 profile 只是分组的 UI,不是 scope 隔离。
  2. 不可复现。同事 clone 一个项目,他的全局 skills 和你的不一样,行为就不一样。
  3. 隐式依赖。项目需要某个 skill 才能正确工作,但 repo 里没有任何声明——新人不知道,CI 不知道,换个 agent 环境也不知道。
  4. 上下文膨胀。所有全局 skills 的描述都进了 system-reminder,不管当前项目用不用得上。
  5. 升级风险。一个全局 skill 的更新影响所有项目——和全局 npm 包的教训一模一样。

这些问题和我之前遇到的一样,根源不在于"做得不够好",而在于抽象层级本身有问题


关键转折:作用域决定一切

在写完

我回头看 lazyskills 的操作链:

全局 config → 全局 resolve → 全局 lockfile → 全局 install

每一层的代码逻辑都"正确",但作用域错了。同样是 resolve + lock + install 的流程,放在项目级和放在全局级,工程价值天差地别。

正确的链条应该是:

项目 manifest → 项目 resolve → 项目 lockfile → 项目 install

这不是我原创的洞察。这就是 pnpm、Cargo、Go modules 已经验证过的模型——依赖声明跟着项目走,安装产物本地隔离,lockfile 确保可复现。

把 skills 当作"全局增强能力"还是"项目级工程依赖",决定了整个工具的抽象层级。


然后看到了 APM

在我做这个判断的几乎同一时间,Microsoft 开源了 apm(Agent Package Manager)

它就是这个正确抽象的工程实现:

项目 apm.yml → resolve → apm.lock.yaml → 写入 .claude/skills/(以及 cursor/copilot/codex 等)

而且它不止于 Claude——同一个 manifest 可以部署到 Copilot、Cursor、Codex、Gemini、Windsurf。有 content hashing、有 policy 层、有 marketplace 机制、有 frozen install。API 设计明显借鉴了 npm/Cargo 的语义。

回头看,它和我之前的方案对比是这样的:

维度 imperative CLI Nix 声明式 lazyskills APM
作用域 全局/项目混合 用户级 全局 项目级
一致性
可复现 ✅ lock + frozen
配置成本
多 agent
团队协作 ✅ manifest 进 git

APM 不是"另一个选择"。它是这个方向上第一个做对了抽象层级的工程实现。我前面尝试过的所有方案,都是在不同的作用域上做着类似的事——而 APM 选择了那个唯一正确的作用域。


结论:项目级包管理器是唯一正确的方向

回顾整个探索过程,路径是清晰的:

命令式 CLI(跑得通但不一致)
  → Nix 声明式(一致但配置成本高)
    → 混合方案(实用主义妥协)
      → 自建 TUI 工具(做对了操作链但选错了 scope)
        → APM(项目级包管理器——正确的抽象)

每一步的决策在当时看来都是合理的。但只有走到最后一步,才看清楚前面的所有方案为什么都差了一口气。

不是技术实现的问题,是抽象层级的问题。

这不是 lazyskills 一个项目的故事。它反映出的是:当你在一个新兴领域(agent skills)里做工具时,最大的风险不是写不出代码,而是找不到正确的 scope。scope 对了,代码怎么写都对;scope 错了,代码写得再好也救不回来。

你应该把你的 skills 当作项目的依赖来管理:

  • 项目根目录放一个 manifest 文件(如 apm.yml
  • lockfile 进 git,确保可复现
  • 安装产物 ignore
  • 项目自有 skill 源码进 git
  • 团队共享 skills 做成 package repo,按版本管理

其他任何方案——无论是命令式 CLI、Nix 声明式、全局 TUI 工具——都是 scope 选错了的变体。


怎么判断skills应该是项目级/全局级?

附录:从 lazyskills 开发中学到的东西

这个部分和上面的结论无关——lazyskills 不会继续开发了,但开发它的过程本身是值得记录的。

1. Go + bubbletea 是 TUI 开发的一流选择

charm 生态(bubbletea、bubbles、lipgloss)非常成熟。并发模型和 Go 的 goroutine 天然契合,消息传递架构让异步操作(如 GitHub clone)的 UI 状态管理变得清晰。如果以后需要写终端 UI,我会毫不犹豫地选这个组合。

2. Content-addressable hashing 是 lockfile 的基石

lazyskills 的 lockfile 对每个 skill 目录做了 SHA-256 hash,记录 resolved commit 和 content hash。这个设计直接借鉴了 Nix store 和 Cargo.lock。一个正确的 lockfile 不只记录版本号——它应该允许你在离线状态下验证内容是否一致。

3. Concurrent pipeline 的设计难度大于预期

resolve 阶段涉及多个 GitHub repo 的并发 clone、扫描、hashing。用 errgroup 做限并发(repository level + hash level 两层限流)在实现上是正确的,但调试并发 pipeline 的竞态条件和错误传播花的时间远超预期。并发 resolve 引擎也许是 lazyskills 里最难写对的部分。

4. TUI 的渲染性能边界

bubbletea 的模型是每次 update 触发全量 re-render。这在大多数场景下不是问题——但当你有上千条 skills 需要渲染、每帧做全量排版计算时,性能瓶颈是很真实的。最终方案是按需切片渲染(virtual list),这个优化带来的提升比预期大得多。

5. 写一个"可用的"TUI 很容易,写一个"好用的"TUI 很难

键盘导航的细节(切换 pane 时的焦点记忆、列表滚动到边缘时的行为、modal 和 confirm dialog 的焦点管理)占据了大约 40% 的 UI 代码量。用户感知不到的细节,往往才是决定一个工具是否值得使用的分水岭。 这个比例本身就是一个值得记住的数字。


关于 lazyskills 的完整代码:https://github.com/xbpk3t/lazyskills 关于 APM(目前最正确的方向):https://github.com/microsoft/apm


skillopt

karminski-牙医 on X: "什么?! skill 也能"训练"了? 以往大家都是凭经验让AI写 skill, 然后调试的时候也是运行几下感觉没bug就完事了. 但 skill 能运行就一定好吗? 于是微软联合上交复旦同济等机构发了一个新框架 SkillOpt, 直接让AI评估skill写的好不好然后不断去优化! 最终, 这个框架写的 skill https://t.co/D4KxyjoxlP" / X

Eval 结果总结

60% 准确率(9/15 正确),模型使用 deepseek-v4-flash + 当前 SKILL.md

正确 (9/15) ✅

题目 预测 黄金答案
tf-001 status 关键字 status ✅ status
tf-002 preconditions 关键字 preconditions ✅ preconditions
tf-003 desc 和 summary desc 和 summary ✅ desc 和 summary
tf-004 pipefail 设置 set: [pipefail] ✅ set: [pipefail]
tf-005 deps 用途 前置依赖 ✅ 前置依赖
tf-007 vars:sh 禁止 副作用 ✅ 副作用
tf-008 status 检查限制 不能只检查文件存在 ✅ 文件存在
tf-010 多入口项目 拆分 Taskfile ✅ 拆分多个 Taskfile.yml
tf-014 MUST_NOT 级别 MUST_NOT ✅ MUST_NOT
tf-002 preconditions preconditions ✅ preconditions

错误 (6/15) ❌

题目 模型回答 正确答案 分析
tf-009 复用值的作用域 "根作用域" vars 回答了位置而非关键词
tf-006 复用逻辑放哪 "子 Taskfile" 模板 task 概念混淆(includes vs 模板)
tf-011 CLI_ARGS 适用场景 "包装外部命令" 单一位置参数 回答太泛
tf-012 interactive 标记 "interactive 字段" interactive: true 语义正确但 keyword 没匹配上
tf-015 run 模式 "always" when_changed 真·错误
tf-013 修改啥会导致问题 "vars" silent 真·错误

结论

  • 模型在 核心概念(status/preconditions/deps/pipefail)上表现好
  • 细节区分(MUST vs MUST_NOT、when_changed vs always)上容易混淆
  • 60% baseline — 可以开始训练了,看看 SkillOpt 的 optimizer 能否通过分析失败模式来改进 SKILL.md

要开始跑训练吗?预计 4 epochs × 5 batch = 20 次 API 调用。


3️⃣ 关键训练指标

指标
总 steps 8
Accept 1
Reject 4
Skip 3
最佳 val score 0.3333(step 3)
最终 test score 0.5000(与 baseline 一致)
总 tokens ~494K
耗时 48 分钟

关键的变化不是加了多少内容,而是 SkillOpt 的 training loop 通过 analyst 分析失败 trajectory,识别出了原始 skill 中缺失的区分性知识— 模型需要的不是更多 YAML schema 描述,而是 requires/status/preconditions 三者的职责边界这类容易混淆但实际高频使用的知识。


好,收据收集够了。下面是完整的复盘分析。


这次优化实验的六个教训

1. SkillOpt 的核心瓶颈不在模型,在数据

这是最重要的教训。训练跑完 4 轮只产出了 1 个被 accept 的 patch,不是因为模型不好,而是因为:

数据集只有 10 条训练数据,其中还包含了"坏"的测试项。

看这个典型的例子:

问题:多处复用的逻辑应该放在哪里?
模型回答:将多处复用的逻辑封装在独立的 Taskfile 中,并通过 includes 指令引入。
期望答案:["模板 task", "模板任务"]
法官裁决:keyword_fallback → 0 分 ❌

模型的回答完全正确,但 gold answer 是狭窄的"模板 task",keyword matcher 匹配不上就给 0。这导致 analyst 看到"failure trajectory",分析后认为"技能缺了模板 task 的概念"——但实际上模型是对的,是数据的问题。

★ 启示:自动化优化的质量上限 = 数据集的质量下限。在扩大数据集之前,先确保每条数据的 gold answer 是合理且包容的。

2. LLM-as-judge 是最大的单点故障

法官(judge)的职责是判断模型答案是否正确,但如果法官自己都判不准,整个训练信号就坏了。

从数据看,你的 evaluator 有 107 次 judge 调用,其中一部分 fallback 到了 keyword_fallback——意味着 LLM judge 没有返回可解析的 JSON。而且当 gold answer 是"模板 task"而模型答案是完整句子时,keyword_fallback 也无法匹配。

Judge reason: keyword_fallback → 这意味着 LLM 未按格式回答
              keyword_fallback_exact → LLM 回答但关键词不完全匹配

★ 启示:在任何 LLM 评估链路中,judge 的可靠性决定了整个系统的可信度。如果 judge 经常 fallback,训练信号就有噪声。这在你手工迭代 prompt 时也同样成立——你依赖的是"目测"而非结构化评估。

3. Analyst 的有效性取决于 trajectory 的丰富度

前 3 次训练 analyst 全返回 0 个 edits,不是因为模型不行,而是因为:

  1. 没有 conversation.json — trajectory 为空,analyst 看不到模型是怎么回答的
  2. optimizer deployment 设错了 — 一直在用 Qwen/Qwen3.5-4B 而不是 deepseek-v4-pro

修复后,deepseek-v4-pro 作为 analyst 立刻生成了有意义的 patch:

{
  "failure_type": "missing_information",
  "patch": {
    "edits": [{
      "op": "append",
      "content": "常见关键字用途..."
    }]
  }
}

★ 启示:自动化优化的前提是对"失败"有足够的观察上下文。单轮 Q&A 的 trajectory 过于简单(只有问+答),缺乏推理过程。如果想让 analyst 产生更好的建议,需要让 trajectory 包含更多信息——比如模型的 reasoning trace。

4. 慢更新(slow_update)比快更新(analyst patch)更稳定

观察两种更新机制:

机制 生成次数 Accept 内容质量
Analyst patch(step 级) 5 次 1 次 (20%) 简单(关键字列表)
Slow_update(epoch 级) 2 次 force-injected 详细(完整策略指令)

Slow_update 通过对比两个 epoch 的性能差异,自动生成了大段的策略指令(requires/preconditions/status 的区分、vars:sh 约束等),而且它不需要经过 accept/reject 门控,直接注入到 skill 中。

★ 启示:慢速的、基于统计对比的更新比快速的、基于单步分析的更新更可靠。这对应到你的日常 prompt 迭代中——基于多次实验的统计观察("这个 prompt 在 10 个案例中提升了 8 个")比基于单次直觉的调整更有效。

5. 这次实验的 ROI 评估

总投入:

资源 消耗
训练轮次 4 次(含 debug)
API tokens ~1.4M
耗时 ~1.5 小时(含 debug 时间)
成本 估计 < $1(DeepSeek 便宜)

产出:

  • 验证分从 0.0000 → 0.3333
  • 测试分 0.5000(无变化)
  • Skill 新增 1 个核心知识节 + 3 个补充节
  • 识别出 2 条有问题的测试数据

★ 启示:SkillOpt 本身不是银弹,但作为"自动化回归测试 + 差异分析"工具是有用的。它最大的价值不是自动优化 skill,而是系统性地暴露了:哪些测试项持续失败、模型的常见混淆模式是什么、当前技能的覆盖盲区在哪里。这些信息对人工迭代更宝贵。

6. 对你最有价值的部分

不是最终的 SKILL.md 改动,而是这整个过程揭示的系统性问题

  1. 你的 skill 缺少概念区分层requires/status/preconditions 三者的边界模糊,模型(和可能的人类)都会混淆。这被你 skill 中的references/best-practices.yaml 的 items 涵盖了吗?如果 YAML 里也没有,那就是真缺口
  2. keyword_fallback 意味着"简答"型黄金答案容易误判合理回答 — 建议在数据集评审时考虑答案的表述多样性
  3. validation 集(CLI_ARGS / interactive / silent)完全不覆盖 skill 内容 — 这些是 skill doc 里没提到的知识,val set 应该测量"skill 能覆盖的内容"而非"模型本身的知识"

★ 总启示:这次实验的真正收获不是 skill 文本的增量改进,而是看到了一个可重复的、数据驱动的评估框架如何暴露知识盲区。这个"暴露能力"比自动修改能力更值得保留——以后你每次修改 skill,都可以用这个 eval 管道跑一轮,看到具体哪个 item 从错变对、哪个依然失败。这是持续的工程资产。


你觉得这个分析有道理吗?另外你的 references/best-practices.yaml 里有没有 requires/status/preconditions 的区分条目?如果 YAML 里也没有,那这个知识缺口确实值得补上。