神族九帝's blog 神族九帝's blog
首页
  • 神卡套餐 (opens new window)
  • 神族九帝 (opens new window)
  • 网盘资源 (opens new window)
  • 今日热点 (opens new window)
  • 在线PS (opens new window)
  • IT工具 (opens new window)
  • FC游戏 (opens new window)
  • 在线壁纸 (opens new window)
  • AI团队搭建总结
  • 面试突击
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 一面
  • 工作笔记
  • 前端基础建设与架构 30 讲
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • 思维导图
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • React
  • Agent学习笔记
  • 更多
  • 未来要做的事
  • Stirling-PDF
  • ComfyUI
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 收藏夹
  • 更多
GitHub (opens new window)

神族九帝,永不言弃

首页
  • 神卡套餐 (opens new window)
  • 神族九帝 (opens new window)
  • 网盘资源 (opens new window)
  • 今日热点 (opens new window)
  • 在线PS (opens new window)
  • IT工具 (opens new window)
  • FC游戏 (opens new window)
  • 在线壁纸 (opens new window)
  • AI团队搭建总结
  • 面试突击
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 一面
  • 工作笔记
  • 前端基础建设与架构 30 讲
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • 思维导图
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • React
  • Agent学习笔记
  • 更多
  • 未来要做的事
  • Stirling-PDF
  • ComfyUI
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 收藏夹
  • 更多
GitHub (opens new window)
  • 工作笔记

  • 前端基础建设与架构 30 讲

  • vue2源码学习

  • 剖析vuejs内部运行机制

  • TypeScript 入门实战笔记

  • vue3源码学习

  • 2周刷完100道前端优质面试真题

  • 思维导图

  • npm发包

  • 重学node

  • 前端性能优化方法与实战

  • webpack原理与实战

  • webGl

  • 前端优化

  • Web3

  • React

  • Agent学习笔记

    • AI-Agent开发要学什么
    • Tool-让大模型调用工具
    • 实现mini-cursor
    • MCP-可跨进程调用的Tool
    • RAG-把文档向量化实现语义搜索
    • RAG的Loader和Splitter
    • LangChain全部Splitter
    • Milvus向量数据库
    • Milvus加RAG实战电子书语义检索
    • Memory管理三大策略
      • Memory 管理的三大策略:截断、总结、检索
      • 存储层:消息存在哪
        • 短时记忆(内存)
        • 长时记忆(文件持久化)
      • 策略一:截断
        • 按消息条数截断
        • 按 token 数量截断
      • 策略二:总结
      • 策略三:检索(RAG)
        • 存储对话到 Milvus
        • 检索相关历史对话
        • RAG 流程
      • 三种策略对比
      • 要点
    • 结构化输出OutputParser和Tool
    • OutputParser实战智能录入和流式Cursor
  • 更多

  • 笔记
  • Agent学习笔记
wu529778790
2026-06-16

Memory管理三大策略

大模型是无状态的,每次调用独立,不记得之前聊过什么。Memory 管理就是让它"记住"。三种策略:截断(按条数或 token 数去掉旧消息)、总结(用 LLM 生成摘要替代旧消息)、检索(存入 Milvus 向量数据库,用 RAG 检索相关历史对话)。存储层有 InMemoryChatMessageHistory(短时记忆)和 FileSystemChatMessageHistory(长时记忆/持久化)。Cursor 和 Claude Code 就是用总结策略——达到 token 限制自动触发总结。之前的 memory API 已废弃,现在直接自己实现。

# Memory 管理的三大策略:截断、总结、检索

大模型是无状态的,每次调用独立,不知道之前问了什么、回答了什么。你感觉它能接着聊,是因为已经做了 Memory 管理。

# 存储层:消息存在哪

# 短时记忆(内存)

import { InMemoryChatMessageHistory } from '@langchain/core/chat_history';

const history = new InMemoryChatMessageHistory();

// 添加消息
await history.addMessage(new HumanMessage('你好'));
await history.addMessage(new AIMessage('你好!有什么可以帮助你的?'));

// 读取消息
const messages = await history.getMessages();

# 长时记忆(文件持久化)

import { FileSystemChatMessageHistory } from '@langchain/community/stores/message/file_system';

const history = new FileSystemChatMessageHistory({
  filePath: './chat_history.json',
  sessionId: 'user_session_001',
});

// 同样的 addMessage / getMessages API
// 关闭程序后重新打开,历史消息还在

类比:Cursor 就是把对话持久化了,随时可以找到之前的聊天继续聊。

# 策略一:截断

超出限制直接去掉旧消息,保留最近的。

# 按消息条数截断

const maxMessages = 4;
const allMessages = await history.getMessages();
const trimmedMessages = allMessages.slice(-maxMessages);  // 保留最近 4 条

# 按 token 数量截断

import { trimMessages } from '@langchain/core/messages';
import { getEncoding } from 'js-tiktoken';

const enc = getEncoding('cl100k_base');

