Journal Query Understanding & Retrieval

จากคำถามสู่คำตอบ: คำถามแบบไหนกลายเป็น tool-call แบบไหนกลายเป็น vector search

คำถามแต่ละชนิดเข้ากับวิธีดึงข้อมูลคนละแบบ — บทนี้พาเข้าใจว่าคำถามแบบไหนเข้ากับ tool-call/text-to-SQL, vector, hybrid หรือ graph และทำไม ผ่าน retrieval pipeline ทั้งเส้น · เมื่อเห็นว่าแต่ละวิธีเก่งงานแบบไหนและแลกมาด้วยอะไร วิธีที่เข้ากับคำถามมักเป็นวิธีที่เบาที่สุดด้วย บทที่ 5 ของ LLM systems series

ผู้ใช้พิมพ์ประโยคเดียว — “ออเดอร์ #1234 ส่งถึงไหนแล้ว” · แต่ก่อนจะตอบ ระบบต้องตอบคำถามที่ผู้ใช้ไม่เห็นก่อน — คำถามนี้เข้ากับการดึงข้อมูลแบบไหน

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

ขอบเขต — บทนี้คือบทที่ 5 ของ LLM systems series · ต่อจาก เลือกระดับ · เลือก vendor · เลือกอย่างปลอดภัย · วางโครงให้ทน · บทก่อนพูดว่า data layer ต้องนิ่ง — บทนี้พูดว่า จะดึงจากมันให้เข้ากับคำถามได้อย่างไร

หัวใจ: คำถามไม่ได้มีชนิดเดียว

เวลาพูดถึง RAG หลายคนนึกถึงภาพเดียว — เอาคำถามไป vector search · แต่ vector search เป็นแค่หนึ่งในหลายวิธี

คำถามของคนแบ่งได้ตาม สิ่งที่มันถามหา:

  • อยากได้ คำตอบที่แน่นอน / คำนวณได้ → เข้ากับ structured query (tool-call, text-to-SQL)
  • อยากได้ ความหมายที่ใกล้เคียง → เข้ากับ semantic search (vector)
  • มีทั้งสองอย่างปนกัน → hybrid · ถามความสัมพันธ์ → graph
แผนภาพ · คำถามภาษาคนเข้าสู่ router ที่เข้าใจ intent และดึง entity/filter แล้วแยกไปสี่ปลายทาง: (1) tool-call / text-to-SQL เมื่อต้องการคำตอบแน่นอน filter นับ join exact lookup เช่น ออเดอร์ #1234 ส่งถึงไหน หรือ เดือนนี้ลูกค้าใหม่กี่คน · (2) vector search เมื่อต้องการความหมายที่ใกล้เคียง fuzzy paraphrase เช่น นโยบายคืนสินค้าเป็นยังไง · (3) hybrid ผสม BM25 + vector + filter เมื่อมีทั้งคำเฉพาะและความหมาย เช่น เงื่อนไขโปรโมชัน X11 ล่าสุด · (4) graph traversal เมื่อถามความสัมพันธ์หลายชั้น เช่น ลูกค้าที่ซื้อ A มักซื้ออะไรต่อ
คำถามแต่ละชนิดเข้ากับวิธีดึงข้อมูลคนละทาง · vector search ถนัดความหมาย ส่วน structured query ถนัดคำตอบที่แน่นอน

ลองวางคำถามจากร้านค้าร้านเดียวเป็นชั้น ๆ — ไล่จาก structured สุด ลงไป semantic สุด · แต่ละชั้นเข้ากับวิธีดึงคนละแบบ:

ตัวอย่างชนิดคำถามเข้ากับ
“ออเดอร์ #1234 ถึงไหน”หาตัวเดียวด้วย keytool-call · point lookup
“เมนูราคาเกิน 100” · “เมนูใส่สตรอเบอร์รี”กรองด้วย fieldSQL filter — WHERE
“เดือนนี้ลูกค้าใหม่กี่คน” · “เมนูขายดีสุด”นับ / คำนวณ / จัดอันดับSQL aggregate — COUNT/SUM
“เมนูไหนสดชื่น” · “อะไรเบา ๆ”คุณภาพที่ไม่มี fieldsemantic — vector หรือ LLM→tag
“นโยบายคืนของเป็นยังไง”อธิบาย / แนวคิดvector — RAG บนเอกสาร
“เงื่อนไขโปร X11 ล่าสุด”คำเฉพาะ + ความหมายhybrid — BM25 + vector
“คนที่ซื้อ A มักซื้ออะไรต่อ”ความสัมพันธ์หลายชั้นgraph

เส้นแบ่ง vector กับ SQL จำง่าย ๆ — คำตอบเป็น แถวที่กรองหรือนับได้ → SQL · เป็น ความหมายที่ต้องเทียบความใกล้ → vector · มีทั้งสอง → hybrid · เป็นความสัมพันธ์ → graph

catalog กับ vector — ดูที่รูปของข้อมูล

เส้นแบ่งจะคมขึ้นถ้าดูอีกชั้น — ไม่ใช่แค่คำถามถามอะไร แต่ ข้อมูลที่ต้องดึงอยู่ในรูปไหน:

  • catalog (structured) — เมนู ราคา สต็อก สถานะออเดอร์ · มี field/key ให้ query ตรง · นี่คืองานของ database
  • text อิสระ (unstructured) — นโยบาย FAQ คำอธิบาย เอกสาร · ไม่มี field ให้ filter มีแต่ความหมาย · ที่ของ vector อยู่ตรงนี้

ทำไมแยกตรงนี้: catalog มี key อยู่แล้ว การ query ตรงจึงเร็วและเป๊ะ · ถ้าเอา catalog ไป embed แล้ว vector search ผลจะช้ากว่าและนับ/กรองไม่แม่น เพราะ vector จับ ความหมาย ไม่ได้จับ ค่าเป๊ะ · คำถามที่ตัดได้เลย — ข้อมูลที่ต้องดึงมี key ให้ค้นไหม · มี → query catalog · ไม่มี เหลือแต่ความหมาย → vector

สังเกตว่าแม้แต่ใน catalog เดียวกัน คำถามยังแยกอีกชั้น — สิ่งที่ถามเป็น field ไหม · ราคา/ส่วนผสมเป็น field → filter ตรง เร็วและเป๊ะ · ส่วนคุณภาพที่ไม่มี field อย่าง “สดชื่น” (หรือ “เบา ๆ”, “เหมาะหน้าฝน”) ต้องตีความก่อน — ให้ LLM แปลงเป็น tag ที่มีอยู่ (เย็น · ซิตรัส · มินต์) แล้ว filter · หรือ vector บนคำอธิบายเมนู

นี่คือเหตุผลที่ร้านซึ่งมี catalog ปิด (เมนูจำกัด สินค้านับชิ้นได้) มักไม่ต้องแตะ vector เลย · key-value lookup เบากว่าและตรงกว่าสำหรับข้อมูลแบบนั้น · vector ไม่ใช่ขั้นที่ “สูงกว่า” ของ catalog — มันคือเครื่องมือสำหรับข้อมูลคนละรูป

Pipeline ทั้งเส้น — หัวใจอยู่ตรงกลาง

รู้แล้วว่ามีหลายวิธี และอะไรเข้ากับอะไร · ทีนี้มาดูว่าคำถามเดินจากปากผู้ใช้ไปถึงวิธีที่ใช่ได้ยังไง

คำถามกว่าจะเป็นคำตอบ เดินผ่านห้าขั้น · งานที่ตัดสินทุกอย่างอยู่ที่ ขั้น 2-3 — เข้าใจ แล้วแปลงรูป · ขั้น 4-5 แค่ทำตามที่สองขั้นนี้วางไว้

