引言

在人工智能快速发展的当下,大语言模型(LLM)已成为构建智能应用的核心技术之一。LangChain4j 作为 Java 生态中领先的 LLM 应用开发框架,为开发者提供了强大的工具,助力构建基于大语言模型的各类应用。在 Java 领域,目前整合大语言模型的主流工具主要有 Spring AI 和 LangChain4j。许多 Java 开发者可能对 Spring AI 更为熟悉,但 LangChain4j 延续了 LangChain 框架的诸多优点,在 Java 中同样易于使用。

不过,当前网络上关于 LangChain4j 的整合教程较少,官方文档的粒度也不够细致,导致将其集成到现有项目中并非易事。为此,我计划编写一个系列教程,帮助大家快速地将大语言模型集成到自己的项目中。目前已实现了多轮对话和工具调用功能,接下来的短期目标是支持多模态能力和知识库系统。

项目概述

本项目实现了一个基于SpringBoot3的智能对话系统,具有以下核心特性:

  • 流式响应:支持实时流式输出,提供更好的用户体验
  • 多轮对话:基于Redis实现对话历史持久化
  • 工具集成:支持自定义工具函数扩展AI能力
  • 内存管理:智能的对话历史管理,避免上下文过长

技术栈

  • SpringBoot 3.5.3:现代化的Java Web框架
  • Java 21:使用最新的LTS版本
  • LangChain4j 1.1.0-beta7:Java版LangChain框架
  • Redis:用于对话历史持久化存储
  • Lombok:简化Java代码编写

项目结构

src/main/java/com/fengzeng/langchain4j/
├── chat/
│ └── ChatController.java # 聊天控制器
├── config/
│ ├── AssistantConfiguration.java # AI助手配置
│ ├── PersistentChatMemoryStore.java # Redis持久化存储
│ └── RedisTemplateConfig.java # Redis配置
├── service/
│ ├── Assistant.java # 普通助手接口
│ └── StreamingAssistant.java # 流式助手接口
├── tool/
│ └── AssistantTools.java # 自定义工具
└── listener/
└── MyChatModelListener.java # 聊天模型监听器

核心实现

1. 依赖配置

首先在pom.xml中添加必要的依赖:

<dependencies>
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!-- Redis支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> <!-- LangChain4j核心 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.1.0-beta7</version>
</dependency> <!-- OpenAI集成 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>1.1.0-beta7</version>
</dependency> <!-- 响应式支持 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>1.1.0-beta7</version>
</dependency>
</dependencies>

2. 应用配置

application.yaml中配置OpenAI和Redis:

langchain4j:
open-ai:
streaming-chat-model:
base-url: https://yunwu.ai/v1
api-key: your-api-key
model-name: gpt-4o-mini
log-requests: true
log-responses: true spring:
data:
redis:
host: 10.0.5.55
port: 6379
database: 1
password: your-password server:
port: 8000

3. Redis配置

创建Redis模板配置类:

@Configuration
public class RedisTemplateConfig { @Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
}

4. 持久化聊天存储

实现基于Redis的聊天历史持久化:

@Component
@Slf4j
public class PersistentChatMemoryStore implements ChatMemoryStore { @Resource
private RedisTemplate<String, Object> redisTemplate; @Override
public List<ChatMessage> getMessages(Object memoryId) {
Object raw = redisTemplate.opsForValue().get(String.valueOf(memoryId));
if (raw == null) {
// todo 从数据库中查询最近的历史消息记录
return List.of(); // 返回空历史,表示是第一次对话
}
return messagesFromJson(raw.toString());
} @Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
String json = messagesToJson(messages);
redisTemplate.opsForValue().set(String.valueOf(memoryId), json);
} @Override
public void deleteMessages(Object memoryId) {
redisTemplate.delete(String.valueOf(memoryId));
}
}

5. 流式助手接口

定义支持流式响应的AI助手:

@AiService
public interface StreamingAssistant { @SystemMessage("You are a helpful assistant")
Flux<String> chat(@UserMessage String userMessage, @MemoryId int memoryId);
}

6. 自定义工具

扩展AI助手的能力:

@Component
public class AssistantTools { @Tool
@Observed
public String currentTime() {
return LocalDateTime.now().toString();
}
}

