【LangChain】存储与管理对话历史

0. 代码演示

from langchain_community.chat_message_histories import SQLChatMessageHistorydef get_session_history(session_id):# 通过 session_id 区分对话历史,并存储在 sqlite 数据库中return SQLChatMessageHistory(session_id, "sqlite:///memory.db")
from langchain_core.messages import HumanMessage
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI
from langchain.schema.output_parser import StrOutputParsermodel = ChatOpenAI(model="gpt-4o-mini", temperature=0)runnable = model | StrOutputParser()runnable_with_history = RunnableWithMessageHistory(runnable, # 指定 runnableget_session_history, # 指定自定义的历史管理方法
)runnable_with_history.invoke([HumanMessage(content="你好,我叫麦酷")],config={"configurable": {"session_id": "wzr"}},
)'你好,麦酷!很高兴再次见到你。有什么想聊的或者需要帮助的呢?'runnable_with_history.invoke([HumanMessage(content="你知道我叫什么名字")],config={"configurable": {"session_id": "wzr"}},
)'是的,你叫麦酷。有什么我可以帮助你的吗?'runnable_with_history.invoke([HumanMessage(content="你知道我叫什么名字")],config={"configurable": {"session_id": "test"}},
)'抱歉,我无法知道你的名字。你可以告诉我你的名字,或者如果你有其他问题,我也很乐意帮助你!'

代码功能解析

这段代码实现了一个带持久化历史记忆的对话系统,通过 session_id 区分不同用户的对话历史,并存储到 SQLite 数据库中。以下是核心模块的解析:


1. 对话历史管理模块

from langchain_community.chat_message_histories import SQLChatMessageHistorydef get_session_history(session_id):# 每个 session_id 对应独立的数据库记录return SQLChatMessageHistory(session_id=session_id, connection_string="sqlite:///memory.db" # SQLite 数据库路径)
  • 核心作用: 为每个用户/会话创建独立的历史存储
  • 技术细节:
    • 使用 SQLite 数据库存储对话记录(文件名为 memory.db
    • session_id 作为主键区分不同对话(如用户ID、设备ID等)
    • 实际表结构包含 id, session_id, message, timestamp 等字段
  • 扩展性:可替换为其他存储后端(如PostgreSQL、Redis)

2. 对话链构建模块

from langchain_core.runnables.history import RunnableWithMessageHistorymodel = ChatOpenAI(model="gpt-4o-mini", temperature=0)
runnable = model | StrOutputParser()  # 基础问答链runnable_with_history = RunnableWithMessageHistory(runnable=runnable,                # 原始链get_session_history=get_session_history, # 历史管理方法input_messages_key="input",       # 输入消息字段名(默认)history_messages_key="history"    # 历史消息字段名(默认)
)
  • 组件连接:
    用户输入
    附加历史
    大模型
    输出解析
    保存历史
  • 关键参数:
    • input_messages_key: 输入消息在上下文中的键名
    • history_messages_key: 历史消息的键名(模型需支持上下文窗口)

3. 对话调用示例

response = runnable_with_history.invoke([HumanMessage(content="你好,我叫麦酷")], # 当前消息config={"configurable": {"session_id": "wzr"}} # 指定会话
)
  • 执行流程:
    1. 根据 session_id="wzr" 从数据库加载历史消息
    2. 将当前消息 "你好,我叫麦酷" 添加到历史记录
    3. 组合历史消息 + 当前输入 → 发送给 GPT-4
    4. 解析模型输出 → 返回最终响应
    5. 将新消息对(用户输入 + 模型回复)保存到数据库

4. 数据库操作示例

假设进行三次连续对话:

调用顺序用户输入数据库存储内容(session_id=“wzr”)
第一次“你好,我叫麦酷”[Human: 你好,我叫麦酷, AI: 回复1]
第二次“记住我的名字了吗?”添加 [Human: 记住我的名字了吗?, AI: 回复2]
第三次“我是谁?”添加 [Human: 我是谁?, AI: 回复3]

模型在第三次调用时,实际接收的上下文包含前两次对话历史,因此能正确回答姓名。


5. 关键技术点

5.1 历史注入机制
# 伪代码展示实际发送给模型的内容
full_context = [{"role": "user", "content": "你好,我叫麦酷"},{"role": "assistant", "content": "回复1"},{"role": "user", "content": "记住我的名字了吗?"},{"role": "assistant", "content": "回复2"},{"role": "user", "content": "我是谁?"}
]
response = model.generate(full_context)
5.2 自动历史管理
  • 自动追加:每次调用自动添加新消息到历史
  • 上下文截断:当历史超过模型窗口时需处理(此示例未展示)

6. 优化建议

