LangGraph状态管理实战,多轮交互中维护Agent状态
LangGraph状态管理实战多轮交互中维护Agent状态上一篇讲了LangGraph的核心概念。这一篇深入状态管理。状态管理是LangGraph最有价值的功能。Agent执行复杂任务的时候中间会产生大量信息。搜索结果、中间推理、用户偏好、任务进度。这些信息要在多个节点之间共享和更新。状态管理做不好Agent就会健忘。做了前面忘了后面或者信息在不同步骤之间对不上。状态的设计状态设计是第一步。好的状态设计能让工作流清晰高效。设计状态要考虑几个问题。需要存什么信息。把任务执行过程中需要共享的信息都列出来。对话历史、搜索结果、中间结论、任务进度、用户信息。信息之间有没有层级。简单的用扁平结构就行。复杂的可以嵌套。哪些信息是只读的哪些需要更新。只读的不用管需要更新的要想好更新策略。fromtypingimportTypedDict,List,OptionalclassResearchState(TypedDict):# 用户输入topic:str# 研究主题user_level:str# 用户水平初学者/中级/专家# 搜索相关search_queries:List[str]# 搜索关键词列表search_results:List[str]# 搜索结果search_round:int# 搜索轮次# 分析相关key_findings:List[str]# 关键发现summary:str# 总结# 控制流status:str# 当前状态retry_count:int# 重试次数max_retries:int# 最大重试次数这个状态设计覆盖了一个研究Agent需要的所有信息。用户输入、搜索过程、分析结果、控制流分门别类。状态的更新机制LangGraph的状态更新机制是这样的。每个节点返回一个字典只包含要更新的字段。LangGraph会把这个字典合并到当前状态里。defsearch_node(state:ResearchState)-dict:topicstate[topic]round_numstate.get(search_round,0)1# 执行搜索new_resultf第{round_num}轮搜索{topic}的结果# 只返回要更新的字段return{search_results:state[search_results][new_result],search_round:round_num,status:searched,}对于列表类型的字段更新时要手动拼接旧值和新值。state[search_results] [new_result]把新结果追加到旧列表后面。这样写有点麻烦。LangGraph提供了Annotated类型可以自动处理列表的追加。fromtypingimportAnnotatedfromoperatorimportaddclassResearchState(TypedDict):search_results:Annotated[List[str],add]# 自动追加search_queries:Annotated[List[str],add]# 自动追加topic:strsummary:strstatus:strsearch_round:int用了Annotated和add以后节点返回时直接给新值就行LangGraph会自动追加。defsearch_node(state:ResearchState)-dict:new_resultf搜索{state[topic]}的结果# 直接给新值自动追加到现有列表return{search_results:[new_result],search_round:state.get(search_round,0)1,}消息列表的管理对话型Agent的状态里最常见的是消息列表。用户消息、AI消息、工具调用消息都要存。LangGraph提供了add_messagesreducer专门用来管理消息列表。fromtypingimportAnnotated,TypedDictfromlanggraph.graph.messageimportadd_messagesfromlangchain_core.messagesimportHumanMessage,AIMessageclassChatState(TypedDict):messages:Annotated[list,add_messages]user_id:strdefchat_node(state:ChatState)-dict:# 读取所有消息messagesstate[messages]# 调用大模型fromlangchain_openaiimportChatOpenAI llmChatOpenAI(modelgpt-3.5-turbo,temperature0)responsellm.invoke(messages)# 返回AI的回复自动追加到消息列表return{messages:[response]}add_messages会自动处理消息的追加。如果同一条消息被重复添加它还会自动去重。比手动拼接方便多了。多轮对话的状态管理多轮对话是状态管理的典型场景。用户跟Agent来回对话每轮对话都要参考之前的上下文。fromlanggraph.graphimportStateGraph,ENDfromtypingimportAnnotated,TypedDictfromlanggraph.graph.messageimportadd_messagesfromlangchain_core.messagesimportHumanMessage,AIMessage,SystemMessagefromlangchain_openaiimportChatOpenAIclassConversationState(TypedDict):messages:Annotated[list,add_messages]user_name:strtopic_count:int# 对话节点defchat_node(state:ConversationState)-dict:llmChatOpenAI(modelgpt-3.5-turbo,temperature0.7)messagesstate[messages]# 如果知道用户名字加到系统提示里ifstate.get(user_name):system_msgSystemMessage(contentf你是一个友好的助手。用户叫{state[user_name]}。)messages[system_msg]messages responsellm.invoke(messages)return{messages:[response],topic_count:state.get(topic_count,0)1,}# 判断是否结束defshould_continue(state:ConversationState)-str:ifstate.get(topic_count,0)5:returnENDreturnchat# 构建图workflowStateGraph(ConversationState)workflow.add_node(chat,chat_node)workflow.set_entry_point(chat)workflow.add_conditional_edges(chat,should_continue)appworkflow.compile()# 模拟多轮对话resultapp.invoke({messages:[HumanMessage(content你好我叫张三),HumanMessage(content我想聊聊AI Agent),HumanMessage(contentLangChain和LangGraph有什么区别),],user_name:张三,topic_count:0,})# 查看完整的对话历史formsginresult[messages]:role用户ifisinstance(msg,HumanMessage)else助手print(f{role}:{msg.content[:50]}...)状态持久化默认情况下LangGraph的状态存在内存里。程序结束就没了。要想跨会话保持状态需要用持久化存储。LangGraph支持用SQLite做持久化。fromlanggraph.checkpoint.sqliteimportSqliteSaverimportsqlite3# 创建SQLite持久化存储connsqlite3.connect(agent_state.db,check_same_threadFalse)checkpointerSqliteSaver(conn)# 编译时传入checkpointerappworkflow.compile(checkpointercheckpointer)# 运行时指定thread_id不同对话用不同的idconfig{configurable:{thread_id:user_001_session_1}}# 第一轮对话resultapp.invoke({messages:[HumanMessage(content我叫张三)]},configconfig,)# 第二轮对话同一个thread_id能访问之前的状态resultapp.invoke({messages:[HumanMessage(content我叫什么名字)]},configconfig,)# Agent能回答张三因为状态被持久化了用了持久化以后即使程序重启状态也不会丢。下次用同一个thread_id还能接着之前的对话继续。状态的查看和调试开发的时候经常需要查看中间状态。用stream方法可以看到每一步的状态变化。foreventinapp.stream({messages:[HumanMessage(content什么是RAG)],topic_count:0},configconfig,):fornode_name,state_updateinevent.items():print(f节点{node_name}执行完毕)print(f状态更新:{state_update})print()也可以用get_state方法查看当前状态。# 获取当前状态current_stateapp.get_state(config)print(current_state.values)调试的时候把状态打印出来看比猜来猜去高效得多。状态设计的几个建议状态不要太大。状态在节点之间传递太大会影响性能。特别是消息列表聊久了会很长。定期做摘要压缩。状态字段要有明确的语义。别用data1、data2这种名字。用search_results、key_findings这种一看就懂的名字。控制流字段和业务字段分开。status、retry_count这些是控制流用的。search_results、summary这些是业务数据。分开放逻辑更清晰。给状态加默认值。新建状态时给所有字段初始值。避免节点读到None报错。下一篇讲条件分支与循环。让Agent学会思考和重试处理更复杂的任务流程。

