别再乱存 Agent 数据!State/Store/Context 底层逻辑 + 实战落地

    |     2026年8月22日   |   AI大模型应用, LangChain框架   |     0 条评论   |    28

上篇你把私厨 Demo 拼起来了——看图、工具、会话记忆都能跑。可「这通对话的计数」「跨会话的饮品偏好」「当前登录用户是谁」常被揉进同一个 list。这篇讲 Runtime 三件套:State / Store / Context,并在 Tool 里正确访问它们。


小明把三种「记住」混成一锅

私厨上线试玩后,产品又提需求:

1) 本会话点了几次「换一道」→ 显示 visit_count
2) 用户喜欢少油 → 换个 thread 还要记得
3) 同一套 Agent 服务小明和小华 → 别串档案

小明全往 ConversationMemory 里塞。换 thread_id 后偏好丢了;不换 thread,两个用户的忌口又串了。

他去找老张:”都是记忆,为啥不能一个 list 搞定?”

老张说:”因为生命周期不一样。Runtime 三件套各管一段:

State   = 这通电话聊到哪(含本轮任务字段)
Store   = 客户档案柜(跨电话线还能查)
Context = 这次是谁打进来的(user_id 等配置)

“


什么是 Runtime 三分法

压成一张表:

概念 说明 生命周期 工具里怎么拿
State 短期:messages + 自定义字段 单 thread_id runtime.state / Command
Store 长期:偏好、可检索笔记 跨会话 / 跨 thread runtime.store.get/put/search
Context 本次调用配置(如登录用户) 单次请求 runtime.context
invoke(messages, config.thread_id, context=user_id)
    │
    ├─► State(本 thread 消息与计数)
    ├─► Context(这次是谁)
    └─► Store(长期档案 / 向量笔记)
        ▲
        │ 工具经 ToolRuntime 读写

“比喻:

  • State = 白板(这节课写满,下课可擦,同教室续写靠 thread)
  • Store = 档案室(换教室还能借阅)
  • Context = 工牌(告诉工具现在接待的是哪位客户)”
需求 该放哪
「我叫什么?」同会话追问 State.messages
本会话 visit_count State 自定义字段
「喜欢龙井」换会话仍在 Store
按「喝茶和西湖」语义搜笔记 Store + 向量 index
区分 user_xiao / user_hua Context.user_id

代码拆解:State → Store → Context

1. State:自定义短期字段

默认 AgentState 主要是 messages。要记「会话开始时间、访问次数」:

class CustomState(AgentState):
  session_start: NotRequired[str]
  visit_count: NotRequired[int]
  model_call_count: NotRequired[int]

创建时挂上:

return create_agent(
  get_chat_model(),
  tools=CUSTOM_TOOLS,
  system_prompt="……",
  state_schema=CustomState,
  checkpointer=InMemorySaver(),
)

工具里读 / 写:

@tool
def get_session_info(runtime: ToolRuntime) -> str:
  state = runtime.state
  return f"session_start={state.get('session_start')}; visit_count={...}"

@tool
def bump_visit(runtime: ToolRuntime) -> Command:
  count = int(runtime.state.get("visit_count") or 0) + 1
  return Command(update={"visit_count": count, "messages": [...]})

“runtime 是框架注入参数,模型看不见;业务参数别叫这个名。写回用 Command(update=...)。”

2. Store:跨 thread 的长期记忆

键值结构:namespace + key + JSON value。

USERS_NS = ("users",)

def make_store() -> InMemoryStore:
  return InMemoryStore()

# 预置
store.put(USERS_NS, "user_xiao", {"name": "小明", "drink": "龙井茶"})

Agent 注入:

def build_agent(*, store: BaseStore):
  return create_agent(
    get_chat_model(),
    tools=PROFILE_TOOLS,
    system_prompt="需要用户档案时调用 get_user_profile;……",
    store=store,
    context_schema=Context,
    checkpointer=InMemorySaver(),
  )

工具经 runtime.store + runtime.context.user_id:

@tool
def get_user_profile(runtime: ToolRuntime[Context]) -> str:
  user_id = runtime.context.user_id
  item = runtime.store.get(USERS_NS, user_id)
  ...

@tool
def save_user_profile(name: str, drink: str, runtime: ToolRuntime[Context]) -> str:
  user_id = runtime.context.user_id
  runtime.store.put(USERS_NS, user_id, {"name": name, "drink": drink})
  return f"已保存档案 user_id={user_id}: ..."

“Demo B 的故事:thread-1 写入偏好 → thread-2 换短期会话 → 同一 Context(user_id=...) 仍能读出档案。这就是 Store 相对 State 的价值。”

3. 向量 Store:语义检索长期笔记

导图:文字→向量,相近含义在空间中更近。课件用 text-embedding-v4:

def make_vector_store() -> InMemoryStore:
  return InMemoryStore(
    index={
      "dims": EMBED_DIMS,
      "embed": embed_texts,
      "fields": ["text"],
    }
  )
@tool
def search_memories(query: str, runtime: ToolRuntime[Context]) -> str:
  hits = runtime.store.search(MEMORIES_NS, query=query, limit=2)
  ...

4. Context:本次是谁

@dataclass
class Context:
  user_id: str

调用时传入(与 thread 分开):

agent.invoke(
  {"messages": [{"role": "user", "content": "我的档案里写了什么?"}]},
  {"configurable": {"thread_id": "day10-a"}},
  context=Context(user_id="user_xiao"),
)

“导图例子:用户先登录再访问 Agent——登录身份进 Context,工具用 runtime.context 取,再去 Store 里按 user_id 取档案。别把 user_id 只写在某句聊天里碰运气。“

小明复述:”State 管这通;Store 管档案;Context 管工牌;工具统一走 ToolRuntime。”


总结

老张说:”第九篇只办一件事——把三种『记住』拆开。”

“三个核心理解:

  1. State —— 本会话消息与任务字段;state_schema + runtime.state
  2. Store —— 跨会话键值 / 向量;store= + runtime.store
  3. Context —— 本次工牌;context_schema + runtime.context“

LangChain 支线进度:

… → AI 私厨实战
    ↓
Runtime:State / Store / Context(本篇)
    ↓
Middleware → 多 Agent → Agentic RAG …

小明说:”下一篇该看中间件了——在模型调用前后挂钩子,做限流、摘要、脱敏。”

“对。下一篇:Middleware。”

Runtime 三分法:白板记这通,档案柜记长期,工牌标明此刻是谁。混用一个 list,不是省事,是埋雷。

转载请注明来源:别再乱存 Agent 数据!State/Store/Context 底层逻辑 + 实战落地
本文链接地址:https://ai.zhousir.top/?p=3869
回复 取消