当前位置: 首页 > news >正文

[智能体-233]:传统的基于LLMchain langchain与基于LCEL langchain,在已定义的chain基础之上增加记忆功能的方式上的区别?

一、核心结论先行

  1. 传统 LLMChain记忆是链的内置属性创建链时直接注入,强耦合记忆和链绑定死,后期难以动态增删、局部启用。
  2. LCEL:记忆是外层包装能力,原有纯业务链路完全不变,解耦独立;支持动态包装、局部加记忆、多套记忆混用。

二、传统 LLMChain:构造函数注入记忆(内置绑定)

1. 完整写法

记忆组件(Memory)作为初始化参数,在创建LLMChain实例时一并传入,链路与记忆从一开始就绑定。

python

运行

from langchain.chains import LLMChain from langchain.prompts import PromptTemplate from langchain_openai import ChatOpenAI from langchain.memory import ConversationBufferMemory # 1. 基础组件 llm = ChatOpenAI() prompt = PromptTemplate( input_variables=["history", "input"], template="历史对话:{history}\n用户:{input}\n助手:" ) # 2. 定义记忆 memory = ConversationBufferMemory(memory_key="history") # 3. 关键:创建 LLMChain 时,直接把 memory 传入构造方法 !!! llm_chain = LLMChain(llm=llm, prompt=prompt, memory=memory) # 4. 调用(无需手动传 history,链内部自动读写记忆) res1 = llm_chain.invoke({"input": "你好"}) res2 = llm_chain.invoke({"input": "刚才我说了什么?"})

2. 核心特点

  • 绑定时机:实例化阶段一次性绑定,无法后期动态解绑 / 替换
  • 数据流转history由 Chain 内部自动从 Memory 读取、自动写入,属于黑盒逻辑
  • 耦合度:链 ↔ 记忆 强耦合,一条链只能绑定唯一一个 Memory 实例
  • 多会话:需手动创建多个独立LLMChain + Memory组合,代码冗余。
  • 局限性
    • 不能只给 “链路某一段” 加记忆,整条链统一生效;
    • 想临时关闭记忆,必须重新创建不带 memory的新链实例。

三、LCEL 方式:外层包装追加记忆(解耦外挂)