7. 聊天控制器

其实,核心步骤就在这里。由于引入了 langchain4j-starter 后,框架会根据配置文件中定义的 xxx-chat-model,自动为你注入对应的实例。因此,关键就在于如何正确获取 Assistant。官方文档给出的示例是直接通过注解注入 Assistant,但这种方式无法注入自定义的 memory(记忆)和 tools(工具),限制了更复杂场景的使用。

下面是一个通过显式方式构建 Assistant 的示例,并提供了一个简单的 REST API 接口:

@RestController
@RequestMapping("/api/v1/chat")
public class ChatController { @Resource
private OpenAiStreamingChatModel openAiChatModel; @Resource
PersistentChatMemoryStore chatMemoryStore; @Resource
AssistantTools assistantTools; @GetMapping(value = "/chat", produces = TEXT_EVENT_STREAM_VALUE)
public Flux<String> model(@RequestParam(value = "message", defaultValue = "Hello") String message,
@RequestParam(value = "memoryId") int memoryId) { StreamingAssistant assistant = getAssistant(memoryId);
return assistant.chat(message, memoryId);
} private StreamingAssistant getAssistant(int memoryId) {
ChatMemoryProvider chatMemoryProvider = o -> MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(10)
.chatMemoryStore(chatMemoryStore)
.build(); return AiServices.builder(StreamingAssistant.class)
.streamingChatModel(openAiChatModel)
.chatMemoryProvider(chatMemoryProvider)
.tools(assistantTools)
.build();
}
}

核心特性解析

1. 多轮对话支持

通过@MemoryId注解和Redis持久化存储,系统能够:

  • 为每个用户会话分配唯一的memoryId
  • 自动保存和恢复对话历史
  • 支持最多10轮对话的上下文窗口

2. 流式响应

使用Flux<String>TEXT_EVENT_STREAM_VALUE实现:

  • 实时流式输出,提升用户体验
  • 减少等待时间,提供即时反馈
  • 支持长文本的渐进式显示

3. 工具集成

通过@Tool注解可以轻松扩展AI能力:

  • 自定义工具函数
  • 自动注入到AI助手中
  • 支持复杂的业务逻辑

4. 内存管理

智能的对话历史管理:

  • 自动限制上下文长度
  • 防止token超限
  • 保持对话的连贯性

使用示例

启动应用

mvn spring-boot:run

API调用

curl -N "http://localhost:8000/api/v1/chat/chat?message=你好&memoryId=123"

前端集成

const eventSource = new EventSource('/api/v1/chat/chat?message=你好&memoryId=123');
eventSource.onmessage = function(event) {
console.log('收到流式响应:', event.data);
};

总结

本项目展示了如何使用SpringBoot3和LangChain4j构建现代化的AI对话系统。通过Redis实现持久化存储,结合流式响应和工具集成,为开发者提供了一个完整的解决方案。

项目特点:

  • 简单易用:基于SpringBoot的熟悉开发模式
  • 功能完整:支持多轮对话、流式响应、工具集成
  • 可扩展性强:模块化设计,易于扩展新功能
  • 生产就绪:包含完整的配置和部署方案

相关资源

