LangChain4j

LangChain4J中实现持久化记忆

我们之前也介绍过LangChain4j中的记忆,但是也是介绍的基于内存短期记忆,利用LangChain4j也能做持久化的记忆,但是官方没给现成的实现,只能靠我们自己实现。 在LangChain4j中,有一个内置的ChatMemory…

TL;DR

我们之前也介绍过LangChain4j中的记忆,但是也是介绍的基于内存短期记忆,利用LangChain4j也能做持久化的记忆,但是官方没给现成的实现,只能靠我们自己实现。 在LangChain4j中,有一个内置的ChatMemory…

我们之前也介绍过LangChain4j中的记忆,但是也是介绍的基于内存短期记忆,利用LangChain4j也能做持久化的记忆,但是官方没给现成的实现,只能靠我们自己实现。 在LangChain4j中,有一个内置的ChatMemoryStore接口,可以用它来扩展实现内存记忆。 这个接口中定义了删、改、查等接口:

public interface ChatMemoryStore {


    List<ChatMessage> getMessages(Object memoryId);


    void updateMessages(Object memoryId, List<ChatMessage> messages);

    void deleteMessages(Object memoryId);
}

有了它之后,就可以自己扩展,使用MySQL或者Redis等其他数据库来做保存了。如:

@Component
public class RedisChatMemoryStore implements ChatMemoryStore {

    private final RedisTemplate<String, String> redisTemplate;

    public RedisChatMemoryStore(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public List<ChatMessage> getMessages(Object memoryId) {
        String key = buildKey(memoryId);
        String json = redisTemplate.opsForValue().get(key);

        if (json == null || json.isEmpty()) {
            return Collections.emptyList();
        }

        return ChatMessageDeserializer.messagesFromJson(json);
    }

    @Override
    public void updateMessages(Object memoryId, List<ChatMessage> messages) {
        String key = buildKey(memoryId);
        String json = ChatMessageSerializer.messagesToJson(messages);
        redisTemplate.opsForValue().set(key, json);
    }

    @Override
    public void deleteMessages(Object memoryId) {
        redisTemplate.delete(buildKey(memoryId));
    }

    private String buildKey(Object memoryId) {
        return "langchain4j:chat-memory:" + memoryId;
    }
}

使用方法同样是构造一个MessageWindowChatMemory,把这个RedisChatMemoryStore设置进去就行了。和Spring AI差不多。(应该是Spring AI参考了LangChain4j,只不过自己做了些实现的扩展,更好用了)

langChainMemoryAiService = AiServices.builder(LangChainMemoryAiService.class)
                .chatModel(chatModel)
                .chatMemoryProvider(memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(10).chatMemoryStore(redisChatMemoryStore).build())
                .build();

总的来说,就是LangChain4j 通过三层抽象实现多轮对话记忆:

┌───────────────────────────────────────────────────────┐
│                    AiServices                         │
│  (代理层:自动管理消息的 add / messages 生命周期)          │
└────────────────────────┬──────────────────────────────┘
                         │ 使用
┌────────────────────────▼──────────────────────────────┐
│              ChatMemory (接口)                         │
│  实现类:MessageWindowChatMemory                        │
│  职责:控制记忆窗口大小、消息淘汰策略                       │
│  核心方法:add(message) / messages()                    │
└────────────────────────┬──────────────────────────────┘
                         │ 委托持久化
┌────────────────────────▼──────────────────────────────┐
│            ChatMemoryStore (接口)                      │
│  职责:消息的存储和读取(持久化层)                         │
│  核心方法:getMessages() / updateMessages()             │
└───────────────────────────────────────────────────────┘

LangChain4j 的 AiServices 在每次 LLM 调用时,内部执行以下流程:

// 伪代码:AiServices 内部对 ChatMemory 的操作
List<ChatMessage> history = chatMemoryStore.getMessages(memoryId); // 1. 加载历史
history.add(systemMessage);   // 2. 加入 SystemMessage
history.add(userMessage);     // 3. 加入当前用户消息
chatMemoryStore.updateMessages(memoryId, history); // 4. 持久化(含新用户消息)

AiMessage response = llm.chat(history);  // 5. 调用 LLM

history.add(response);        // 6. 加入 AI 回复
chatMemoryStore.updateMessages(memoryId, history); // 7. 再次持久化(含 AI 回复)

这意味着 ChatMemoryStore 的实现必须保证: - getMessages() 返回的列表在同一次调用内可变且一致 - updateMessages() 需要真正保存状态,否则下一次请求会丢失历史 通过 chatMemoryProvider 可以实现多会话隔离:

.chatMemoryProvider(memoryId -> MessageWindowChatMemory.builder()
        .id(memoryId)                              // memoryId = conversationId
        .maxMessages(10)                           // 滑动窗口:最多保留10条
        .chatMemoryStore(databaseChatMemoryStore)  // 持久化委托
        .build())

配合 AiService 接口上的 @MemoryId 注解:

@AiService
public interface LangChainMemoryAiService {

    String chatMemory(@MemoryId String memoryId, @UserMessage String userMessage);
}

LangChain4j 会自动将 conversationId 作为 memoryId 传递给 ChatMemoryStore,实现每个会话独立记忆。

版本提示

模型、框架与接口会持续变化。涉及版本号、参数与生产配置时,请在实践前对照对应官方文档。

LLMentor系统化学习大模型应用工程

内容来自个人课程知识库备份,并经过结构化整理。技术版本持续演进,生产使用前请结合官方文档验证。