LangChain4j实战之四:集成到spring-boot

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

LangChain4j实战全系列链接

  1. 准备工作
  2. 极速开发体验
  3. 细说聊天API
  4. 集成到spring-boot

本篇概览

  • 《前文》[https://xinchen.blog.csdn.net/article/details/155223658\]对API做了梳理,如下图,今天通过编码实战来熟悉这些API
  • 由于spring-boot是工程中的常用框架,因此本次实战把spring-boot与LangChain4j集成在一起,增加项目的扩展性和实用性
  • 上图中涉及的API,有一部分不会进入实战,它们是:
  1. LanguageMode:官方都不推荐使用了,那么我们也没必要体验了
  2. ToolExecutionResultMessage:和Tool有关的略为复杂,后面会有单独的一篇来实践,所以本次跳过
  3. CustomMessage:只有ollama支持,所以本次跳过
  4. ImageContent:涉及到文件处理和模型选择,会有单独一篇来讲解
  5. AudioContent、VideoContent、PdfContent:这些都和ImageContent类似,因此就略过了
  • 现在开始编码吧

源码下载(觉得作者啰嗦的,直接在这里下载)

名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本篇的源码在langchain4j-tutorials文件夹下,如下图红色箭头所示:

开发:创建子工程

  • 《准备工作》(https://xinchen.blog.csdn.net/article/details/155104992)一文中创建好了整个实战系列的父工程langchain4j-totorials,所以今天的实战就在此父工程下创建子工程即可,名为demo-with-spring-boot
  • 父工程下新增文件夹demo-with-spring-boot,里面增加pom.xml文件,内容如下,可见主要是spring-boot和langchain4j部分的依赖:
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.bolingcavalry</groupId>
        <artifactId>langchain4j-totorials</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>demo-with-spring-boot</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- JUnit Jupiter Engine -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- Mockito Core -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- Mockito JUnit Jupiter -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- LangChain4j Core -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-core</artifactId>
        </dependency>
        
        <!-- LangChain4j OpenAI支持(用于通义千问的OpenAI兼容接口) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>

        <!-- 官方 langchain4j(包含 AiServices 等服务类) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        
        <!-- 日志依赖由Spring Boot Starter自动管理,无需单独声明 -->
    </dependencies>

    <build>
        <plugins>
            <!-- Spring Boot Maven Plugin -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.3.5</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

开发:配置文件

  • 新建目录langchain4j-totorials/demo-with-spring-boot/src/main/resources,在里面新增文件application.properties,内容如下,重点是和模型有关的参数,请把your-api-key改成你自己的大模型API Key
properties 复制代码
# Spring Boot 应用配置
server.port=8080
server.servlet.context-path=/

# LangChain4j 使用OpenAI兼容模式配置通义千问模型
# 注意:请将your-api-key替换为您实际的通义千问API密钥
langchain4j.open-ai.chat-model.api-key=your-api-key
# 通义千问模型名称
langchain4j.open-ai.chat-model.model-name=qwen3-max
# 阿里云百炼OpenAI兼容接口地址
langchain4j.open-ai.chat-model.base-url=https://dashscope.aliyuncs.com/compatible-mode/v1

# 日志配置
logging.level.root=INFO
logging.level.com.bolingcavalry=DEBUG
logging.pattern.console=%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
# 应用名称
spring.application.name=demo-with-spring-boot

编码:启动类

  • 首先有springboot的application类,平平无奇
java 复制代码
package com.bolingcavalry;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Spring Boot应用程序的主类
 */
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

编码:高级LLM API的功能定义

  • 本篇要体验高级LLM API,如下图红框所示
  • 需要通过接口来定义这个高级LLM API能做什么,这里打算提供三种能力:
  1. 最简单的对话,传入字符串返回字符串,方法名为simpleChat
  2. 使用模板,就是定义好模板,然后用外部变量来替代模板中的占位符,方法名为temlateChat
  3. 设置系统消息,就是设定大模型的身份角色等,方法名为temlateChatWithSysMsg
  • 上述三种能力都集中在名为Assistant的接口中,如下所示,可见这些能力由一些注解来辅助实现
java 复制代码
package com.bolingcavalry.service;

import dev.langchain4j.service.*;

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

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

    @SystemMessage("你的回答不会超过一百汉字")
    @UserMessage("简单介绍一下{{name}}")
    String temlateChatWithSysMsg(@V("name") String name);
}
  • 高级LLM API的好处就是我们只要做好上述定义,具体实现交给LangChain4j来负责,也就是截图中的AiServices.create

编码:配置类

  • 接下来是配置类,这样就可以通过配置文件来创建模型服务类的实例了
java 复制代码
package com.bolingcavalry.config;

import dev.langchain4j.model.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import dev.langchain4j.service.AiServices;
import com.bolingcavalry.service.Assistant;

/**
 * LangChain4j配置类
 */
@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兼容接口)
     * @return OpenAiChatModel实例
     */
    @Bean
    public OpenAiChatModel openAiChatModel() {
        return OpenAiChatModel.builder()
                .apiKey(apiKey)
                .modelName(modelName)
                .baseUrl(baseUrl)
                .build();
    }

    @Bean
    public Assistant assistant(OpenAiChatModel chatModel) {
        return AiServices.create(Assistant.class, chatModel);
    }
}
  • 上述代码中的assistant方法值得注意,这里创建了高级LLM API实例bean,就是下图红框中那个,可以看到只要把Assistant.class作为入参,LangChain4j就能创建具有对应能力的bean
  • 也就是说应用会通过LangChain4jConfig类创建两个实例:openAiChatModel负责低级LLM API,assistant负责高级LLM API

