Spring AI Alibaba 1.x 系列【25】 Skills 技能体系使用攻略
文章目录
1. 基础知识
Skills(技能) 是 Spring AI Alibaba 中可复用的指令与上下文封装单元,智能体在处理相关任务时可自动发现、按需加载并使用技能。
Spring AI Alibaba 通过 SkillRegistry 统一管理技能资源,配合 SkillsAgentHook 实现技能列表注入、read_skill 工具注册,模型可按照渐进式披露策略,仅在需要时加载完整技能内容,大幅提升提示词效率与智能体能力复用性。
1.1 Skill 目录结构规范
每个技能对应独立子目录,目录结构标准化,SKILL.md 为强制必需文件:
技能根目录/
├── pdf-extractor/ # 技能1:PDF提取
│ ├── SKILL.md # ✅ 必需:技能核心描述与使用说明
│ ├── references/ # 可选:参考文档、API说明
│ ├── examples/ # 可选:使用示例
│ └── scripts/ # 可选:Python/Shell脚本
│
├── code-analyzer/ # 技能2:代码分析
│ ├── SKILL.md
│ └── ...
1.2 SKILL.md 格式规范
SKILL.md 采用 YAML 头 + Markdown 正文 格式,是技能的核心描述文件。
基础格式:
---
name: pdf-extractor
description: 用于从PDF文件中提取文本、表格、图片与关键信息,支持本地PDF路径解析
---
# PDF 提取技能
本技能支持对本地PDF文件执行:
1. 文本全文提取
2. 表格结构化解析
3. 关键信息自动抽取
4. 配合Python脚本实现PDF加密破解
## 可用资源
- scripts/extract_pdf.py:PDF解析主脚本
- references/pdf-spec.pdf:PDF格式规范说明
必需字段:
| 字段 | 要求 | 说明 |
|---|---|---|
| name | 必需,最长64字符 | 技能唯一标识,建议小写字母+数字+连字符 |
| description | 必需 | 技能用途简述,超长会被自动截断 |
1.3 渐进式披露
Skills 采用渐进式披露设计,是技能机制的核心设计思想:
- 系统提示中仅注入技能摘要:技能名称(
name)、描述(description)、技能路径(skillPath) - 模型判断需要使用某技能时,主动调用
read_skill(skill_name)工具 - 加载该技能对应的完整
SKILL.md内容 - 按需使用技能绑定的工具、脚本、参考资料等资源
优势:
- 避免一次性注入大量技能内容导致提示词过长
- 模型按需加载,精准使用能力
- 技能可复用、可插拔、可扩展
2. 案例演示
2.1 下载 Skill
在 https://skills.sh/ 可以看到当前有 9 万多个 Skills ,可以在这里下载你想要的:

这里直接在 Spring AI Alibaba 框架 中下载一些:

包含 4 个技能:
| 技能英文 | 中文名称 | 技能描述 |
|---|---|---|
| copywriting | 商品文案写作 | 中文技能,根据商品信息生成营销文案,输出 10 字以内的简短文案 |
| product-selection | 选品分析 | 中文技能,根据市场趋势分析推荐商品品类,输出 10 字以内的选品建议 |
| pdf-extractor | PDF 提取器 | 从 PDF 文档中提取文本、表格和表单数据,支持元数据提取 |
| grouped-tools-test | 分组工具测试 | 测试技能,用于验证通过 groupedTools 注册的工具是否可用 |
2.2 注册中心
Spring AI Alibaba 提供两种标准 SkillRegistry 实现,用于加载技能资源:
FileSystemSkillRegistry:从本地文件系统加载技能ClasspathSkillRegistry:从Classpath(resources) 加载技能
2.2.1 FileSystemSkillRegistry
适用于本地开发、外部技能目录,支持项目级/用户级目录覆盖。
通过 Builder 模式构建,支持以下配置项:
| 配置项 | 类型 | 默认值 | 用途 |
|---|---|---|---|
| userSkillsDirectory | String 或 Resource | ~/saa/skills(用户主目录下的 skills 文件夹) | 存放全局技能,对所有项目可用 |
| projectSkillsDirectory | String 或 Resource | ./skills(当前工作目录下的 skills 文件夹) | 存放项目特定技能,优先级高于用户技能 |
| autoLoad | boolean | true | 是否在初始化时自动加载技能 |
| systemPromptTemplate | SystemPromptTemplate 或 String | 内置 DEFAULT_SYSTEM_PROMPT_TEMPLATE | 自定义技能在系统提示中的展示方式,支持变量:{skills_registry}、{skills_list}、{skills_load_instructions} |
使用示例:
// 使用默认配置
FileSystemSkillRegistry registry = FileSystemSkillRegistry.builder().build();
// 自定义用户技能目录
FileSystemSkillRegistry registry = FileSystemSkillRegistry.builder()
.userSkillsDirectory("/custom/path/to/skills")
.build();
// 完整配置
FileSystemSkillRegistry registry = FileSystemSkillRegistry.builder()
.userSkillsDirectory("/global/skills")
.projectSkillsDirectory("./project/skills")
.autoLoad(true)
.build();
// Use Spring Resource for directories
FileSystemSkillRegistry registry = FileSystemSkillRegistry.builder()
.userSkillsDirectory(new FileSystemResource("/custom/user/skills"))
.projectSkillsDirectory(new ClassPathResource("skills"))
.build();
2.2.2 ClasspathSkillRegistry
适用于技能随项目打包(src/main/resources/skills),JAR 包内资源会自动复制到临时目录。
通过 Builder 模式构建,支持以下配置项:
| 配置项 | 类型 | 默认值 | 用途 |
|---|---|---|---|
| classpathPath | String | skills(即 classpath:skills) | 存放技能的类路径位置,支持文件系统(开发环境)和 JAR 包(生产环境) |
| basePath | String | /tmp | 用于存储从类路径复制出来的技能资源(脚本、配置文件等),JAR 包内文件无法直接访问,会复制到此目录 |
| autoLoad | boolean | true | 是否在初始化时自动加载技能 |
| systemPromptTemplate | SystemPromptTemplate 或 String | 内置 DEFAULT_SYSTEM_PROMPT_TEMPLATE | 自定义技能在系统提示中的展示方式 |
使用示例:
// 使用默认配置(classpath:skills)
ClasspathSkillRegistry registry = ClasspathSkillRegistry.builder().build();
// 自定义类路径技能目录
ClasspathSkillRegistry registry = ClasspathSkillRegistry.builder()
.classpathPath("custom/skills")
.build();
// 完整配置
ClasspathSkillRegistry registry = ClasspathSkillRegistry.builder()
.classpathPath("skills")
.basePath("/tmp/skills")
.autoLoad(true)
.build();
2.2.3 配置注册中心
配置注册中心:
// 创建 FileSystemSkillRegistry 实例,用于从文件系统加载和管理技能
SkillRegistry registry = FileSystemSkillRegistry.builder()
// 设置用户技能目录(全局技能,对所有项目可用)
// System.getProperty("user.home") 获取当前用户主目录
// Windows 示例:C:\Users\TD\saa\skills
// Linux/Mac 示例:/home/td/saa/skills
.userSkillsDirectory(System.getProperty("user.home") + "/saa/skills")
// 设置项目技能目录(项目特有技能,优先级高于用户技能)
// 如果用户技能和项目技能有同名,项目技能会覆盖用户技能
// 当前项目路径:D:/java/ai/spring-ai-alibaba/skills
.projectSkillsDirectory("D:/java/ai/spring-ai-alibaba/skills")
// 启用自动加载(默认值为 true)
// true = 在 build() 时立即扫描并加载两个目录下的所有技能
// false = 不自动加载,需要手动调用 reload() 方法加载
.autoLoad(true)
.build();
默认的系统提示词模板:
/**
* FileSystemSkillRegistry 的默认系统提示词模板。
* 该模板定义了技能在系统提示词中的展示方式。
* 支持以下变量:
* - {skills_registry}:注册表类型名称
* - {skills_list}:格式化后的可用技能列表
* - {skills_load_instructions}:技能加载说明
*/
public static final String DEFAULT_SYSTEM_PROMPT_TEMPLATE = """
## 技能系统
你可以使用一套技能库,它提供专业能力与领域知识支持。所有技能均存储在基于文件系统的技能注册表中。
### 可用技能
{skills_list}
### 技能使用方式(渐进式披露)
技能遵循**渐进式披露**模式——你已知晓技能的存在(名称+描述),但仅在需要时才读取完整指令:
1. **判断技能适用场景**:检查用户任务是否匹配任一技能的描述
2. **读取技能完整指令**:上方技能列表中会给出可用于 `read_skill` 的精确技能 ID
3. **遵循技能执行流程**:SKILL.md 中包含分步工作流、最佳实践与示例
4. **访问配套文件**:技能可能包含 Python 脚本、配置或参考文档,请使用绝对路径访问
#### 如何读取完整技能指令
当前使用的是基于文件系统的技能注册表,请按照下方加载规则执行:
{skills_load_instructions}
**重要说明:**
- **对于 SKILL.md(技能说明文件)**:必须使用 `read_skill` 读取技能指令,禁止通过其他方式访问 SKILL.md
- **对于技能使用的其他配套文件(脚本、参考文档等)**:可根据需要使用其他合适工具读取或访问,一律使用技能列表中的绝对路径
#### 技能适用场景
- 用户请求与技能领域匹配时(例如:“调研XX”→对应 web-research 技能)
- 需要专业领域知识或结构化工作流时
- 技能提供成熟方案可用于处理复杂任务时
#### 技能自包含说明
- 每个 SKILL.md 都会明确说明技能功能与使用方法
- 上方技能列表展示了每个技能 SKILL.md 文件的完整路径
#### 执行技能脚本
技能可能包含 Python 脚本或其他可执行文件,请一律使用技能列表中的绝对路径运行。
### 流程示例
用户:“你能调研一下量子计算的最新进展吗?”
1. 查看上方可用技能 → 找到 `web-research` 技能及其 ID
2. 使用列表中展示的 ID 读取该技能
3. 遵循技能的调研流程(搜索→整理→归纳)
4. 使用绝对路径调用相关辅助脚本
记住:技能是提升你能力与输出一致性的工具。如有疑问,先检查是否存在对应任务的技能!
""";
2.2.4 查询、管理技能
查看技能列表:
// 列出所有技能
List<SkillMetadata> allSkills = registry.listAll();
// 获取技能数量
int count = registry.size();
返回如下:

其中 SkillMetadata 包含的字段:
| 字段 | 说明 |
|---|---|
| name | 技能名称(如 inventory_management) |
| description | 技能描述 |
| skillPath | 技能目录的绝对路径 |
| source | 来源(user 或 project) |
| allowedTools | 允许使用的工具列表 |
| fullContent | SKILL.md 完整内容 |
查找技能:
// 按名称查找
Optional<SkillMetadata> skill = registry.get("inventory_management");
// 按路径查找
Optional<SkillMetadata> skillByPath = registry.getByPath("C:/Users/TD/saa/skills/inventory_management");
// 搜索(按名称、描述或路径)
List<SkillMetadata> results = registry.search("inventory");
// 检查是否存在
boolean exists = registry.contains("sales_analytics");
读取技能内容:
// 按名称读取 SKILL.md 完整内容
String content = registry.readSkillContent("inventory_management");
// 按路径读取
String contentByPath = registry.readSkillContentByPath("/path/to/skill");
查看注册表信息:
// 获取注册表类型(如 "FileSystem" 或 "Classpath")
String type = registry.getRegistryType();
// 获取技能加载说明
String instructions = registry.getSkillLoadInstructions();
// 获取系统提示模板
SystemPromptTemplate template = registry.getSystemPromptTemplate();
技能状态管理:
// 禁用技能
registry.disable("inventory_management");
// 按路径禁用
registry.disableByPath("/path/to/skill");
// 检查是否已禁用
boolean isDisabled = registry.isDisabled("inventory_management");
重新加载技能:
// 重新扫描目录并加载技能
registry.reload();
生产环境中,技能常配合 Python 脚本、Shell 命令 实现真实业务能力,以下为完整集成方案:
// 1. 加载 Classpath 技能
SkillRegistry registry = ClasspathSkillRegistry.builder()
.classpathPath("skills")
.build();
// 2. 技能 Hook
SkillsAgentHook skillsHook = SkillsAgentHook.builder()
.skillRegistry(registry)
.build();
// 3. Shell 工具 Hook(指定工作目录)
ShellToolAgentHook shellHook = ShellToolAgentHook.builder()
.shellTool2(ShellTool2.builder(System.getProperty("user.dir")).build())
.build();
// 4. 构建 Agent:技能 + Shell + Python
ReactAgent agent = ReactAgent.builder()
.name("skills-integration-agent")
.model(chatModel)
.saver(new MemorySaver())
.tools(PythonTool.createPythonToolCallback(PythonTool.DESCRIPTION))
.hooks(List.of(skillsHook, shellHook))
.enableLogging(true)
.build();
// 5. 执行:模型先 read_skill,再调用 Python/Shell 处理文件
String pdfPath = "/skills/pdf-extractor/saa-roadmap.pdf";
agent.call("请从 " + pdfPath + " 中提取关键信息");
2.3 技能钩子
使用 SkillsAgentHook 将 SkillRegistry 传递给 ReactAgent 。
SkillsAgentHook 提供的功能:
- 自动注入
read_skill工具 - LLM 可以用它读取技能详情 - 自动注入
search_skills工具 - 搜索可用技能 - 自动注入
disable_skill工具 - 禁用技能 - 注册
SkillsInterceptor- 在系统提示中添加技能列表
必选配置:
| 配置项 | 类型 | 说明 |
|---|---|---|
| skillRegistry | SkillRegistry | 技能注册表实例,必须提供。通常使用 FileSystemSkillRegistry.builder() 创建 |
可选配置:
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| autoReload | boolean | false | 是否在每次 agent 调用前自动重新加载技能 |
| groupedTools | Map<String, List<ToolCallback>> | 空 Map | 技能名到工具列表的映射,将工具与技能绑定,实现按需暴露工具:仅在模型调用 read_skill 后,对应工具才会生效。 |
示例代码:
// 2. 创建 SkillsAgentHook
SkillsAgentHook hook = SkillsAgentHook.builder()
.skillRegistry(registry) // 必选:技能注册表
.autoReload(true) // 可选:启用自动重载
.build();
2.4 商品文案写作、选品分析
Agent 配置类:
@Configuration
class ClientConfig {
@Bean("chatAgent")
public ReactAgent chatAgent(ZhiPuAiChatModel zhiPuAiChatModel) throws GraphRunnerException {
// 1. 创建 SkillRegistry
SkillRegistry registry = FileSystemSkillRegistry.builder()
.userSkillsDirectory(System.getProperty("user.home") + "/saa/skills")
.projectSkillsDirectory("D:/java/ai/skills")
.autoLoad(true)
.build();
// 2. 创建 Hook
SkillsAgentHook hook = SkillsAgentHook.builder()
.skillRegistry(registry) // 必选:技能注册表
.autoReload(true) // 可选:启用自动重载
.build();
// 3. 创建 agent
return ReactAgent.builder()
.name("chat_agent") // 指定名称
.model(zhiPuAiChatModel) // 指定 ChatModel
.hooks(hook) // 指定 Skill Hook
.enableLogging(true)
.build();
}
}
商品文案写作输出结果:
@SpringBootTest
class ReactAgentTest {
@Autowired
private ReactAgent chatAgent;
@Test
void testCopywriting() throws Exception {
Optional<OverAllState> result = chatAgent.invoke("请为这款咖啡杯写一个营销文案:容量 350ml,陶瓷材质,简约设计,适合办公室使用");
printResult(result);
}
@Test
void testProductSelection() throws Exception {
Optional<OverAllState> result = chatAgent.invoke("现在市场上智能家居设备很火,年轻人喜欢便捷生活,请分析应该选什么品类");
printResult(result);
}
private void printResult(Optional<OverAllState> result) {
if (result.isPresent()) {
System.out.println(result.get());
}
}
}
testCopywriting 输出结果:
{
"OverAllState": {
"data": {
"_graph_execution_id_": "d877f9f0-f2bb-4d72-b148-b0a3e49055f3",
"input": "请为这款咖啡杯写一个营销文案:容量 350ml,陶瓷材质,简约设计,适合办公室使用",
"messages": [
{
"messageType": "USER",
"metadata": {
"messageType": "USER"
},
"media": [],
"text": "请为这款咖啡杯写一个营销文案:容量 350ml,陶瓷材质,简约设计,适合办公室使用"
},
{
"text": "\n我来为这款咖啡杯写一个营销文案。让我先查看文案写作技能的详细指导。\n",
"toolCalls": [
{
"id": "call_-7703135548885431832",
"name": "read_skill",
"type": "function",
"arguments": "{\"skill_name\":\"copywriting\"}"
}
],
"metadata": {
"finishReason": "TOOL_CALLS",
"id": "202604181702407bf1d5b8015a4ded",
"role": "ASSISTANT",
"messageType": [
"org.springframework.ai.chat.messages.MessageType",
"ASSISTANT"
]
}
},
{
"responses": [
{
"id": "call_-7703135548885431832",
"name": "read_skill",
"responseData": "\"# 商品文案写作\r\n\r\n你是一个商品文案写作专家。根据用户提供的商品信息,输出简短的营销文案。\r\n\r\n## 输出要求\r\n- 只输出10个字以内的文案\r\n- 格式:「文案:XXX」\""
}
],
"metadata": {
"messageType": "TOOL"
},
"messageType": "TOOL",
"text": ""
},
{
"text": "\n根据您提供的咖啡杯信息,我来为您创作营销文案:\n\n**文案:职场好伴侣**",
"toolCalls": [],
"metadata": {
"finishReason": "STOP",
"id": "20260418170241c52c524468f041ea",
"role": "ASSISTANT",
"messageType": [
"org.springframework.ai.chat.messages.MessageType",
"ASSISTANT"
]
}
}
]
}
}
}
2.5 PDF 提取器
scripts/ 是 AI Agent 技能(Skill)标准工程中的核心可执行代码目录,用于存放执行时需要调用的确定性、可复用脚本,是技能的工具库。
95% 场景只用 4 种语言:
PythonShell / BashJavaScript(Node.js)PowerShell(Windows专用)
提示:pdf-extractor 中就包含了 Python 脚本,使用起来比只有 SKILL.md 的技能肯定需要添加执行脚本的能力。
pdf-extractor 的 SKILL.md 内容:
---
名称:PDF提取器
描述:从PDF文档中提取文本、表格与表单数据,用于分析和处理。当用户要求提取、解析或分析PDF文件时使用。
---
# PDF提取器技能
你是一名专业的PDF提取专员。当用户要求从PDF文档中提取数据时,请遵循以下说明。
## 使用说明
1. **校验输入**
- 确认已提供PDF文件路径
- PDF文件默认路径为当前工作目录
- 使用 `shell` 或 `read_file` 工具检查文件是否存在
- 验证文件为有效PDF格式
2. **提取内容**
- 通过 `shell` 工具执行提取脚本:
```bash
python scripts/extract_pdf.py <pdf_file_path>
```
- 脚本将以JSON格式输出提取到的数据
3. **处理结果**
- 解析脚本输出的JSON数据
- 将数据整理为易读格式
- 处理各类编码问题(UTF-8、特殊字符等)
4. **呈现输出**
- 对提取内容进行概括说明
- 按用户要求的格式展示数据(JSON、Markdown、纯文本)
- 标注出现的问题或使用限制
## 脚本位置
提取脚本路径:
`scripts/extract_pdf.py`
## 输出格式
脚本返回JSON结构:
```json
{
"success": true,
"filename": "report.pdf",
"text": "完整文本内容……",
"page_count": 10,
"tables": [
{
"page": 1,
"data": [["表头1", "表头2"], ["数值1", "数值2"]]
}
],
"metadata": {
"title": "文档标题",
"author": "作者姓名",
"created": "2024-01-01"
}
}
pdf-extractor 可以通过 Shell 执行 Python 脚本,本地除了需要 Python 环境外,还需要添加 ShellToolAgentHook 自动注入 shell 命令执行工具,并在 Agent 执行前后自动管理 Shell 会话的初始化和清理:
// 3. 创建 ShellToolAgentHook (支持 shell 命令执行)
ShellToolAgentHook shellHook = ShellToolAgentHook.builder()
.build();
// 4. 创建 agent,同时添加两个 Hook
ReactAgent agent = ReactAgent.builder()
.name("chat_agent")
.model(zhiPuAiChatModel)
.hooks(skillsHook, shellHook) // 添加 Skills 和 Shell 两个 Hook
.enableLogging(true)
.build();
单元测试:
@Test
void testPdfExtractor() throws Exception {
Optional<OverAllState> result = chatAgent.invoke("从 D:/java/ai/skills/pdf-extractor/saa-roadmap.pdf 中提取内容");
printResult(result);
}
// 1. 绑定工具到指定技能(key = 技能name)
Map<String, List<ToolCallback>> groupedTools = Map.of(
"pdf-extractor",
List.of(pdfParseTool, fileReadTool)
);
// 2. 注入分组工具
SkillsAgentHook hook = SkillsAgentHook.builder()
.skillRegistry(registry)
.groupedTools(groupedTools)
.build();
3. 自定义 SkillRegistry 实现
只需实现 SkillRegistry 接口,即可扩展技能来源(DB、Nacos、Git 等):
get()/listAll():获取技能信息readSkillContent():读取SKILL.mdreload():重载技能(可选)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)