首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >langchain4j 学习系列(10)-Skill使用示例

langchain4j 学习系列(10)-Skill使用示例

作者头像
菩提树下的杨过
发布2026-04-27 07:59:12
发布2026-04-27 07:59:12
40
举报

上节继续,今天来学习Skill的使用,要说明的是:目前langchain4j关于SKILL的API尚在试验阶段,未来可能会有较大变化,生产环境使用时,请大家谨慎。

image
image

先添加pom依赖:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.0.0</version>
        <relativePath/>
    </parent>

    <groupId>com.yjmyzz</groupId>
    <artifactId>langchain4j-study</artifactId>
    <version>1.0.0</version>
    <name>langchain4j-study</name>
    <description>langchain4j学习项目 - Skill示例 by 菩提树下的杨过</description>

    <properties>
        <maven.compiler.source>25</maven.compiler.source>
        <maven.compiler.target>25</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <langchain4j.version>1.13.1-beta23</langchain4j.version>
    </properties>

    <dependencies>

        <!-- Spring Boot Starters -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webflux</artifactId>
        </dependency>

        <!-- langchain4j Core -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
            <version>1.13.0</version>
        </dependency>

        <!-- langchain4j Ollama Integration -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-ollama</artifactId>
            <version>1.13.1</version>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-skills</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- Lombok for reducing boilerplate code -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project> 

以下是使用步骤:

一、编写SKILL.md说明

这里我们以订单处理为示例,写1个process-order的skill

代码语言:javascript
复制
---
name: process-order
description: 处理客户订单
---

处理订单的步骤:

1. 调用 validateOrder(orderId) 检查订单是否有效。
2. 调用 reserveInventory(orderId) 预留所需库存。
3. 仅当预留成功时,调用 chargePayment(orderId) 进行扣款。
4. 最后,调用 sendConfirmationEmail(orderId) 发送确认邮件。

如果任何步骤失败,在报告错误之前调用 rollbackOrder(orderId) 回滚订单。

skill有多种存储方式,本例直接存放于文件src/main/resources/skills/process-order/SKILL.md

image
image

二、定义Tools

process-order的skill中,会用到一系列Tool,这里给出mock实现

代码语言:javascript
复制
package com.cnblogs.yjmyzz.langchain4j.study.tools;

import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Component;

/**
 * 一组用于处理客户订单的工具。
 * 当 'process-order' SKILL激活时,LLM 将调用这些方法。
 */
@Component
public class OrderTools {

    @Tool("验证订单ID是否有效")
    public String validateOrder(String orderId) {
        System.out.println("工具:正在验证订单:" + orderId);
        // 模拟验证逻辑
        if (orderId != null && orderId.startsWith("ORD")) {
            System.out.println("订单 " + orderId + " 有效。");
            return "订单 " + orderId + " 有效。";
        } else {
            System.out.println("订单 " + orderId + " 无效。");
            return "订单 " + orderId + " 无效。";
        }
    }

    @Tool("为指定订单ID预留库存。返回成功或失败信息。")
    public String reserveInventory(String orderId) {
        System.out.println("工具:正在为订单预留库存:" + orderId);
        // 模拟库存预留
        if ("ORD001".equals(orderId)) { // 模拟成功示例
            System.out.println("订单 " + orderId + " 的库存已预留。");
            return "订单 " + orderId + " 的库存已预留。";
        } else if ("ORD002".equals(orderId)) { // 模拟失败示例
            System.out.println("为订单 " + orderId + " 预留库存失败。库存不足。");
            return "为订单 " + orderId + " 预留库存失败。库存不足。";
        } else {
            System.out.println("订单 " + orderId + " 的库存预留状态未知。");
            return "订单 " + orderId + " 的库存预留状态未知。";
        }
    }

    @Tool("为指定订单ID扣款。返回支付状态。")
    public String chargePayment(String orderId) {
        System.out.println("工具:正在为订单扣款:" + orderId);
        // 模拟支付处理
        return "订单 " + orderId + " 扣款成功。";
    }

    @Tool("向客户发送指定订单ID的确认邮件。返回确认状态。")
    public String sendConfirmationEmail(String orderId) {
        System.out.println("工具:正在为订单发送确认邮件:" + orderId);
        // 模拟邮件发送
        return "订单 " + orderId + " 的确认邮件已发送。";
    }

    @Tool("因处理出错回滚订单。返回回滚状态。")
    public String rollbackOrder(String orderId) {
        System.out.println("工具:因失败正在回滚订单:" + orderId);
        // 模拟回滚
        return "订单 " + orderId + " 已成功回滚。";
    }
}

三、定义AIService

代码语言:javascript
复制
package com.cnblogs.yjmyzz.langchain4j.study.service;

import dev.langchain4j.service.UserMessage;

public interface OrderProcessingAiService {

    // 系统消息由 Spring 配置中的 AiServices.builder(...).systemMessage(...) 提供
    String chat(@UserMessage String userMessage);
}

四、添加配置(注入skill)

代码语言:javascript
复制
package com.cnblogs.yjmyzz.langchain4j.study.config;

import com.cnblogs.yjmyzz.langchain4j.study.service.OrderProcessingAiService;
import com.cnblogs.yjmyzz.langchain4j.study.tools.OrderTools;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.tool.ToolProvider;
import dev.langchain4j.skills.ClassPathSkillLoader;
import dev.langchain4j.skills.FileSystemSkill;
import dev.langchain4j.skills.Skill;
import dev.langchain4j.skills.Skills;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.stream.Collectors;

@Configuration
public class LangChain4jConfig {

    private final OrderTools orderTools; // 自动注入 OrderTools

    // 注入 OrderTools,用于技能作用域的工具
    public LangChain4jConfig(OrderTools orderTools) {
        this.orderTools = orderTools;
    }

    @Bean
    public Skills skills() {
        // 从类路径下的 'skills' 目录加载所有技能
        // 假设你的 SKILL.md 文件位于 src/main/resources/skills/ 下
        List<FileSystemSkill> loadedSkills = ClassPathSkillLoader.loadSkills("skills");

        // 为 "process-order" 技能附加 OrderTools 作为技能作用域的工具
        // 这意味着 OrderTools 中的方法只有在显式激活 "process-order" 技能后,
        // 才会对 LLM 可见
        List<Skill> configuredSkills = loadedSkills.stream()
                .map(fsSkill -> {
                    if ("process-order".equals(fsSkill.name())) {
                        return Skill.builder()
                                .name(fsSkill.name())
                                .description(fsSkill.description())
                                .content(fsSkill.content())
                                .resources(fsSkill.resources())
                                .tools(orderTools) // 附加 OrderTools 作为技能作用域的工具
                                .build();
                    }
                    return fsSkill;
                })
                .collect(Collectors.toList());

        return Skills.from(configuredSkills);
    }

    @Bean
    public ToolProvider skillsToolProvider(Skills skills) {
        // 该 ToolProvider 将处理 'activate_skill'、'read_skill_resource'
        // 并在技能激活时动态暴露技能作用域的工具(例如 OrderTools 中的工具)
        return skills.toolProvider();
    }

    @Bean
    public OrderProcessingAiService orderProcessingAiService(ChatModel chatModel, Skills skills, ToolProvider skillsToolProvider) {
        // 构建 AI 服务,整合聊天模型、聊天记忆以及技能 ToolProvider
        return AiServices.builder(OrderProcessingAiService.class)
                .chatModel(chatModel)
                .chatMemory(MessageWindowChatMemory.withMaxMessages(100)) // 保留对话历史
                .toolProvider(skillsToolProvider) // 注册技能工具提供者
                // 将技能目录注入到系统消息中,以便 LLM 知道它可以激活哪些技能
                .systemMessage("你是一个订单处理助手。你可以使用以下技能:\n"
                        + skills.formatAvailableSkills() // 将技能格式化为 XML 提供给 LLM
                        + "\n当用户请求与这些技能之一相关时,请先使用 `activate_skill` 工具激活该技能,然后再继续处理。")
                .build();
    }
}

五、使用Skill

代码语言:javascript
复制
package com.cnblogs.yjmyzz.langchain4j.study.controller;

import com.cnblogs.yjmyzz.langchain4j.study.service.OrderProcessingAiService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 与使用技能的 LangChain4j AI 服务进行交互的 REST 控制器。
 */
@RestController
public class OrderController {

    private final OrderProcessingAiService orderProcessingAiService;

    // 自动注入 AI 服务
    public OrderController(OrderProcessingAiService orderProcessingAiService) {
        this.orderProcessingAiService = orderProcessingAiService;
    }

    /**
     * 与订单处理 AI 助手进行聊天的端点。
     * 示例:http://localhost:8080/chat/order?message=处理订单 ORD001
     * 示例:http://localhost:8080/chat/order?message=你叫什么名字?
     */
    @GetMapping("/chat/order")
    public String chatWithOrderAssistant(@RequestParam(value = "message", defaultValue = "处理订单 ORD001") String message) {
        System.out.println("用户消息:" + message);
        String aiResponse = orderProcessingAiService.chat(message);
        System.out.println("AI 回复:" + aiResponse);
        return aiResponse;
    }
}

六、测试运行

http://localhost:8080/chat/order?message=处理订单 ORD001

代码语言:javascript
复制
用户消息:处理订单 ORD001
工具:正在验证订单:ORD001
订单 ORD001 有效。
工具:正在为订单预留库存:ORD001
订单 ORD001 的库存已预留。
工具:正在为订单扣款:ORD001
工具:正在为订单发送确认邮件:ORD001
AI 回复:✅ 订单 ORD001 处理完成!

处理结果:
- ✅ 订单验证:有效
- ✅ 库存预留:成功
- ✅ 支付扣款:成功
- ✅ 确认邮件:已发送

订单 ORD001 已成功处理完毕,客户将收到确认邮件。

http://localhost:8080/chat/order?message=处理订单 ORD002

代码语言:javascript
复制
用户消息:处理订单 ORD002
工具:正在验证订单:ORD002
订单 ORD002 有效。
工具:正在为订单预留库存:ORD002
为订单 ORD002 预留库存失败。库存不足。
工具:因失败正在回滚订单:ORD002
AI 回复:❌ 订单 ORD002 处理失败!

处理结果:
- ✅ 订单验证:有效
- ❌ 库存预留:失败(库存不足)
- ➖ 支付扣款:未执行(因库存预留失败)
- ➖ 确认邮件:未发送

订单已成功回滚。请通知客户库存不足的情况,建议客户联系客服或选择其他商品。

完整代码:GitHub - yjmyzz/langchain4j-study at day10 · GitHub

参考文档:

https://docs.langchain4j.dev/tutorials/skills

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档