编码:服务类

  • 前面如果依赖注入创建了openAiChatModel和assistant,接下来就创建服务类QwenService,作用是使用openAiChatModel和assistant完成业务功能
  • 完整的代码如下,稍后会详细说明里面的重点
java 复制代码
package com.bolingcavalry.service;

import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.openai.OpenAiChatModel;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import dev.langchain4j.data.message.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

    private static final Logger logger = LoggerFactory.getLogger(QwenService.class);

    // 注入OpenAiChatModel,用于与通义千问进行交互
    private final OpenAiChatModel openAiChatModel;

    /**
     * 构造函数,通过依赖注入获取OpenAiChatModel实例
     * 
     * @param openAiChatModel OpenAiChatModel实例
     */
    @Autowired
    public QwenService(OpenAiChatModel openAiChatModel) {
        this.openAiChatModel = openAiChatModel;
    }

    /**
     * 调用通义千问模型进行对话
     * 
     * @param message 用户消息
     * @return AI回复
     */
    public String chat(String message) {
        return openAiChatModel.chat(message);
    }

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

    @Autowired
    private Assistant assistant;

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

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

    /**
     * 调用AiService进行模板对话,包含系统消息
     * 
     * @param name 模板中的变量
     * @return 助手生成的回答
     */
    public String aiServiceTemplateChatWithSysMsg(String name) {
        return assistant.temlateChatWithSysMsg(name) + "[from aiservice 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]";
    }
}
  • 上述代码有下面七处要注意的重点:
  1. openAiChatModel和assistant都被依赖注入进来,可以直接使用
  2. getResponse方法,其实就是最简单的一问一答
  3. aiServiceSimpleChat方法,演示了AiService的基本用法,assistant是LangChain4j根据我们定义的Assistant接口创建的实例,内部实现会调用openAiChatModel
  4. aiServiceTemplateChat方法,演示了AiService的模板用法,会拿着入参去填充模板中的占位符,以此作为传入大模型的提示词
  5. aiServiceTemplateChatWithSysMsg方法,演示了AiService的系统提示词能力,该能力通过SystemMessage注解就实现了
  6. simulateMultiRoundChat方法,这里演示了如何手动实现多轮对话,举个例子,你问AI:他的主要对手有哪些?,这时候AI一定不知道你说的那个他是谁,但如果之前你和AI聊过曹操的话题,并且把之前的聊天记录在本次对话时都带上,那么AI就知道你说的那个他是曹操,所以simulateMultiRoundChat方法就模拟了第二次对话时带上第一次对话信息的场景
  7. useChatRequest方法,演示了如何使用ChatRequest作为入参
  • 以上就是服务类的全部代码,可以看到其实非常简单,只需调用模型对象或者AiService对象的方法,看来LangChain4j确实在帮我们简化LLM应用开发
  • 好了,现在服务类已备好,接下来再开发一个controller类接收http请求,这样就能通过http接口调用来使用服务类提供的能力了

