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

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

欢迎访问我的GitHub

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

LangChain4j实战全系列链接

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

本篇概览

  • 由于spring-boot是工程中的常用框架,因此本次实战把spring-boot与LangChain4j集成在一起,增加项目的扩展性和实用性
  • 上图中涉及的API,有一部分不会进入实战,它们是:

《前文》[https://xinchen.blog.ZEEKLOG.net/article/details/155223658]对API做了梳理,如下图,今天通过编码实战来熟悉这些API

在这里插入图片描述
  1. LanguageMode:官方都不推荐使用了,那么我们也没必要体验了
  2. ToolExecutionResultMessage:和Tool有关的略为复杂,后面会有单独的一篇来实践,所以本次跳过
  3. CustomMessage:只有ollama支持,所以本次跳过
  4. ImageContent:涉及到文件处理和模型选择,会有单独一篇来讲解
  5. AudioContent、VideoContent、PdfContent:这些都和ImageContent类似,因此就略过了
  • 现在开始编码吧

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

  • 如果您只想快速浏览完整源码,可以在GitHub下载代码直接运行,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称链接备注
项目主页https://github.com/zq2599/blog_demos该项目在GitHub上的主页
git仓库地址(https)https://github.com/zq2599/blog_demos.git该项目源码的仓库地址,https协议
git仓库地址(ssh)[email protected]:zq2599/blog_demos.git该项目源码的仓库地址,ssh协议

这个git项目中有多个文件夹,本篇的源码在langchain4j-tutorials文件夹下,如下图红色箭头所示:

在这里插入图片描述

开发:创建子工程

  • 《准备工作》(https://xinchen.blog.ZEEKLOG.net/article/details/155104992)一文中创建好了整个实战系列的父工程langchain4j-totorials,所以今天的实战就在此父工程下创建子工程即可,名为demo-with-spring-boot
  • 父工程下新增文件夹demo-with-spring-boot,里面增加pom.xml文件,内容如下,可见主要是spring-boot和langchain4j部分的依赖:
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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
# 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类,平平无奇
packagecom.bolingcavalry;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;/** * Spring Boot应用程序的主类 */@SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String[] args){SpringApplication.run(Application.class, args);}}

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

  • 需要通过接口来定义这个高级LLM API能做什么,这里打算提供三种能力:

本篇要体验高级LLM API,如下图红框所示

在这里插入图片描述
  1. 最简单的对话,传入字符串返回字符串,方法名为simpleChat
  2. 使用模板,就是定义好模板,然后用外部变量来替代模板中的占位符,方法名为temlateChat
  3. 设置系统消息,就是设定大模型的身份角色等,方法名为temlateChatWithSysMsg
  • 上述三种能力都集中在名为Assistant的接口中,如下所示,可见这些能力由一些注解来辅助实现
packagecom.bolingcavalry.service;importdev.langchain4j.service.*;publicinterfaceAssistant{/** * 最简单的对话,只返回助手的回答,不包含任何额外信息 * * @param userMessage 用户消息 * @return 助手生成的回答 */StringsimpleChat(String userMessage);/** * 使用模板进行对话,返回助手的回答 * * @param name 模板中的变量 * @return 助手生成的回答 */@UserMessage("简单介绍一下{{name}}")StringtemlateChat(@V("name")String name);@SystemMessage("你的回答不会超过一百汉字")@UserMessage("简单介绍一下{{name}}")StringtemlateChatWithSysMsg(@V("name")String name);}
  • 高级LLM API的好处就是我们只要做好上述定义,具体实现交给LangChain4j来负责,也就是截图中的AiServices.create

编码:配置类

  • 接下来是配置类,这样就可以通过配置文件来创建模型服务类的实例了
