AI Engineering Academy · 课时

在 Redis 与 PostgreSQL 中持久化聊天记录

使用 RedisChatMessageHistory 和 PostgresChatMessageHistory 在外部存储对话记录,使记忆能够跨应用重启保留,并支持多个实例扩展。

第 4 / 4 课13 个步骤

在 Redis 与 PostgreSQL 中持久化聊天记录 是 CoddyKit 上的免费 AI Engineering Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Engineering Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Engineering Academy 课程共包含 4 节课。

为什么要在外部持久化聊天历史?

应用程序重启或扩展到多个实例时,内存中的对话历史会消失。外部持久化解决了三个问题:历史记录可以在崩溃后保留,多个服务器实例可以共享同一份历史记录,还可以为回访用户加载过去的会话。Redis 和 PostgreSQL 是最常用的两个后端。

LangChain 聊天消息历史接口

LangChain 定义了一个 BaseChatMessageHistory 接口,其中包含两个方法:add_message(message) 和 messages(属性)。任何实现此接口的存储后端,都可以作为内存组件接入任意 LangChain 链。Redis 和 PostgreSQL 的实现都遵循此接口。

from langchain_community.chat_message_histories import RedisChatMessageHistory

# Each unique session_id gets its own history namespace
history = RedisChatMessageHistory(
    session_id='user:alice:session:42',
    url='redis://localhost:6379'
)

# Add messages
history.add_user_message('What is RAG?')
history.add_ai_message('RAG stands for Retrieval-Augmented Generation...')

# Retrieve stored messages
for msg in history.messages:
    print(msg.type, ':', msg.content[:50])

将 Redis 历史记录连接到链

请使用 RunnableWithMessageHistory 包装您的链,并提供一个工厂函数,为每个会话返回正确的历史记录对象。LangChain 会在每次调用前自动加载历史记录,并在每次响应后保存新消息。

from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

llm = ChatOpenAI(model='gpt-4o-mini')
prompt = ChatPromptTemplate.from_messages([
    ('system', 'You are a helpful assistant.'),
    MessagesPlaceholder(variable_name='history'),
    ('human', '{input}')
])

chain = prompt | llm

chain_with_history = RunnableWithMessageHistory(
    chain,
    lambda session_id: RedisChatMessageHistory(
        session_id=session_id,
        url='redis://localhost:6379'
    ),
    input_messages_key='input',
    history_messages_key='history'
)

使用会话 ID 调用链

调用使用消息历史记录包装的链时,请将会话 ID 放入 config 字典中 configurable 对应的项下。LangChain 会自动将每次调用路由到正确的历史记录存储,因此 Alice 和 Bob 的对话历史完全分开。

# First turn for session alice-001
response = chain_with_history.invoke(
    {'input': 'My name is Alice.'},
    config={'configurable': {'session_id': 'alice-001'}}
)
print(response.content)

# Second turn — the chain remembers Alice's name from Redis
response = chain_with_history.invoke(
    {'input': 'What is my name?'},
    config={'configurable': {'session_id': 'alice-001'}}
)
print(response.content)  # Should say 'Your name is Alice.'

聊天历史记录的 Redis 密钥设计

Redis 会将每个会话的消息作为列表存储在一个密钥下,该密钥由会话 ID 派生而来。请使用类似 chat:<app>:<user_id>:<session_id> 的结构化密钥模式,避免不同应用之间发生密钥冲突,并支持按用户高效扫描。请为旧会话密钥设置 TTL,防止存储空间无限增长。

import redis

r = redis.Redis.from_url('redis://localhost:6379')

# List all chat sessions for user alice
keys = r.keys('message_store:alice-*')
print('Active sessions:', len(keys))

# Set a 30-day TTL on a session to auto-expire old history
for key in keys:
    r.expire(key, 60 * 60 * 24 * 30)

PostgreSQL 聊天历史记录表设计

对于基于 SQL 的持久化存储,请创建一个包含会话 ID、消息角色、内容和时间戳等列的表。当您需要查询、审计聊天历史记录,或将其与用户账户数据连接时,PostgreSQL 是理想选择。langchain_postgres 软件包提供了现成的实现。

