LangChain4j实战二:集成到Springboot

1. 准备工作

1.1. 构建项目,添加pom文件
xml 复制代码
<?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 https://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>3.5.0</version>
        <relativePath/>
    </parent>

    <groupId>cn.cjc</groupId>
    <artifactId>springboot-ai</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


        <!-- https://mvnrepository.com/artifact/dev.langchain4j/langchain4j -->
        <!--  LangChain4j 核心库 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
            <version>1.9.1</version>
        </dependency>
        <!-- AiService依赖 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-spring-boot-starter</artifactId>
            <version>1.0.1-beta6</version>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-core</artifactId>
            <version>1.9.1</version>
        </dependency>
        <!-- LangChain4j OpenAI支持(可用于通义千问的OpenAI兼容接口) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
            <version>1.9.1-beta17</version>
        </dependency>
        <!--  导入响应式编程依赖包-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
            <version>1.9.1-beta17</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
    </dependencies>
</project>
1.2. 配置文件
yaml 复制代码
spring:
  application:
    name: springboot-ai
  main:
    allow-bean-definition-overriding: true
    
langchain4j:
  open-ai:
    chat-model:
      api-key: ******
      model-name: qwen-plus
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
1.3. 提示词请求类
java 复制代码
@Data
public class PromptRequest {
    private String prompt;
    private int userId;
}

2. 高级LLM API的功能定义

  • 以下三种能力都集中在名为Assistant的接口中,这些能力由一些注解来辅助实现

  • 高级LLM API的好处就是只要做好接口定义,具体实现交给LangChain4j来负责,也就是AiServices.create

java 复制代码
public interface Assistant {
    
    /**
     * 最简单的对话,只返回助手的回答,不包含任何额外信息
     * @param userMessage 用户消息
     * @return 助手生成的回答
     */
    String simpleChat(String userMessage);

    /**
     * 使用模板进行对话,返回助手的回答
     * @param name 模板中的变量
     * @return 助手生成的回答
     */
    @UserMessage("简单介绍一下{{name}}")
    String templateChat(@V("name") String name);

    /**
     * 设置系统消息,就是设定大模型的身份角色,返回助手的回答
     * @param name 模板中的变量
     * @return 助手生成的回答
     */
    @SystemMessage("你的回答不会超过一百汉字")
    @UserMessage("简单介绍一下{{name}}")
    String templateChatWithSysMsg(@V("name") String name);
}

3. 配置类

  • 应用会通过LangChain4jConfig类创建两个实例:openAiChatModel负责低级LLM API,assistant负责高级LLM API
java 复制代码
@Configuration
public class LangChain4jConfig {

    @Value("${langchain4j.open-ai.chat-model.api-key}")
    private String apiKey;

    @Value("${langchain4j.open-ai.chat-model.model-name:qwen-turbo}")
    private String modelName;

    @Value("${langchain4j.open-ai.chat-model.base-url}")
    private String baseUrl;

    /**
     * 创建并配置OpenAiChatModel实例(使用通义千问的OpenAI兼容接口)
     */
    @Bean
    public OpenAiChatModel openAiChatModel() {
        return OpenAiChatModel.builder()
                .apiKey(apiKey)
                .modelName(modelName)
                .baseUrl(baseUrl)
                .build();
    }

    @Bean
    public Assistant assistant(@Qualifier("openAiChatModel") OpenAiChatModel chatModel) {
        return AiServices.create(Assistant.class, chatModel);
    }
}

4. 服务类

java 复制代码
package cn.cjc.ai.service.impl;

import cn.cjc.ai.service.HighAssistant;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.openai.OpenAiChatModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;


/**
 * 通义千问服务类,用于与通义千问模型进行交互
 */
@Service
@Slf4j
public class QwenService {

    @Autowired
    private OpenAiChatModel openAiChatModel;
    
    @Autowired
    private Assistant assistant;

    /**
     * 获取AI模型的响应(用于接口调用)
     * @param prompt 用户提示词
     * @return AI生成的回答
     */
    public String getResponse(String prompt) {
        return openAiChatModel.chat(prompt);
    }

    /**
     * 调用AiService进行最简单的对话
     * @param prompt 用户提示词
     * @return 助手生成的回答
     */
    public String simpleChat(String prompt) {
        return assistant.simpleChat(prompt) + "[from simpleChat]";
    }

    /**
     * 调用AiService进行模板对话
     * @param name 模板中的变量
     * @return 助手生成的回答
     */
    public String templateChat(String name) {
        return assistant.templateChat(name) + "[from templateChat]";
    }

    /**
     * 调用AiService进行模板对话,包含系统消息
     * @param name 模板中的变量
     * @return 助手生成的回答
     */
    public String templateChatWithSysMsg(String name) {
        return assistant.templateChatWithSysMsg(name) + "[from templateChatWithSysMsg]";
    }

    /**
     * 模拟多轮对话
     * @param prompt 模板中的变量
     * @return 助手生成的回答
     */
    public String simulateMultiRoundChat(String prompt) {
        List<ChatMessage> history = List.of(
                SystemMessage.from("你是历史学者,回答问题是简洁风格"),
                UserMessage.from("介绍曹操是谁"),
                AiMessage.from("曹操(155-220年),东汉末年杰出政治家、军事家、文学家,魏国奠基者。他统一北方,推行屯田,唯才是举,善用兵法,亦为建安文学代表人物,著有《观沧海》等诗作。"),
                UserMessage.from(prompt));

        AiMessage reply = openAiChatModel.chat(history).aiMessage();

        return reply.text() + "[from simulateMultiRoundChat]";
    }

    public String useChatRequest(String prompt) {
        List<ChatMessage> messages = List.of(
                SystemMessage.from("你是Java程序员,回答问题是简洁风格"),
                UserMessage.from(prompt));

        ChatRequest request = ChatRequest.builder()
                .messages(messages)
                .temperature(0.7)
                .maxOutputTokens(100)
                .build();

        return openAiChatModel.chat(request).aiMessage().text() + "[from useChatRequest]";
    }
}

5. controller

java 复制代码
@RestController
@RequestMapping("/api/qwen")
public class QwenController {

    @Autowired
    private QwenService qwenService;

    /**
     * 1.仅支持一轮对话
     */
    @PostMapping("/chat")
    public ResponseEntity<String> chat(@RequestBody PromptRequest request) {
        // 检查请求体是否有效
        if (request == null || request.getPrompt() == null || request.getPrompt().trim().isEmpty()) {
            return ResponseEntity.badRequest().body("提示词不能为空");
        }
        try {
            // 调用QwenService获取模型响应
            String response = qwenService.getResponse(request.getPrompt());
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            // 捕获异常并返回错误信息
            return ResponseEntity.status(500).body("请求处理失败: " + e.getMessage());
        }
    }

   /**
     * 2.使用了AiService,不用显式调用大模型服务,仅支持一轮对话
     */
    @PostMapping("/simpleChat")
    public ResponseEntity<String> simpleChat(@RequestBody PromptRequest request) {
        String response = qwenService.simpleChat(request.getPrompt());
        return ResponseEntity.ok(response);
    }

   /**
     * 3.使用了AiService,使用模板
     */
    @PostMapping("/templateChat")
    public ResponseEntity<String> templateChat(@RequestBody PromptRequest request) {
        String response = qwenService.templateChat(request.getPrompt());
        return ResponseEntity.ok(response);
    }

   /**
     * 4.使用了AiService,设置系统消息,用注解SystemMessage来实现,相比3回答更简洁
     */
    @PostMapping("/templateChatWithSysMsg")
    public ResponseEntity<String> templateChatWithSysMsg(@RequestBody PromptRequest request) {
        String response = qwenService.templateChatWithSysMsg(request.getPrompt());
        return ResponseEntity.ok(response);
    }

   /**
     * 5.手动实现多轮对话
	 * "prompt": "他有哪些主要对手?"
     */
    @PostMapping("/simulatemultiroundchat")
    public ResponseEntity<String> simulateMultiRoundChat(@RequestBody PromptRequest request) {
        String response = qwenService.simulateMultiRoundChat(request.getPrompt());
        return ResponseEntity.ok(response);
    }

   /**
     * 6.用ChatRequest作为入参,与ChatMesage相比,可以在ChatRequest中加入各种设置
     */
    @PostMapping("/usechatrequest")
    public ResponseEntity<String> useChatRequest(@RequestBody PromptRequest request) {
        String response = qwenService.useChatRequest(request.getPrompt());
        return ResponseEntity.ok(response);
    }
}
相关推荐
fengtangjiang1 小时前
nacos服务之间相互调用
android·java·开发语言
每天都要加加油王得坤1 小时前
langchain学习笔记
笔记·学习·langchain
石牌桥网管1 小时前
正则表达式:匹配不包含指定字符串的文本
java·javascript·python·正则表达式·go·php
独隅1 小时前
macOS 查看与安装 Java JDK 全面指南(2026年版)
java·开发语言·macos
西门吹雪分身1 小时前
SpringCloudGateway过滤器之RequestRateLimiterGatewayFilterFactory
java·redis·spring cloud
敲代码的哈吉蜂2 小时前
Tomcat的功能介绍
java·tomcat
独自破碎E2 小时前
BISHI75 阶幂
android·java·开发语言
红中️2 小时前
Tomcat
java·tomcat
Charlie_lll2 小时前
力扣解题-无重复字符的最长子串
后端·算法·leetcode