ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

Claude Code与Codex CLI的Agentic Skills框架:从提示词到技能工程

Claude Code与Codex CLI的Agentic Skills框架:从提示词到技能工程

1. 从“superpowers”说起:这套技能框架到底在解决什么问题

第一次看到“superpowers”这个词,是在一个开发者社群里有人贴了一张截图,里面是一套围绕 Claude Code 和 Codex CLI 构建的 agentic skills framework。当时我的第一反应是:又是一个包装概念的东西。但仔细看完它的结构之后,我改变了看法——它其实在试图回答一个非常具体的问题:当 AI 编程助手从“补全代码”进化到“自主执行任务”之后,我们该怎么组织它的能力,才能让它在真实项目里稳定干活,而不是每次都靠运气?

这个问题的背景是这样的。Claude Code 和 Codex CLI 这类工具,本质上是一个跑在终端里的 agent。你给它一个任务,它会自己读文件、改代码、跑命令、看报错、再改,循环往复直到任务完成或者卡住。听起来很美好,但实际用起来你会发现,同一个任务,有时候它一次就做对了,有时候它会在同一个坑里反复横跳,浪费大量 token 和时间。差别往往不在于模型本身,而在于你怎么给它定义任务边界、怎么组织项目上下文、怎么设计验证回路。

superpowers 这套框架的核心思路,就是把“怎么跟 agent 协作”这件事从玄学变成工程。它把常见的开发任务拆成一组可复用的 skill(技能),每个 skill 定义了明确的输入、输出、约束条件和验证方式。你可以把它理解成给 agent 写的一份“岗位操作手册”——不是告诉它具体怎么做,而是告诉它在什么场景下应该遵循什么流程、检查什么、避免什么。

这套东西适合谁?如果你只是偶尔用 Claude Code 改个脚本、跑个一次性任务,那可能不需要这么重的框架。但如果你每天都要跟 agent 协作,项目有一定复杂度,涉及多文件修改、测试验证、依赖管理,那这套方法论能帮你省下大量反复沟通和纠错的成本。下面我会从设计思路、核心机制、实操落地、常见坑四个层面,把这套框架拆开讲清楚。

2. 框架整体设计:为什么是“技能”而不是“提示词”

2.1 从提示词工程到技能工程的转变

大多数人用 Claude Code 的方式是:打开终端,输入一段自然语言描述,等它执行。这种方式在简单任务上没问题,但一旦任务涉及多个步骤、多个文件、多个验证环节,问题就来了。你写的提示词再详细,agent 在执行过程中也可能因为上下文丢失、优先级混乱、验证缺失而跑偏。

superpowers 的做法是把“提示词”升级成“技能”。一个 skill 不是一段静态的文本,而是一个结构化的定义,包含几个关键要素:

  • 触发条件:什么情况下应该激活这个 skill。比如“当任务涉及修改现有测试文件时”或者“当需要新增依赖时”。
  • 执行流程:分步骤的操作序列,每一步都有明确的输入和预期输出。
  • 约束规则:哪些事情绝对不能做,哪些事情必须先确认。比如“不允许直接修改生产环境配置文件”。
  • 验证标准:怎么判断这一步做完了、做对了。比如“所有现有测试必须通过”或者“新增代码的行覆盖率不低于 80%”。
  • 回退策略:如果验证失败,应该怎么处理。是重试、回退到上一个稳定状态,还是上报给人类。

这种结构化的好处是,agent 在执行时有了明确的“轨道”,不会因为上下文窗口里的信息太多而迷失方向。同时,因为每个 skill 都是独立的,你可以根据项目需要组合不同的 skill,形成一套适合自己团队的协作流程。

2.2 为什么选择 Claude Code 和 Codex CLI 作为载体

这套框架目前主要围绕 Claude Code 和 Codex CLI 两个工具展开,这不是偶然的。这两个工具的共同特点是:它们都是终端原生的 agent,能够直接访问文件系统、执行 shell 命令、读取命令输出。这意味着 agent 不仅能“说”,还能“做”,而且做的结果能被立即验证。

