# ค้นหาแบบผสานหลายโหมด: เลือกตัวค้นคืนที่ใช่สำหรับทุกคำค้น

Canonical source: https://maguyva.ai/th/blog/multi-modal-fusion-search

License: text under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/); code samples under [MIT-0](https://opensource.org/license/mit-0); the Maguyva name, logos, brand assets and other code are not covered. Details: [maguyva.ai/license](https://maguyva.ai/license).

Date: 2026-04-15 · Author: Maguyva Team

> คำค้นอย่าง 'parseConfig ถูกนิยามที่ไหน' ต้องการการค้นหาที่ต่างจาก 'auth ทำงานอย่างไร' Maguyva จำแนกเจตนา ให้น้ำหนักทั้งสี่รูปแบบการค้นคืนตามนั้น แล้วรวมผลลัพธ์ด้วย weighted Reciprocal Rank Fusion

> หมายเหตุเกี่ยวกับการออกแบบในอดีต: บทความเดือนเมษายน 2026 นี้อธิบายการออกแบบการกำหนดเส้นทางในขณะนั้น ไม่ใช่พฤติกรรมเริ่มต้นในปัจจุบัน ข้อแก้ไขในเดือนกันยายนด้านล่างกล่าวถึงข้อกล่าวอ้างเกี่ยวกับการวัดผลเท่านั้น สำหรับการกำหนดเส้นทาง ชุดค่าที่กำหนดไว้ล่วงหน้า และการควบคุมวิธีค้นหาอย่างชัดเจนในปัจจุบัน โปรดดู[วิธีการทำงาน](https://maguyva.ai/th/docs/how-it-works)

คำค้นหาแต่ละแบบต้องการสิ่งที่ต่างกัน

"`parseConfig` ถูกนิยามที่ไหน" ต้องการสัญลักษณ์ที่แน่นอน — ตำแหน่งเดียวที่แม่นยำ เร็ว "authentication ทำงานอย่างไร" ต้องการความหมาย — การกระจายของโค้ดที่เกี่ยวข้องซึ่งอธิบายแนวคิด "อะไรจะพังถ้าฉันเปลี่ยนฟังก์ชันนี้" ต้องการ dependency graph "หาสตริง `ECONNREFUSED`" ต้องการการจับคู่แบบตรงตัว ไม่ต้องมีอะไรฉลาด

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

## สี่รูปแบบ

ภายใต้ระบบมีสี่วิธีอิสระในการหาโค้ด:

- **semantic** — การค้นหาเวกเตอร์บน Voyage binary embedding หาโค้ดตามความหมาย
- **text** — การจับคู่ trigram หาข้อความตรงตัว, สตริงข้อผิดพลาด, ตัวระบุที่แน่นอน
- **structural** — AST คิวรี หาคำนิยาม, ซิกเนเจอร์ และโครงสร้างภาษา
- **graph** — dependency graph หาผู้เรียก, สิ่งที่ถูกเรียก และรัศมีผลกระทบ

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

## การจำแนกเจตนา

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

- เริ่มด้วย `def `, `class `, `func `, `import `… → **find_definition** (ความมั่นใจ 0.95)
- "who calls", "usages of", "references to" (ใครเรียก การใช้งานของ การอ้างอิงถึง) → **find_references** (0.90)
- "impact", "blast radius", "what depends on" (ผลกระทบ รัศมีผลกระทบ สิ่งที่พึ่งพา) → **impact_analysis** (0.90)
- `"string"` ที่ใส่เครื่องหมายคำพูด หรือโทเคนข้อผิดพลาดอย่าง `traceback` → **exact_match** (0.85–0.90)
- ตัวระบุแบบ `CamelCase` หรือ `snake_case` → **find_definition** (0.60–0.80)
- "how", "why", "explain", "architecture" (อย่างไร ทำไม อธิบาย สถาปัตยกรรม) → **understand_code** (0.75)
- ไม่มีอะไรตรง → **understand_code** ความมั่นใจต่ำ (0.40)

แต่ละเจตนามีโปรไฟล์น้ำหนักข้ามสี่รูปแบบ นี่คือตัวเลขจริง:

| เจตนา | semantic | text | structural (AST) | graph |
|---|---|---|---|---|
| find_definition | 0.2 | 0.1 | **0.6** | 0.1 |
| find_references | 0.1 | 0.2 | 0.2 | **0.5** |
| understand_code | **0.5** | 0.2 | 0.2 | 0.1 |
| find_similar | **0.4** | 0.3 | 0.2 | 0.1 |
| impact_analysis | 0.1 | 0.1 | 0.1 | **0.7** |
| exact_match | 0.0 | **0.9** | 0.1 | 0.0 |

ดังนั้น "`parseConfig` ถูกนิยามที่ไหน" จะเอนหนักไปทาง AST (0.6) "auth ทำงานอย่างไร" เอนไปทาง semantic เวกเตอร์ (0.5) "อะไรพึ่งพาสิ่งนี้" แทบทั้งหมดเป็น graph (0.7) "หา `ECONNREFUSED`" แทบทั้งหมดเป็น trigram (0.9) โดยปิดโมเดล embedding ไปเลย — เพราะความคล้ายคลึงเชิงความหมายเป็นเครื่องมือที่ผิดโดยสิ้นเชิงสำหรับสตริงที่แน่นอน

## เส้นทางด่วน และเส้นทางที่ผสมแล้ว

เมื่อตัวจำแนกมั่นใจ — คะแนน ≥ 0.85 — และคำค้นเป็นแบบปกติ Maguyva ข้ามการผสมทั้งหมด แล้วส่งตรงไปยังรูปแบบหลักที่ครองอยู่ "X ถูกนิยามที่ไหน" ไม่ต้องการตัวค้นคืนสี่ตัว มันต้องการดัชนี AST ทันที เส้นทางตรงนั้นถูกรายงานกลับมาเป็น `fusion_strategy: "direct"`

ทุกอย่างที่คลุมเครือจะผ่านการผสม สี่รูปแบบ (หรือสามบนพรีเซ็ตเริ่มต้น) รันคู่ขนานกัน แต่ละอย่างคืนรายการจัดอันดับของตัวเอง แล้วเรารวมพวกมัน

## Weighted Reciprocal Rank Fusion

การผสมตัวค้นคืนที่แตกต่างกันนั้นยากกว่าที่ฟังดู: ความคล้ายคลึงแบบโคไซน์ 0.82, คะแนน trigram 137 และความเป็นศูนย์กลางของกราฟ 0.004 ไม่ได้อยู่บนมาตราส่วนเดียวกัน ดังนั้นคุณบวกมันตรงๆ ไม่ได้ Reciprocal Rank Fusion หลบเลี่ยงปัญหาด้วยการทิ้งคะแนนดิบไป แล้วเก็บไว้แค่ **อันดับ** ที่แต่ละเอนจินกำหนดให้ การมีส่วนร่วมของผลลัพธ์หนึ่งจากรูปแบบหนึ่งคือ:

```text
contribution = weight × 1 / (k + rank + 1)
```

โดยที่ `rank` คือตำแหน่งของมันในรายการของรูปแบบนั้น และ `k` คือค่าคงที่ทำให้เรียบ การมีส่วนร่วมจะถูกรวมข้ามรูปแบบสำหรับผลลัพธ์ใดๆ ที่มากกว่าหนึ่งเอนจินพบ — ความสอดคล้องระหว่างตัวค้นคืนลอยขึ้นไปด้านบนตามธรรมชาติ เราใช้ **k = 40** บนพรีเซ็ตเริ่มต้น และ 60 บน `thorough` (`quick` รันแบบ semantic-only เท่านั้น ดังนั้นการผสมจึงไม่เคยเข้ามาเกี่ยวข้องที่นั่น) งาน RRF ดั้งเดิมลงเอยที่ k = 60 สำหรับการค้นคืนเอนกประสงค์ ค่าเริ่มต้นของเราให้น้ำหนักเพิ่มขึ้นเล็กน้อยกับผลลัพธ์ที่หลายรูปแบบจัดไว้ในอันดับต้นๆ — และเราไม่แนะนำให้ปรับแต่งด้วยมือ

นอกจากนั้น ผลลัพธ์ยังพก **การเพิ่มค่าตามความสำคัญของ graph** ฮับ — ฟังก์ชันที่ทั้งโค้ดเบสพึ่งพา — ควรอยู่เหนือโหนดใบที่ไม่ค่อยมีใครรู้จักแม้ที่ความเกี่ยวข้องเชิงข้อความเท่ากัน ดังนั้นเราคูณการมีส่วนร่วมแต่ละอย่างด้วย:

```text
boost = min(1 + 0.3 × ln(1 + centrality), 1.5)
```

ความเป็นศูนย์กลางมาจากเมตริก PageRank/ดีกรีที่คำนวณล่วงหน้าของ pipeline และการเพิ่มค่าถูกจำกัดที่ 1.5 เท่า เพื่อไม่ให้ฟังก์ชันยอดนิยมกลบฟังก์ชันที่ไม่ค่อยมีใครรู้จักแต่เกี่ยวข้องมากกว่าไปเสียหมด สุดท้ายเราลดอันดับผลลัพธ์จาก path ของ vendor, build และ archive และตัดซ้ำเหลือส่วนที่ดีที่สุดต่อไฟล์

## สิ่งที่ยังไม่สมบูรณ์แบบ

ตัวจำแนกเจตนาเป็นชุดของนิพจน์ปรกติ ไม่ใช่โมเดลที่ฝึกมา มันจัดการรูปแบบคำค้นทั่วไปด้วยฮิวริสติก และคำค้นที่กำกวมจะใช้ `understand_code` กับการผสมผลที่ให้น้ำหนักด้านความหมายมากกว่า บทความฉบับก่อนระบุว่าได้ลดอัตราคำค้นที่ไม่มีผลลัพธ์จากประมาณ 15% เหลือต่ำกว่า 5% สำเร็จแล้ว แต่ข้อเสนอในเดือนธันวาคม 2025 ระบุเพียงค่าประมาณเริ่มต้นและเป้าหมาย โดยไม่ได้ให้ชุดคำค้นหรือบันทึกการวัดที่สนับสนุนผลดังกล่าว เราขอถอนข้อกล่าวอ้างว่าได้ปรับปรุงสำเร็จแล้วนี้ ดู[หลักฐานต้นทางและข้อแก้ไข (ภาษาอังกฤษ)](https://maguyva.ai/evidence/search-quality.md) เรายังไม่ได้แทนที่ตัวจำแนกด้วยโมเดลที่ฝึกมา เพราะรุ่นต้นทุนต่ำนี้เร็วและดีพอสำหรับหน้าที่กำหนดเส้นทางที่ตั้งใจไว้ และตัวจำแนกที่ผิดแต่มั่นใจนั้นแย่กว่าทางเลือกสำรองที่ซื่อตรง น้ำหนักต่าง ๆ เป็นค่าตั้งต้นที่เลือกด้วยมือ ไม่ได้เรียนรู้จากข้อมูลการคลิกที่เราไม่ได้เก็บรวบรวม

## ถามสิ่งที่ต้องการรู้ โดยไม่ต้องเลือกเครื่องมือเอง

agent ไม่ควรต้องรู้ว่าจะหยิบ grep หรือ embedding หรือ call graph ขึ้นมา — มันควรถามคำถามด้วยคำพูดธรรมดาแล้วได้คำตอบที่ถูกต้อง การผสานหลายโหมดคือสิ่งที่ทำให้ `find_symbol`, semantic search และการวิเคราะห์ dependency อยู่ภายใต้อินเทอร์เฟซคำค้นเดียว: ระบบอ่านรูปแบบของคำถามแล้วประกอบตัวค้นคืนที่ถูกต้องให้อย่างเงียบๆ โมเดลที่ให้คะแนน embedding สำคัญ แต่การรู้ว่าเมื่อไหร่ *ไม่ควร* ใช้มันก็สำคัญเช่นกัน การเลือกเครื่องมือที่ถูกต้องสำหรับแต่ละคำค้นเป็นคุณภาพชนิดหนึ่งในตัวมันเอง และเป็นชนิดที่เราอยากรับผิดชอบเองมากกว่าผลักให้ผู้เรียก

`// you bring the question. it brings the tools.`
