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

基于 Streamlit 与 LangChain 构建具备对话记忆的 AI Agent

一、引言

在构建智能对话系统时,对话记忆是实现连贯多轮对话的关键。本文将以 basic_memory.py 为例,详细讲解如何基于 Streamlit 和 LangChain 构建具备对话记忆的 AI Agent。

二、代码剖析

1. 初始化对话记忆

msgs = StreamlitChatMessageHistory(key="langchain_messages")
if len(msgs.messages) == 0:msgs.add_ai_message("How can I help you?")

原理剖析

  • 使用 StreamlitChatMessageHistory 类创建对话记忆对象,指定 key 参数为 "langchain_messages"
  • 如果对话消息为空,则添加一条 AI 消息 "How can I help you?" 作为对话起点。
  • 内存存储机制StreamlitChatMessageHistory 会将消息存储在 Streamlit 的 Session State 中,利用 Streamlit 的会话机制实现记忆的持久化。

流程图

初始化对话记忆
消息列表是否为空
添加 AI 消息
加载现有消息

2. 构建对话链

prompt = ChatPromptTemplate.from_messages([("system", "You are an AI chatbot having a conversation with a human."),MessagesPlaceholder(variable_name="history"),("human", "{question}"),]
)
chain = prompt | ChatOpenAI(api_key=openai_api_key)

原理剖析

  • 使用 ChatPromptTemplate 构建对话提示模板,包含系统消息、历史消息占位符和人类消息。
  • 历史消息传递:通过 MessagesPlaceholder 将历史消息融入提示模板,确保模型能获取完整对话上下文。
  • 将提示模板与 OpenAI 模型组合成对话链,实现对话逻辑的封装。

架构图

ChatPromptTemplate
ChatOpenAI
System Message
History Placeholder
Human Message

3. 整合对话历史

chain_with_history = RunnableWithMessageHistory(chain,lambda session_id: msgs,input_messages_key="question",history_messages_key="history",
)

原理剖析

  • 使用 RunnableWithMessageHistory 将对话链与对话记忆整合。
  • 记忆绑定:通过 lambda 函数将 msgs 对象绑定到对话链,实现记忆的自动加载与更新。
  • 指定输入消息键和历史消息键,确保消息的正确传递。

流程图

对话链
RunnableWithMessageHistory
消息历史
输入消息键
历史消息键

4. 渲染对话消息

for msg in msgs.messages:st.chat_message(msg.type).write(msg.content)

原理剖析

  • 遍历对话消息列表,使用 Streamlit 的 chat_message 方法渲染对话消息。
  • 消息类型区分:根据消息类型(人类或 AI)进行不同样式的消息展示。

界面图

人类消息
AI 消息
消息列表遍历
判断消息类型
人类消息样式渲染
AI 消息样式渲染

5. 条件设置

if "openai_api_key" in st.secrets:openai_api_key = st.secrets.openai_api_key
else:openai_api_key = st.sidebar.text_input("OpenAI API Key", type="password")
if not openai_api_key:st.info("Enter an OpenAI API Key to continue")st.stop()

原理剖析

  • 检查 Streamlit 秘密配置中是否存在 OpenAI API 密钥,若不存在则通过侧边栏输入获取。
  • 权限控制:若未获取到 API 密钥,则阻止后续操作,防止未授权访问。

流程图

存在
不存在
有效
无效
检查 API 密钥
密钥是否存在
获取密钥
输入密钥
验证密钥
密钥有效
继续执行
阻止操作

6. 处理新消息

if prompt := st.chat_input():st.chat_message("human").write(prompt)response = chain_with_history.invoke({"question": prompt}, config)st.chat_message("ai").write(response.content)

原理剖析

  • 捕获用户输入的新消息,通过 RunnableWithMessageHistory 调用对话链生成响应。
  • 自动记忆更新:新消息和响应会自动存储到对话记忆中,实现多轮对话的记忆延续。

流程图

捕获新消息
渲染人类消息
调用对话链
获取响应
渲染 AI 消息
更新对话记忆

三、代码整体架构图与解析

整体架构图

Streamlit 应用入口
初始化对话记忆
设置 API 密钥
构建对话链
整合对话历史
渲染对话消息
条件设置
处理新消息
更新对话记忆

整体架构解析

  1. Streamlit 应用入口

    • 使用 st.set_page_configst.title 设置应用的基本信息。
    • 提供应用的简介和源码链接。
  2. 初始化对话记忆

    • 创建 StreamlitChatMessageHistory 对象,用于存储对话消息。
    • 如果消息列表为空,添加一条初始 AI 消息。
  3. 设置 API 密钥

    • 检查 Streamlit 秘密配置中是否存在 OpenAI API 密钥。
    • 若不存在,通过侧边栏输入获取密钥。
  4. 构建对话链

    • 使用 ChatPromptTemplate 定义对话提示模板。
    • 将提示模板与 OpenAI 模型组合成对话链。
  5. 整合对话历史

    • 使用 RunnableWithMessageHistory 将对话链与对话记忆整合。
    • 绑定消息历史,确保对话链能获取完整上下文。
  6. 渲染对话消息

    • 遍历消息列表,使用 Streamlit 的 chat_message 方法渲染对话消息。
  7. 条件设置

    • 检查是否获取到有效的 API 密钥。
    • 如果未获取到密钥,阻止后续操作。
  8. 处理新消息

    • 捕获用户输入的新消息。
    • 通过整合后的对话链生成响应。
  9. 更新对话记忆

    • 自动将新消息和响应存储到对话记忆中。
    • 确保多轮对话的连贯性。

通过以上架构,代码实现了对话记忆的存储、调用和更新,确保了多轮对话的连贯性和上下文一致性。

四、完整代码

from langchain_community.chat_message_histories import StreamlitChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAIimport streamlit as stst.set_page_config(page_title="StreamlitChatMessageHistory", page_icon="📖")
st.title("📖 StreamlitChatMessageHistory")"""
A basic example of using StreamlitChatMessageHistory to help LLMChain remember messages in a conversation.
The messages are stored in Session State across re-runs automatically. You can view the contents of Session State
in the expander below. View the
[source code for this app](https://github.com/langchain-ai/streamlit-agent/blob/main/streamlit_agent/basic_memory.py).
"""# Set up memory
msgs = StreamlitChatMessageHistory(key="langchain_messages")
if len(msgs.messages) == 0:msgs.add_ai_message("How can I help you?")view_messages = st.expander("View the message contents in session state")# Get an OpenAI API Key before continuing
if "openai_api_key" in st.secrets:openai_api_key = st.secrets.openai_api_key
else:openai_api_key = st.sidebar.text_input("OpenAI API Key", type="password")
if not openai_api_key:st.info("Enter an OpenAI API Key to continue")st.stop()# Set up the LangChain, passing in Message Historyprompt = ChatPromptTemplate.from_messages([("system", "You are an AI chatbot having a conversation with a human."),MessagesPlaceholder(variable_name="history"),("human", "{question}"),]
)chain = prompt | ChatOpenAI(api_key=openai_api_key)
chain_with_history = RunnableWithMessageHistory(chain,lambda session_id: msgs,input_messages_key="question",history_messages_key="history",
)# Render current messages from StreamlitChatMessageHistory
for msg in msgs.messages:st.chat_message(msg.type).write(msg.content)# If user inputs a new prompt, generate and draw a new response
if prompt := st.chat_input():st.chat_message("human").write(prompt)# Note: new messages are saved to history automatically by Langchain during runconfig = {"configurable": {"session_id": "any"}}response = chain_with_history.invoke({"question": prompt}, config)st.chat_message("ai").write(response.content)# Draw the messages at the end, so newly generated ones show up immediately
with view_messages:"""Message History initialized with:```pythonmsgs = StreamlitChatMessageHistory(key="langchain_messages")```Contents of `st.session_state.langchain_messages`:"""view_messages.json(st.session_state.langchain_messages)

本教程中用作参考剖析的代码来源于 langchain-ai 开源项目。

http://www.xdnf.cn/news/5255.html

相关文章:

  • 汽车四缸汽油机曲柄连杆机构设计关键技术研究
  • DAMA第10章深度解析:参考数据与主数据管理的核心要义与实践指南
  • Ansible模块——从控制节点向目标主机复制文件!
  • 文生视频模型速读:LTX-Video
  • Flink 运维监控与指标采集实战
  • 排序算法——总结
  • MySQL COUNT(*) 查询优化详解!
  • 【C++】string类(一)构造、重载、容量操作、访问与遍历(迭代器、范围for)、练习
  • 计算机网络:WiFi路由器发射的电磁波在空气中的状态是什么样的?
  • 打工人TOP,截图工具天花板
  • 智能商品推荐系统技术路线图
  • RabbitMQ深入学习
  • Taccel:一个高性能的GPU加速视触觉机器人模拟平台
  • yum install 如何卸载
  • vue3的响应式设计原理
  • DHT11温湿度传感器
  • 05 mysql之DDL
  • 复习javascript
  • MindSpore框架学习项目-ResNet药物分类-模型评估
  • 前端EXCEL插件,智表ZCELL产品V3.0 版本发布,底层采用canvas全部重构,功能大幅扩展,性能极致提升,满足千万级单元格加载
  • git 忽略 打包文件
  • CSS弹性布局
  • 深入解析进程地址空间:从虚拟到物理的奇妙之旅
  • PySide6 GUI 学习笔记——常用类及控件使用方法(常用类字体QFont)
  • Linux基本指令(一)
  • HDFS 常用基础命令详解——快速上手分布式文件系统
  • [python] 类
  • AtCoder Beginner Contest 405(CD)
  • 问题及解决01-面板无法随着窗口的放大而放大
  • 互联网大厂Java求职面试:基于RAG的智能问答系统设计与实现-3