ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Superpowers 技能框架:让 AI 编程代理行为可预测的工程实践

Superpowers 技能框架:让 AI 编程代理行为可预测的工程实践

1. 从“superpowers”说起:这套 agentic skills framework 到底在解决什么问题

第一次看到 “superpowers” 这个词,是在几个做 AI 编程工具链的朋友群里。有人甩了个链接,配文是“终于有人把 agentic skills framework 这件事讲明白了”。点进去看完之后,我的第一反应是:这东西解决的不是“AI 能不能写代码”的问题,而是“AI 写代码时到底听谁的、按什么规矩来”的问题。

说白了,superpowers 是一套面向 AI 编程代理的技能框架和方法论。它不绑定某一个具体的工具,而是试图定义一套通用的“技能描述规范”,让 Claude Code、Codex CLI 这类命令行 AI 编程工具能够按照统一的逻辑去理解任务、拆解步骤、调用能力、验证结果。你可以把它理解成给 AI 代理写的一份“岗位说明书 + 操作手册 + 质量检查清单”的合集。

为什么这件事值得单独拿出来讲?因为过去大半年,我身边大量开发者都在用 Claude Code 和 Codex CLI 干活,但几乎每个人都踩过同样的坑:AI 一开始表现得像个天才,写着写着就开始胡编 API、跳过测试、把简单问题复杂化。你骂它两句,它道歉,然后换个姿势继续错。问题的根源不在于模型不够强,而在于我们从来没有认真告诉过它“在这个项目里,什么叫做把活干好”。

superpowers 这套框架的核心主张就是:与其反复在对话里纠正 AI,不如把技能、约束、验证标准提前结构化地定义好,让代理在框架内自主运转。这跟传统的“提示词工程”是两种思路——后者是你在每次对话里临时调教,前者是你一次性把规矩立好,之后代理自己按规矩办事。

这篇文章适合三类人看:第一类是想把 Claude Code 或 Codex CLI 真正用进日常开发流程的工程师;第二类是在团队里负责搭建 AI 辅助开发规范的技术负责人;第三类是对 agentic skills framework 这个概念感兴趣、想搞清楚它和普通 prompt 有什么区别的探索者。我会从设计思路、核心机制、实操落地、常见坑四个维度把它拆开讲,尽量做到你看完就能上手改自己的配置。

2. 核心设计思路拆解:为什么是“技能框架”而不是“提示词模板”

2.1 从“对话式调教”到“结构化技能定义”的转变

大部分人用 Claude Code 的方式是这样的:打开终端,输入一句“帮我重构这个模块”,然后看它表演。它改得不对,你就补一句“不要动那个函数”,它再改,你再补。整个过程像在带一个记性不太好但手很快的实习生。

这种模式在任务简单时还能凑合,一旦任务涉及多个文件、多个步骤、多个验证环节,就会迅速失控。原因很简单:对话是线性的、易失的,而软件开发是网状的、有状态的。你在第 3 轮对话里强调的约束,到第 15 轮可能已经被淹没在上下文里了。

superpowers 的思路是把“约束”和“技能”从对话流里抽出来,变成独立的、可复用的、有明确触发条件的定义。一个技能定义通常包含几个要素:这个技能叫什么、什么时候该用它、用它的前提是什么、具体步骤是什么、做完之后怎么验证、失败了怎么回退。这跟人类团队里写 SOP 的逻辑是一样的——不是每次遇到问题都重新讨论一遍怎么做,而是把成熟的做法固化下来。

我自己的体会是,当你把三五个核心技能定义清楚之后,Claude Code 的表现会有肉眼可见的变化。它不再需要你反复提醒“记得跑测试”,因为测试验证已经写进了技能定义里;它也不会动不动就重构半个项目,因为技能定义里明确了改动范围的边界。

2.2 技能框架与工具链的解耦设计

