AI Engineering Academy · บทเรียน

การเก็บประวัติการสนทนาใน Redis และ PostgreSQL

จัดเก็บประวัติการสนทนาภายนอกด้วย RedisChatMessageHistory และ PostgresChatMessageHistory เพื่อให้หน่วยความจำยังคงอยู่หลังแอปพลิเคชันเริ่มทำงานใหม่ และรองรับการขยายไปยังอินสแตนซ์หลายรายการ

บทเรียน 4 จาก 413 ขั้นตอน

การเก็บประวัติการสนทนาใน 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เหตุใด LLM แบบไร้สถานะจึงต้องใช้หน่วยความจำภายนอก
  2. หน่วยความจำแบบบัฟเฟอร์และหน้าต่าง
  3. หน่วยความจำแบบสรุปและการตัดข้อความโดยคำนึงถึงโทเคน
  4. การเก็บประวัติการสนทนาใน Redis และ PostgreSQL
← กลับไปที่ AI Engineering Academy