相比之下,那些只在编辑器里做代码补全的工具,虽然也能提升效率,但它们的能力边界被限制在“生成文本”这个层面。你没法让一个补全工具去跑测试、看日志、根据报错调整方案。而 Claude Code 和 Codex CLI 可以形成一个完整的闭环:读代码 → 改代码 → 跑测试 → 看结果 → 再改。superpowers 要做的,就是让这个闭环更可控、更可重复。

另一个原因是这两个工具都支持通过配置文件和环境变量来定制行为。Claude Code 有CLAUDE.md这样的项目级指令文件,Codex CLI 也有类似的配置机制。superpowers 利用这些机制,把技能定义注入到 agent 的运行时环境中,让 agent 在执行任务时自动加载相关的 skill,而不需要你每次手动输入。

2.3 核心设计原则:约束比自由更重要

这套框架最反直觉的一点是:它花了大量精力在“限制 agent 能做什么”上,而不是“让 agent 能做更多”。这跟很多人的直觉相反——大家通常觉得,给 AI 的自由度越高,它就越能发挥创造力。但在实际工程场景里,创造力往往不是瓶颈,稳定性才是。

我举个例子。你让 Claude Code 帮你重构一个函数,如果没有约束,它可能会顺手把旁边的变量名也改了,把 import 顺序也调整了,甚至把不相关的注释也删了。这些改动单独看可能都没问题,但合在一起就可能导致代码审查时难以定位真正的变更点,或者引入意料之外的副作用。superpowers 的做法是,在 skill 里明确规定“只修改目标函数体内的代码,不触碰函数签名、不调整 import、不删除任何注释”。这样 agent 的行为就变得可预测了。

这种“约束优先”的设计思路,在 agentic skills framework 里是一个关键的分水岭。它意味着你不是在“使用”一个 AI 工具,而是在“管理”一个执行者。管理的关键不是给它多少自由,而是给它多清晰的边界。

3. 核心机制拆解:技能定义、加载与执行

3.1 技能定义的结构与写法

一个典型的 skill 定义,通常是一个 Markdown 文件或者 YAML 文件,放在项目的特定目录下(比如.superpowers/skills/)。它的结构大致如下:

name: refactor-function trigger: 当任务涉及重构单个函数且不改变其外部行为时 steps: - 读取目标函数及其所有调用点 - 确认函数签名和返回值类型 - 在函数体内进行重构,保持输入输出不变 - 运行相关测试,确认全部通过 constraints: - 不修改函数名、参数列表、返回值类型 - 不修改函数外的任何代码 - 不删除或修改现有注释 validation: - 所有调用点编译通过 - 相关测试用例全部通过 - 代码差异仅限目标函数体内 fallback: 如果测试失败,回退到重构前的版本并报告失败原因

这个定义里,trigger决定了什么时候加载这个 skill。steps是执行流程,constraints是硬性规则,validation是完成标准,fallback是失败处理。这五个部分缺一不可,因为它们共同构成了一个完整的“任务契约”。

写 skill 定义的时候,有几个经验性的原则。第一,trigger要尽量具体,避免模糊匹配。比如“当任务涉及重构”就太宽泛了,“当任务涉及重构单个函数且不改变其外部行为时”就明确得多。第二,steps要按顺序排列,每一步都应该是可验证的。如果某一步没法验证,那它就不应该出现在 steps 里。第三,constraints要写成“不做什么”,而不是“尽量做什么”。因为 agent 对否定指令的执行力通常比肯定指令更强。

3.2 技能加载机制:怎么让 agent 知道该用哪个 skill

技能加载有两种模式:自动匹配和显式调用。

自动匹配模式下,agent 会根据当前任务的描述,去匹配已注册的 skill 的trigger条件。比如你输入“帮我重构一下calculateTotal这个函数”,agent 会扫描所有 skill 的 trigger,发现refactor-function的 trigger 匹配上了,就自动加载这个 skill 并按照它的流程执行。

显式调用模式下,你直接在指令里指定 skill 名称,比如“用refactor-function这个 skill 来重构calculateTotal”。这种方式适合你对任务类型非常明确、不想让 agent 自己判断的情况。

