Skip to content
LlamaIndex 文档版本 跟随上游 源快照 6f7d8c1f 更新于 2026-10-15

概念

记忆是智能体系统的核心组件。它让你能够存取过去发生的信息。

在 LlamaIndex 里,定制记忆通常有两种做法:沿用现成的 BaseMemory 类,或者自己写一个。

agent 运行过程中会调用 memory.put() 存信息、调用 memory.get() 取信息。

注意:ChatMemoryBuffer 已弃用。未来的某个版本里,默认将被更灵活、能支持更复杂配置的 Memory 类取代,本节示例都会使用 Memory 类。目前框架各处默认使用 ChatMemoryBuffer,它创建一个基础的聊天历史缓冲区,给 agent 提供能塞进 token 限制的最近 X 条消息。Memory 类的运作方式类似,但更灵活,支持更复杂的记忆配置。

用量

使用 Memory 类,你可以创建一个同时具备短期记忆(即一个消息的先进先出队列)与可选长期记忆(即随时间不断抽取信息)的记忆对象。

为 agent 配置记忆

你可以在调用 run() 方法时把记忆传进去,为 agent 设置 memory:

from llama_index.core.agent.workflow import FunctionAgent
from llama_index.core.memory import Memory

memory = Memory.from_defaults(session_id="my_session", token_limit=40000)

agent = FunctionAgent(llm=llm, tools=tools)

response = await agent.run("<question that invokes tool>", memory=memory)

手动管理记忆

你也可以直接调用 memory.put_messages() 与 memory.get() 来手动管理记忆,把聊天历史传进去。

from llama_index.core.agent.workflow import FunctionAgent
from llama_index.core.llms import ChatMessage
from llama_index.core.memory import Memory

memory = Memory.from_defaults(session_id="my_session", token_limit=40000)
memory.put_messages(
    [
        ChatMessage(role="user", content="Hello, world!"),
        ChatMessage(role="assistant", content="Hello, world to you too!"),
    ]
)
chat_history = memory.get()

agent = FunctionAgent(llm=llm, tools=tools)

# passing in the chat history overrides any existing memory
response = await agent.run(
    "<question that invokes tool>", chat_history=chat_history
)

取回 agent 的最新记忆

要从 agent 拿到最新的记忆,可以从 agent context 中取出:

from llama_index.core.workflow import Context

ctx = Context(agent)

response = await ctx.run("<question that invokes tool>", ctx=ctx)

# get the memory
memory = await ctx.store.get("memory")
chat_history = memory.get()

定制记忆

短期记忆

默认情况下,Memory 类会保存能塞进 token 限制的最近 X 条消息。你可以给 Memory 类传 token_limit 与 chat_history_token_ratio 参数来自定义这一行为。

  • token_limit(默认:30000):短期与长期记忆总共最多存放多少 token。
  • chat_history_token_ratio(默认:0.7):短期聊天历史占总 token 上限的比例。一旦聊天历史超过这个比例,最早的消息就会被刷入长期记忆(前提是启用了长期记忆)。
  • token_flush_size(默认:3000):当聊天历史超出 token 限制时,一次刷入长期记忆的 token 数量。
memory = Memory.from_defaults(
    session_id="my_session",
    token_limit=40000,
    chat_history_token_ratio=0.7,
    token_flush_size=3000,
)

长期记忆

长期记忆由 Memory Block 对象表示。这些对象接收从短期记忆刷出来的消息,并按需做处理以抽取信息。之后在读取记忆时,短期记忆与长期记忆会被合并在一起。

目前预置了三种记忆块:

  • StaticMemoryBlock:保存一段静态信息的记忆块。
  • FactExtractionMemoryBlock:从聊天历史中抽取事实的记忆块。
  • VectorMemoryBlock:把成批聊天消息存入向量库并从中取回的记忆块。

默认情况下,记忆块的内容会根据 insert_method 参数,被插入到系统消息或最新一条用户消息中。

听起来有点复杂,其实相当简单。我们看一个例子:

from llama_index.core.memory import (
    StaticMemoryBlock,
    FactExtractionMemoryBlock,
    VectorMemoryBlock,
)