编码:controller类

  • controller类也很简单:定义好path,然后在响应方法中调用前面服务类的方法即可
java 复制代码
/*
 * @Author: 程序员欣宸 zq2599@gmail.com
 * @Date: 2025-11-28 09:41:52
 * @LastEditors: 程序员欣宸 zq2599@gmail.com
 * @LastEditTime: 2025-11-28 11:37:52
 * @FilePath: /langchain4j-totorials/demo-with-spring-boot/src/main/java/com/bolingcavalry/controller/QwenController.java
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
package com.bolingcavalry.controller;

import com.bolingcavalry.service.QwenService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 通义千问控制器,处理与大模型交互的HTTP请求
 */
@RestController
@RequestMapping("/api/qwen")
public class QwenController {

    private final QwenService qwenService;

    /**
     * 构造函数,通过依赖注入获取QwenService实例
     * 
     * @param qwenService QwenService实例
     */
    @Autowired
    public QwenController(QwenService qwenService) {
        this.qwenService = qwenService;
    }

    /**
     * 提示词请求实体类
     */
    @Data
    static class PromptRequest {
        private String prompt;
    }

    /**
     * 响应实体类
     */
    @Data
    static class Response {
        private String result;

        public Response(String result) {
            this.result = result;
        }
    }

    /**
     * 检查请求体是否有效
     * 
     * @param request 包含提示词的请求体
     * @return 如果有效则返回null,否则返回包含错误信息的ResponseEntity
     */
    private ResponseEntity<Response> check(PromptRequest request) {
        if (request == null || request.getPrompt() == null || request.getPrompt().trim().isEmpty()) {
            return ResponseEntity.badRequest().body(new Response("提示词不能为空"));
        }
        return null;
    }

    /**
     * 处理POST请求,接收提示词并返回模型响应
     * 
     * @param request 包含提示词的请求体
     * @return 包含模型响应的ResponseEntity
     */
    @PostMapping("/chat")
    public ResponseEntity<Response> chat(@RequestBody PromptRequest request) {
        // 检查请求体是否有效
        ResponseEntity<Response> checkRlt = check(request);
        if (checkRlt != null) {
            return checkRlt;
        }

        try {
            // 调用QwenService获取模型响应
            String response = qwenService.getResponse(request.getPrompt());
            return ResponseEntity.ok(new Response(response));
        } catch (Exception e) {
            // 捕获异常并返回错误信息
            return ResponseEntity.status(500).body(new Response("请求处理失败: " + e.getMessage()));
        }
    }

    @PostMapping("/aiservicesimplechat")
    public ResponseEntity<Response> aiServiceSimpleChat(@RequestBody PromptRequest request) {
        ResponseEntity<Response> checkRlt = check(request);
        if (checkRlt != null) {
            return checkRlt;
        }

        try {
            // 调用QwenService获取模型响应
            String response = qwenService.aiServiceSimpleChat(request.getPrompt());
            return ResponseEntity.ok(new Response(response));
        } catch (Exception e) {
            // 捕获异常并返回错误信息
            return ResponseEntity.status(500).body(new Response("请求处理失败: " + e.getMessage()));
        }
    }

