Skip to main content
Glama
ndodth

MCPTest

by ndodth

สรุประบบ: (MCP + AI Agent)


1. ระบบนี้ทำอะไร

ระบบ MCP ที่คอยคุมการทำงานของ AI เป็นผู้ช่วยตอบคำถามเรื่องข้อมูล

  • ผู้ใช้ถาม $\rightarrow$ Agent เลือก tool $\rightarrow$ tool เช็ก cache ก่อน ไม่มีค่อยไป DB จริง $\rightarrow$ ถ้า DB เปลี่ยน ระบบแจ้งเตือนกลับมาล้าง cache ทันที


Related MCP server: Enterprise Financial Compliance Audit Framework

2. องค์ประกอบหลัก

ไฟล์

หน้าที่

main.py

AI Agent — รับคำถาม, ตัดสินใจเรียก tool ผ่าน Gemini

server.py

MCP Server — เปิด tools ให้ Agent เรียกใช้ฐานข้อมูล

semantic_cache.py

Cache ชั้น 1 — เก็บคำถาม-คำตอบเดิมแบบ embedding

webhook_cdc.py

รับแจ้งเตือนจาก Supabase เมื่อข้อมูลเปลี่ยน แล้วล้าง cache

schema.sql

โครงสร้าง DB (customers, purchase_ledger, customer_interactions)


3. ในฐานข้อมูล (DB) เก็บอะไรไว้บ้าง และป้องกันยังไง

DB (PostgreSQL บน Supabase) มี 3 ตารางหลัก:

ตาราง

เก็บอะไร

การป้องกัน / กลไก

customers

ข้อมูลโปรไฟล์ลูกค้า (ชื่อ, ข้อมูลติดต่อ ฯลฯ)

แก้ไขได้ปกติ แต่ทุกครั้งที่แก้ trigger จะยิง webhook แจ้งล้าง cache

purchase_ledger

ประวัติธุรกรรม/ยอดการเงินของลูกค้า

Append-only — ห้าม UPDATE/DELETE เด็ดขาด ผ่าน DB Trigger ที่บล็อกไว้ตรงๆ ที่ระดับฐานข้อมูล (ต่อให้เจาะเข้ามาตรงๆ ก็แก้ไม่ได้)

customer_interactions

ประวัติการพูดคุย/โต้ตอบกับลูกค้า พร้อมเก็บ embedding vector (ใช้ extension pgvector)

ใช้สำหรับ semantic search ย้อนดูบทสนทนาเก่าที่เกี่ยวข้อง

Hash Chain (สำหรับ purchase_ledger โดยเฉพาะ):

  • แต่ละ record ในตารางนี้จะมีค่า entry_hash ที่คำนวณจากข้อมูลของ record นั้น + prev_hash (hash ของ record ก่อนหน้า) ด้วย SHA-256

  • ทำให้ record ทั้งหมดเชื่อมกันเป็น "โซ่" ถ้ามีใครแอบไปแก้ข้อมูลตรงกลางโซ่ (แม้จะพยายามเลี่ยง trigger ก็ตาม) hash ของ record ถัดไปจะไม่ตรงกันทันที ตรวจจับได้ตอน audit

  • พูดง่ายๆ: ต่อให้ป้องกันด้วย trigger แล้ว hash chain คือ "เช็คซ้ำอีกชั้น" ว่าข้อมูลไม่ถูกแตะต้องจริงๆ

PROMPT ของ AI

SYSTEM_PROMPT = """
You are an Enterprise CRM & Financial Audit Ledger AI Assistant.
You have access to trusted backend tools that provide customer profiles, live financial transactions, audit logs, and historical interaction text search.
...
"""

4. Workflow

[1] ผู้ใช้พิมพ์คำถามเข้า main.py
      │
      ▼
[2] ระบบแปลงคำถามเป็น embedding (ด้วย Sentence-Transformers, รันในเครื่อง ไม่เสีย token)
      │
      ▼
[3] เช็ค Layer 1 – Semantic Cache ใน Redis
    ค้นด้วย key: semantic_cache:customer:{customer_id}:*
    เทียบ embedding คำถามใหม่ กับคำถามเก่าที่เคยถามและตอบไปแล้ว (cosine similarity)
      │
      ├───────────────────────────────┐
      ▼ (similarity ≥ 0.92)           ▼ ไม่เจอ / ไม่คล้ายพอ (MISS)