packagecom.bolingcavalry.config;importdev.langchain4j.model.openai.OpenAiChatModel;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importdev.langchain4j.service.AiServices;importcom.bolingcavalry.service.Assistant;/** * LangChain4j配置类 */@ConfigurationpublicclassLangChain4jConfig{@Value("${langchain4j.open-ai.chat-model.api-key}")privateString apiKey;@Value("${langchain4j.open-ai.chat-model.model-name:qwen-turbo}")privateString modelName;@Value("${langchain4j.open-ai.chat-model.base-url}")privateString baseUrl;/** * 创建并配置OpenAiChatModel实例(使用通义千问的OpenAI兼容接口) * @return OpenAiChatModel实例 */@BeanpublicOpenAiChatModelopenAiChatModel(){returnOpenAiChatModel.builder().apiKey(apiKey).modelName(modelName).baseUrl(baseUrl).build();}@BeanpublicAssistantassistant(OpenAiChatModel chatModel){returnAiServices.create(Assistant.class, chatModel);}}
  • 也就是说应用会通过LangChain4jConfig类创建两个实例:openAiChatModel负责低级LLM API,assistant负责高级LLM API

上述代码中的assistant方法值得注意,这里创建了高级LLM API实例bean,就是下图红框中那个,可以看到只要把Assistant.class作为入参,LangChain4j就能创建具有对应能力的bean

在这里插入图片描述

编码:服务类

  • 前面如果依赖注入创建了openAiChatModel和assistant,接下来就创建服务类QwenService,作用是使用openAiChatModel和assistant完成业务功能
  • 完整的代码如下,稍后会详细说明里面的重点