SpringBoot3 + LangChain4j + Redis 实现大模型多轮对话及工具调用的更多相关文章

  1. 详解redis网络IO模型

    前言 "redis是单线程的" 这句话我们耳熟能详.但它有一定的前提,redis整个服务不可能只用到一个线程完成所有工作,它还有持久化.key过期删除.集群管理等其它模块,redi ...

  2. redis的线程模型是什么?

    1.面试题 redis和memcached有什么区别? redis的线程模型是什么? 为什么单线程的redis比多线程的memcached效率要高得多(为什么redis是单线程的但是还可以支撑高并发) ...

  3. 深入了解一下Redis的内存模型!

    一.前言 Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站高并发不可或缺的一部分. 我们使用Redis时,会接触Redis的5种对象类型(字 ...

  4. 2.redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?

    作者:中华石杉 面试题 redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发? 面试官心理分析 这个是问 redis 的时候,最基本的 ...

  5. redis和memcached有什么区别?redis的线程模型是什么?为什么单线程的redis比多线程的memcached效率要高得多(为什么redis是单线程的但是还可以支撑高并发)?

    1.redis和memcached有什么区别? 这个事儿吧,你可以比较出N多个区别来,但是我还是采取redis作者给出的几个比较吧 1)Redis支持服务器端的数据操作:Redis相比Memcache ...

  6. redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?

    redis 和 memcached 有啥区别? redis 支持复杂的数据结构 redis 相比 memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作.如果需要缓存能够支持更复杂的结构 ...

  7. 《【面试突击】— Redis篇》-- Redis的线程模型了解吗?为啥单线程效率还这么高?

    能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis的线程模型了解吗?为啥单线程效率还这 ...

  8. C基础 带你手写 redis ae 事件驱动模型

    引言 - 整体认识 redis ae 事件驱动模型, 网上聊得很多. 但当你仔细看完一篇又一篇之后, 可能你看的很舒服, 但对于 作者为什么要这么写, 出发点, 好处, 缺点 ... 可能还是好模糊, ...

  9. Redis 和 Memcached 有什么区别?Redis 的线程模型是什么?为什么单线程的 Redis 比多线程的 Memcached 效率要高得多?

    面试题 redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发? 面试官心理分析 这个是问 redis 的时候,最基本的问题吧,redi ...

  10. Redis 的大 Key 对持久化有什么影响?

    作者:小林coding 图解计算机基础(操作系统.计算机网络.计算机组成.数据库等)网站:https://xiaolincoding.com 大家好,我是小林. 上周有位读者字节一二面时,被问到:Re ...

随机推荐

  1. java开发中简简单单的全局异常处理

    今天吃饭时,被公司新来的同事问道:"项目controller层里好多都没写try,catch,难道异常不用处理吗?".虽然正吃饭时被打扰,让我很讨厌,但是既然他诚心诚意的问了,本着 ...

  2. js判断对象任意深度的key属性是否存在,js的iset方法

    ​ 方法一: 支持纯对象的obj // isset.js module.exports = (obj, keyPath) => { const keys = keyPath.split('.') ...

  3. 2个小时1.5w字| React & Golang 全栈微服务实战

    目录 前言 Golang 入门教程 1. 下载与环境配置 安装 Go Windows 安装 macOS 安装 Linux 安装 理解 GOROOT 和 GOPATH GOROOT GOPATH Go ...

  4. 一个基于 C# Unity 开发的金庸群侠传 3D 版,直呼牛逼!

    前言 大家应该都知道 Unity 游戏引擎是基于 C# 编程语言开发的,今天大姚给大家分享一个基于 C# Unity 开发的金庸群侠传 3D 版,该游戏真的是勾起了一代人的慢慢回忆. 项目介绍 JYX ...

  5. python爬虫爬取小说网站

    项目场景: 利用python爬取某小说网站,主要爬取小说名字,作者,类别,将其保存为三元组形式:(xxx, xxx, xxx)并将其保存至excel表格中.本文从爬取目的到爬取的各步骤都尽量详细的去复 ...

  6. Mysql如何给字符串添加索引(前缀索引)

    在日常开发中,我们经常给字符串添加索引,那么给字段添加索引有什么技巧吗,我们看看下面的例子,我们给一个邮箱添加索引,应该如何添加呢 看看下面这条sql select * from user where ...

  7. 使用IDEA构建SpringBoot应用镜像

    目录 前置设置 编写Dockerfile文件 添加运行配置 前置设置 确保IDEA已经设置了服务器Docker的信息.[1] 确保您有可运行的SpringBoot项目 编写Dockerfile文件 D ...

  8. 快速查看kafka消息内容(支持指定group)

    下载开源的 kafka 界面客户端 KafkaKing:https://github.com/Bronya0/Kafka-King 在成功下载该客户端后,进行连接操作.连接完毕后,切换到 consum ...

  9. 异步日志监控:FastAPI与MongoDB的高效整合之道

    title: 异步日志监控:FastAPI与MongoDB的高效整合之道 date: 2025/05/27 17:49:39 updated: 2025/05/27 17:49:39 author: ...

  10. Java泛型<T> T与T的用法

             泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的 ...