两种模式各有优劣。自动匹配更省心,但依赖 trigger 写得足够准确;显式调用更可控,但需要你记住 skill 的名称和适用场景。实际使用中,我通常会把两者结合起来:日常任务用自动匹配,关键任务用显式调用。

加载机制的技术实现,通常是通过在CLAUDE.md或 Codex CLI 的配置文件中注入一段“技能索引”,告诉 agent 有哪些 skill 可用、各自的 trigger 是什么。当 agent 开始执行任务时,它会先读这个索引,然后根据任务描述决定加载哪个 skill。这个过程对用户是透明的,你不需要手动干预。

3.3 执行引擎:skill 是怎么被一步步执行的

当一个 skill 被加载后,agent 会按照steps里的顺序逐步执行。每一步执行前,agent 会检查当前状态是否满足该步骤的前置条件;执行后,会检查是否满足该步骤的验证标准。如果某一步验证失败,agent 会根据fallback策略决定是重试、回退还是上报。

这里有一个关键设计:每一步的验证是独立的。也就是说,即使前面的步骤都通过了,如果某一步的验证失败,整个 skill 的执行也会被中断。这看起来有点严格,但正是这种严格保证了最终结果的可信度。我见过太多这样的情况:agent 改完代码,跑了一下测试,看到没有报错就认为完成了,但实际上测试根本没覆盖到修改的代码路径。有了独立的验证步骤,这种问题就能被及时发现。

执行过程中,agent 会维护一个“执行日志”,记录每一步的输入、输出、验证结果和耗时。这个日志在排查问题时非常有用。比如某个 skill 执行失败了,你可以翻日志看到底是哪一步出了问题、当时的上下文是什么、agent 做了什么决策。这比事后猜测要高效得多。

4. 实操落地:从零搭建一套可用的技能框架

4.1 环境准备与工具安装

在开始搭建之前,你需要先确保 Claude Code 和 Codex CLI 至少有一个能正常运行。这两个工具的安装方式略有不同,但基本流程都是:下载安装包 → 配置 API 密钥或登录账号 → 验证安装成功。

对于 Claude Code,安装完成后你可以在终端里输入claude命令,如果能看到交互界面就说明安装成功了。Codex CLI 类似,输入codex命令后如果能进入交互模式就没问题。如果你在 Ubuntu 上安装,可能需要额外处理一些依赖库的问题,比如确保libc版本符合要求。Mac 上安装通常更顺利,因为系统环境比较统一。

安装完成后,建议先跑一个简单的任务测试一下,比如让它“在当前目录下创建一个 hello.txt 文件并写入 Hello World”。这个任务足够简单,能帮你快速确认 agent 的基本功能是否正常。

4.2 项目初始化:创建技能目录与配置文件

在你的项目根目录下,创建一个.superpowers目录,里面再建一个skills子目录。这个目录结构是 superpowers 框架约定的,agent 会自动去这里查找 skill 定义。

然后,在项目根目录下创建或修改CLAUDE.md文件(如果用的是 Claude Code)或者对应的 Codex CLI 配置文件。在这个文件里,你需要添加一段技能索引,告诉 agent 去哪里找 skill、有哪些 skill 可用。一个典型的索引配置如下:

## Skills 本项目使用 superpowers 技能框架。所有 skill 定义位于 `.superpowers/skills/` 目录下。 可用 skill 列表: - refactor-function: 重构单个函数,不改变外部行为 - add-test: 为指定函数或模块新增测试用例 - fix-bug: 根据报错信息定位并修复 bug - add-dependency: 新增项目依赖并更新配置文件

这段配置的作用是让 agent 在启动时就知道有哪些 skill 可用。当它遇到匹配的任务时,会自动去加载对应的 skill 定义文件。

4.3 编写第一个 skill:以“新增测试”为例

我们以add-test这个 skill 为例,完整走一遍编写流程。假设你的项目里有一个utils.py文件,里面有一个parse_date函数,你想让 agent 为它新增测试用例。

首先,在.superpowers/skills/目录下创建add-test.md文件,内容如下:

name: add-test trigger: 当任务涉及为现有函数或模块新增测试用例时 steps: - 读取目标函数或模块的源代码 - 识别函数的输入参数、返回值类型和边界条件 - 检查项目中已有的测试文件和测试框架 - 按照项目现有的测试风格编写测试用例 - 运行新增的测试,确认全部通过 constraints: - 不修改被测试的源代码 - 不删除或修改已有的测试用例 - 测试文件命名和目录结构遵循项目现有约定 validation: - 新增测试用例全部通过 - 测试覆盖了正常路径、边界条件和异常路径 - 代码风格与项目现有测试一致 fallback: 如果测试运行失败,检查测试代码本身是否有误,修正后重试;如果连续三次失败,报告失败原因并停止

写完之后,你可以直接在 Claude Code 里输入:“用 add-test 这个 skill 为parse_date函数新增测试用例”。agent 会加载这个 skill,按照 steps 逐步执行。执行过程中,它会先读utils.py,找到parse_date函数,分析它的参数和返回值,然后去项目里找现有的测试文件,参考它们的写法来生成新的测试用例。

这里有一个实操心得:在 skill 的 steps 里加入“检查项目现有约定”这一步非常重要。因为不同的项目用的测试框架可能不一样,有的是 pytest,有的是 unittest,有的是 jest。如果不检查现有约定,agent 可能会用错框架,导致测试跑不起来。我刚开始用的时候没注意这一点,结果 agent 给一个 pytest 项目生成了 unittest 风格的测试,虽然逻辑没错,但跟项目风格完全不搭,还得手动改。

4.4 技能组合与流程编排

单个 skill 能解决单一类型的问题,但真实项目里的任务往往是复合的。比如“修复一个 bug 并补充测试”就涉及fix-bug和add-test两个 skill。superpowers 支持技能组合,你可以在一个 skill 的 steps 里引用另一个 skill。

比如,你可以定义一个fix-bug-with-test的复合 skill:

name: fix-bug-with-test trigger: 当任务涉及修复 bug 且需要补充测试时 steps: - 调用 fix-bug skill 定位并修复 bug - 调用 add-test skill 为修复后的代码新增测试用例 - 运行完整测试套件,确认没有引入回归 constraints: - 修复和测试必须针对同一个 bug - 不修改与 bug 无关的代码 validation: - bug 被修复且新增测试通过 - 完整测试套件全部通过 fallback: 如果完整测试套件失败,回退到修复前的状态并报告失败原因

这种组合方式让 skill 框架变得非常灵活。你可以根据项目的实际需要,把基础 skill 组合成更复杂的流程。而且因为每个基础 skill 都是独立验证的,组合后的流程也保持了可追溯性——如果最终结果有问题,你可以逐层排查是哪个环节出了错。

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

5.1 技能不触发或触发错误

这是最常见的问题。你明明定义了一个 skill,但 agent 执行任务时没有加载它,或者加载了错误的 skill。原因通常有几个:

trigger 写得太宽泛或太狭窄。太宽泛会导致误触发,太狭窄会导致该触发的时候不触发。解决办法是先用几个典型任务测试 trigger 的匹配情况,根据结果调整措辞。比如“当任务涉及修改代码时”就太宽泛了,几乎任何任务都会匹配上;“当任务涉及修改 Python 文件中第 42 行到第 58 行的代码时”又太狭窄,稍微换个行号就不匹配了。比较合适的粒度是“当任务涉及重构单个函数且不改变其外部行为时”这种级别。

skill 文件没有被正确索引。检查CLAUDE.md或 Codex CLI 配置文件里的技能索引是否包含了这个 skill 的名称和路径。如果索引里没有,agent 根本不知道这个 skill 存在。

skill 文件格式有误。YAML 对缩进和特殊字符很敏感,一个多余的空格就可能导致解析失败。建议用 YAML 校验工具检查一下文件格式。

5.2 执行过程中卡住或反复重试

有时候 agent 会在某一步反复重试,消耗大量 token 但就是不成功。这种情况通常是因为fallback策略没有定义清楚,或者验证标准太严格导致 agent 永远达不到。