[4a] ส่งคำตอบเดิมกลับทันที          [4b] ส่งคำถาม + รายชื่อ tool ที่มีให้ Gemini
     จบ flow ตรงนี้                     (ไม่เรียก DB, ไม่เรียก DB cache เลย)
                                      │
                                      ▼
                                [5] Gemini ตัดสินใจว่าจะเรียก MCP tool ไหน
                                    (เช่น get_customer_profile, get_customer_financial_summary)
                                      │
                                      ▼
                                [6] Tool ทำงานผ่าน server.py
                                    เช็ค Layer 2 – DB Result Cache ใน Redis ก่อน
                                    key: cache:db:profile:{customer_id}
                                    หรือ cache:db:financial:{customer_id}:{page}:{limit}
                                      │
                                ┌─────┴──────┐
                                ▼ HIT        ▼ MISS
                          [7a] ดึงข้อมูล      [7b] Query PostgreSQL จริง
                               จาก Redis          แล้วเก็บผลลัพธ์ลง Redis
                               (เร็ว ไม่กิน DB)     (ตั้ง TTL 24 ชม.)
                                │            │
                                └─────┬──────┘
                                      ▼
                                [8] ได้ข้อมูลดิบกลับมาที่ Agent
                                      │
                                      ▼
                                [9] เรียก Gemini อีกครั้ง เพื่อเรียบเรียงข้อมูลดิบ
                                    ให้เป็นคำตอบภาษาคนอ่านง่าย
                                      │
                                      ▼
                                [10] ตอบกลับผู้ใช้
                                     + บันทึกคำถาม-คำตอบคู่นี้ลง Layer 1 cache
                                     (ไว้ให้คำถามคล้ายๆ กันครั้งหน้า hit ได้)
  • Layer 1 เช็คจาก ความหมายของคำถาม

  • Layer 2 เช็คจาก ผลลัพธ์ของ DB query ที่เคยทำมาก่อน — เป็นด่านที่สองที่กัน DB ไม่ให้โดนถามซ้ำ

  • ทั้งสอง layer แยกกันทำงานคนละหน้าที่ ไม่ใช่ตัวเดียวกัน


5. Webhook + Backend สำหรับล้าง Cache (CDC) — Workflow ละเอียด

[1] มีการเปลี่ยนแปลงข้อมูลจริงในตาราง customers หรือ purchase_ledger
    (เช่น เพิ่มธุรกรรมใหม่ / แก้โปรไฟล์ลูกค้า)
      │
      ▼
[2] PostgreSQL Trigger บนตารางนั้นทำงานทันที (ก่อน trigger นี้จะเรียกฟังก์ชัน notify_cache_invalidation() ที่เขียนไว้)
      │
      ▼
[3] ฟังก์ชันเรียก net.http_post(...) (มาจาก extension pg_net) ยิง HTTP POST ออกไปหา backend ภายนอก
      │
      ▼
[4] Backend ที่ deploy แยกไว้บน Render (ไฟล์ webhook_cdc.py, เขียนด้วย FastAPI) รับ request ที่ endpoint POST /api/webhook/db-change
      │
      ▼
[5] Backend ตรวจสอบ header x-supabase-signature เทียบกับ secret ที่ตั้งไว้
    → ถ้าไม่ตรง ปฏิเสธทันที (กัน webhook ปลอมยิงเข้ามาสั่งล้าง cache มั่ว)
      │
      ▼
[6] แกะ payload ดูว่า:
    - TG_TABLE_NAME = ตารางไหนที่เปลี่ยน (customers หรือ purchase_ledger)
    - ถ้า table = customers → เอา customer_id จาก record.id
    - ถ้า table = purchase_ledger → เอา customer_id จาก record.customer_id
      │
      ▼
[7] สั่งลบ key ใน Redis:
    - ลบ Layer 1 เสมอ: semantic_cache:customer:{customer_id}:*
      (เพราะคำตอบเก่าที่เคย cache ไว้อาจอ้างอิงข้อมูลลูกค้ารายนี้ที่เปลี่ยนไปแล้ว)
    - ลบ Layer 2 เฉพาะส่วนที่เกี่ยวกับตารางที่เปลี่ยน:
      cache:db:profile:{id} หรือ cache:db:financial:{id}:*
      │
      ▼
