LangChain4j Java Agent智能体会话记忆实战指南

2026-06-06阅读 0热度 0
智能体

LangChain4j 的会话记忆机制,专门用来解决大语言模型天生“无状态”的缺陷——模型自身无法记住历史对话,每次交互都如同初次见面。要在多轮对话中维持上下文连贯,必须依赖 ChatMemory 组件进行有效管理。

直接看效果:用之前的代码测试,第一轮输入“我是小锋”,模型记住了;接着问“我是谁?”——模型完全遗忘。这验证了默认情况下模型确实不具备记忆能力。

会话记忆的核心机制

  • Memory vs. History: ChatMemory 是 LangChain4j 提供的核心抽象,负责管理送入模型的上文信息。与记录完整对话历史的 History 不同,ChatMemory 通过内置算法(如驱逐旧消息、摘要生成、信息注入等)实现选择性“记忆”,既能适配模型的上下文窗口限制,又能控制调用成本与响应延迟。

内置的 ChatMemory 实现

LangChain4j 提供两种开箱即用的 ChatMemory 实现,也支持通过实现 ChatMemory 接口自行扩展。

  • MessageWindowChatMemory:基于滑动窗口,只保留最近的 N 条消息。逻辑清晰,适合快速原型开发或对话轮次较少的场景。
  • TokenWindowChatMemory:同样是滑动窗口,但以 Token 数为限制条件。更精准地控制送入模型的上下文长度(尤其在 Token 计费敏感的场景),超出限制的消息会被彻底丢弃。

会话隔离:@MemoryId 注解

默认情况下 ChatMemory 是所有用户或会话共享的,这容易导致“记忆串扰”——用户 A 的对话内容可能污染用户 B 的上下文。@MemoryId 注解提供了优雅的隔离方案。在 AI Service 接口方法的参数上标注该注解后,LangChain4j 会自动为每个 memoryId 创建并维护独立的 ChatMemory 实例。

先看一个简单会话实例

首先在 AssistantConfig 中定义 ChatMemoryProvider:

@Bean
public ChatMemoryProvider memoryChatMemoryProvider() {
    return memoryId -> MessageWindowChatMemory.builder()
            .id(memoryId) 
            .maxMessages(20) 
            .build(); 
}

接着创建 Assistant4Service 接口,并在 AI Service 注解中配置 chatMemoryProvider:

package com.ja va1234.service;

import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;

@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,
        streamingChatModel = "openAiStreamingChatModel",
        chatMemoryProvider = "memoryChatMemoryProvider"
)
public interface Assistant4Service {

    Flux chat(@MemoryId String memoryId, @UserMessage String question);
}

最后在 MyChatController 中注入 Assistant4Service 并实现 chat6 端点:

@Autowired
private Assistant4Service assistant4Service;

@RequestMapping(value = "/chat6", produces = "text/html;charset=utf-8")
public Flux chat6(String memoryId, String question) {
    return assistant4Service.chat(memoryId, question);
}

测试:先提问“我是小锋”,记得在浏览器地址栏带上 memoryId 参数。

再次提问“我是谁?”——模型已成功记住“我是小锋”。

本质上,第二次请求发送时,系统会将历史提问与回答一并作为提示词传入模型,从而实现上下文连贯。

再学习一个会话持久化实例

实现会话持久化,可以选用数据库或 Redis。企业级开发更倾向于 Redis。

在 Windows 上运行 Redis,推荐使用 Docker 环境。安装 Docker Desktop 后即可操作。

直接执行镜像启动命令:

docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 -v d:/redis-data:/data redis/redis-stack:latest

端口映射说明:6379 映射 redis-stack 服务,8001 映射可视化界面。

第一步:在 pom.xml 中添加 Redis 依赖:


    dev.langchain4j
    langchain4j-community-redis-spring-boot-starter
    1.15.0-beta25

第二步:在 application.yml 中配置 Redis 连接信息:

langchain4j:
  community:
    redis:
      enabled: false # 关闭 Redis 向量库自动配置,仅保留手动管理的会话记忆
  redis:
    host: localhost
    port: 6379
    password: # 无密码时留空
    ttl-seconds: 3600 # 每个会话 key 过期时间,演示用 1 小时

第三步:新建 Redis 会话配置类 RedisChatMemoryConfig:

package com.ja va1234.config;

import dev.langchain4j.community.store.memory.chat.redis.RedisChatMemoryStore;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties(prefix = "langchain4j.redis")
@EnableConfigurationProperties(RedisChatMemoryConfig.class)
public class RedisChatMemoryConfig {
    private String host;
    private int port;
    private String password;
    private long ttlSeconds;

    @Bean
    public RedisChatMemoryStore redisChatMemoryStore() {
        var builder = RedisChatMemoryStore.builder()
                .host(host)
                .port(port)
                .ttl(ttlSeconds);
        if (password != null && !password.isBlank()) {
            builder.password(password);
        }
        return builder.build();
    }

    // getter 和 setter 方法
    public String getHost() { return host; }
    public void setHost(String host) { this.host = host; }
    public int getPort() { return port; }
    public void setPort(int port) { this.port = port; }
    public String getPassword { public void setPassword(String password) { , public getTtlSeconds() {  get?t; }                            ;
}

最后:修改 AssistantConfig,注入 RedisChatMemoryStore:

@Bean
public ChatMemoryProvider memoryChatMemoryProvider(RedisChatMemoryStore redisChatMemoryStore) {
    return memoryId -> MessageWindowChatMemory.builder()
            .id(memoryId)
            .chatMemoryStore(redisChatMemoryStore)
            .maxMessages(20)
            .build();
}

继续测试:先告诉模型“我是小锋”。

在 Redis 客户端中可以看到会话信息已持久化。

再次向模型提问“我是谁?”——模型正确回答。

刷新 Redis 客户端,会话信息也已同步更新。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策