在 LangGraph 的中间件(Middleware / Hooks)中访问长期记忆(Store),并对比热路径写入与后台异步写入两种记忆整理策略。
LangGraph 中访问长期记忆(Store)的核心入口是 Runtime 实例,无论在哪一层,只要能拿到 Runtime,就能通过 runtime.store 进行 put / get / search 操作。
| 访问位置 | 获取 Runtime 的方式 |
|---|
| 工具(Tool)内 | 直接在工具函数参数中获取 runtime,然后 runtime.store |
节点风格 Hook(如 before_model) | Hook 参数中直接包含 runtime |
包装风格 Hook — wrap_model_call | 通过 request.runtime 间接获取(request 类型为 ModelRequest) |
包装风格 Hook — wrap_tool_call | 通过 request.runtime 间接获取(request 类型为 ToolCallRequest) |
| 类型 | 作用域 | 用途 |
|---|
| State | 线程级别(单次会话) | 短期记忆 |
| Store | 跨会话级别 | 长期记忆 |
| Context | 静态配置级别 | 用户元数据、工具/数据库连接等静态信息 |
用户请求 → LangGraph 节点流程
│
┌──────────┼──────────┐
▼ ▼ ▼
Tool before_ wrap_model
model _call / wrap_tool_call
│ │ │
│ runtime.store request.runtime.store
▼ ▼ ▼
Store (长期记忆)
put / get / search
def my_tool(state, config, runtime):
store = runtime.store
store.put(("namespace",), "key", {"data": "value"})
result = store.get(("namespace",), "key")
items = store.search(("namespace",))
return result
def before_model(state, config, runtime):
store = runtime.store
memories = store.search(("user_memory",))
return state
def wrap_model_call(request, handler):
store = request.runtime.store
return handler(request)
def wrap_tool_call(request, handler):
store = request.runtime.store
state = request.runtime.state
return handler(request)
| 策略 | Hot Path(热路径/主流程写入) | Background(后台异步写入) |
|---|
| 方式 | AI 一边回答一边决定是否记录 | 先回答用户,后台异步整理记忆 |
| 优点 | 立即生效,下一轮即可感知 | 主流程更快,逻辑更清晰 |
| 缺点 | 增加延迟,逻辑更复杂(需配合工具/中间件) | 不会立即生效,需考虑整理频率 |
| 适用场景 | 用户偏好、账号信息 | 对话摘要、经验沉淀、行为分析 |
- 节点风格 Hook 有 4 种:
before_model 等,参数中直接有 runtime - 包装风格 Hook 有 2 种:
wrap_model_call 和 wrap_tool_call,需通过 request.runtime 间接获取 - Context(静态上下文)使用频率低于 State 和 Store,可作为课外阅读内容
- 访问长期记忆的统一入口是
Runtime,无论处于 Graph 的哪个位置,获取 Runtime 的模式是相通的 - 实际工程中建议:高频、需立即生效的记忆走 Hot Path;大批量、非急迫的记忆走 Background
- Context 适合存放不变的配置信息,如数据库连接串、API Key 等,避免在 State/Store 中混入静态数据