> ## Documentation Index
> Fetch the complete documentation index at: https://nvd-54.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 记忆概述

[记忆](/oss/javascript/langgraph/add-memory)是一种记住先前交互信息的系统。对于 AI 智能体来说，记忆至关重要，因为它让智能体能够记住先前的交互、从反馈中学习并适应用户偏好。随着智能体处理越来越复杂的任务并与用户进行大量交互，这种能力对效率和用户满意度都变得至关重要。

本概念指南涵盖两种基于召回范围的记忆类型：

* [短期记忆](#short-term-memory)，或[线程](/oss/javascript/langgraph/persistence#threads)范围记忆，通过在会话中维护消息历史来跟踪正在进行的对话。LangGraph 将短期记忆作为智能体[状态](/oss/javascript/langgraph/graph-api#state)的一部分进行管理。状态通过[检查点器](/oss/javascript/langgraph/persistence#checkpoints)持久化到数据库中，以便线程可以随时恢复。短期记忆在图被调用或步骤完成时更新，并在每个步骤开始时读取状态。
* [长期记忆](#long-term-memory)跨会话存储用户特定或应用级数据，并在对话线程\_之间\_共享。它可以\_在任何时间\_和\_任何线程\_中被召回。记忆被限定在任何自定义命名空间中，而不仅仅是单个线程 ID 中。LangGraph 提供[存储](/oss/javascript/langgraph/persistence#memory-store)（[参考文档](https://langchain-ai.github.io/langgraph/reference/store/#langgraph.store.base.BaseStore)）让你保存和召回长期记忆。

<img src="https://mintcdn.com/nvd-54/KKmYhbrpyTWf5iQl/oss/images/short-vs-long.png?fit=max&auto=format&n=KKmYhbrpyTWf5iQl&q=85&s=b822e8e98917006e0d786c8637ca4b9b" alt="短期记忆 vs 长期记忆" width="571" height="372" data-path="oss/images/short-vs-long.png" />

## 短期记忆

[短期记忆](/oss/javascript/langgraph/add-memory#add-short-term-memory)让你的应用能够记住单个[线程](/oss/javascript/langgraph/persistence#threads)或对话中的先前交互。[线程](/oss/javascript/langgraph/persistence#threads)组织会话中的多次交互，类似于电子邮件将消息分组在单个对话中的方式。

LangGraph 将短期记忆作为智能体状态的一部分进行管理，通过线程范围的检查点持久化。此状态通常可以包括对话历史以及其他有状态数据，如上传的文件、检索的文档或生成的工件。通过将这些存储在图的状态中，机器人可以访问给定对话的完整上下文，同时保持不同线程之间的分离。

### 管理短期记忆

对话历史是短期记忆最常见的形式，而长对话对当今的 LLM 构成挑战。完整的历史可能不适合 LLM 的上下文窗口，导致不可恢复的错误。即使你的 LLM 支持完整的上下文长度，大多数 LLM 在长上下文中的表现仍然很差。它们会被陈旧或离题的内容"分散注意力"，同时遭受更慢的响应时间和更高的成本。

聊天模型使用消息接受上下文，包括开发者提供的指令（系统消息）和用户输入（人类消息）。在聊天应用中，消息在人类输入和模型响应之间交替，导致消息列表随时间不断增长。由于上下文窗口有限且富含 Token 的消息列表可能很昂贵，许多应用可以受益于使用技术来手动移除或遗忘过期信息。

<img src="https://mintcdn.com/nvd-54/u9mURd9IHXggg6bM/oss/images/filter.png?fit=max&auto=format&n=u9mURd9IHXggg6bM&q=85&s=c244e9fbcf7566587f6d2f948b7c07d5" alt="过滤" width="594" height="200" data-path="oss/images/filter.png" />

有关管理消息的常见技术的更多信息，请参阅[添加和管理记忆](/oss/javascript/langgraph/add-memory#manage-short-term-memory)指南。

## 长期记忆

LangGraph 中的[长期记忆](/oss/javascript/langgraph/add-memory#add-long-term-memory)允许系统在不同的对话或会话之间保留信息。与**线程范围**的短期记忆不同，长期记忆保存在自定义"命名空间"中。

长期记忆是一个没有通用解决方案的复杂挑战。然而，以下问题提供了一个框架来帮助你导航不同的技术：

* 记忆的类型是什么？人类使用记忆来记住事实（[语义记忆](#semantic-memory)）、经历（[情景记忆](#episodic-memory)）和规则（[程序性记忆](#procedural-memory)）。AI 智能体可以用同样的方式使用记忆。例如，AI 智能体可以使用记忆来记住关于用户的特定事实以完成任务。
* [何时更新记忆？](#writing-memories)记忆可以作为智能体应用逻辑的一部分更新（例如"在热路径上"）。在这种情况下，智能体通常在回复用户之前决定记住事实。或者，记忆可以作为后台任务更新（在后台/异步运行的逻辑并生成记忆）。我们在[下方章节](#writing-memories)解释了这些方法之间的权衡。

不同的应用需要各种类型的记忆。虽然类比并不完美，但研究[人类记忆类型](https://www.psychologytoday.com/us/basics/memory/types-of-memory?ref=blog.langchain.dev)可以提供洞察。一些研究（例如 [CoALA 论文](https://arxiv.org/pdf/2309.02427)）甚至将这些人类记忆类型映射到 AI 智能体中使用的类型。

| 记忆类型                      | 存储内容 | 人类示例      | 智能体示例    |
| ------------------------- | ---- | --------- | -------- |
| [语义](#semantic-memory)    | 事实   | 我在学校学到的东西 | 关于用户的事实  |
| [情景](#episodic-memory)    | 经历   | 我做过的事情    | 过去的智能体操作 |
| [程序性](#procedural-memory) | 指令   | 本能或运动技能   | 智能体系统提示  |

### 语义记忆

[语义记忆](https://en.wikipedia.org/wiki/Semantic_memory)，无论是在人类还是 AI 智能体中，都涉及保留特定的事实和概念。对于人类来说，它可以包括在学校学到的信息以及对概念及其关系的理解。对于 AI 智能体来说，语义记忆通常用于通过记住过去交互中的事实或概念来个性化应用。

<Note>
  语义记忆不同于"语义搜索"，后者是使用"含义"（通常以嵌入形式）查找相似内容的技术。语义记忆是心理学术语，指存储事实和知识，而语义搜索是基于含义而非精确匹配来检索信息的方法。
</Note>

语义记忆可以通过不同方式管理：

#### 配置文件

记忆可以是一个持续更新的"配置文件"，包含关于用户、组织或其他实体（包括智能体本身）的范围明确且具体的信息。配置文件通常只是一个 JSON 文档，包含你选择的代表你领域的各种键值对。

记住配置文件时，你需要确保每次都在**更新**配置文件。因此，你需要传入先前的配置文件并[要求模型生成新的配置文件](https://github.com/langchain-ai/memory-template)（或一些 [JSON 补丁](https://github.com/hinthornw/trustcall)应用到旧配置文件上）。随着配置文件变大，这可能变得容易出错，可能需要将配置文件拆分为多个文档或在生成文档时使用**严格**解码来确保记忆模式保持有效。

<img src="https://mintcdn.com/nvd-54/KKmYhbrpyTWf5iQl/oss/images/update-profile.png?fit=max&auto=format&n=KKmYhbrpyTWf5iQl&q=85&s=554914bf5b1aed93c91b681636ec55c5" alt="更新配置文件" width="507" height="516" data-path="oss/images/update-profile.png" />

#### 集合

或者，记忆可以是一个随时间持续更新和扩展的文档集合。每个单独的记忆可以更窄范围且更容易生成，这意味着随时间推移你不太可能**丢失**信息。对于 LLM 来说，为新信息生成\_新\_对象比将新信息与现有配置文件进行协调更容易。因此，文档集合往往导致更高的[召回率](https://en.wikipedia.org/wiki/Precision_and_recall)。

然而，这将一些复杂性转移到了记忆更新上。模型现在必须\_删除\_或\_更新\_列表中的现有项目，这可能很棘手。此外，一些模型可能默认过度插入，而其他模型可能默认过度更新。请参阅 [Trustcall](https://github.com/hinthornw/trustcall) 包了解管理此问题的一种方式，并考虑使用评测（例如像 [LangSmith](/langsmith/evaluation) 这样的工具）来帮助你调优行为。

使用文档集合还将复杂性转移到对列表的记忆**搜索**上。`Store` 目前支持[语义搜索](https://langchain-ai.github.io/langgraph/reference/store/#langgraph.store.base.SearchOp.query)和[按内容过滤](https://langchain-ai.github.io/langgraph/reference/store/#langgraph.store.base.SearchOp.filter)。

最后，使用记忆集合可能使向模型提供全面上下文变得困难。虽然单个记忆可能遵循特定模式，但这种结构可能无法捕获记忆之间的完整上下文或关系。因此，当使用这些记忆生成响应时，模型可能缺少在统一配置文件方法中更容易获得的重要上下文信息。

<img src="https://mintcdn.com/nvd-54/KKmYhbrpyTWf5iQl/oss/images/update-list.png?fit=max&auto=format&n=KKmYhbrpyTWf5iQl&q=85&s=995888e91390186efb388aacc1d29b7f" alt="更新列表" width="483" height="491" data-path="oss/images/update-list.png" />

无论采用哪种记忆管理方法，核心要点是智能体将使用语义记忆来[为其响应提供基础](/oss/javascript/langchain/retrieval)，这通常会带来更个性化和相关的交互。

### 情景记忆

[情景记忆](https://en.wikipedia.org/wiki/Episodic_memory)，在人类和 AI 智能体中，都涉及回忆过去的事件或行动。[CoALA 论文](https://arxiv.org/pdf/2309.02427)很好地框架了这一点：事实可以写入语义记忆，而*经历*可以写入情景记忆。对于 AI 智能体来说，情景记忆通常用于帮助智能体记住如何完成任务。

在实践中，情景记忆通常通过少样本示例提示实现，智能体从过去的序列中学习以正确执行任务。有时"展示"比"告诉"更容易，LLM 从示例中学习效果很好。少样本学习让你通过用输入-输出示例更新提示来["编程"](https://x.com/karpathy/status/1627366413840322562)你的 LLM，以说明预期行为。虽然可以使用各种最佳实践来生成少样本示例，但挑战通常在于根据用户输入选择最相关的示例。

请注意，记忆[存储](/oss/javascript/langgraph/persistence#memory-store)只是将数据存储为少样本示例的一种方式。如果你想要更多开发者参与，或将少样本更紧密地与你的评测框架联系起来，你也可以使用 LangSmith 数据集来存储数据并实现自己的检索逻辑，根据用户输入选择最相关的示例。

参阅这篇[博客文章](https://blog.langchain.dev/few-shot-prompting-to-improve-tool-calling-performance/)，展示了少样本提示如何提高工具调用性能，以及这篇[博客文章](https://blog.langchain.dev/aligning-llm-as-a-judge-with-human-preferences/)使用少样本示例将 LLM 与人类偏好对齐。

### 程序性记忆

[程序性记忆](https://en.wikipedia.org/wiki/Procedural_memory)，在人类和 AI 智能体中，都涉及记住执行任务所使用的规则。对于人类来说，程序性记忆就像内化的关于如何执行任务的知识，例如通过基本的运动技能和平衡来骑自行车。情景记忆则涉及回忆特定的经历，例如第一次在没有辅助轮的情况下成功骑自行车或一次令人难忘的穿越风景路线的自行车骑行。对于 AI 智能体来说，程序性记忆是模型权重、智能体代码和智能体提示的组合，共同决定智能体的功能。

在实践中，智能体修改其模型权重或重写其代码是相当少见的。然而，智能体修改其自身提示则更为常见。

改进智能体指令的一种有效方法是通过["反思"](https://blog.langchain.dev/reflection-agents/)或元提示。这涉及用其当前指令（例如系统提示）以及最近的对话或显式用户反馈来提示智能体。然后智能体根据此输入改进其自身指令。此方法特别适用于指令难以预先指定的任务，因为它允许智能体从其交互中学习和适应。

例如，我们构建了一个[推文生成器](https://www.youtube.com/watch?v=Vn8A3BxfplE)，使用外部反馈和提示重写来生成高质量的论文 Twitter 摘要。在这种情况下，具体的摘要提示难以*事先*指定，但用户批评生成的推文并提供改进摘要过程的反馈相当容易。

下面的伪代码展示了如何使用 LangGraph 记忆[存储](/oss/javascript/langgraph/persistence#memory-store)实现这一点，使用存储来保存提示，`update_instructions` 节点获取当前提示（以及在 `state["messages"]` 中捕获的与用户对话的反馈），更新提示并将新提示保存回存储。然后，`call_model` 从存储获取更新后的提示并使用它来生成响应。

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// 使用指令的节点
const callModel = async (state: State, store: BaseStore) => {
    const namespace = ["agent_instructions"];
    const instructions = await store.get(namespace, "agent_a");
    // 应用逻辑
    const prompt = promptTemplate.format({
        instructions: instructions[0].value.instructions
    });
    // ...
};

// 更新指令的节点
const updateInstructions = async (state: State, store: BaseStore) => {
    const namespace = ["instructions"];
    const currentInstructions = await store.search(namespace);
    // 记忆逻辑
    const prompt = promptTemplate.format({
        instructions: currentInstructions[0].value.instructions,
        conversation: state.messages
    });
    const output = await llm.invoke(prompt);
    const newInstructions = output.new_instructions;
    await store.put(["agent_instructions"], "agent_a", {
        instructions: newInstructions
    });
    // ...
};
```

<img src="https://mintcdn.com/nvd-54/KKmYhbrpyTWf5iQl/oss/images/update-instructions.png?fit=max&auto=format&n=KKmYhbrpyTWf5iQl&q=85&s=84b85373db88d2a518a589f04a01b77b" alt="更新指令" width="493" height="515" data-path="oss/images/update-instructions.png" />

### 写入记忆

智能体写入记忆有两种主要方法：["在热路径上"](#in-the-hot-path)和["在后台"](#in-the-background)。

<img src="https://mintcdn.com/nvd-54/u9mURd9IHXggg6bM/oss/images/hot_path_vs_background.png?fit=max&auto=format&n=u9mURd9IHXggg6bM&q=85&s=7b4c0846e03cfc64f7542a2117feadfa" alt="热路径 vs 后台" width="842" height="418" data-path="oss/images/hot_path_vs_background.png" />

#### 在热路径上

在运行时创建记忆既有优势也有挑战。积极的一面是，这种方法允许实时更新，使新记忆立即可用于后续交互。它还支持透明性，因为用户可以在创建和存储记忆时收到通知。

然而，这种方法也存在挑战。如果智能体需要一个新工具来决定将什么提交到记忆中，可能会增加复杂性。此外，思考保存什么到记忆的过程可能影响智能体延迟。最后，智能体必须在记忆创建和其他职责之间多任务处理，可能影响所创建记忆的数量和质量。

例如，ChatGPT 使用 [save\_memories](https://openai.com/index/memory-and-new-controls-for-chatgpt/) 工具将记忆作为内容字符串进行更新插入，在每条用户消息中决定是否以及如何使用此工具。请参阅我们的 [memory-agent](https://github.com/langchain-ai/memory-agent) 模板作为参考实现。

#### 在后台

将记忆创建作为单独的后台任务有多种优势。它消除了主应用中的延迟，将应用逻辑与记忆管理分离，并允许智能体更专注地完成任务。这种方法还提供了时间安排记忆创建的灵活性，以避免冗余工作。

然而，这种方法有其自身的挑战。确定写入记忆的频率变得至关重要，因为不频繁的更新可能使其他线程缺少新上下文。决定何时触发记忆形成也很重要。常见策略包括在设定时间段后调度（如果有新事件则重新调度）、使用 cron 调度，或允许用户或应用逻辑手动触发。

请参阅我们的 [memory-service](https://github.com/langchain-ai/memory-template) 模板作为参考实现。

### 记忆存储

LangGraph 将长期记忆作为 JSON 文档存储在[存储](/oss/javascript/langgraph/persistence#memory-store)中。每个记忆在自定义 `namespace`（类似于文件夹）和唯一的 `key`（类似于文件名）下组织。命名空间通常包含用户或组织 ID 或其他标签，使信息更容易组织。这种结构支持记忆的层次化组织。然后通过内容过滤器支持跨命名空间搜索。

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import { InMemoryStore } from "@langchain/langgraph";

const embed = (texts: string[]): number[][] => {
    // 替换为实际的嵌入函数或 LangChain 嵌入对象
    return texts.map(() => [1.0, 2.0]);
};

// InMemoryStore 将数据保存到内存字典中。在生产中使用数据库支持的存储。
const store = new InMemoryStore({ index: { embed, dims: 2 } });
const userId = "my-user";
const applicationContext = "chitchat";
const namespace = [userId, applicationContext];

await store.put(
    namespace,
    "a-memory",
    {
        rules: [
            "User likes short, direct language",
            "User only speaks English & TypeScript",
        ],
        "my-key": "my-value",
    }
);

// 通过 ID 获取"记忆"
const item = await store.get(namespace, "a-memory");

// 在此命名空间中搜索"记忆"，按内容等价性过滤，按向量相似度排序
const items = await store.search(
    namespace,
    {
        filter: { "my-key": "my-value" },
        query: "language preferences"
    }
);
```

有关记忆存储的更多信息，请参阅[持久化](/oss/javascript/langgraph/persistence#memory-store)指南。

## 了解更多

* [上下文概念概述](/oss/javascript/concepts/context)
* [LangChain 中的短期记忆](/oss/javascript/langchain/short-term-memory)
* [LangGraph 中的记忆](/oss/javascript/langgraph/add-memory)

***

<div className="source-links">
  <Callout icon="terminal-2">
    [连接这些文档](/use-these-docs)到 Claude、VSCode 等工具，通过 MCP 获取实时解答。
  </Callout>

  <Callout icon="edit">
    [在 GitHub 上编辑此页面](https://github.com/langchain-ai/docs/edit/main/src/oss/concepts/memory.mdx)或[提交问题](https://github.com/langchain-ai/docs/issues/new/choose)。
  </Callout>
</div>
