在当今AI应用开发领域,让AI智能体具备灵活的工具调用能力和可扩展的技能体系,是落地复杂业务场景的核心挑战。Spring AI Alibaba 原生提供了完善的 Skill 技能支持,能让智能体实现「技能发现→按需加载→工具执行」的全流程自动化。
本文将从核心概念、组件解析、实战场景、最佳实践四个维度,手把手教你掌握 Spring AI Alibaba Skill 的使用方法。
一、核心概念
1.1 渐进式披露(核心设计思想)
Spring AI Alibaba Skill 采用渐进式披露机制,最大化提升模型效率:
- 系统初始仅注入技能元数据(名称、描述、路径);
- 模型判断需要使用某技能时,调用
read_skill(skill_name)加载完整的SKILL.md文档; - 最后按需访问技能资源、执行绑定工具。
1.2 Skill 标准目录结构
每个技能独立为一个子目录,SKILL.md 为强制必需文件,目录结构如下:
skills/ # 技能根目录
└── pdf-extractor/ # 单个技能目录(自定义命名)
├── SKILL.md # ✅ 必需:技能核心定义文档
├── references/ # 可选:技能参考资料
├── examples/ # 可选:使用示例
└── scripts/ # 可选:执行脚本
1.3 SKILL.md 格式规范
SKILL.md 采用元数据+正文结构,元数据通过 --- 包裹,是模型识别技能的关键:
---
name: pdf-extractor # 必需:小写字母、数字、连字符,最长64字符
description: 用于从PDF文档中提取文本、表格和表单数据 # 必需:简洁描述,超长会被截断
---
# PDF 提取技能
## 功能说明
You are a PDF extraction specialist. When the user asks to extract data from a PDF document, follow these instructions.
## 使用方法
1. **Validate Input**
- Confirm the PDF file path is provided.
- The default path for the pdf file is the current working directory.
- Use the `shell` or `read_file` tool to check if the file exists
- Verify it's a valid PDF format
2. **Extract Content**
- Execute the extraction script using the `shell` tool:
```bash
python scripts/extract_pdf.py <pdf_file_path>
```
- The script will output JSON format with extracted data
3. **Process Results**
- Parse the JSON output from the script
- Structure the data in a readable format
- Handle any encoding issues (UTF-8, special characters)
4. **Present Output**
- Summarize what was extracted
- Present data in the requested format (JSON, Markdown, plain text)
- Highlight any issues or limitations
## Script Location
The extraction script is located at:
`scripts/extract_pdf.py`
## Output Format
The script returns JSON:
```json
{
"success": true,
"filename": "report.pdf",
"text": "Full text content...",
"page_count": 10,
"tables": [
{
"page": 1,
"data": [["Header1", "Header2"], ["Value1", "Value2"]]
}
],
"metadata": {
"title": "Document Title",
"author": "Author Name",
"created": "2024-01-01"
}
}
```
scripts/extract_pdf.py简介,因为目前测试脚本的执行,所以mock返回了一个json格式的解析内容。
二、核心组件解析
Spring AI Alibaba Skill 体系由四大核心组件构成,各司其职、协同工作:
2.1 对话模型(ChatModel)
对接阿里通义千问大模型,是智能体的「大脑」,负责推理决策:
private static ChatModel getChatModel() {
// 构建通义千问API客户端
DashScopeApi dashScopeApi = DashScopeApi.builder()
.apiKey(System.getenv("AliQwen_API")) // 环境变量配置API Key
.build();
// 创建对话模型
return DashScopeChatModel.builder()
.dashScopeApi(dashScopeApi)
.build();
}
2.2 技能注册中心(SkillRegistry)
负责加载、管理所有技能,Spring AI Alibaba 提供两种常用实现:
ClasspathSkillRegistry:从项目类路径(resources)加载技能FileSystemSkillRegistry:从本地文件系统加载技能
代码示例:
SkillRegistry registry = ClasspathSkillRegistry.builder()
.classpathPath("skills") // 指向resources/skills目录
.build();
2.3 技能钩子(SkillsAgentHook)
连接智能体与技能系统的桥梁,负责注入技能上下文、提供工具调用能力:
SkillsAgentHook hook = SkillsAgentHook.builder()
.skillRegistry(registry) // 绑定技能注册中心
.build();
2.4 ReAct 智能体(ReactAgent)
基于 ReAct(推理+执行) 模式的智能体,自主完成「思考→选技能→执行任务」的全流程:
ReactAgent agent = ReactAgent.builder()
.name("skills-agent") // 智能体名称
.model(chatModel) // 绑定大模型
.saver(new MemorySaver()) // 内存记忆(保存对话上下文)
.hooks(List.of(hook)) // 绑定技能钩子
.build();
三、实战场景
场景一:技能发现(智能体自我认知)
让AI智能体主动披露自身具备的所有技能,验证技能加载是否成功。
核心代码
private static void findSkills() throws GraphRunnerException {
// 1. 初始化核心组件
ChatModel chatModel = getChatModel();
SkillsAgentHook hook = getSkillsAgentHook();
// 2. 构建技能智能体
ReactAgent agent = ReactAgent.builder()
.name("skills-agent")
.model(chatModel)
.saver(new MemorySaver())
.hooks(List.of(hook))
.build();
// 3. 执行对话:查询技能
AssistantMessage resp = agent.call("请介绍你有哪些技能");
System.out.println(resp.getText());
}
执行结果
11:29:36.067 [main] INFO com.alibaba.cloud.ai.graph.skills.registry.classpath.ClasspathSkillRegistry -- Loaded 1 skills from classpath: skills
我目前拥有的技能包括:
- **pdf-extractor**: 用于从 PDF 文档中提取文本、表格和表单数据,适用于分析和处理 PDF 文件。当用户需要提取、解析或分析 PDF 文件时可使用此技能。
如需了解某项技能的详细说明(例如具体操作步骤、支持的文件类型、使用示例等),我可以为您读取其完整的技能文档(`SKILL.md`)。您也可以告诉我您的具体需求(例如:“请帮我从一份PDF中提取所有表格”),我会判断是否适用某项技能并执行相应操作。
是否需要我为您详细展开某一项技能?
场景二:技能使用(PDF 信息提取)
结合技能系统 + Python 执行工具 + Shell 工具,实现多工具协作,完成 PDF 文本/表格提取。
步骤1:自定义 Python 执行工具(GraalVM 支持)
依赖如下
<!-- GraalVM Polyglot for Python execution -->
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>polyglot</artifactId>
<version>24.2.1</version>
</dependency>
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>python-community</artifactId>
<version>24.2.1</version>
<type>pom</type>
</dependency>
用于执行 Python 脚本完成 PDF 解析,工具代码如下:
package com.jcq.springaialibabaagent.tools;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.PolyglotException;
import org.graalvm.polyglot.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.function.FunctionToolCallback;
import java.util.function.BiFunction;
/**
* GraalVM 沙箱环境执行 Python 代码的工具
* 安全沙箱:禁用文件IO、进程创建、本地访问
*/
public class PythonTool implements BiFunction<PythonTool.PythonRequest, ToolContext, String> {
public static final String DESCRIPTION = """
Executes Python code and returns the result.
- 代码必须为合法Python语法
- 沙箱执行,安全无风险
- 支持返回数字、字符串、数组、执行结果
""";
private static final Logger log = LoggerFactory.getLogger(PythonTool.class);
private final Engine engine;
public PythonTool() {
this.engine = Engine.newBuilder()
.option("engine.WarnInterpreterOnly", "false")
.build();
}
/** 构建Spring AI 标准工具回调 */
public static ToolCallback createPythonToolCallback(String description) {
return FunctionToolCallback.builder("python_tool", new PythonTool())
.description(description)
.inputType(PythonRequest.class)
.build();
}
@Override
public String apply(PythonRequest request, ToolContext toolContext) {
if (request.code == null || request.code.trim().isEmpty()) {
return "Error:Python代码不能为空";
}
// 沙箱环境执行Python
try (Context context = Context.newBuilder("python")
.engine(engine)
.allowAllAccess(false)
.allowIO(false)
.allowNativeAccess(false)
.allowCreateProcess(false)
.allowHostAccess(true)
.build()) {
log.debug("执行Python代码:{}", request.code);
Value result = context.eval("python", request.code);
// 结果类型转换
if (result.isNull()) return "执行完成,无返回值";
if (result.isString()) return result.asString();
if (result.isNumber() || result.isBoolean()) return result.toString();
if (result.hasArrayElements()) {
StringBuilder sb = new StringBuilder("[");
long size = result.getArraySize();
for (long i = 0; i < size; i++) {
if (i > 0) sb.append(", ");
sb.append(result.getArrayElement(i));
}
return sb.append("]").toString();
}
return result.toString();
}
catch (PolyglotException e) {
log.error("Python执行异常", e);
return "执行错误:" + e.getMessage();
}
}
/** 工具请求参数 */
public static class PythonRequest {
@JsonProperty(required = true)
@JsonPropertyDescription("需要执行的Python代码")
public String code;
public PythonRequest() {
}
public PythonRequest(String code) {
this.code = code; }
}
}
步骤2:构建多技能协作智能体
private static void useSkills() throws Exception {
// 1. 初始化大模型
ChatModel chatModel = getChatModel();
// 2. 绑定技能钩子 + Shell工具钩子
SkillsAgentHook skillsHook = getSkillsAgentHook();
ShellToolAgentHook shellHook = ShellToolAgentHook.builder()
.shellTool2(ShellTool2.builder(System.getProperty("user.dir")).build())
.build();
// 3. 构建智能体(绑定技能+工具+日志)
ReactAgent agent = ReactAgent.builder()
.name("skills-integration-agent")
.model(chatModel)
.saver(new MemorySaver())
.tools(PythonTool.createPythonToolCallback(PythonTool.DESCRIPTION)) // 自定义Python工具
.hooks(List.of(skillsHook, shellHook)) // 多钩子组合
.enableLogging(true) // 开启日志,便于调试
.build();
// 4. 执行PDF提取任务
String pdfPath = getTestSkillsDirectory() + "/pdf-extractor/skill-test.pdf";
AssistantMessage response = agent.call(String.format("请从 %s 文件中提取关键信息", pdfPath));
// 5. 输出结果
System.out.println("========== PDF提取结果 ==========");
System.out.println(response.getText());
}
执行结果
==========
The PDF extraction was successful! Here's the key information extracted from the `skill-test.pdf` file:
## Document Metadata
- **Title**: Sample PDF Document
- **Author**: Test Author
- **Created**: 2024-01-01
- **Modified**: 2024-01-15
- **Page Count**: 5 pages
## Extracted Text
The document contains: "This is extracted text from the PDF document. It contains multiple paragraphs and sections."
## Tables Found
### Table 1 (Page 1) - Product Inventory
| Product | Price | Quantity |
|---------|-------|----------|
| Widget A | $10.00 | 100 |
| Widget B | $15.00 | 50 |
### Table 2 (Page 3) - Financial Summary
| Month | Revenue | Expenses |
|-------|---------|----------|
| January | $50,000 | $30,000 |
| February | $55,000 | $32,000 |
四、最佳实践建议
技能规范化管理
- 所有技能统一放在
resources/skills目录,按业务拆分子目录; SKILL.md严格遵循格式规范,保证模型准确识别。
- 所有技能统一放在
多钩子灵活组合
- 基础能力:
SkillsAgentHook(技能系统); - 系统操作:
ShellToolAgentHook(Shell命令); - 自定义能力:自定义工具(Python/Java/第三方API)。
- 基础能力:
开发与调试优化
- 开发阶段开启
enableLogging(true),查看智能体推理全流程; - 测试使用
MemorySaver快速验证,生产环境替换为持久化存储。
- 开发阶段开启
模型选型策略
- 简单技能查询:基础版通义千问;
- 复杂工具协作/多步骤推理:高级版大模型。