Μετάβαση στο περιεχόμενο
cd /blog

Πολυτροπική Συγχωνευμένη Αναζήτηση: Επιλέγοντας τον Σωστό Ανακτητή για Κάθε Ερώτημα

[Αναζήτηση][Αρχιτεκτονική]

> Ένα ερώτημα όπως «πού ορίζεται το parseConfig» θέλει διαφορετική αναζήτηση από το «πώς λειτουργεί η ταυτοποίηση». Το Maguyva ταξινομεί την πρόθεση, σταθμίζει ανάλογα τέσσερις τρόπους ανάκτησης και συγχωνεύει τα αποτελέσματα με σταθμισμένη Reciprocal Rank Fusion.

Ένα ερώτημα αναζήτησης δεν είναι ένα και μόνο πράγμα.

Το «πού ορίζεται το parseConfig» θέλει ένα ακριβές σύμβολο — μία συγκεκριμένη τοποθεσία, γρήγορα. Το «πώς λειτουργεί η ταυτοποίηση» θέλει νόημα — το εύρος του σχετικού κώδικα που εξηγεί μια έννοια. Το «τι σπάει αν αλλάξω αυτή τη συνάρτηση» θέλει τον γράφο εξαρτήσεων. Το «βρες τη συμβολοσειρά ECONNREFUSED» θέλει μια κυριολεκτική αντιστοίχιση, τίποτα έξυπνο.

Το grep είναι εξαιρετικό για κυριολεκτικές αντιστοιχίσεις και χρήσιμο για κάποιες αναζητήσεις αναφορών, όμως δεν είναι γράφος εξαρτήσεων και δεν κατανοεί το νόημα. Τα ενσωματώματα καλύπτουν τη σημασιολογική πλευρά, όμως είναι το λάθος εργαλείο για ακριβείς συμβολοσειρές και ανάλυση επίδρασης. Τα περισσότερα εργαλεία αναζήτησης κώδικα επιλέγουν μία μηχανή και αναγκάζουν κάθε ερώτημα να ζει με αυτή την επιλογή. Το Maguyva δεν επιλέγει. Καταλαβαίνει τι είδους ερώτημα κάνατε, και έπειτα συνδυάζει τέσσερις ανακτητές στην αναλογία που αξίζει εκείνο το ερώτημα.

Τέσσερις τρόποι αναζήτησης

Κάτω από την επιφάνεια υπάρχουν τέσσερις ανεξάρτητοι τρόποι για να βρεθεί κώδικας:

  • σημασιολογικός — διανυσματική αναζήτηση πάνω σε δυαδικά ενσωματώματα Voyage· βρίσκει κώδικα βάσει νοήματος.
  • κειμενικός — αντιστοίχιση τριγραμμάτων· βρίσκει κυριολεξίες, συμβολοσειρές σφαλμάτων, ακριβή αναγνωριστικά.
  • δομικός — ερωτήματα AST· βρίσκει ορισμούς, υπογραφές και δομικά στοιχεία της γλώσσας.
  • γράφου — ο γράφος εξαρτήσεων· βρίσκει καλούντες, καλούμενους και ακτίνα επίδρασης.

Καθένας είναι δυνατός σε διαφορετική κατηγορία ερωτήματος. Το κόλπο είναι να αποφασίσεις πόσο να εμπιστευτείς τον καθέναν για το ερώτημα που έχεις μπροστά σου.

Ταξινόμηση πρόθεσης

Πριν τρέξει οποιαδήποτε ανάκτηση, ένας ελαφρύς ταξινομητής κατατάσσει το ερώτημα σε μία από έξι προθέσεις, με μια βαθμολογία εμπιστοσύνης. Είναι σκόπιμα φθηνός — διατεταγμένοι ευρετικοί κανόνες, κερδίζει η πρώτη αντιστοίχιση — επειδή τρέχει στο κρίσιμο μονοπάτι και προσθέτει μόλις ένα ή δύο χιλιοστά του δευτερολέπτου:

  • ξεκινά με def , class , func , import … → find_definition (εμπιστοσύνη 0,95)
  • «ποιος καλεί», «χρήσεις του», «αναφορές σε» → find_references (0,90)
  • «επίδραση», «ακτίνα επίδρασης», «τι εξαρτάται από» → impact_analysis (0,90)
  • ένα εισαγωγικό "string" ή ένα token σφάλματος όπως το tracebackexact_match (0,85–0,90)
  • ένα αναγνωριστικό CamelCase ή snake_casefind_definition (0,60–0,80)
  • «πώς», «γιατί», «εξήγησε», «αρχιτεκτονική» → understand_code (0,75)
  • τίποτα δεν ταιριάζει → understand_code, χαμηλή εμπιστοσύνη (0,40)

