🇬🇧 มีฉบับภาษาอังกฤษ: Read this article in English →

เจาะลึกการออกแบบ Hierarchical Long-Term Memory: สร้างสมองที่ไม่สิ้นสุดให้ Local Agent ด้วย SQLite และ Vector DB แบบ Zero-Cloud

เจาะลึกการออกแบบ Hierarchical Long-Term Memory: สร้างสมองที่ไม่สิ้นสุดให้ Local Agent ด้วย SQLite และ Vector DB แบบ Zero-Cloud

บทนำ: ข้ามผ่านข้อจำกัดของ Context Window สู่ความทรงจำที่ยั่งยืน

ในโลกของการพัฒนาปัญญาประดิษฐ์แบบกระจายศูนย์ (Decentralized AI) และ Local Agent ปัจจุบันเราเผชิญกับจุดเปลี่ยนสำคัญที่เรียกว่า "Context Window Crisis" หรือวิกฤตหน้าต่างบริบท แม้ว่าโมเดลภาษาขนาดใหญ่ (LLM) รุ่นใหม่ๆ จะมีประสิทธิภาพสูงขึ้นเรื่อยๆ แต่ข้อจำกัดทางฮาร์ดแวร์และต้นทุนการคำนวณยังคงเป็นกำแพงกั้นที่สำคัญ การพึ่งพา Cloud API เพื่อจัดการความทรงจำระยะยาวไม่ใช่ทางเลือกที่ยั่งยืนสำหรับผู้ที่เน้นความเป็นส่วนตัวและความสามารถแบบ Offline ดังนั้น การออกแบบสถาปัตยกรรม Hierarchical Long-Term Memory ที่ใช้ SQLite คู่กับ Vector Database ในระบบ Zero-Cloud จึงกลายเป็นกุญแจสำคัญในการสร้าง "สมองที่ไม่สิ้นสุด" ให้ Local Agent ของคุณ

ก่อนเริ่ม: ติดตั้งแพ็กเกจ Python ที่ใช้ในบทความนี้

pip install sentence-transformers

บทความนี้จะเจาะลึกถึงวิธีการออกแบบระบบความทรงจำที่มีโครงสร้างชั้น (Hierarchy) อย่างละเอียด ตั้งแต่การจัดการข้อจำกัดของ Context Window ไปจนถึงการเขียนโค้ดจริงด้วย Python เพื่อสร้างระบบที่ทำงานได้อย่างรวดเร็วและแม่นยำบนเครื่องของคุณเอง โดยไม่ต้องพึ่งพาอินเทอร์เน็ตเลยแม้แต่น้อย

The Context Window Crisis: ทำไม Local Agent ถึงติดอยู่กับการแค่ Context Window

ก่อนที่เราจะก้าวไปสู่ทางออก เราต้องเข้าใจปัญหาอย่างถ่องแท้ "Context Window" หรือหน้าต่างบริบท คือจำนวนโทเค็น (Tokens) ที่โมเดล AI สามารถอ่านและประมวลผลได้ในครั้งเดียว สำหรับ Local Agent ที่ทำงานบนฮาร์ดแวร์ส่วนบุคคล เช่น Laptop หรือ Desktop การมี VRAM จำกัดหมายความว่าเราไม่สามารถโหลด Context ที่ใหญ่เกินกว่าความสามารถของกราฟิกการ์ดได้

หากคุณพยายามส่งประวัติการสนทนาทั้งหมดหรือเอกสารจำนวนมากเข้าสู่ Prompt ในแต่ละรอบ คุณจะเผชิญกับปัญหาสามประการหลัก:

1. ความล่าช้าอย่างรุนแรง (Latency Spike): เมื่อ Context มีขนาดใหญ่ขึ้น เวลาในการ Inferencing จะเพิ่มขึ้นแบบไม่เป็นเชิงเส้น ทำให้ Agent รู้สึกเหมือน "คิดไม่ออก" หรือตอบสนองช้าจนใช้งานจริงไม่ได้

