LangChain v1Note 08

第 4 章:长期记忆与 Store

长期记忆是跨 thread 的受控数据。Store 挂在编译 Agent 上,工具通过 ToolRuntime.store 读取;namespace 必须包含已认证用户 id,避免 A 用户读到 B 用户的偏好。

长期记忆是跨 thread 的受控数据。Store 挂在编译 Agent 上,工具通过 ToolRuntime.store 读取;namespace 必须包含已认证用户 id,避免 A 用户读到 B 用户的偏好。

store = InMemoryStore()
agent = create_agent(model, tools=[remember, recall], context_schema=UserContext, store=store)
await agent.ainvoke(input, context=UserContext(user_id="u-123"))
API 参数 说明
store.put(namespace, key, value, index=...) namespace 为字符串元组 写入;key 由应用定义,例如 "profile"
store.get(namespace, key) 精确 key 读取单个 item
store.search(namespace_prefix, query=..., filter=..., limit=...) 前缀和检索条件 列出或语义检索;仅在配置索引后依赖语义能力

本课用 InMemoryStore 证明 API 和隔离逻辑;它不持久化。示例的偏好是“回答语言”,并不写真实个人资料。运行 08_long_term_memory.py,它先调用 Agent 写入,再用另一个 thread 读取同一用户偏好,并断言另一用户不可见。

state 是模型可见的对话工作区;context 是可信运行依赖;Store 是服务端长期数据。只有把 Store 内容经过最小化、脱敏和任务相关筛选后,才应放入 prompt。当前项目的 get_all_tools(configurable, runtime.store) 已接收 Store,以支持受控的服务端能力;它并不意味着所有 state 都会自动长期保存。

相关资源

  • 查看示例代码:docs/langchain/examples/08_long_term_memory.py
    """Chapter 4: store a user preference across two different threads."""
    
    import asyncio
    from dataclasses import dataclass
    
    from dotenv import load_dotenv
    from langchain.agents import create_agent
    from langchain.chat_models import init_chat_model
    from langchain.tools import ToolRuntime, tool
    from langgraph.store.memory import InMemoryStore
    
    from open_deep_research.configuration import Configuration
    
    
    load_dotenv()
    
    
    @dataclass
    class UserContext:
        user_id: str
    
    
    @tool
    def save_language(language: str, runtime: ToolRuntime[UserContext]) -> str:
        """Save the current user's preferred response language."""
        runtime.store.put(("preferences", runtime.context.user_id), "profile", {"language": language})
        return f"已保存语言偏好:{language}"
    
    
    @tool
    def get_language(runtime: ToolRuntime[UserContext]) -> str:
        """Read the current user's preferred response language."""
        item = runtime.store.get(("preferences", runtime.context.user_id), "profile")
        return str(item.value if item else {"language": "未设置"})
    
    
    async def main() -> None:
        settings = Configuration.from_env()
        store = InMemoryStore()
        agent = create_agent(
            init_chat_model(model=settings.research_model, max_tokens=100),
            tools=[save_language, get_language],
            context_schema=UserContext,
            store=store,
            system_prompt="必须调用合适的偏好工具。不要猜测工具返回值。",
        )
        user = UserContext(user_id="lesson-user-a")
        await agent.ainvoke(
            {"messages": [("user", "调用 save_language,把我的偏好保存为中文。")]},
            context=user,
            config={"configurable": {"thread_id": "write-preference"}},
        )
        result = await agent.ainvoke(
            {"messages": [("user", "调用 get_language,告诉我我的语言偏好。")]},
            context=user,
            config={"configurable": {"thread_id": "read-preference"}},
        )
        other = store.get(("preferences", "lesson-user-b"), "profile")
        assert other is None
        assert "中文" in str(result["messages"][-1].content)
        print("跨 thread 偏好: 中文;其他用户不可见")
    
    
    if __name__ == "__main__":
        asyncio.run(main())