แผนภาพ retrieval pipeline ห้าขั้นเรียงต่อกัน: (1) รับคำถาม natural language · (2) เข้าใจ คือ classify intent และ extract entity/filter · (3) แปลงรูป คือ route ไปเป็น SQL, tool-call หรือ embedding · (4) ดึงข้อมูล จาก DB หรือ vector store แล้ว merge + rerank · (5) ประกอบคำตอบ คือ synthesize + cite โดยตอบจากที่ดึงมาเท่านั้น · ขั้น 2-3 คือหัวใจ ที่ตีความคำถามและจับคู่กับวิธีดึง
ขั้น 2-3 เป็นที่ตีความคำถามและจับคู่กับวิธีดึง · ขั้นที่เหลือทำตามที่สองขั้นนี้กำหนด

ขั้น 2 · เข้าใจคำถาม — อ่าน “รูป” ของมัน

ก่อนดึงอะไร ระบบตอบสองอย่างให้ได้ก่อน — intent (ผู้ใช้ถามหาอะไร) และ entity/filter (มีค่าเจาะจงอะไรในประโยค)

คำถามจริงไม่ได้มาเดี่ยว ๆ · “เอาอีกแก้ว” หรือ “อันนั้นเท่าไหร่” ตีความไม่ได้ถ้าไม่รู้ว่าคุยอะไรกันมาก่อน · ขั้นนี้จึงอ่านคำถาม พร้อม thread ของมัน ไม่ใช่อ่านบรรทัดเดียว · บทนี้เดินตามคำถามเดียวเพื่อให้เห็นภาพ — แต่ในระบบจริง ทุกคำถามถูกตีความบนประวัติที่สะสมมา

อ่านรูปของคำถามได้สองวิธี ต่างกันที่น้ำหนัก:

  • Rule / classifier เบา ๆ — regex จับ ID/วันที่/ตัวเลข + keyword list · เร็วระดับ µs, ไม่ใช้ LLM call · ครอบคลุมคำถามซ้ำ ๆ ส่วนใหญ่ได้
  • LLM router — ให้ LLM จัด intent + ดึง entity เป็น structured output · ยืดหยุ่นกว่า แลกกับ latency + cost หนึ่ง call · เหมาะกับคำถามที่ rule จับไม่อยู่

คำถามอย่าง “ออเดอร์ #\d+ ส่งถึงไหน” มี pattern ชัด · regex อ่าน intent ได้เอง ไม่ต้องให้ LLM ช่วย “เข้าใจ” · พอแยกออกว่าคำถามไหน rule พอ คำถามไหนต้องใช้ LLM · เราก็ใช้ LLM เฉพาะที่มันสร้างความต่างจริง — เร็วและถูกในคราวเดียว

อีกชั้นของความยืดหยุ่น — route ไม่ต้องผูกกับ keyword ตายตัว · เก็บ “คำอธิบายของแต่ละงาน” ไว้เป็นข้อมูล แล้วให้ router จับคู่คำถามกับคำอธิบายนั้น · เพิ่มงานใหม่ก็แค่เพิ่มข้อมูลหนึ่งแถว ไม่ต้องแก้โค้ด

ผลของขั้นนี้คือ structured object เช่น {intent: "order_status", order_id: 1234} หรือ {intent: "policy_lookup", topic: "return"} — เอาไปป้อนขั้นถัดไป

ขั้น 3 · แปลงรูป — คำถามกลายเป็นอะไร

นี่คือขั้นที่คนสงสัยบ่อยสุด: คำถามภาษาคน กลายเป็นการดึงข้อมูลจริงได้ยังไง · มีสามเส้นทางหลัก

เส้นทาง A · กลายเป็น tool-call / text-to-SQL — เมื่อ intent คือคำตอบที่แน่นอน

LLM ไม่ตอบคำถามเอง · มันแปลคำถามเป็น structured args ตาม schema ที่เรากำหนด · เช่น

