记忆让您的代理能够在对话中学习和改进。Deep Agents 以文件系统支持的记忆作为一流功能:代理将记忆作为文件读写,您使用后端控制这些文件的存储位置。
本页面涵盖长期记忆:跨对话持久化的记忆。关于短期记忆(单次会话内的对话历史和草稿文件),请参阅上下文工程指南。短期记忆作为代理状态的一部分自动管理。

记忆如何工作

  1. 将代理指向记忆文件。 创建代理时将文件路径传递给 memory=。您还可以通过 skills= 传递技能,以获取程序化记忆(可重用的指令,告诉代理如何执行任务)。后端控制文件存储位置和访问权限。
  2. 代理读取记忆。 代理可以在启动时将记忆文件加载到系统提示中,或在对话期间按需读取。例如,技能使用按需加载:代理在启动时只读取技能描述,然后在匹配任务时才读取完整的技能文件。这在需要能力之前保持上下文精简。
  3. 代理更新记忆(可选)。 当代理学习到新信息时,它可以使用内置的 edit_file 工具更新记忆文件。更新可以在对话期间发生(默认),也可以通过后台整合在对话之间后台进行。更改被持久化并在下次对话中可用。并非所有记忆都是可写的:开发者定义的技能组织策略通常是只读的。请参阅只读与可写记忆了解更多详情。
两种最常见的模式是代理范围记忆(所有用户共享)和用户范围记忆(每个用户独立)。

范围记忆

代理记忆可以设置范围,以便所有使用代理的人可以访问相同的记忆文件,或者记忆文件可以是每个用户独立的。

代理范围记忆

赋予代理一个随时间演变的持久化身份。代理范围记忆在所有用户之间共享,因此代理通过每次对话建立自己的角色、积累的知识和学习到的偏好。当它与用户交互时,它会发展专业知识、完善方法并记住有效的内容。如果有写权限,它还可以学习和更新技能 关键是后端命名空间:将其设置为 (assistant_id,) 意味着此代理的每次对话都读取和写入相同的记忆文件。
访问 rt.server_info 需要 deepagents>=0.5.0。在较旧版本中,改为从 get_config()["metadata"]["assistant_id"] 读取助手 ID。
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend

agent = create_deep_agent(
    memory=["/memories/AGENTS.md"],
    skills=["/skills/"],
    backend=CompositeBackend(
        default=StateBackend(),
        routes={
            "/memories/": StoreBackend(
                namespace=lambda rt: (
                    rt.server_info.assistant_id,
                ),
            ),
            "/skills/": StoreBackend(
                namespace=lambda rt: (
                    rt.server_info.assistant_id,
                ),
            ),
        },
    ),
)
用初始记忆填充存储,然后在两个线程中调用代理,以查看它记住并更新所学的内容。
from langchain_core.utils.uuid import uuid7

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from deepagents.backends.utils import create_file_data
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()  # 部署到 LangSmith 时使用平台存储

# 预填充记忆文件
store.put(
    ("my-agent",),
    "/memories/AGENTS.md",
    create_file_data("""## 回复风格
- 保持回复简洁
- 尽可能使用代码示例
"""),
)

# 预填充技能
store.put(
    ("my-agent",),
    "/skills/langgraph-docs/SKILL.md",
    create_file_data("""---
name: langgraph-docs
description: 获取相关的 LangGraph 文档以提供准确的指导。
---

# langgraph-docs

使用 fetch_url 工具读取 https://docs.langchain.com/llms.txt,然后获取相关页面。
"""),
)

agent = create_deep_agent(
    memory=["/memories/AGENTS.md"],
    skills=["/skills/"],
    backend=lambda rt: CompositeBackend(
        default=StateBackend(rt),
        routes={
            "/memories/": StoreBackend(
                rt, namespace=lambda rt: ("my-agent",)
            ),
            "/skills/": StoreBackend(
                rt, namespace=lambda rt: ("my-agent",)
            ),
        },
    ),
    store=store,
)

