【LangChain】langchain_community.chat_message_histories.SQLChatMessageHistory 类:将聊天消息历史存储到 SQL 数据库的工具类

langchain_community.chat_message_histories.SQLChatMessageHistory 类是 LangChain 社区库中用于将聊天消息历史存储到 SQL 数据库的工具类,适合持久化管理和多轮对话的上下文跟踪。

本文基于 LangChain 0.3.x ,详细介绍 SQLChatMessageHistory 的定义、参数、方法和典型场景,并提供一个独立示例,展示如何使用 SQLChatMessageHistory 结合 ChatOpenAI 和 SQLite 数据库实现人工智能主题的多轮对话,示例突出消息历史的持久化存储和上下文保留。


langchain_community.chat_message_histories.SQLChatMessageHistory 简介

SQLChatMessageHistory 是 LangChain 社区库中的消息历史存储类,通过 SQL 数据库(支持 SQLite、PostgreSQL 等)持久化存储对话消息(HumanMessageAIMessage 等)。它适合需要长期保存对话历史或多用户会话管理的场景,相比内存存储的 ChatMessageHistory,它提供数据持久化和跨会话访问能力。

核心功能

  • 将对话消息存储到 SQL 数据库,支持持久化。
  • 按会话 ID(session_id)组织消息,支持多用户或多会话。
  • 支持添加、获取、清除消息。
  • 集成到对话链,实现上下文感知的多轮对话。

适用场景

  • 构建生产级聊天机器人,需持久化对话历史。
  • 多用户应用,跟踪每个用户的会话。
  • 需要跨设备或会话恢复对话的场景。
  • 与 LLM 链结合,提供长期上下文支持。

与其他消息历史类对比

  • ChatMessageHistory:内存存储,临时使用,非持久化。
  • RedisChatMessageHistory:基于 Redis,适合高并发但需额外部署。
  • SQLChatMessageHistory:基于 SQL 数据库,持久化且易于集成。

类定义和初始化

以下是 SQLChatMessageHistory 的定义,基于 LangChain 社区库源码(langchain_community/chat_message_histories/sql.py)和官方文档(SQLChatMessageHistory)。

类签名
class SQLChatMessageHistory(BaseChatMessageHistory):
    def __init__(
        self,
        session_id: str,
        connection_string: str,
        table_name: str = "message_store",
        session_id_field_name: str = "session_id",
        created_at_field_name: str = "created_at",
        custom_message_to_dict: Optional[Callable[[BaseMessage], Dict[str, Any]]] = None,
        custom_dict_to_message: Optional[Callable[[Dict[str, Any]], BaseMessage]] = None
    ) -> None
  • 参数
    • session_idstr):会话标识符,区分不同对话。
    • connection_stringstr):SQL 数据库连接字符串(如 "sqlite:///chat_history.db")。
    • table_namestr,默认 "message_store"):存储消息的表名。
    • session_id_field_namestr,默认 "session_id"):会话 ID 列名。
    • created_at_field_namestr,默认 "created_at"):创建时间列名。
    • custom_message_to_dictOptional[Callable],默认 None):自定义消息转字典函数。
    • custom_dict_to_messageOptional[Callable],默认 None):自定义字典转消息函数。
  • 功能
    • 自动创建数据库表(包含 session_idmessage 等列)。
    • session_id 存储和查询消息。
    • 支持 SQLite、PostgreSQL 等数据库。
初始化示例
from langchain_community.chat_message_histories import SQLChatMessageHistory
history = SQLChatMessageHistory(
    session_id="ai_chat_001",
    connection_string="sqlite:///chat_history.db",
    table_name="message_store"
)

数据库表结构

SQLChatMessageHistory 自动创建以下表结构(以 table_name="message_store" 为例):