function countTokens(messages) {
  let total = 0;
  for (const msg of messages) {
    total += enc.encode(typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content)).length;
  }
  return total;
}

const trimmedMessages = await trimMessages(allMessages, {
  maxTokens: 100,
  tokenCounter: async (msgs) => countTokens(msgs, enc),
  strategy: 'last',  // 保留最近的消息
});

# 策略二:总结

用 LLM 把旧消息总结成摘要,只保留摘要 + 最近几条消息。

import { getBufferString } from '@langchain/core/messages';

async function summarizeHistory(messages) {
  const conversationText = getBufferString(messages, {
    humanPrefix: '用户',
    aiPrefix: '助手',
  });

  const summaryPrompt = `请总结以下对话的核心内容,保留重要信息:\n${conversationText}\n\n总结:`;
  const response = await model.invoke([new SystemMessage(summaryPrompt)]);
  return response.content;
}

// 触发总结逻辑
const allMessages = await history.getMessages();
if (allMessages.length >= maxMessages) {
  const keepRecent = 2;
  const recentMessages = allMessages.slice(-keepRecent);
  const messagesToSummarize = allMessages.slice(0, -keepRecent);

  // 用 LLM 总结旧消息
  const summary = await summarizeHistory(messagesToSummarize);

  // 清空历史,只保留总结 + 最近消息
  await history.clear();
  // 可以把 summary 作为 SystemMessage 加入
  for (const msg of recentMessages) {
    await history.addMessage(msg);
  }
}

Cursor 和 Claude Code 就是这样:达到 token 限制自动触发总结。Claude Code 还可以 /compact 手动总结。

# 策略三:检索(RAG)

把对话存入 Milvus 向量数据库,用 RAG 检索相关历史对话。

# 存储对话到 Milvus

const conversations = [
  { id: 'conv_001', content: '用户: 我叫赵六\n助手: 你好赵六!', round: 1 },
  { id: 'conv_002', content: '用户: 我在研究机器学习\n助手: 机器学习很有意思!', round: 2 },
  // ...
];

const conversationData = await Promise.all(
  conversations.map(async (conv) => ({
    ...conv,
    vector: await getEmbedding(conv.content),
    timestamp: new Date().toISOString(),
  }))
);

await client.insert({ collection_name: 'conversations', data: conversationData });

# 检索相关历史对话

async function retrieveRelevantConversations(query, k = 2) {
  const queryVector = await getEmbedding(query);
  const searchResult = await client.search({
    collection_name: 'conversations',
    vector: queryVector,
    limit: k,
    metric_type: MetricType.COSINE,
    output_fields: ['id', 'content', 'round', 'timestamp'],
  });
  return searchResult.results;
}

# RAG 流程

// 1. 检索相关历史
const retrievedConversations = await retrieveRelevantConversations(input);

// 2. 构建上下文
const relevantHistory = retrievedConversations
  .map((conv, idx) => `[历史对话 ${idx + 1}]\n轮次: ${conv.round}\n${conv.content}`)
  .join('\n\n━━━━━\n\n');

// 3. 用检索到的历史作为上下文调用 LLM
const response = await model.invoke([
  new HumanMessage(`相关历史对话:\n${relevantHistory}\n\n用户问题: ${input}`)
]);

// 4. 把当前对话也存入 Milvus(供未来检索)
await client.insert({
  collection_name: 'conversations',
  data: [{ id: `conv_${Date.now()}`, vector: convVector, content: conversationText }],
});

不管之前多久聊过什么,都能通过语义检索找到相关对话继续聊。

# 三种策略对比

截断:简单粗暴,直接删旧消息 → 丢失历史信息
总结:LLM 生成摘要,保留核心信息 → 需要额外 LLM 调用
检索:向量数据库语义检索 → 最灵活,但需要 Milvus

# 要点

  • 大模型是无状态的 — Memory 管理是让它"记住"的前提
  • 短时记忆(内存)vs 长时记忆(持久化) — InMemoryChatMessageHistory vs FileSystemChatMessageHistory
  • 截断 — 按条数 slice(-n) 或按 token trimMessages() 去掉旧消息
  • 总结 — 用 LLM 生成对话摘要,Cursor / Claude Code 都用这个策略
  • 检索 — 存入 Milvus,用 RAG 语义检索历史对话,最灵活
  • 之前的 memory API 已废弃 — 现在直接自己实现,逻辑更清晰
  • 可以组合使用 — 比如总结 + 检索:存总结到 Milvus,检索时拿到的是摘要
编辑 (opens new window)
上次更新: 2026/06/17, 14:57:34
Milvus加RAG实战电子书语义检索
结构化输出OutputParser和Tool

← Milvus加RAG实战电子书语义检索 结构化输出OutputParser和Tool→

最近更新
01
OutputParser实战智能录入和流式Cursor
06-18
02
结构化输出OutputParser和Tool
06-17
03
Milvus加RAG实战电子书语义检索
06-15
更多文章>
Power by vuepress | Copyright © 2015-2026 神族九帝
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×