DeepAgents 上下文管理详解全景图智能体的大脑由四层上下文组成┌─────────────────────────────────────────────────┐ │ 第1层输入响应层启动时加载固定不变 │ │ ┌──────────┬──────────┬──────────┬──────────┐ │ │ │ system_ │ memory │ skills │ tool │ │ │ │ prompt │ 文件 │ 技能 │ 工具说明 │ │ │ └──────────┴──────────┴──────────┴──────────┘ │ ├─────────────────────────────────────────────────┤ │ 第2层运行时上下文每次调用动态传入 │ │ ┌────────────────────────────────────────────┐ │ │ │ context_schema 定义 → invoke 时传入 context │ │ │ └────────────────────────────────────────────┘ │ ├─────────────────────────────────────────────────┤ │ 第3层子代理隔离自动隔离不可控 │ │ ┌──────────────┬──────────────┐ │ │ │ 子智能体 A │ 子智能体 B │ 互不可见 │ │ └──────────────┴──────────────┘ │ ├─────────────────────────────────────────────────┤ │ 第4层长短期记忆 │ │ ┌──────────────────┬───────────────────────┐ │ │ │ 短期checkpointer│ 长期store backend │ │ │ │ 同一会话内 │ 跨会话 │ │ │ └──────────────────┴───────────────────────┘ │ └─────────────────────────────────────────────────┘第1层输入响应层启动时加载固定不变这一层的内容在 create_deep_agent() 时就确定了之后不会变。1.1 system_prompt —— 身份定义agentcreate_deep_agent(modelllm,system_prompt 你是一个旅行规划师。 ## 角色 - 你是专业的旅行顾问 - 你熟悉全球各大旅游城市 ## 行为准则 - 回答必须使用中文 - 涉及金额保留两位小数 - 不要编造数据不确定就说不确定 ## 工作流程 1. 先了解用户需求 2. 查询天气 3. 推荐景点 4. 计算预算 5. 生成旅行计划 ## 边界 - 不要帮用户订机票 - 不要处理签证问题 )system_prompt 的三个作用作用说明身份定义告诉 AI “你是谁”行为准则告诉 AI “怎么做事”边界限制告诉 AI “什么不能做”1.2 memory —— 总是被读取的记忆文件memory 是独立的 markdown 文件每次执行都会被加载到上下文中。agentcreate_deep_agent(modelllm,memory[/project/AGENTS.md,# 项目规则/project/preferences.md# 用户偏好],backendfile_backend)AGENTS.md 示例# 项目规则## 数据规范-所有金额使用人民币保留两位小数-日期格式统一使用 YYYY-MM-DD-电话号码脱敏显示138****1234## 行为规范-回答优先使用表格和列表-涉及敏感操作必须提示用户确认-日志记录所有工具调用## 禁止事项-不要编造数据-不要执行 DELETE 操作-不要泄露数据库密码preferences.md 示例# 用户偏好## 语言-默认使用中文回答-代码注释使用英文## 输出格式-喜欢简洁的回答-优先使用表格对比-重要信息加粗标注## 业务偏好-优先推荐性价比高的方案-预算超支时自动推荐替代方案memory 和 system_prompt 的区别特性system_promptmemory定义位置代码里外部文件内容量通常较短可以很长修改方式改代码改文件不改代码加载时机启动时启动时适用场景核心身份和规则详细的规范和偏好1.3 skills —— 渐进式加载skills 不会全部加载只在任务相关时才读取对应的 SKILL.md。agentcreate_deep_agent(modelllm,skills[skills],# 技能目录backendfile_backend)目录结构skills/├── weather_report/│ └── SKILL.md# 天气报告技能├── code_review/│ └── SKILL.md# 代码审查技能└── data_analysis/├── SKILL.md# 数据分析技能└── scripts/└── chart.py# 附带脚本1.4 tool —— 总是被加载的工具说明tooldefquery_database(sql:str)-str:执行 SQL 查询语句。pass这个 docstring 会被自动提取作为工具说明加载到上下文中。1.5 四种组件加载方式对比agentcreate_deep_agent(modelllm,system_prompt你是旅行规划师...,# 总是加载memory[/project/AGENTS.md],# 总是加载skills[skills],# 渐进式加载tools[query_database,search_web],# 总是加载docstringbackendfile_backend)组件加载时机加载方式内容来源system_prompt启动时总是加载代码字符串memory启动时总是加载外部 markdown 文件tool启动时总是加载函数 docstringskills启动时渐进式加载SKILL.md 文件第2层运行时上下文每次调用动态传入这是最实用的一层解决的问题是工具执行时需要知道当前用户是谁。2.1 典型场景用户 A普通用户调用查询订单 → 只能查自己的 用户 B管理员调用查询订单 → 可以查所有人的没有运行时上下文工具怎么知道当前是 A 还是 B2.2 四步实现第一步定义上下文数据类型fromdataclassesimportdataclassdataclassclassUserContext:user_id:str# 用户 IDusername:str# 用户名role:str# 角色admin / usertoken:str# 登录 tokendepartment:str# 部门第二步创建智能体时指定 context_schemafromdeepagentsimportcreate_deep_agent agentcreate_deep_agent(modelllm,tools[query_orders,delete_record],system_prompt你是一个订单管理助手。,context_schemaUserContext# 告诉智能体运行时会传入这个类型)第三步执行时传入上下文# 普通用户调用resultagent.invoke(input{messages:[{role:user,content:查询我的订单}]},config{configurable:{thread_id:thread_1}},contextUserContext(user_idU001,username大风子,roleuser,tokeneyJhbGciOiJI...,department技术部))# 管理员调用resultagent.invoke(input{messages:[{role:user,content:查询所有订单}]},config{configurable:{thread_id:thread_2}},contextUserContext(user_idA001,username管理员,roleadmin,tokeneyJhbGciOiJI...,department管理部))第四步在工具中读取上下文fromdeepagents.toolsimportToolRuntimefromlangchain.toolsimporttooltooldefquery_orders(user_filter:str)-str:查询订单信息 runtime:ToolRuntime[UserContext]get_runtime()ctxruntime.contextprint(f[工具] 当前用户:{ctx.username}(ID:{ctx.user_id}))print(f[工具] 角色:{ctx.role})ifctx.roleadmin:sqlfSELECT * FROM orders{user_filter}else:sqlfSELECT * FROM orders WHERE user_id {ctx.user_id}returnexecute_sql(sql)2.3 完整流程用户登录 → 拿到 token、user_id、role|v agent.invoke(input{messages:[...]},config{thread_id:...},contextUserContext(user_id,username,role,token))|v 智能体收到 messages|v 智能体决定调用 query_orders 工具|v query_orders 内部执行 runtimeget_runtime()ctxruntime.context--ctx.roleadmin-查所有订单--ctx.roleuser-只查自己的订单|v 返回结果给智能体-整理后返回给用户2.4 实际应用场景# 场景1权限校验tooldefdelete_record(table:str,record_id:int)-str:删除记录 ctxget_runtime().contextifctx.role!admin:return权限不足只有管理员可以删除记录returnf已删除{table}表中 ID 为{record_id}的记录# 场景2操作审计tooldefexport_data(query:str)-str:导出数据 ctxget_runtime().context log_audit(userctx.username,actionexport,detailquery)returnexecute_export(query)# 场景3API 调用鉴权tooldefcall_external_api(endpoint:str)-str:调用外部 API ctxget_runtime().context headers{Authorization:fBearer{ctx.token}}returnrequests.get(endpoint,headersheaders).json()第3层子代理隔离自动不可控这一层你不需要手动管理理解原理就行。3.1 隔离机制主智能体|--子智能体 A有自己的上下文|-看不到子智能体 B 的数据|-看不到主智能体的运行时上下文|--子智能体 B有自己的上下文-看不到子智能体 A 的数据-看不到主智能体的运行时上下文3.2 为什么隔离# 主智能体传任务给子智能体时只传 messages# 不传 context、config 等# 子智能体收到的只有{messages:[HumanMessage(content请帮我查询北京天气)]}# 子智能体拿不到# - 主智能体的 context用户信息# - 主智能体的 config线程信息3.3 如果子智能体也需要用户信息怎么办方案把用户信息写进 messages 里传过去。# 在主智能体的 system_prompt 中引导system_prompt 你是协调员。在委派任务给子智能体时必须在任务描述中包含 1. 用户ID 2. 用户角色 3. 具体任务 第4层长短期记忆4.1 短期记忆checkpointerfromlanggraph.checkpoint.memoryimportInMemorySaver checkpointerInMemorySaver()agentcreate_deep_agent(modelllm,tools[tool1,tool2],checkpointercheckpointer,system_prompt...)config{configurable:{thread_id:thread_1}}# 第1次调用agent.invoke({messages:[{role:user,content:我叫大风子}]},configconfig)# 第2次调用同一个 thread_idresultagent.invoke({messages:[{role:user,content:我叫什么}]},configconfig)print(result[messages][-1].content)# 你叫大风子# 不同的 thread_id互相隔离config_b{configurable:{thread_id:thread_2}}resultagent.invoke({messages:[{role:user,content:我叫什么}]},configconfig_b)# thread_2 不知道 thread_1 的信息短期记忆的特点特性说明作用域同一个 thread_id 内生命周期程序运行期间内存用途多轮对话、HITL 中断恢复持久化不持久化程序关了就没了4.2 长期记忆store backendfromlanggraph.store.memoryimportInMemoryStorefromdeepagents.backendsimportStoreBackend storeInMemoryStore()store_backendStoreBackend(namespacelambdactx:(filesystem,))agentcreate_deep_agent(modelllm,storestore,backendstore_backend,system_prompt...)# Thread A 写入记忆config_a{configurable:{thread_id:thread_a}}agent.invoke({messages:[{role:user,content:我叫大风子幸运数字是 7请记住}]},configconfig_a)# Thread B 读取记忆不同的 thread_id但共享同一个 storeconfig_b{configurable:{thread_id:thread_b}}resultagent.invoke({messages:[{role:user,content:我叫什么幸运数字是几}]},configconfig_b)print(result[messages][-1].content)# 你叫大风子幸运数字是 7长期记忆的特点特性说明作用域跨会话所有 thread_id 共享生命周期持久化取决于 store 实现用途用户偏好、文件存储、知识积累持久化可以Redis、数据库等4.3 长短期记忆对比维度短期记忆长期记忆实现checkpointerstore backend作用域同一 thread_id跨所有 thread_id生命周期程序运行期间可持久化典型用途多轮对话、HITL用户偏好、文件、知识数据位置内存内存 / Redis / 数据库四层上下文协作示例fromdataclassesimportdataclassfromdeepagentsimportcreate_deep_agentfromdeepagents.backendsimportFilesystemBackendfromlanggraph.checkpoint.memoryimportInMemorySaverfromlanggraph.store.memoryimportInMemoryStorefrompathlibimportPathdataclassclassUserContext:user_id:strusername:strrole:strworkspace_dirPath(./agent_workspace).resolve()file_backendFilesystemBackend(root_dirworkspace_dir,virtual_modeTrue)checkpointerInMemorySaver()storeInMemoryStore()agentcreate_deep_agent(modelllm,tools[my_tool1,my_tool2],# 第1层工具说明总是加载system_prompt你是一个智能助手...,# 第1层身份定义总是加载memory[/project/AGENTS.md],# 第1层规则文件总是加载skills[skills],# 第1层技能渐进式加载context_schemaUserContext,# 第2层运行时上下文类型backendfile_backend,# 第4层长期记忆后端checkpointercheckpointer,# 第4层短期记忆storestore# 第4层长期记忆存储)resultagent.invoke(input{messages:[{role:user,content:帮我查询数据}]},config{configurable:{thread_id:thread_1}},# 第4层短期记忆contextUserContext(# 第2层运行时上下文user_idU001,username大风子,roleadmin))速记口诀层次一句话关键词第1层输入响应启动时加载固定不变system_prompt memory skills tool第2层运行时上下文每次调用动态传入context_schema invoke(context)第3层子代理隔离自动隔离不可控子智能体只收到 messages第4层长短期记忆短期同会话长期跨会话checkpointer vs store一句话总结第1层定身份第2层传身份第3层隔离身份第4层记住身份。