我遇到过一个典型案例:一个 skill 的验证标准是“所有测试通过”,但项目里有一个已知的、跟当前任务无关的测试是失败的。agent 每次跑完测试都看到有失败,就认为自己的任务没完成,然后反复重试。解决办法是在验证标准里加上“排除已知失败的测试”或者“只运行与当前任务相关的测试”。这个经验告诉我,验证标准必须考虑项目的实际状态,不能假设项目是完美的。

另一个常见原因是 agent 对某一步的理解有偏差,导致它一直在用错误的方式执行。这时候可以检查执行日志,看看 agent 在这一步的输入输出是什么,然后调整 steps 里的描述,让它更明确。

5.3 技能之间的冲突与优先级

当多个 skill 的 trigger 同时匹配一个任务时,agent 需要决定加载哪个。如果没有明确的优先级规则,它可能会随机选一个,或者同时加载多个导致行为混乱。

解决办法是在 skill 定义里加一个priority字段,数值越小优先级越高。或者在CLAUDE.md里定义一个全局的优先级顺序。比如:

Skill 优先级(从高到低): 1. fix-bug 2. refactor-function 3. add-test 4. add-dependency

这样当任务同时匹配多个 skill 时,agent 会按照优先级选择最高的那个。如果确实需要同时使用多个 skill,那就应该定义一个复合 skill,而不是让 agent 自己组合。

5.4 常见问题速查表

问题现象可能原因排查方法解决措施
skill 不触发trigger 不匹配或索引缺失检查 trigger 措辞和索引配置调整 trigger 或补充索引
触发错误 skilltrigger 过于宽泛或优先级冲突查看执行日志确认加载了哪个 skill收窄 trigger 或设置优先级
执行卡住fallback 缺失或验证标准过严检查执行日志中卡在哪一步补充 fallback 或放宽验证标准
结果不符合预期constraints 不够明确对比执行前后的代码差异细化 constraints 描述
token 消耗过大steps 过于冗长或反复重试统计各步骤的 token 消耗精简 steps 或优化 fallback

6. 进阶技巧:让技能框架真正融入日常开发

6.1 技能版本管理与团队共享

当你的 skill 数量多起来之后,就需要考虑版本管理了。我的做法是把.superpowers/skills/目录纳入 Git 管理,每个 skill 的修改都走正常的代码审查流程。这样有几个好处:一是可以追溯每个 skill 的变更历史,知道某个约束是什么时候加的、为什么加;二是团队成员可以共享同一套 skill,保证大家的 agent 行为一致;三是新人加入时可以直接复用现有的 skill,不需要从零摸索。

如果团队规模比较大,还可以考虑把 skill 拆分成“基础技能”和“项目技能”两层。基础技能是通用的,比如add-test、fix-bug这种,可以跨项目复用;项目技能是针对特定项目的,比如“按照本项目的 API 规范新增接口”。基础技能放在一个共享仓库里,项目技能放在各自的项目仓库里,通过符号链接或者包管理工具来引用。

6.2 根据项目特点定制验证标准

验证标准是 skill 框架里最需要根据项目特点定制的部分。不同的项目对“完成”的定义不一样。有的项目要求所有测试通过,有的项目要求代码覆盖率不低于某个阈值,有的项目要求通过 lint 检查,有的项目要求性能指标不能退化。

我的经验是,验证标准应该分层:必须通过的(比如编译通过、核心测试通过)和建议通过的(比如覆盖率、lint)。必须通过的标准放在validation里,不通过就中断执行;建议通过的标准放在constraints里,不通过只警告不中断。这样既能保证基本质量,又不会因为一些非关键问题导致 agent 反复重试。

另外,验证标准最好能自动化执行。比如“所有测试通过”可以通过运行pytest或npm test来验证,“代码风格一致”可以通过运行eslint或black --check来验证。如果验证标准需要人工判断,那它就不适合放在 skill 里,应该作为人工审查的环节。

6.3 与现有开发流程的集成

