🐎 第3章 授人以渔:Skills 工程实践
📄 一句话概括

技能可以放在四个地方:企业策略、用户记忆、项目记忆、插件。 四份同名时,只有一个生效,优先级从企业到插件递减。 这和记忆层的规则正好相反:记忆是叠加,技能是覆盖。同名就是整份覆盖,不是逐条合并。

📝 本章和前面几章的关系

上一节讲一个技能怎么被调用,这一节讲它从哪儿被找到。 这一节最好和第 2 章 2.2 节对着看:同一套四层结构,两套完全不同的合并规则。

一、四个地方

第一个是企业策略:组织统一下发,所有人都有,改不了。 第二个是用户记忆:放在用户主目录下,跨项目生效,跟着人走。 第三个是项目记忆:放在仓库里,跟着代码走,团队共享。

第四个是插件:别人写好的,装上就有,谁都能发布。 四个地方都能放技能,扫描的时候全扫一遍,然后按名字去重。 优先级数字从企业往插件递减:企业最高,插件最低。

为什么插件最低?因为它是别人写的,不能盖掉你自己项目的规矩。

二、扫描与去重

扫描的动作很简单:把四个位置都走一遍,收集所有 SKILL.md,按名字分组。 同名的一组里,只留优先级最高的那份,其余的被遮蔽。 演示里四份都叫 deploy-check,优先级四三二一,最后只剩企业那份生效。

没有同名的照旧都在:release-note 和 security-scan 各出现一次,扫描后都活着。 所以能用的技能总数不是文件数,是去重之后的个数。四个位置放二十份同名文件,最后只有一个能用。

三、被遮蔽不等于被删除

被遮蔽的那三份还在磁盘上,只是这一层扫描时被更高优先级的同名项挡住了。 这个区别带来一类很难查的问题:「我改了技能怎么没反应」。 你改的是项目里那份,实际生效的是企业那份,改完一点变化没有——而且没有任何提示。

查的办法是看扫描结果里这个技能来自哪个目录。 多数实现会打出「这个技能从哪加载」的日志,或者有个列出全部技能的命令。 养成一个习惯:改技能之前先确认它现在是从哪加载的。这一步花十秒,能省半小时。

四、整份覆盖的坑

同名覆盖是整份覆盖,不是逐条合并。这一条是这套机制最容易踩的坑。 举个具体场景:企业版写死了内网审批流程,项目里想再补一项灰度检查。 你在项目里放了一份同名技能,写了内网审批加灰度检查两段。 结果不是「两份合并」,是「企业那份整个不生效,项目那份整个生效」。 也就是说,只要企业版还在,你的项目版就永远被遮蔽,补的那一项进不去。

反过来也一样:你把项目版删了,企业版回来,但你想加的那一段也没了。 想在企业版基础上加东西,只有一条路:复制一份、改名之外的内容照抄,然后在项目这块自己维护这份副本。 企业版以后更新了,你得手动跟。 这就是「继承」缺位的代价。四层作用域给的是「优先级」,不是「继承链」。

五、和记忆层那套的差别

第 2 章的五层记忆是叠加:五层全读进来,十三条就是十三条,冲突时越具体越赢。 技能是覆盖:同名只留一份,其余的不进上下文。 为什么会不一样?因为两者的目标是相反的。

记忆要的是「把所有约束都拿到」,多一条约束不会让模型做错事,所以宁可全读、冲突时按就近原则挑。 技能要的是「这件事只有一种做法」。 两份同名技能同时生效,模型会照着两份自相矛盾的流程做,那比没有更糟。 所以记忆可以叠加,技能必须唯一。同一条原理,两种合并策略。

六、实际怎么摆

企业层放「必须统一」的:合规检查、发布流程、审计上报。数量应该很少。 用户层放「我个人习惯」的:提交信息模板、代码风格偏好。跟着人走,换项目还在。 项目层放「这个仓库特有」的:这个项目的构建命令、目录约定、部署步骤。这是最多的一层。

插件层放「通用能力」的:各种语言的最佳实践、常见框架的脚手架。别人维护,你只是用。 分层的判据和记忆层一样:这条规矩该在多大范围里生效。范围越大放得越靠上。 唯一要额外记住的是:范围大意味着「优先级高」,也就是「会盖掉下面的」。 所以企业层放得越多,项目自己越没有余地。

七、动手 Demo:四个地方都叫 deploy-check,最后用哪个

造四份同名技能,分别放在企业策略、用户记忆、项目记忆、插件四个位置,优先级四三二一。 再放两份不同名的,看它们会不会被误伤。最后看这条规则带来的两个实际问题。

FOUND = [(u"企业策略", 4, u"deploy-check"), (u"用户记忆", 3, u"deploy-check"),
         (u"项目记忆", 2, u"deploy-check"), (u"插件", 1, u"deploy-check"),
         (u"项目记忆", 2, u"release-note"), (u"用户记忆", 3, u"security-scan")]

best = {}
for where, pri, name in FOUND:
    if name not in best or pri > best[name][1]:   # 同名只留优先级最高的
        best[name] = (where, pri)

实跑输出:

--------------------------------------------------------------------
四个地方都叫 deploy-check,最后用哪个
--------------------------------------------------------------------


  ① 四份同名,四份都在磁盘上
  --------------------------------------------------------------------
