文档索引 在以下地址获取完整的文档索引:https://docs.langchain.org.cn/llms.txt
在进一步探索之前,请使用此文件发现所有可用页面。
记忆功能让你的代理能够在跨对话过程中进行学习和改进。Deep Agents 通过文件系统支持的记忆,将记忆提升为一等公民:代理将记忆作为文件进行读写,你可以通过 后端 (backends) 控制这些文件的存储位置。
记忆如何工作
将代理指向记忆文件。 创建代理时,通过 memory= 传入文件路径。你还可以通过 skills= 传入 技能 (skills) 以获取程序化记忆(即告诉代理如何 执行任务的可重用指令)。后端 用于控制文件的存储位置及其访问权限。
代理读取记忆。 代理可以在启动时将记忆文件加载到系统提示词中,或者在对话过程中按需读取。例如,技能 使用按需加载:代理在启动时只读取技能描述,仅当匹配到任务时才读取完整的技能文件。这在需要某种能力之前保持了上下文的精简。
代理更新记忆(可选)。 当代理学到新信息时,可以使用内置的 edit_file 工具更新记忆文件。更新可以在对话过程中(默认),也可以通过 后台整合 在对话间隙进行。变更会被持久化,并在下一次对话中可用。并非所有记忆都是可写的:开发者定义的 技能 和 组织策略 通常是只读的。详情请参阅 只读 vs 可写记忆 。
最常见的两种模式是 代理作用域记忆 (在所有用户间共享)和 用户作用域记忆 (每个用户独立)。
作用域记忆
代理记忆可以被设定作用域,使得同一组记忆文件可供所有使用该代理的用户访问,或者记忆文件也可以对每个用户保持独立。
代理作用域记忆
赋予代理随时间演变的独特持久身份。代理作用域记忆在所有用户间共享,因此代理通过每一次对话积累起自己的人格、知识和已习得的偏好。随着与用户的互动,它会发展出专业知识、优化处理方法,并记住哪些做法有效。如果拥有写入权限,它还可以学习和更新 技能 。 关键在于后端命名空间:将其设置为 (assistant_id,) 意味着该代理的每一次对话都会读取和写入同一个记忆文件。 访问 rt.serverInfo 需要 deepagents>=1.9.0。旧版本请改用 getConfig().metadata.assistantId 来读取助手 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] ,
} ) ,
},
) ,
} ) ;
使用初始记忆填充存储,然后在两个线程中调用代理,观察它如何记住并更新所学内容。 import { v4 as uuidv4 } from "uuid" ;
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.org.cn/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 : uuidv4 () } };
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 : uuidv4 () } };
await agent . invoke ( {
messages : [ { role : "user" , content : "Explain how transformers work." } ] ,
}, config2) ;
用户作用域记忆
赋予每个用户各自的记忆文件。代理在保持核心指令固定的同时,按用户记住偏好、上下文和历史记录。如果存储在用户作用域的后端中,用户还可以拥有针对个人的 技能 。 命名空间使用 (user_id,),因此每个用户都拥有记忆文件的独立副本。用户 A 的偏好永远不会泄漏到用户 B 的对话中。 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] ,
} ) ,
},
) ,
} ) ;
播种每个用户的记忆,并以两个不同用户的身份调用代理。每个用户只能看到自己的偏好。 import { v4 as uuidv4 } from "uuid" ;
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.org.cn/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 : uuidv4 () } },
) ;
高级用法
除了记忆路径和作用域的基本配置选项外,你还可以配置更多高级参数
维度 回答的问题 选项 持续时间 它能持续多久? 短期 (单次对话)或 长期 (跨对话)信息类型 这是什么类型的信息? 情景记忆 (过往经历)、程序化记忆 (指令和技能)或 语义记忆 (事实)范围 谁可以查看和修改它? 用户 、代理 或 组织 更新策略 何时写入记忆? 对话过程中(默认)或 对话之间 检索 如何读取记忆? 加载到提示词中(默认)或按需(例如 技能 ) 代理权限 代理可以写入记忆吗? 读写 (默认)或 只读 (用于共享策略)
情景记忆
情景记忆存储过往经历的记录:发生了什么、发生顺序以及结果如何。与语义记忆(存储在 AGENTS.md 等文件中的事实和偏好)不同,情景记忆保留了完整的对话上下文,以便代理能够回忆起问题是如何 解决的,而不仅仅是从中学到了什么 。 Deep Agents 已经使用了支持情景记忆的机制:检查点 (checkpoints) ,即每一次对话都作为检查点线程持久化。 要使过往对话可搜索,请将线程搜索封装在一个工具中。user_id 从运行时上下文获取,而不是作为参数传递: 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." ,
}
) ;
你可以通过调整元数据过滤器,按用户或组织来限定线程搜索范围。
// 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 ,
} ) ;
这对于执行复杂、多步骤任务的代理非常有用。例如,编码代理可以回顾过去的调试会话,直接跳到可能的根本原因。
组织级记忆
组织级记忆遵循与用户作用域记忆相同的模式,但使用组织范围的命名空间而不是用户个人命名空间。将其用于应适用于组织内所有用户和代理的策略或知识。 组织记忆通常是只读 的,以防止通过共享状态进行提示词注入。详情请参阅 只读 vs 可写记忆 。 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] ,
} ) ,
},
) ,
} ) ;
通过应用程序代码填充组织记忆
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) 强制组织级记忆为只读,或使用 策略钩子 (policy hooks) 实现自定义验证逻辑。
后台整合
默认情况下,代理在对话期间(热路径)写入记忆。另一种选择是作为后台任务在对话之间 处理记忆,有时称为休眠时间计算 。一个独立的深度代理审查最近的对话,提取关键事实,并将它们与现有记忆合并。
方法 优点 缺点 热路径 (对话期间)记忆即时可用,对用户透明 增加延迟,代理必须执行多任务 后台 (对话之间)无面向用户的延迟,可以跨多个对话进行合成 记忆直到下一次对话才可用,需要第二个代理
对于大多数应用程序,热路径已经足够。当你需要减少延迟或改善跨多次对话的记忆质量时,可以添加后台整合。 建议的模式是与主代理一起部署一个整合代理 ——一个读取最近对话历史、提取关键事实并将其合并到记忆存储中的深度代理——并按 定时任务计划 触发它。选择一个反映用户实际与代理互动频率的节奏:拥有稳定每日流量的聊天产品可能每几小时整合一次,而每周仅使用几次的工具只需每晚或每周运行一次。整合频率远高于用户对话频率只会浪费 Token 运行无效任务。 整合代理
整合代理读取最近的对话历史并将关键事实合并到记忆存储中。在 langgraph.json 中将其与主代理一起注册。
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.1-pro-preview" ,
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) 按固定的时间表运行整合代理。该代理搜索最近的对话并将其合成为记忆。将计划与你的使用模式相匹配,以便整合运行大致跟踪实际活动。
使用定时任务调度整合代理
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." } ] },
},
) ;
所有定时任务计划均以 UTC 时间解释。有关管理和删除定时任务的详细信息,请参阅 定时任务 。
定时任务的间隔必须与整合代理内部的回溯窗口匹配。上述示例每 6 小时运行一次 (0 */6 * * *),且代理的 search_recent_conversations 工具向后查找 timedelta(hours=6) ——请保持两者同步。如果定时任务运行频率高于回溯时间,你将重复处理相同的对话;如果频率较低,你将丢失落在此窗口之外的记忆。
有关部署带有后台进程的代理的更多信息,请参阅 投入生产 。
只读 vs 可写记忆
默认情况下,代理既可以读取也可以写入记忆文件。对于组织策略或合规规则等共享状态,你可能希望将记忆设为只读 ,以便代理可以引用但不能修改它。这可以防止通过共享记忆进行提示词注入,并确保只有你的应用程序代码能控制文件中的内容。
权限 用例 工作原理 读写 (默认)用户偏好、代理自我完善、已习得的 技能 代理通过 edit_file 工具更新文件 只读 组织策略、合规规则、共享知识库、开发者定义的 技能 通过应用程序代码或 存储 API 填充。使用 权限 拒绝写入特定路径,或使用 策略钩子 实现自定义验证逻辑。
安全注意事项: 如果一个用户可以写入另一个用户读取的记忆,恶意用户可能会将指令注入到共享状态中。为了缓解这一点:
默认为用户作用域 (user_id),除非你有特定理由需要共享。
对共享策略使用只读记忆 (通过应用程序代码填充,而不是通过代理)。
在代理写入共享记忆之前添加人工参与 (human-in-the-loop) 验证。使用 中断 (interrupt) 来要求人类对敏感路径的写入进行批准。
要强制执行只读记忆,请使用 权限 以声明方式拒绝向特定路径写入。对于自定义验证逻辑(速率限制、审计日志、内容检查),请使用 后端策略钩子 。
并发写入
多个线程可以并行写入记忆,但对同一个文件 的并发写入可能导致“最后写入获胜”冲突。对于用户作用域记忆,这种情况很少见,因为用户通常一次只有一个活跃对话。对于代理作用域或组织作用域记忆,请考虑使用 后台整合 来串行化写入,或将记忆结构化为按主题划分的独立文件以减少争用。 在实践中,如果因为冲突导致写入失败,大语言模型通常足够聪明,可以进行重试或平稳恢复,因此丢失单次写入并非灾难性事件。 同一部署中的多个代理
要在共享部署中为每个代理提供其专属记忆,请将 assistant_id 添加到命名空间中。
new StoreBackend ( {
namespace : ( rt ) => [
rt . serverInfo . assistantId ,
rt . serverInfo . user . identity ,
] ,
} )
如果你只需要代理间隔离而不需要用户作用域,请单独使用 assistant_id。
将这些文档 连接到 Claude、VSCode 等,以获得实时答案。