# 线程 1:代理学习新的偏好并将其保存到记忆
config1 = {"configurable": {"thread_id": str(uuid7())}}
agent.invoke(
    {"messages": [{"role": "user", "content": "我更喜欢详细的解释。请记住这一点。"}]},
    config=config1,
)

# 线程 2:代理读取记忆并应用偏好
config2 = {"configurable": {"thread_id": str(uuid7())}}
agent.invoke(
    {"messages": [{"role": "user", "content": "解释 transformer 是如何工作的。"}]},
    config=config2,
)

用户范围记忆

为每个用户提供自己的记忆文件。代理记住每个用户的偏好、上下文和历史,而核心代理指令保持不变。如果将技能存储在用户范围的后端中,用户也可以拥有每个用户的技能 命名空间使用 (user_id,),因此每个用户获得记忆文件的独立副本。用户 A 的偏好永远不会泄漏到用户 B 的对话中。
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend

agent = create_deep_agent(
    memory=["/memories/preferences.md"],
    skills=["/skills/"],
    backend=CompositeBackend(
        default=StateBackend(),
        routes={
            "/memories/": StoreBackend(
                namespace=lambda rt: (rt.server_info.user.identity,),
            ),
            "/skills/": StoreBackend(
                namespace=lambda rt: (rt.server_info.user.identity,),
            ),
        },
    ),
)
为每个用户预填充记忆,作为两个不同用户调用代理。每个用户只看到自己的偏好。
from langchain_core.utils.uuid import uuid7

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from deepagents.backends.utils import create_file_data
from langgraph.store.memory import InMemoryStore


store = InMemoryStore()  # 部署到 LangSmith 时使用平台存储

# 为两个用户预填充偏好
store.put(
    ("user-alice",),
    "/memories/preferences.md",
    create_file_data("""## 偏好
- 喜欢简洁的要点列表
- 偏好 Python 示例
"""),
)
store.put(
    ("user-bob",),
    "/memories/preferences.md",
    create_file_data("""## 偏好
- 喜欢详细解释
- 偏好 TypeScript 示例
"""),
)

# 为 Alice 预填充技能
store.put(
    ("user-alice",),
    "/skills/langgraph-docs/SKILL.md",
    create_file_data("""---
name: langgraph-docs
description: 获取相关的 LangGraph 文档以提供准确的指导。
---

# langgraph-docs

使用 fetch_url 工具读取 https://docs.langchain.com/llms.txt,然后获取相关页面。
"""),
)

agent = create_deep_agent(
    memory=["/memories/preferences.md"],
    skills=["/skills/"],
    backend=lambda rt: CompositeBackend(
        default=StateBackend(rt),
        routes={
            "/memories/": StoreBackend(
                rt,
                namespace=lambda rt: (rt.server_info.user.identity,),
            ),
            "/skills/": StoreBackend(
                rt,
                namespace=lambda rt: (rt.server_info.user.identity,),
            ),
        },
    ),
    store=store,
)

# 部署后,每个经过身份验证的请求都会将
# `rt.server_info.user.identity` 解析为调用用户,因此 Alice 和 Bob
# 自动只看到自己的偏好。
agent.invoke(
    {"messages": [{"role": "user", "content": "如何读取 CSV 文件?"}]},
    config={"configurable": {"thread_id": str(uuid7())}},
)

高级用法