blocks = [
    StaticMemoryBlock(
        name="core_info",
        static_content="My name is Logan, and I live in Saskatoon. I work at LlamaIndex.",
        priority=0,
    ),
    FactExtractionMemoryBlock(
        name="extracted_info",
        llm=llm,
        max_facts=50,
        priority=1,
    ),
    VectorMemoryBlock(
        name="vector_memory",
        # required: pass in a vector store like qdrant, chroma, weaviate, milvus, etc.
        vector_store=vector_store,
        priority=2,
        embed_model=embed_model,
        # The top-k message batches to retrieve
        # similarity_top_k=2,
        # optional: How many previous messages to include in the retrieval query
        # retrieval_context_window=5
        # optional: pass optional node-postprocessors for things like similarity threshold, etc.
        # node_postprocessors=[...],
    ),
]

这里我们配置了三个记忆块:

  • core_info:一个静态记忆块,存放关于用户的某些核心信息。静态内容可以是一个字符串,也可以是 TextBlock、ImageBlock 等 ContentBlock 对象组成的列表。这些信息始终会被插入记忆。
  • extracted_info:一个抽取型记忆块,会从聊天历史里抽取信息。这里我们传入了用于从刷出的聊天历史中抽取事实的 llm,并把 max_facts 设为 50。一旦抽取的事实数超过这个上限,max_facts 里的内容会被自动摘要并压缩,为新信息腾出空间。
  • vector_memory:一个向量记忆块,把成批聊天消息存入向量库并按需取回。每一批就是一批被刷出的聊天消息。这里我们传入了用于存取的 vector_store 与 embed_model。

你还会注意到我们为每个块设置了 priority。它决定当「记忆块内容(即长期记忆)+ 短期记忆」超出 Memory 对象的 token 上限时该如何处理。

当记忆块过长时,它们会被自动“截断”。默认的含义很简单:把它们从记忆中移除,直到重新腾出空间。你可以通过实现自定义截断逻辑的记忆块子类来改变这一行为。

  • priority=0:该块始终保留在记忆中。
  • priority=1, 2, 3, 等等:决定记忆超出 token 上限时各块的截断顺序,从而使「短期记忆 + 长期记忆」的总内容不超过 token_limit。

现在,把这些块传给 Memory 类:

memory = Memory.from_defaults(
    session_id="my_session",
    token_limit=40000,
    memory_blocks=blocks,
    insert_method="system",
)

随着记忆被使用,短期记忆会逐渐填满。一旦短期记忆超过 chat_history_token_ratio,那些能装进 token_flush_size 的最早消息就会被刷出,并交给每个记忆块处理。

读取记忆时,短期记忆与长期记忆会被合并。Memory 对象会确保「短期记忆 + 长期记忆」的内容不超过 token_limit;如果超出,就会对各记忆块调用 .truncate(),并按 priority 决定截断顺序。

提示

默认使用 tiktoken 统计 token。想自定义,可以把 tokenizer_fn 参数设成一个可调用的对象:给它一个字符串,它返回一个列表,列表长度就作为 token 数。

一旦记忆积累了足够的信息,我们可能会看到类似这样的内容:

# optionally pass in a list of messages to get, which will be forwarded to the memory blocks
chat_history = memory.get(messages=[...])

print(chat_history[0].content)

打印出来大致是这样:

<memory>
<static_memory>
My name is Logan, and I live in Saskatoon. I work at LlamaIndex.
</static_memory>
<fact_extraction_memory>
<fact>Fact 1</fact>
<fact>Fact 2</fact>
<fact>Fact 3</fact>
</fact_extraction_memory>
<retrieval_based_memory>
<message role='user'>Msg 1</message>
<message role='assistant'>Msg 2</message>
<message role='user'>Msg 3</message>
</retrieval_based_memory>
</memory>

这里,记忆被插入到系统消息中,并为每个记忆块留出专门的小节。

自定义记忆块

除了预置的记忆块,你也可以创建自己的记忆块。

from typing import Optional, List, Any
from llama_index.core.llms import ChatMessage
from llama_index.core.memory.memory import BaseMemoryBlock

# use generics to define the output type of the memory block
# can be str or List[ContentBlock]
class MentionCounter(BaseMemoryBlock[str]):
    """
    A memory block that counts the number of times a user mentions a specific name.
    """

    mention_name: str = "Logan"
    mention_count: int = 0

    async def _aget(
        self, messages: Optional[List[ChatMessage]] = None, **block_kwargs: Any
    ) -> str:
        return f"Logan was mentioned {self.mention_count} times."

    async def _aput(self, messages: List[ChatMessage]) -> None:
        for message in messages:
            if self.mention_name in message.content:
                self.mention_count += 1

    async def atruncate(
        self, content: str, tokens_to_truncate: int
    ) -> Optional[str]:
        return ""

这里我们定义了一个记忆块,用来统计用户提到某个特定名字的次数。

它的 truncate 方法很简单,直接返回一个空字符串。

远端记忆

默认情况下,Memory 类使用一个内存版 SQLite 数据库。只要改动数据库 URI,你就能接入任意远端数据库。

你可以自定义表名,还可以选择直接传入一个异步引擎。这对自行管理连接池很有用。

from llama_index.core.memory import Memory

memory = Memory.from_defaults(
    session_id="my_session",
    token_limit=40000,
    async_database_uri="postgresql+asyncpg://postgres:mark90@localhost:5432/postgres",
    # Optional: specify a table name
    # table_name="memory_table",
    # Optional: pass in an async engine directly
    # this is useful for managing your own connection pool
    # async_engine=engine,
)

自定义聊天存储

如果 SQLAlchemy 不适合你的基础设施,可以实现 AsyncDBChatStore 接口并作为 chat_store 传入。给定 chat_store 时,那些 SQL 专用参数(table_name、async_database_uri、async_engine、db_schema)会被忽略。

from llama_index.core.memory import Memory
from llama_index.core.storage.chat_store.base_db import (
    AsyncDBChatStore,
    MessageStatus,
)

class MyChatStore(AsyncDBChatStore):
    # implement get_messages, add_message(s), set_messages,
    # delete_message(s), delete_oldest_messages,
    # archive_oldest_messages, count_messages and get_keys
    ...

memory = Memory.from_defaults(
    session_id="my_session",
    token_limit=40000,
    chat_store=MyChatStore(),
)

记忆与工作流上下文

读到这里,你可能已经遇到过这样的场景:在使用 Workflow 时,需要序列化一个 Context 对象来保存并恢复某个工作流状态。工作流的 Context 是个复杂的对象,既保存工作流的运行时信息,也保存跨工作流步骤共享的键值对。

相比之下,Memory 对象简单得多,只保存 ChatMessage 对象,以及可选的一组用于长期记忆的 MemoryBlock 对象。

多数实际场景里你会两者都用。如果你不定制记忆,那么只序列化 Context 对象就够了。

from llama_index.core.workflow import Context

ctx = Context(workflow)

# serialize the context
ctx_dict = ctx.to_dict()

# deserialize the context
ctx = Context.from_dict(workflow, ctx_dict)

而在其他场景,比如使用 FunctionAgent、AgentWorkflow 或 ReActAgent 并定制了记忆时,你就需要把它作为单独的运行参数传进去(尤其是超出默认配置之后,Memory 对象是不可序列化的)。

response = await agent.run("Hello!", memory=memory)

最后,还有一些情形(比如人在环路)需要你同时提供 Context(用于恢复工作流)与 Memory(用于存储聊天历史)。

response = await agent.run("Hello!", ctx=ctx, memory=memory)

(已弃用)记忆类型

在 llama_index.core.memory 里,我们提供几种不同的记忆类型:

  • ChatMemoryBuffer:基础记忆缓冲区,保存能塞进 token 限制的最近 X 条消息。
  • ChatSummaryMemoryBuffer:记忆缓冲区,保存能塞进 token 限制的最近 X 条消息,并在对话过长时周期性地对其做摘要。
  • VectorMemory:把聊天消息存入向量库并从中取回。它不保证消息顺序,返回的是与最新用户消息最相似的那些消息。
  • SimpleComposableMemory:把多个记忆组合在一起的记忆。通常用于把 VectorMemory 与 ChatMemoryBuffer 或 ChatSummaryMemoryBuffer 组合使用。

示例

下面可以看到几个记忆实际使用的例子:

**注意:**以下为已弃用的示例:

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。