2. อาการหลงลืม (Forgetting Effect): แม้โมเดลจะมี Context Window กว้างขวาง แต่ตามหลักวิจัยเรื่อง "Lost in the Middle" โมเดลมักจะสนใจข้อมูลที่อยู่ตอนต้นและตอนท้ายของบทสนทนา ในขณะที่ข้อมูลสำคัญที่ปรากฏอยู่ตรงกลางมักจะถูกมองข้ามหรือละเลยเมื่อความยาวเพิ่มขึ้น

3. ต้นทุนทรัพยากรที่สูงเกินจำเป็น: การส่งข้อมูลที่ไม่เกี่ยวข้อง (Irrelevant Data) เข้าสู่ระบบการคิด เป็นการเสียพลังงานและการคำนวณโดยไม่เกิดมูลค่าเพิ่ม

ดังนั้น Local Agent จึงไม่สามารถพึ่งพา "ความจำระยะสั้น" ที่ขยายออกไปเรื่อยๆ ได้ มันต้องการ "ความจำระยะยาว" ที่มีโครงสร้าง ซึ่งสามารถดึงข้อมูลเฉพาะส่วนที่ relevan (สอดคล้องกับบริบทปัจจุบัน) มาใส่ใน Context Window เฉพาะหน้าได้อย่างชาญฉลาด นี่คือที่มาของการออกแบบ Hierarchical Memory

สถาปัตยกรรม Hierarchical Long-Term Memory: โครงสร้างสมองสองชั้น

เพื่อให้ Local Agent ทำงานได้เหมือนมนุษย์ที่มีความทรงจำยาวนาน เราต้องแบ่งโครงสร้างความทรงจำออกเป็น 2 ชั้นหลัก ซึ่งทำงานประสานกันผ่านระบบ Zero-Cloud:

1. ชั้นที่ 1: Episodic Memory (ความจำเหตุการณ์)

ใช้ SQLite เป็นฐานข้อมูลหลัก เก็บข้อมูลดิบ เช่น ประวัติการสนทนา, ไฟล์ที่อ่าน, หรือบันทึกเหตุการณ์ต่างๆ ข้อมูลในชั้นนี้จะมีโครงสร้างชัดเจน (Structured Data) มี Timestamp และ Metadata ทำให้สามารถค้นหาด้วยเงื่อนไขที่แม่นยำได้รวดเร็วมาก

2. ชั้นที่ 2: Semantic Memory (ความจำเชิงแนวคิด)

ใช้ Vector Database (เช่น ChromaDB, Qdrant หรือ SQLite-VSS) เก็บ Embedding ของความรู้สำคัญ ข้อมูลในชั้นนี้แปลงจากข้อความปกติเป็นเวกเตอร์ตัวเลข ทำให้สามารถค้นหาแบบ "ความหมาย" (Semantic Search) ได้ เช่น คุณถามว่า "วิธีทำกาแฟ" ระบบจะเข้าใจแม้คุณไม่ได้ใช้คำว่า "กาแฟ" ในคำถามเดิม

การเชื่อมโยงระหว่างสองชั้นนี้คือหัวใจของระบบ โดย SQLite ทำหน้าที่เป็นตัวจัดการ Metadata และอ้างอิงถึงตำแหน่งใน Vector DB ในขณะที่ Vector DB ทำหน้าที่หาความสัมพันธ์เชิงความหมาย ทั้งสองอย่างทำงานอยู่บนเครื่องของคุณผ่านไฟล์หรือ Local Server ทำให้เป็นระบบ Zero-Cloud อย่างแท้จริง

การตั้งค่าและติดตั้งระบบฐานข้อมูลคู่ (SQLite + Vector DB)

ขั้นตอนแรกคือการเตรียมสภาพแวดล้อมให้รองรับการจัดเก็บข้อมูลทั้งแบบโครงสร้างและแบบเวกเตอร์ เราจะใช้ Python เป็นตัวเชื่อมประสาน โดยแนะนำไลบรารี sqlite-vec หรือ ChromaDB สำหรับกรณีที่ต้องการความเรียบง่ายในการติดตั้งบนเครื่องเดียว

