Agent 框架 11:Skills 与 Claude Code——模块化技能系统设计

在构建企业级智能体或研发辅助 Agent 时,团队往往会面临一个典型的困境:随着业务能力的增加,团队希望让 Agent 既精通数据库慢查询排查,又精通 Kubernetes 资源发布,还熟悉前端代码审查规范。

传统最直接的做法,是把所有业务 SOP、接口文档和编码规范全部堆进全局的 System Prompt。这种做法有三个致命硬伤:

  1. Token 浪费与成本飙升:即使用户只是打个招呼或者问个天气,模型也必须吞吐几万字的规则文档。
  2. 上下文污染与注意力涣散(Lost in the Middle):过长且无关的提示词会稀释大模型的注意力,导致在关键指令上产生“指令遗忘”或执行走样。
  3. 团队协作维护噩梦:不同部门的规范混在一个巨大的文本里,改动极易相互冲突。

Anthropic 在其命令行编程助手 Claude Code 中推广的 Skill(技能)机制,给出了一个极具工程美感的解决方案:将专业技能拆分为相互独立的模块化文件,按需动态加载(On-demand Loading),用完即走,不占用常驻上下文。


核心设计:按需翻阅的“技能书”模型

Skill 机制的哲学可以类比为人类专家的工作方式:一位全栈架构师并不需要每分每秒把《MySQL 性能优化》和《Kubernetes 权威指南》完整背诵在大脑工作内存中;当遇到数据库问题时,才去书架上翻开对应的操作手册:


Skill 目录规范与文件结构

一个合规的 Skill 采用类似静态博客或静态站点的轻量文件组织结构:

1
2
3
4
5
6
7
8
9
skills/
├── database-ops/
│ ├── SKILL.md # 必须:技能核心规范(含 YAML Frontmatter 与操作指令)
│ └── references/ # 可选:供深入检索的补充排查手册
│ └── explain-guide.md
├── code-review/
│ └── SKILL.md
└── k8s-deploy/
└── SKILL.md

标准 SKILL.md 模板示范

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
---
name: database-ops
description: >
生产级数据库运维操作指南,包含 MySQL 慢查询分析、索引优化与锁冲突排查。
当用户提到"数据库"、"慢查询"、"SQL 优化"、"死锁"时动态激活。
---

# 数据库排查与优化指南

## 1. 慢查询分析标准操作流 (SOP)
当排查线上慢查询时,必须引导用户按以下顺序提供信息:
1. 先确认是否通过 `EXPLAIN` 查看了实际执行计划,检查 `type` 是否为 `ALL`(全表扫描)。
2. 检查 `rows` 扫描行数与实际返回行数的比例。
3. 检查 `key` 字段是否有效命中预期索引。

## 2. 索引设计红线
- 严禁在基数极低(如 status 仅有 0/1)的字段上建立单列索引。
- 联合索引必须严格遵循最左前缀原则。
- 涉及范围查询(`<`, `>`)的字段必须放在联合索引的最右侧。

## 3. 输出格式
按以下结构给出排查结论:
- **【核心瓶颈诊断】**:说明慢查询根因。
- **【执行计划分析】**:针对 key/type 进行分析。
- **【优化改写建议】**:给出具体 SQL 改写或 `ALTER TABLE` 语句。

从零实现:支持动态 Skill 加载的 Agent

我们不需要安装 Claude Code 客户端,只需利用 Python 即可实现一个具备相同能力的 SkillAgent。

1. 技能扫描与元数据提取器

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import os
import re
from pathlib import Path
from typing import Optional
from anthropic import Anthropic

client = Anthropic()

class SkillAgent:
"""具备按需加载技能能力的现代化智能体"""

def __init__(self, skills_dir: str = "./skills"):
self.skills_dir = Path(skills_dir)
self.skills_meta: list[dict] = self._index_skills()

def _index_skills(self) -> list[dict]:
"""扫描本地目录,仅提取各 Skill 的 name 与 description 元数据"""
indexed = []
if not self.skills_dir.exists():
return indexed