CREATE TABLE message_store (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id TEXT NOT NULL,
    message TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
  • 字段
    • id:消息唯一标识,自增。
    • session_id:会话 ID,区分对话。
    • message:消息内容(序列化为 JSON,包含类型和内容)。
    • created_at:消息创建时间。

常用方法

SQLChatMessageHistory 继承自 langchain_core.chat_history.BaseChatMessageHistory,提供以下核心方法。

1. add_message
def add_message(self, message: BaseMessage) -> None
  • 功能:添加单条消息到数据库。
  • 输入messageBaseMessage),如 HumanMessageAIMessage
  • 示例
    from langchain_core.messages import HumanMessage, AIMessage
    history.add_message(HumanMessage(content="什么是人工智能?"))
    history.add_message(AIMessage(content="人工智能是计算机科学的一个分支。"))
    
2. add_user_message
def add_user_message(self, message: str) -> None
  • 功能:添加用户消息(HumanMessage)。
  • 输入messagestr),用户输入文本。
  • 示例
    history.add_user_message("AI 有哪些应用?")
    
3. add_ai_message
def add_ai_message(self, message: str) -> None
  • 功能:添加 AI 消息(AIMessage)。
  • 输入messagestr),模型响应文本。
  • 示例
    history.add_ai_message("AI 应用于医疗、自动驾驶等领域。")
    
4. clear
def clear(self) -> None
  • 功能:删除当前 session_id 的所有消息。
  • 示例
    history.clear()
    print(len(history.messages))  # 0
    
5. messages 属性
  • 功能:从数据库查询当前 session_id 的消息列表。
  • 输出List[BaseMessage],所有消息。
  • 示例
    for msg in history.messages:
        print(f"{msg.__class__.__name__}: {msg.content}")
    
6. 异步方法
  • 功能:异步版本方法(如 aclearaadd_message)。
  • 使用场景:高并发场景。
  • 示例
    import asyncio
    await history.aclear()
    

使用方式

以下是使用 SQLChatMessageHistory 的步骤。

1. 安装依赖
pip install --upgrade langchain langchain-openai langchain-community sqlalchemy
2. 设置 OpenAI API 密钥
export OPENAI_API_KEY="your-api-key"

或在代码中:

import os
os.environ["OPENAI_API_KEY"] = "your-api-key"
3. 初始化 SQLChatMessageHistory
from langchain_community.chat_message_histories import SQLChatMessageHistory
history = SQLChatMessageHistory(
    session_id="ai_chat_001",
    connection_string="sqlite:///chat_history.db"
)
4. 构建对话链
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
llm = ChatOpenAI(model="gpt-3.5-turbo")
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个人工智能专家,回答用户问题。"),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{input}")
])
chain = prompt | llm
5. 调用链并存储历史
from langchain_core.runnables.history import RunnableWithMessageHistory
chain_with_history = RunnableWithMessageHistory(
    runnable=chain,
    get_session_history=lambda session_id: SQLChatMessageHistory(
        session_id=session_id,
        connection_string="sqlite:///chat_history.db"
    ),
    input_messages_key="input",
    history_messages_key="history"
)
response = chain_with_history.invoke(
    {"input": "什么是人工智能?"},
    config={"configurable": {"session_id": "ai_chat_001"}}
)

使用 SQLChatMessageHistory 的示例

以下是一个独立示例,展示如何使用 SQLChatMessageHistory 结合 ChatOpenAI 和 SQLite 数据库实现人工智能主题的多轮对话,持久化存储消息历史并保留上下文。示例使用 RunnableWithMessageHistory 简化对话管理。

准备环境

  • 获取 OpenAI API 密钥:OpenAI Platform
  • 设置环境变量:
    export OPENAI_API_KEY="your-api-key"
    
  • 安装依赖:
    pip install --upgrade langchain langchain-openai langchain-community sqlalchemy
    

代码

from langchain_community.chat_message_histories import SQLChatMessageHistory
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables.history import RunnableWithMessageHistory

# 初始化 ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)

# 定义提示模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个人工智能专家,回答用户问题。"),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{input}")
])

# 定义输出解析器
parser = StrOutputParser()

# 创建对话链
chain = prompt | llm | parser

# 包装链以支持消息历史
chain_with_history = RunnableWithMessageHistory(
    runnable=chain,
    get_session_history=lambda session_id: SQLChatMessageHistory(
        session_id=session_id,
        connection_string="sqlite:///chat_history.db"
    ),
    input_messages_key="input",
    history_messages_key="history"
)

