法不净空,觉无性也。

第18章 三分架构——Tool、Skill、Capability

2026.07.29

一个 agent 要成长,需要三种不同的能力增长机制。不是一种,不是四种,恰好三种。


引子

想象一个只有 Tool 的 agent。它知道怎么读写文件、跑命令、搜网页——每次都是同一套操作,同样的配方。你让它"帮我把测试覆盖率从 60% 提到 80%",它会老老实实打开每个文件加测试。但下一次同样的需求,它还是会从头做一遍,不会因为你上次说"优先补核心模块"就改变策略。因为它没有地方"记住"这个偏好。

再想象一个只有 Skill 的 agent。它知道很多方法论——"做代码审查应该分三步"、"遇到 panic 先看调用栈"。但它什么也执行不了,因为它连一个 read_file 工具都没有。它像一个手握地图但迈不动步的人。

再想象一个只有 Capability 的 agent。它能跑各种脚本——日报生成、性能采集、定时发消息。但它没有框架判断什么时候该跑什么、跑完的结果怎么解读。它像一个装了太多 App 但不知道什么时候该用哪个的手机。

这三个场景的共同教训是:agent 的能力增长需要三种不同的机制,任何一种单独存在都做不成事。

Tool:编译时固定

Tool 是 agent 天生就会的东西。在 CodeCoder 里,一共有 26 个内置工具,从 read_filewrite_filerun_command 这样的基础操作,到 globgrepdiff 这样的搜索和比较工具,再到 planmilestonereviewcommit 这样的工程流程工具,还有 generate_skillgenerate_capability 这样的自修改工具。

这些 Tool 在编译时固定。你运行 cargo build 的那一刻,agent 会什么、不会什么就定下来了。运行时不能增加,不能删除,不能修改。

这看起来像是限制——实际上它是安全的基础。一个 Tool 是 26 个还是 100 个不是核心问题,核心是:Tool 是不可伪造的。 你不能通过对话注入一个假工具。不能通过写一个 .md 文件就创造一个新的 run_command。Agent 手里的工具集是确定的、可枚举的、可审计的。

那为什么是 26 个,不是 3 个也不是 100 个?3 个太少——只给读、写、执行,agent 做不了任何复杂的判断。100 个太多——LLM 记不住工具的签名,选错工具的概率随数量上升。26 个是一个实用主义的选择:覆盖了 agent 完成工程任务所需的所有操作,同时每类工具在最窄的粒度上有自己的权限 key。比如 run_command:gitrun_command:cargo 可以分别授权。

Skill:注入式知识

Skill 是 agent "怎么想"的那部分。不是代码,是 Markdown 文本——存在 skills/ 目录下。

一个 Skill 文件长这样:

# Debug Causal Chain

遇到 bug 时按这个顺序:

1. 复现:写一个最小的输入来触发它
2. 锁定:用 git bisect 找到引入 commit
3. 验证:确认根因不是其他地方引入的
4. 修复:写最少代码修
5. 对照:提交前确认修复不破坏已有测试

没有函数签名,没有类型声明,就是纯文本的方法论。Agent 在需要的时候读取这个文件,把全文注入到推理路径中。它不改变 agent 原本能做什么——它改变 agent 怎么做决定。

Skill 的注入有三种时机:

  • 全量注入: skills/ 目录下的所有文件在启动时被 Registry 扫描,内容拼进 system prompt。这是高频技能——比如行为准则、决策框架。
  • 按需激活: 通过 use_skill 工具,在遇到特定场景时主动加载。agent 说"用 security-review skill",然后把对应的 .md 文件全文注入后续 context。
  • 回退草稿层: prompts/ 目录存放未转正的 Skill 草稿。use_skillskills/ 找不到时回退到 prompts/。草稿可以通过 promote_prompt 晋升为正式 Skill——但晋升本身就是一次独立的 agent 操作,不会悄无声息。

这带来了一个自然的成熟度模型:

消息(临时)→ Prompt 草稿(一次使用)→ Skill(正式化)→ 常驻(注入 system prompt)

每一步都有明确的工具操作。没有"随口说了一句话就变成永久行为"的隐式升级。

Capability:可执行产物

Capability 是 agent 写的可执行代码。不是纯知识的 .md 文件,而是带有 manifest 的产物,声明了:

  • Environment: 在什么环境下执行(Shell / Wasm / Docker)
  • Lifecycle: 执行一次还是常驻(OneShot / OnDemand / Persistent)

写一个 Capability 的流程是:

  1. agent 用 generate_capability 工具写代码 + manifest 到 capabilities/ 目录
  2. 用户或 agent 触发 run_capability,指定能力名
  3. 系统按 manifest 的环境声明路由到对应的执行后端

关键的安全设计在于:generate_capability 只有 write_file 级别的权限——它跟写一个普通的 .md 文件没有区别。真正触达权限闸门的是 run_capability。这套"写廉价、执行昂贵"原则的完整论述见篇 4「大门开在哪里——自修改系统的信任边界」,这里不再展开。

所以三个机制的能力边界是这样划分的:

维度ToolSkillCapability
修改时机编译时运行时运行时
内容形式Rust 代码Markdown代码 + manifest
安全隐含不可伪造改变推理路径改变执行能力
审计追踪看二进制看 git log看 git log + 执行记录

为什么恰好是三种?

不是架构师的设计洁癖——是三个不同的安全边界催生的自然分类。

Tool 对应"不可伪造的原语"——这些是 agent 能力的原子操作,必须由编译器和类型系统保证不变形。你不能让一个 Skill 或 Capability 来定义 run_command,否则信任就崩塌了。

Skill 对应"可注入的推理路径"——它是纯文本,永远不直接执行。所以它的安全成本最低:你往 skills/ 放一个文件,最多改变 agent 的思考方式,无法改变它实际能做的事。

Capability 对应"可执行的新长出的手脚"——它需要执行环境,需要权限检查。所以它的安全成本最高:每一步都有 manifest 声明、环境路由、权限闸门。

这三种机制恰好覆盖了 agent 能力增长的三个维度:做什么(Tool)、怎么做(Skill)、做什么新的事(Capability)。 任何一个维度的缺失都会导致系统的不完整——只有 Tool 无法学习,只有 Skill 无法行动,只有 Capability 没有方向。

代价与权衡

三分架构的代价首先体现在分类边界处——还有"准 Tool"、"准 Skill"、"准 Capability"的灰色地带。比如 generate_milestones 工具(自动分解目标为 workgraph 里程碑)算 Tool 还是 Capability?它编译在二进制里(Tool),但做的动作"生成一个结构化的计划"在逻辑上更像一个 Skill 的行为。这种跨类工具在 CodeCoder 的架构中最终定位为 Tool,但这种判断需要反复的设计审视,并非一眼分明。

第二个代价在注册与分发侧。三类能力各自有目录、扫描路径、注入时机,系统必须为三者维护独立的一致性。新增一种分类就新增了一个"这个能力当前是否可用"的状态维度。在三分的规模下管理一致性尚可承受——但如果以后增加第四类,管理的负担会指数级上升。三分恰好是"一个人能用手跟踪所有状态"的上限。

第三个代价是 Skill 的全量注入对 token 成本的侵蚀。skills/ 目录下的所有文件在启动时都被注入 system prompt,这不是零成本的。每增加一个 Skill,prompt 前缀就增长数百 token。虽然 CodeCoder 用 use_skill 按需激活来缓解这个问题,但全量注入的默认行为在当前设计中仍然存在。正如三分本身所揭示的:每一点灵活性都对应着可量化的开销。

收尾:今天你就能用的判断框架

下次你的 agent 需要一项新能力时,先问自己三个问题:

  1. 这是所有场景都需要的原子操作吗?→ 不适合作为 Tool,成本太高
  2. 这会改变 agent 的决策方式吗?→ 写一个 Skill,放进 skills/
  3. 这会创建一个可复用的自动化操作吗?→ 生成一个 Capability,放进 capabilities/

如果答案是"2"和"3"都不太确定——从 Skill 开始。Skill 是最低成本的实验方式:写一个 .md 文件,试几轮,如果发现这个流程需要反复执行,再升级为 Capability。不要跳过草稿层,不要一开始就写可执行代码。

这不是理论——CodeCoder 自己的 6 个 Skill 和 1 个 Capability(写作时数据)就是这么长出来的。没有一个是设计阶段规划的,全部来自"这个场景反复出现,值得写成一份知识"的实践判断。

下一篇,我们看内核的底层——从 REPL 循环到事件驱动,再到操作系统的演进路径。