Κάθε πρόθεση κουβαλά ένα προφίλ βαρών στους τέσσερις τρόπους αναζήτησης. Αυτοί είναι οι πραγματικοί αριθμοί:

Πρόθεση σημασιολογικός κειμενικός δομικός (AST) γράφου
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). Το «πώς λειτουργεί η ταυτοποίηση» στηρίζεται σε σημασιολογικά διανύσματα (0,5). Το «τι εξαρτάται από αυτό» είναι σχεδόν αποκλειστικά γράφος (0,7). Το «βρες ECONNREFUSED» είναι σχεδόν αποκλειστικά τριγράμματα (0,9), με το μοντέλο ενσωματωμάτων εντελώς απενεργοποιημένο — επειδή η σημασιολογική ομοιότητα είναι ακριβώς το λάθος εργαλείο για μια ακριβή συμβολοσειρά.

Το γρήγορο μονοπάτι, και το συγχωνευμένο μονοπάτι

Όταν ο ταξινομητής είναι σίγουρος — βαθμολογία ≥ 0,85 — και το ερώτημα είναι συνηθισμένο, το Maguyva παρακάμπτει εντελώς τη συγχώνευση και δρομολογεί απευθείας στον έναν κυρίαρχο τρόπο αναζήτησης. Το «πού ορίζεται το X» δεν χρειάζεται τέσσερις ανακτητές· χρειάζεται το ευρετήριο AST, τώρα. Αυτό το απευθείας μονοπάτι αναφέρεται πίσω ως fusion_strategy: "direct".

Οτιδήποτε είναι διφορούμενο περνά από συγχώνευση. Οι τέσσερις (ή τρεις, στην προεπιλεγμένη διαμόρφωση) τρόποι αναζήτησης τρέχουν παράλληλα, ο καθένας επιστρέφοντας τη δική του κατατεταγμένη λίστα, και τους συνδυάζουμε.

Σταθμισμένη Reciprocal Rank Fusion

Η συγχώνευση ετερογενών ανακτητών είναι πιο δύσκολη απ’ όσο ακούγεται: μια συνημιτονοειδής ομοιότητα 0,82 και μια βαθμολογία τριγράμματος 137 και μια κεντρικότητα γράφου 0,004 δεν βρίσκονται στην ίδια κλίμακα, οπότε δεν μπορείτε απλώς να τις προσθέσετε. Η Reciprocal Rank Fusion παρακάμπτει το πρόβλημα πετώντας τις ακατέργαστες βαθμολογίες και κρατώντας μόνο την κατάταξη που έδωσε κάθε μηχανή. Η συνεισφορά ενός αποτελέσματος από έναν τρόπο αναζήτησης είναι:

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

όπου το rank είναι η θέση του στη λίστα εκείνου του τρόπου αναζήτησης και το k είναι μια σταθερά εξομάλυνσης. Οι συνεισφορές αθροίζονται σε όλους τους τρόπους αναζήτησης για κάθε αποτέλεσμα που βρήκε περισσότερη από μία μηχανή — η συμφωνία μεταξύ ανακτητών φυσικά ανεβαίνει στην κορυφή. Χρησιμοποιούμε k = 40 στην προεπιλεγμένη διαμόρφωση και 60 στο thorough (quick τρέχει μόνο σημασιολογικά, οπότε η συγχώνευση δεν ενεργοποιείται ποτέ εκεί). Η αρχική εργασία για το RRF κατέληξε σε k = 60 για γενικού σκοπού ανάκτηση· εμείς έχουμε ελαφρώς πιο αιχμηρή προεπιλογή, κάτι που δίνει λίγο περισσότερο βάρος στη συμφωνία μεταξύ των κορυφαίων τρόπων αναζήτησης — και δεν συνιστούμε χειροκίνητη ρύθμιση.

Επιπλέον, τα αποτελέσματα φέρουν μια ενίσχυση σπουδαιότητας γράφου. Ένας κεντρικός κόμβος — μια συνάρτηση στην οποία στηρίζεται ολόκληρη η βάση κώδικα — πρέπει να κατατάσσεται πάνω από ένα ασαφές φύλλο ακόμη και με την ίδια κειμενική σχετικότητα, οπότε πολλαπλασιάζουμε κάθε συνεισφορά με:

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

Η κεντρικότητα προέρχεται από τις προϋπολογισμένες μετρικές PageRank/βαθμού του pipeline, και η ενίσχυση είναι περιορισμένη στο 1,5× ώστε μια δημοφιλής συνάρτηση να μην μπορεί να θάψει εντελώς μια πιο σχετική αλλά ασαφή. Τέλος υποβιβάζουμε αποτελέσματα από διαδρομές προμηθευτών, κατασκευής και αρχειοθέτησης, και αφαιρούμε διπλότυπα κρατώντας το καλύτερο τμήμα ανά αρχείο.