superpowers 另一个让我觉得设计得聪明的地方,是它刻意和具体工具解耦。Claude Code 有它自己的 skill 机制,Codex CLI 有它自己的配置方式,但 superpowers 试图抽象出一层通用的描述逻辑。

这意味着什么?意味着你为项目写的一套技能定义,理论上可以在不同工具之间迁移。今天你用 Claude Code,明天想试试 Codex CLI,不需要把整套规范推倒重来。当然,实际迁移时肯定有适配工作,但至少核心逻辑是复用的。

这种解耦设计背后有一个判断:AI 编程工具的格局远未定型,今天的主流工具明年可能就换人了。如果把所有规范都绑死在某个工具的私有格式上,迁移成本会高到让你不想换工具。而技能框架作为中间层,保护的是你团队积累的方法论资产,而不是某个具体工具的配置。

我在实际项目里是这么做的:把技能定义写成相对中立的 Markdown 文档,然后用一层薄薄的适配脚本把它转换成 Claude Code 或 Codex CLI 能识别的格式。这样核心内容只有一份,工具相关的部分尽量薄。

2.3 为什么“验证闭环”是这套框架的灵魂

如果只能从 superpowers 里保留一个设计理念,我会选“验证闭环”。这是它和普通提示词模板最本质的区别。

普通提示词模板告诉你“怎么做”,但不管“做完怎么确认做对了”。而 superpowers 的每个技能定义里,验证环节是强制的、不可省略的。比如一个“实现新功能”的技能,它的验证环节可能包括:单元测试是否通过、类型检查是否干净、是否引入了新的 lint 警告、改动是否影响了其他模块的测试。

这个设计直接对应了 AI 编程最大的痛点:它会非常自信地告诉你“完成了”,但实际上根本没完成,或者完成的方式引入了新问题。有了强制验证闭环,代理就不能靠嘴说“搞定了”,必须拿出证据。

我踩过的一个坑是:早期我写的技能定义里验证环节太模糊,只写了“确保代码质量”。结果 Claude Code 的验证方式就是自己读一遍代码然后说“看起来没问题”。后来我把验证改成具体的命令和预期输出,比如“运行npm test,所有测试必须通过;运行tsc --noEmit,不能有类型错误”,它的行为立刻就规范了。验证标准必须可执行、可观测,不能是主观判断。

3. 核心机制与实操要点:技能定义到底怎么写

3.1 技能定义的五个必备要素

经过几个项目的迭代,我总结出一套技能定义的最小结构。每个技能至少包含五个部分,缺一个都会导致代理行为不稳定。

触发条件:什么情况下该用这个技能。写得越具体越好,不要写“需要写代码时”,而要写“当用户要求新增一个 API 端点,且该端点需要访问数据库时”。

前置检查:动手之前必须确认的事情。比如“确认当前分支是 feature 分支”“确认依赖已经安装”“确认相关测试当前是通过的”。前置检查能避免代理在错误的状态下开始工作。

执行步骤:具体的操作序列。这里的关键是步骤要原子化,每一步都有明确的输入和输出。不要写“实现业务逻辑”这种大而化之的话,要拆成“在 models 目录下创建数据模型”“在 services 目录下实现业务方法”“在 routes 目录下注册端点”。

验证方法:怎么确认这一步做对了。必须是可执行的命令或可观测的结果。

回退策略:如果验证失败怎么办。是重试、是回滚、还是停下来问人。这个要素最容易被忽略,但恰恰是保证代理不把事情搞砸的关键。

下面是一个简化版的技能定义示例,用 Markdown 写,方便人和工具都能读:

## 技能:新增 API 端点 ### 触发条件 用户要求新增一个需要访问数据库的 REST API 端点。 ### 前置检查 - 当前分支为 feature 分支 - 依赖已安装(node_modules 存在) - 现有测试全部通过 ### 执行步骤 1. 在 src/models/ 下创建或修改数据模型 2. 在 src/services/ 下实现业务逻辑方法 3. 在 src/routes/ 下注册端点并绑定 service 方法 4. 在 tests/ 下补充对应的单元测试 ### 验证方法 - 运行 `npm test`,全部通过 - 运行 `npm run lint`,无新增警告 - 手动 curl 端点,返回预期结构 ### 回退策略 - 若测试失败,先修复测试再继续 - 若连续两次修复失败,停止并输出当前 diff 供人工判断

这套结构看起来有点繁琐,但写顺了之后,一个技能定义大概十分钟就能写完。而它带来的收益是:代理在执行同类任务时的稳定性大幅提升,你不需要每次都在对话里重复同样的约束。

3.2 技能粒度怎么把握:太粗和太细都是坑

技能定义的粒度是个需要反复调试的参数。我一开始犯的错误是定义得太粗,比如写了一个“实现功能”的技能,结果它什么都能干,也什么都干不好。后来矫枉过正,定义得太细,每个小操作都写一个技能,导致代理在选择技能时频繁犹豫,反而降低了效率。

比较合理的粒度是:一个技能对应一个“人类开发者需要独立思考和决策的完整任务单元”。比如“新增 API 端点”是一个合适的粒度,“在文件里加一行 import”就太细了,“重构整个后端架构”又太粗了。

判断粒度是否合适,有个简单的测试方法:如果一个技能的执行步骤超过 10 步,或者验证方法超过 5 条,那大概率是太粗了,应该拆分。如果一个技能的步骤少于 3 步,且不需要任何判断,那大概率是太细了,可以合并到相邻技能里。

我在实际项目里大概维护了 8 到 12 个核心技能,覆盖了日常开发 80% 的场景。剩下的 20% 长尾场景,就让代理在框架外自由发挥,不强行套技能。

3.3 约束条件的写法:用“必须”和“禁止”代替“尽量”

写技能定义时,语言的选择会直接影响代理的执行效果。我做过对比测试,同样的约束,用“尽量”“最好”“建议”这类词写,代理的遵守率大概只有六七成;换成“必须”“禁止”“不得”这类强约束词,遵守率能到九成以上。

这不是代理在偷懒,而是模糊语言本身就给了它解释空间。当你说“尽量写测试”时,它可以在时间紧张时选择不写;当你说“必须为每个新增函数写单元测试,否则不得提交”时,它就没有解释空间了。

所以我的建议是:凡是真正重要的约束,一律用强约束词。只有那些确实可以灵活处理的偏好,才用弱约束词。而且强约束和弱约束要明确区分开,不要让代理去猜哪条更重要。

另外,约束条件最好带上理由。比如不要只写“禁止修改 config 目录下的文件”,而要写“禁止修改 config 目录下的文件,因为这些文件由运维团队统一管理,本地修改会在部署时被覆盖”。带上理由之后,代理在遇到边界情况时能做出更合理的判断,而不是机械地遵守或违反。

3.4 与 Claude Code 和 Codex CLI 的对接方式

技能定义写完之后,怎么让 Claude Code 或 Codex CLI 用起来,是实操层面的关键。

Claude Code 这边,它本身支持在项目根目录放一个约定文件来加载项目级指令。我的做法是把技能定义拆成两部分:一部分是通用的框架说明,放在全局配置里;另一部分是项目特有的技能,放在项目根目录。这样换项目时,通用部分不用重写,只写项目特有的部分。

Codex CLI 这边,它的配置方式略有不同,更依赖命令行参数和配置文件。我的做法是写一个简单的同步脚本,把 Markdown 格式的技能定义转换成 Codex CLI 能读的格式,然后在启动时通过参数指定。

这里有个实操细节值得注意:两个工具对上下文长度的处理策略不一样。Claude Code 倾向于把项目级指令完整加载,Codex CLI 则更依赖按需检索。所以同样的技能定义,在 Claude Code 里可以写得详细一些,在 Codex CLI 里则要更精炼,把最关键的约束放在最前面。