| 放在哪 | 优先级 | 技能名 |
|---|---:|---|
| 企业策略 | 4 | deploy-check |
| 用户记忆 | 3 | deploy-check |
| 项目记忆 | 2 | deploy-check |
| 插件 | 1 | deploy-check |

  优先级数字越大越优先。企业最高,插件最低——插件是别人写的,不能盖掉你自己项目的规矩。

  ② 扫描之后,只剩一个生效
  --------------------------------------------------------------------
| 技能名 | 来自 | 优先级 | 结果 |
|---|---|---|---|
| deploy-check | 企业策略 | 4 | 生效 |
| deploy-check | 用户记忆 | 3 | 被遮蔽 |
| deploy-check | 项目记忆 | 2 | 被遮蔽 |
| deploy-check | 插件 | 1 | 被遮蔽 |

  ! 被遮蔽的那三份不是删掉了,是这一层扫描时被更高优先级的同名项挡住了。
  所以「我改了技能怎么没反应」这类问题,第一个要查的就是有没有同名的高优先级副本。

  ③ 不同名的照旧都在
  --------------------------------------------------------------------
| 技能名 | 出现次数 | 扫描后 |
|---|---:|---|
| deploy-check | 4 | 4 个同名 |
| release-note | 1 | 一个 |
| security-scan | 1 | 一个 |

  deploy-check 出现四次,扫描后只有一个;另外两个各出现一次,都活着。
  所以能用的技能总数不是文件数,是【去重之后的个数】。

  ④ 这条规则带来的两个实际问题
  --------------------------------------------------------------------
  第一个是调试难。你以为改了项目里那份,实际生效的是企业那份,改完没反应。
  查的办法是看扫描结果里这个技能来自哪个目录。
  第二个是加不上去。
  企业版写死了内网审批,项目里想再补一项灰度检查——只要企业版还在,项目版就整个不生效,
  补的那一项永远进不去。
  ! 所以同名覆盖是【整份覆盖】,不是逐条合并。
  想在企业版基础上加东西,只能复制一份改成项目版,然后自己维护这份副本。这是这套机制最容易踩的坑。

①四份同名、四份都在磁盘上,优先级四三二一。 企业最高,插件最低——插件是别人写的,不能盖掉你自己项目的规矩。 ②扫描之后只剩一个生效,另外三份被遮蔽。被遮蔽不是删掉,是这一层扫描时被更高优先级的同名项挡住了。 所以「我改了技能怎么没反应」这类问题,第一个要查的就是有没有同名的高优先级副本。 ③不同名的照旧都在:release-note 和 security-scan 各出现一次,扫描后都活着。 所以能用的技能总数不是文件数,是去重之后的个数。四个位置放二十份同名文件,最后只有一个能用。 ④这条规则带来的两个实际问题:调试难——你以为改了项目那份,实际生效的是企业那份; 加不上去——企业版写死了内网审批,项目里想补一项灰度检查,只要企业版还在,项目版就整个不生效。 所以同名覆盖是整份覆盖,不是逐条合并。 想在企业版基础上加东西,只能复制一份改成项目版,然后自己维护这份副本。 这一点和第 2 章的记忆层正好相反:记忆是叠加、冲突时就近赢,技能是覆盖、只留一份。

30 秒实验

  1. 把「插件」那份的优先级改成五(最高),重跑第 ② 步。谁生效? 这说明优先级数字是可以被配置改的,还是固定死的?
  2. 在项目记忆里放一份叫 deploy-check-v2 的技能(改了名),重跑第 ③ 步。它会被遮蔽吗? 这份副本和企业版之间是什么关系?
  3. 把四份同名文件换成四份内容不同的同名文件,重跑一遍。扫描结果能告诉你「哪份内容生效」吗? 如果不能,调试时该看什么?

常见误区

  1. 以为同名技能会逐条合并。是整份覆盖——高优先级那份生效,低的那份一个字都不进上下文。
  2. 改了项目里的技能却没反应,就去怀疑语法或缓存。先查有没有同名的高优先级副本。
  3. 把该放项目层的技能放到用户层。用户层跨项目生效,会盖掉别的项目里同名的那份。
  4. 以为四层作用域是「继承」。它只给优先级,不给继承链; 想在企业版基础上加内容,只能整份复制自己维护。
  5. 把技能的分层规则照搬到记忆层(或反过来)。记忆是叠加,技能是覆盖,两套规则不能混用。
自测三问(点开对答案) 1. 四个技能作用域分别是什么,优先级怎么排? —— 企业策略、用户记忆、项目记忆、插件。 优先级从企业到插件递减,因为插件是别人写的,不该盖掉自己项目的规矩。 2. 同名技能是合并还是覆盖? —— 整份覆盖。优先级最高的那份生效,其余的被遮蔽,一个字都不进上下文。 3. 为什么记忆层可以叠加,技能层必须唯一? —— 记忆要的是把所有约束都拿到,多一条不会让模型做错事; 技能要的是「这件事只有一种做法」,两份同时生效会让模型照着矛盾流程做。

作用域清楚了,下一节动手把三类技能各建一份,看结构差在哪。

相关笔记