[LangGraph] 管理短期记忆

随着对话会随着轮数不断增长。

这时候,一个非常现实的问题就会出现:对话越聊越长,最终可能会超出大模型的上下文窗口限制。

这并不是 langgraph 独有的问题,而是所有基于大模型的长对话系统都会遇到的限制。

为了解决这个问题,通常有几种常见的处理思路。

  1. 裁剪消息
  2. 永久删除消息
  3. 总结消息
  4. 自定义策略

1. 裁剪消息

最简单的做法是:在每次调用 LLM 之前,只保留一部分对话消息。

例如:

  • 只保留最近的 N 轮对话
  • 或者删除最早的几条消息

这种方式的优点是实现简单、成本低;但缺点也很明显:被裁掉的内容,大模型就“彻底不知道了”。

因此,它更适合用于对历史依赖不强的聊天场景。

2. 永久删除消息

和裁剪类似,但更加彻底:

  • 不是“这一次不用”
  • 而是直接从 langgraph 的 State 中删除

一旦删除,这些消息就不会再参与后续的流程,也不会被 checkpoint 记录。

这种方式适合那些:

  • 明确已经“失去价值”的历史消息
  • 或者只对当前流程阶段有意义的临时信息

3. 总结消息

相比简单裁剪,更合理的一种方式是:把早期对话“压缩成一段总结”。

做法通常是:

  1. 将较早的对话内容交给 LLM
  2. 生成一段摘要
  3. 用这段摘要,替换原本冗长的消息列表

这样一来:

  • 大模型仍然能“知道之前发生了什么”
  • 但上下文占用大幅减少

这也是实际项目中最常见、最平衡的一种方案。

// 这是图里面的一个节点:用于对对话进行压缩总结的
import type { TState } from "./state.ts";
import { KEEP_LAST_N_MESSAGES } from "./config.ts";
import { model } from "./model.ts";
import { AIMessage } from "@langchain/core/messages";

export async function summarizeNode(state: TState): Promise<Partial<TState>> {
  console.log("📝 正在对早期对话进行总结...");

  // 拿出需要被总结的旧消息
  const messagesToSummarize = state.messages.slice(
    0,
    state.messages.length - KEEP_LAST_N_MESSAGES,
  );

  // 构造总结 Prompt
  const summaryPrompt = `
  请将以下对话内容总结成一段简短的中文摘要,
  保留关键信息和上下文,不要逐条列举:
  
  ${messagesToSummarize.map((m) => `${m.type}: ${m.content}`).join("\n")}
  `;

  // 调用大模型得到摘要结果
  const summaryResponse = await model.invoke(summaryPrompt);

  const summaryContent =
    typeof summaryResponse.content === "string"
      ? summaryResponse.content
      : JSON.stringify(summaryResponse.content);

  // 输出总结后的内容
  console.log("\n" + "=".repeat(50));
  console.log("🧹 触发历史消息总结 (Summarization)");
  console.log(`📝 摘要内容: ${summaryContent}`);
  console.log("=".repeat(50) + "\n");

  // 这个相当于就是一条信息
  const summaryMessage = new AIMessage(`【对话摘要】${summaryContent}`);

  // 上面的这一条 AIMessage 就需要去替换原来对话历史里面对应条数的对话
  const newMessages = [
    summaryMessage,
    ...state.messages.slice(-KEEP_LAST_N_MESSAGES),
  ];

  return {
    messages: newMessages,
  };
}

4. 自定义策略

在真实业务中,往往不会只用上述某一种方法,而是组合使用。例如:

  • messages 里,只保留「最近的 + 必要的」
  • 早期对话,压缩成摘要
  • 无关内容直接过滤
  • 关键事实,单独写入长期记忆

这样混合使用,可以取各种策略的优点。总之,自定义策略的核心目标只有一个:让模型在不超出上下文限制的前提下,依然能“知道自己在干什么”。

posted @ 2026-03-11 14:24  Zhentiw  阅读(9)  评论(0)    收藏  举报