Redis와 PostgreSQL에 채팅 기록 저장하기
RedisChatMessageHistory와 PostgresChatMessageHistory를 사용해 대화 기록을 외부에 저장함으로써 애플리케이션을 다시 시작해도 메모리가 유지되고 여러 인스턴스로 확장되도록 합니다.
Redis와 PostgreSQL에 채팅 기록 저장하기은(는) CoddyKit의 무료 AI Engineering Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 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로 체인 호출하기
메시지 기록으로 감싼 체인을 호출할 때는 config 딕셔너리의 configurable 아래에 세션 ID를 전달하십시오. 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는 1밀리초 미만의 읽기 속도를 제공하므로 지연 시간이 가장 중요한 실시간 대화에 적합합니다. PostgreSQL은 완전한 SQL 조회 기능, ACID 트랜잭션, 그리고 분석 및 감사 목적으로 기존 사용자 데이터베이스와 쉽게 통합할 수 있는 기능을 제공합니다. 많은 운영 시스템에서는 Redis를 기본 캐시로, PostgreSQL을 영구 보관용 저장소로 사용합니다.
보안: 다중 테넌트 기록 격리
다중 테넌트 애플리케이션에서는 사용자가 서로의 기록에 접근할 수 없도록 해야 합니다. 항상 세션 키에 사용자 ID를 포함하고, 기록을 불러오기 전에 해당 세션 ID가 인증된 사용자에게 속하는지 확인하며, 클라이언트 측 URL이나 쿠키에 원시 세션 키를 절대 노출하지 마십시오.
- 좋은 키:
chat:app1:user:42:session:abc - 나쁜 키:
session:abc(추측할 수 있고 사용자 범위가 없음)
빠른 확인
대화 기록을 외부에 영속화하는 방법에 대한 이해도를 확인해 보십시오.
레슨 요약
이 레슨에서는 다음을 배웠습니다. RedisChatMessageHistory는 세션별 키를 사용하여 Redis에 대화 기록을 저장합니다. PostgresChatMessageHistory는 SQL로 조회할 수 있는 영구 저장소를 제공합니다. 또한 RunnableWithMessageHistory는 session_id 팩터리를 통해 모든 백엔드를 체인에 연결합니다. 다음으로는 추론 및 행동 에이전트를 구축하기 위한 ReAct 프레임워크를 살펴봅니다.
AI 튜터와 함께 Python을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 30
- 레슨
- 120
자주 묻는 질문
“Redis와 PostgreSQL에 채팅 기록 저장하기” 강의는 무료인가요?
네 — “Redis와 PostgreSQL에 채팅 기록 저장하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Engineering Academy 강의 전체를 잠금 해제할 수 있습니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“Redis와 PostgreSQL에 채팅 기록 저장하기”에서 뭘 배우나요?
RedisChatMessageHistory와 PostgresChatMessageHistory를 사용해 대화 기록을 외부에 저장함으로써 애플리케이션을 다시 시작해도 메모리가 유지되고 여러 인스턴스로 확장되도록 합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Engineering Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Engineering Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Engineering Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“Redis와 PostgreSQL에 채팅 기록 저장하기” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Engineering Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Engineering Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 상태 비저장 LLMs에 외부 메모리가 필요한 이유
- 버퍼 및 윈도우 메모리
- 요약 메모리와 토큰 인식형 잘라내기
- Redis와 PostgreSQL에 채팅 기록 저장하기