LangGraph 多用户并发:Thread 会话隔离 + Redis 持久化,彻底解决 Agent 上下文串话泄露
平时遇到线上AI Agent一旦上线多用户并发会出现致命级 Bug用户 A 询问订单数据用户 B 对话里突然出现 A 的隐私订单用户聊完 A 的业务切换会话后历史记忆错乱批量并发请求时不同用户 LLM 上下文互相穿插回答完全答非所问。根源只有一个多用户共享同一个 Agent 状态空间发生状态泄露。很多开发者尝试手动拆分历史消息、前端缓存对话记录不仅开发成本高还无法实现对话回滚、多轮记忆持久化、会话断点续聊。底层原理LangGraph Thread 如何实现会话完全隔离Thread 核心定义Thread 是 LangGraph 内置逻辑隔离单元核心依靠唯一thread_id作为会话标识具备三大隔离特性独立状态空间不同 thread_id 的 messages、自定义状态完全互不共享独立 Checkpoint 快照每个会话拥有专属历史记录撤回、分支不会影响其他用户独立配置上下文图执行参数、记忆边界完全隔离。核心运行逻辑所有用户共用同一个 Graph 实例、同一套 Redis 存储仅通过 config 内的 thread_id 做数据分区# 用户1会话配置 config_user1 {configurable: {thread_id: user_1001_session_01}} # 用户2会话配置 config_user2 {configurable: {thread_id: user_1002_session_01}} # 底层Redis自动按thread_id分区存储状态读写互不干扰 await graph.ainvoke(inputs, configconfig_user1) await graph.ainvoke(inputs, configconfig_user2)隔离性验证逻辑简单测试即可证明隔离效果thread1 存入记忆我叫张三工程师thread2 存入记忆我叫李四设计师询问 thread1 “我叫什么”只会返回张三完全看不到李四信息询问 thread2 仅返回李四无任何跨会话数据泄露。业务层Thread 隔离粒度怎么选4 种场景落地方案thread_id 拼接规则直接决定业务灵活性4 种主流隔离粒度覆盖全部 Agent 场景用户级隔离 thread_id fuser:{user_id}适用通用单会话聊天机器人优点实现简单缺点同一用户无法新建独立对话。会话级隔离最推荐 thread_id fuser:{user_id}:session:{session_id}适用客服系统、多会话对话优点一个用户可创建多个独立聊天窗口会话互不干扰。文档级隔离 thread_id fdoc:{doc_id}适用本地知识库 RAG 文档问答每个文档对应独立对话跨文档不会混入上下文。任务 / 工单级隔离 thread_id ftask:{task_id}适用工作流智能体、审批流程 Agent每个任务状态独立流程执行互不干扰。多维度组合隔离 thread_id forg:{org_id}:user:{uid}:doc:{did}适用企业多租户 SaaS 系统租户、用户、文档三层隔离满足权限合规要求生产进阶Thread 生命周期自动管理长期运行会产生大量过期会话堆积海量对话快照占用 Redis 存储需要做自动清理机制记录每个 thread_id 最后活跃时间定时扫描过期会话例如 48 小时无交互自动判定过期过期会话可先归档至 MySQL / 对象存储再清理 Redis 状态节省内存后台异步定时任务执行清理不阻塞正常用户请求。可观测Thread 会话监控方案搭配 LangSmith 链路追踪给每条 Trace 自动挂载 thread_id 标签线上问题排查效率翻倍根据 thread_id 筛选单一用户全部交互日志统计每个会话 token 消耗、消息条数、平均响应耗时快速定位异常会话超长对话、频繁超时、幻觉严重的用户会话。FastAPI 全异步服务兼容 Redis Thread 隔离依赖pip install fastapi uvicorn langgraph langgraph-checkpoint-redis redis langchain-openai pydantic httpxmain.py —模拟Agentimport asyncio from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.responses import StreamingResponse from pydantic import BaseModel from typing import List, Optional from datetime import datetime, timedelta from langgraph.graph import StateGraph, START, END, MessagesState from langchain_openai import ChatOpenAI from langgraph.checkpoint.redis.aio import AsyncRedisSaver from langgraph.checkpoint.base import BaseCheckpointSaver from langgraph.checkpoint.memory import InMemorySaver # 全局资源 checkpointer: Optional[BaseCheckpointSaver] None agent None # llm ChatOpenAI(modelgpt-4o-mini, streamingTrue) api_keysk-xxxxxxxxxxxxxxxxxxx base_urlhttps://api.deepseek.com/v1 llm ChatOpenAI( modeldeepseek-chat, temperature0.6, api_keyapi_key, base_urlbase_url ) # Thread生命周期管理器自动清理过期会话 class ThreadManager: def __init__(self, max_age_hours: int 48): self.max_age timedelta(hoursmax_age_hours) self.active_threads: dict[str, datetime] {} def touch(self, thread_id: str): self.active_threads[thread_id] datetime.now() def get_expired_threads(self) - list[str]: now datetime.now() return [ tid for tid, last_active in self.active_threads.items() if now - last_active self.max_age ] async def cleanup_expired(self, graph): expired_list self.get_expired_threads() for tid in expired_list: config {configurable: {thread_id: tid}} try: state await graph.aget_state(config) if state.values: print(f归档并清理过期会话: {tid}) await graph.adelete_state(config) except Exception as e: print(f清理会话{tid}失败: {str(e)}) for tid in expired_list: self.active_threads.pop(tid, None) thread_mgr ThreadManager(max_age_hours48) # LangGraph工作流定义 async def call_model(state: MessagesState): resp await llm.ainvoke(state[messages]) return {messages: [resp]} builder StateGraph(MessagesState) builder.add_node(agent, call_model) builder.add_edge(START, agent) builder.add_edge(agent, END) # 生命周期管理器 asynccontextmanager async def lifespan(app: FastAPI): global checkpointer, agent try: # 初始化Redis持久化存储器 checkpointer AsyncRedisSaver(redis_urlredis://localhost:6379/0) # 连通性测试 await checkpointer.aget_state({configurable: {thread_id: test_conn}}) print(Redis持久化连接成功开启Thread会话隔离) except Exception as e: print(fRedis连接失败自动降级内存会话存储: {str(e)}) # Redis不可用时切换内存存储保证对话记忆跨请求生效 checkpointer InMemorySaver() # 编译工作流注入状态存储器 agent builder.compile(checkpointercheckpointer) # 后台定时清理过期会话每小时执行一次 async def cleanup_task(): while True: await asyncio.sleep(3600) await thread_mgr.cleanup_expired(agent) asyncio.create_task(cleanup_task()) yield # 退出阶段无需手动关闭连接saver自动管理 print(服务关闭资源释放完成) # 初始化FastAPI应用 app FastAPI(title多会话隔离AI Agent服务, lifespanlifespan) # 请求入参模型 class AgentRequest(BaseModel): message: str user_id: str session_id: str default stream: bool False # 1. 一次性问答接口 app.post(/agent/invoke) async def invoke_agent(req: AgentRequest): thread_id fuser:{req.user_id}:session:{req.session_id} thread_mgr.touch(thread_id) config {configurable: {thread_id: thread_id}} res await agent.ainvoke( {messages: [{role: user, content: req.message}]}, config ) return {response: res[messages][-1].content, thread_id: thread_id} # 2. SSE流式打字机输出接口 app.post(/agent/stream) async def stream_agent(req: AgentRequest): thread_id fuser:{req.user_id}:session:{req.session_id} thread_mgr.touch(thread_id) config {configurable: {thread_id: thread_id}} async def event_generator(): async for event in agent.astream_events( {messages: [{role: user, content: req.message}]}, config, versionv2 ): if event[event] on_chat_model_stream: chunk event[data][chunk] if chunk.content: yield fdata: {chunk.content}\n\n yield data: [DONE]\n\n return StreamingResponse(event_generator(), media_typetext/event-stream) # 3. 获取用户单会话全部历史修复req未定义BUG app.get(/agent/history/{user_id}/{session_id}) async def get_session_history(user_id: str, session_id: str): # 修复直接使用路径参数session_id删除不存在的req变量 thread_id fuser:{user_id}:session:{session_id} config {configurable: {thread_id: thread_id}} state await agent.aget_state(config) msg_list state.values.get(messages, []) history [] # 只返回最新20条消息截断长文本至300字符 for m in msg_list[-20:]: role user if getattr(m, type, ) human else assistant history.append({role: role, content: m.content[:300]}) return { thread_id: thread_id, message_count: len(msg_list), history: history } # 服务启动入口修复uvicorn.run传参语法错误 if __name__ __main__: import uvicorn uvicorn.run(appmain:app, host0.0.0.0, port8000, reloadTrue)隔离性自测脚本 test_run.pyimport httpx import asyncio BASE_URL http://localhost:8000/agent/invoke async def test_thread_isolation(): # 两个完全独立会话 payload_a { message: 我叫张三专职做后端开发, user_id: u001, session_id: s01 } payload_b { message: 我叫李四产品设计师, user_id: u002, session_id: s01 } async with httpx.AsyncClient() as client: # 分别存入记忆 await client.post(BASE_URL, jsonpayload_a) await client.post(BASE_URL, jsonpayload_b) # 查询会话A res_a await client.post(BASE_URL, json{ message: 我叫什么名字, user_id: u001, session_id: s01 }) # 查询会话B res_b await client.post(BASE_URL, json{ message: 我叫什么名字, user_id: u002, session_id: s01 }) print(会话A回答, res_a.json()[response]) print(会话B回答, res_b.json()[response]) # 结果A只会输出张三B只会输出李四无交叉信息即隔离生效 if __name__ __main__: asyncio.run(test_thread_isolation())运行结果学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

相关新闻

百度开发者中心软文_企业AI知识库的价值

百度开发者中心软文_企业AI知识库的价值

当800人团队告别"翻聊天记录找文件":企业AI知识库的协作效率革命 开篇:一场让我下定决心的复盘会 去年年初的公司年度复盘会上,COO投屏了一张数据报表,全场安静了。 报表显示:过去一年,公司内部的…

2026/10/18 6:10:07 阅读更多 →
现代C++ :constexpr:一个常态的世界

现代C++ :constexpr:一个常态的世界

引言我们已经连续讲了几讲比较累人的编译期编程了。今天我们还是继续这个话题,但是,相信今天学完之后,你会感觉比之前几讲要轻松很多。C 语言里的很多改进,让我们做编译期编程也变得越来越简单了。初识 constexpr我们先来看一些例…

2026/10/18 6:10:14 阅读更多 →
EDMA寄存器配置实战:从架构理解到性能优化与错误处理

EDMA寄存器配置实战:从架构理解到性能优化与错误处理

1. 从手册到实战:为什么EDMA寄存器配置是嵌入式开发的硬骨头在嵌入式系统开发,尤其是基于TI C6000、C7000系列DSP或Sitara系列处理器的项目中,但凡涉及到高速数据搬移,比如图像处理中的帧数据搬运、音频处理中的Ping-Pong缓冲区切…