"เดือนนี้ลูกค้าใหม่กี่คน"
  → call get_customer_count(period="2026-06", filter="new")
  → SELECT COUNT(*) FROM customers WHERE created >= '2026-06-01' AND type='new'

ทำไมเข้ากับคำถามแบบนี้: คำตอบมาจาก source of truth โดยตรง · ตัวเลขเป๊ะเพราะ DB เป็นคนนับ ไม่ใช่ LLM เดา · เร็วระดับ ms · ไม่ต้อง embed อะไรเลย · ความแม่นอยู่ที่ schema/description ของ tool ที่ชัดพอให้ LLM เลือกถูก — description สำคัญกว่าโครง schema (ดูบทที่ 4)

เส้นทาง B · กลายเป็น vector search — เมื่อ intent คือความหมายที่ใกล้เคียง

คำถามถูกแปลงเป็น embedding (เวกเตอร์ตัวเลข) แล้วหา neighbor ที่ใกล้ที่สุดใน vector store

"นโยบายคืนของเป็นยังไง"
  → embed(query) → ANN search → top-k chunks ที่ความหมายใกล้

สามจุดที่กำหนดว่า vector search จะเบาหรือหนัก:

  • top-k — ดึง 50 chunk มาทั้งที่ใช้จริง 3 · context ยาวขึ้น ต้นทุนสูงขึ้น chunk ส่วนเกินกลายเป็น noise กลบสัญญาณ · เริ่มที่ k เล็กแล้ว rerank ให้ผลตรงข้าม
  • สิ่งที่เอาไป embed — บางครั้ง embed คำตอบสมมติ (HyDE) แทนคำถามดิบให้ผลใกล้กว่า เพราะ “คำตอบ” อยู่ใกล้ “เอกสารคำตอบ” มากกว่า “คำถามสั้น ๆ”
  • filter ก่อน vector — ถ้ารู้ว่า scope แค่ “หมวดนโยบาย” การตัด search space ลงก่อน ทำให้ไม่ต้องสแกนทั้ง corpus

เส้นทาง C · hybrid — เมื่อคำถามมีทั้งคำเฉพาะและความหมาย · รวม BM25 (keyword exact) + vector (semantic) + metadata filter แล้ว rerank ผลรวม · เข้ากับคำถามที่มี ID/ชื่อรุ่นซึ่ง vector เดี่ยว ๆ มักจับไม่ติด ปนกับเจตนาเชิงความหมาย

Query rewrite / decompose — คำถามคลุมเครือ rewrite ให้ชัดก่อนได้ · คำถามที่ต้องหลายแหล่ง แตกเป็นหลาย sub-query ได้ · ประโยชน์ชัดเมื่อคำถามต้องหลายแหล่งจริง · ถ้า single query ตอบได้ การแตกเพิ่มจ่ายค่า LLM หลายเท่าเพื่อผลเท่าเดิม · จึงอยู่ที่ว่าคำถามตรงหน้าต้องการแค่ไหน

ขั้น 4-5 · ดึง · จัด · ประกอบ

ขั้นที่เหลือเบากว่าเมื่อสองขั้นแรกทำดี:

ดึง (retrieve) — execute SQL/tool หรือ vector query · ปัญหาคลาสสิกของเส้น vector คือ chunk ที่ใช่ดันอยู่อันดับ 12 — top-5 พลาด แต่ดัน top-k เป็น 20 ก็ท่วม context · กุญแจคือเห็นว่าปัญหาอยู่ที่ การจัดอันดับ ไม่ใช่ จำนวนที่ดึง:

  • retrieve กว้าง แล้ว rerank — ดึง candidate มาเยอะด้วยวิธีถูก (vector/hybrid) แล้วให้ reranker (cross-encoder) ให้คะแนนใหม่ทีละคู่กับคำถาม · chunk ที่ embedding จัดอันดับพลาดถูกดันขึ้น top-3 · LLM เห็นแค่ไม่กี่ chunk — ได้ทั้ง recall และ context สั้น
  • แก้ที่เหตุว่าทำไมมันอันดับต่ำ — embedding ล้วนมักพลาดคำเฉพาะ · hybrid (BM25 + vector) ดันคำตรงขึ้น · query rewrite / HyDE ให้คำถามอยู่ใกล้ chunk คำตอบ · filter ตัด candidate ที่ไม่เกี่ยวออกก่อน
  • บีบ แทนที่จะเพิ่ม — ถ้าต้องดึงเยอะจริง compress ก่อนส่ง (สกัดเฉพาะประโยคที่เกี่ยว) · ได้ recall สูงโดย token ไม่บาน

context ที่ท่วมจึงแก้ด้วยการจัดอันดับให้ดีขึ้น ไม่ใช่ดึงมาเยอะขึ้น

จัด context ให้พอดีกับโมเดล — chunk ที่ rerank แล้วไม่ได้ไปอยู่ลำพัง · มันแชร์ window กับ system prompt, ประวัติ, และที่ต้องเหลือให้ output · แล้ว window ของแต่ละโมเดลก็ไม่เท่ากัน

  • งบจริงน้อยกว่าที่โฆษณา — โมเดลโฆษณา context เป็นล้านโทเค็น แต่ความแม่นมักตกหลัง ~100-200k · “ใส่ได้” ไม่เท่ากับ “โมเดลใช้ได้ดี” (effective context ≠ advertised — ดูบทที่ 2)
  • ตำแหน่งมีผล — โมเดลอ่านต้นกับท้าย window แม่นกว่ากลาง (lost-in-the-middle) · chunk ที่ตรงสุดควรวางที่ขอบ ไม่ใช่ฝังกลางกอง
  • ผูกกับโมเดลที่ใช้ — window, ความสนใจ, พฤติกรรม prompt-caching ต่างกันต่อโมเดล · เปลี่ยนโมเดลทีไร กลยุทธ์ context ก็ขยับ — อีกเหตุผลที่ model อยู่หลัง gateway (ดูบทที่ 4)

retrieval ที่ดีจึงไม่จบที่ “ได้ chunk ที่ใช่” · มันจบที่ chunk ที่ใช่ วางถูกที่ ในงบที่โมเดลใช้ได้จริง

ประกอบ (synthesize) — มีสองวิธีสร้างคำตอบ ต่างกันที่ ใครเป็นคนเขียนส่วนที่ต้องจริง

  • code render — เมื่อคำตอบเป็น closed set (เมนู ราคา สถานะออเดอร์) code ประกอบประโยคจาก source ตรง ๆ · LLM ไม่แตะ output · ค่าที่ต้องเป๊ะถูกล็อกด้วยโครงสร้าง ไม่ใช่ด้วยคำสั่ง
  • LLM synthesize + cite — เมื่อคำตอบเป็น open (อธิบาย สรุป เทียบ) เลี่ยงให้ LLM เขียนไม่ได้ · ให้มันเรียบเรียงจากบริบทที่ดึงมา แล้วแนบแหล่งอ้างอิง

แก่นของการกันหลอนอยู่ตรงนี้ — หลอนเป็นคุณสมบัติของ “ใครเขียนส่วนที่ต้องจริง” · ถ้า code เขียนค่าจาก source โมเดลก็เติมเองไม่ได้ · citation ทำให้ ตรวจเจอ ว่าหลอน · code render ทำให้ หลอนไม่ได้ ตั้งแต่แรก · closed set จึงกันได้ · open answer ทำได้แค่ลดความเสี่ยงกับตรวจให้เจอ

“3 RAG systems” คือจุดบน spectrum เดียว

ภาพยอดนิยมชอบแบ่ง RAG เป็นสามแบบ — Standard, Graph, Agentic · จริง ๆ มันไม่ใช่สามทางเลือกแยกกัน แต่คือจุดบนเส้นเดียว: ใครเลือกแหล่ง และดึงจากกี่แหล่ง

  • Standard RAG — vector ทางเดียว: embed → top-k → LLM · คือเส้นทาง vector + rerank ที่เพิ่งเดินมา
  • Graph RAG — แตก entity ออกจากคำถาม → เดินใน knowledge graph → ได้ context ที่โยงกัน · เข้ากับคำถามชนิด “ความสัมพันธ์หลายชั้น”
  • Agentic RAG — ไม่ fix เส้นไว้ล่วงหน้า · ปล่อยให้ agent เลือกเองว่าจะใช้ vector / graph / web / tool ไหน แล้ววน self-eval จนพอ

มันคือกรอบเดิม — เลือกระดับ (workflow ที่ fix เส้น vs agent ที่เลือกเอง · บทที่ 1) คูณกับ routing (คำถามไหนไปแหล่งไหน · ทั้งบทนี้) · Agentic RAG ก็คือเอา routing นี้ไปให้ agent รันแบบ dynamic แล้วตรวจด้วย eval (บทที่ 4)

เลยไม่ต้องเลือกว่าจะเป็น “ระบบ RAG แบบไหน” · เลือกที่ คำถาม ว่าต้องการแหล่งไหน แล้วค่อยเพิ่มความซับซ้อน (จาก fix เส้น → ให้ agent เลือกเอง) เมื่องานเรียกร้องจริง

ร้อยเข้าด้วยกัน

เมื่อเห็นว่าคำถามแต่ละชนิดถามหาอะไร และแต่ละวิธีเก่งงานแบบไหน แลกมาด้วยอะไร การจับคู่จะชัดขึ้นเอง — คำถามคำนวณ/เจาะจงไป tool-call/SQL · คำถามความหมายไป vector · ปนกันไป hybrid · ความสัมพันธ์ไป graph · ส่วนชั้นเสริมอย่าง rewrite, decompose, LLM router มีที่ของมันเมื่อคำถามต้องการจริง ๆ

ที่ระบบช้าและแพงมักเพราะใช้เครื่องมือหนักเกินคำถาม · เครื่องมือที่หนักกว่าไม่ได้แปลว่าดีกว่า — ความเร็วและความถูกมาจากการจับคู่ให้พอดี ไม่ใช่จากการเพิ่มชั้นความฉลาด · วิธีที่เข้ากับคำถาม จึงมักเป็นวิธีที่เบาที่สุด และนั่นคือที่มาของ performance

เหมือนแกนของทั้ง series — เข้าใจปัญหาก่อน แล้วรูปร่างที่พอดีจะปรากฏเอง · กับ retrieval มันแปลว่า เข้าใจคำถามก่อน แล้ววิธีดึงที่ใช่จะตามมา


ขอบเขต — บทนี้พาเข้าใจ “คำถามแต่ละแบบเข้ากับการดึงข้อมูลแบบไหน และทำไม” · เดินตามคำถามเดียวเพื่อให้เห็นภาพ · ชั้น conversation-state ที่ตีความคำถามบนประวัติทั้งบทสนทนา เป็นมิติที่ใหญ่พอจะแยกเล่า · ต่อยอดจาก data layer ใน บทที่ 4 และระดับ Augmented LLM ใน บทที่ 1 · retrieval ที่เข้ากับคำถามคือสิ่งที่ทำให้ระดับ Augmented LLM ทำงานได้จริง · แนวคิดหลัก: tool/function calling, text-to-SQL, dense retrieval + HyDE, hybrid search (BM25 + vector), query routing, two-stage retrieve→rerank (cross-encoder), contextual compression, context budgeting (lost-in-the-middle · effective ≠ advertised window), constrain-render (code-built output) · รายละเอียดเชิงเครื่องมือเปลี่ยนไปตามยุค แต่ความเข้าใจ “คำถามแบบไหนเข้ากับวิธีไหน” อยู่นาน