AI Coding Agent 的 Skill 加载机制深度解析
Skill 加载看起来像一个文件读取问题,实际包含两条不同的链路:
- 宿主进程何时扫描、解析并缓存
SKILL.md - Skill 内容何时进入模型可见的上下文
两条链路可能一早一晚。OpenCode 会在宿主侧初始化 Skill registry,但模型仍要调用 skill 工具才会看到正文;Claude Code、Codex、Cursor 和 Kimi Code 也都把轻量目录与完整说明分开处理。用“启动时有没有读文件”判断是否按需加载,很容易得出相反结论。
更准确的问题有三个:模型启动时看到了什么,正文以什么形式进入会话,长会话压缩后哪些内容能够恢复。
核验日期:2026-07-17。产品实现会持续变化。正文把官方公开契约、源码观察和未知行为分开标注,不用一个产品的行为推断另一个产品。
比较对象必须处在同一层
模型、API、Harness 和最终产品经常共用一个名字,但它们负责的事情不同。
| 层级 | 负责什么 | 例子 |
|---|---|---|
| 模型 | 上下文上限、推理、工具调用能力、多模态 | Claude、GPT、Kimi K2 |
| API / Provider | 请求协议、缓存计费、Tool Search、托管工具 | Anthropic Messages、OpenAI Responses、Moonshot API |
| Harness | 扫描文件、装配上下文、执行工具、compact、权限与 Hook | Claude Code、Codex CLI、OpenCode、Cursor Agent、Kimi Code |
| 能力包 | 可复用说明、脚本、参考资料和资源 | Agent Skills、Rules、Commands、Plugins |
| 产品 | UI、会话管理、账户、配额和团队治理 | Codex App、Cursor IDE、Kimi Agent |
Kimi K2 是模型,不能和 Claude Code、OpenCode、Cursor 直接比较 Skill 扫描。初版 Kimi K2 的官方模型卡给出 128K 上下文;2025 年 9 月的 K2-0905 才升级到 256K。承担 Skill 发现和 compact 的同层对象是 Kimi Code。
同样,API 支持每次请求携带不同的 tools,不等于某个 Harness 每轮都会重建工具集合。Tool Search 是 API 或模型提供的延迟工具定义能力,也不等于 Agent Skills 的加载实现。
Agent Skills 的三级渐进披露
Agent Skills 开放标准把一个 Skill 定义为目录中的 SKILL.md,并允许附带脚本、参考资料和资源。常见结构如下:
1 | |
渐进披露分为三层。
| 层级 | 进入上下文的内容 | 目的 |
|---|---|---|
| Discovery | name、description,有时还有路径或触发提示 |
让模型知道有哪些能力 |
| Activation | 被选中的 SKILL.md 正文 |
提供流程、边界和决策规则 |
| Execution | 特定 reference、脚本输出或资源 | 完成当前分支,不加载无关材料 |
这是一种上下文索引。目录负责召回,正文负责执行,支持文件负责展开细节。目录不是正文的摘要替代品;如果 description 已经足以让模型跳过正文,Skill 的分阶段流程反而容易失效。
组件结构:谁保存内容,谁决定进入窗口
Skill 系统至少包含来源、注册表、路由器、加载器和上下文装配器。长会话还需要缓存、压缩器和外部状态协同。
图中经常被混淆的是 Registry 和 Context Assembler。
- Registry 面向宿主进程。它可以保存 metadata,也可以预先保存解析后的完整正文。
- Router 面向当前任务。它根据显式命令、description、文件作用域或权限选择候选能力。
- Loader 负责取得正文和支持文件。数据可能来自磁盘缓存、插件包、远程目录或已初始化的 registry。
- Context Assembler 决定哪些内容进入 system、developer、user、tool description 或 tool result 等模型输入位置。
- Compactor 处理历史增长;Rehydrator 决定 compact 后重新挂载哪些外部材料。
“宿主已读正文”不代表“正文已占用模型上下文”。反过来,正文进入会话历史后,也不代表每一轮都会重新从磁盘读取。
一次 Skill 调用的运行时生命周期
时序图只表达跨产品都能成立的抽象过程,不承诺具体消息 role 或 XML 包装。
sequenceDiagram
participant FS as Skill sources
participant REG as Registry
participant ASM as Context assembler
participant M as Model
participant LOAD as Loader
participant T as Tools / scripts
participant C as Compactor
FS->>REG: 扫描并解析 metadata
REG->>ASM: 提供可用能力目录
ASM->>M: 轻量 catalog 随当前上下文进入模型
M->>M: 根据任务、description、权限与作用域选择
M->>LOAD: 显式命令或 Skill 调用
LOAD->>REG: 取得 SKILL.md 正文
LOAD-->>M: 正文进入当前会话
M->>T: 按需读取 reference 或运行 script
T-->>M: 返回与当前任务相关的结果
M->>C: 长会话接近阈值时触发 compact
C-->>ASM: 摘要、保留尾部与可恢复材料
ASM-->>M: 重建下一段工作上下文
这条链路可以由用户手动触发,也可以由模型自动路由。两种方式共享正文和资源,差别只在选择器。
正文第一次进入会话后通常成为历史的一部分。后续 API 请求会携带仍在工作窗口内的历史,但这叫“保留已有上下文”,不是“每轮新增一份 Skill”。如果 Harness 采用精确前缀缓存,历史前缀还可能命中缓存,不能把累计输入 token 直接当成每轮新增计算量。
两种加载:宿主加载与上下文加载
OpenCode 很适合说明这一区别。当前官方文档和 dev 分支源码显示:
- Skill service 扫描目录、解析 frontmatter,并可把正文存入 registry。
- 模型初始获得可用 Skill 目录。
- 模型调用内置
skill({name})后,工具才把正文、base directory 和部分支持文件信息返回到当前会话。
因此,OpenCode 的文件读取可以是 eager,正文对模型的暴露仍然是 lazy。调用时也不是新增一个专属 tool schema;skill 是预先注册的元工具,按需变化的是返回的 Skill 内容。
Claude Code、Codex 和 Kimi Code 的公开文档同样采用轻量目录与正文按调用展开。Cursor 则同时保留两套机制:
- Rules /
AGENTS.md提供静态或条件式指令 - Agent Skills 提供由模型或用户选择的动态能力
把 Cursor 简化为 glob Rules,会漏掉 2026 年加入的 Agent Skills、Subagents、Plugins 和动态上下文发现。
消息形态是实现细节,不是跨产品标准
Skill 内容最终必须以某种形式进入模型输入,但具体 role、包装标签和数组位置可能随 Provider、模型或版本变化。稳定比较应该停在语义槽位。
| 语义槽位 | 常见内容 | 生命周期 |
|---|---|---|
| Initial instructions | Harness 基线、项目指令、无条件 Rules | 会话启动或作用域切换 |
| Capability catalog | Skill metadata、延迟工具目录 | 启动装配,受预算和权限过滤 |
| Tool definitions | 内置工具、MCP schema、Skill 元工具 | 由 Harness 和 API 能力决定 |
| Conversation history | 用户请求、模型输出、已加载 Skill 正文 | 随轮次增长,可能被 compact |
| Tool output | 文件内容、脚本结果、Skill 工具返回 | 靠近当前调用,之后进入历史 |
| Rehydrated context | compact 摘要、根指令、最近 Skill、记忆指针 | 压缩后重新装配 |
Claude Code 官方文档只承诺 Skill listing 和调用后的正文生命周期,不承诺 listing 永远位于固定 API role,也不承诺使用固定 <system-reminder> 包装。把一次运行时 trace 提升成长期产品契约,会让文章很快过期。
热更新不等于重复注入
热更新解决的是 Registry 和未来调用看到哪个版本,重复注入讨论的是会话历史是否增加副本。两者没有必然关系。
截至核验日期,各产品公开边界如下。
| Harness | 已确认行为 | 不能据此推出 |
|---|---|---|
| Claude Code | 监视已存在的个人、项目和附加目录;更新 SKILL.md 后影响 catalog 与未来调用 |
历史中的旧正文会被原地替换 |
| Codex | 文档描述 Skill 变更可被检测,异常时仍可能需要重启 | 所有 surface 都有相同的实时刷新语义 |
| OpenCode | 当前源码从初始化后的 registry 返回正文 | 下一次调用一定重新读取磁盘 |
| Cursor | 官方承诺启动时发现 Skills | 当前聊天必然实时更新 catalog |
| Kimi Code | 官方说明扫描来源和调用方式 | 新增或修改 Skill 必然在下一轮生效 |
Claude Code 的边界更具体:启动后新建顶层 Skill 目录可能需要重启;热检测主要覆盖 SKILL.md,插件中的 Hook、MCP 和 Agent 变化需要单独 reload。已加载的旧正文不会追溯替换。相同渲染结果的重复调用在当前版本只附加短提示;正文发生变化时,新的渲染结果才会作为新内容进入会话。
Compact 之后,Skill 怎样回来
压缩恢复是产品差异最大的环节,也是最不适合互相类推的环节。
stateDiagram-v2
[*] --> Discovered
Discovered --> Selected: route / explicit invoke
Selected --> Loaded: SKILL.md enters context
Loaded --> Active: references / scripts / tools
Active --> Resident: retained in recent history
Resident --> Summarized: full compaction
Resident --> Pruned: tool-output pruning
Summarized --> Rehydrated: product-specific restore
Pruned --> Selected: invoke again
Rehydrated --> Active
Summarized --> Selected: invoke again if not restored
| Harness | 公开可确认的恢复行为 | 仍然未知或没有保证 |
|---|---|---|
| Claude Code | system prompt 保持;根 CLAUDE.md、无条件 Rules、auto memory 重新注入;最近调用的 Skill 正文按预算重挂 |
超出预算的旧 Skill 不会全部保留 |
| OpenCode | 原生 Skill 工具输出受普通 tool-output prune 保护 | full LLM compaction 没有 Skill 正文自动原样重挂保证 |
| Cursor | Always Rules 跨 summarization 保持;历史会话可作为文件检索 | Agent Skill 正文的精确保留和重注入算法未公开 |
| Codex | 自动或手动 compact 可产生 opaque compaction item | 本地 Skill 与 AGENTS.md 的逐项恢复规则未完整公开 |
| Kimi Code | 支持自动压缩和 /compact |
Skill 正文如何保留、淘汰或重挂未公开 |
Claude Code 当前公开了最明确的预算:compact 后每个已调用 Skill 最多重附加 5000 token,全部 Skill 合计最多 25000 token,最近调用优先。这里的 5000 是恢复上限,不是“单个 Skill 平均大小”。
OpenCode 还要区分普通 pruning 与 full compaction。核验日固定 commit 的 compaction 源码把原生 skill 放入 prune 保护名单,因此启用普通工具输出裁剪时不会直接擦掉它;full compaction 会把旧消息总结成摘要,旧 Skill 是否留下足够细节取决于摘要。模型仍可再次调用 skill,但那是恢复路径,不是自动恢复承诺。
Rules、Skill、Tool Search 与 MCP 分别解决什么
这些机制都可能减少前置上下文,却不属于同一层。
| 机制 | 被选择的对象 | 选择器 | 进入上下文的内容 |
|---|---|---|---|
| Rules / AGENTS | 项目约束或文件作用域指令 | always、路径、glob、层级覆盖 | 规则正文 |
| Agent Skills | 可复用工作流与资源包 | description、显式命令、权限 | SKILL.md 与按需资源 |
| Tool Search | 延迟工具定义 | 模型搜索或 Provider 检索 | 具体 tool schema |
| MCP | 外部工具、资源与提示词协议 | Host 配置、权限、Tool Search | 工具定义和调用结果 |
| Plugin | 安装、分发与治理单元 | 用户、项目或组织配置 | 内含组件按各自生命周期工作 |
Anthropic 的 Tool Search 使用 tool_search_tool_regex_20251119 或 tool_search_tool_bm25_20251119 等工具类型。Deferred tool 的完整定义仍随请求提交给 API,但在被发现前不进入模型上下文;发现后以 tool_reference 对应的定义追加到上下文尾部。它优化的是 tool schema 暴露,不是 SKILL.md 的路由。
Codex 所用模型与 Responses API也提供 Tool Search 能力,但不能据此断言所有 Codex CLI、IDE、App 和 Cloud surface 都默认对相同工具集合启用它。API 原语与产品配置仍要分开。
Prompt Cache 不能用“上下文更小”推断命中率
Prompt cache 依赖精确前缀、模型、工具顺序和 Provider 策略。上下文小可能降低单次输入量,但不会自动提高命中率。
一次 Skill 会话的成本至少要拆成:
1 | |
Anthropic 的缓存层级以 tools、system、messages 组成前缀。改变工具集合或顺序可能使后续前缀失效。Tool Search 把新发现的定义追加在后部,目的之一就是避免改写已缓存的前缀。Skill 正文进入对话尾部也通常比修改最前面的 system 内容更容易保持前缀稳定,但实际 cache read/write 仍要看 Provider 返回的计量字段。
产品比较不应再写“缓存利用率高、中、低”。可复现实验至少需要固定:
- Harness 和版本
- Provider 与模型
- Skill 集合、description 长度和权限过滤结果
- tokenizer 与初始工作目录
- 首次请求、重复请求、调用 Skill、修改 Skill、compact 后请求五个测量点
- input、cache creation、cache read、output 和 wall time 的原始记录
没有这些条件,80k、255、4500、135k 之类数字只是环境快照,不能当成产品属性。
Lost in the Middle 是风险,不是固定注意力公式
Lost in the Middle在特定模型和任务上观察到:相关信息放在上下文开头或结尾时,表现往往优于放在中间。论文没有给当前 Claude、GPT 或 Kimi 产品提供统一的 0.9、0.3–0.5 注意力系数,也没有证明某个 Skill 在第 100 轮必然衰减到固定比例。
这项研究对 Skill 设计仍有价值,但结论应该收敛为三个工程判断:
- 目录必须短而可区分,避免候选能力互相遮蔽。
- 当前任务需要的正文应在选择后进入工作上下文,不靠很早以前的一次说明维持。
- 长会话需要明确恢复路径:自动重挂、再次调用、外部指针或重新检索,至少要有一种可观察机制。
更大的最大上下文可以推迟容量耗尽。如果实际 Prompt 内容和位置都不变,仅把模型上限从 128K 换成 256K,并不会自动改变其中 token 的顺序,也不能据此证明注意力分布改善。
五个 Harness 的当前共同点与差异
| Harness | 启动目录 | 正文进入时机 | 主要差异 |
|---|---|---|---|
| Claude Code | 预算治理后的 Skill listing | 用户或模型调用 | 热更新边界、重复调用去重、compact 重挂预算公开较细 |
| Codex | name + description + path,受目录预算约束 |
显式 $skill 或隐式匹配后 |
AGENTS.md 链、Skill、API Skill 和 Plugin 分属不同执行面 |
| OpenCode | system prompt 与 skill 工具描述中均有目录 |
调用内置 skill 元工具 |
宿主 registry 可预读正文,普通 prune 与 full compact 分开 |
| Cursor | Rules / AGENTS.md 与 Skill catalog 并存 |
Rule 按模式应用;Skill 动态或手动调用 | 静态指令、动态能力、Subagent、Hook 和 Plugin 已组成完整体系 |
| Kimi Code | 按项目、用户、额外目录和内置来源发现 | 模型路由或 /skill:name |
可使用不同 Provider,不能把 K2 模型窗口当作 Harness 策略 |
主流实现已经不再是“Claude Code 全量加载、OpenCode 按需加载、Cursor 只有 glob、Kimi 靠大窗口”这条四分法。它们正在收敛到轻量目录与正文渐进展开,差异转向目录预算、路由、消息形态、刷新边界、压缩恢复、权限和分发。
设计一个可维护的 Skill 加载器
一个新的 Harness 若要实现 Skill,最低限度应把以下契约写清楚。
Discovery
- 支持哪些目录和优先级
- 重名 Skill 如何覆盖
- catalog 的字段、预算和截断告警
- 权限拒绝的 Skill 是否从目录隐藏
Routing
- 显式调用和自动调用是否共用入口
- description 如何参与选择
- 文件作用域、项目规则和用户指令冲突时谁优先
- 路由失败是否可观察
Loading
- 宿主何时读磁盘,是否缓存正文
- 正文以哪类语义消息进入会话
- references、scripts、assets 怎样按需展开
- 重复调用是复用、短提示还是正文副本
Recovery
- tool-output pruning 是否保护 Skill
- full compact 是否摘要、重挂或要求再次调用
- compact 后的目录是否重建
- 旧正文与磁盘新版本冲突时采用哪个版本
Observability
- 能否看到 catalog 实际占用
- 能否区分 cache creation、cache read 和未缓存输入
- 能否追踪哪个 Skill 被选择、加载、裁剪和恢复
- 能否用固定 prompt 集测试触发率与执行质量
这五组契约比“支持 Agent Skills”这个布尔值更有解释力。同样读取 SKILL.md 的产品,运行时成本和长会话可靠性仍可能完全不同。
系列文章
- AI Coding Agent 的上下文操作系统:组件、生命周期与阅读地图
- AI Coding Agent 的上下文栈:组件边界与装配顺序
- 从 Rules 到 Agent Skills:能力加载机制的演变
- 2026 Coding Harness 实现图谱
- 一次 Agent Turn:Hook、Loop、Tool 与 Messages
- Messages 数组与 Prompt Cache:六种操纵策略
- Context Paging:Compact、外部化、恢复与 Memory 生命周期
参考资料
- Agent Skills open standard
- Claude Code: Extend Claude with skills
- Claude Code: Explore the context window
- Claude Code: Prompt caching
- Codex: Build skills
- Codex: How Codex discovers project guidance
- OpenAI: Unrolling the Codex agent loop
- OpenCode: Skills
- OpenCode: Skill service,固定于 2026-07-17 dev commit
- OpenCode: Session compaction,固定于 2026-07-17 dev commit
- OpenCode: Native Agent Skills PR
- Cursor: Agent Skills
- Cursor: Rules
- Cursor: Dynamic context discovery
- Kimi Code: Skills
- Kimi Code: Sessions and context
- Kimi K2 model card
- Kimi K2-0905 update
- Anthropic: Tool search tool
- Anthropic: Tool use with prompt caching
- Liu et al.: Lost in the Middle





