Memory 让你的 agent 可以跨 conversations 学习和改进。Deep Agents 通过 filesystem-backed memory 将 memory 作为 first-class capability:agent 以 files 的形式 read 和 write memory,你使用 backends 控制这些 files 存储在哪里。
本页介绍 long-term memory :跨 conversations 持久化的 memory。Short-term memory(单个 session 内的 conversation history 和 scratch files)请参阅 context engineering guide。Short-term memory 会作为 agent state 的一部分自动管理。
How memory works
将 agent 指向 memory files。 创建 agent 时将 file paths 传给 memory=。你也可以通过 skills= 传入 skills ,用于 procedural memory(告诉 agent 如何 执行 task 的 reusable instructions)。backend 控制 files 存储在哪里,以及谁可以访问。
Agent 读取 memory。 Agent 可以在 startup 时将 memory files 加载到 system prompt 中,也可以在 conversation 期间按需读取它们。例如,skills 使用 on-demand loading:agent 在 startup 时只读取 skill descriptions,然后只在 skill 匹配 task 时读取 full skill file。这样在 capability 被需要前,context 会保持精简。
Agent 更新 memory(可选)。 当 agent 学到新 information 时,它可以使用内置 edit_file tool 更新 memory files。Updates 可以在 conversation 期间发生(默认),也可以通过 background consolidation 在 conversations 之间后台发生。Changes 会被 persisted,并在下一次 conversation 中可用。并非所有 memory 都是 writable:developer-defined skills 和 organization policies 通常是 read-only。详情请参阅 read-only vs writable memory 。
最常见的两种 patterns 是 agent-scoped memory (所有 users 共享)和 user-scoped memory (按 user 隔离)。
Scoped memory
Agent memory 可以 scoped,使同一组 memory files 对所有使用 agent 的人可访问,也可以让每个 user 拥有各自的 memory files。
Agent-scoped memory
为 agent 提供随时间演化的 persistent identity。Agent-scoped memory 在所有 users 之间共享,因此 agent 会通过每次 conversation 积累自己的 persona、knowledge 和 learned preferences。随着它与 users 交互,它会发展 expertise、refine approach,并记住哪些做法有效。如果它拥有 write access,也可以学习并更新 skills 。
关键是 backend namespace:将其设置为 (assistant_id,) 意味着该 agent 的每个 conversation 都会 read 和 write 同一个 memory file。
访问 rt.serverInfo 需要 deepagents>=1.9.0。在更旧版本中,请改为从 getConfig().metadata.assistantId 读取 assistant ID。
import { createDeepAgent , CompositeBackend , StateBackend , StoreBackend } from "deepagents" ;
const agent = createDeepAgent ( {
memory : [ "/memories/AGENTS.md" ] ,
skills : [ "/skills/" ] ,
backend : new CompositeBackend (
new StateBackend () ,
{
"/memories/" : new StoreBackend ( {
namespace : ( rt ) => [rt . serverInfo . assistantId] ,
} ) ,
"/skills/" : new StoreBackend ( {
namespace : ( rt ) => [rt . serverInfo . assistantId] ,
} ) ,
},
) ,
} ) ;
Full example: seed memory and invoke
用 initial memories 填充 store,然后跨两个 threads invoke agent,观察它如何记住并更新学到的内容。 import { createDeepAgent , CompositeBackend , StateBackend , StoreBackend , createFileData } from "deepagents" ;
import { InMemoryStore } from "@langchain/langgraph" ;
const store = new InMemoryStore () ; // Use platform store when deploying to LangSmith
// Seed the memory file
await store . put (
[ "my-agent" ] ,
"/memories/AGENTS.md" ,
createFileData ( `## Response style
- Keep responses concise
- Use code examples where possible
` ) ,
) ;
// Seed a skill
await store . put (
[ "my-agent" ] ,
"/skills/langgraph-docs/SKILL.md" ,
createFileData ( `---
name: langgraph-docs
description: Fetch relevant LangGraph documentation to provide accurate guidance.
---
# langgraph-docs
Use the fetch_url tool to read https://docs.langchain.com/llms.txt, then fetch relevant pages.
` ) ,
) ;
const agent = createDeepAgent ( {
memory : [ "/memories/AGENTS.md" ] ,
skills : [ "/skills/" ] ,
backend : ( rt ) => new CompositeBackend (
new StateBackend (rt) ,
{
"/memories/" : new StoreBackend (rt , {
namespace : ( rt ) => [ "my-agent" ] ,
} ) ,
"/skills/" : new StoreBackend (rt , {
namespace : ( rt ) => [ "my-agent" ] ,
} ) ,
},
) ,
store ,
} ) ;
// Thread 1: the agent learns a new preference and saves it to memory
const config1 = { configurable : { thread_id : crypto . randomUUID () } };
await agent . invoke ( {
messages : [ { role : "user" , content : "I prefer detailed explanations. Remember that." } ] ,
}, config1) ;
// Thread 2: the agent reads memory and applies the preference
const config2 = { configurable : { thread_id : crypto . randomUUID () } };
await agent . invoke ( {
messages : [ { role : "user" , content : "Explain how transformers work." } ] ,
}, config2) ;
User-scoped memory
为每个 user 提供自己的 memory file。Agent 会按 user 记住 preferences、context 和 history,同时 core agent instructions 保持固定。如果 skills 存储在 user-scoped backend 中,users 也可以拥有 per-user skills 。
Namespace 使用 (user_id,),因此每个 user 都获得 isolated copy 的 memory file。User A 的 preferences 永远不会泄漏到 User B 的 conversations。
import { createDeepAgent , CompositeBackend , StateBackend , StoreBackend } from "deepagents" ;
const agent = createDeepAgent ( {
memory : [ "/memories/preferences.md" ] ,
skills : [ "/skills/" ] ,
backend : new CompositeBackend (
new StateBackend () ,
{
"/memories/" : new StoreBackend ( {
namespace : ( rt ) => [rt . serverInfo . user . identity] ,
} ) ,
"/skills/" : new StoreBackend ( {
namespace : ( rt ) => [rt . serverInfo . user . identity] ,
} ) ,
},
) ,
} ) ;
Full example: isolated memory across users
Seed per-user memories,并以两个不同 users 身份 invoke agent。每个 user 只会看到自己的 preferences。 import { createDeepAgent , CompositeBackend , StateBackend , StoreBackend , createFileData } from "deepagents" ;
import { InMemoryStore } from "@langchain/langgraph" ;
const store = new InMemoryStore () ; // Use platform store when deploying to LangSmith
// Seed preferences for two users
await store . put (
[ "user-alice" ] ,
"/memories/preferences.md" ,
createFileData ( `## Preferences
- Likes concise bullet points
- Prefers Python examples
` ) ,
) ;
await store . put (
[ "user-bob" ] ,
"/memories/preferences.md" ,
createFileData ( `## Preferences
- Likes detailed explanations
- Prefers TypeScript examples
` ) ,
) ;
// Seed a skill for Alice
await store . put (
[ "user-alice" ] ,
"/skills/langgraph-docs/SKILL.md" ,
createFileData ( `---
name: langgraph-docs
description: Fetch relevant LangGraph documentation to provide accurate guidance.
---
# langgraph-docs
Use the fetch_url tool to read https://docs.langchain.com/llms.txt, then fetch relevant pages.
` ) ,
) ;
const agent = createDeepAgent ( {
memory : [ "/memories/preferences.md" ] ,
skills : [ "/skills/" ] ,
backend : ( rt ) => new CompositeBackend (
new StateBackend (rt) ,
{
"/memories/" : new StoreBackend (rt , {
namespace : ( rt ) => [rt . serverInfo . user . identity] ,
} ) ,
"/skills/" : new StoreBackend (rt , {
namespace : ( rt ) => [rt . serverInfo . user . identity] ,
} ) ,
},
) ,
store ,
} ) ;
// When deployed, each authenticated request resolves
// `rt.serverInfo.user.identity` to the calling user, so Alice and Bob
// automatically see only their own preferences.
await agent . invoke (
{ messages : [ { role : "user" , content : "How do I read a CSV file?" } ] },
{ configurable : { thread_id : crypto . randomUUID () } },
) ;
Advanced usage
在 memory paths 和 scope 的 basic configuration options 之上,你还可以为 memory 配置更高级的 parameters:
Dimension Question it answers Options Duration 它持续多久? Short-term (single conversation)或 long-term (across conversations)Information type 它是什么类型的信息? Episodic (past experiences)、procedural (instructions 和 skills)或 semantic (facts)Scope 谁可以 see 和 modify 它? User 、agent 或 organization Update strategy Memories 何时写入? Conversation 期间(默认)或 between conversations Retrieval Memories 如何读取? 加载到 prompt(默认)或 on demand(例如 skills ) Agent permissions Agent 是否可以 write memory? Read-write (默认)或 read-only (用于 shared policies)
Episodic memory
Episodic memory 存储 past experiences 的 records:发生了什么、顺序如何,以及结果是什么。不同于 semantic memory(存储在 AGENTS.md 等 files 中的 facts 和 preferences),episodic memory 会保留完整 conversational context,因此 agent 可以回忆问题是 如何 解决的,而不仅是从中学到了 什么 。
Deep Agents 已经使用 checkpointers ,这是支持 episodic memory 的机制:每个 conversation 都会作为 checkpointed thread 持久化。
若要让 past conversations 可搜索,请将 thread search 包装成 tool。user_id 从 runtime context 拉取,而不是作为 parameter 传入:
import { Client } from "@langchain/langgraph-sdk" ;
import { tool } from "@langchain/core/tools" ;
const client = new Client ( { apiUrl : "<DEPLOYMENT_URL>" } ) ;
const searchPastConversations = tool (
async ({ query }, runtime ) => {
const userId = runtime . serverInfo . user . identity ;
const threads = await client . threads . search ( {
metadata : { userId },
limit : 5 ,
} ) ;
const results = [] ;
for ( const thread of threads) {
const history = await client . threads . getHistory (thread . threadId) ;
results . push (history) ;
}
return JSON . stringify (results) ;
},
{
name : "search_past_conversations" ,
description : "Search past conversations for relevant context." ,
}
) ;
你可以通过调整 metadata filter,按 user 或 organization scope thread search:
// Search conversations for a specific user
const userThreads = await client . threads . search ( {
metadata : { userId },
limit : 5 ,
} ) ;
// Search conversations across an organization
const orgThreads = await client . threads . search ( {
metadata : { orgId },
limit : 5 ,
} ) ;
这对执行 complex multi-step tasks 的 agents 很有用。例如,coding agent 可以回看 past debugging session,并直接跳到可能的 root cause。
Organization-level memory
Organization-level memory 与 user-scoped memory 遵循相同 pattern,但使用 organization-wide namespace,而不是 per-user namespace。将其用于应适用于 organization 内所有 users 和 agents 的 policies 或 knowledge。
Organization memory 通常是 read-only ,以防通过 shared state 发生 prompt injection。详情请参阅 read-only vs writable memory 。
import { createDeepAgent , CompositeBackend , StateBackend , StoreBackend } from "deepagents" ;
const agent = createDeepAgent ( {
memory : [
"/memories/preferences.md" ,
"/policies/compliance.md" ,
] ,
backend : new CompositeBackend (
new StateBackend () ,
{
"/memories/" : new StoreBackend ( {
namespace : ( rt ) => [rt . serverInfo . user . identity] ,
} ) ,
"/policies/" : new StoreBackend ( {
namespace : ( rt ) => [rt . context . orgId] ,
} ) ,
},
) ,
} ) ;
从 application code 填充 organization memory:
import { Client } from "@langchain/langgraph-sdk" ;
import { createFileData } from "deepagents" ;
const client = new Client ( { apiUrl : "<DEPLOYMENT_URL>" } ) ;
await client . store . putItem (
[orgId] ,
"/compliance.md" ,
createFileData ( `## Compliance policies
- Never disclose internal pricing
- Always include disclaimers on financial advice
` ) ,
) ;
使用 permissions enforce org-level memory 为 read-only,或使用 policy hooks 实现 custom validation logic。
Background consolidation
默认情况下,agent 会在 conversation 期间写入 memories(hot path)。另一种方式是将 memories 作为 background task 在 between conversations 处理,有时称为 sleep time compute 。一个单独的 deep agent 会 review recent conversations、extract key facts,并将其与 existing memories 合并。
Approach Pros Cons Hot path (conversation 期间)Memories 立即可用,对 user 透明 增加 latency,agent 必须 multitask Background (between conversations)无 user-facing latency,可以跨多个 conversations synthesize Memories 要到下一次 conversation 才可用,需要 second agent
对于大多数 applications,hot path 已足够。当你需要减少 latency 或提升跨许多 conversations 的 memory quality 时,再添加 background consolidation。
推荐 pattern 是在 main agent 旁部署一个 consolidation agent ,即一个读取 recent conversation history、extract key facts,并 merge 到 memory store 的 deep agent,然后按 cron schedule 触发它。请选择反映 users 实际交互频率的 cadence:日常稳定使用的 chat product 可以每几个小时 consolidate 一次,而每周只用几次的 tool 只需要 nightly 或 weekly 运行。比 users conversation 频率高很多的 consolidation 只会在 no-op runs 上消耗 tokens。
Consolidation agent
Consolidation agent 读取 recent conversation history,并将 key facts 合并进 memory store。在 langgraph.json 中将其与 main agent 一起注册:
src/consolidation-agent.ts
import { createDeepAgent } from "deepagents" ;
import { Client } from "@langchain/langgraph-sdk" ;
import { tool } from "@langchain/core/tools" ;
const sdkClient = new Client ( { apiUrl : "<DEPLOYMENT_URL>" } ) ;
const searchRecentConversations = tool (
async ({ query }, runtime ) => {
const userId = runtime . serverInfo . user . identity ;
const since = new Date (Date . now () - 6 * 60 * 60 * 1000 ) . toISOString () ;
const threads = await sdkClient . threads . search ( {
metadata : { userId },
updatedAfter : since ,
limit : 20 ,
} ) ;
const conversations = [] ;
for ( const thread of threads) {
const history = await sdkClient . threads . getHistory (thread . threadId) ;
conversations . push (history . values . messages) ;
}
return JSON . stringify (conversations) ;
},
{
name : "search_recent_conversations" ,
description : "Search this user's conversations updated in the last 6 hours." ,
}
) ;
const agent = createDeepAgent ( {
model : "google_genai:gemini-3.5-flash" ,
systemPrompt : `Review recent conversations and update the user's memory file.
Merge new facts, remove outdated information, and keep it concise.` ,
tools : [searchRecentConversations] ,
} ) ;
export { agent };
{
" dependencies " : [ "." ],
" graphs " : {
" agent " : "./src/agent.ts:agent" ,
" consolidation_agent " : "./src/consolidation-agent.ts:agent"
},
" env " : ".env"
}
Cron
cron job 会按固定 schedule 运行 consolidation agent。Agent 会搜索 recent conversations,并将其 synthesize 到 memory 中。请将 schedule 与你的 usage patterns 匹配,让 consolidation 大致跟随真实 activity。
使用 cron job schedule consolidation agent:
import { Client } from "@langchain/langgraph-sdk" ;
const client = new Client ( { apiUrl : "<DEPLOYMENT_URL>" } ) ;
const cronJob = await client . crons . create (
"consolidation_agent" ,
{
schedule : "0 */6 * * *" ,
input : { messages : [ { role : "user" , content : "Consolidate recent memories." } ] },
},
) ;
所有 cron schedules 都按 UTC 解释。管理和删除 cron jobs 的 details 请参阅 cron jobs 。
Cron interval 必须匹配 consolidation agent 内的 lookback window。上方 example 每 6 小时运行一次(0 */6 * * *),agent 的 search_recent_conversations tool 会回看 timedelta(hours=6),请保持二者同步。如果 cron 运行频率高于 lookback,你会重复处理相同 conversations;如果运行频率低于 lookback,你会丢掉 window 外的 memories。
有关使用 background processes 部署 agents 的更多信息,请参阅 going to production 。
Read-only vs writable memory
默认情况下,agent 可以 read 和 write memory files。对于 organization policies 或 compliance rules 等 shared state,你可能希望将 memory 设为 read-only ,让 agent 可以 reference 它,但不能 modify 它。这可以防止 shared memory 中的 prompt injection,并确保只有你的 application code 控制 file 内容。
Permission Use case How it works Read-write (默认)User preferences、agent self-improvement、learned skills Agent 通过 edit_file tool 更新 files Read-only Organization policies、compliance rules、shared knowledge bases、developer-defined skills 通过 application code 或 Store API 填充。使用 permissions deny writes to specific paths,或使用 policy hooks 实现 custom validation logic。
Security considerations: 如果一个 user 可以写入另一个 user 会读取的 memory,malicious user 可能会将 instructions 注入 shared state。为缓解这一点:
默认使用 user scope (user_id),除非你有具体理由共享
对 shared policies 使用 read-only memory (通过 application code 填充,而不是 agent)
在 agent 写入 shared memory 前添加 human-in-the-loop validation。使用 interrupt 要求 human approval 后再写入 sensitive paths。
若要 enforce read-only memory,请使用 permissions declaratively deny writes to specific paths。对于 custom validation logic(rate limiting、audit logging、content inspection),请使用 backend policy hooks 。
Concurrent writes
多个 threads 可以并行写入 memory,但并发写入 同一个 file 可能导致 last-write-wins conflicts。对于 user-scoped memory,这通常很少见,因为 users 通常一次只有一个 active conversation。对于 agent-scoped 或 organization-scoped memory,请考虑使用 background consolidation serialize writes,或将 memory 组织为按 topic 分离的 files,以减少 contention。
实践中,如果 write 因 conflict 失败,LLM 通常足够智能,可以 retry 或 graceful recover,因此单个 lost write 通常不是灾难性问题。
Multiple agents in the same deployment
若要在 shared deployment 中为每个 agent 提供自己的 memory,请将 assistant_id 添加到 namespace:
new StoreBackend ( {
namespace : ( rt ) => [
rt . serverInfo . assistantId ,
rt . serverInfo . user . identity ,
] ,
} )
如果你只需要 per-agent isolation,而不需要 per-user scoping,请只使用 assistant_id。
使用 LangSmith tracing audit agent 写入 memory 的内容。每次 file write 都会在 trace 中显示为 tool call。