6.1 历史长度控制
from langchain.memory import ConversationBufferWindowMemory# 仅保留最近3轮对话
memory = ConversationBufferWindowMemory(k=3)
runnable_with_history.memory = memory
6.2 自定义历史格式
def custom_history_formatter(history):return "\n".join([f"{msg.type}: {msg.content}" for msg in history])chain = runnable_with_history.configure(history_formatter=custom_history_formatter
)
6.3 多模态历史支持
from langchain_core.messages import ImageMessage# 支持图片消息存储
history.add_message(ImageMessage(content="path/to/image.png"))

7. 常见问题排查

现象可能原因解决方案
数据库无写入文件权限问题检查 memory.db 可写权限
历史消息未生效session_id 不一致确认每次调用使用相同 session_id
响应时间越来越长历史消息过多未截断添加窗口记忆或摘要记忆
中文内容存储乱码数据库编码问题使用 sqlite:///memory.db?charset=utf8

8. 典型应用场景

  1. 客服系统

    # 根据用户手机号保持对话连续性
    session_id = user.phone_number
    
  2. 教育机器人

    # 为每个学生保存学习进度
    session_id = f"{student_id}-{course_id}"
    
  3. 多设备同步

    # 通过用户账户实现跨设备同步
    session_id = user.account_id
    

该代码展示了如何快速构建具备长期记忆能力的对话系统,通过简洁的接口实现复杂的状态管理,是开发智能对话应用的基石。

通过 LCEL,还可以实现

  1. 配置运行时变量:https://python.langchain.com/v0.2/docs/how_to/configure/
  2. 故障回退:https://python.langchain.com/v0.2/docs/how_to/fallbacks
  3. 并行调用:https://python.langchain.com/v0.2/docs/how_to/parallel/
  4. 逻辑分支:https://python.langchain.com/v0.2/docs/how_to/routing/
  5. 动态创建 Chain: https://python.langchain.com/v0.2/docs/how_to/dynamic_chain/

更多例子:https://python.langchain.com/v0.2/docs/how_to/lcel_cheatsheet/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/897096.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从0开始的操作系统手搓教程21:进程子系统的一个核心功能——简单的进程切换

目录 具体说说我们的简单RR调度 处理时钟中断处理函数 调度器 schedule switch_to 我们下面,就要开始真正的进程切换了。在那之前,笔者想要说的是——我们实现的进程切换简单的无法再简单了——也就是实现一个超级简单的轮询调度器。 每一个进程按照…

mysql新手常见问题解决方法总结

1. 安装与配置问题 1.1 无法安装MySQL Server MySQL Server安装失败是新手常见的问题之一,以下是具体原因及解决方案: 系统要求不满足:MySQL对操作系统有最低版本要求,如Windows 7 SP1及以上、macOS 10.13及以上。若系统版本过…

数字组合(信息学奥赛一本通-1291)

【题目描述】 有n个正整数,找出其中和为t(t也是正整数)的可能的组合方式。如:n5,5个数分别为1,2,3,4,5,t5;那么可能的组合有514和523和55三种组合方式。 【输入】 输入的第一行是两个正整数n和t,用空格隔开&#xff0c…

搜索引擎(基于java在线文档)

背景: 基于java文档的搜索引擎,可以输入搜索词,然后就可以查询出与搜索词相关的文档。该项目的最主要的工作是要构建索引,就是正排和倒排索引。正排索引:根据文档id获取到文档;倒排索引:根据搜…

【每日学点HarmonyOS Next知识】web滚动、事件回调、selectable属性、监听H5内部router、Grid嵌套时高度设置

【每日学点HarmonyOS Next知识】web滚动、事件回调、selectable属性、监听H5内部router、Grid嵌套时高度设置 1、HarmonyOS WebView加载url无法滚动? scroll 里面嵌套webView,demo参考: // xxx.ets import web_webview from ohos.web.webv…

Flink性能指标详解MetricsAnalysis

文章目录 Flink 组成1.JobManager2.TaskManager3.ResourceManager4.Dispatcher5.Client6. Env JobManager MetricsTaskManager Metrics Flink 组成 1.JobManager 管理任务 作业调度:负责接收和调度作业,分配任务到 TaskManager。资源管理:…

Flutter底层实现

1. Dart 语言 Dart 是 Flutter 的主要编程语言。Dart 设计之初就是为了与 JavaScript 兼容,并且可以编译为机器代码运行。Dart 提供了一些特性,如异步支持(通过 async 和 await),这使得编写高效的网络请求和复杂动画变…

< 自用文儿 > CertBot 申请 SSL 证书 使用 challenge 模式 避开防火墙的阻挡

