作者复盘 Cursor 编辑流水线,发现“每个动作一个技能”的拆分方式无法适应同一 Notion 卡片持续创建、补充和重分类的领域生命周期。实践说明技能边界应围绕业务对象及其状态变化设计,而非机械对应单次操作。
我一直在 Cursor 中搭建一套 AI 辅助的编辑流水线。Notion 卡片用于记录观察,skills 负责评分和排期,Agents 则起草 markdown,最终同步到 dev.to。在这套系统中,skill 是一个 markdown 文件:当你调用某个工作流时,Agent 会加载它。这个文件定义了 Agent 可以做什么、禁止做什么,以及如何在各个子步骤之间进行路由。
刚开始时,我觉得最安全的模型是:每个操作对应一个 skill。在这里创建卡片,在那里丰富卡片,再到别处重新分类。每个 prompt 都有清晰的边界,每个文件也都保持得很小。这种拆分方式看起来很符合良好的工程实践。
但这个假设逐渐开始与实际领域模型产生冲突。
我的 Inbox skill 第一版只负责创建 Inbox 卡片。这与早期的使用方式相符:捕获一条观察,将其规范化为标准结构,附上一小组有依据的参考信息,然后停止。这个 skill 只负责创建,并且把每张离开 Inbox 的新卡片视为不可变对象。
随着捕获流程逐渐成熟,同一张卡片在仍处于 Inbox 阶段时,往往需要继续处理:
当出现新的观察时,执行 Create
当新的证据或叙事角度改变了规范化结构时,执行 Enrich
当路由规则判定卡片应该从精简变为丰富,或者应该从快速笔记变为计划中的博客文章时,执行 Reclassify
它们看起来像三项不同的工作。使用的动词不同,检索触发条件也不同。把它们拆成独立的 skills,似乎是显而易见的选择。
但这种拆分在处理日常修正时失败了。我会先用新证据丰富一张 Inbox 卡片,随后又意识到,它应该从快速笔记改成计划中的博客文章。这意味着还要第二次调用 reclassify skill,并在其中维护同一套生命周期规则的第二份副本。那一刻,究竟该由哪个 skill 负责确保页面始终只有一份当前版本的内容,而不是逐渐累积成编辑历史,并不明确。如果顺序弄错,就会重复劳动:要么 enrich 完成后卡片类型仍然过时,要么 reclassify 忽略了仍然需要完成的证据重写。
更深层的问题在于所有权。这三个操作处理的是同一个归属对象:Notion 数据库中的一张 Inbox 卡片。它们共享同一个生命周期门槛——卡片必须仍然位于 Inbox;共享相同的修改边界——对于已有页面,绝不能修改生命周期状态、来源路径或已发布 URL;也共享相同的路由规则——决定卡片应该精简还是丰富,以及它应该是一篇快速笔记还是一篇计划中的文章。它们还共享同一条规则:每次更新后,页面必须恰好包含一份当前的规范化内容,以及恰好一条捕获到的观察。Notion 历史记录才是修订日志;实际使用中的卡片并不是只能追加的审计日志。
把 Create、Enrich 和 Reclassify 当成三个 skills,意味着要让三个 prompts 共同维护一项连贯的能力。边界被划在了错误的层级上。
解决办法是不再假装它们是彼此独立的能力。现在,一个 inbox skill 负责完整的 Inbox 生命周期:只要卡片仍在 Inbox 中,就由它处理 Create、Enrich 和 Reclassify。
操作者仍然只需调用一个 skill,由 skill 在内部进行路由:
Reclassify 不再是一个独立的用户命令。当路由规则判定卡片应该比之前更丰富或更精简,或者应该从快速笔记转变为计划中的文章时,系统会在 enrich 内部检测到这一点。精简捕获可以变成内容更丰富的现场报告。当这些派生选择发生变化时,skill 会重建当前的 Inbox 表示,而不是不断追加新的内容丰富历史章节。
这次合并让 inbox skill 从“创建后不可变”扩展为“拥有整个 Inbox 生命周期”。skill 文件变大了,但系统反而更简单:一个地方负责 Inbox 规范化,一套共享规则,只有一个地方拥有这些规则的管理权限。
这与我原本的预期正好相反。我原以为,更大的 skill 文件会显得更笨重。但实际上,路由变得更容易了。我不再纠结:修正内容和把笔记改成文章,分别应该调用哪个 inbox skill。我只需调用 inbox skill,再由路由规则决定 enrich 是否包含 reclassify。
这次经历可以归纳出一套简短的“合并还是拆分”判断标准:
在同一个生命周期门槛下操作同一个归属对象。如果生命周期阶段或产物类型发生分化,就不要继续合并。
修改规则和安全边界彼此兼容。如果这些操作需要相互冲突的写入权限,或者需要无法由同一权威主体统一管理的拒绝规则,就应该保持分离。
不同操作共享相同的类型与结构规则。对于相同输入,如果这些操作会对它最终应该变成什么产生分歧,就应该保持分离。
这些属于内部操作,而不是独立的能力。
流水线的其他部分其实早已有一个类似的例子。triage skill 会为 Inbox 卡片评分,建议将卡片从 Inbox 提升到后续阶段,并归档最弱的记录。它们属于不同的修改操作,但都位于同一个 triage skill 中,因为它们共同承担队列审查的所有权。我没有把 score、promote 和 archive 拆成三个 skills。操作虽然不同,但它们负责的工作流并没有改变。
当然,这种类比也有边界。Triage promotion 在生成 dry-run 报告之后,需要显式的 apply 命令才能执行。Inbox enrich 则会拒绝处理已经离开 Inbox 的卡片。内部的门槛可以不同,并不意味着必须拆分所有权。其模式仍然清晰可辨:每项连贯的能力对应一个 skill,并在内部的不同操作之间进行路由。
这并不意味着所有相关操作都应该塞进同一个 skill。Scheduling、drafting、critique 和 publishing 分别负责不同的产物,也有各自的终止边界,因此它们仍然保持独立。
即使不用 Cursor,你也能识别出这种结构。REST API 通常不会因为同一资源上的每个操作都不同,就把它们分别做成独立服务。
POST 负责创建,PATCH 负责更新,DELETE 负责删除。操作不同,但共享同一个资源契约。在我的系统中,Reclassification 只是对同一张 Inbox 卡片资源的另一种修改。
把这些操作拆成独立的 Agent skills,就像为创建构建一个服务、为更新构建另一个服务,再为删除构建第三个服务。单独来看,每个端点都很清晰,但资源的所有权却被割裂了。
Agentic 工作流很容易滑向这种拆分方式,因为操作比所有权更容易命名。“Create card”和“enrich card”都是形象鲜明的动词。“在整个 Inbox 生命周期内负责 Inbox 规范化”虽然准确,却更加抽象。动词让 skills 很容易命名,而资源则揭示了真正应该划定边界的位置。
你的领域可能会采用不同的拆分方式。真正有用的问题不是“我有多少个 skills?”,而是“这项能力拥有哪个对象?这些动词只是针对该对象的不同操作,还是代表完全不同的能力?”
核心结论:如果“每个操作对应一个 skill”能帮助你尽快交付,那就从这里开始。但当多个操作共享同一个归属对象、生命周期以及彼此兼容的安全边界时,应当把它们合并为一个能力模块,并在内部进行路由。真正的风险已经不再是某个 skill 变得过于宽泛,而是同一项能力出现多个相互竞争的所有者。
如果你想看看这些工作流实验背后的项目,可以试试 Codenames AI。
对于后续操作,你可以考虑屏蔽此人和/或举报滥用行为。