การติดตั้ง Dependencies

คุณต้องติดตั้งไลบรารีที่จำเป็นก่อนเริ่มเขียนโค้ด โปรดใช้คำสั่ง Shell ต่อไปนี้:

pip install sqlite-vec langchain chromadb numpy pandas

*หมายเหตุ: หากคุณต้องการประสิทธิภาพสูงสุดและไม่ต้องพึ่งพาไลบรารีภายนอกมากเกินไป คุณสามารถใช้ sqlite-vec ซึ่งเป็น Extension ของ SQLite ที่ให้คุณเก็บและค้นหา Vector ได้โดยตรงภายในฐานข้อมูล SQLite ไฟล์เดียว ซึ่งเหมาะสำหรับ Local Agent ขนาดเล็กมาก*

การออกแบบ Schema ของ SQLite

โครงสร้างตารางใน SQLite ควรแยกเก็บ Metadata ของความทรงจำ เพื่อให้การค้นหาในชั้นแรก (Retrieval) ทำได้รวดเร็ว ก่อนที่จะส่งไปค้นหาเชิงความหมายในชั้นที่สอง

CREATE TABLE episodic_memory (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
    content_type TEXT CHECK(content_type IN ('chat', 'file', 'note')),
    summary TEXT, -- สรุปสั้นๆ ของเนื้อหาเพื่อใช้ในการค้นหาเบื้องต้น
    metadata_json TEXT, -- เก็บข้อมูลเสริมในรูปแบบ JSON เช่น source_file, tags
    vector_store_id TEXT -- ID ที่อ้างอิงไปยัง Vector DB (เช่น ChromaDB)
);

CREATE TABLE semantic_memory_index (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    memory_ref_id INTEGER,
    embedding_vector BLOB, -- หากใช้ sqlite-vec จะเก็บเป็น BLOB
    FOREIGN KEY(memory_ref_id) REFERENCES episodic_memory(id)
);

การเขียนโค้ด Python: กลไกการบันทึกและดึงความจำ

ส่วนที่สำคัญที่สุดคือ Logic ในการจัดการข้อมูล เราจะสร้าง Class พื้นฐานที่รับผิดชอบในการแปลงข้อความเป็น Embedding และจัดเก็บลงสู่ระบบทั้งสองชั้นพร้อมกัน

ส่วนที่ 1: การสร้าง Embedding แบบ Local

เพื่อให้เป็น Zero-Cloud คุณต้องใช้โมเดล Embedding ที่ทำงานบนเครื่องได้ เช่น sentence-transformers ซึ่งสามารถรันผ่าน CPU หรือ GPU ในเครื่องของคุณได้

from sentence_transformers import SentenceTransformer
import sqlite3
import json

