跳转到内容

Skills 注册表与渐进式披露

学习目标

理解 CrewAI 的 Skills 注册表系统如何通过三级渐进式披露和三级注册表解析实现按需加载,以及如何在 Agent 上下文中注入技能指令。

前置知识

下文假设你已理解上述概念,直接聚焦 CrewAI 的具体实现。


项目实践

SKILL.md 标准

每个 Skill 目录包含一个 SKILL.md 文件,包含 frontmatter 元数据和指令:

---
name: skill-name
description: 一句话描述
version: 1.0.0
compatibility: ["crewai>=0.100"]
allowed_tools: ["tool_a", "tool_b"]
---
# Skill 指令内容
...

三级渐进式披露

级别加载内容触发方式
METADATA=1仅元数据discover_skills() 目录扫描发现
INSTRUCTIONS=2包含指令内容(SKILL.md 正文)activate_skill()
RESOURCES=3包含资源文件load_resources()

与通用渐进式披露(如 Claude Code 在触发时一次性加载 SKILL.md)不同,CrewAI 将披露分为三个阶段,每个阶段明确可控。Agent 可以先了解有什么 Skill,再决定是否需要加载指令,最后才加载资源文件。

三级注册表解析

# 伪代码:解析顺序
# 1. 项目本地
skill = resolve("./skills/{name}/")
# 2. 全局缓存
skill = resolve("~/.crewai/skills/{org}/{name}/")
# 3. 远程 API
skill = resolve("@org/name") # 通过 PlusAPI 下载

支持 @org/name 格式的注册表引用。SkillNotCachedError 在 CI/非交互模式下抛出,确保生产环境不依赖外部 API。

XML 提示词注入

format_skill_context() 将 Skill 内容生成为 XML 包装的提示词:

<skill name="skill-name">
<metadata>...</metadata>
<instructions>...</instructions>
<resources>...</resources>
</skill>

XML 格式使得 LLM 可以清晰区分不同 Skill 的指令,减少多 Skill 同时激活时的指令混淆。


问题与规避

SkillNotCachedError 在 CI 环境下阻塞

  • 远程 Skill 未缓存到本地时,非交互模式会抛出此错误
  • 对策:在 CI 环境中预先缓存所需 Skill,或使用 --skip-skills 跳过技能加载

多 Skill 指令冲突

  • 多个 Skill 同时激活时,指令可能相互矛盾
  • 对策:在 Skill 的 compatibility 字段中声明不兼容的 Skill,Loader 在激活时检查

资源文件路径安全

  • Skill 的资源文件可能被诱导读取超出 Skill 目录的路径
  • 对策:load_resources() 严格限制在 Skill 目录内解析

设计取舍

三级披露 vs 一次性加载

  • 三级披露的优势是精细控制 Token 消耗,避免不必要的资源文件加载
  • 代价是增加了 Loader 的复杂度,需要维护三个级别的加载状态

注册表引用 vs 本地目录

  • 注册表引用(@org/name)支持跨项目共享 Skill
  • 本地目录(./skills/)更简单,适合项目特定的技能
  • CrewAI 同时支持两者,解析顺序确保本地优先

参考来源

  • 源码验证: lib/crewai/src/crewai/skills/loader.py
  • 源码验证: lib/crewai/src/crewai/skills/models.py
  • 源码验证: lib/crewai/src/crewai/skills/registry.py