Skip to content

技能设计:把能力写成按需加载的单元

技能(skill)是智能体在需要时才加载的一小块能力,形态通常是一个带元信息的文件加若干参考文件与脚本。它和提示词最大的区别是:提示词是这次说的话,技能是长期维护的资产。这篇讲我在科研工作流套件里踩出来的写法。

先说结论

  • 技能好不好用,主要不取决于正文写得多全,而取决于触发条件写得够不够窄
  • 反直觉的一点:正文越长,被正确调用的概率越低——一次加载就灌满上下文,技能反而成了负担,所以要渐进披露;
  • 边界(不许做什么)和触发条件同等重要,缺了它,技能会改掉不该改的数据;
  • 技能必须可验收,而验收主要靠负例:说"这种情况不该调用它"时,它有没有真的不调用。

一、从一段长提示词到 13 个模块

2026 年 7–8 月,第二个课题又要把"选题—训练—验证—写作—画图"流程重搭一遍。第一版做法很直接:把全流程写成一段长提示词,四千多字,从数据划分写到论文插图。

现象很快就有了:主流程要么整段加载后仍然漏步骤(比如忘了在实验前写判定标准),要么干脆不用它、自己临时发挥;出错时也无法定位——四千字是一个整体,说不清哪一步没执行。

排查方式是把长提示词按阶段切开,逐块看有没有被调用、哪一步被跳过。原因不在内容少,而在没有触发条件:模块不知道"现在轮到我了"。切开之后的形态是 13 个技能模块,加上约 20 个确定性脚本和 90 余项测试;再配上总入口负责判断阶段、按需路由。第二个反转在脚本上:确定性步骤抽出来单独测试之后,测试才有意义——90 余项测试覆盖脚本,不覆盖判断。

二、技能与提示词的区别

维度提示词技能
生命周期这次会话长期,可复用,随项目版本管理
加载时机每次都占用上下文命中触发条件才加载
可测试性只能看结果触发用例 + 脚本测试,可回归
演进方式随手改走提交记录,可回滚、可对比

三、触发条件与边界

触发条件要写两边:什么时候该调用、什么时候不该。只写正面条件,技能会到处抢活:

yaml
name: figure-export
triggers:
  - 把实验结果导出成论文用图
  - 同一批图要重复生成、格式一致
do_not_use:
  - 一次性示意图(直接画更快)
  - 数据还没定稿(图会重画)
requires:
  - results/metrics.json 已存在

边界写"不许做什么",和触发条件一样具体:

text
- 原始实验记录只读
- 不改数据划分与随机种子
- 不在画图脚本里重算指标(只读 metrics.json)

边界不是形式主义:硬件设计流水线的 9 个技能模块按阶段划分(拓扑讨论 → 原理图 → 布局 → Gerber),每个模块只碰本阶段产物,上一阶段产物不齐不进入下一阶段。它挡住的是"边改电路边改布局"这类互相干扰。

四、渐进披露:正文只放最关键的

技能正文只保留四样:触发条件、步骤骨架、边界、产物路径。细节放被链接的参考文件,正文写明"什么时候去读哪个文件":

text
skills/
├─ research-workflow/SKILL.md      # 总入口:判断阶段,路由到子模块
├─ data-split/SKILL.md             # 触发 / 骨架 / 边界 / 产物
│   └─ references/split-protocol.md  # 细节:分层与种子约定
└─ scripts/
    ├─ split_dataset.py            # 确定性:同输入同输出
    └─ tests/                      # 90 余项测试挂在这里

原因是一次加载的成本:正文里的细节,每个命中它的任务都要付一遍,而多数任务只需要其中一小部分。

性价比最高的一步

给正文设一个行数上限(我定的是 120 行),超了就把细节挪进 references。这个约束逼着你判断"什么必须每次都知道"。

五、验收:怎么知道技能被正确调用

验收的对象是"调用行为",不是输出好不好看。每个模块准备一组触发用例,正例负例都要:

text
正例:导出这次实验的结果图        → 应调用 figure-export
正例:按上次格式重画第 3 组图      → 应调用 figure-export
负例:画一张流程示意图            → 不应调用
负例:数据还在跑,先看图          → 不应调用(前置产物缺失)

跑一遍用例,把"该调的没调""不该调的调了"分开计数,两类都为零,触发条件才算合格。再叠一层脚本测试:约 20 个确定性脚本由 90 余项测试覆盖,保证同样输入同样输出。

容易踩的坑

只测正例会让技能越来越"积极":任何沾边的任务都想加载,抢掉本该由主流程判断的事。负例才是真正的约束力。

六、脚本与判断的分界线

分界线只有一条:同样的输入是否必须得到同样的输出。 是,做成脚本;不是,留在技能里由模型判断。

判据归脚本留在技能(判断)
输入输出同样的输入必须同样输出依上下文取舍
出错的代价静默错误,必须靠测试兜住可复核,人能兜底
例子数据划分、指标计算、图表生成、记录模板填充这个方法是否值得试、结论能不能写、是否进入下一阶段

把确定性部分抽干净,剩下的判断才会被认真对待;反之,让脚本"顺手"决定划分比例,测试就失去意义。

七、可复用的清单

  • 一件事会在下个项目重现,就写成技能;不会,就留在提示词里;
  • 触发条件写两栏:该调用、不该调用;
  • 边界写"不许做什么",具体到文件与字段;
  • 正文不超过 120 行,细节放 references 并写明何时去读;
  • 每个技能配正例与负例触发用例,两类错误分别计数;
  • 同样输入必须同样输出的工作抽成脚本,用测试覆盖;

由 VitePress 构建 · 部署于 Cloudflare Pages 与 GitHub Pages

热爱 DeepSeek V4.1 Flash · 快、省、够用,一个人也能把整条流水线跑完