class LocalMemoryManager:
    def __init__(self, db_path="agent_memory.db"):
        self.db_path = db_path
        self.conn = sqlite3.connect(db_path)
        self.setup_db()
        
        # โหลดโมเดล Embedding ในเครื่อง (ใช้ CPU Model เพื่อความเข้ากันได้กับทุกเครื่อง)
        # 'all-MiniLM-L6-v2' เป็นโมเดลที่เล็กและเร็ว เหมาะกับ Local Agent
        self.embedder = SentenceTransformer('all-MiniLM-L6-v2')
        
    def setup_db(self):
        cursor = self.conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS episodic_memory (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
                content_type TEXT,
                summary TEXT,
                metadata_json TEXT,
                embedding_vector BLOB
            )
        """)
        self.conn.commit()

    def _text_to_embedding(self, text):
        """แปลงข้อความเป็นเวกเตอร์ตัวเลข"""
        embedding = self.embedder.encode(text)
        # แปลง numpy array เป็น bytes เพื่อเก็บใน SQLite
        return embedding.tobytes()

    def store_memory(self, content_type: str, raw_content: str, metadata: dict = None):
        """บันทึกความจำลงสู่ระบบ Hierarchical"""
        summary = raw_content[:200] + "..." if len(raw_content) > 200 else raw_content
        
        # 1. สร้าง Embedding จากเนื้อหา
        embedding_vector = self._text_to_embedding(raw_content)
        
        # 2. บันทึก Metadata ลงใน SQLite
        meta_json = json.dumps(metadata) if metadata else "{}"
        cursor = self.conn.cursor()
        cursor.execute(
            "INSERT INTO episodic_memory (content_type, summary, metadata_json, embedding_vector) VALUES (?, ?, ?, ?)",
            (content_type, summary, meta_json, embedding_vector)
        )
        self.conn.commit()
        
        return cursor.lastrowid

ส่วนที่ 2: การดึงความจำแบบ Hybrid Search

เมื่อ Agent ต้องการตอบคำถามหรือดำเนินการต่อ มันต้องค้นหาข้อมูลที่เกี่ยวข้องจากฐานข้อมูล massive ข้อมูลนี้เรียกว่า Retrieval เราใช้เทคนิค Hybrid Search คือค้นหาทั้งจาก Keyword (ใน summary/metadata) และ Semantic (จาก embedding vector)

    def retrieve_relevant_memories(self, query: str, limit: int = 5):
        """ดึงความจำที่เกี่ยวข้องกับคำถาม"""
        
        # แปลง Query เป็น Vector
        query_vector = self.embedder.encode(query)
        query_bytes = query_vector.tobytes()
        
        cursor = self.conn.cursor()
        
        # ใช้ฟังก์ชัน distance ของ sqlite-vec เพื่อค้นหาข้อมูลที่คล้ายกันที่สุด
        # หมายเหตุ: ต้องมี extension sqlite-vec ติดตั้งใน Python environment ด้วย
        # หากไม่มี extension อาจใช้การคำนวณ cosine similarity เองผ่าน numpy
        
        query_sql = f"""
            SELECT id, summary, metadata_json, 
                   vec_distance_cosine(embedding_vector, x'{''.join(f'{b:02x}' for b in query_bytes)}') as distance
            FROM episodic_memory
            ORDER BY distance ASC
            LIMIT ?
        """
        
        cursor.execute(query_sql, (limit,))
        results = cursor.fetchall()
        
        # แปลงผลลัพธ์กลับเป็น Dictionary
        memories = []
        for row in results:
            mem_id, summary, meta_json, score = row
            metadata = json.loads(meta_json)
            memories.append({
                "id": mem_id,
                "summary": summary,
                "metadata": metadata,
                "relevance_score": 1.0 / (1.0 + score) # แปลง distance เป็นความคล้ายคลึง
            })
            
        return memories

การปรับจูนประสิทธิภาพจริง: เคล็ดลับสำหรับ Local Agent

การมีระบบฐานข้อมูลที่ถูกต้องเป็นเพียงครึ่งเดียว อีกครึ่งหนึ่งคือการปรับจูนให้ทำงานได้ลื่นไหลบนทรัพยากรจำกัด นี่คือเทคนิคสำคัญที่คุณควรนำไปใช้:

1. การใช้ Quantization สำหรับ Embedding

โมเดล Embedding ขนาดปกติ (Float32) กินพื้นที่และความเร็วในการคำนวณสูง สำหรับ Local Agent คุณสามารถใช้ Quantized Model (เช่น INT8 หรือ FP16) ได้ ซึ่ง sentence-transformers รองรับฟีเจอร์นี้โดยอัตโนมัติ การลดขนาดข้อมูลลงครึ่งหนึ่งหรือมากกว่า จะช่วยให้การคำนวณบน CPU เร็วขึ้นอย่างมีนัยสำคัญ โดยเสียความแม่นยำเพียงเล็กน้อยที่ยอมรับได้ในการค้นหาทั่วไป

# ตัวอย่างการใช้โมเดลที่ผ่านการ Quantize แล้วเพื่อความเร็วสูงสุด
quantized_model = SentenceTransformer('all-MiniLM-L6-v2', quantized=True)

2. การทำ Aggregation และความทรงจำระยะยาว (Summarization)

หากคุณบันทึกทุกการสนทนาทุกวัน ข้อมูลจะเติบโตเร็วมากและทำให้การค้นหาช้าลง คุณควรสร้าง "Agent Summary Worker" ที่ทำงานเป็น Background Process เพื่อสรุปความทรงจำเก่าๆ ให้กระชับขึ้น แทนที่จะเก็บประโยคเดิมทั้งหมด

ตัวอย่างเช่น แทนที่จะเก็บบันทึก 50 ประโยคของวันที่ผ่านมา คุณสามารถใช้โมเดลขนาดเล็กสรุปเป็นย่อหน้าเดียว แล้วเก็บย่อนั้นลงใน SQLite พร้อมเวกเตอร์ของความหมายโดยรวม วิธีนี้เรียกว่า Memory Condensation ช่วยลดขนาดข้อมูลได้กว่า 90% โดยคงสาระสำคัญไว้

3. การจัดการ Metadata Filtering

ก่อนจะทำการค้นหาเชิงความหมาย (Vector Search) ควรมีการกรองด้วย Metadata ของ SQLite ก่อนเสมอ หากผู้ใช้ถามว่า "ไฟล์ PDF ที่ฉันอัปโหลดเมื่อวาน", คุณควรใช้ SQL Query กรอง content_type='file' และ timestamp > yesterday ออกมาก่อน แล้วจึงส่งเฉพาะส่วนที่เหลือไปหา Vector DB การทำ Hybrid Filtering แบบนี้ช่วยลดจำนวน Vector ที่ต้องคำนวณระยะห่างลงได้มหาศาล ทำให้ความเร็วในการตอบกลับเพิ่มขึ้นหลายเท่า

บทสรุป: สร้างสมองที่ยั่งยืนด้วยทรัพยากรที่มีอยู่

การออกแบบ Hierarchical Long-Term Memory ด้วย SQLite และ Vector Database ในรูปแบบ Zero-Cloud ไม่ใช่เพียงเทคนิคทางวิศวกรรมซอฟต์แวร์ แต่เป็นการเปลี่ยนมุมมองต่อความสัมพันธ์ระหว่างมนุษย์และ AI จาก "ผู้ใช้บริการคลาวด์" สู่ "เจ้าของข้อมูลส่วนบุคคล" ด้วยสถาปัตยกรรมนี้ Local Agent ของคุณจะไม่ติดกับดักของ Context Window Crisis อีกต่อไป

คุณสามารถบันทึกประสบการณ์ ความรู้ และบริบทต่างๆ ลงในระบบความจำที่มีโครงสร้างได้ไม่จำกัด โดยระบบจะจัดการดึงข้อมูลที่จำเป็นมาแสดงเฉพาะหน้าเมื่อต้องการ ทำให้การโต้ตอบเป็นไปอย่างมีความหมายและต่อเนื่อง แม้จะทำงานบนเครื่องคอมพิวเตอร์ทั่วไปที่ไม่มี GPU ระดับสูงก็ตาม

ในก้าวถัดไป คุณอาจพิจารณาเพิ่มชั้นของความทรงจำแบบ Procedural (ความจำในการกระทำ) หรือเชื่อมต่อกับ File System ของระบบปฏิบัติการโดยตรง เพื่อสร้าง Agent ที่ไม่เพียงแต่ "จำ" ได้ แต่ยัง "เข้าใจ" และ "ดำเนินการ" กับโลกดิจิทัลของคุณได้อย่างแท้จริง เริ่มต้น从今天นี้ด้วยการติดตั้ง SQLite และ Vector DB ให้เป็นรากฐานแห่งปัญญาของคุณเอง

🛒 TREND DEE STORE • ร้านเทรนด์ดี

🛠️ เครื่องสำหรับรัน Autonomous Agent ตลอด 24 ชม.

คัดสรรอุปกรณ์ที่ตอบโจทย์และใช้งานจริงตามเนื้อหาในบทความนี้