[8] ครั้งต่อไปที่มีคนถามถึงลูกค้ารายนี้ → Layer 1 และ Layer 2 จะ miss โดยอัตโนมัติ
    → ระบบไปดึงข้อมูลจาก DB จริง → ได้ข้อมูลล่าสุดเสมอ (Zero-Stale Data)

6. ทำไมเอา Redis มาใช้ (2-Layer Cache)

ปัญหาที่เจอ: ทุกครั้งที่ผู้ใช้ถามคำถาม ถ้าปล่อยให้ระบบวิ่งไปเรียก LLM หรือ query DB ใหม่ทุกครั้ง จะช้าและสิ้นเปลือง โดยเฉพาะกับคำถามที่ถามซ้ำๆ หรือคล้ายเดิม เลยเพิ่ม Redis เข้ามาเป็น cache 2 ชั้น:

  • ชั้น 1 (Semantic Cache) — คำถามคล้ายเดิม ตอบกลับเลยไม่ต้องเรียก LLM ใหม่

  • ชั้น 2 (DB Result Cache) — ผลลัพธ์จาก DB ที่ไม่ค่อยเปลี่ยน ดึงจาก Redis แทนที่จะยิง query เข้า PostgreSQL ใหม่ทุกครั้ง


7. ปัญหาการใช้ Token (LLM) และวิธีลด

ปัญหา: การเรียก Gemini ทุกครั้งที่มีคำถามเข้ามา ทำให้เสีย token และมี latency สูง โดยเฉพาะเวลาที่มีคนถามคำถามซ้ำๆ หรือคล้ายกัน วิธีที่แก้:

  1. Semantic Cache (Layer 1) — เช็คก่อนเรียก Gemini ทุกครั้งว่าเคยมีคนถามคำถามที่ "ความหมายคล้ายกัน" ไหม ถ้าคล้าย $\ge$ 0.92 $\rightarrow$ ข้ามการเรียก Gemini ไปเลย

  2. ใช้ Local Embeddings (Sentence-Transformers) แทนการยิง embedding ผ่าน API ของ Gemini/OpenAI — ขั้นตอนเช็คความคล้ายนี้เลยไม่เสีย token เพิ่มเลย เพราะรันฟรีแบบ offline

  3. แยก cache ตาม customer_id (multi-tenant) กันคำตอบของลูกค้ารายหนึ่งไปปนกับอีกราย

IMPORTANT

ข้อควรรู้: Layer 2 (DB cache) ช่วยลดแค่ฝั่ง DB load/latency เท่านั้น ไม่ได้ลด token ฝั่ง Gemini เพราะไม่ว่า Layer 2 จะ hit หรือ miss ตัว Agent ก็ยังต้องเรียก Gemini อย่างน้อย 2 ครั้งอยู่ดี (เลือก tool + สรุปคำตอบ) — ตัวเดียวที่ลด token จริงคือ Layer 1


8. ภาพรวมทั้งระบบ (End-to-End)

  1. ผู้ใช้ถามผ่าน main.py

  2. เช็ค Semantic Cache ก่อน — คล้ายพอก็ตอบเลย ไม่เรียก Gemini

  3. ถ้าไม่เจอ $\rightarrow$ Gemini เลือก tool ที่เหมาะสม

  4. Tool เช็ค DB Cache ก่อนค่อยไป PostgreSQL จริง

  5. ตอบกลับ + จำคำตอบไว้ใน cache

  6. ถ้า DB เปลี่ยนเมื่อไหร่ $\rightarrow$ Webhook ยิงมาล้าง cache อัตโนมัติทันที


NOTE

python3 -m venv venv
source venv/bin/activate # (สำหรับ Windows ให้ใช้: venv\Scripts\activate)
pip install -r requirements.txt

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that integrates with MySQL databases, enabling secure read and write operations through LLM-driven interfaces with support for transaction handling and performance monitoring.
    63 npm
    18
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A production-ready MCP server for MySQL database integration with AI agents, enabling database exploration, CRUD operations, schema management, and performance monitoring through natural language.
    455 npm
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    A governed MCP server that enforces a trust layer between AI agents and databases, requiring sign-off on joins and metrics and producing auditable receipts for every query.
    -