    @PostMapping("/aiservicetemplatechat")
    public ResponseEntity<Response> aiServiceTemplateChat(@RequestBody PromptRequest request) {
        ResponseEntity<Response> checkRlt = check(request);
        if (checkRlt != null) {
            return checkRlt;
        }

        try {
            // 调用QwenService获取模型响应
            String response = qwenService.aiServiceTemplateChat(request.getPrompt());
            return ResponseEntity.ok(new Response(response));
        } catch (Exception e) {
            // 捕获异常并返回错误信息
            return ResponseEntity.status(500).body(new Response("请求处理失败: " + e.getMessage()));
        }
    }

    @PostMapping("/aiservicetemplatechatwithsysmsg")
    public ResponseEntity<Response> aiServiceTemplateChatWithSysMsg(@RequestBody PromptRequest request) {
        ResponseEntity<Response> checkRlt = check(request);
        if (checkRlt != null) {
            return checkRlt;
        }

        try {
            // 调用QwenService获取模型响应
            String response = qwenService.aiServiceTemplateChatWithSysMsg(request.getPrompt());
            return ResponseEntity.ok(new Response(response));
        } catch (Exception e) {
            // 捕获异常并返回错误信息
            return ResponseEntity.status(500).body(new Response("请求处理失败: " + e.getMessage()));
        }
    }

    @PostMapping("/simulatemultiroundchat")
    public ResponseEntity<Response> simulateMultiRoundChat(@RequestBody PromptRequest request) {
        ResponseEntity<Response> checkRlt = check(request);
        if (checkRlt != null) {
            return checkRlt;
        }

        try {
            // 调用QwenService获取模型响应
            String response = qwenService.simulateMultiRoundChat(request.getPrompt());
            return ResponseEntity.ok(new Response(response));
        } catch (Exception e) {
            // 捕获异常并返回错误信息
            return ResponseEntity.status(500).body(new Response("请求处理失败: " + e.getMessage()));
        }
    }

    @PostMapping("/usechatrequest")
    public ResponseEntity<Response> useChatRequest(@RequestBody PromptRequest request) {
        ResponseEntity<Response> checkRlt = check(request);
        if (checkRlt != null) {
            return checkRlt;
        }

        try {
            // 调用QwenService获取模型响应
            String response = qwenService.useChatRequest(request.getPrompt());
            return ResponseEntity.ok(new Response(response));
        } catch (Exception e) {
            // 捕获异常并返回错误信息
            return ResponseEntity.status(500).body(new Response("请求处理失败: " + e.getMessage()));
        }
    }
}
  • 至此,代码已写完,我们运行起来

体验:启动服务

  • 这是个spring-boot应用,因此我用了下面的mvn命令来启动
bash 复制代码
# 进入本篇创建的demo-with-spring-boot子工程内
cd langchain4j-totorials/demo-with-spring-boot
# 这是启动spring-boot应用的命令
mvn spring-boot:run
  • 启动成功的输出效果如下

体验:准备http工具

  • 接下来要做的就是发http请求了,由于个人喜好的关系,大家的http工具各不相同,我这里使用的是vscode的REST Client插件,主要是为了好管理历史请求数据
  • 装好REST Client插件后,再创建个XXX.http的脚本文件,就能在vscode上发送请求了,我的test-api.http内容如下
bash 复制代码
# 测试 Qwen API 接口

### GET 请求测试
GET http://localhost:8080/api/qwen
Accept: application/json

### POST 请求测试 (如果接口支持POST)
POST http://localhost:8080/api/qwen/chat
Content-Type: application/json
Accept: application/json

{
  "prompt": "你好,请介绍一下自己,包括详细的版本信息以及当前的年月日时分秒"
}

### POST 请求测试 (如果接口支持POST)
POST http://localhost:8080/api/qwen/aiservicesimplechat
Content-Type: application/json
Accept: application/json

{
  "prompt": "他打败过哪些对手?"
}

### 测试带参数的 GET 请求
GET http://localhost:8080/api/qwen?query=你好世界
Accept: application/json


### POST 请求测试 (如果接口支持POST)
POST http://localhost:8080/api/qwen/aiservicetemplatechat
Content-Type: application/json
Accept: application/json

{
  "prompt": "三国演义"
}

### POST 使用系统消息的模板对话
POST http://localhost:8080/api/qwen/aiservicetemplatechatwithsysmsg
Content-Type: application/json
Accept: application/json

{
  "prompt": "三国演义"
}

### POST 模拟多轮对话
POST http://localhost:8080/api/qwen/simulatemultiroundchat
Content-Type: application/json
Accept: application/json

{
  "prompt": "他打败过哪些对手?"
}

### POST 使用 ChatRequest 作为入参
POST http://localhost:8080/api/qwen/usechatrequest
Content-Type: application/json
Accept: application/json

{
  "prompt": "Java最新版本有哪些特性?"
}
  • 如下图所示,只要在vscode打开上述文件,再用鼠标点击下图黄框位置,就能发送请求
  • 收到http响应后,会自动弹出新的TAB页展示响应详情,如下图

体验:低级LLM API,最简单的问答

  • 先体验一下最简单的问答,对应下图红框的知识点

  • 请求信息

bash 复制代码
POST http://localhost:8080/api/qwen/chat
Content-Type: application/json
Accept: application/json

{
  "prompt": "简单介绍曹操是谁?"
}
  • 没问题,收到来自大模型的回答
bash 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Tue, 02 Dec 2025 00:51:08 GMT
Connection: close

{
  "result": "曹操(155年-220年),字孟德,东汉末年著名的政治家、军事家、文学家和诗人,沛国谯县(今安徽亳州)人。他是三国时期曹魏政权的奠基者,虽未称帝,但其子曹丕建立魏国后追尊他为魏武帝。\n\n在东汉末年天下大乱、群雄割据的背景下,曹操以"挟天子以令诸侯"的策略,迎汉献帝至许都,掌握朝廷实权。他统一了中国北方,击败袁绍、吕布、袁术等割据势力,并推行屯田制、唯才是举等政策,恢复社会秩序与经济生产。\n\n曹操也是一位杰出的文学家,是"建安文学"的代表人物之一,其诗作如《观沧海》《短歌行》等气势雄浑,情感深沉,对后世影响深远。\n\n历史上对曹操的评价复杂多元:传统史书(如《三国志》《后汉书》)多肯定其才能与功绩;而小说《三国演义》则将其塑造成"奸雄"形象,强调其权谋与多疑。现代史学界普遍认为他是乱世中的杰出人物,兼具雄才大略与复杂性格。"
}
  • 上面的问题问了曹操的情况,如果我们打算像平时对话一样接着聊曹操,大模型会不会和我们继续聊呢?咋们再请求一次试试,如下所示,继续问他有哪些主要对手?
bash 复制代码
POST http://localhost:8080/api/qwen/chat
Content-Type: application/json
Accept: application/json

{
  "prompt": "他有哪些主要对手?"
}
  • 得到回复如下,可见大模型完全不知道所谓的他是谁,也就是说回答问题是完全不知道前面的对话信息
bash 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Tue, 02 Dec 2025 07:23:35 GMT
Connection: close

{
  "result": "您的问题中没有明确指出"他"具体指代哪位人物。为了提供准确的回答,请您补充说明所指的人物姓名或相关背景(例如:历史人物、政治人物、企业家、运动员等)。这样我才能更好地为您解答。"
}
  • 有两种方法解决这个问题:
  1. 自己动手,把前面的聊天记录也发给大模型,让它知道之前发生了什么,稍后我们就会体验到
  2. 借助LangChain4J的记忆功能,这个后面会有单独的一篇来学习

体验:低级LLM API,自己动手实现多轮问答

  • 这里会体验QwenService的simulateMultiRoundChat方法,在聊天时把前面问答的内容也带上,以此来实现多轮问答的效果
  • 下面是聊天内容,可见这里没有提到他是谁,而在QwenService的simulateMultiRoundChat方法中,实际上已经给出了前面的聊天内容,即关于曹操的问答
