Agent Skills | Spring Ai Alibaba从零构建可扩展 AI 智能体
一、核心概念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 its 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 groupIdorg.graalvm.polyglot/groupId artifactIdpolyglot/artifactId version24.2.1/version /dependency dependency groupIdorg.graalvm.polyglot/groupId artifactIdpython-community/artifactId version24.2.1/version typepom/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 BiFunctionPythonTool.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 ErrorPython代码不能为空; } // 沙箱环境执行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! Heres 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技能系统系统操作ShellToolAgentHookShell命令自定义能力自定义工具Python/Java/第三方API。开发与调试优化开发阶段开启enableLogging(true)查看智能体推理全流程测试使用MemorySaver快速验证生产环境替换为持久化存储。