除了记忆路径和范围的基本配置选项外,您还可以为记忆配置更高级的参数:
维度它回答的问题选项
持续时间它持续多久?短期(单次对话)或长期(跨对话)
信息类型它是什么类型的信息?情景记忆(过去的经历)、程序性(指令和技能)或语义(事实)
范围谁可以查看和修改它?用户代理组织
更新策略何时写入记忆?在对话期间(默认)或对话之间
检索如何读取记忆?加载到提示中(默认)或按需(例如技能
代理权限代理可以写入记忆吗?可读写(默认)或只读(用于共享策略)

情景记忆

情景记忆存储过去经历的记录:发生了什么、按什么顺序、以及结果如何。与存储在 AGENTS.md 等文件中的语义记忆(事实和偏好)不同,情景记忆保留完整的对话上下文,以便代理能够回忆问题如何被解决的,而不仅仅是中学到了什么。 Deep Agents 已经使用检查点,这是支持情景记忆的机制:每次对话都作为检查点的线程持久化。 要使过去的对话可搜索,请在工具中包装线程搜索。user_id 从运行时上下文拉取,而不是作为参数传递:
from langgraph_sdk import get_client
from langchain.tools import tool, ToolRuntime

client = get_client(url="<部署URL>")


@tool
async def search_past_conversations(query: str, runtime: ToolRuntime) -> str:
    """搜索过去的对话以获取相关上下文。"""
    user_id = runtime.server_info.user.identity  
    threads = await client.threads.search(
        metadata={"user_id": user_id},
        limit=5,
    )
    results = []
    for thread in threads:
        history = await client.threads.get_history(thread_id=thread["thread_id"])
        results.append(history)
    return str(results)
您可以通过调整元数据过滤器来按用户或组织范围进行线程搜索:
# 搜索特定用户的对话
threads = await client.threads.search(
    metadata={"user_id": user_id},
    limit=5,
)

# 跨组织搜索对话
threads = await client.threads.search(
    metadata={"org_id": org_id},
    limit=5,
)
这对于执行复杂多步骤任务的代理很有用。例如,编码代理可以回顾过去的调试会话,直接跳到可能的根本原因。

组织级记忆

组织级记忆遵循与用户范围记忆相同的模式,但使用组织范围的命名空间而不是每个用户一个。将其用于应在组织内所有用户和代理之间应用的策略或知识。 组织记忆通常对代理是只读的,以防止通过共享状态进行提示注入。请参阅只读与可写记忆了解更多详情。
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend

agent = create_deep_agent(
    memory=[
        "/memories/preferences.md",
        "/policies/compliance.md",
    ],
    backend=CompositeBackend(
        default=StateBackend(),
        routes={
            "/memories/": StoreBackend(
                namespace=lambda rt: (rt.server_info.user.identity,),
            ),
            "/policies/": StoreBackend(
                namespace=lambda rt: (rt.context.org_id,),
            ),
        },
    ),
)
从应用程序代码填充组织记忆:
from langgraph_sdk import get_client
from deepagents.backends.utils import create_file_data

client = get_client(url="<部署URL>")

await client.store.put_item(
    (org_id,),
    "/compliance.md",
    create_file_data("""## 合规策略
- 永远不要披露内部定价
- 在财务建议时始终包含免责声明
"""),
)
使用权限强制组织级记忆为只读,或使用策略钩子进行自定义验证逻辑。

后台整合

默认情况下,代理在对话期间写入记忆(热路径)。另一种方法是将记忆在对话之间作为后台任务处理,有时称为睡眠时间计算。一个单独的深层代理审查最近的对话,提取关键事实,并将它们与现有记忆合并。
方法优点缺点
热路径(对话期间)记忆立即可用,对用户透明增加延迟,代理必须多任务处理
后台(对话之间)没有面向用户的延迟,可以跨多个对话综合记忆在下次对话之前不可用,需要第二个代理
对于大多数应用程序,热路径就足够了。当您需要减少延迟或跨多个对话提高记忆质量时,添加后台整合。 推荐模式是在您的代理旁边部署一个整合代理——一个读取最近对话历史、提取关键事实并将其合并到记忆存储中的深层代理——并按定时计划触发它。选择反映用户实际与代理交互频率的时间间隔:每天有稳定流量的聊天产品可能每几小时整合一次,而每周只使用几次的工具只需要在夜间或每周运行一次。整合频率远高于用户对话频率只是在无操作运行时浪费令牌。

整合代理

整合代理读取最近的对话历史并将关键事实合并到记忆存储中。在 langgraph.json 中与您的代理一起注册它:
consolidation_agent.py
from datetime import datetime, timedelta, timezone

from deepagents import create_deep_agent
from langchain.tools import tool, ToolRuntime
from langgraph_sdk import get_client

sdk_client = get_client(url="<部署URL>")


@tool
async def search_recent_conversations(query: str, runtime: ToolRuntime) -> str:
    """搜索此用户在过去 6 小时内更新的对话。"""
    user_id = runtime.server_info.user.identity  

    since = datetime.now(timezone.utc) - timedelta(hours=6)
    threads = await sdk_client.threads.search(
        metadata={"user_id": user_id},
        updated_after=since.isoformat(),
        limit=20,
    )
    conversations = []
    for thread in threads:
        history = await sdk_client.threads.get_history(
            thread_id=thread["thread_id"]
        )
        conversations.append(history["values"]["messages"])
    return str(conversations)


agent = create_deep_agent(
    model="claude-sonnet-4-6",
    system_prompt="""审查最近的对话并更新用户的记忆文件。
合并新事实、删除过时信息并保持简洁。""",
    tools=[search_recent_conversations],
)
langgraph.json
{
  "dependencies": ["."],
  "graphs": {
    "agent": "./agent.py:agent",
    "consolidation_agent": "./consolidation_agent.py:agent"
  },
  "env": ".env"
}

定时任务

定时任务按固定计划运行整合代理。代理搜索最近的对话并将其综合成记忆。将计划与您的使用模式匹配,使整合运行大致跟踪实际活动。 使用定时任务调度整合代理:
from langgraph_sdk import get_client

client = get_client(url="<部署URL>")

cron_job = await client.crons.create(
    assistant_id="consolidation_agent",
    schedule="0 */6 * * *",
    input={"messages": [{"role": "user", "content": "整合最近的记忆。"}]},
)
所有定时计划都在UTC中解释。请参阅定时任务了解管理和删除定时任务的详情。
定时间隔必须与整合代理内的回溯窗口匹配。上面的示例每 6 小时运行一次(0 */6 * * *),代理的 search_recent_conversations 工具回溯 timedelta(hours=6)——保持同步。如果定时运行比回溯更频繁,您将重新处理相同的对话;如果运行不那么频繁,您将丢失超出窗口的记忆。
有关部署带有后台进程的代理的更多信息,请参阅投入生产

只读与可写记忆

默认情况下,代理可以读取和写入记忆文件。对于共享状态(如组织策略或合规规则),您可能希望将记忆设为只读,以便代理可以引用它但不能修改它。这可以防止通过共享记忆进行提示注入,并确保只有您的应用程序代码控制文件中的内容。
权限用例工作原理
可读写(默认)用户偏好、代理自我改进、学习的技能代理通过 edit_file 工具更新文件
只读组织策略、合规规则、共享知识库、开发者定义的技能通过应用程序代码或 Store API 填充。使用权限拒绝写入特定路径,或使用策略钩子进行自定义验证逻辑。
**安全考虑:**如果一个用户可以写入另一个用户读取的记忆,恶意的用户可以将指令注入到共享状态中。要缓解此问题:
  • 默认为用户范围 (user_id),除非您有特定原因需要共享
  • 对共享策略使用只读记忆(通过应用程序代码填充,而不是代理)
  • 在代理写入共享记忆之前添加人工介入验证。使用中断来要求对敏感路径的写入进行人工批准。
要强制只读记忆,请使用权限声明性地拒绝写入特定路径。对于自定义验证逻辑(速率限制、审计日志、内容检查),请使用后端策略钩子

并发写入

多个线程可以并行写入记忆,但对同一文件的并发写入可能导致最后写入胜出的冲突。对于用户范围记忆,这很少见,因为用户通常一次只有一个活动对话。对于代理范围或组织范围记忆,请考虑使用后台整合来序列化写入,或将记忆构建为每个主题的单独文件以减少争用。 在实践中,如果写入因冲突而失败,LLM 通常足够智能来重试或优雅地恢复,因此丢失一次写入不是灾难性的。

同一部署中的多个代理

要在共享部署中为每个代理提供自己的记忆,请将 assistant_id 添加到命名空间:
StoreBackend(
    namespace=lambda rt: (
        rt.server_info.assistant_id,
        rt.server_info.user.identity,
    ),
)
如果只需要按代理隔离而不需要按用户范围,请单独使用 assistant_id
使用 LangSmith 追踪来审计代理写入记忆的内容。每次文件写入都会作为工具调用出现在追踪中。