环境: 腾讯 VPS 腾讯会向你销售 SSL , 这个本是免费的。CertBot 默认申请证书要用到 80 端口,会蹭边什么什么条款,备案法律来阻止80端口的通讯,没有网站也一样被阻拦。 通过腾讯买的域名: bestherbs.cn …

【AI】【Unity】关于Unity接入DeepseekAPI遇到的坑

前言 由于deepseek网页端在白天日常抽风,无法正常的使用,所以调用API就成了目前最好的选择,尤其是Deepseek的API价格低得可怕,这不是和白送的一样吗!然后使用过很多本地部署接入API的方式,例如Chatbox、Pa…

【微知】Mellanox驱动中to是什么?有哪些超时时间?(time out,心跳2s,reset 1分钟)

to是tout缩写,tout是time out 单位是毫秒。 static const u32 tout_def_sw_val[MAX_TIMEOUT_TYPES] {[MLX5_TO_FW_PRE_INIT_TIMEOUT_MS] 120000, # 2min。预初始化的总超时时间[MLX5_TO_FW_PRE_INIT_ON_RECOVERY_TIMEOUT_MS] 7200000, #设备恢复过程中的固件预初…

linux | Vim 命令快捷操作

注:本文为过去的 “vim 使用笔记”。 跳转命令 跳转命令 #:向前查找光标当前所在单词,并跳转到该单词的上一个出现位置。*:向后查找光标当前所在单词,并跳转到该单词的下一个出现位置。 行内跳转 0:跳转…

树莓派3B+的初步使用

树莓派3B的初步使用 一、安装使用树莓派系统1.将系统写入SD卡2.登录树莓派系统3.用C和Python编译运行hello world 一、安装使用树莓派系统 1.将系统写入SD卡 首先,准备至少16GB大小的SD卡以便装入树莓派系统,将SD卡插入读卡器后连接电脑准备给SD卡写入…

基于Windows11的DockerDesktop安装和布署方法简介

基于Windows11的DockerDesktop安装和布署方法简介 一、下载安装Docker docker 下载地址 https://www.docker.com/ Download Docker Desktop 选择Download for Winodws AMD64下载Docker Desktop Installer.exe 双点击 Docker Desktop Installer.exe 进行安装 测试Docker安装是…

文档处理控件Aspose.Total教程:使用 C# 将 Obsidian Markdown 转换为 OneNote

Obsidian 是一款广泛使用的基于 Markdown 的笔记应用程序。它提供了一种强大而有效的方式来构建和组织想法。用户可以无缝地连接他们的想法,提高清晰度和工作效率。另一方面,OneNote 是 Microsoft 的一款功能强大的笔记应用程序。它还可以帮助用户组织他…

第5章:vuex

第5章:vuex 1 求和案例 纯vue版2 vuex工作原理图3 vuex案例3.1 搭建vuex环境错误写法正确写法 3.2 求和案例vuex版细节分析源代码 4 getters配置项4.1 细节4.2 源代码 5 mapState与mapGetters5.1 总结5.2 细节分析5.3 源代码 6 mapActions与mapMutations6.1 总结6.2…

迷你世界脚本对象库接口:ObjectLib

对象库接口:ObjectLib 迷你世界 更新时间: 2023-04-26 20:21:09 具体函数名及描述如下: 序号 函数名 函数描述 1 getAreaData(...) 获取区域数据 2 getPositionData(...) 获取位置数据 3 getLivingData(...) 获取生物数据 4 getItemDat…

测试是如何跟进和管理 bug

测试在跟进和管理 Bug定位精确、问题反馈及时、修复闭环高效 三大关键环节中起到了至关重要的作用。Bug定位精确 是整个流程的基础,通过详细记录和复现问题,可以帮助开发团队迅速找出缺陷根源;而及时有效的反馈机制则确保问题不会被遗漏&…

运动控制卡--固高实用

目录 组件 配置参数 编程控制 组件 我手头有固高卡,记录使用。 用运动控制卡 伺服(步进)电机搭建一个运动控制系统,主要包括:1、控制器 2、端子板 1、控制器 2、端子板 3、伺服(步进)…

2025年能源工作指导意见

2025年是“十四五”规划收官之年,做好全年能源工作意义重大。为深入贯彻落实党中央、国务院决策部署,以能源高质量发展和高水平安全助力我国经济持续回升向好,满足人民群众日益增长的美好生活用能需求,制定本意见。 一、总体要求…

键值对(C++实现)

目录 键值对的定义 键值对的底层实现 键值对的作用 键值对的使用 对键值对中的值的搜索 一、键值对的定义 键值对(Key-Value Pair)是一种数据结构,用于存储和表示两个相关联的值。在键值对中,一个值被关联到一个唯一的键上&…