我实测下来,一套技能定义在两个工具之间迁移,大概需要花半天时间做适配和调试。这个成本是可以接受的,尤其是考虑到它保护的是团队积累的方法论资产。

4. 完整实操流程:从零搭建一套可用的技能框架

4.1 环境准备与工具安装的实操记录

在开始写技能定义之前,得先把工具装好。这部分看起来简单,但实际操作时坑不少,我把自己在 Ubuntu 和 macOS 上的安装过程记录一下。

Claude Code 的安装,官方推荐的方式是通过 npm 全局安装。在 Ubuntu 上,我遇到过一次权限问题,原因是 npm 的全局目录没有正确配置。解决办法是重新配置 npm 的 prefix,或者用 nvm 管理 Node 版本,避免用系统自带的 Node。macOS 上相对顺利,但如果你用的是 Apple Silicon 芯片,要注意某些依赖包的架构兼容性。

Codex CLI 的安装类似,也是通过包管理器。安装完成后,第一次运行通常需要做一些初始化配置,比如指定工作目录、设置默认模型等。这里有个细节:如果你在受限的网络环境里,某些初始化步骤可能会卡住,这时候可以先用离线模式启动,再手动补配置。

VSCode 的配置是另一个容易出问题的地方。Claude Code 有官方的 VSCode 插件,安装后在设置里需要指定 CLI 的路径。如果你同时装了多个版本,一定要确认插件指向的是你想用的那个。我就遇到过插件调用了旧版本 CLI,导致行为不一致的问题,排查了半天才发现是路径配置错了。

关于模型接入,很多人会问能不能用本地模型或者其他第三方模型。技术上是可以的,通过配置 API 端点就能实现。但我的建议是:技能框架的调试阶段,尽量用官方推荐的模型,因为不同模型对指令的遵循程度差异很大。等框架稳定了,再尝试替换模型,这样能把“框架问题”和“模型问题”分开排查。

4.2 技能库的目录结构与版本管理

技能定义写多了之后,目录结构就变得重要了。我现在的做法是按功能域分目录,每个目录下放相关的技能定义文件。

skills/ core/ framework.md # 框架通用说明 verification.md # 验证规范 backend/ api-endpoint.md # 新增 API 端点 db-migration.md # 数据库迁移 service-refactor.md # 服务层重构 frontend/ component-create.md # 新建组件 state-management.md # 状态管理改动 testing/ unit-test.md # 单元测试规范 integration-test.md # 集成测试规范

这个结构的好处是,当项目只涉及后端时,可以只加载 backend 和 core 目录,减少上下文占用。当项目是全栈时,再加载全部。

版本管理方面,技能定义一定要进 Git。原因很简单:技能定义会随着项目演进不断调整,你需要知道每次调整改了什么、为什么改。我习惯在每次调整技能定义时,在 commit message 里写清楚触发这次调整的具体问题。比如“修复代理在数据库迁移时忘记回滚的问题”,这样半年后回头看,能快速理解当时的决策背景。

另外,技能定义最好和代码放在同一个仓库里,而不是单独开一个仓库。因为技能定义和代码是强耦合的,分开管理容易导致版本不同步。放在一起,切换分支时技能定义也跟着切换,不会出现“代码是旧版但技能是新版”的错配。

4.3 一个完整技能的执行过程实录

拿“新增 API 端点”这个技能举例,我记录一次完整的执行过程,让你看看技能框架在实际运行时是什么样子。

任务背景是给一个已有的用户服务新增一个“查询用户活跃度”的端点。我在 Claude Code 里输入任务描述,它识别到这属于“新增 API 端点”技能的触发条件,于是加载对应的技能定义。

第一步是前置检查。它先确认当前分支,发现是 feature 分支,通过。然后检查依赖,发现 node_modules 存在,通过。最后运行现有测试,发现有两个测试是失败的。这时候它没有继续往下走,而是停下来告诉我:“前置检查未通过,现有测试有两个失败,是否先修复?”

这个行为就是技能框架的价值所在。如果没有前置检查,它可能直接开始写新代码,然后在验证阶段发现测试失败,但分不清是新代码导致的还是原本就失败的,排查成本会高很多。

我让它先修复现有测试。它进入修复流程,定位到失败原因是某个 mock 数据过期了,更新后测试通过。然后重新执行前置检查,全部通过,开始正式执行。

执行步骤它按定义走:先改数据模型,加了一个 last_active_at 字段;然后在 service 层实现查询逻辑;接着注册路由;最后补单元测试。每一步做完它都会简短汇报,但不会停下来等我确认,因为技能定义里没有要求逐步确认。

到了验证阶段,它运行npm test,全部通过;运行 lint,无新增警告;然后用 curl 手动测试端点,返回了预期结构。全部验证通过后,它输出了一份改动摘要,包括改了哪些文件、每个文件改了什么、测试结果如何。

整个过程大概花了七八分钟,我全程只做了一次决策(是否先修复现有测试)。如果没有技能框架,同样的任务我可能要在对话里来回纠正十几次,耗时至少翻倍,而且质量还不稳定。

4.4 参数选择与配置调优的经验

技能框架跑起来之后,还有一些参数需要调优。这些参数没有标准答案,要根据项目特点和团队习惯来定。

上下文加载范围:是加载全部技能定义,还是按需加载。加载全部的好处是代理随时能用到任何技能,坏处是占用上下文,可能挤掉其他重要信息。我的做法是核心技能常驻,边缘技能按需加载。

验证严格度:验证环节是只跑快速测试,还是跑完整测试套件。快速测试反馈快但覆盖不全,完整测试覆盖全但耗时长。我的做法是开发过程中跑快速测试,提交前跑完整测试。

回退阈值:验证失败几次后停止并求助。设得太低,代理容易放弃;设得太高,代理可能陷入无效重试。我实测下来,两次是比较合适的阈值。

技能选择策略:当多个技能都匹配当前任务时,怎么选。我的做法是给技能定义加优先级字段,优先级高的先匹配。同时避免技能触发条件重叠,从源头上减少选择困难。

这些参数我建议先用默认值跑一段时间,观察代理的实际表现,再针对性调整。不要一上来就追求完美配置,那样反而容易过度设计。

5. 常见问题与排查技巧实录

5.1 代理不遵守技能定义怎么办

这是最常见的问题。你明明写了技能定义,代理却视而不见,还是按自己的方式来。排查思路分三层。

第一层,检查技能定义是否被正确加载。有时候是配置文件路径写错了,或者格式不对导致解析失败。可以在代理启动时让它输出当前加载的技能列表,确认目标技能在里面。

第二层,检查触发条件是否匹配。代理可能认为当前任务不满足触发条件,所以没加载对应技能。这时候要么调整触发条件让它更宽松,要么在任务描述里明确指定使用哪个技能。

第三层,检查技能定义本身是否有矛盾。如果两个技能的定义互相冲突,代理可能选择忽略其中一个。这种情况需要重新梳理技能边界,消除冲突。

我遇到过一次比较隐蔽的问题:技能定义里用了中文标点,而解析器只认英文标点,导致部分内容被截断。这种问题很难从代理行为上看出来,只能通过检查解析日志发现。所以技能定义最好统一用英文标点,减少不必要的麻烦。

5.2 验证环节频繁失败的处理方法

验证失败本身是好事,说明框架在起作用。但如果频繁失败,就要分析原因了。

一种情况是验证标准定得太严。比如要求“零 lint 警告”,但项目本身就有历史遗留警告,那每次验证都会失败。这种要区分“新增警告”和“历史警告”,只对新增部分做要求。

