การเก็บประวัติการสนทนาใน Redis และ PostgreSQL
จัดเก็บประวัติการสนทนาภายนอกด้วย RedisChatMessageHistory และ PostgresChatMessageHistory เพื่อให้หน่วยความจำยังคงอยู่หลังแอปพลิเคชันเริ่มทำงานใหม่ และรองรับการขยายไปยังอินสแตนซ์หลายรายการ
การเก็บประวัติการสนทนาใน Redis และ PostgreSQL เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน 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'
)การเรียกใช้เชนด้วยรหัสเซสชัน
เมื่อเรียกใช้เชนที่ครอบด้วยประวัติข้อความ ให้ส่งรหัสเซสชันในพจนานุกรม 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 จัดเก็บข้อความของแต่ละเซสชันเป็นรายการภายใต้คีย์ที่สร้างจากรหัสเซสชัน ควรใช้รูปแบบคีย์ที่มีโครงสร้าง เช่น 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 ให้สร้างตารางที่มีคอลัมน์สำหรับรหัสเซสชัน บทบาทของข้อความ เนื้อหา และเวลา 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);PostgresChatMessageHistory ใน LangChain
คลาส PostgresChatMessageHistory จาก langchain_postgres ทำงานคล้ายกับรุ่น Redis ทุกประการ แต่จัดเก็บข้อความไว้ในฐานข้อมูล PostgreSQL ของคุณ เพียงส่งสตริงการเชื่อมต่อและรหัสเซสชัน แล้วคลาสนี้จะจัดการสร้างตารางและแปลงข้อความเป็นรูปแบบสำหรับจัดเก็บโดยอัตโนมัติ
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 สำหรับการเก็บถาวรที่คงทน
ความปลอดภัย: การแยกประวัติของผู้เช่าหลายราย
ในแอปพลิเคชันที่รองรับผู้เช่าหลายราย คุณต้องตรวจสอบให้แน่ใจว่าผู้ใช้ไม่สามารถเข้าถึงประวัติของกันและกันได้ ให้รวม รหัสผู้ใช้ไว้ในคีย์เซสชันเสมอ ตรวจสอบว่ารหัสเซสชันเป็นของผู้ใช้ที่ผ่านการยืนยันตัวตนก่อนโหลดประวัติ และอย่าเปิดเผยคีย์เซสชันดิบใน URL หรือคุกกี้ฝั่งไคลเอนต์
- คีย์ที่ดี:
chat:app1:user:42:session:abc - คีย์ที่ไม่ดี:
session:abc(คาดเดาได้ และไม่มีขอบเขตผู้ใช้)
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจของคุณเกี่ยวกับการเก็บประวัติการสนทนาภายนอก
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า RedisChatMessageHistory จัดเก็บประวัติการสนทนาใน Redis โดยใช้คีย์แยกตามเซสชัน PostgresChatMessageHistory ช่วยให้จัดเก็บข้อมูลถาวรที่สืบค้นด้วย SQL ได้ และ RunnableWithMessageHistory เชื่อมแบ็กเอนด์ใดก็ได้เข้ากับเชนของคุณผ่านตัวสร้าง session_id บทถัดไป เราจะเจาะลึกเฟรมเวิร์ก ReAct สำหรับสร้างเอเจนต์ที่ให้เหตุผลและลงมือทำ
เรียนรู้ Python ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “การเก็บประวัติการสนทนาใน Redis และ PostgreSQL” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การเก็บประวัติการสนทนาใน Redis และ PostgreSQL” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเก็บประวัติการสนทนาใน Redis และ PostgreSQL”
จัดเก็บประวัติการสนทนาภายนอกด้วย RedisChatMessageHistory และ PostgresChatMessageHistory เพื่อให้หน่วยความจำยังคงอยู่หลังแอปพลิเคชันเริ่มทำงานใหม่ และรองรับการขยายไปยังอินสแตนซ์หลายรายการ คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การเก็บประวัติการสนทนาใน Redis และ PostgreSQL” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม
ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุใด LLM แบบไร้สถานะจึงต้องใช้หน่วยความจำภายนอก
- หน่วยความจำแบบบัฟเฟอร์และหน้าต่าง
- หน่วยความจำแบบสรุปและการตัดข้อความโดยคำนึงถึงโทเคน
- การเก็บประวัติการสนทนาใน Redis และ PostgreSQL