当我们谈论 AI Agent 框架时,往往关注的是模型能力、工具调用或是工作流编排,却忽略了一个核心问题:技能(Skill)本身是如何被声明、注册并自动触发的。Superpowers 作为一款面向编码 Agent 的技能框架,提供了一套完整的声明式注册与自动触发机制,使得 Agent 能够在合适的时机调用合适的技能,而无需人工干预。本文将从工程实现角度,解析这一机制的设计细节与可落地参数。
技能定义的结构设计
Superpowers 中的技能并非简单的函数,而是一种声明式的能力对象。每个技能定义包含以下几个核心字段:
元数据层承载技能的身份信息,包括名称、描述、标签和用途说明。这些信息不仅用于人类理解,更重要的是供注册中心和触发匹配器使用。名称采用小写加连字符的命名规范,如 test-driven-development、systematic-debugging,确保全局唯一性。
输入输出模式定义了技能的契约边界。Superpowers 推荐使用结构化模式(如 JSON Schema 或 Zod)来描述输入输出,使得技能调用可以提前验证参数合法性,也为后续的自动化测试和类型安全提供保障。
触发条件是技能系统的核心机制。它不只是一个简单的布尔开关,而是一个由多个匹配器组成的复合条件。匹配器可以基于意图(Intent)判断,如检测用户是否在讨论 “设计规范”;也可以基于上下文(Context)判断,如当前是否处于测试阶段、是否存在失败的测试用例等。触发条件还支持优先级设置,确保在多个技能同时匹配时能够有序选择。
执行处理器是技能的业务逻辑载体。它接收经过模式验证的输入和完整的 Agent 上下文,执行具体的任务,并返回结构化的结果。处理器的设计应当是纯函数式的,便于单元测试和结果复现。
注册中心的实现模式
Superpowers 采用模块级声明配合中心注册表的模式来实现技能的自动发现。注册中心是一个单例对象,维护着一个技能列表,并提供注册、查询和匹配的核心方法。
class SkillRegistry {
private skills: SkillDefinition<any, any>[] = [];
register(skill: SkillDefinition<any, any>) {
this.skills.push(skill);
}
findTriggered(ctx: AgentContext, intent: string) {
return this.skills.filter(s =>
s.triggers.some(t =>
(t.always ?? false) ||
(t.matchIntent?.(intent) ?? false) ||
(t.matchContext?.(ctx) ?? false)
)
).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
}
}
注册中心的核心方法 findTriggered 接收当前上下文和意图标签,返回所有匹配触发条件的技能,并按优先级排序。这一设计确保了触发决策与执行逻辑的分离,符合开闭原则。
为了让技能能够自动被发现,Superpowers 提供了 defineSkill 辅助函数。每个技能文件只需要调用此函数并导出定义,模块被导入时就会自动执行注册逻辑。这种.side-effect 式的设计避免了手动 wiring 的繁琐,也使得技能的添加、删除和版本管理变得简单。
export const brainstormingSkill = defineSkill({
name: "brainstorming",
description: "Socratic design refinement before writing code",
inputSchema: z.object({ idea: z.string() }),
outputSchema: z.object({ refinedSpec: z.string() }),
triggers: [
{
matchIntent: intent => intent === "design_discussion",
},
],
priority: 10,
handler: async ({ idea }, ctx) => {
// Socratic questioning logic
return { refinedSpec: /* ... */ };
},
});
在框架启动时,系统会通过动态导入或文件扫描的方式加载所有技能模块,完成注册过程。开发者只需在 skills/ 目录下新增文件,无需修改其他代码。
触发机制的工作流程
自动触发是 Superpowers 区别于传统工具调用的关键所在。它的触发流程分为四个阶段:意图推断、技能匹配、智能路由和结果整合。
意图推断是触发流程的起点。Agent 在每次循环开始时会分析当前对话状态和计划步骤,提取出意图标签。这个标签可以是简单的字符串(如 design_spec、write_tests、refactor_code),也可以是更复杂的结构化表示。意图推断可以基于规则匹配,也可以由 LLM 本身完成分类。
技能匹配阶段调用注册中心的 findTriggered 方法,传入当前上下文和推断出的意图,返回所有满足触发条件的技能候选列表。匹配过程严格遵循触发条件的逻辑:只要任意一个触发器的条件满足,该技能就会进入候选队列。优先级字段确保了当多个技能匹配时,高优先级的技能会被优先考虑。
智能路由是可选的增强层。当候选技能数量大于一时,系统可以将候选技能作为工具描述提供给 LLM,让模型根据当前上下文选择最合适的技能。这种设计充分利用了 LLM 的推理能力,避免了硬编码的 if-else 逻辑。
结果整合将技能执行的结果写入 Agent 上下文,供下一个循环使用。整合过程应当保持上下文的连续性,确保技能之间能够有效地传递信息。
触发条件的工程实践
在实际工程中,触发条件的设计需要平衡精确性和覆盖率。Superpowers 支持四种主要的触发模式:
基于意图的触发适用于明确的任务切换场景。例如,当用户提出 “我想规划这个功能” 时,系统检测到 design_spec 意图,随即触发 brainstorming 技能。这种模式的优点是精确度高,用户意图明确时几乎不会误触发。
基于阶段的触发适合工作流驱动的场景。Superpowers 定义了完整的开发流程:brainstorming → using-git-worktrees → writing-plans → subagent-driven-development → test-driven-development → requesting-code-review → finishing-a-development-branch。每个阶段对应特定的技能集合,阶段转换时自动触发相关技能。
基于上下文的触发最为灵活,可以根据文件状态、测试结果、Git 状态等动态决定是否触发。例如,当检测到存在失败的测试用例时,systematic-debugging 技能会自动激活,引导 Agent 进行四阶段的根因分析。
基于显式标记的触发提供了人工干预的入口。用户可以通过特定指令(如 /plan、/debug)显式调用技能,这在前三种自动触发无法满足需求时作为兜底方案。
以下是一个综合的触发条件配置示例,展示了如何组合多种触发模式:
triggers: [
{
matchIntent: intent => intent === "write_tests",
},
{
matchContext: ctx => ctx.currentStep?.type === "testing",
},
{
matchContext: ctx => ctx.hasFailingTests && !ctx.hasDebugged,
},
],
实践建议与监控要点
在生产环境中使用 Superpowers 的声明式注册和触发机制时,有几个关键点值得关注。
首先是技能的粒度控制。每个技能应当聚焦于单一职责,避免功能的过度膨胀。Superpowers 官方技能的粒度控制在一个完整的开发子任务级别,如 “编写测试计划” 或 “执行子 Agent 开发”。过细的粒度会导致触发频繁、上下文切换成本增加;过粗的粒度则会降低技能的复用性。
其次是触发条件的测试。由于触发逻辑涉及意图推断和上下文匹配,需要建立专门的测试套件来验证各类场景下的触发正确性。建议模拟不同的上下文状态(有无测试失败、当前处于哪个开发阶段),确认技能能够在预期时机激活。
第三是监控与可观测性。在生产环境中,应当记录每次技能触发的输入参数、执行耗时和输出结果。这些数据是优化触发条件和技能实现的重要依据。关键监控指标包括:触发成功率(匹配到的技能中实际执行的比例)、触发延迟(从意图推断到技能执行完成的时间)、技能冲突率(多个技能同时匹配需要路由的频率)。
最后是版本管理机制。Superpowers 支持技能的自动更新,但这也带来了兼容性风险。建议在引入新技能或修改触发条件时,采用灰度发布策略,先在部分会话中验证效果,再全量推广。
资料来源
本文核心信息来源于 Superpowers 官方 GitHub 仓库(https://github.com/obra/superpowers),该仓库包含了完整的技能框架实现、工作流定义和安装配置文档。