for s_dir in self.skills_dir.iterdir():
skill_file = s_dir / "SKILL.md"
if s_dir.is_dir() and skill_file.exists():
text = skill_file.read_text(encoding="utf-8")
# 正则提取 YAML Frontmatter
name_match = re.search(r"^name:\s*(.+)$", text, re.MULTILINE)
desc_match = re.search(r"^description:\s*>?(.*?)(?=---|\n#)", text, re.DOTALL | re.MULTILINE)

if name_match:
name = name_match.group(1).strip()
desc = desc_match.group(1).strip() if desc_match else ""
indexed.append({
"name": name,
"description": desc,
"file_path": skill_file,
})
return indexed

def _match_skill(self, user_query: str) -> Optional[dict]:
"""利用轻量快速模型做意图匹配,毫秒级判定该加载哪本技能书"""
if not self.skills_meta:
return None

skills_summary = "\n".join([
f"- 技能标识 [{s['name']}]: {s['description']}"
for s in self.skills_meta
])

router_prompt = f"""根据用户的输入,判断是否需要激活特定的专业技能。
可用技能库:
{skills_summary}

用户当前输入:
"{user_query}"

判定规则:
若匹配,仅输出对应的技能标识(例如: database-ops)。
若无任何技能匹配,仅输出 NONE。不要输出多余解释。"""

# 使用低延迟模型(如 Claude 3.5 Haiku)降低路由耗时
res = client.messages.create(
model="claude-3-5-haiku-20241022",
max_tokens=20,
temperature=0,
messages=[{"role": "user", "content": router_prompt}],
)
matched_name = res.content[0].text.strip()
for s in self.skills_meta:
if s["name"] == matched_name:
return s
return None

def run(self, user_query: str) -> str:
"""主执行流程:意图匹配 -> 动态装配 -> 执行主推理"""
base_system = "你是一个高水平的技术工程助手。用客观、严谨且精炼的中文回答。"

# 1. 尝试匹配技能
matched = self._match_skill(user_query)
if matched:
print(f"💡 [动态技能激活] 命中技能: {matched['name']}")
skill_content = matched["file_path"].read_text(encoding="utf-8")
# 过滤掉顶部 frontmatter,提取纯指令
clean_instruction = re.sub(r"^---.*?---\s*", "", skill_content, flags=re.DOTALL)
system_prompt = f"{base_system}\n\n# 【当前激活领域技能规范】\n{clean_instruction}"
else:
print("ℹ️ [通用模式] 未命中特定技能,使用基础系统指令")
system_prompt = base_system

# 2. 调用主思考模型生成最终答复
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=3000,
system=system_prompt,
messages=[{"role": "user", "content": user_query}],
)
return response.content[0].text

编写高质量 Skill 的四项黄金法则

在为 Agent 沉淀技能库时,以下工程原则至关重要:

  1. 单一职责原则(Single Responsibility):每个 Skill 必须高度聚焦在单一垂直场景(如“代码审查”、“SQL 排查”、“接口文档生成”),严禁把相互无关的运维手册与财务规范混入同一个文件。
  2. 触发词明确具体:在 description 中明确列出触发该技能的高频技术专有名词和典型场景,便于路由器准确识别。
  3. 指令使用祈使句与具体 SOP:大模型更适合执行“先做 A,再做 B,输出格式为 C”这种指令式 SOP,而非宽泛的概念科普。
  4. 严格控制 Token 长度:单篇 SKILL.md 建议控制在 300~500 行以内。如果业务背景极长,应放入 references/ 目录供二级细粒度检索。

优缺点分析与工程选型边界

核心优势

  • 极致的上下文经济性:将数万字的领域知识压缩为若干短句 Summary,只有真正命中时才产生 Token 开销。
  • 团队资产沉淀极佳:每个工程师都可以把自己擅长领域的排查经验提炼成一个独立的 Markdown 文件,PR 提交后全团队立即共享该技能。
  • 解耦无框架依赖:底层只是纯 Markdown 文件,既可以无缝对接 Claude Code,也可以嵌入自研的 Python、Go 或 Node.js 智能体服务。

现实痛点与妥协

  • 多一轮路由判定开销:在未命中显式 Slash Command(如 /skill xxx)时,需要前置调用一次轻量模型判定,增加数十毫秒的网络延时。
  • 复杂场景下的技能冲突:如果存在两个定义边界模糊的技能(例如“SQL 重构”与“数据库排查”),路由器可能会出现摆动或误激活。

关联导航