2026/10/18 6:11:17 阅读更多 →

最新新闻

AI开发工程师面试全解析:从简历到系统设计的高频考点与备战方法

AI开发工程师面试全解析:从简历到系统设计的高频考点与备战方法

面试这件事,最微妙的地方在于:你以为你在展示自己,面试官却往往在60分钟内只做一件事——验证“如果把这个项目交点给我,我能放心吗”。作为一个面过别人、也被别人面过的AI开发工程师,我见过太多准备充分却答偏的候选…

2026/10/19 5:37:25 阅读更多 →
OpenCV-Python手动框选+CSRT追踪实战指南

OpenCV-Python手动框选+CSRT追踪实战指南

1. 项目概述:为什么手动框选追踪比全自动检测更值得深挖在计算机视觉落地场景里,我见过太多团队一上来就堆YOLO、Mask R-CNN,结果部署到产线摄像头前,模型对光照突变、遮挡变形、小目标抖动直接“失明”。这时候反而是一支鼠标、一…

2026/10/19 5:37:25 阅读更多 →
artcraft:融合艺术直觉与工艺理性的数字创作新范式

artcraft:融合艺术直觉与工艺理性的数字创作新范式

1. 项目概述:当“艺术”与“工艺”在数字时代重新握手“artcraft”这个词乍看像一个生造词,但拆开来看——art是艺术,craft是工艺,合起来就是“艺术工艺”的浓缩表达。它不是某个具体软件、平台或产品的官方命名,而是一…

2026/10/19 5:37:25 阅读更多 →
基于WinPcap的UDP发包实战:亲手构造并发送原始数据包

基于WinPcap的UDP发包实战:亲手构造并发送原始数据包

简介:这是一份基于WinPcap库实现的UDP发包程序源码包,面向网络编程学习者、协议研究人员以及需要底层发包能力的安全测试人员。它重点演示如何绕过常规Socket接口,直接通过WinPcap与网卡交互来构造并发送UDP数据报,可服务于网络协…

2026/10/19 5:37:25 阅读更多 →
大模型简单题上的过度思考:现象、量化与优化

大模型简单题上的过度思考:现象、量化与优化

去年有段时间我集中做了一批开源大模型的推理能力评测,测到一半发现个特别哭笑不得的现象:让模型做“3.5 乘以 2 等于几”这种题,它居然先写“设第一项为 x,第二项为 y”,再列方程、展开、化简,最后补一句“…

2026/10/19 5:37:25 阅读更多 →
编译原理语法分析:从CFG理论到工程级错误恢复实战

编译原理语法分析:从CFG理论到工程级错误恢复实战

1. 项目概述:为什么“语法”是编译原理里最常被低估的硬核关卡刚接触编译原理的人,十有八九会把注意力全砸在“词法分析”和“语义分析”上——前者像查字典,后者像解数学题,听着就带感;而“语法”这个词,表…

2026/10/19 5:36:25 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →