langchain4j+mysql+历史记录

langchain4j+mysql+历史记录

一、前言

在构建 AI 聊天应用的过程中,很多开发者往往会把"记忆"和"聊天记录"混为一谈。但实际上,这两者在系统中的角色完全不同。

在 LangChain4j 的体系中,"记忆(Memory)"更多是服务于大模型本身,用于拼接上下文、提升对话连贯性,通常依赖于 Redis 等高性能存储实现短期缓存。而"聊天记录"则是面向用户的功能,需要支持历史查询、分页展示,甚至多会话管理,这类数据更适合持久化存储在 MySQL 中。

因此,在一个完整的 AI 聊天系统中,我们往往需要同时设计两套存储体系:

一套用于服务模型的"短期记忆",另一套用于服务用户的"长期历史记录"。

本文将接上期来实现长期历史记录。

二、环境与依赖

环境上期有说到,与上次相似但需要mysql。

依赖

复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.6</version>
</dependency>

<!-- MySQL驱动 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
</dependency>

application.yml

复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/langchain4j_db?useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456

ChatHistory

复制代码
@Data
public class ChatHistory {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String sessionId;
    private String userId;
    private String role;
    private String content;
    private LocalDateTime createTime;
}

ChatHistoryService

复制代码
@Service
public class ChatHistoryService {

    @Resource
    private ChatHistoryMapper mapper;

    public void save(String sessionId, String userId, String role, String content) {
        ChatHistory chat = new ChatHistory();
        chat.setSessionId(sessionId);
        chat.setUserId(userId);
        chat.setRole(role);
        chat.setContent(content);

        mapper.insert(chat);
    }
}

ChatHistoryMapper

复制代码
public interface ChatHistoryMapper extends BaseMapper<ChatHistory> {
}

AiController

复制代码
@Resource
private AiCodeHelperService aiCodeHelperService;

@Resource
private ChatHistoryService chatHistoryService;



@GetMapping(value = "/chat", produces = "text/event-stream")
public Flux<ServerSentEvent<String>> chat(int memoryId, String message) {

    if (message == null || message.isBlank()) {
        return Flux.empty();
    }

    String sessionId = String.valueOf(memoryId);
    String userId = "default";

    // 存用户消息
    chatHistoryService.save(sessionId, userId, "user", message);

    StringBuilder fullAnswer = new StringBuilder();

    return aiCodeHelperService.chatStream(memoryId, message)

            .doOnNext(chunk -> fullAnswer.append(chunk))

            .bufferUntil(chunk ->
                    chunk.endsWith("。") ||
                            chunk.endsWith("!") ||
                            chunk.endsWith("?") ||
                            chunk.endsWith("\n")
            )
            .map(list -> String.join("", list))
            .map(sentence -> ServerSentEvent.<String>builder().data(sentence).build())

            // 存AI回复
            .doOnComplete(() -> {
                chatHistoryService.save(
                        sessionId,
                        userId,
                        "assistant",
                        fullAnswer.toString()
                );
            });
}

Langchain4jApplication

复制代码
@MapperScan("cn.langchain4j.ai.mapper")

创建数据库 langchain4j_db

复制代码
CREATE TABLE chat_history (

    id BIGINT PRIMARY KEY AUTO_INCREMENT,

    session_id VARCHAR(64),

    user_id VARCHAR(64),

    role VARCHAR(20),

    content TEXT,

    create_time DATETIME DEFAULT CURRENT_TIMESTAMP

);

到这里就完成了对聊天信息的存储,接下来做查询。

MybatisPlusConfig

复制代码
@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}

ChatHistoryService

复制代码
public Page<ChatHistory> page(String sessionId, int page, int size) {

    Page<ChatHistory> pageParam = new Page<>(page, size);

    LambdaQueryWrapper<ChatHistory> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(ChatHistory::getSessionId, sessionId)
            .orderByDesc(ChatHistory::getCreateTime);

    return mapper.selectPage(pageParam, wrapper);
}

AiController

复制代码
@GetMapping("/history")
public Page<ChatHistory> history(
        String sessionId,
        int page,
        int size) {

    return chatHistoryService.page(sessionId, page, size);
}
相关推荐
玖玥拾12 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
渣渣灰飞14 小时前
MySQL 系统学习 第五阶段:企业级 MySQL 实战开发 第二章:RBAC 权限系统设计
android·学习·mysql
AskHarries15 小时前
PostgreSQL 还是 MySQL
mysql·postgrel
Leighteen16 小时前
Redis与MySQL双写一致性:从问题根源到工程落地
数据库·redis·mysql
pycharm使用学习18 小时前
NCSS 2025安装教程(附安装包)NCSS 数据分析环境配置图文教程
数据库·mysql·其他·数据分析
醉城夜风~19 小时前
MySQL 常用内置函数全解:字符串、数值、日期、流程控制实战教程
数据库·mysql
Database_Cool_19 小时前
阿里云 RDS MySQL vs 腾讯云 CDB 国内云关系型数据库深度对比
数据库·mysql·阿里云
X-⃢_⃢-X21 小时前
七、数据库的设计规范
数据库·mysql·架构·设计规范
渣渣灰飞21 小时前
MySQL 系统学习 第五阶段:企业级 MySQL 实战开发 第一章:企业数据库设计规范
数据库·学习·mysql