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

如何通过LangChain实现记忆功能的总结

真正贴近人类的智能体,关键在于拥有 “记忆能力”。就像人与人相处时,我们会记住对方的喜好、过往的交流细节,并以此调整后续的沟通方式;具备记忆的智能体,同样能在与用户的互动中,主动留存对话信息、记录关键需求,甚至沉淀用户偏好,进而在未来的交互中给出更精准、更贴心的响应。
本篇实践指南,就将聚焦如何基于 Langchain 框架,一步步打造出具备记忆能力的智能体。从记忆机制的设计逻辑,到具体的技术实现细节,带你解锁智能体 “记住” 用户的关键能力,让你的 AI 应用真正拥有 “温度”。

一、无记忆的对话

这种无记忆的对话就像一位左耳进右耳出的小傻瓜,你问到“我上一句说的什么”的时候,他就胡乱的回答你。

示例代码:

import osimport dotenv
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAIdotenv.load_dotenv()prompt = ChatPromptTemplate.from_messages([("system", "你是一位幽默、话少的聊天助手,请用简短幽默的语言回答用户提问"),("human", "{query}")
])llm = ChatOpenAI(model="qwen-max",base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",api_key=os.getenv("TONGYI_KEY"))chain = prompt | llmwhile True:query = input("Human: ")if query == "q":exit(0)resp = chain.stream({"query": query})print("AI: ", flush=True, end="")ai_content = ""for r in resp:ai_content += r.contentprint(r.content, flush=True, end="")print("\n")

输出结果:

Human: 你好,我是小黑,是一名全栈程序员,我主要使用的开发语言有C#、python、js。
AI: 你好,小黑!全栈程序员啊,那你肯定是个“多面手”了。C#、Python、JS,这组合听起来就像是编程界的“摇滚乐队”,你就是那个能演奏多种乐器的超级明星!Human: 我是谁?
AI: 你就是那个在镜子里最好看的人啊!但具体是谁,我这还真的猜不出来。Human: 上一句我说的什么
AI: 你上一句说的是:“上一句我说的什么?” 我猜你可能是想考考我的记忆力?哈哈,我可是过了科目二的哦!

二、利用对话列表增加记忆能力

通过“无记忆的对话”测试,我发现要解决记忆问题是不是可以简单的将原有对话列表拼接后丢给大模型,于是我果断升级代码。

示例代码:

import osimport dotenv
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAIdotenv.load_dotenv()chat_list = []prompt = ChatPromptTemplate.from_messages([("system", "你是一位幽默、话少的聊天助手,请用简短幽默的语言回答用户提问"),MessagesPlaceholder("chat_histories"),("human", "{query}")
])llm = ChatOpenAI(model="qwen-max",base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",api_key=os.getenv("TONGYI_KEY"))chain = RunnablePassthrough.assign(chat_histories=lambda x: chat_list
) | prompt | llmwhile True:query = input("Human: ")if query == "q":exit(0)resp = chain.stream({"query": query})print("AI: ", flush=True, end="")ai_content = ""for r in resp:ai_content += r.contentprint(r.content, flush=True, end="")print("\n")chat_list.append(HumanMessage(content=query))chat_list.append(AIMessage(content=ai_content))

输出结果:

Human: 你好,我是小黑,是一名全栈程序员,我主要使用的开发语言有C#、python、js。
AI: 嘿,小黑,程序员界的“全栈大厨”啊!C#、Python、JS,这组合就像是厨房里的刀叉勺,啥菜都能做。下次电脑出问题我直接找你得了,全能选手!Human: 我是谁?
AI: 你不是刚刚说你是小黑吗?难道你已经变身成超人了,连自己都不认识了? 😄Human: 重庆最出名的是什么
AI: 重庆最出名的当然是火锅和魔幻的地形了!吃着麻辣火锅,一边爬坡上坎,那感觉就像在玩现实版的“极限挑战”!Human: 上一句我说的什么
AI: 上一句你问的是重庆最出名的是什么。看来你的记忆力比我的代码调试速度还快啊! 😄

上面代码利用chat_list存储了人类和AI的对话内容,在每次人类发起提问的时候通过chat_histories组装到prompt中,最近将整个prompt交给LLM,这样LLM就拿到了对话上下文信息,就能根据人类的提问给出准确的回答。

三、利用摘要增加长期记忆

通过“利用对话列表增加记忆能力”的测试,我发现记忆确实有了,但又来了一个新的问题,我这样持续拼接下去总有一天会超过大模型的上下文长度,因此就引出了利用摘要能力实现长期记忆。

示例代码:

import os
from typing import List, Anyimport dotenv
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAIdotenv.load_dotenv()chat_list = []
summary = ""
summary_prompt = """结合新的会话内容和之前的总结内容返回一个新的总结,并确保新总结的长度不要超过800个字符,尽可能保持简洁。EXAMPLE
当前总结:
人类询问 AI 对天气的看法。AI 认为天气影响着人们的日常活动和心情。新的会话:
Human: 为什么你觉得天气会影响人们的日常活动和心情呢?
AI: 天气晴朗时,阳光明媚,温度宜人,人们更愿意外出游玩、运动或者进行社交活动,心情也会随之变得愉悦。而遇到下雨天,出行会变得不便,一些室外活动不得不取消,人们可能就只能待在室内,心情也容易变得压抑。寒冷的天气可能让人不想出门,温暖舒适的天气则会让人感到放松和惬意 ,所以天气对人们的日常活动和心情影响显著。新的总结:
人类询问 AI 对天气的看法,AI 认为天气影响着人们的日常活动和心情,因为不同天气状况会改变人们出行、活动的意愿,进而影响心情。
END OF EXAMPLE当前总结:
{summary}新的会话:
{new_conversation}新的总结:"""system_prompt_template = """你是一位幽默、话少的聊天助手,请用简短幽默的语言回答用户提问
<摘要记忆>
{long_memory}
</摘要记忆>
"""prompt = ChatPromptTemplate.from_messages([MessagesPlaceholder("chat_histories"),("human", "{query}")
])llm = ChatOpenAI(model="qwen-max",base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",api_key=os.getenv("TONGYI_KEY"))def generate_summary(human_message, ai_message):summary_chain = ChatPromptTemplate.from_template(summary_prompt) | llmnew_summary_message = summary_chain.invoke({"summary": summary,"new_conversation": f"Human: {human_message} \nAI: {ai_message}"})return new_summary_message.contentdef preset_history_message() -> List[Any]:_histories = []_histories.append(SystemMessage(system_prompt_template.format(long_memory=summary)))for msg in chat_list:_histories.append(msg)return _historieschain = RunnablePassthrough.assign(chat_histories=lambda x: preset_history_message()
) | prompt | llmwhile True:query = input("Human: ")if query == "q":exit(0)resp = chain.stream({"query": query})print("AI: ", flush=True, end="")ai_content = ""for r in resp:ai_content += r.contentprint(r.content, flush=True, end="")print("\n")chat_list.append(HumanMessage(content=query))chat_list.append(AIMessage(content=ai_content))summary = generate_summary(query, ai_content)if len(chat_list) > 4:del chat_list[0:2]

输出结果:

Human: 你好,我是小黑,是一名全栈程序员,我主要使用的开发语言有C#、python、js。
AI: 嘿,小黑!全栈程序员啊,那你肯定是个多面手,C#、Python、JS样样精通。你这是要代码拯救世界吗?😎💻Human: 中国的地理位置
AI: 中国啊,那可是位于亚洲东部,东临太平洋,西靠喜马拉雅山脉,北接蒙古和俄罗斯,南边还有东南亚各国。简单说,就是在地图上那个大公鸡形状的地方!啼鸣一声,四邻皆惊的那种!🐓🌍Human: 重庆在那个地区
AI: 重庆啊,那可是咱们中国的“火锅之城”,位于西南地区,就在大公鸡的“大腿”那儿!辣得你直跳脚的那种地方!🌶️这个地图上的位置,吃了麻辣火锅你就记住了!Human: 小黑是谁?
AI: 小黑啊,他可是个全栈程序员高手,精通C#、Python和JavaScript。简直就是代码界的“三栖明星”!💻🌟

这次我在“对话列表增加记忆能力”的基础上增加generate_summary和preset_history_message两个主要方法。
generate_summary:实现根据以前的摘要和最后一轮对话信息生成新的摘要内容,并保存到summary变量上
preset_history_message:实现将摘要内容和系统提示词的拼接,以及对最近两轮对话消息进行拼接,以实现长短期记忆的效果

四、在Agent中整合记忆能力

上述代码只简单实现了从“无记忆”到“对话列表增加记忆”,再到“利用摘要增加长期记忆”的测试,如果要实现具备记忆的智能体考虑的细节还有很,如摘要和对话消息如何存储、摘要如何总结更为合理和准确、短期记录信息拼接多少条等。推荐一个可供学习和交流的Agent在线编排管理平台,源码地址:https://github.com/tiny-rep/ai_agent。下图就是Ai Agent平台对记忆能力的整合。

ai_20250913_01

http://www.wxhsa.cn/company.asp?id=2752

相关文章:

  • python 轻量级别的网页包Streamlit
  • 完整教程:技术小白如何快速的了解opentenbase?--把握四大特色
  • 9.13日模考总结
  • 高斯消元
  • wpf-MVVM+IOC/ID
  • uni-app iOS 性能监控全流程 多器具协作的实战优化指南
  • 矩阵快速幂
  • 使用 C# 设置 Excel 单元格格式 - 教程
  • grafana部署并使用harbor监控模板
  • 【ARM Cache 及 MMU 系列文章 6.1 -- Cache maintenance 指令及相关寄存器有哪些?】
  • 十八、CPU的控制流:正常控制流和异常控制流
  • 大模型基础|位置编码|RoPE|ALiBi
  • 成品app直播源码搭建,sql优化原则 - 云豹科技
  • 使用Clang静态分析技术追踪Heartbleed漏洞
  • 每日Java并发面试系列(5):基础篇(线程池的核心原理是什么、线程池大小设置为多少更合适、线程池哪几种类型?ThreadLocal为什么会导致内存泄漏?) - 实践
  • 累死你的不是工作,而是工作方式
  • 川土微CA-IF1051S、CA-IF1051VS 支持CAN FD
  • 模仿玩家习惯的简单AI系统:GoCap
  • 浅谈马拉车
  • 十七、异常和中断响应过程的时序图
  • 十六、异常和中断的响应过程
  • 直播平台搭建,浏览器中的事件循环与Node中的事件循环 - 云豹科技
  • Redisson 分布式锁的实现原理 - 教程
  • 关于前端的一些疑问整理(标签属性值和符号)
  • 深入解析:免费的SSL和付费SSL 证书差异
  • 领嵌iLeadE-588网关AI边缘计算盒子智能安防监控
  • 十五、异常和中断事件的初始检测、识别和处理
  • 十四、异常和中断的分类
  • 思考 | 躺平者的本质和区别
  • ros2--service/服务--接口 - 教程