在 Redis 与 PostgreSQL 中持久化聊天记录
使用 RedisChatMessageHistory 和 PostgresChatMessageHistory 在外部存储对话记录,使记忆能够跨应用重启保留,并支持多个实例扩展。
在 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 反馈 — 无需本地设置。
此课程中的所有课时
- 无状态 LLM 为什么需要外部记忆
- 缓冲区记忆与窗口记忆
- 摘要记忆与令牌感知截断
- 在 Redis 与 PostgreSQL 中持久化聊天记录