การคงอยู่ของบริบทข้ามเซสชัน
จัดเก็บและโหลดการตั้งค่าผู้ใช้ ประวัติการสนทนา และสถานะงาน
การคงอยู่ของบริบทข้ามเซสชัน เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องคงบริบทไว้
หากไม่มีการคงบริบทไว้ ทุกเซสชันของเอเจนต์จะเริ่มต้นใหม่ทั้งหมด เอเจนต์ที่คงบริบทจะจดจำชื่อผู้ใช้ บทสนทนาที่ผ่านมา การตั้งค่าที่ผู้ใช้ระบุ และข้อเท็จจริงที่ผู้ใช้แบ่งปัน ทำให้การโต้ตอบต่อเนื่องและเป็นส่วนตัวมากขึ้น
SQLite สำหรับสถานะเซสชัน
SQLite เหมาะอย่างยิ่งสำหรับเอเจนต์ส่วนตัวที่มีผู้ใช้คนเดียว เพราะไม่ต้องมีเซิร์ฟเวอร์เพิ่มเติม ใช้ไฟล์เป็นพื้นฐาน และมีความน่าเชื่อถือ ให้จัดเก็บประวัติการสนทนาและข้อมูลผู้ใช้ไว้ในฐานข้อมูลภายในเครื่อง
import sqlite3
from datetime import datetime
def init_db(db_path: str = 'agent_memory.db') -> sqlite3.Connection:
conn = sqlite3.connect(db_path, check_same_thread=False)
conn.row_factory = sqlite3.Row # Dict-like access
conn.executescript('''
CREATE TABLE IF NOT EXISTS sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT UNIQUE NOT NULL,
user_id TEXT NOT NULL,
started_at TEXT,
last_active TEXT
);
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
role TEXT NOT NULL,
content TEXT NOT NULL,
timestamp TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS user_facts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id TEXT NOT NULL,
fact_key TEXT NOT NULL,
fact_value TEXT NOT NULL,
created_at TEXT,
UNIQUE(user_id, fact_key)
);
''')
conn.commit()
return conn
conn = init_db()
print('Database initialized')การบันทึกและโหลดข้อความ
ควรบันทึกข้อความของผู้ใช้และคำตอบของเอเจนต์ทุกข้อความพร้อม ID ของเซสชัน เมื่อกลับมาใช้เซสชันต่อ ให้โหลดข้อความล่าสุดจำนวน N ข้อความเพื่อกู้คืนบริบทการสนทนา
import sqlite3
from datetime import datetime
def save_message(conn: sqlite3.Connection, session_id: str, role: str, content: str):
conn.execute(
'INSERT INTO messages (session_id, role, content, timestamp) VALUES (?, ?, ?, ?)',
(session_id, role, content, datetime.utcnow().isoformat())
)
conn.commit()
def load_recent_messages(conn: sqlite3.Connection, session_id: str, limit: int = 20) -> list:
rows = conn.execute(
'SELECT role, content FROM messages WHERE session_id = ? ORDER BY id DESC LIMIT ?',
(session_id, limit)
).fetchall()
# Reverse to get chronological order
return [{'role': r['role'], 'content': r['content']} for r in reversed(rows)]
def load_all_session_messages(conn: sqlite3.Connection, user_id: str, days: int = 30) -> list:
from datetime import timedelta
since = (datetime.utcnow() - timedelta(days=days)).isoformat()
rows = conn.execute(
'SELECT m.role, m.content, m.timestamp FROM messages m '
'JOIN sessions s ON s.session_id = m.session_id '
'WHERE s.user_id = ? AND m.timestamp >= ? ORDER BY m.id',
(user_id, since)
).fetchall()
return [dict(r) for r in rows]
if __name__ == '__main__':
conn = sqlite3.connect(':memory:')
conn.row_factory = sqlite3.Row
conn.execute('CREATE TABLE messages (id INTEGER PRIMARY KEY, session_id TEXT, role TEXT, content TEXT, timestamp TEXT)')
save_message(conn, 'sess1', 'user', 'Hello agent')
save_message(conn, 'sess1', 'assistant', 'Hi! How can I help?')
for msg in load_recent_messages(conn, 'sess1'):
print(f"{msg['role']}: {msg['content']}")
Redis สำหรับสถานะเซสชัน
สำหรับเอเจนต์บนเว็บหรือการนำระบบไปใช้งานบนหลายเซิร์ฟเวอร์ Redis เหมาะกว่า SQLite ให้จัดเก็บข้อมูลเซสชันเป็น JSON พร้อม TTL เพื่อให้เซสชันเก่าถูกล้างโดยอัตโนมัติ
import redis
import json
from datetime import datetime
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
SESSION_TTL = 3600 * 24 * 7 # 7 days
def save_session_state(session_id: str, state: dict):
key = f'session:{session_id}'
state['last_updated'] = datetime.utcnow().isoformat()
r.setex(key, SESSION_TTL, json.dumps(state))
def load_session_state(session_id: str) -> dict:
key = f'session:{session_id}'
raw = r.get(key)
if not raw:
return {}
state = json.loads(raw)
# Refresh TTL on access
r.expire(key, SESSION_TTL)
return state
def append_to_session_history(session_id: str, role: str, content: str):
state = load_session_state(session_id)
history = state.get('history', [])
history.append({'role': role, 'content': content})
# Keep last 50 messages
state['history'] = history[-50:]
save_session_state(session_id, state)
# Test
save_session_state('sess-abc', {'user_name': 'Alice', 'history': []})
append_to_session_history('sess-abc', 'user', 'Hello!')
state = load_session_state('sess-abc')
print('Session state:', state)การโหลดการตั้งค่าของผู้ใช้เมื่อเริ่มต้น
เมื่อเริ่มเซสชันใหม่ ให้โหลดการตั้งค่าที่จัดเก็บไว้ของผู้ใช้ ได้แก่ ภาษา เขตเวลา การตั้งค่าการแจ้งเตือน และการกำหนดค่าเฉพาะของเอเจนต์ จากนั้นใส่ข้อมูลเหล่านี้ลงในคำสั่งระบบ
import sqlite3
def load_user_preferences(conn: sqlite3.Connection, user_id: str) -> dict:
rows = conn.execute(
'SELECT fact_key, fact_value FROM user_facts WHERE user_id = ?',
(user_id,)
).fetchall()
return {row['fact_key']: row['fact_value'] for row in rows}
def build_system_prompt_with_preferences(base_prompt: str, user_id: str, conn: sqlite3.Connection) -> str:
prefs = load_user_preferences(conn, user_id)
if not prefs:
return base_prompt
pref_lines = []
if 'name' in prefs:
pref_lines.append(f'The user\'s name is {prefs["name"]}.')
if 'timezone' in prefs:
pref_lines.append(f'The user is in timezone {prefs["timezone"]}.')
if 'language' in prefs:
pref_lines.append(f'Respond in {prefs["language"]}.')
if 'profession' in prefs:
pref_lines.append(f'The user is a {prefs["profession"]}.')
prefs_text = ' '.join(pref_lines)
return f'{base_prompt}\n\nUser context: {prefs_text}'
conn = init_db()
enhanced_prompt = build_system_prompt_with_preferences(
'You are a helpful assistant.',
'user-42',
conn
)
print('System prompt:', enhanced_prompt)การจัดเก็บสรุปการสนทนา
การจัดเก็บประวัติการสนทนาทั้งหมดใช้โทเค็นจำนวนมาก ให้ใช้การสรุปด้วย LLM เพื่อสร้างสรุปแบบย่อของบทสนทนาเก่า แล้วโหลดเฉพาะสรุปสำหรับประวัติที่อยู่ห่างออกไป
import openai
client = openai.OpenAI(api_key='sk-...')
def summarize_conversation(messages: list) -> str:
if not messages:
return ''
conversation_text = '\n'.join([
f'{m["role"].upper()}: {m["content"]}'
for m in messages
])
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=[{
'role': 'user',
'content': (
'Summarize this conversation in 2-3 sentences, '
'focusing on key facts, decisions, and user preferences revealed:\n\n'
f'{conversation_text}'
)
}]
)
return response.choices[0].message.content
def compress_old_history(conn: sqlite3.Connection, session_id: str, keep_recent: int = 10):
all_messages = load_recent_messages(conn, session_id, limit=1000)
if len(all_messages) <= keep_recent:
return
old_messages = all_messages[:-keep_recent]
summary = summarize_conversation(old_messages)
# Store summary as a special message
save_message(conn, session_id, 'summary', f'[Previous conversation summary]: {summary}')
print(f'Compressed {len(old_messages)} old messages into summary')การดึงและจัดเก็บข้อเท็จจริงของผู้ใช้
เมื่อผู้ใช้แบ่งปันข้อเท็จจริงเกี่ยวกับตนเอง ให้ดึงข้อมูลเหล่านั้นและจัดเก็บไว้ วิธีนี้จะสร้างหน่วยความจำระยะยาวที่คงอยู่ในทุกเซสชันต่อ ๆ ไป
import openai
import json
client = openai.OpenAI(api_key='sk-...')
def extract_user_facts(message: str) -> dict:
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=[{
'role': 'user',
'content': (
f'Extract any personal facts the user revealed in this message: "{message}"\n'
'Return JSON with fields: name, location, profession, preferences, or other relevant facts. '
'Return empty dict {{}} if no facts were revealed.'
)
}],
response_format={'type': 'json_object'}
)
return json.loads(response.choices[0].message.content)
def store_user_facts(conn: sqlite3.Connection, user_id: str, facts: dict):
for key, value in facts.items():
if value: # Skip empty values
conn.execute(
'INSERT OR REPLACE INTO user_facts (user_id, fact_key, fact_value, created_at) VALUES (?, ?, ?, ?)',
(user_id, key, str(value), __import__('datetime').datetime.utcnow().isoformat())
)
conn.commit()
if facts:
print(f'Stored {len(facts)} facts for user {user_id}: {list(facts.keys())}')
conn = init_db()
facts = extract_user_facts('I am a software engineer in Berlin working on AI projects')
store_user_facts(conn, 'user-42', facts)
print('Facts extracted:', facts)การโหลดบริบทที่เกี่ยวข้องสำหรับรอบการโต้ตอบปัจจุบัน
เมื่อเริ่มรอบการทำงานของเอเจนต์แต่ละครั้ง ให้ประกอบบริบทจากข้อความล่าสุด การตั้งค่าของผู้ใช้ และข้อเท็จจริงที่เกี่ยวข้อง วิธีนี้ช่วยให้ LLM มีข้อมูลทุกอย่างที่จำเป็นโดยไม่เกินขนาดหน้าต่างบริบท
def build_agent_context(conn: sqlite3.Connection, session_id: str, user_id: str, new_message: str) -> list:
messages = []
# Step 1: System prompt with user preferences
prefs = load_user_preferences(conn, user_id)
system_content = 'You are a helpful personal AI assistant.'
if prefs:
facts_text = ', '.join([f'{k}: {v}' for k, v in prefs.items()])
system_content += f' User context: {facts_text}'
messages.append({'role': 'system', 'content': system_content})
# Step 2: Load conversation history (last 15 messages)
history = load_recent_messages(conn, session_id, limit=15)
messages.extend(history)
# Step 3: Add the new user message
messages.append({'role': 'user', 'content': new_message})
return messages
conn = init_db()
context = build_agent_context(conn, 'sess-abc', 'user-42', 'What should I work on today?')
print(f'Context assembled: {len(context)} messages')
for m in context:
print(f' {m["role"]}: {m["content"][:60]}...')การเรียกคืนหน่วยความจำข้ามเซสชัน
สำหรับเอเจนต์ที่ทำงานเป็นเวลานานมาก ให้ใช้การค้นหาแบบเวกเตอร์เพื่อค้นหาบทสนทนาเก่าที่เกี่ยวข้อง ไม่ใช่ค้นหาเฉพาะบทสนทนาล่าสุด วิธีนี้ทำให้เอเจนต์เรียกคืนบริบทที่เกี่ยวข้องจากหลายเดือนได้
import openai
import chromadb
client = openai.OpenAI(api_key='sk-...')
chroma = chromadb.Client()
memory_collection = chroma.get_or_create_collection('user_memory')
def store_memory(user_id: str, content: str, metadata: dict):
emb_response = client.embeddings.create(
model='text-embedding-3-small', input=content
)
embedding = emb_response.data[0].embedding
import hashlib
doc_id = f'{user_id}_{hashlib.md5(content.encode()).hexdigest()[:8]}'
memory_collection.add(
ids=[doc_id],
embeddings=[embedding],
documents=[content],
metadatas=[{'user_id': user_id, **metadata}]
)
def retrieve_relevant_memories(user_id: str, current_query: str, top_k: int = 3) -> list:
emb_response = client.embeddings.create(
model='text-embedding-3-small', input=current_query
)
query_embedding = emb_response.data[0].embedding
results = memory_collection.query(
query_embeddings=[query_embedding],
n_results=top_k,
where={'user_id': user_id}
)
return results['documents'][0] if results['documents'] else []
print('Cross-session memory retrieval defined')ความเป็นส่วนตัวและการจัดการข้อมูล
เอเจนต์ที่ทำงานตลอดเวลาจะจัดเก็บข้อมูลส่วนบุคคลที่มีความละเอียดอ่อน ให้กำหนดขีดจำกัดระยะเวลาเก็บรักษาข้อมูล อนุญาตให้ผู้ใช้ลบข้อมูลของตนเอง และอย่าบันทึกเนื้อหาการสนทนาดิบลงในบันทึกของแอปพลิเคชัน
import sqlite3
from datetime import datetime, timedelta
def delete_user_data(conn: sqlite3.Connection, user_id: str):
'''Fully delete all data for a user (right to erasure).'''
conn.execute(
'DELETE FROM messages WHERE session_id IN (SELECT session_id FROM sessions WHERE user_id = ?)',
(user_id,)
)
conn.execute('DELETE FROM sessions WHERE user_id = ?', (user_id,))
conn.execute('DELETE FROM user_facts WHERE user_id = ?', (user_id,))
conn.commit()
print(f'All data deleted for user {user_id}')
def purge_old_messages(conn: sqlite3.Connection, retention_days: int = 90):
'''Remove messages older than retention period.'''
cutoff = (datetime.utcnow() - timedelta(days=retention_days)).isoformat()
cursor = conn.execute(
'DELETE FROM messages WHERE timestamp < ?', (cutoff,)
)
conn.commit()
print(f'Purged {cursor.rowcount} messages older than {retention_days} days')
# Run nightly retention cleanup
conn = init_db()
purge_old_messages(conn, retention_days=90)
print('Retention policy applied')การตรวจสอบความต่อเนื่องของเซสชัน
เมื่อกลับมาใช้เซสชันต่อหลังจากเว้นช่วงเป็นเวลานาน ให้แจ้งเอเจนต์เกี่ยวกับช่วงเวลาดังกล่าวว่า ผู้ใช้หายไปนานเท่าใดและมีอะไรเปลี่ยนแปลงบ้าง วิธีนี้ช่วยป้องกันการเปลี่ยนบริบทอย่างฉับพลันจนทำให้สับสน
import sqlite3
from datetime import datetime, timedelta
def get_session_gap_context(conn: sqlite3.Connection, session_id: str) -> str:
row = conn.execute(
'SELECT last_active FROM sessions WHERE session_id = ?',
(session_id,)
).fetchone()
if not row or not row['last_active']:
return ''
last_active = datetime.fromisoformat(row['last_active'])
gap = datetime.utcnow() - last_active
if gap < timedelta(minutes=30):
return '' # Recent session, no gap context needed
elif gap < timedelta(hours=12):
return f'Note: The user was last active {int(gap.total_seconds() / 3600)} hours ago.'
elif gap < timedelta(days=7):
return f'Note: The user was last active {gap.days} days ago.'
else:
return f'Note: The user returns after {gap.days} days away. Welcome them back warmly.'
conn = init_db()
gap = get_session_gap_context(conn, 'sess-abc')
if gap:
print('Gap context:', gap)
else:
print('No gap context needed')ตรวจสอบความรู้: การคงบริบท
ทดสอบความเข้าใจเกี่ยวกับการคงบริบทข้ามเซสชันของเอเจนต์
สรุปการคงบริบท
เอเจนต์ที่คงบริบทจัดเก็บสถานะเซสชันใน SQLite (ผู้ใช้คนเดียว) หรือ Redis (หลายเซิร์ฟเวอร์) บันทึกทุกข้อความเพื่อสร้างประวัติ ดึงและจัดเก็บข้อเท็จจริงของผู้ใช้เพื่อสร้างหน่วยความจำระยะยาว สร้างคำสั่งระบบที่เสริมด้วยการตั้งค่าของผู้ใช้ ใช้การสรุปบทสนทนาเพื่อจัดการข้อจำกัดของหน้าต่างบริบท และใช้นโยบายการเก็บรักษาข้อมูลเพื่อให้สอดคล้องกับข้อกำหนดด้านความเป็นส่วนตัว
คำถามที่พบบ่อย
บทเรียน “การคงอยู่ของบริบทข้ามเซสชัน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การคงอยู่ของบริบทข้ามเซสชัน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การคงอยู่ของบริบทข้ามเซสชัน”
จัดเก็บและโหลดการตั้งค่าผู้ใช้ ประวัติการสนทนา และสถานะงาน คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การคงอยู่ของบริบทข้ามเซสชัน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม
ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- รูปแบบการออกแบบเอเจนต์ที่ทำงานตลอดเวลา
- ระบบการแจ้งเตือนและการเตือนเชิงรุก
- การคงอยู่ของบริบทข้ามเซสชัน
- การสร้างเอเจนต์สรุปข้อมูลประจำวัน