另一种情况是验证命令本身不稳定。比如依赖网络的测试、依赖时序的测试,可能时好时坏。这种要把不稳定测试隔离出来,不要放进技能定义的强制验证环节。

还有一种情况是代理确实没做对。这时候要看失败模式:如果是同类错误反复出现,说明技能定义里的执行步骤不够明确,需要补充细节;如果是偶发错误,可能是模型能力边界问题,考虑换模型或降低任务复杂度。

我整理了一个常见验证失败的处理对照表:

失败模式可能原因处理方式
每次都失败,错误相同验证标准过严或命令有误调整验证标准,确认命令可手动执行
间歇性失败测试不稳定或依赖外部环境隔离不稳定测试,改用确定性验证
失败但手动检查没问题验证命令与预期不符核对命令输出格式,调整断言逻辑
失败后代理不报告回退策略缺失或模糊补充明确的回退策略定义

5.3 技能定义膨胀后的维护策略

技能定义写多了之后,维护成本会上升。我踩过的坑是:一开始每个新问题都加一条技能定义,半年后积累了三十多个技能,代理选择困难,我自己也记不清哪个是哪个。

后来我做了一次大清理,把技能按使用频率分成三类:高频核心技能(每周都用)、中频技能(每月用几次)、低频技能(偶尔用)。高频的保留在主目录,中频的归档到子目录按需加载,低频的直接删掉,需要时再临时写。

清理之后,核心技能从三十多个精简到十个左右,代理的表现反而更稳定了。这印证了一个道理:技能框架的价值不在于覆盖所有场景,而在于把最高频、最容易出错的场景规范化。剩下的长尾场景,让代理自由发挥就好,不必强行套框架。

另外,技能定义要定期回顾。我习惯每个月花半小时过一遍现有技能,看看哪些已经过时、哪些需要更新。软件开发变化快,半年前写的技能定义可能已经不适合现在的代码结构了。

5.4 团队协作中的技能框架同步问题

如果是团队使用,技能框架的同步是个绕不开的问题。每个人对技能的理解可能不一样,写出来的定义风格也各异。

我的做法是:指定一个人负责技能框架的维护,其他人可以提建议,但最终由负责人统一修改。这样能保证风格一致,避免多人编辑导致的混乱。

新成员加入时,要花时间讲解技能框架的设计思路,而不只是扔给他一堆定义文件。理解设计思路之后,他才能正确地使用和扩展框架。我见过有团队直接把技能定义当文档发下去,结果新成员照着用,遇到边界情况就不知道怎么处理了。

还有一个细节:技能定义的修改要通知团队。因为技能定义变了,代理的行为也会变,如果大家不知道,可能会对代理的“异常行为”感到困惑。我习惯在技能定义修改后,在团队频道里简短说明改了什么、为什么改。

6. 技能框架的扩展方向与个人实践体会

技能框架跑顺之后,可以往几个方向扩展。一个是和 CI/CD 流程打通,让技能定义里的验证环节直接复用 CI 的检查项,这样本地验证和流水线验证保持一致,减少“本地过了但 CI 挂了”的情况。另一个是积累技能执行的日志,分析哪些技能最常用、哪些验证最容易失败,用数据驱动框架的优化。

我自己在实际操作中的体会是:技能框架最大的价值不是让 AI 变得更聪明,而是让 AI 的行为变得可预测。在软件开发里,可预测性往往比聪明更重要。一个行为可预测的中等水平代理,比一个时好时坏的天才代理更有用,因为前者能融入流程,后者只能当玩具。

最后分享一个小技巧:刚开始搭技能框架时,不要追求大而全。先挑一个你最常做、最容易出错的任务,为它写一个技能定义,跑一周看看效果。有效果了,再扩展到第二个、第三个。这样渐进式的搭建方式,比一次性设计一套完整框架要靠谱得多,因为你对框架的理解也是在实践中逐步深化的。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进