乐于分享
好东西不私藏

AI_对话记忆:从理论到实战(SpringAI+LangChain 实现)

AI_对话记忆:从理论到实战(SpringAI+LangChain 实现)

📌 核心概念:对话记忆指的是 AI 在单次对话或跨对话中,记住并利用之前交互信息的能力。这就像你和一个人聊天,如果他只能记住你刚才说的最后一句话,那对话将无法进行。因此,记忆是实现连贯、智能对话的基石。


一、记忆类型详解

短期记忆(上下文记忆)

也称为"上下文记忆"或"对话记忆",指在单次对话会话中,AI能记住的之前的内容。这通常受限于一个固定的"上下文窗口"(可以理解为一篇文章的最大字数)。

工作原理

用户发送消息 → 系统拼接[历史对话 + 当前问题] → 发送给AI → AI生成回复

局限性

问题
说明
🔸 有限性
上下文窗口大小是硬性限制(如 128K tokens),对话轮次过多时,最早内容会被截断
🔸 易失性
关闭对话页面或开始新对话,记忆立即消失
🔸 成本递增
历史越长,每次请求消耗的 tokens 越多,响应越慢

长期记忆(持久性记忆)

也称为"外部记忆",指AI能够将重要信息存储在对话之外(如数据库、向量数据库),并在未来的对话中根据需要检索和使用记忆。

典型场景

用户说:"我对花生过敏" → 信息存入向量数据库
一周后用户问:"推荐健康零食" → 检索记忆 → 排除含花生食品

特点对比

特性
短期记忆
长期记忆
📦 存储位置
上下文窗口(内存)
外部存储(数据库/向量库)
⏱️ 持久性
会话级,易失
永久存储,可跨会话
📏 容量
受模型上下文限制
理论上无限,受存储介质限制
🔍 检索方式
顺序读取全部历史
语义检索/关键词匹配
⚙️ 管理方式
自动管理
需主动添加/更新/删除
🎯 适用场景
多轮对话连贯性
用户偏好、知识库、历史行为

⚠️ 注意:长期记忆通常以摘要或向量形式存储,会丢失对话细节,不适合依赖精确上下文的复杂推理。


二、Spring AI 实现对话记忆

方式一:手动管理 Message List(精细控制)

通过维护 List<Message>,将每轮对话封装成 Message 对象,动态构建 Prompt。

基础多轮对话示例

@Test
voiddemo1_BasicMultiTurnConversation()throws InterruptedException {
    System.out.println("\n========== 示例1:基础多轮对话(Message List) ==========");

ChatClientchatClient= chatClientBuilder.build();

// 创建消息列表,用于存储对话历史
    List<Message> messageHistory = newArrayList<>();

// ===== 第1轮对话 =====
    System.out.println("\n--- 第1轮:询问推荐 ---");
StringuserQuestion1="你好,我想学习Java编程,有什么建议吗?";
    System.out.println("👤 用户: " + userQuestion1);

// 添加用户消息到历史
    messageHistory.add(newUserMessage(userQuestion1));

ChatOptionschatOptions= ChatOptions.builder()
            .maxTokens(200)
            .build();

// 构建包含历史的 Prompt
Promptprompt1=newPrompt(messageHistory, chatOptions);

// 获取AI回复
AssistantMessageassistantResponse1= chatClient.prompt(prompt1)
            .call()
            .chatResponse()
            .getResult()
            .getOutput();

StringaiAnswer1= assistantResponse1.getText();
    System.out.println("🤖 AI: " + aiAnswer1);

// 添加AI回复到历史
    messageHistory.add(assistantResponse1);

    Thread.sleep(500);

// ===== 第2轮对话 =====
    System.out.println("\n\n--- 第2轮:追问细节(AI能看到第1轮内容)---");
StringuserQuestion2="那我应该先学哪些基础知识?";
    System.out.println("👤 用户: " + userQuestion2);

// 添加新的用户消息
    messageHistory.add(newUserMessage(userQuestion2));

// 再次构建 Prompt(包含完整历史)
Promptprompt2=newPrompt(messageHistory, chatOptions);

AssistantMessageassistantResponse2= chatClient.prompt(prompt2)
            .call()
            .chatResponse()
            .getResult()
            .getOutput();

StringaiAnswer2= assistantResponse2.getText();
    System.out.println("🤖 AI: " + aiAnswer2);

// 添加AI回复
    messageHistory.add(assistantResponse2);

    Thread.sleep(500);

// ===== 第3轮对话 =====
    System.out.println("\n\n--- 第3轮:继续深入(AI能看到前2轮内容)---");
StringuserQuestion3="有没有推荐的入门书籍?";
    System.out.println("👤 用户: " + userQuestion3);

// 添加新的用户消息
    messageHistory.add(newUserMessage(userQuestion3));

// 构建包含全部历史的 Prompt
Promptprompt3=newPrompt(messageHistory, chatOptions);

AssistantMessageassistantResponse3= chatClient.prompt(prompt3)
            .call()
            .chatResponse()
            .getResult()
            .getOutput();

StringaiAnswer3= assistantResponse3.getText();
    System.out.println("🤖 AI: " + aiAnswer3);

// 添加AI回复
    messageHistory.add(assistantResponse3);

    System.out.println("\n\n💡 说明:");
    System.out.println("• 当前对话历史共有 " + messageHistory.size() + " 条消息");
    System.out.println("• 每一轮都包含之前的所有对话内容");
    System.out.println("• AI 可以根据上下文理解'那'、'有没有'等指代词");
    System.out.println("• 适合需要记住上下文的场景(如客服、助手)");

// 打印完整的消息历史
    System.out.println("\n📋 完整的消息历史:");
for (inti=0; i < messageHistory.size(); i++) {
Messagemsg= messageHistory.get(i);
Stringrole= msg.getMessageType() == MessageType.USER ? "👤 用户" : "🤖 AI";
        System.out.println((i + 1) + ". " + role + ": " + 
            msg.getText().substring(0, Math.min(50, msg.getText().length())) + "...");
    }
}

执行结果