# 测试 SQLChatMessageHistory 和对话链
print("测试 SQLChatMessageHistory 和对话链:")
try:
    session_id = "ai_chat_001"
    
    # 第一轮对话
    question1 = "什么是人工智能?"
    result1 = chain_with_history.invoke(
        {"input": question1},
        config={"configurable": {"session_id": session_id}}
    )
    print(f"问题 1: {question1}")
    print(f"回答 1: {result1}")
    
    # 第二轮对话(依赖上下文)
    question2 = "它有哪些应用?"
    result2 = chain_with_history.invoke(
        {"input": question2},
        config={"configurable": {"session_id": session_id}}
    )
    print(f"\n问题 2: {question2}")
    print(f"回答 2: {result2}")
    
    # 显示消息历史
    history = SQLChatMessageHistory(session_id=session_id, connection_string="sqlite:///chat_history.db")
    print("\n消息历史:")
    for i, msg in enumerate(history.messages):
        print(f"消息 {i+1} ({msg.__class__.__name__}): {msg.content}")
except Exception as e:
    print(f"错误: {e}")

输出示例(实际输出取决于模型和 API 响应):

测试 SQLChatMessageHistory 和对话链:
问题 1: 什么是人工智能?
回答 1: 人工智能(AI)是计算机科学的一个分支,旨在模拟人类智能,如学习、推理和问题解决。

问题 2: 它有哪些应用?
回答 2: 人工智能的应用包括医疗诊断、自动驾驶、语音识别、推荐系统和金融分析等领域。

