DeepAgents 上下文管理(全网最细)
·
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 —— 身份定义
agent = create_deep_agent(
model=llm,
system_prompt="""
你是一个旅行规划师。
## 角色
- 你是专业的旅行顾问
- 你熟悉全球各大旅游城市
## 行为准则
- 回答必须使用中文
- 涉及金额保留两位小数
- 不要编造数据,不确定就说"不确定"
## 工作流程
1. 先了解用户需求
2. 查询天气
3. 推荐景点
4. 计算预算
5. 生成旅行计划
## 边界
- 不要帮用户订机票
- 不要处理签证问题
"""
)
system_prompt 的三个作用:
| 作用 | 说明 |
|---|---|
| 身份定义 | 告诉 AI “你是谁” |
| 行为准则 | 告诉 AI “怎么做事” |
| 边界限制 | 告诉 AI “什么不能做” |
1.2 memory —— 总是被读取的记忆文件
memory 是独立的 markdown 文件,每次执行都会被加载到上下文中。
agent = create_deep_agent(
model=llm,
memory=[
"/project/AGENTS.md", # 项目规则
"/project/preferences.md" # 用户偏好
],
backend=file_backend
)
AGENTS.md 示例:
# 项目规则
## 数据规范
- 所有金额使用人民币,保留两位小数
- 日期格式统一使用 YYYY-MM-DD
- 电话号码脱敏显示:138****1234
## 行为规范
- 回答优先使用表格和列表
- 涉及敏感操作必须提示用户确认
- 日志记录所有工具调用
## 禁止事项
- 不要编造数据
- 不要执行 DELETE 操作
- 不要泄露数据库密码
preferences.md 示例:
# 用户偏好
## 语言
- 默认使用中文回答
- 代码注释使用英文
## 输出格式
- 喜欢简洁的回答
- 优先使用表格对比
- 重要信息加粗标注
## 业务偏好
- 优先推荐性价比高的方案
- 预算超支时自动推荐替代方案
memory 和 system_prompt 的区别:
| 特性 | system_prompt | memory |
|---|---|---|
| 定义位置 | 代码里 | 外部文件 |
| 内容量 | 通常较短 | 可以很长 |
| 修改方式 | 改代码 | 改文件,不改代码 |
| 加载时机 | 启动时 | 启动时 |
| 适用场景 | 核心身份和规则 | 详细的规范和偏好 |
1.3 skills —— 渐进式加载
skills 不会全部加载,只在任务相关时才读取对应的 SKILL.md。
agent = create_deep_agent(
model=llm,
skills=["skills"], # 技能目录
backend=file_backend
)
目录结构:
skills/
├── weather_report/
│ └── SKILL.md # 天气报告技能
├── code_review/
│ └── SKILL.md # 代码审查技能
└── data_analysis/
├── SKILL.md # 数据分析技能
└── scripts/
└── chart.py # 附带脚本
1.4 @tool —— 总是被加载的工具说明
@tool
def query_database(sql: str) -> str:
""""执行 SQL 查询语句。""""
pass
这个 docstring 会被自动提取,作为工具说明加载到上下文中。
1.5 四种组件加载方式对比
agent = create_deep_agent(
model=llm,
system_prompt="你是旅行规划师...", # 总是加载
memory=["/project/AGENTS.md"], # 总是加载
skills=["skills"], # 渐进式加载
tools=[query_database, search_web], # 总是加载(docstring)
backend=file_backend
)
| 组件 | 加载时机 | 加载方式 | 内容来源 |
|---|---|---|---|
| system_prompt | 启动时 | 总是加载 | 代码字符串 |
| memory | 启动时 | 总是加载 | 外部 markdown 文件 |
| @tool | 启动时 | 总是加载 | 函数 docstring |
| skills | 启动时 | 渐进式加载 | SKILL.md 文件 |
第2层:运行时上下文(每次调用动态传入)
这是最实用的一层!解决的问题是:工具执行时需要知道"当前用户是谁"。
2.1 典型场景
用户 A(普通用户)调用:查询订单 → 只能查自己的
用户 B(管理员)调用:查询订单 → 可以查所有人的
没有运行时上下文,工具怎么知道"当前是 A 还是 B"?
2.2 四步实现
第一步:定义上下文数据类型
from dataclasses import dataclass
@dataclass
class UserContext:
user_id: str # 用户 ID
username: str # 用户名
role: str # 角色:admin / user
token: str # 登录 token
department: str # 部门
第二步:创建智能体时指定 context_schema
from deepagents import create_deep_agent
agent = create_deep_agent(
model=llm,
tools=[query_orders, delete_record],
system_prompt="你是一个订单管理助手。",
context_schema=UserContext # 告诉智能体:运行时会传入这个类型
)
第三步:执行时传入上下文
# 普通用户调用
result = agent.invoke(
input={"messages": [{"role": "user", "content": "查询我的订单"}]},
config={"configurable": {"thread_id": "thread_1"}},
context=UserContext(
user_id="U001",
username="大风子",
role="user",
token="eyJhbGciOiJI...",
department="技术部"
)
)
# 管理员调用
result = agent.invoke(
input={"messages": [{"role": "user", "content": "查询所有订单"}]},
config={"configurable": {"thread_id": "thread_2"}},
context=UserContext(
user_id="A001",
username="管理员",
role="admin",
token="eyJhbGciOiJI...",
department="管理部"
)
)
第四步:在工具中读取上下文
from deepagents.tools import ToolRuntime
from langchain.tools import tool
@tool
def query_orders(user_filter: str = "") -> str:
""""查询订单信息""""
runtime: ToolRuntime[UserContext] = get_runtime()
ctx = runtime.context
print(f"[工具] 当前用户: {ctx.username} (ID: {ctx.user_id})")
print(f"[工具] 角色: {ctx.role}")
if ctx.role == "admin":
sql = f"SELECT * FROM orders {user_filter}"
else:
sql = f"SELECT * FROM orders WHERE user_id = '{ctx.user_id}'"
return execute_sql(sql)
2.3 完整流程
用户登录 → 拿到 token、user_id、role
|
v
agent.invoke(
input={"messages": [...]},
config={"thread_id": "..."},
context=UserContext(user_id, username, role, token)
)
|
v
智能体收到 messages
|
v
智能体决定调用 query_orders 工具
|
v
query_orders 内部执行:
runtime = get_runtime()
ctx = runtime.context
+-- ctx.role == "admin" -> 查所有订单
+-- ctx.role == "user" -> 只查自己的订单
|
v
返回结果给智能体 -> 整理后返回给用户
2.4 实际应用场景
# 场景1:权限校验
@tool
def delete_record(table: str, record_id: int) -> str:
""""删除记录""""
ctx = get_runtime().context
if ctx.role != "admin":
return "权限不足:只有管理员可以删除记录"
return f"已删除 {table} 表中 ID 为 {record_id} 的记录"
# 场景2:操作审计
@tool
def export_data(query: str) -> str:
""""导出数据""""
ctx = get_runtime().context
log_audit(user=ctx.username, action="export", detail=query)
return execute_export(query)
# 场景3:API 调用鉴权
@tool
def call_external_api(endpoint: str) -> str:
""""调用外部 API""""
ctx = get_runtime().context
headers = {"Authorization": f"Bearer {ctx.token}"}
return requests.get(endpoint, headers=headers).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 短期记忆(checkpointer)
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver()
agent = create_deep_agent(
model=llm,
tools=[tool1, tool2],
checkpointer=checkpointer,
system_prompt="..."
)
config = {"configurable": {"thread_id": "thread_1"}}
# 第1次调用
agent.invoke({"messages": [{"role": "user", "content": "我叫大风子"}]}, config=config)
# 第2次调用(同一个 thread_id)
result = agent.invoke({"messages": [{"role": "user", "content": "我叫什么?"}]}, config=config)
print(result['messages'][-1].content) # "你叫大风子"
# 不同的 thread_id,互相隔离
config_b = {"configurable": {"thread_id": "thread_2"}}
result = agent.invoke({"messages": [{"role": "user", "content": "我叫什么?"}]}, config=config_b)
# thread_2 不知道 thread_1 的信息
短期记忆的特点:
| 特性 | 说明 |
|---|---|
| 作用域 | 同一个 thread_id 内 |
| 生命周期 | 程序运行期间(内存) |
| 用途 | 多轮对话、HITL 中断恢复 |
| 持久化 | 不持久化,程序关了就没了 |
4.2 长期记忆(store + backend)
from langgraph.store.memory import InMemoryStore
from deepagents.backends import StoreBackend
store = InMemoryStore()
store_backend = StoreBackend(namespace=lambda ctx: ("filesystem",))
agent = create_deep_agent(
model=llm,
store=store,
backend=store_backend,
system_prompt="..."
)
# Thread A 写入记忆
config_a = {"configurable": {"thread_id": "thread_a"}}
agent.invoke({
"messages": [{"role": "user", "content": "我叫大风子,幸运数字是 7,请记住"}]
}, config=config_a)
# Thread B 读取记忆(不同的 thread_id,但共享同一个 store)
config_b = {"configurable": {"thread_id": "thread_b"}}
result = agent.invoke({
"messages": [{"role": "user", "content": "我叫什么?幸运数字是几?"}]
}, config=config_b)
print(result['messages'][-1].content) # "你叫大风子,幸运数字是 7"
长期记忆的特点:
| 特性 | 说明 |
|---|---|
| 作用域 | 跨会话,所有 thread_id 共享 |
| 生命周期 | 持久化(取决于 store 实现) |
| 用途 | 用户偏好、文件存储、知识积累 |
| 持久化 | 可以(Redis、数据库等) |
4.3 长短期记忆对比
| 维度 | 短期记忆 | 长期记忆 |
|---|---|---|
| 实现 | checkpointer | store + backend |
| 作用域 | 同一 thread_id | 跨所有 thread_id |
| 生命周期 | 程序运行期间 | 可持久化 |
| 典型用途 | 多轮对话、HITL | 用户偏好、文件、知识 |
| 数据位置 | 内存 | 内存 / Redis / 数据库 |
四层上下文协作示例
from dataclasses import dataclass
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
from pathlib import Path
@dataclass
class UserContext:
user_id: str
username: str
role: str
workspace_dir = Path("./agent_workspace").resolve()
file_backend = FilesystemBackend(root_dir=workspace_dir, virtual_mode=True)
checkpointer = InMemorySaver()
store = InMemoryStore()
agent = create_deep_agent(
model=llm,
tools=[my_tool1, my_tool2], # 第1层:工具说明(总是加载)
system_prompt="你是一个智能助手...", # 第1层:身份定义(总是加载)
memory=["/project/AGENTS.md"], # 第1层:规则文件(总是加载)
skills=["skills"], # 第1层:技能(渐进式加载)
context_schema=UserContext, # 第2层:运行时上下文类型
backend=file_backend, # 第4层:长期记忆后端
checkpointer=checkpointer, # 第4层:短期记忆
store=store # 第4层:长期记忆存储
)
result = agent.invoke(
input={"messages": [{"role": "user", "content": "帮我查询数据"}]},
config={"configurable": {"thread_id": "thread_1"}}, # 第4层:短期记忆
context=UserContext( # 第2层:运行时上下文
user_id="U001",
username="大风子",
role="admin"
)
)
速记口诀
| 层次 | 一句话 | 关键词 |
|---|---|---|
| 第1层:输入响应 | 启动时加载,固定不变 | system_prompt + memory + skills + @tool |
| 第2层:运行时上下文 | 每次调用动态传入 | context_schema + invoke(context=) |
| 第3层:子代理隔离 | 自动隔离,不可控 | 子智能体只收到 messages |
| 第4层:长短期记忆 | 短期同会话,长期跨会话 | checkpointer vs store |
一句话总结:第1层定身份,第2层传身份,第3层隔离身份,第4层记住身份。
更多推荐



所有评论(0)