Claude Code 05:Skill Loading——领域知识动态加载

随着 Agent 接入的业务系统越来越复杂,团队往往希望为它注入各种专有知识:代码审查规范、安全审计红线、API 文档模版、数据库变更规范、前端埋点要求等。

很多开发者的第一反应是把所有这些规范全量拼接到 System Prompt(系统提示词)中。然而,这种做法在真实工程中会迅速撞上物理墙:

  1. Token 费用线性暴增:哪怕用户只是让 Agent 执行一条 git status,每一次模型请求都要带上 20,000+ Token 的静态规范;
  2. 长距离注意力稀释:Prompt 越长,大模型对核心用户指令的遵从度越低,甚至会出现相互冲突的规则互相打架;
  3. 极度缺乏灵活性:每更新一次规范,都要重启服务或修改全局硬编码配置。

Claude Code 采用了优雅的渐进式披露(Progressive Disclosure)与按需动态加载机制(Skill Loading)。本文将拆解其双层注入架构与 SKILL.md 标准设计。


两层渐进披露机制

Skill 加载的核心理念非常朴素:平时只保留极简目录,需要时才调取全文文档。

这种方案实现了惊人的 Token 经济性:将每轮对话的默认系统开销从 20,000+ Token 骤降到 100 Token 以内。只有当具体任务涉及安全审查或数据库重构时,对应规范才会临时加载一轮,任务完成后自动淡出,不长期霸占上下文。


极简 Python 实现:SkillManager 与动态技能工具

我们实现一个扫描本地目录并支持动态加载的技能管理器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import os
import re
from typing import Dict, List

SKILLS_DIR = os.path.expanduser("./skills")

class SkillManager:
def __init__(self, base_dir: str = SKILLS_DIR):
self.base_dir = base_dir
self.skills: Dict[str, dict] = {}
self.load_all_manifests()

def load_all_manifests(self):
"""仅预扫描所有技能的元数据(极简描述),不读取正文"""
if not os.path.exists(self.base_dir):
os.makedirs(self.base_dir, exist_ok=True)
return

for name in os.listdir(self.base_dir):
skill_path = os.path.join(self.base_dir, name, "SKILL.md")
if os.path.isdir(os.path.join(self.base_dir, name)) and os.path.exists(skill_path):
desc = self._extract_description(skill_path)
self.skills[name] = {
"name": name,
"description": desc,
"file_path": skill_path
}

def _extract_description(self, file_path: str) -> str:
"""从 SKILL.md 的 YAML 前置元数据中提取 description"""
with open(file_path, "r", encoding="utf-8") as f:
content = f.read(1024)
m = re.search(r"description:\s*([^\n\r]+)", content)
return m.group(1).strip() if m else "暂无描述"

def render_system_index(self) -> str:
"""构建轻量级的 System Prompt 索引摘要"""
if not self.skills:
return ""
lines = ["\n## 可用专业技能 (可调用 load_skill 获取完整操作准则):"]
for name, meta in self.skills.items():
lines.append(f"- **{name}**: {meta['description']}")
return "\n".join(lines)

def fetch_full_skill(self, name: str) -> str:
"""模型按需加载:读取完整的操作指南 Markdown 文本"""
if name not in self.skills:
return f"Error: 未找到名为 '{name}' 的技能。可用技能: {list(self.skills.keys())}"

with open(self.skills[name]["file_path"], "r", encoding="utf-8") as f:
return f.read()

skill_mgr = SkillManager()

将技能加载封装为 Tool 挂载至分发字典:

1
TOOL_HANDLERS["load_skill"] = lambda **kw: skill_mgr.fetch_full_skill(kw["skill_name"])

在系统初始化时,仅将 skill_mgr.render_system_index() 拼入 system_prompt。当用户提问“请审计这段代码的安全风险”时,模型在索引中命中 sec-audit,主动发起 load_skill(skill_name="sec-audit"),规范全文随即作为工具结果注入。


生产源码探秘:Claude Code 的三条加载路径

在 Claude Code 源码的 src/skills/loadSkillsDir.ts 中,系统支持并维护了三条并行的技能发现链路:

路径 1:现代 /skills/ 规范目录(工业标准)

只接受目录嵌套格式:~/.claude/skills/<skill-name>/SKILL.md。

1
2
3
4
5
6
7
// 源码来自 loadSkillsDir.ts -> loadSkillsFromSkillsDir()
if (!entry.isDirectory() && !entry.isSymbolicLink()) {
// 单个独立 .md 文件在现代 /skills/ 目录下会被安全忽略
return null
}
const skillDirPath = join(basePath, entry.name)
const skillFilePath = join(skillDirPath, 'SKILL.md')

路径 2:遗留 /commands/ 目录(已声明废弃)

兼容历史命令库。同时支持单文件 xxx.md 与子目录;但源码在解析时会将 loadedFrom 标记为 'commands_DEPRECATED',且不享受条件路径自动激活特性。

路径 3:MCP 动态注入技能

通过 mcpSkillBuilders.ts 注册中心解耦。当外部 MCP Server 连接成功后,将其对外暴露的复合工作流注册为本地 Skill,主运行时与底层协议彻底松耦合。


现代 SKILL.md 标准文件规范

一个结构严谨、支持多 Agent 通用的 SKILL.md 包含 YAML Frontmatter 元数据与执行正文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
---
name: security-audit
description: 审计当前工程中潜在的 SQL 注入、密钥泄露、SSRF 与危险依赖
triggers:
- "安全审计"
- "security audit"
- "检查漏洞"
paths:
- "src/api/**/*.ts"
- "src/controllers/**/*.ts"
tools_required:
- Read
- Grep
- Bash
---

# 安全审计操作准则

你是资深应用安全工程专家。当加载本技能后,执行以下严格规程:

## 1. 静态特征扫描
- 必须使用 Grep 工具搜索源码中的 `password =`、`PRIVATE KEY`、`sk-ant-` 等敏感硬编码;
- 检查所有 SQL 执行点,确认全部采用参数化绑定(Parameterized Queries)。

## 2. 输出格式约定
审计报告必须严格采用以下结构化 Markdown 呈现:
| 严重程度 | 问题类型 | 物理位置 (文件:行号) | 风险描述与修复建议 |
| :--- | :--- | :--- | :--- |

关键特性:paths 条件自动唤醒

注意 Frontmatter 中的 paths 字段:当主 Agent 正在读取或编辑匹配 src/api/**/*.ts 的文件时,系统会在后台隐式自动激活该技能,无需用户显式输入触发词。这种上下文感知的自动激活让开发体验行云流水。


总结

Skill Loading 机制代表了 Agent 工程化中关于知识管理的成熟范式:

  1. 告别 Prompt 堆砌:用极简索引替代大段静态文本,将常驻 Token 损耗压制在极限水平;
  2. 渐进式调取:把规范降级为一种“可被调用的工具数据”,由大模型根据任务上下文自主按需获取;
  3. 跨平台规范化:基于目录与 SKILL.md 契约,让一个技能包可以在 Claude Code、Pi 以及各类自研 Agent 之间无缝复用。

至此,我们的 Agent 已经拥有了核心循环、原子文件工具、防迷航规划与动态技能库。但在长达数小时的长任务中,随着消息不断累积,整个会话最终依然会突破物理上下文窗口上限。

下一篇我们将攻坚最硬核的内存治理环节:Context Compact 三层上下文压缩机制。