相关新闻

终极指南:3分钟掌握跨平台桌面待办工具My-TODOs,彻底告别任务混乱

终极指南:3分钟掌握跨平台桌面待办工具My-TODOs,彻底告别任务混乱

终极指南:3分钟掌握跨平台桌面待办工具My-TODOs,彻底告别任务混乱 【免费下载链接】My-TODOs A cross-platform desktop To-Do list. 跨平台桌面待办小工具 项目地址: https://gitcode.com/gh_mirrors/my/My-TODOs 你是否经常感到任务堆积如山却无…

2026/10/21 9:25:52 阅读更多 →
Transformer推理核心机制拆解:从Attention、GQA、RoPE到KV Cache

Transformer推理核心机制拆解:从Attention、GQA、RoPE到KV Cache

1. 从“黑盒”到“骨架”:为什么我们需要拆解Transformer如果你在2024年还在搞AI,尤其是大模型,那么“Transformer”这个词大概已经听得耳朵起茧了。网上铺天盖地的文章都在说它“颠覆了NLP”、“是GPT的基石”、“Attention is all you need…

2026/10/24 3:02:26 阅读更多 →
过度依赖外部模型,该公司下调 2026 年营收预测三分之一

过度依赖外部模型,该公司下调 2026 年营收预测三分之一

AI 依赖之痛:营收预测下调三分之一据报道,某公司因过度依赖其他提供商的前沿模型来驱动平台上的 AI 功能,将 2026 年的营收预测下调了三分之一。这一举措反映出公司在 AI 发展战略上的困境。自有模型难产:定价与需求的失衡首席执行…

2026/10/21 17:34:21 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/27 17:33:32 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/27 4:06:49 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/27 7:21:53 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/27 18:20:50 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/27 6:20:47 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/27 4:06:50 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 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/27 13:55:19 阅读更多 →
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/27 7:21:50 阅读更多 →
黑夜航拍船只数据集训练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/27 19:19:37 阅读更多 →