bash 复制代码
### POST 模拟多轮对话
POST http://localhost:8080/api/qwen/simulatemultiroundchat
Content-Type: application/json
Accept: application/json

{
  "prompt": "他有哪些主要对手?"
}
  • 响应如下,可见只要带上了之前的问答信息,大模型就能理解你说的他是谁
bash 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Tue, 02 Dec 2025 07:45:20 GMT
Connection: close

{
  "result": "曹操主要对手包括:  \n1. **袁绍**------北方强敌,官渡之战被曹操击败。  \n2. **刘备**------汉室宗亲,后建蜀汉,长期与曹魏对峙。  \n3. **孙权**------据江东,联刘抗曹,赤壁之战大败曹操。  \n4. **马超、韩遂**------关中割据势力,被曹操平定。  \n5. **吕布**------勇将,曾占徐州,后被曹操擒杀。[from simulateMultiRoundChat]"
}

体验:高级LLM API,最简单的问答

  • 接下来要连续体验AiService的能力,如下图红框,看看LangChain4j帮我们把开发简化到什么程度
  • 先体验最简单的问答,就是Assistant接口的simpleChat方法,如下图黄框
  • 接下来发送http请求:
bash 复制代码
### POST 请求测试 (如果接口支持POST)
POST http://localhost:8080/api/qwen/aiservicesimplechat
Content-Type: application/json
Accept: application/json

{
  "prompt": "简单介绍曹操是谁?"
}
  • 这是收到的响应
bash 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Tue, 02 Dec 2025 03:41:48 GMT
Connection: close

{
  "result": "曹操(155年-220年),字孟德,东汉末年著名的政治家、军事家、文学家和诗人,沛国谯县(今安徽亳州)人。他是三国时期曹魏政权的奠基者。\n\n在东汉末年天下大乱、群雄割据的背景下,曹操通过征战逐步统一了中国北方,挟天子以令诸侯,迎汉献帝至许昌,掌握朝廷实权。他推行屯田制、唯才是举等政策,恢复经济、稳定社会,为后来曹魏的建立打下基础。\n\n曹操也是一位杰出的文学家,擅长诗歌,其作品如《观沧海》《短歌行》等气势雄浑,开创建安文学之风,与儿子曹丕、曹植并称"三曹"。\n\n虽然传统戏曲和小说(如《三国演义》)常将他描绘为"奸雄",但历史上曹操兼具雄才大略与复杂性格,是中国历史上极具影响力的人物之一。他去世后,其子曹丕称帝,追尊他为魏武帝。[from aiservice simpleChat]"
}
  • 可见使用了AiService后,不用显式调用大模型服务,只需要设计一个接口也能实现同样效果

体验:高级LLM API,使用模板

  • 使用模板来格式化对话内容,请求如下,请求参数会被放入模板中,生成一个新的内容再发给大模型
bash 复制代码
### POST 请求测试 (如果接口支持POST)
POST http://localhost:8080/api/qwen/aiservicetemplatechat
Content-Type: application/json
Accept: application/json

{
  "prompt": "三国演义"
}
  • 响应如下
bash 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Tue, 02 Dec 2025 08:54:10 GMT
Connection: close

{
  "result": "《三国演义》全名《三国志通俗演义》,是中国古代四大名著之一,由元末明初小说家罗贯中根据陈寿的正史《三国志》以及民间传说、戏曲等资料创作而成。它是一部历史演义小说,以东汉末年到西晋初年约百年间的历史为背景,描写了魏、蜀、吴三个政治集团之间的政治斗争和军事冲突。\n\n小说以"桃园三结义"开篇,讲述了刘备、关羽、张飞结为兄弟,共图大业的故事;随后围绕曹操、刘备、孙权三大势力展开,重点刻画了诸如诸葛亮、周瑜、吕布、赵云、司马懿等众多性格鲜明的历史人物。书中融合了真实历史与艺术虚构,情节跌宕起伏,语言生动,充满谋略、忠义、智谋与悲壮色彩。\n\n《三国演义》不仅具有很高的文学价值,也深刻影响了中国人的价值观和文化心理,其中"忠义仁勇""运筹帷幄""天下大势,分久必合,合久必分"等思想广为流传。著名情节如"草船借箭""赤壁之战""空城计""三顾茅庐"等,至今仍被广泛传颂和改编。[from aiservice templateChat]"
}

体验:高级LLM API,设置系统消息

  • 再来体验设置系统消息的AiService,用注解SystemMessage来实现
  • 请求如下
bash 复制代码
### POST 使用系统消息的模板对话
POST http://localhost:8080/api/qwen/aiservicetemplatechatwithsysmsg
Content-Type: application/json
Accept: application/json

{
  "prompt": "三国演义"
}
  • 响应如下,与前面的/api/qwen/aiservicetemplatechat相比,同样的问题,这次的回答更加简洁,可见系统消息已经生效
bash 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Tue, 02 Dec 2025 09:06:50 GMT
Connection: close

{
  "result": "《三国演义》是罗贯中所著历史小说,描写了东汉末年魏、蜀、吴三国争霸的故事,以忠义智谋为核心,塑造了诸葛亮、关羽、曹操等经典人物形象。[from aiservice templateChatWithSysMsg]"
}

体验:低级LLM API,用ChatRequest作为入参

  • 最后是ChatRequest作为入参的体验,与ChatMesage相比,可以在ChatRequest中加入各种设置,这里设置了系统消息
bash 复制代码
### POST 使用 ChatRequest 作为入参
POST http://localhost:8080/api/qwen/usechatrequest
Content-Type: application/json
Accept: application/json

{
  "prompt": "Java最新版本有哪些特性?"
}
  • 响应如下
bash 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Tue, 02 Dec 2025 09:11:21 GMT
Connection: close

{
  "result": "截至 Java 21(2023年9月发布,当前最新 LTS 版本),主要新特性包括:\n\n1. **虚拟线程(Virtual Threads)**(JEP 446)  \n   轻量级线程,简化高并发编程,替代传统平台线程。\n\n2. **模式匹配 for switch**(JEP 441)  \n   支持在 `switch` 中使用类型、null 和守卫[from useChatRequest]"
}
  • 至此,聊天API的实战体验就全部完成了,相信您已经熟悉了基本使用方法,接下来还会继续探索LangChain4j的更多能力,把咱们得大模型应用构造得更加强大

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列
相关推荐
cmdyu_3 小时前
告别 LLM 输出的不确定性:深度解析 TypeChat 如何重塑 AI 工程化开发
人工智能
想你依然心痛3 小时前
AI赋能编程语言挑战赛:从Python到Rust,我用AI大模型重塑开发效率
人工智能·python·rust
测试人社区-千羽3 小时前
AR/VR应用测试核心要点与实施策略
人工智能·安全·职场和发展·自动驾驶·测试用例·ar·vr
慧都小项3 小时前
Parasoft Jtest 如何用 JSON 文件驱动Java 测试自动化
java·自动化·json
人工智能技术咨询.3 小时前
DNN案例一步步构建深层神经网络
人工智能·神经网络
机器之心3 小时前
让谷歌翻身的Gemini 3,上线Flash版
人工智能·openai
bryant_meng3 小时前
【Depth Estimation】learning notes
人工智能·深度学习·计算机视觉·深度估计·depth anything
大模型实验室Lab4AI3 小时前
LLaMA-Factory 课程答疑系列一:10个关键问题速查,官方认证解法让训练推理不踩雷
人工智能·llama
Rabbit_QL3 小时前
【深度学习】Hidden vs Latent:神经网络与概率模型中两个“隐”的本质区别
人工智能·深度学习·神经网络