LCEL 原生链路(prompt | llm完全无状态、无记忆,通过RunnableWithMessageHistory对已有链路做二次包装,实现记忆能力。原有业务链路代码一行不用改。

1. 完整写法

python

运行

from langchain_core.prompts import PromptTemplate from langchain_openai import ChatOpenAI from langchain_core.runnables.history import RunnableWithMessageHistory from langchain_community.chat_message_histories import ChatMessageHistory # 1. 先定义【纯业务链路】(无任何记忆,可单独复用) llm = ChatOpenAI() prompt = PromptTemplate( input_variables=["history", "input"], template="历史对话:{history}\n用户:{input}\n助手:" ) # 基础链:纯逻辑,无记忆 base_chain = prompt | llm # 2. 定义会话存储与历史读取规则(记忆逻辑独立) session_store = {} def get_history(session_id: str) -> ChatMessageHistory: if session_id not in session_store: session_store[session_id] = ChatMessageHistory() return session_store[session_id] # 3. 关键:在已有 chain 外层包装,追加记忆能力 chain_with_memory = RunnableWithMessageHistory( runnable=base_chain, # 传入已定义好的原始链,记忆是基于此进行包装 get_session_history=get_history, ## 支持基于session的记忆,记忆体是外部定义的session_store input_messages_key="input", # 与原始链的用户输入变量关联 history_messages_key="history" # 与原始链的history变量关联 ) # 4. 调用:通过 session_id 自动隔离会话、读写记忆 res1 = chain_with_memory.invoke( {"input": "你好"}, config={"configurable": {"session_id": "user1"}} ) res2 = chain_with_memory.invoke( {"input": "刚才我说了什么?"}, config={"configurable": {"session_id": "user1"}} )

2. 核心特点

  • 绑定时机:链路创建完成后动态包装记忆和业务逻辑彻底分离
  • 数据流转:历史消息读取、拼接、回写全部显式可控,可拦截、改写。
  • 耦合度:完全解耦:
    • 原始base_chain可单独使用(无记忆模式);
    • 可给同一条基础链,包装多套不同记忆规则。
  • 多会话原生依靠session_id做会话隔离,天然适配多用户、多会话。
  • 灵活性
    1. 临时关闭记忆:直接调用原始base_chain即可,无需新建实例;
    2. 局部记忆:仅对链路中某一个子 Runnable单独包装,实现局部状态;
    3. 替换记忆存储:只修改get_history函数,业务链不动。

四、关键差异点对点对比

表格

对比维度传统 LLMChain + MemoryLCEL +RunnableWithMessageHistory
接入位置构造函数参数,创建链时绑定外层包装,链定义完成后追加
耦合关系强耦合,链与记忆绑定为整体完全解耦,业务链、记忆相互独立
启用 / 关闭记忆需新建不同实例,无法动态切换切换调用「原链 / 包装后链」即可
会话隔离手动维护多组 Chain+Memory,繁琐原生session_id隔离,开箱即用
作用范围整条链统一生效,不支持局部记忆

可对单个节点 / 子链路单独加记忆

可任何被包装的链进行记忆。

记忆读写逻辑内部黑盒,无法干预全流程透明,可自定义拦截、改写
复用性带记忆的链无法拆分为无记忆链路基础链可反复复用,按需加记忆

五、拓展场景对比(直观体现差距)

场景 1:同一条链路,交替使用「有记忆 / 无记忆」

  • 传统 LLMChain:必须创建两个实例

    python

    运行

    # 无记忆 chain_no_mem = LLMChain(llm=llm, prompt=prompt) # 有记忆 chain_with_mem = LLMChain(llm=llm, prompt=prompt, memory=memory)
  • LCEL:只写一条基础链,按需选择调用对象

    python

    运行

    # 无记忆:调用 base_chain base_chain.invoke(...) # 有记忆:调用包装后的链 chain_with_memory.invoke(..., config=...)

场景 2:仅给复杂链路中的某一段加记忆

  • 传统 LLMChain 体系:几乎无法实现,所有组合链全局共用一套记忆。
  • LCEL:天然支持局部包装

    python

    运行

    # 整条链路:A → 带记忆的B → C part_b_with_mem = RunnableWithMessageHistory(part_b, get_history) # RunnableWithMessageHistory,被包装后,该链与其他链一同对等,进行组合, full_chain = part_a | part_b_with_mem | part_c

六、一句话总结

  1. 传统 LLMChain:记忆是链的一部分,造链的时候就把记忆 “装进去”,一体成型,改不了、拆不开;
  2. LCEL:记忆是附加功能壳子,原有链路保持纯粹,想加记忆就外层包一层,想去掉就直接用原链路,灵活、解耦、易维护。
http://www.jsqmd.com/news/946300/

相关文章:

  • 示波器函数/任意波形发生器直流电源 | SiC/GaN 宽禁带半导体器件动态特性测试
  • 磁盘寻道时间计算与调度算法(FCFS、SSTF、SCAN、C-SCAN)
  • 计算机毕业设计之基于推荐的系统的新闻阅读平台的设计与实现
  • 从传感器延迟到坐标变换:深入拆解Lidar与IMU标定的核心难题
  • 规范与约束:抽象类与接口核心学习笔记
  • WinCC数据备份避坑指南:用VBS脚本搞定OnlineTableControl周期性导出CSV(附解决‘文件已存在’弹窗方法)
  • 别再只会用LM2596降压了!手把手教你搭建一个可调恒压恒流电源(附完整电路图)
  • 避坑指南:Verilog写BMP图片时多出0D字节?详解‘wb+’与‘w+’模式的区别
  • AutoJs Pro 7.0.4-1 保姆级脚本实战:从零写一个快手极速版自动化脚本(附完整源码)
  • 保姆级教程:在ROS1/ROS2中配置AMCL参数,让机器人定位又快又准
  • 大数据量高并发的数据库优化
  • 终极指南:5个简单步骤使用MediaCreationTool.bat轻松安装Windows 11,完整绕过硬件限制
  • AI编程智能体协作失败:两个模型合作效果不如一个
  • AUTOSAR SPI实战避坑:从SyncTransmit阻塞到AsyncTransmit回调,你的车规级通信选对了吗?
  • 多层组织光传输仿真工具:支持自定义参数与三类光学响应输出
  • 找好用的倒计时AE模版?11个优质站点帮你省创作时间
  • unity项目文件拷贝
  • 1.3 OrCAD 原理图导 PCB 报错,为什么总提示不匹配的封装?I 芯巧Cadence快问快答系列-操作锦囊
  • 如何快速掌握DankDroneDownloader:无人机固件管理完整指南
  • 3分钟掌握百度文库文档纯净打印技巧:告别广告干扰,专注内容获取
  • 避坑指南:树莓派连接PX4时遇到的‘serial0: receive: End of file’错误全解析与解决
  • 别再为缺失的交通数据发愁了!手把手教你用Python实现TAS-LR时空数据重建
  • Switch 2 屏幕保护膜推荐:多款产品对比,总有一款适合你!
  • STM32F103 DAC输出不稳定?排查这几点让你的模拟电压更精准(附ADC闭环验证)
  • 告别CH340!用STM32F103C8T6的USB虚拟串口实现稳定通信(附完整工程源码)
  • 2026年知名的上海排烟窗/三角型排烟窗/电动排烟窗口碑好的厂家推荐 - 行业平台推荐
  • 别再浪费性能了!ESXi硬盘控制器直通实战,让虚拟机磁盘IO飞起来
  • 用泡沫芯材DIY战斗机器人:低成本入门机器人制作全攻略
  • 2026年靠谱的深圳整厂打包回收/深圳闲置设备回收/深圳厂房拆除回收高口碑品牌推荐 - 品牌宣传支持者
  • 终极指南:如何在VS Code中高效开发现代Fortran科学计算项目