大模型之LangGraph多轮对话记忆
用 LangGraph 的 Reducer轻松搞定多轮对话记忆做聊天机器人最头疼的是什么是记不住上文。今天分享一个 LangGraph 的小技巧用 Reducer 机制优雅地管理对话历史。核心只有一行代码messages: Annotated[Sequence[AnyMessage], operator.add]这里的 operator.add 就是 Reducer归约器。它的妙处在于节点函数只需返回新增的消息LangGraph 会自动把旧历史和新消息拼接起来不用手动维护完整列表代码瞬间清爽。另一个容易踩坑的点图里定义的 END 只是本次流程的终点不是程序终点。多轮对话要靠外层 while 循环驱动每次 invoke 后用返回的 result 更新 state再传回下一轮历史就自然延续了。最后附上一个小实践调用模型时只取最近 6 条消息作为上下文既保证连贯性又控制了 token 成本。Reducer 截断窗口 外层循环三件套齐活一个专业级多轮对话系统就搭好了。代码# -*- coding: utf-8 -*- 基于 LangGraph 构建的多轮对话系统示例 核心知识点 1. 使用 Annotated operator.add 作为 Reducer实现消息历史的自动合并累加 2. 图的每次 invoke 是一次独立执行END 只是本次流程的终点外层 while 循环负责多轮对话 3. 通过不断用返回的 result 更新 state实现跨轮次的消息历史保留 from typing import TypedDict, Annotated, Sequence from langchain_core.messages import HumanMessage, AIMessage, BaseMessage, SystemMessage, AnyMessage from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, END import operator import os from dotenv import load_dotenv # 加载 .env 文件中的环境变量如 API Key、Base URL load_dotenv() # 初始化大语言模型客户端兼容 OpenAI 接口协议这里对接阿里云百炼的 deepseek-v3 model ChatOpenAI( model_namedeepseek-v3, api_keyos.getenv(DASHSCOPE_API_KEY), base_urlos.getenv(API_BASE_URL) ) # 类型定义 class ChatState(TypedDict): 对话状态定义 Annotated[Sequence[AnyMessage], operator.add] 中的 operator.add 是 Reducer归约器 - 节点返回 {messages: [新消息]} 时LangGraph 不会覆盖旧消息 而是自动执行 旧消息 新消息 的拼接实现历史记录的累加 - 这就是为什么节点函数只需返回增量消息而不用手动拼接完整历史 messages: Annotated[Sequence[AnyMessage], operator.add] # 自动合并消息的历史记录 # 节点函数1 def handle_user_input(state: ChatState): 处理用户输入节点从控制台读取用户输入封装成 HumanMessage try: print(fhandle_user_input_node state:{state}) user_input input(\n用户输入输入退出结束: ).strip() # 用户输入退出时返回 END提前终止本次图流程跳过 ai_response 节点 if user_input.lower() 退出: print(正在结束对话...) return END # 注意借助 Reduceroperator.add这里只需返回新增的消息即可 # LangGraph 会自动将其与 state 中的历史消息合并。 # 若没有 Reducer则需要手动写 state[messages] [HumanMessage(...)] 来覆盖整个列表 return {messages: [HumanMessage(contentuser_input)]} except KeyboardInterrupt: # 用户按 CtrlC 中断时同样优雅退出本次图流程 return END # 节点函数2 def generate_ai_response(state: ChatState): 生成AI响应节点取最近几条消息作为上下文调用模型生成回复 try: print(fgenerate_ai_response_node state:{state}) # 只取最近 6 条消息作为上下文截断窗口 # 既保持对话连贯性又控制 token 消耗、避免超出模型上下文长度 recent_history state[messages][-6:] response model.invoke(recent_history) # 返回一个 AIMessage 对象 print(模型答复,response) # 返回增量消息由 Reducer 自动追加到历史中 return {messages: [response]} except Exception as e: # 调用失败网络异常、鉴权失败等时不中断程序 # 而是生成一条兜底的错误提示消息保证图流程能正常走完 error_msg f系统暂时无法响应请稍后再试错误代码{str(e)[:30]}) return {messages: [AIMessage(contenterror_msg)]} # 对话图构建 builder StateGraph(ChatState) # 节点注册将节点函数挂载到图上指定节点名称 builder.add_node(user_input, handle_user_input) builder.add_node(ai_response, generate_ai_response) # 流程设计入口 - 用户输入 - AI响应 - 结束 builder.set_entry_point(user_input) builder.add_edge(user_input, ai_response) builder.add_edge(ai_response, END) # 编译图得到可执行invoke / stream的对话应用 conversation builder.compile() # 运行逻辑 if __name__ __main__: # 系统提示词对话历史中的第一条消息为模型设定角色 system_prompt f 你是一个专业级中文智能助手 # 初始状态只包含系统消息后续历史由 Reducer 自动累加 state ChatState(messages[SystemMessage(contentsystem_prompt)]) print( 智能对话系统已启动 ) print(输入退出可随时结束对话\n) 关键机制说明 1、每次调用 conversation.invoke(state) 都是一次独立的调用 虽然图流程定义了 END但图本身不会阻止下一次调用。 2、状态 state 会持续更新每次执行完 conversation.invoke(state) 后 返回的 result 会更新 state从而保留了对话历史。 当下次调用 invoke 时传入的是更新后的 state因此对话可以继续。 3、END 只是图流程的结束点不是程序的终止点 END 只是告诉 LangGraph 当前流程已结束但并不会终止外部的 while 循环。 # 外层 while 循环负责多轮对话每轮执行一次完整的图流程 while True: try: # 执行一次图流程user_input - ai_responseinvoke 返回执行后的完整状态 result conversation.invoke(state) print(图执行一次后,result) # 异常防御返回结果为空或缺少 messages 字段时退出循环 if result is None or messages not in result: break # 提取本轮新增的消息 # 由于 Reducer 是追加语义result 中前面部分就是调用前的旧历史 # 从旧历史长度开始的切片即为本次流程新产生的消息HumanMessage AIMessage new_messages result[messages][len(state[messages]):] # 打印本轮 AI 响应跳过用户新输入的 HumanMessage for msg in new_messages: if isinstance(msg, AIMessage): print(f\n【AI响应】\n{msg.content}\n) # 更新对话状态用包含完整历史的 result 替换旧 state # 下一轮循环将其传回 invoke实现跨轮次的历史延续 state result # 检查退出条件历史中出现内容为退出的用户消息时结束循环 # 正常情况下输入退出时节点会直接返回 END 不会进入 ai_response # 这里是双保险 if any(isinstance(m, HumanMessage) and m.content.lower() 退出 for m in state[messages]): break except Exception as e: # 捕获图执行过程中的其他异常打印后退出避免程序崩溃 print(f\n系统异常{str(e)}) break # 对话结束后的收尾打印完整对话记录 print(\n 对话已结束 ) print(\n【完整对话记录】) # state[messages][1:] 跳过第一条系统提示只展示用户与 AI 的往来消息 for i, msg in enumerate(state[messages][1:]): prefix 用户 if isinstance(msg, HumanMessage) else AI print(f{i 1}. {prefix}{msg.content})学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%免费】

