欢迎光临
我们一直在努力

Agent Skills | Spring Ai Alibaba从零构建可扩展 AI 智能体

在当今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、进程创建、本地访问
     */
    publicclass PythonTool implements BiFunction<PythonTool.PythonRequest, ToolContext, String> {

    publicstaticfinal String DESCRIPTION = """
       Executes Python code and returns the result.
       – 代码必须为合法Python语法
       – 沙箱执行,安全无风险
       – 支持返回数字、字符串、数组、执行结果
       """;
    privatestaticfinal Logger log = LoggerFactory.getLogger(PythonTool.class);
    privatefinal 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();
      }
     }

    /** 工具请求参数 */
    publicstaticclass 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());
    }

    执行结果

    ========== PDF提取结果 ==========
    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快速验证,生产环境替换为持久化存储。

  • 模型选型策略

    • 简单技能查询:基础版通义千问;

    • 复杂工具协作/多步骤推理:高级版大模型。

  • 最后

    从0到1!大模型(LLM)最全学习路线图,建议收藏!

    想入门大模型(LLM)却不知道从哪开始? 我根据最新的技术栈和我自己的经历&理解,帮大家整理了一份LLM学习路线图,涵盖从理论基础到落地应用的全流程!拒绝焦虑,按图索骥~~

    因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

    因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

    因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

    因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

    因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

    因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

    因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

    赞(0)
    未经允许不得转载:171主机测评 » Agent Skills | Spring Ai Alibaba从零构建可扩展 AI 智能体
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址