Τι εξακολουθεί να είναι ατελές

Ο ταξινομητής πρόθεσης είναι μια στοίβα κανονικών εκφράσεων, όχι ένα εκπαιδευμένο μοντέλο. Καλύπτει καλά τα συνηθισμένα σχήματα ενός ερωτήματος — η απόφαση που τον εισήγαγε κατέγραψε το ποσοστό μηδενικών αποτελεσμάτων να πέφτει από περίπου 15% σε κάτω από 5% — όμως είναι ευρετικός, και ένα γνήσια διφορούμενο ερώτημα καταλήγει στο understand_code και σε ένα σημασιολογικά προσανατολισμένο μείγμα. Αυτή είναι μια ασφαλής προεπιλογή, όχι μια έξυπνη. Δεν τον έχουμε αντικαταστήσει με έναν εκπαιδευμένο ταξινομητή επειδή η φθηνή εκδοχή είναι γρήγορη και αρκετά καλή, και επειδή ένας λάθος-αλλά-σίγουρος ταξινομητής είναι χειρότερος από μια ειλικρινή εναλλακτική λύση. Τα ίδια τα βάρη είναι χειροεπιλεγμένες εκ των προτέρων εκτιμήσεις, όχι κάτι που μαθεύτηκε από δεδομένα κλικ που δεν συλλέγουμε.

Κάνε την Ερώτηση, Όχι το Εργαλείο

Ένας πράκτορας δεν θα έπρεπε να χρειάζεται να ξέρει αν πρέπει να καταφύγει στο grep, στα ενσωματώματα ή στον γράφο κλήσεων — θα έπρεπε να κάνει την ερώτησή του με απλά λόγια και να πάρει τη σωστή απάντηση. Η πολυτροπική συγχώνευση είναι αυτό που επιτρέπει στο find_symbol, στη σημασιολογική αναζήτηση και στην ανάλυση εξαρτήσεων να βρίσκονται πίσω από μία επιφάνεια ερωτήματος: το σύστημα διαβάζει το σχήμα της ερώτησης και συναρμολογεί σιωπηλά τον σωστό ανακτητή γι’ αυτήν. Το μοντέλο που βαθμολογεί τα ενσωματώματα έχει σημασία, όμως έχει σημασία και το να ξέρεις πότε να μην τα χρησιμοποιήσεις. Η επιλογή του σωστού εργαλείου για κάθε ερώτημα είναι ένα δικό της είδος ποιότητας, και είναι ένα που προτιμούμε να αναλαμβάνουμε εμείς παρά να το μεταθέτουμε στον καλούντα.

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

Σχετική ανάγνωση

Περισσότερα από το ημερολόγιο κατασκευής του Maguyva

Γιατί Αναβαθμίσαμε την Αναζήτηση Κώδικα σε voyage-4-large_

Μεταφέραμε τα ενσωματώματα κώδικά μας στο voyage-4-large — προς το παρόν στην κορυφή του δημόσιου πίνακα κατάταξης ανάκτησης κώδικα RTEB. Η ειλικρινής εκδοχή: το ανταλλάγμα που κάνουμε, τι πραγματικά ευρετηριάζουμε και γιατί πληρώνουμε για ενσωματώματα πρέμιουμ.

[Ενσωματώσεις][Αναζήτηση][Αρχιτεκτονική]

Αναδρομική Αυτο-βελτίωση Γλωσσών: Βελτιώνοντας Αδιάκοπα την Ευφυΐα Κώδικα σε ~280 Γλώσσες_

Υποστηρίζουμε ευφυΐα κώδικα για ~280 γλώσσες. Κανένας άνθρωπος δεν μπορεί να ελέγξει χειροκίνητα κάτι τέτοιο. Έτσι φτιάξαμε έναν βρόχο αναδρομικής αυτο-βελτίωσης γλωσσών — δειγματοληπτικός έλεγχος, LLM ως κριτής, διόρθωση ενός πράγματος τη φορά, επανεπικύρωση — και τον τρέχουμε με έναν στόλο απομονωμένων πρακτόρων μέχρι η εξαγωγή να είναι πράγματι σωστή, όχι απλώς πράσινη.

[Αρχιτεκτονική][Γλώσσες][Πράκτορες]

Παρατηρησιμότητα Πρακτόρων: Hooks, Alloy και Grafana_

Συνδέσαμε το Claude Code και το Codex σε μία ενιαία στοίβα Grafana με OpenTelemetry και Alloy, και έπειτα χρησιμοποιήσαμε ίχνη (traces) και αρχεία καταγραφής για να εντοπίσουμε και να διορθώσουμε προβλήματα συμπεριφοράς πρακτόρων στην πηγή τους.

[Παρατηρησιμότητα][Grafana][OpenTelemetry][Αρχιτεκτονική]