superpowers 框架不是要取代现有的开发流程,而是要融入其中。我的做法是把 skill 执行作为开发流程的一个前置环节:在提交代码之前,先用 agent 跑一遍相关的 skill,确保代码符合基本质量要求;然后再走正常的人工审查和 CI 流程。

这样做的好处是,人工审查可以更聚焦在架构设计、业务逻辑这些真正需要人类判断的地方,而不是浪费在“这个函数有没有测试”“代码风格对不对”这些可以自动化检查的事情上。同时,因为 skill 执行有完整的日志记录,人工审查时也可以参考这些日志,了解 agent 做了哪些改动、为什么这么改。

还有一个技巧是把常用的 skill 组合封装成一条命令。比如你可以定义一个pre-commit的复合 skill,包含“运行 lint”“运行测试”“检查代码差异”三个步骤。每次提交前跑一下这个 skill,就能快速确认代码没有明显问题。这比手动跑一堆命令要高效得多。

6.4 持续优化:从执行日志中学习

skill 框架的一个隐藏价值是:它会产生大量的执行日志。这些日志记录了 agent 在每一步的决策和结果,是优化 skill 定义的宝贵素材。

我通常会定期翻看执行日志,关注几个指标:哪些步骤的失败率最高、哪些 skill 的 token 消耗最大、哪些约束经常被触发。失败率高的步骤说明描述不够清晰或者验证标准不合理,需要调整;token 消耗大的 skill 说明 steps 可能过于冗长,需要精简;经常被触发的约束说明这个约束可能太严格了,需要考虑放宽或者拆分成更细的规则。

这个过程有点像调参:先定义一个初始版本,然后根据实际运行数据不断调整,直到 skill 的行为稳定且高效。我自己的经验是,一个 skill 通常需要经过三到五轮调整才能达到比较理想的状态。第一轮是功能验证,确保它能跑通;第二轮是边界测试,看看它在异常情况下表现如何;第三轮是效率优化,减少不必要的步骤和 token 消耗;后面几轮就是根据实际使用中的反馈做微调了。

7. 一些踩过的坑和真实体会

刚开始用这套框架的时候,我犯过一个很典型的错误:把 skill 定义写得过于详细,恨不得把每一步的代码都写进去。结果 agent 执行时反而变得很死板,遇到稍微不同的情况就不知道变通了。后来我意识到,skill 定义应该定义“做什么”和“不做什么”,而不是“怎么做”。具体的实现方式应该留给 agent 根据实际情况判断。比如“为函数新增测试”这个 skill,你只需要告诉它要覆盖正常路径、边界条件和异常路径,不需要告诉它具体用哪个断言方法、怎么组织测试类。这些细节让 agent 自己决定就好。

另一个坑是忽略了 skill 之间的依赖关系。有一次我定义了一个add-dependencyskill,它会修改package.json并运行安装命令。但另一个fix-bugskill 在执行过程中也可能需要新增依赖,而它并不知道add-dependency的存在,结果就是它自己手动改了package.json,但没有运行安装命令,导致后续步骤全部失败。后来我在fix-bug的 steps 里加了一步“如果需要新增依赖,调用 add-dependency skill”,这个问题才解决。所以定义 skill 的时候,一定要考虑它可能跟哪些其他 skill 产生交互,提前把依赖关系理清楚。

还有一个体会是:不要试图用 skill 框架解决所有问题。有些任务就是适合人类直接做,比如架构设计、技术选型、代码审查。skill 框架擅长的是那些重复性高、流程明确、验证标准清晰的任务。把不适合的任务硬塞进 skill 里,只会增加维护成本,降低整体效率。我现在的做法是,只把那些我每周都要做、每次做法都差不多、做完之后能自动验证的任务写成 skill,其他的还是手动处理。

最后分享一个提高 skill 复用率的小技巧:在写 skill 的时候,尽量把项目相关的配置抽成参数。比如add-test这个 skill,不要硬编码测试框架是 pytest 还是 jest,而是定义一个test_framework参数,让 agent 在执行时根据项目实际情况填充。这样同一个 skill 就能在不同项目之间复用了。参数化的程度越高,skill 的通用性就越强,维护成本也越低。

RELATED READING

延伸阅读

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