-- SQL table for storing chat messages
CREATE TABLE chat_messages (
    id          SERIAL PRIMARY KEY,
    session_id  TEXT NOT NULL,
    role        TEXT NOT NULL,   -- 'human' or 'ai'
    content     TEXT NOT NULL,
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_chat_session ON chat_messages (session_id, created_at);

LangChain 中的 PostgresChatMessageHistory

langchain_postgres 中的 PostgresChatMessageHistory 类的工作方式与 Redis 版本相同,但会将消息存储在您的 PostgreSQL 数据库中。传入连接字符串和会话 ID 后,它会自动处理表创建和消息序列化。

from langchain_postgres import PostgresChatMessageHistory
import psycopg

CONNECTION_STRING = 'postgresql://user:pass@localhost:5432/mydb'

# Create history object for a session
history = PostgresChatMessageHistory(
    table_name='chat_messages',
    session_id='alice-001',
    connection=psycopg.connect(CONNECTION_STRING)
)

history.add_user_message('Tell me about embeddings.')
history.add_ai_message('Embeddings are dense vector representations...')

print(f'Stored {len(history.messages)} messages')

为回访用户加载之前的会话

用户关闭应用后再次回来时,您可以从 Redis 或 PostgreSQL 加载历史记录,以恢复其上一个会话。您可以向用户展示其上次进展的摘要,也可以将存储的历史记录注入下一次提示,从而无缝继续对话。

def get_or_create_history(user_id: str, session_id: str):
    history = RedisChatMessageHistory(
        session_id=f'{user_id}:{session_id}',
        url='redis://localhost:6379'
    )
    if history.messages:
        print(f'Resuming session with {len(history.messages)} messages.')
    else:
        print('Starting a new session.')
    return history

在数据库中裁剪历史记录

长期运行的会话可能会积累数千条消息。请实现一种裁剪策略:删除早于截止时间的消息,或在数据库中仅保留最近的 N 条消息。这样可以保持检索速度,并防止加载历史记录时上下文窗口溢出。

# Keep only the last 20 messages per session in PostgreSQL
CLEAN_SQL = '''
    DELETE FROM chat_messages
    WHERE session_id = %s
    AND id NOT IN (
        SELECT id FROM chat_messages
        WHERE session_id = %s
        ORDER BY created_at DESC
        LIMIT 20
    )
'''

def trim_session(conn, session_id: str, keep_last: int = 20):
    with conn.cursor() as cur:
        cur.execute(CLEAN_SQL, (session_id, session_id))
    conn.commit()

在 Redis 和 PostgreSQL 之间进行选择

这两种后端都已达到生产可用水平,但各自优势不同。Redis 提供亚毫秒级读取速度,非常适合最看重延迟的实时聊天场景。PostgreSQL 支持完整的 SQL 查询、ACID 事务,并且能够轻松与现有用户数据库集成,用于分析和审计。许多生产系统使用 Redis 作为主缓存,并使用 PostgreSQL 进行持久化归档。

安全性:隔离多租户历史记录

在多租户应用中,您必须确保用户无法访问彼此的历史记录。请始终将用户 ID 包含在会话密钥中,在加载历史记录前验证会话 ID 是否属于经过身份验证的用户,并且绝不要在客户端网址或 Cookie 中暴露原始会话密钥。

  • 良好的密钥:chat:app1:user:42:session:abc
  • 不良的密钥:session:abc(容易猜测,未限定用户范围)

快速检查

请测试您对外部持久化聊天历史记录的理解。

课程回顾

在本课中,您学到了:RedisChatMessageHistory 使用按会话划分的密钥将聊天历史记录存储在 Redis 中;PostgresChatMessageHistory 支持可通过 SQL 查询的持久化存储;RunnableWithMessageHistory 通过 session_id 工厂将任意后端连接到您的链。接下来,我们将深入了解用于构建推理与行动代理的 ReAct 框架。

免费开始

用 AI 导师学习 Python — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
30
课程
120

常见问题解答

「在 Redis 与 PostgreSQL 中持久化聊天记录」课时是免费的吗?

是的 — 「在 Redis 与 PostgreSQL 中持久化聊天记录」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Engineering Academy 课程的其余内容,请升级到 CoddyKit PRO。 AI Engineering Academy 课程共包含 4 节课。

「在 Redis 与 PostgreSQL 中持久化聊天记录」这节课中我会学到什么?

使用 RedisChatMessageHistory 和 PostgresChatMessageHistory 在外部存储对话记录,使记忆能够跨应用重启保留,并支持多个实例扩展。 你通过在浏览器中直接运行的动手代码来练习 AI Engineering Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 AI Engineering Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 AI Engineering Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「在 Redis 与 PostgreSQL 中持久化聊天记录」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 AI Engineering Academy 课中编写并运行代码吗?

能。每节 AI Engineering Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 无状态 LLM 为什么需要外部记忆
  2. 缓冲区记忆与窗口记忆
  3. 摘要记忆与令牌感知截断
  4. 在 Redis 与 PostgreSQL 中持久化聊天记录
← 返回 AI Engineering Academy