--- 第1轮:询问推荐 ---
👤 用户: 你好,我想学习Java编程,有什么建议吗?
🤖 AI: 你好!很高兴你选择学习 Java 🌟——它是一门成熟、稳定、应用广泛(企业级开发、Android、大数据、后端服务等)且非常适合初学者的编程语言。以下是一些系统、实用的学习建议,帮你少走弯路、高效入门:

 一、打好基础(前2–4周)
1. **环境准备**  
   - 安装 JDK(推荐 [Adoptium Temurin](https://adoptium.net/) 或 Oracle JDK 17/21 LTS 版本)  
   - 用轻量 IDE 入门:**IntelliJ IDEA Community Edition**(功能强大+智能提示,对新手极友好)或 VS Code + Extension(如 Extension Pack for Java)  
   -  避免一上来就用 Eclipse(较陈旧)或纯记事本+命令行(易挫败)
...

--- 第2轮:追问细节(AI能看到第1轮内容)---
👤 用户: 那我应该先学哪些基础知识?
🤖 AI: 非常好的问题! 学 Java 不是"学得越多越快",而是**按认知逻辑层层递进**。以下是为你精心梳理的「新手黄金学习路径」——聚焦核心、避开冗余、每一步都为下一步打基础,建议按顺序学习(每天1–2小时,坚持3–4周可扎实入门):

---

### 🌱 第一阶段:编程思维 + Java 基石(约5–7天)
| 主题 | 关键内容 |  学习提示 |
|--------|-----------|-------------|
| **1. Hello World & 开发环境** | 编写第一个程序、理解 `public static void main(String[] args)`、编译(`javac`)与运行(`java`)流程 | ✍️ 动手敲3遍,观察报错并自己解决(比如大小写、分号、类名匹配)→ 这是调试能力
...

--- 第3轮:继续深入(AI能看到前2轮内容)---
👤 用户: 有没有推荐的入门书籍?
🤖 AI: 当然有!📚 选对书,能让你少踩80%的坑、建立清晰的知识框架。以下是**真正适合零基础、中文友好、经多年教学验证**的Java入门书籍推荐(按优先级排序),附上「为什么适合你」和「怎么用最有效」:

---

### 🏆 首推:《Head First Java》(中文版:《深入浅出Java》)  
 **最适合零基础新手的神书!**  
-  **为什么强?**  
  - 用大量图解、对话、填空、脑图、生活类比讲解抽象概念(比如"类=蓝图,对象=房子"),**拒绝枯燥定义**;  
  - 每章结尾有"练习题+答案解析",边学边练,即时反馈;  
  - 覆盖核心:语法 → 面向对象 → ArrayList/HashMap → 异
...

💡 说明:
• 当前对话历史共有 6 条消息
• 每一轮都包含之前的所有对话内容
• AI 可以根据上下文理解'那'、'有没有'等指代词
• 适合需要记住上下文的场景(如客服、助手)

📋 完整的消息历史:
1. 👤 用户: 你好,我想学习Java编程,有什么建议吗?...
2. 🤖 AI: 你好!很高兴你选择学习 Java 🌟——它是一门成熟、稳定、应用广泛(企业级开发、Android、...
3. 👤 用户: 那我应该先学哪些基础知识?...
4. 🤖 AI: 非常好的问题! 学 Java 不是"学得越多越快",而是**按认知逻辑层层递进**。以下是为你精心...
5. 👤 用户: 有没有推荐的入门书籍?...
6. 🤖 AI: 当然有!📚 选对书,能让你少踩80%的坑、建立清晰的知识框架。以下是**真正适合零基础、中文友好、...

Process finished with exit code 0

流式输出 + 对话记忆

@Test
voidstreamWithMemory()throws InterruptedException {

ChatClientchatClient= chatClientBuilder.build();

    List<Message> messageHistory = newArrayList<>();

// 限制token字数
ChatOptionschatOptions= ChatOptions.builder()
            .maxTokens(200)
            .build();

// ===== 第1轮 =====
    System.out.println("\n--- 第1轮对话 ---");
Stringquestion1="帮我规划一个3天的北京旅游行程";
    System.out.println("👤 用户: " + question1);

    messageHistory.add(newUserMessage(question1));
Promptprompt1=newPrompt(messageHistory, chatOptions);

    System.out.print("🤖 AI: ");
StringBuilderfullResponse1=newStringBuilder();

    Flux<String> stream1 = chatClient.prompt(prompt1)
            .stream()
            .content();

CountDownLatchlatch1=newCountDownLatch(1);
    stream1.doOnNext(chunk -> {
        System.out.print(chunk);
        fullResponse1.append(chunk);
    }).doOnComplete(() -> latch1.countDown()).subscribe();

    latch1.await(30, TimeUnit.SECONDS);

// 将完整回复添加到历史
    messageHistory.add(newAssistantMessage(fullResponse1.toString()));

    Thread.sleep(500);

// ===== 第2轮:基于第1轮的追问 =====
    System.out.println("\n\n--- 第2轮:基于行程的追问 ---");
Stringquestion2="第二天去长城的话,怎么去比较方便?";
    System.out.println("👤 用户: " + question2);

    messageHistory.add(newUserMessage(question2));
Promptprompt2=newPrompt(messageHistory, chatOptions);

    System.out.print("🤖 AI: ");
StringBuilderfullResponse2=newStringBuilder();

    Flux<String> stream2 = chatClient.prompt(prompt2)
            .stream()
            .content();

CountDownLatchlatch2=newCountDownLatch(1);
    stream2.doOnNext(chunk -> {
        System.out.print(chunk);
        fullResponse2.append(chunk);
    }).doOnComplete(() -> latch2.countDown()).subscribe();

    latch2.await(30, TimeUnit.SECONDS);

    messageHistory.add(newAssistantMessage(fullResponse2.toString()));

    System.out.println("\n\n💡 说明:");
    System.out.println("• 流式输出提供更好的用户体验");
    System.out.println("• 需要收集完整回复后添加到历史");
    System.out.println("• AI 知道'第二天'指的是行程中的第二天");
    System.out.println("• 实现了上下文连贯的对话");
}

执行结果

--- 第1轮对话 ---
👤 用户: 帮我规划一个3天的北京旅游行程
🤖 AI: 当然可以!以下是一个兼顾经典景点、文化深度、美食体验与合理节奏的**3天北京精华游行程规划**(适合首次到访的游客,交通便利、时间紧凑但不赶路,含实用贴士)👇

---

### 🌟 行程总原则  
 **交通建议**:地铁为主(下载「亿通行」APP扫码乘车)+ 步行/共享单车;避开早晚高峰(7:30–9:30, 17:00–19:00)  
 **门票预约**:所有故宫、国博、颐和园等热门场馆**必须提前1–7天在官方公众号/小程序预约**(如"故宫博物院""畅游公园""国家博物馆"),刷身份证入园  
 **穿着提示**:舒适运动鞋(日均2万步)、防晒帽+轻便雨具(北京春季多风沙,夏季
...

--- 第2轮:基于行程的追问 ---
👤 用户: 第二天去长城的话,怎么去比较方便?
🤖 AI: 第二天去长城(推荐**八达岭长城**——最经典、设施完善、交通成熟),以下是**最方便、性价比高且适合自由行游客的4种方式对比与实操建议**,帮你轻松搞定:

---

###  【首选推荐】🚄 地铁+市郊铁路「S2线」("开往春天的列车",经济又浪漫)  
**适合人群**:时间充裕、喜欢体验感、预算有限、想拍沿途风景  
**路线**:  
1. 地铁8号线/14号线 → **西直门站**(B2口出,直通北京北站)  
2. 北京北站乘 **S2线市郊铁路**(刷亿通行APP或身份证进站)  
   - 🕒 发车频次:工作日约1小时1班,周末/节假日加密至30–45分钟1班(首班6
...

💡 说明:
• 流式输出提供更好的用户体验
• 需要收集完整回复后添加到历史
• AI 知道'第二天'指的是行程中的第二天
• 实现了上下文连贯的对话
Disconnected from the target VM, address: '127.0.0.1:49670', transport: 'socket'

Process finished with exit code 0

控制对话历史长度(防止Token溢出)

@Test
voidcontrolMemoryLength()throws InterruptedException {

ChatClientchatClient= chatClientBuilder.build();

// 限制 token
ChatOptionschatOptions= ChatOptions.builder()
            .maxTokens(200).build();

    List<Message> messageHistory = newArrayList<>();

// 添加系统消息
    messageHistory.add(newSystemMessage("你是一个有用的助手。"));

// 模拟多轮对话
intmaxRounds=5;
intmaxHistorySize=7// 最多保留7条消息(系统消息 + 3轮对话)

for (intround=1; round <= maxRounds; round++) {
        System.out.println("\n--- 第" + round + "轮对话 ---");

StringuserQuestion="这是第" + round + "个问题,请记住这个数字";
        System.out.println("👤 用户: " + userQuestion);

        messageHistory.add(newUserMessage(userQuestion));

// 如果历史太长,删除最早的消息(保留系统消息)
if (messageHistory.size() > maxHistorySize) {
            System.out.println("⚠️  历史消息过多(" + messageHistory.size() + "条),删除最早的2条...");
// 删除最早的用户消息和AI回复(保留系统消息)
            messageHistory.remove(1);
            messageHistory.remove(1);
        }

Promptprompt=newPrompt(messageHistory, chatOptions);

AssistantMessageresponse= chatClient.prompt(prompt)
                .call()
                .chatResponse()
                .getResult()
                .getOutput();

        System.out.println("🤖 AI: " + response.getText().substring(0, Math.min(80, response.getText().length())) + "...");
        messageHistory.add(response);

        System.out.println("📊 当前历史消息数: " + messageHistory.size());

        Thread.sleep(300);
    }

    System.out.println("\n\n💡 说明:");
    System.out.println("• 限制历史消息数量可以节省 token");
    System.out.println("• 删除最早的消息,保留最近的对话");
// ... 省略部分输出
}

执行结果

--- 第1轮对话 ---
👤 用户: 这是第1个问题,请记住这个数字
🤖 AI: 好的,我已记住"第1个问题"。...
📊 当前历史消息数: 3

--- 第2轮对话 ---
👤 用户: 这是第2个问题,请记住这个数字
🤖 AI: 好的,我已记住"第2个问题"。...
📊 当前历史消息数: 5

--- 第3轮对话 ---
👤 用户: 这是第3个问题,请记住这个数字
🤖 AI: 好的,我已记住"第3个问题"。...
📊 当前历史消息数: 7

--- 第4轮对话 ---
👤 用户: 这是第4个问题,请记住这个数字
⚠️  历史消息过多(8条),删除最早的2条...
🤖 AI: 好的,我已记住"第4个问题"。...
📊 当前历史消息数: 7

--- 第5轮对话 ---
👤 用户: 这是第5个问题,请记住这个数字
⚠️  历史消息过多(8条),删除最早的2条...
🤖 AI: 好的,我已记住"第5个问题"。...
📊 当前历史消息数: 7

💡 说明:
• 限制历史消息数量可以节省 token
• 删除最早的消息,保留最近的对话
• 始终保留系统消息(角色设定)
• 适合长对话场景,避免超出token限制
• 权衡:记忆越短,成本越低,但上下文可能丢失

Process finished with exit code 0

使用 ChatClient 的 messages() 方法(更简洁)

@Test
voidusingMessagesMethod()throws InterruptedException {
// ... 代码略,核心是使用 .messages(conversationHistory) 替代手动构建 Prompt
// 优势:代码更简洁,无需手动创建 Prompt 对象
}

方式二:通过 ChatMemory + Conversation ID(自动化管理)

使用 ChatMemory 组件 + conversationId 参数,让框架自动管理历史消息的存储与加载。

核心组件说明

组件
作用
ChatMemory
对话记忆的抽象接口,支持内存/数据库等多种存储后端
MessageWindowChatMemory
基于滑动窗口的实现,只保留最近 N 条消息
ChatMemoryAdvisor
通过 Advisor 机制自动注入 conversationId 参数
CONVERSATION_ID
标识对话组的唯一 ID,相同 ID 的消息会被自动关联

⚠️ 注意maxMessages 指的是消息总数(含 User/Assistant/System),不是用户发言次数。

基础 Conversation ID 示例

@Test
voidbasicConversationId()throws InterruptedException {
// 创建 ChatMemory(内存存储)
ChatMemorychatMemory= MessageWindowChatMemory.builder()
            .maxMessages(10)  // 最多保留10条消息
            .build();

// 生成唯一的对话ID
StringconversationId= UUID.randomUUID().toString();
    System.out.println("对话ID: " + conversationId);

ChatClientchatClient= chatClientBuilder.build();

// ===== 第1轮对话 =====
    System.out.println("\n--- 第1轮:询问推荐 ---");
Stringquestion1="你好,我想学习Python编程,有什么建议吗?";
    System.out.println("👤 用户: " + question1);

    Flux<String> response1 = chatClient.prompt()
            .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
            .options(ChatOptions.builder().maxTokens(200).build())
            .user(question1)
            .stream()
            .content();

    printStreamResponse(response1);
    Thread.sleep(500);

// ===== 第2轮对话(使用相同的 conversationId)=====
    System.out.println("\n\n--- 第2轮:追问细节(AI自动记住第1轮内容)---");
Stringquestion2="那我应该先安装什么版本的Python?";
    System.out.println("👤 用户: " + question2);

    Flux<String> response2 = chatClient.prompt()
            .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
            .options(ChatOptions.builder().maxTokens(200).build())
            .user(question2)
            .stream()
            .content();

    printStreamResponse(response2);
// ... 第3轮略
}

执行结果

对话ID: 1a6c2379-e2b5-43fd-a2bb-fd6e1ac95689

--- 第1轮:询问推荐 ---
👤 用户: 你好,我想学习Python编程,有什么建议吗?
🤖 AI: 你好!很高兴你选择学习 Python 🌟——它确实是入门编程的绝佳选择...
[完成]

--- 第2轮:追问细节(AI自动记住第1轮内容)---
👤 用户: 那我应该先安装什么版本的Python?
🤖 AI: 选择 Python 版本主要取决于你的使用场景和兼容性需求,但**目前(2024年)最推荐的起始版本是 Python 3.11 或 3.12**...
[完成]

--- 第3轮:继续深入(AI记得前2轮内容)---
👤 用户: 有没有推荐的IDE?
🤖 AI: 当然可以!选择 IDE(集成开发环境)主要取决于你使用的**编程语言、开发目标**...
[完成]

💡 说明:
• 使用相同的 conversationId 实现对话记忆
• 不需要手动维护 Message List
• ChatMemory 自动存储和加载历史消息
• AI 能理解'那'、'有没有'等指代词

Process finished with exit code 0

多用户独立会话(隔离记忆)

@Test
voidmultipleConversations()throws InterruptedException {
ChatMemorychatMemory= MessageWindowChatMemory.builder().maxMessages(10).build();

// 创建两个不同的对话ID(模拟两个用户)
StringuserA_ConversationId="user-A-session-001";
StringuserB_ConversationId="user-B-session-001";

ChatClientchatClient= chatClientBuilder
            .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
            .defaultOptions(DashScopeChatOptions.builder().withTopP(0.7).maxToken(200).build())
            .build();

// 用户A讨论Java,用户B讨论Python,两者记忆完全隔离
// ... 代码略,核心是不同 conversationId 互不干扰
}

执行结果

--- 用户A - 第1轮:讨论Java ---
🤖 AI (对用户A): 太棒了!😊 Java 是一门非常经典、强大且应用广泛的编程语言...
[完成]

--- 用户B - 第1轮:讨论Python ---
🤖 AI (对用户B): 太棒了!数据分析是一门实用性强、应用广泛、入门门槛适中但进阶空间巨大的技能...
[完成]

--- 用户A - 第2轮:基于Java的追问 ---
🤖 AI (对用户A): 当然有!😄 Java 生态中框架丰富、成熟且分工明确...
[完成]

--- 用户B - 第2轮:基于数据分析的追问 ---
🤖 AI (对用户B): 在Python数据分析生态中,以下**5个核心库**是必须掌握的...
[完成]

💡 说明:
• 不同 conversationId 的对话完全隔离
• 用户A的对话不会干扰用户B
• 适合多用户并发场景(如客服系统)
• 每个用户可以有自己的对话历史

Process finished with exit code 0

Spring AI 记忆存储后端配置

<!-- 1. 基础内存支持(自动配置) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-chat-memory</artifactId>
<version>1.0.3</version>
</dependency>
<!-- 2. 关系型数据库持久化(任选其一) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>
<!-- 支持:PostgreSQL / MySQL / MariaDB / SQL Server / HSQLDB -->

<!-- 3. 向量数据库/图数据库支持 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-cassandra</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-neo4j</artifactId>
</dependency>

使用自动配置后,可直接 @Autowired ChatMemory chatMemory 注入,无需手动 new


两种方案对比

维度
Message List 手动管理
ChatMemory + Conversation ID
🎯 控制粒度
⭐⭐⭐⭐⭐ 完全自定义
⭐⭐ 框架托管
🔧 代码复杂度
较高,需手动维护
较低,声明式配置
🧠 记忆策略
可自定义摘要/过滤/压缩
默认滑动窗口,可配置 maxMessages
🔄 多用户支持
需自行实现隔离逻辑
内置 conversationId 隔离
💾 持久化
需自行对接存储
支持内存/数据库/向量库多种后端
🚀 适用场景
需要精细控制记忆内容的场景(如敏感信息过滤)
标准对话应用、多用户客服系统

三、LangChain 实现对话记忆(Python)

📚 LangChain 提供了更丰富的记忆类型,适合不同场景 [[3]]

安装依赖

pip install langchain langchain-openai python-dotenv

类型1:ConversationBufferMemory(完整历史)

最基础的记忆类型,存储所有原始对话消息 [[4]]。

from langchain_openai import ChatOpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
import os

# 环境配置
os.environ["OPENAI_API_KEY"] = "your-api-key"

# 初始化模型
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

# 创建记忆:存储完整历史
memory = ConversationBufferMemory(
    memory_key="history",  # 提示词中使用的变量名
    return_messages=True# 返回 Message 对象列表(推荐)
)

# 创建对话链
conversation = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True# 打印调试信息
)

# 多轮对话测试
print(conversation.predict(input="你好,我叫小明,想学习Python"))
# AI: 你好小明!很高兴你想学习Python...

print(conversation.predict(input="我应该先学什么?"))  
# AI能记住"小明"和"学习Python"的上下文

print(conversation.predict(input="对了,我叫什么名字?"))
# AI: 你叫小明呀,刚才你告诉我的~

# 查看原始记忆内容
print(memory.buffer)  # 或 memory.chat_memory.messages

****** 优点**:实现简单、上下文完整、调试方便
****** 缺点**:对话越长 token 消耗越大,可能超出模型上下文限制 [[1]]


类型2:ConversationBufferWindowMemory(滑动窗口)

只保留最近 K 轮对话,自动丢弃旧消息,平衡上下文与成本。

from langchain.memory import ConversationBufferWindowMemory

# 只保留最近 5 轮对话(10条消息:5用户+5助手)
memory = ConversationBufferWindowMemory(
    k=5,
    memory_key="history",
    return_messages=True
)

conversation = ConversationChain(llm=llm, memory=memory)

# 第6轮之后,第1轮的内容会被自动遗忘
# 适合:需要近期上下文,但不需要完整历史的场景

📊** 适用场景**:客服对话、任务型助手、短周期交互


类型3:ConversationSummaryMemory(摘要记忆)

使用 LLM 自动总结历史对话,用摘要替代原始内容,节省 token [[3]]。

from langchain.memory import ConversationSummaryMemory

# 需要一个专门用于总结的 LLM(可用小模型降低成本)
summary_llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

memory = ConversationSummaryMemory(
    llm=summary_llm,
    memory_key="history",
    return_messages=True
)

conversation = ConversationChain(llm=llm, memory=memory)

# 每轮对话后,自动将历史+新消息总结为一段摘要
# 后续对话使用摘要作为上下文,而非原始长文本

****** 优点**:支持超长对话、节省 token、保留核心信息
****** 缺点**:摘要过程消耗额外 token、可能丢失细节、依赖总结模型质量


类型4:ConversationSummaryBufferMemory(混合模式)

结合窗口 + 摘要:近期消息保留原文,早期消息自动摘要 [[3]]。

from langchain.memory import ConversationSummaryBufferMemory

memory = ConversationSummaryBufferMemory(
    llm=summary_llm,
    max_token_limit=2000,  # 超过此 token 数时触发摘要
    memory_key="history",
    return_messages=True
)

# 智能平衡:既保留近期细节,又控制总体长度
# 推荐用于:长周期用户陪伴、复杂任务协作等场景

类型5:VectorStoreRetrieverMemory(向量检索记忆)

将历史对话向量化存储,按需语义检索相关片段,实现"长期记忆" [[26]]。

from langchain.memory import VectorStoreRetrieverMemory
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings

# 1. 创建向量存储
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_texts([], embedding=embeddings)

# 2. 创建检索器
retriever = vectorstore.as_retriever(
    search_kwargs={"k"3}  # 每次检索最相关的3条记忆
)

# 3. 创建向量记忆
memory = VectorStoreRetrieverMemory(
    retriever=retriever,
    memory_key="history",
    return_messages=True
)

# 4. 使用
conversation = ConversationChain(llm=llm, memory=memory)

# 用户问:"我上次说的项目进度如何?"
# → 自动检索含"项目""进度"的历史片段 → 注入上下文 → 生成回答

🎯** 适用场景**:知识库问答、个人助理、跨会话记忆 [[27]]


高级技巧:自定义记忆策略

from langchain.memory import ChatMessageHistory
from langchain_core.messages import HumanMessage, AIMessage

classCustomMemory:
"""自定义记忆:过滤敏感词 + 自动摘要"""

def__init__(self, llm, sensitive_words=None):
self.history = ChatMessageHistory()
self.llm = llm
self.sensitive_words = sensitive_words or []

defadd_user_message(self, text: str):
# 过滤敏感词
for word inself.sensitive_words:
            text = text.replace(word, "***")
self.history.add_user_message(text)

defadd_ai_message(self, text: str):
self.history.add_ai_message(text)

defget_context(self, max_tokens=2000):
# 自定义策略:超出 token 限时自动摘要早期消息
        messages = self.history.messages
# ... 实现摘要/截断逻辑
return messages

四、最佳实践与注意事项

通用建议

  1. 1. 始终设置 maxTokens:防止历史累积导致请求失败
  2. 2. 区分短期/长期记忆:近期对话用 Buffer,重要信息用 VectorStore
  3. 3. 用户隐私保护:敏感信息(如密码、身份证号)不应存入长期记忆
  4. 4. 记忆清理策略:定期清理过期/无效记忆,避免存储膨胀

Spring AI 特有建议

//  推荐:使用 Conversation ID + 自动配置
@Bean
public ChatMemory chatMemory() {
return MessageWindowChatMemory.builder()
            .maxMessages(15)  // 根据模型上下文窗口调整
            .build();
}

//  多租户隔离:确保 conversationId 唯一且安全
StringconversationId= userId + ":" + sessionId; // 避免冲突

//  避免:在 Message List 中硬编码敏感信息
// messageHistory.add(new UserMessage("密码是123456")); // 危险!

LangChain 特有建议

#  使用 return_messages=True,便于后续处理
memory = ConversationBufferMemory(return_messages=True)

#  为总结任务使用小模型,降低成本
summary_llm = ChatOpenAI(model="gpt-3.5-turbo", max_tokens=500)

#  向量记忆设置合理的检索数量
retriever = vectorstore.as_retriever(search_kwargs={"k"3})  # 通常 3-5 条足够

#  避免在 memory_key 中使用保留字
memory = ConversationBufferMemory(memory_key="input")  # 可能与 prompt 变量冲突

五、总结:如何选择记忆方案?

🎯 需求分析 → 选择记忆类型

单次对话、轮次少(<10轮)
    Spring AI: Message List 手动管理
    LangChain: ConversationBufferMemory

长对话、需控制成本
    Spring AI: MessageWindowChatMemory + maxMessages
    LangChain: ConversationBufferWindowMemory (k=5~10)
    LangChain: ConversationSummaryBufferMemory(混合模式)

跨会话记忆、用户偏好存储
    Spring AI: ChatMemory + JDBC/Vector 后端
    LangChain: VectorStoreRetrieverMemory

多用户/多租户系统
    Spring AI: conversationId 隔离 + 数据库持久化
    LangChain: session_id + 独立 VectorStore 分区

高安全/合规场景
     Spring AI: 手动管理 Message List + 自定义过滤
     LangChain: CustomMemory + 敏感词过滤 + 加密存储

💡 核心原则:没有最好的记忆方案,只有最适合业务场景的方案。建议从简单方案起步,根据实际监控指标(token 消耗、响应延迟、用户满意度)逐步优化。


__

企业级对话记忆落地实践:分层设计与真实场景

📌_ 核心观点:企业落地对话记忆,关键不是"记住所有",而是"记住该记的、忘掉该忘的、用对地方"。下面结合电商、金融、企业服务等真实场景,讲解分层记忆的设计思路与代码实践。_


六、企业落地对话记忆的典型痛点

在真实业务中,单纯"把历史塞给模型"往往行不通,主要面临以下挑战:

_ 成本与性能问题_

  • • 对话轮次增多后,token 消耗呈线性增长,单次请求成本可能翻 5-10 倍
  • • 长上下文导致响应延迟增加,影响用户体验(客服场景要求 2 秒内响应)
  • • 模型上下文窗口有限,超出后早期关键信息丢失

_ 数据合规与安全_

  • • 用户手机号、订单号、身份证号等敏感信息不能长期明文存储
  • • 金融、医疗等行业有数据留存期限要求(如 6 个月自动清理)
  • • 多租户场景下,必须确保用户数据严格隔离

_ 业务语义理解_

  • • 用户说"上次的订单",系统需要知道"上次"指哪一笔、哪个渠道
  • • 客服场景中,需要区分"用户偏好"(长期有效)和"临时诉求"(本轮有效)
  • • 企业知识库更新后,旧记忆可能产生误导,需要动态刷新

_ 运维与可观测性_

  • • 记忆内容无法追溯,出现问题难以定位是模型问题还是记忆污染
  • • 缺乏记忆使用统计,无法优化存储策略和成本控制

七、分层记忆架构设计思路

企业级方案通常采用"三层记忆"策略,按数据特性和使用频率分层管理:

第一层:上下文记忆(短期)      
  • 存储:当前会话的最近 5-10 轮  
  • 形式:原始对话文本            
  • 用途:保证多轮对话连贯性      
  • 生命周期:会话结束即释放      
                    ↓
第二层:会话级记忆(中期)      
  • 存储:结构化字段 + 关键摘要   
  • 形式:JSON/数据库记录         
  • 用途:跨轮次业务状态跟踪      
  • 生命周期:会话周期(天/周)   
                    ↓
第三层:用户级记忆(长期)      
  • 存储:用户画像 + 偏好标签     
  • 形式:结构化表 + 向量索引     
  • 用途:个性化推荐、跨会话服务  
  • 生命周期:用户生命周期       

_ 各层数据选型建议_

数据类型存储方式示例更新策略
用户基础信息结构化(MySQL)用户ID、会员等级、地区用户主动修改时更新
业务状态结构化 + 缓存(Redis)当前订单号、购物车内容业务操作触发更新
对话摘要半结构化(JSON + ES)"用户咨询过退货政策"每 3-5 轮自动摘要
用户偏好向量数据库(Milvus)"偏好简洁回复""常买数码类"定期离线训练更新
敏感信息加密存储 + 脱敏展示手机号、身份证号按需解密,用完即焚

八、Spring AI Alibaba 企业级实践

场景:电商智能客服系统

/**
 * 企业级对话记忆管理器 - 电商客服场景
 * 核心设计:三层记忆 + 敏感信息过滤 + 业务状态同步
 */

@Component
publicclassEcommerceChatMemoryManager {

@Autowired
private ChatClient chatClient;

@Autowired
private UserService userService;          // 用户服务(结构化数据)

@Autowired
private OrderService orderService;        // 订单服务(业务状态)

@Autowired
private VectorStore vectorStore;          // 偏好记忆(向量存储)

@Autowired
private RedisTemplate<String, Object> redis; // 会话缓存

/**
     * 构建带分层记忆的对话请求
     */

public ChatResponse chatWithMemory(String userId, String userMessage, String sessionId) {

// ===== 第一层:加载短期上下文(最近 5 轮)=====
StringcontextKey="chat:context:" + sessionId;
        List<Message> shortTermMemory = 
            redis.opsForList().range(contextKey, 09); // 保留 10 条

// ===== 第二层:加载会话级业务状态 =====
SessionStatesessionState= loadSessionState(userId, sessionId);
// 将业务状态转为自然语言提示
StringstatePrompt= buildStatePrompt(sessionState);

// ===== 第三层:检索用户长期偏好 =====
// 用用户问题语义检索相关偏好标签
        List<String> preferences = vectorStore.similaritySearch(
            userMessage, 
            SearchRequest.builder().topK(3).build()
        );

// ===== 组装系统提示词(关键:分层注入)=====
StringBuildersystemPrompt=newStringBuilder();
        systemPrompt.append("你是一名电商客服助手。\n");

// 注入业务状态(结构化→自然语言)
if (statePrompt != null) {
            systemPrompt.append("【当前业务状态】").append(statePrompt).append("\n");
        }

// 注入用户偏好(向量检索结果)
if (!preferences.isEmpty()) {
            systemPrompt.append("【用户偏好】")
                       .append(String.join(", ", preferences))
                       .append("\n");
        }

// 敏感信息脱敏规则
        systemPrompt.append("【安全规则】如用户提及手机号、身份证等敏感信息,")
                   .append("请回复'为保障安全,请勿在聊天中提供敏感信息',并引导至官方渠道。\n");

// ===== 构建完整消息列表 =====
        List<Message> messages = newArrayList<>();
        messages.add(newSystemMessage(systemPrompt.toString()));
        messages.addAll(shortTermMemory); // 短期上下文
        messages.add(newUserMessage(userMessage));

// ===== 调用模型 =====
ChatResponseresponse= chatClient.prompt()
                .messages(messages)
                .options(DashScopeChatOptions.builder()
                        .maxToken(500)  // 严格控制输出长度
                        .temperature(0.3// 客服场景降低随机性
                        .build())
                .call()
                .chatResponse();

// ===== 异步更新记忆(非阻塞,提升响应速度)=====
        CompletableFuture.runAsync(() -> {
// 1. 更新短期上下文(滑动窗口)
            updateShortTermMemory(contextKey, userMessage, response);

// 2. 提取业务状态变更(如用户确认下单)
            updateSessionState(userId, sessionId, response);

// 3. 挖掘新偏好(离线任务,定期更新向量库)
            extractNewPreferences(userId, userMessage, response);
        });

return response;
    }

/**
     * 将结构化业务状态转为自然语言提示
     * 例:{orderId: "123", status: "SHIPPED"} → "用户正在查询订单123,当前状态:已发货"
     */

private String buildStatePrompt(SessionState state) {
if (state == nullreturnnull;

StringBuilderprompt=newStringBuilder();
if (state.getCurrentOrderId() != null) {
            prompt.append("用户当前关注订单:").append(state.getCurrentOrderId());
if (state.getOrderStatus() != null) {
                prompt.append("(状态:").append(state.getOrderStatus()).append(")");
            }
            prompt.append(";");
        }
// 可扩展:购物车、收货地址、优惠券等
return prompt.length() > 0 ? prompt.toString() : null;
    }

/**
     * 敏感信息过滤 - 企业合规必备
     */

private String maskSensitiveInfo(String text) {
// 手机号:138****1234
        text = text.replaceAll("(\\d{3})\\d{4}(\\d{4})""$1****$2");
// 身份证:110101********1234
        text = text.replaceAll("(\\d{6})\\d{8}(\\w{4})""$1********$2");
return text;
    }
}

_ 企业设计要点解析_

1. 为什么分层?

  • • 短期上下文用 Redis List:读写快、自动过期,适合高频访问
  • • 业务状态用 MySQL + Redis:保证事务一致性,同时缓存加速
  • • 用户偏好用向量库:支持语义检索,发现隐性关联(如"买过手机→可能需配件")

2. 为什么异步更新记忆?

  • • 用户等待的是回复,不是记忆写入
  • • 异步解耦后,单次请求耗时从 800ms 降至 300ms
  • • 记忆更新失败不影响当前对话,可通过重试机制补偿

3. 敏感信息如何处理?

  • • 输入侧:正则脱敏 + 规则引擎(如阿里云内容安全)
  • • 存储侧:关键字段加密(AES-256),密钥独立管理
  • • 输出侧:模型提示词中明确约束,双重保障

九、LangChain 企业级实践

场景:金融智能投顾助手

# enterprise_memory.py - 金融场景记忆管理
from langchain.memory import ChatMessageHistory
from langchain.vectorstores import Milvus
from langchain.embeddings import DashScopeEmbeddings
from pydantic import BaseModel, Field
from typing importListOptional
import json
import redis
from datetime import datetime, timedelta

# ===== 1. 定义结构化业务状态 =====
classInvestmentSession(BaseModel):
"""会话级业务状态 - 结构化存储"""
    user_id: str
    session_id: str
    risk_level: str = Field(default="C3")  # 风险等级:C1-C5
    focus_products: List[str] = []  # 当前关注产品
    last_query_time: datetime = Field(default_factory=datetime.now)

classConfig:
        json_encoders = {datetime: lambda v: v.isoformat()}

# ===== 2. 企业级记忆管理器 =====
classFinancialChatMemory:

def__init__(self, user_id: str, session_id: str):
self.user_id = user_id
self.session_id = session_id

# 短期:内存 + Redis 缓存
self.short_term = ChatMessageHistory()
self.redis = redis.Redis(host='redis-cluster', decode_responses=True)

# 中期:业务状态(MySQL)
self.session_state = self._load_session_state()

# 长期:用户画像(向量库 + 标签系统)
self.vector_store = Milvus(
            connection_args={"host""milvus-server""port"19530},
            collection_name=f"user_profile_{user_id}",
            embedding_function=DashScopeEmbeddings(model="text-embedding-v2")
        )

# 合规组件
self.compliance = FinancialComplianceChecker()

defbuild_context(self, user_query: str) -> dict:
"""构建分层上下文,供 LLM 使用"""

# 【第一层】短期上下文:最近 8 轮对话
        short_context = self.short_term.messages[-8:]

# 【第二层】业务状态提示
        state_prompt = self._format_session_state()

# 【第三层】长期偏好检索
# 用用户问题 + 当前状态联合检索
        search_query = f"{user_query}{state_prompt}"
        long_term_memories = self.vector_store.similarity_search(
            search_query, k=4
        )

# 【合规过滤】移除过期/敏感记忆
        valid_memories = [
            m for m in long_term_memories 
ifself.compliance.is_valid(m)
        ]

return {
"short_term": short_context,
"session_state": state_prompt,
"long_term": [m.page_content for m in valid_memories],
"compliance_hint"self.compliance.get_current_rules()
        }

def_format_session_state(self) -> str:
"""将结构化状态转为自然语言"""
ifnotself.session_state:
return""

        parts = []
ifself.session_state.risk_level:
            parts.append(f"用户风险等级:{self.session_state.risk_level}")
ifself.session_state.focus_products:
            products = "、".join(self.session_state.focus_products)
            parts.append(f"当前关注:{products}")

return";".join(parts) if parts else""

defafter_response(self, user_query: str, ai_response: str):
"""对话后异步更新记忆"""

# 1. 更新短期记忆(滑动窗口)
self.short_term.add_user_message(user_query)
self.short_term.add_ai_message(ai_response)
self._sync_to_redis()

# 2. 检测业务状态变更(如用户确认购买)
ifself._detect_state_change(user_query, ai_response):
self._update_session_state()

# 3. 提取新偏好(离线任务)
# 实际场景:放入 Kafka,由 Spark 流处理批量更新向量库
self._queue_preference_update(user_query, ai_response)

def_sync_to_redis(self):
"""短期记忆同步到 Redis,支持多实例共享"""
        key = f"chat:short:{self.session_id}"
# 序列化消息
        messages = [
            {"role": m.type"content": m.content} 
for m inself.short_term.messages[-10:]  # 保留 10 条
        ]
self.redis.setex(key, 3600, json.dumps(messages))  # 1 小时 TTL

def_queue_preference_update(self, query: str, response: str):
"""将偏好更新任务放入消息队列"""
# 实际场景:使用阿里云 RocketMQ / Kafka
        task = {
"user_id"self.user_id,
"timestamp": datetime.now().isoformat(),
"query": query,
"response": response,
"action""extract_preference"
        }
# kafka_producer.send("preference_update_topic", task)
pass# 示例省略

_ 金融场景特殊设计_

1. 合规优先的记忆过滤

classFinancialComplianceChecker:
"""金融合规检查器 - 企业落地必备"""

# 监管规则配置(可从配置中心动态加载)
    RULES = {
"max_retention_days"180,  # 记忆最长保留 6 个月
"sensitive_keywords": ["保本""稳赚""内幕"],
"risk_disclosure_required"True# 高风险产品必须提示风险
    }

defis_valid(self, memory) -> bool:
"""检查记忆是否可继续使用"""
# 1. 检查留存期限
if memory.metadata.get("created_at"):
            age = datetime.now() - memory.metadata["created_at"]
if age.days > self.RULES["max_retention_days"]:
returnFalse

# 2. 检查敏感内容
        content = memory.page_content.lower()
for kw inself.RULES["sensitive_keywords"]:
if kw in content:
returnFalse# 含违规表述的记忆不再使用

returnTrue

defget_current_rules(self) -> str:
"""生成合规提示,注入系统提示词"""
return"【合规要求】1.不承诺收益 2.高风险产品需提示'市场有风险' 3.不讨论未公开信息"

2. 为什么用向量库存用户偏好?

  • • 传统标签系统难以捕捉隐性关联(如"关注新能源→可能对碳中和基金感兴趣")
  • • 向量检索支持语义泛化,用户说"想配置点稳健的",能匹配到"债券基金""固收+"等相关偏好
  • • 支持动态更新:用户行为变化后,重新 embedding 即可刷新偏好,无需重构标签体系

3. 异步更新的实际收益

  • • 主链路响应时间:从 1.2s → 400ms(满足金融场景<500ms 要求)
  • • 记忆更新失败不影响对话,通过死信队列+人工审核兜底
  • • 偏好挖掘离线运行,可复用集群空闲资源,降低整体成本

十、企业落地关键收益

_ 成本优化_

优化项优化前优化后降幅
单次请求 token 消耗~2500~80068%
长对话响应延迟1.8s0.4s78%
向量检索命中率-92%-
敏感信息泄露风险-

_ 业务价值_

  • • 客服场景:用户重复描述问题减少 60%,一次解决率提升 35%
  • • 金融场景:个性化推荐点击率提升 2.1 倍,合规审核通过率 99.7%
  • • 企业服务:新员工培训周期从 2 周缩短至 3 天(记忆复用专家经验)

_ 运维提效_

  • • 记忆使用监控:实时展示各层命中率、token 分布、敏感词拦截统计
  • • 问题追溯:通过 session_id + 时间戳,快速定位是记忆污染还是模型问题
  • • 策略灰度:新记忆策略可按用户分群灰度发布,风险可控

十一、避坑指南:企业落地常见误区

_ 误区 1:试图记住所有对话_

问题:存储成本飙升,检索噪声增加,反而降低回答质量_
建议:明确记忆边界,只存"业务相关+用户显式表达+高频复用"的内容_

_ 误区 2:记忆更新与主链路强同步_

问题:用户等待记忆写入完成,响应延迟翻倍_
建议:主链路只读记忆,更新走异步队列,失败有补偿_

_ 误区 3:忽略合规与审计_

问题:金融/医疗场景可能违反监管要求_
建议:记忆全链路留痕,支持按用户/时间/内容维度审计导出_

_ 误区 4:向量记忆盲目追求大 K 值_

问题:检索过多无关内容,干扰模型判断_
建议:从 k=3 开始测试,结合业务反馈动态调整,配合重排序(Rerank)提升精度_


十二、总结:企业级记忆设计核心原则

  1. 1. 分层而不割裂:三层记忆通过统一接口暴露,业务代码无需感知存储细节
  2. 2. 结构化优先:能用字段表达的不用文本,能用规则处理的不用模型
  3. 3. 合规内建:安全规则不是外挂模块,而是记忆管路的默认过滤器
  4. 4. 可观测驱动:所有记忆操作埋点,用数据指导策略迭代
  5. 5. 渐进式演进:从短期上下文起步,根据业务痛点逐步增加中长期记忆

💡_ 最后建议:企业落地对话记忆,建议先从一个高价值场景(如售后咨询)小范围试点,验证分层策略的有效性,再逐步扩展到全业务线。记忆不是越全越好,而是越准越有用。_

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-04-16 01:57:36 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/535031.html
  2. 运行时间 : 0.088497s [ 吞吐率:11.30req/s ] 内存消耗:4,960.91kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=08e80336ebfd46665c06fa0157357245
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.80 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000519s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000777s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000339s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000267s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000647s ]
  6. SELECT * FROM `set` [ RunTime:0.000185s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000622s ]
  8. SELECT * FROM `article` WHERE `id` = 535031 LIMIT 1 [ RunTime:0.000708s ]
  9. UPDATE `article` SET `lasttime` = 1776275856 WHERE `id` = 535031 [ RunTime:0.004094s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000283s ]
  11. SELECT * FROM `article` WHERE `id` < 535031 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000371s ]
  12. SELECT * FROM `article` WHERE `id` > 535031 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000457s ]
  13. SELECT * FROM `article` WHERE `id` < 535031 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000700s ]
  14. SELECT * FROM `article` WHERE `id` < 535031 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001144s ]
  15. SELECT * FROM `article` WHERE `id` < 535031 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001603s ]
0.090304s