消息历史:
消息 1 (HumanMessage): 什么是人工智能?
消息 2 (AIMessage): 人工智能(AI)是计算机科学的一个分支,旨在模拟人类智能,如学习、推理和问题解决。
消息 3 (HumanMessage): 它有哪些应用?
消息 4 (AIMessage): 人工智能的应用包括医疗诊断、自动驾驶、语音识别、推荐系统和金融分析等领域。
代码说明
  1. SQLChatMessageHistory
    • 使用 SQLite 数据库(sqlite:///chat_history.db)存储消息。
    • 设置 session_id="ai_chat_001" 区分会话。
  2. LLM 初始化
    • 使用 ChatOpenAI 调用 gpt-3.5-turbo,设置 temperature=0.7
  3. 提示模板
    • ChatPromptTemplate 包含系统消息、历史占位符和用户输入。
    • MessagesPlaceholder 注入历史消息。
  4. 对话链
    • 使用 LCEL 组合 promptllmparser
    • RunnableWithMessageHistory 包装链,动态加载 SQLChatMessageHistory
  5. 测试
    • 进行两轮对话:定义 AI 和询问应用。
    • 使用 session_id 确保上下文一致。
    • 显示数据库中的消息历史。
  6. 错误处理
    • 使用 try-except 捕获 API 或数据库错误。

运行要求

  • 有效的 OpenAI API 密钥:
    export OPENAI_API_KEY="your-api-key"
    
  • 安装依赖:
    pip install --upgrade langchain langchain-openai langchain-community sqlalchemy
    
  • SQLite 无需额外安装(Python 内置支持)。
  • 网络连接:访问 https://api.openai.com.

注意事项

  1. API 密钥
    • 确保 OPENAI_API_KEY 已设置:
      echo $OPENAI_API_KEY
      
    • 或在代码中设置:
      llm = ChatOpenAI(api_key="your-api-key")
      
  2. 数据库配置
    • SQLite:简单,无需服务器:
      connection_string="sqlite:///chat_history.db"
      
    • PostgreSQL:生产环境:
      connection_string="postgresql://user:password@localhost:5432/dbname"
      
    • 确保数据库可写:
      touch chat_history.db
      chmod 666 chat_history.db
      
  3. 会话 ID
    • 唯一 session_id 区分对话:
      session_id="ai_chat_001"
      
    • 重复使用 session_id 加载历史:
      history = SQLChatMessageHistory(session_id="ai_chat_001", connection_string="sqlite:///chat_history.db")
      
  4. 性能优化
    • 限制历史长度:避免上下文过长:
      max_messages = 10
      history.messages = history.messages[-max_messages:]
      
    • 异步调用:使用 ainvoke
      result = await chain_with_history.ainvoke(input, config)
      
    • 数据库索引:为 session_id 添加索引:
      CREATE INDEX idx_session_id ON message_store (session_id);
      
  5. 错误调试
    • 数据库错误
      • 检查连接:
        import sqlalchemy
        engine = sqlalchemy.create_engine("sqlite:///chat_history.db")
        engine.connect()
        
      • 验证表结构:
        sqlite3 chat_history.db "SELECT * FROM message_store LIMIT 1"
        
    • API 错误
      • 检查密钥:
        print(os.environ.get("OPENAI_API_KEY"))
        
      • 增加超时:
        llm = ChatOpenAI(timeout=30)
        
    • 消息丢失
      • 检查历史:
        print(history.messages)
        
      • 验证 session_id
        print(session_id)
        

常见问题

Q1:如何使用 PostgreSQL 替代 SQLite?
A:修改 connection_string

history = SQLChatMessageHistory(
    session_id="ai_chat_001",
    connection_string="postgresql://user:password@localhost:5432/chat_db"
)

安装 PostgreSQL 驱动:

pip install psycopg2

Q2:如何清理特定会话历史?
A:调用 clear

history.clear()

或直接删除数据库记录:

DELETE FROM message_store WHERE session_id = 'ai_chat_001';

Q3:如何与 RAG 结合?
A:添加检索上下文:

from langchain.vectorstores import FAISS
vectorstore = FAISS.from_documents(docs, OpenAIEmbeddings())
retriever = vectorstore.as_retriever()
prompt = ChatPromptTemplate.from_messages([
    ("system", "根据上下文和历史回答:\n{context}"),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{input}")
])
chain = {"context": retriever, "history": lambda x: history.messages, "input": lambda x: x["input"]} | prompt | llm

Q4:如何支持开源模型?
A:使用 ChatOllama

from langchain_ollama import ChatOllama
llm = ChatOllama(model="llama3")
chain = prompt | llm | parser
chain_with_history = RunnableWithMessageHistory(
    runnable=chain,
    get_session_history=lambda session_id: SQLChatMessageHistory(
        session_id=session_id,
        connection_string="sqlite:///chat_history.db"
    ),
    input_messages_key="input",
    history_messages_key="history"
)

总结

langchain_community.chat_message_histories.SQLChatMessageHistory 是 LangChain 中持久化对话历史的核心工具,核心功能包括:

  • 定义:通过 SQL 数据库存储消息历史。
  • 初始化:配置 session_idconnection_string
  • 常用方法add_messageadd_user_messageadd_ai_messageclear
  • 适用场景:多轮对话、持久化存储、生产级应用。
这段引用内容是一个关于使用shell脚本实现文件清理的示例代码\[1\]。它通过双层for循环遍历指定目录下的所有文件,并根据白名单文件中的内容判断是否删除文件。如果文件不在白名单中,则使用rm命令删除该文件。 另外,引用\[2\]是关于使用unalias命令删除别名的示例。通过执行unalias命令,可以删除指定的命令别名。 引用\[3\]是关于使用find命令进行文件查找的示例。通过find命令可以根据不同的条件进行文件查找,比如根据文件的拥有者、文件大小、文件名等。 至于您提到的问题,"fatal: refusing to merge unrelated histories"是Git在合并分支时出现的错误信息。这个错误通常是由于两个分支的历史记录没有共同的祖先导致的。您可以尝试使用--allow-unrelated-histories选项来允许合并没有共同祖先的分支。例如,可以使用以下命令来解决该问题: git merge --allow-unrelated-histories <branch-name> 请注意,这个选项可能会导致合并后的历史记录变得混乱,所以在使用之前请确保您知道自己在做什么。 #### 引用[.reference_title] - *1* [自动化工具-在保留白名单文件的前提下,删除剩余文件](https://blog.csdn.net/monarch91/article/details/129282167)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Linux常用命令](https://blog.csdn.net/weixin_44175418/article/details/123637284)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彬彬侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值