packagecom.bolingcavalry.service;importdev.langchain4j.model.chat.request.ChatRequest;importdev.langchain4j.model.openai.OpenAiChatModel;importjava.util.List;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importdev.langchain4j.data.message.*;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;/** * 通义千问服务类,用于与通义千问模型进行交互 */@ServicepublicclassQwenService{privatestaticfinalLogger logger =LoggerFactory.getLogger(QwenService.class);// 注入OpenAiChatModel,用于与通义千问进行交互privatefinalOpenAiChatModel openAiChatModel;/** * 构造函数,通过依赖注入获取OpenAiChatModel实例 * * @param openAiChatModel OpenAiChatModel实例 */@AutowiredpublicQwenService(OpenAiChatModel openAiChatModel){this.openAiChatModel = openAiChatModel;}/** * 调用通义千问模型进行对话 * * @param message 用户消息 * @return AI回复 */publicStringchat(String message){return openAiChatModel.chat(message);}/** * 获取AI模型的响应(用于接口调用) * * @param prompt 用户提示词 * @return AI生成的回答 */publicStringgetResponse(String prompt){return openAiChatModel.chat(prompt);}@AutowiredprivateAssistant assistant;/** * 调用AiService进行最简单的对话 * * @param prompt 用户提示词 * @return 助手生成的回答 */publicStringaiServiceSimpleChat(String prompt){return assistant.simpleChat(prompt)+"[from aiservice simpleChat]";}/** * 调用AiService进行模板对话 * * @param name 模板中的变量 * @return 助手生成的回答 */publicStringaiServiceTemplateChat(String name){return assistant.temlateChat(name)+"[from aiservice templateChat]";}/** * 调用AiService进行模板对话,包含系统消息 * * @param name 模板中的变量 * @return 助手生成的回答 */publicStringaiServiceTemplateChatWithSysMsg(String name){return assistant.temlateChatWithSysMsg(name)+"[from aiservice templateChatWithSysMsg]";}/** * 模拟多轮对话 * * @param prompt 模板中的变量 * @return 助手生成的回答 */publicStringsimulateMultiRoundChat(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]";}publicStringuseChatRequest(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,然后在响应方法中调用前面服务类的方法即可
/* * @Author: 程序员欣宸 [email protected] * @Date: 2025-11-28 09:41:52 * @LastEditors: 程序员欣宸 [email protected] * @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 */packagecom.bolingcavalry.controller;importcom.bolingcavalry.service.QwenService;importlombok.Data;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;/** * 通义千问控制器,处理与大模型交互的HTTP请求 */@RestController@RequestMapping("/api/qwen")publicclassQwenController{privatefinalQwenService qwenService;/** * 构造函数,通过依赖注入获取QwenService实例 * * @param qwenService QwenService实例 */@AutowiredpublicQwenController(QwenService qwenService){this.qwenService = qwenService;}/** * 提示词请求实体类 */@DatastaticclassPromptRequest{privateString prompt;}/** * 响应实体类 */@DatastaticclassResponse{privateString result;publicResponse(String result){this.result = result;}}/** * 检查请求体是否有效 * * @param request 包含提示词的请求体 * @return 如果有效则返回null,否则返回包含错误信息的ResponseEntity */privateResponseEntity<Response>check(PromptRequest request){if(request ==null|| request.getPrompt()==null|| request.getPrompt().trim().isEmpty()){returnResponseEntity.badRequest().body(newResponse("提示词不能为空"));}returnnull;}/** * 处理POST请求,接收提示词并返回模型响应 * * @param request 包含提示词的请求体 * @return 包含模型响应的ResponseEntity */@PostMapping("/chat")publicResponseEntity<Response>chat(@RequestBodyPromptRequest request){// 检查请求体是否有效ResponseEntity<Response> checkRlt =check(request);if(checkRlt !=null){return checkRlt;}try{// 调用QwenService获取模型响应String response = qwenService.getResponse(request.getPrompt());returnResponseEntity.ok(newResponse(response));}catch(Exception e){// 捕获异常并返回错误信息returnResponseEntity.status(500).body(newResponse("请求处理失败: "+ e.getMessage()));}}@PostMapping("/aiservicesimplechat")publicResponseEntity<Response>aiServiceSimpleChat(@RequestBodyPromptRequest request){ResponseEntity<Response> checkRlt =check(request);if(checkRlt !=null){return checkRlt;}try{// 调用QwenService获取模型响应String response = qwenService.aiServiceSimpleChat(request.getPrompt());returnResponseEntity.ok(newResponse(response));}catch(Exception e){// 捕获异常并返回错误信息returnResponseEntity.status(500).body(newResponse("请求处理失败: "+ e.getMessage()));}}@PostMapping("/aiservicetemplatechat")publicResponseEntity<Response>aiServiceTemplateChat(@RequestBodyPromptRequest request){ResponseEntity<Response> checkRlt =check(request);if(checkRlt !=null){return checkRlt;}try{// 调用QwenService获取模型响应String response = qwenService.aiServiceTemplateChat(request.getPrompt());returnResponseEntity.ok(newResponse(response));}catch(Exception e){// 捕获异常并返回错误信息returnResponseEntity.status(500).body(newResponse("请求处理失败: "+ e.getMessage()));}}@PostMapping("/aiservicetemplatechatwithsysmsg")publicResponseEntity<Response>aiServiceTemplateChatWithSysMsg(@RequestBodyPromptRequest request){ResponseEntity<Response> checkRlt =check(request);if(checkRlt !=null){return checkRlt;}try{// 调用QwenService获取模型响应String response = qwenService.aiServiceTemplateChatWithSysMsg(request.getPrompt());returnResponseEntity.ok(newResponse(response));}catch(Exception e){// 捕获异常并返回错误信息returnResponseEntity.status(500).body(newResponse("请求处理失败: "+ e.getMessage()));}}@PostMapping("/simulatemultiroundchat")publicResponseEntity<Response>simulateMultiRoundChat(@RequestBodyPromptRequest request){ResponseEntity<Response> checkRlt =check(request);if(checkRlt !=null){return checkRlt;}try{// 调用QwenService获取模型响应String response = qwenService.simulateMultiRoundChat(request.getPrompt());returnResponseEntity.ok(newResponse(response));}catch(Exception e){// 捕获异常并返回错误信息returnResponseEntity.status(500).body(newResponse("请求处理失败: "+ e.getMessage()));}}@PostMapping("/usechatrequest")publicResponseEntity<Response>useChatRequest(@RequestBodyPromptRequest request){ResponseEntity<Response> checkRlt =check(request);if(checkRlt !=null){return checkRlt;}try{// 调用QwenService获取模型响应String response = qwenService.useChatRequest(request.getPrompt());returnResponseEntity.ok(newResponse(response));}catch(Exception e){// 捕获异常并返回错误信息returnResponseEntity.status(500).body(newResponse("请求处理失败: "+ e.getMessage()));}}}
  • 至此,代码已写完,我们运行起来

体验:启动服务

  • 这是个spring-boot应用,因此我用了下面的mvn命令来启动
# 进入本篇创建的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内容如下
# 测试 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最新版本有哪些特性?"}

收到http响应后,会自动弹出新的TAB页展示响应详情,如下图

在这里插入图片描述

如下图所示,只要在vscode打开上述文件,再用鼠标点击下图黄框位置,就能发送请求

在这里插入图片描述

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

  • 请求信息

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

在这里插入图片描述
POST http://localhost:8080/api/qwen/chat Content-Type: application/json Accept: application/json {"prompt":"简单介绍曹操是谁?"}
  • 没问题,收到来自大模型的回答
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历史上对曹操的评价复杂多元:传统史书(如《三国志》《后汉书》)多肯定其才能与功绩;而小说《三国演义》则将其塑造成“奸雄”形象,强调其权谋与多疑。现代史学界普遍认为他是乱世中的杰出人物,兼具雄才大略与复杂性格。"}
  • 上面的问题问了曹操的情况,如果我们打算像平时对话一样接着聊曹操,大模型会不会和我们继续聊呢?咋们再请求一次试试,如下所示,继续问他有哪些主要对手?
POST http://localhost:8080/api/qwen/chat Content-Type: application/json Accept: application/json {"prompt":"他有哪些主要对手?"}
  • 得到回复如下,可见大模型完全不知道所谓的他是谁,也就是说回答问题是完全不知道前面的对话信息
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方法中,实际上已经给出了前面的聊天内容,即关于曹操的问答
### POST 模拟多轮对话 POST http://localhost:8080/api/qwen/simulatemultiroundchat Content-Type: application/json Accept: application/json {"prompt":"他有哪些主要对手?"}
  • 响应如下,可见只要带上了之前的问答信息,大模型就能理解你说的他是谁
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,最简单的问答

  • 接下来发送http请求:

先体验最简单的问答,就是Assistant接口的simpleChat方法,如下图黄框

在这里插入图片描述

接下来要连续体验AiService的能力,如下图红框,看看LangChain4j帮我们把开发简化到什么程度

在这里插入图片描述
### POST 请求测试 (如果接口支持POST) POST http://localhost:8080/api/qwen/aiservicesimplechat Content-Type: application/json Accept: application/json {"prompt":"简单介绍曹操是谁?"}
  • 这是收到的响应
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,使用模板

  • 使用模板来格式化对话内容,请求如下,请求参数会被放入模板中,生成一个新的内容再发给大模型
### POST 请求测试 (如果接口支持POST) POST http://localhost:8080/api/qwen/aiservicetemplatechat Content-Type: application/json Accept: application/json {"prompt":"三国演义"}
  • 响应如下
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来实现

在这里插入图片描述
### POST 使用系统消息的模板对话 POST http://localhost:8080/api/qwen/aiservicetemplatechatwithsysmsg Content-Type: application/json Accept: application/json {"prompt":"三国演义"}
  • 响应如下,与前面的/api/qwen/aiservicetemplatechat相比,同样的问题,这次的回答更加简洁,可见系统消息已经生效
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中加入各种设置,这里设置了系统消息
### POST 使用 ChatRequest 作为入参 POST http://localhost:8080/api/qwen/usechatrequest Content-Type: application/json Accept: application/json {"prompt":"Java最新版本有哪些特性?"}
  • 响应如下
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系列

Read more

RabbitMQ用法的6种核心模式全面解析

RabbitMQ用法的6种核心模式全面解析

文章目录 * **一、RabbitMQ核心架构解析** * 1. AMQP协议模型 * 2. 消息流转原理 * **二、六大核心用法详解** * **1. 简单队列模式(Hello World)** * **2. 工作队列模式(Work Queues)** * **3. 发布/订阅模式(Pub/Sub)** * **4. 路由模式(Routing)** * **5. 主题模式(Topics)** * **6. RPC模式(远程调用)** * **三、高级特性实战** * **1. 消息持久化** * **2. 死信队列(DLX)** * **3. 延迟队列(插件实现)** * **四、集群与高可用方案** * 1. 镜像队列配置 * 2. 联邦跨机房部署 * **五、性能调优指南** * **六、

By Ne0inhk
KingbaseES数据库:ksql 命令行从建表到删表实战(含避坑指南)

KingbaseES数据库:ksql 命令行从建表到删表实战(含避坑指南)

KingbaseES数据库:ksql 命令行从建表到删表实战(含避坑指南) 本文围绕 KingbaseES 中 ksql 命令行操作表展开,涵盖表 “创建→查看→数据增删改查→结构修改→删除” 全生命周期。前置准备需连接数据库并切换目标模式,可选确认表空间;创建表要明确数据类型与约束,含基础单表、进阶复合主键表示例;查看表结构可通过 \dt、\d、\d + 命令分别获取表列表、基本结构、详细信息;数据操作聚焦 INSERT(单条 / 批量)、SELECT(全量 / 条件 / 排序)、UPDATE(必加 WHERE)、DELETE(必加 WHERE);结构修改含增列、改列、删列、加约束、改表名;还梳理了三类常见报错解决方案。全文搭配实操命令与验证方法,助力新手快速掌握表操作核心技巧。

By Ne0inhk

PostgreSQL:如何定期验证备份的有效性?(灾备演练)

更多内容请见: 《深入掌握PostgreSQL数据库》 - 专栏介绍和目录 文章目录 * 一、为什么必须验证备份? * 二、验证目标与分类 * 三、逻辑备份(pg_dump / pg_dumpall)验证 * 1. 基础验证:语法与结构 * 2. 完整恢复测试(推荐每月一次) * 3. 自动化脚本示例 * 四、物理备份(Base Backup + WAL 归档)验证 * 步骤 1:准备恢复环境 * 步骤 2:执行 PITR 恢复 * 步骤 3:数据一致性检查 * 五、自动化灾备演练框架 * 架构设计 * 关键组件 * 六、高级验证技术 * 1. WAL

By Ne0inhk

Flutter 组件 pair 适配鸿蒙 HarmonyOS 实战:结构化元组治理,构建轻量级双元数据模型与跨层传递架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 pair 适配鸿蒙 HarmonyOS 实战:结构化元组治理,构建轻量级双元数据模型与跨层传递架构 前言 在鸿蒙(OpenHarmony)生态迈向多维数据感知、涉及高频函数返回值传递、两元坐标互操作及复杂状态标识返回的背景下,如何以最轻量化的方式实现数据的“成对化”封装,已成为提升代码整洁度与系统运行效率的“工程润滑剂”。在鸿蒙设备这类强调 AOT 极致性能与低内存开销的环境下,如果应用为了简单的双元数据(如:经纬度、错误码+消息)而动态创建大量繁琐的单次使用类(POJO),由于由于对象头开销与 GC 压力,极易由于由于“类爆炸”导致内存碎片的堆积。 我们需要一种能够支持强类型泛型、具备不可变属性且无需显式类定义的元组治理方案。 pair 为 Flutter 开发者引入了源自 C++ 与 Java 标准库经典语义的“

By Ne0inhk