相关新闻

免费三步:老 Mac 升级最新 macOS

免费三步:老 Mac 升级最新 macOS

免费三步:老 Mac 升级最新 macOS 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 一台 2015 年的 MacBook Pro,App Store 早就不给推送…

2026/10/14 3:07:32 阅读更多 →
PySide2工具栏与状态栏实战:QToolBar和QStatusBar高效开发指南

PySide2工具栏与状态栏实战:QToolBar和QStatusBar高效开发指南

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

2026/10/14 3:06:32 阅读更多 →
Hadoop+Spark+Python构建商品推荐系统:ALS实战与避坑指南

Hadoop+Spark+Python构建商品推荐系统:ALS实战与避坑指南

看到这个标题,我第一反应是:又一个把推荐系统和大数据技术绑在一起搞的项目。这类项目近几年在校招项目、公司内部数据组、甚至中小电商后台都特别常见,因为它刚好踩中了两个痛点——单机跑不动海量日志,纯规则做不出个性化。Hado…

2026/10/14 3:06:32 阅读更多 →

最新新闻

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

简介:面向 YOLOv11 模型验证需求,这份精简版鸟类目标检测数据集包含一张真实野外鸟类图像及配套标准标注,可用于快速原型验证、轻量级部署测试与小样本检测基线建立。压缩包共五个文件,包含三张 JPG 图像、一个数据配置文件与一个…

2026/10/14 3:39:38 阅读更多 →
ASP.NET + SQLServer葡萄酒商城源码:从数据库还原到下单事务全攻略

ASP.NET + SQLServer葡萄酒商城源码:从数据库还原到下单事务全攻略

简介:一套基于ASP.NET与SQL Server的葡萄酒网上商城销售系统,面向ASP.NET WebForm学习者、毕业设计学生以及需要搭建在线商城教学演示的开发者。系统围绕普通会员、商户会员和管理员三类角色展开,覆盖商品管理、购物车、订单处理、发货、商户…

2026/10/14 3:39:38 阅读更多 →
LangChain项目代码拆解:Chain、Agent、Memory与Retrieval四大核心组件实战指南

LangChain项目代码拆解:Chain、Agent、Memory与Retrieval四大核心组件实战指南

简介:这是一份LangChain入门与实践的项目代码包,面向正在学习大模型应用开发的Python开发者,旨在帮助读者快速理解LangChain的模块化设计与核心用法。包内共3个文件,包含一个HTML格式的入门讲解页、一个项目运行配置文件以及一个版…

2026/10/14 3:39:38 阅读更多 →
C++学习日记 Day21:C++11(下)lambda表达式和function包装器

C++学习日记 Day21:C++11(下)lambda表达式和function包装器

## 今天学了什么今天学习C11的lambda表达式和function包装器。## 可调用对象概念:在C中有一类对象可像函数一样调用;分类:①函数指针using prt void(*)(int, string); prt f1 fun; f1(1, "函数指针");②仿函数 --有 operator&am…

2026/10/14 3:39:38 阅读更多 →
一人公司AI工作流:6步实现内容生产去体力化

一人公司AI工作流:6步实现内容生产去体力化

1. 一人公司的内容困局与破局思路一个人做内容,最怕的不是没灵感,而是灵感来了却卡在“执行”上。写一篇长文要三小时,做一张配图要半小时,剪一条短视频要一整个下午,排版发布又要来回切换四五个平台。一天下来&#x…

2026/10/14 3:39:38 阅读更多 →
8765平台前后摄DVDD电压不一致排查与修复指南

8765平台前后摄DVDD电压不一致排查与修复指南

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

2026/10/14 3:38:38 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →