ค้นหาแบบผสานหลายโหมด: เลือกตัวค้นคืนที่ใช่สำหรับทุกคำค้น
> คำค้นอย่าง 'parseConfig ถูกนิยามที่ไหน' ต้องการการค้นหาที่ต่างจาก 'auth ทำงานอย่างไร' Maguyva จำแนกเจตนา ให้น้ำหนักทั้งสี่รูปแบบการค้นคืนตามนั้น แล้วรวมผลลัพธ์ด้วย weighted Reciprocal Rank Fusion
หมายเหตุเกี่ยวกับการออกแบบในอดีต: บทความเดือนเมษายน 2026 นี้อธิบายการออกแบบการกำหนดเส้นทางในขณะนั้น ไม่ใช่พฤติกรรมเริ่มต้นในปัจจุบัน ข้อแก้ไขในเดือนกันยายนด้านล่างกล่าวถึงข้อกล่าวอ้างเกี่ยวกับการวัดผลเท่านั้น สำหรับการกำหนดเส้นทาง ชุดค่าที่กำหนดไว้ล่วงหน้า และการควบคุมวิธีค้นหาอย่างชัดเจนในปัจจุบัน โปรดดูวิธีการทำงาน
คำค้นหาแต่ละแบบต้องการสิ่งที่ต่างกัน
“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 หลบเลี่ยงปัญหาด้วยการทิ้งคะแนนดิบไป แล้วเก็บไว้แค่ อันดับ ที่แต่ละเอนจินกำหนดให้ การมีส่วนร่วมของผลลัพธ์หนึ่งจากรูปแบบหนึ่งคือ:
contribution = weight × 1 / (k + rank + 1)
โดยที่ rank คือตำแหน่งของมันในรายการของรูปแบบนั้น และ k คือค่าคงที่ทำให้เรียบ การมีส่วนร่วมจะถูกรวมข้ามรูปแบบสำหรับผลลัพธ์ใดๆ ที่มากกว่าหนึ่งเอนจินพบ — ความสอดคล้องระหว่างตัวค้นคืนลอยขึ้นไปด้านบนตามธรรมชาติ เราใช้ k = 40 บนพรีเซ็ตเริ่มต้น และ 60 บน thorough (quick รันแบบ semantic-only เท่านั้น ดังนั้นการผสมจึงไม่เคยเข้ามาเกี่ยวข้องที่นั่น) งาน RRF ดั้งเดิมลงเอยที่ k = 60 สำหรับการค้นคืนเอนกประสงค์ ค่าเริ่มต้นของเราให้น้ำหนักเพิ่มขึ้นเล็กน้อยกับผลลัพธ์ที่หลายรูปแบบจัดไว้ในอันดับต้นๆ — และเราไม่แนะนำให้ปรับแต่งด้วยมือ
นอกจากนั้น ผลลัพธ์ยังพก การเพิ่มค่าตามความสำคัญของ graph ฮับ — ฟังก์ชันที่ทั้งโค้ดเบสพึ่งพา — ควรอยู่เหนือโหนดใบที่ไม่ค่อยมีใครรู้จักแม้ที่ความเกี่ยวข้องเชิงข้อความเท่ากัน ดังนั้นเราคูณการมีส่วนร่วมแต่ละอย่างด้วย:
boost = min(1 + 0.3 × ln(1 + centrality), 1.5)
ความเป็นศูนย์กลางมาจากเมตริก PageRank/ดีกรีที่คำนวณล่วงหน้าของ pipeline และการเพิ่มค่าถูกจำกัดที่ 1.5 เท่า เพื่อไม่ให้ฟังก์ชันยอดนิยมกลบฟังก์ชันที่ไม่ค่อยมีใครรู้จักแต่เกี่ยวข้องมากกว่าไปเสียหมด สุดท้ายเราลดอันดับผลลัพธ์จาก path ของ vendor, build และ archive และตัดซ้ำเหลือส่วนที่ดีที่สุดต่อไฟล์
สิ่งที่ยังไม่สมบูรณ์แบบ
ตัวจำแนกเจตนาเป็นชุดของนิพจน์ปรกติ ไม่ใช่โมเดลที่ฝึกมา มันจัดการรูปแบบคำค้นทั่วไปด้วยฮิวริสติก และคำค้นที่กำกวมจะใช้ understand_code กับการผสมผลที่ให้น้ำหนักด้านความหมายมากกว่า บทความฉบับก่อนระบุว่าได้ลดอัตราคำค้นที่ไม่มีผลลัพธ์จากประมาณ 15% เหลือต่ำกว่า 5% สำเร็จแล้ว แต่ข้อเสนอในเดือนธันวาคม 2025 ระบุเพียงค่าประมาณเริ่มต้นและเป้าหมาย โดยไม่ได้ให้ชุดคำค้นหรือบันทึกการวัดที่สนับสนุนผลดังกล่าว เราขอถอนข้อกล่าวอ้างว่าได้ปรับปรุงสำเร็จแล้วนี้ ดูหลักฐานต้นทางและข้อแก้ไข (ภาษาอังกฤษ) เรายังไม่ได้แทนที่ตัวจำแนกด้วยโมเดลที่ฝึกมา เพราะรุ่นต้นทุนต่ำนี้เร็วและดีพอสำหรับหน้าที่กำหนดเส้นทางที่ตั้งใจไว้ และตัวจำแนกที่ผิดแต่มั่นใจนั้นแย่กว่าทางเลือกสำรองที่ซื่อตรง น้ำหนักต่าง ๆ เป็นค่าตั้งต้นที่เลือกด้วยมือ ไม่ได้เรียนรู้จากข้อมูลการคลิกที่เราไม่ได้เก็บรวบรวม
ถามสิ่งที่ต้องการรู้ โดยไม่ต้องเลือกเครื่องมือเอง
agent ไม่ควรต้องรู้ว่าจะหยิบ grep หรือ embedding หรือ call graph ขึ้นมา — มันควรถามคำถามด้วยคำพูดธรรมดาแล้วได้คำตอบที่ถูกต้อง การผสานหลายโหมดคือสิ่งที่ทำให้ find_symbol, semantic search และการวิเคราะห์ dependency อยู่ภายใต้อินเทอร์เฟซคำค้นเดียว: ระบบอ่านรูปแบบของคำถามแล้วประกอบตัวค้นคืนที่ถูกต้องให้อย่างเงียบๆ โมเดลที่ให้คะแนน embedding สำคัญ แต่การรู้ว่าเมื่อไหร่ ไม่ควร ใช้มันก็สำคัญเช่นกัน การเลือกเครื่องมือที่ถูกต้องสำหรับแต่ละคำค้นเป็นคุณภาพชนิดหนึ่งในตัวมันเอง และเป็นชนิดที่เราอยากรับผิดชอบเองมากกว่าผลักให้ผู้เรียก
// you bring the question. it brings the tools.
อ่านเพิ่มเติมที่เกี่ยวข้อง
เนื้อหาอื่นๆ จากบันทึกการพัฒนา Maguyva
เหตุใดเราจึงอัปเกรดการค้นหาโค้ดเป็น voyage-4-large_
เราย้ายเอ็มเบดดิ้งโค้ดของเราไปที่ voyage-4-large — ปัจจุบันอยู่อันดับหนึ่งของตารางอันดับการค้นคืนโค้ด RTEB สาธารณะ ฉบับตรงไปตรงมา: การแลกเปลี่ยนที่เรายอมรับ สิ่งที่เราทำดัชนีจริง และเหตุผลที่เราจ่ายเงินเพื่อเอ็มเบดดิ้งระดับพรีเมียม
การสังเกตการณ์เอเจนต์: Hooks, Alloy และ Grafana_
เราเชื่อมต่อ Claude Code และ Codex เข้ากับ Grafana สแตกเดียวกันด้วย OpenTelemetry และ Alloy จากนั้นใช้ trace และล็อกเพื่อค้นหาและแก้ไขปัญหาพฤติกรรมของเอเจนต์ที่ต้นตอ
ขุดค้นและปิดวงจร: การเปลี่ยนแปลงกลายเป็นความทรงจำองค์กรได้อย่างไร_
Git commit กลายเป็นรายการบันทึกการเปลี่ยนแปลงที่มีโครงสร้างและบันทึกการตัดสินใจเชิงสถาปัตยกรรม แล้วป้อนกลับเข้าสู่เอเจนต์ AI ในรูปแบบความทรงจำองค์กรที่ค้นหาได้