Tech Blog

การค้นหาแบบเวกเตอร์แอบผสม "สิ่งที่ความหมายใกล้เคียง" เข้ามาเอง — กับดักของแคตตาล็อกต่างประเภทที่ปนเข้าไปในการแนะนำ

RAG Vector Search Embeddings Recommendation Search

บทนำ

ผมกำลังสร้างแพลตฟอร์มรวมบริการ (“EVERY DAYS”) ที่รวมวิดีโอและเพลงไว้ด้วยกันด้วยตัวคนเดียว มันนำหลายบริการ — การสตรีมวิดีโอ (VOD), การเช่าส่งถึงบ้านของ DVD และ CD และอื่น ๆ — มาไว้ภายใต้สมาชิกเดียวกันและหน้าจอเดียวกัน แนวคิดในการขยายธุรกิจเช่ารายเดียวให้กลายเป็นแพลตฟอร์มรวมบริการแบบ DMM เขียนไว้ใน จากการเช่า DVD สู่แพลตฟอร์มแบบ DMM

เพราะการออกแบบนี้ งานวิดีโอ (VOD, DVD) และเพลง (CD) จึงอยู่ด้วยกันภายในระบบเดียวกัน และการค้นหา การแนะนำที่เกี่ยวข้อง และการปรับให้เหมาะกับแต่ละคน ล้วนรองรับด้วยดัชนี embedding ตัวเดียว โดยแปลงไอเทมเป็นเวกเตอร์เก็บไว้ แล้วคืน “สิ่งที่ใกล้เคียง” ด้วยความคล้าย cosine เท่านั้น เป็นโครงสร้างที่เบา เรื่อง embedding และการค้นหาเชิงความหมายเองเขียนไว้ใน เพิ่มความแม่นยำการค้นหาของ RAG แบบขับเคลื่อนด้วยการวัด บทความนี้เป็นเรื่องของกับดักหนึ่งที่แอบซ่อนอยู่ในโครงสร้างนั้น

กับดักจะปรากฏ เมื่อแคตตาล็อกต่างประเภทอยู่ในดัชนีเดียวกัน เมื่องานวิดีโอ (VOD, DVD) และเพลง CD อยู่ในดัชนีเดียวกัน การพยายามแสดง “สิ่งที่ใกล้กับงานวิดีโอชิ้นนี้” กลับได้เพลง CD ปนกลับมาด้วย เพราะสำหรับ embedding แล้ว ทั้งสอง “ความหมายใกล้เคียงกัน” แต่จากฝั่งผู้ใช้ พวกเขากำลังหาวิดีโออยู่ แต่กลับถูกยัดของอย่างอื่นเข้ามา


เกิดอะไรขึ้น

ในโครงสร้างนี้ ดัชนีตัวเดียวมีทางออกสามทาง

                          ┌─▶ ① ค้นหาเชิงความหมาย: ข้อความคำค้น ─────────▶ ไอเทมที่ใกล้
   ดัชนี embedding ตัวเดียว ─┼─▶ ② แนะนำที่เกี่ยวข้อง: ไอเทมหนึ่ง ─────────▶ ไอเทมที่ใกล้
   (ทุกไอเทมอยู่ด้วยกัน)     └─▶ ③ ปรับเฉพาะบุคคล: จุดศูนย์กลางของประวัติ ─▶ ไอเทมที่ใกล้

            └─ แคตตาล็อกต่างชนิด (วิดีโอ/เพลง …) อยู่ในดัชนีเดียวกัน

                        └─▶ หมวดหมู่อื่นแทรกขึ้นอันดับบนเพียงเพราะ "ความหมายใกล้"

                          (เกิดขึ้นที่ทางออกทั้งสาม ①②③)

ทั้งสามฟังก์ชันใช้ดัชนีเดียวกัน การปนกันจึงเกิดในลักษณะเดียวกันที่ทางออกทั้งสาม แม้จะสังเกตเห็นบนหน้าจอเดียว ที่ที่ต้องแก้ก็ไม่ได้มีแค่ที่เดียว


ทำไมจึงเกิดขึ้น

สิ่งที่ความคล้ายของ embedding วัดคือ “ความใกล้ของความหมาย” เท่านั้น ข้อจำกัดเชิงธุรกิจ — ไอเทมนั้น อยู่ในหมวดหมู่ใด, แสดงให้ผู้ใช้คนนี้ได้หรือไม่, เขาเห็นไปแล้วหรือยัง — ไม่ได้อยู่ในเวกเตอร์ ดังนั้นถ้าหยิบจากบนสุดตามลำดับความคล้าย สิ่งที่ความหมายใกล้แต่ห้ามแสดงก็ปนเข้ามาอย่างหน้าตาเฉย

พูดอีกอย่างคือ “ความหมายใกล้” ไม่เท่ากับ “แสดงได้” embedding ไม่รู้จักเส้นแบ่งของธุรกิจ เส้นแบ่งนั้นเป็นความรู้ที่อยู่ภายนอก embedding


จะอุดอย่างไร

มาตรการมาเป็นชุดสองอย่าง อย่างใดอย่างหนึ่งเพียงลำพังไม่ได้ผล

1. ใส่ตัวกรองเชิงธุรกิจที่แต่ละทางออก

วางตัวกรองที่เก็บเฉพาะหมวดหมู่ที่แสดงได้ไว้ที่ แต่ละทางออก — ค้นหา, ที่เกี่ยวข้อง, และปรับเฉพาะบุคคล จะกรองผลลัพธ์ให้แคบลง หรือกันออกที่ฝั่งคำสั่งค้น แบบไหนก็ได้ สิ่งสำคัญคืออย่าจบที่จุดเดียวเพียงเพราะเป็นดัชนีร่วม กับดักอยู่ที่สามทางออก ตัวกรองจึงต้องมีสามที่

2. ถ้าจะกรอง ก็ขยายหน้าต่างการดึงข้อมูล

ตัวกรองลดจำนวนลง แม้เป้าหมายคือ 10 รายการ ถ้าดึงมาแค่ 10 อันดับบนก่อนแล้วค่อยกรอง หลังกันออกก็จะไม่พอ ดังนั้น ดึงมาหลายเท่าของเป้าหมายโดยเผื่อส่วนที่จะหายไป แล้วค่อยกรอง สำหรับการปรับเฉพาะบุคคลยังต้องกัน “สิ่งที่เห็นไปแล้ว” ออกด้วย จึงดึงเผื่อตามจำนวนประวัติเพิ่มจากเป้าหมาย

[แบบง่าย] ดึงแค่ N อันดับบน ─▶ กรอง ─▶ ไม่ถึงเป้าหมาย/หมวดหมู่อื่นยังเหลือ

                          (ไม่ได้เผื่อส่วนที่หายไป) ┘

[แก้ไข] ดึงหลายเท่าเป้าหมาย+จำนวนประวัติ ─▶ ตัวกรองธุรกิจ ─▶ กันของที่เห็นแล้ว ─▶ เอาบนสุดตามจำนวนเป้าหมาย

                                     ดึงเผื่อให้กว้าง เพื่อให้จำนวนเป้าหมายยังเหลือแม้บนสุดจะหายไป

และเมื่อ embedding ไม่สามารถผลิตจำนวนที่เพียงพอ ก็สลับไปใช้วิธีอื่นอย่างเงียบ ๆ เช่น ลำดับความนิยม (graceful degrade) คุณภาพลดลง แต่ก็ยังดีกว่าได้ผลลัพธ์เป็นศูนย์แล้วหน้าจอว่างเปล่า


สิ่งที่ต้องวางไว้ระหว่าง “ใกล้” กับ “เกี่ยวข้อง”

“ความหมายใกล้” ไม่ใช่ “แสดงได้” ความคล้ายของ embedding วัดแค่ความใกล้ของความหมาย เส้นแบ่งหมวดหมู่ และการที่แสดงได้หรือไม่ เป็นความรู้เชิงธุรกิจที่อยู่ภายนอก embedding อย่าปล่อยผ่านเพียงเพราะมันคล้ายกัน

ใส่ตัวกรองธุรกิจที่แต่ละทางออก แม้จะใช้ดัชนีร่วม ทางเข้า (ดัชนี) อาจมีทางเดียว แต่ทางออกมีหลายทาง อย่าเพิ่งรู้สึกว่าจบเมื่อแก้ที่เดียว ฟังก์ชันที่ใช้ดัชนีเดียวกันย่อมมีกับดักเดียวกัน ถ้าเหยียบที่หนึ่ง ก็ตรวจที่เหลือ

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

embedding ทรงพลัง แต่ซื่อเกินไป มันพาทุกอย่างที่คล้ายกันกลับมา การสอนให้มันรู้ความจำเป็นของธุรกิจ เป็นหน้าที่ของตัวกรองของคุณเองที่วางไว้ภายนอก embedding


บทความที่เกี่ยวข้อง

ส่งข้อความได้ตามสบาย

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