วางตัวตัดสินความเกี่ยวข้องขนาดเล็กไว้หน้า RAG — ไม่ส่งทุกอย่างที่ค้นเจอผ่านไปทั้งหมด
บทนำ
ฉันใช้งานฐานความรู้ส่วนตัว (RAG) ที่เก็บบันทึกประจำวันและดึงออกมาด้วยการค้นหาเชิงความหมาย เรื่องการเพิ่มความแม่นยำในการค้นหาด้วยตัวเลขเองนั้น ฉันเขียนไว้ใน การปรับปรุงความแม่นยำการค้นหา RAG แบบขับเคลื่อนด้วยการวัดผล
แต่ต่อให้การค้นหาเก่งขึ้นแล้ว ก็ยังมีปัญหาที่เหลืออยู่ การค้นหาแบบเวกเตอร์จะดึง “สิ่งที่ใกล้เคียงกันในเชิงความหมาย” มาให้ แต่บางอย่างที่ใกล้เคียงกันก็ไม่เกี่ยวข้องกับคำถามจริงๆ นี่คืออีกด้านหนึ่งของความตรงไปตรงมาของ embedding ซึ่งฉันเขียนไว้ในอีกบทความหนึ่งด้วย (กับดักที่การค้นหาเวกเตอร์ปนหมวดหมู่อื่นเข้ามา)
ถ้าส่งทุกอย่างที่ดึงมาตรงไปให้ LLM ทั้งหมด ความทรงจำที่ไม่เกี่ยวข้องจะกลายเป็นสัญญาณรบกวนและทำให้คำตอบขุ่นมัว บทความนี้เป็นเรื่องการวางตัวตัดสินขนาดเล็กไว้ระหว่างการค้นหากับ LLM เพื่อตัดสินว่า “สิ่งนี้เกี่ยวข้องจริงหรือไม่”
ปัญหา: การค้นเจอ ≠ คำตอบที่ถูกต้อง
RAG แบบไร้เดียงสาจะยัดทุกอย่างที่ขึ้นอันดับบนสุดของการค้นหาลงใน prompt ของ LLM โดยตรง ไม่มีประตูคุณภาพคอยกรอง
คำถาม
│
▼
การค้นหา (ดึงสิ่งที่ใกล้เคียงเชิงความหมายจากอันดับบนสุด)
│ ← สิ่งที่แค่ใกล้เคียงแต่ "ไม่เกี่ยวข้อง" ก็ขึ้นมาปนด้วย
▼
ส่งทุกอย่างที่ดึงมาให้ LLM ทั้งหมด ← ความทรงจำที่ไม่เกี่ยวข้องทำให้คำตอบขุ่นมัว
“ใกล้เคียงเชิงความหมาย” ไม่ได้แปลว่า “เกี่ยวข้อง” เสมอไป เมื่อบันทึกที่แค่มีคำคล้ายกันแต่ไม่เกี่ยวข้องกับคำถามเลยปนเข้ามา LLM ก็จะถูกดึงไปตามนั้น
แนวคิด: วางตัวตัดสินไว้ระหว่างการค้นหากับ LLM (CRAG)
แกนของมาตรการนี้เรียบง่าย หลังจากค้นหาแล้ว ก่อนส่งให้ LLM ให้ตัดสิน “เกี่ยวข้องหรือไม่” ทีละรายการ ปล่อยให้เฉพาะที่เกี่ยวข้องผ่านไป ตัดสิ่งที่ไม่เกี่ยวข้องทิ้ง เพราะเป็นการแก้ไขคุณภาพหลังการค้นหา รูปแบบนี้จึงเรียกว่า CRAG (Corrective RAG)
คำถาม
│
▼
การค้นหา (ดึงสิ่งที่ใกล้เคียงเชิงความหมายมา)
│
▼
┌──────────────────────────────────────────────┐
│ ตัวตัดสิน: ความทรงจำนี้เกี่ยวข้องกับคำถามนี้หรือไม่? (ตัดสินแบบสองค่า) │
└──────────────────────────────────────────────┘
│
├─ เกี่ยวข้อง ─▶ ส่งให้ LLM
└─ ไม่เกี่ยวข้อง ─▶ ตัดทิ้ง (ไม่ทำให้คำตอบสกปรก)
ทำไมต้องเป็น “ตัวตัดสินขนาดเล็ก” ไม่ใช่ “LLM ขนาดใหญ่”
การตัดสินเองก็ทำได้ด้วย LLM ขนาดใหญ่เหมือนกัน แต่การถาม LLM ขนาดใหญ่ทีละรายการทุกครั้งที่ค้นหานั้นช้าและหนัก และถ้าส่งไปยัง API ภายนอก ก็เท่ากับส่งความทรงจำของตัวเองขึ้นคลาวด์ทุกครั้งด้วย
ฉันจึงเตรียมโมเดลขนาดเล็กที่เชี่ยวชาญเฉพาะการตัดสินเท่านั้น และไม่ใช่การตัดสินแบบทั่วไป แต่ปรับแต่งด้วย ข้อมูลฝึกที่ตรงกับโดเมนของ RAG ของตัวเอง เพราะงานของตัวตัดสินมีแค่สองค่า “ใช้/ไม่ใช้” โมเดลเล็กก็เพียงพอแล้ว
【ให้ LLM ขนาดใหญ่ตัดสินทุกครั้ง】
ผลการค้นหา ─▶ โมเดลขนาดใหญ่ ─▶ ตัดสิน … ช้า หนัก (ถ้าเป็นภายนอก) ส่งข้อมูลขึ้นคลาวด์
【ตัวตัดสินขนาดเล็กที่ปรับแต่งตามโดเมนของตัวเอง】
ผลการค้นหา ─▶ โมเดลขนาดเล็ก (ในเครื่อง) ─▶ ใช้ / ไม่ใช้ … เร็ว เบา จบในเครื่อง
ข้อดีของการทำให้จบในเครื่องไม่ใช่แค่ความเร็ว ยังตัดสินได้โดยไม่ต้องส่งความทรงจำของตัวเองออกไปข้างนอกเลย (ความเป็นส่วนตัว) สำหรับ RAG ที่จัดการบันทึกส่วนตัว เรื่องนี้สำคัญมาก
สิ่งที่สร้างขึ้น (ผลวัดจริง)
ฐานคือโมเดลขนาดเล็กที่ผ่านการปรับแต่งตามคำสั่งแล้ว (Qwen2.5-3B) ฉันปรับแต่งโมเดลนี้ด้วย QLoRA (quantization 4bit + LoRA) ให้ตัดสินความเกี่ยวข้องแบบสองค่า การฝึกทำบน GPU โน้ตบุ๊กในเครื่อง (RTX 2070 Max-Q) ใช้เวลาประมาณ 1 ชั่วโมง 53 นาที loss สุดท้ายอยู่ที่ประมาณ 1.45 และความแม่นยำในการตัดสินแบบสองค่าอยู่ที่ประมาณ 76%
76% ไม่ใช่ความสมบูรณ์แบบ แต่หน้าที่ของตัวตัดสินคือ “ตัดสิ่งที่ไม่เกี่ยวข้องอย่างชัดเจนทิ้ง” ไม่ใช่การคัดกรองที่สมบูรณ์แบบ ในฐานะตะแกรงกรองด่านแรก มันทำงานได้เพียงพอแล้ว จริงๆ แล้วตอนนี้ตัวตัดสินนี้ทำงานทุกครั้งที่มีการค้นหา คอยตัดชิ้นส่วนที่มีความเกี่ยวข้องต่ำทิ้งอย่างเงียบๆ
แทนที่จะทำให้ตัวเลขดูดีเกินจริง ขอพูดตรงๆ เล็ก เร็ว จบในเครื่อง และตัดสัญญาณรบกวนที่ชัดเจนทิ้งได้ — นั่นคือเป้าหมาย และเป้าหมายนั้นก็บรรลุแล้ว
เพื่อไม่ให้การค้นเจอกลายเป็นคำตอบที่ถูกต้อง
การค้นเจอไม่ใช่คำตอบที่ถูกต้อง วางตัวตัดสินไว้ก่อนส่งผ่าน อย่าส่งทุกอย่างที่ขึ้นอันดับบนในการค้นหาให้ LLM ตรงๆ ทั้งหมด “ใกล้เคียงเชิงความหมาย” กับ “เกี่ยวข้อง” เป็นคนละเรื่อง ต้องแทรกด่านตรวจสอบความเกี่ยวข้องไว้หนึ่งชั้น
ตัวตัดสินไม่จำเป็นต้องพึ่งโมเดลขนาดใหญ่ สร้างให้เล็กและเฉพาะทางได้ สำหรับงานที่จำกัดอย่างการตัดสินแบบสองค่า การปรับแต่งโมเดลเล็กด้วยข้อมูลฝึกในโดเมนของตัวเองก็เพียงพอ เร็ว เบา และทำงานในเครื่องได้
ทำให้จบในเครื่อง อย่าส่งความทรงจำออกไปข้างนอก ถ้าจัดการบันทึกส่วนตัว ให้เลือกโครงสร้างที่ไม่ต้องส่งเนื้อหาขึ้นคลาวด์เพียงเพื่อการตัดสิน
การทำให้ค้นหาเร็วเป็นแค่ครึ่งหนึ่งของการปรับแต่ง การกรองสิ่งที่ดึงมาด้วยว่ามันเกี่ยวข้องจริงหรือไม่ — ต่อเมื่อมีตัวตัดสินนี้ RAG จึงจะเริ่มคืนสิ่งที่ “มีประโยชน์” ไม่ใช่แค่ “ใกล้เคียง”
บทความที่เกี่ยวข้อง
- เรื่องการเพิ่มความแม่นยำในการค้นหาด้วยตัวเลขเองนั้น อยู่ใน การปรับปรุงความแม่นยำการค้นหา RAG แบบขับเคลื่อนด้วยการวัดผล
- กับดักรากเดียวกันที่ว่า “ใกล้เคียงเชิงความหมาย ≠ ควรแสดงผล” สรุปไว้ใน กับดักที่การค้นหาเวกเตอร์ปนหมวดหมู่อื่นเข้ามา
- เรื่องการนำการค้นหาเชิงความหมายนี้มาใช้งานโดยไม่เพิ่ม vector DB เฉพาะทางเลย อยู่ใน “ความหมาย” ไม่ใช่ “ตัวอักษร” — การนำการค้นหาเชิงความหมายมาใช้โดยไม่เพิ่ม vector DB เฉพาะทาง
- บันทึกการปรับแต่งโมเดลขนาดเล็กด้วย GPU ในเครื่อง (QLoRA) ที่เป็นรากฐานของตัวตัดสินนี้ อยู่ใน Fine-Tune RAG ส่วนตัวด้วยแค่แล็ปท็อป RTX 2070