0.17.1 ने आपको Octocode द्वारा जनरेट किया गया हर embedding आपके अपने नियंत्रित हार्डवेयर पर चलाने दिया — कोई भी OpenAI-कम्पैटिबल सर्वर, कोई भी मॉडल, और आपका कोड कभी आपके नेटवर्क से बाहर नहीं जाता। वह रिलीज़ इस बारे में थी कि search कहाँ चलती है।
0.18.0 इस बारे में है कि search असल में कितनी अच्छी है — और इसे ऐसे numbers से साबित करना जिन्हें आप खुद reproduce कर सकें।
ज़्यादातर code-search टूल quality का दावा करते हैं। बहुत कम ऐसा benchmark जारी करते हैं जिसे आप खुद चला सकें। यह रिलीज़ दो देती है: Octocode के अपने source code के खिलाफ एक curated retrieval benchmark, और 560 असली GitHub issues पर एक Loc-Bench harness। यह GraphRAG file-level expansion भी जोड़ती है — एक search step जो reranker के स्कोर करने से पहले structurally related फ़ाइलें खींच लाता है।
यहाँ बताया गया है कि क्या बदला, और numbers क्या कहते हैं — उन हिस्सों समेत जो काम नहीं किए।
आख़िर code search का benchmark क्यों?
जब आप कोई chunking heuristic या fusion weight बदलते हैं, तो आप जानना चाहते हैं कि retrieval बेहतर हुआ या बदतर। चंद queries को आँख से देखना यह नहीं बताता — यह बस वही पुष्ट करता है जो आप पहले से मानते थे। एकमात्र ईमानदार जवाब है: queries का एक fixed सेट, fixed ground truth, और एक number जो हिलता है।
तो 0.18.0 एक असली benchmark देती है। यह repo में benchmark/ में रहता है, और Octocode की पूरी pipeline को end to end मापता है: chunking → embedding → vector search → hybrid fusion → reranking।
Ground truth
code.csv में 127 queries हैं, हर एक में 1–3 सही code locations line ranges के रूप में annotate की गई हैं:
query,result1,result2,result3
हर result src/path/file.rs:start-end:relevance है, जहाँ relevance 2 primary है (query का सीधा जवाब देता है) और 1 secondary है (उपयोगी context)। एक search result line-range overlap से match होता है — lines 40–90 पर एक hit, ground truth 45–92 से match करता है क्योंकि ranges एक-दूसरे को काटती हैं।
Corpus एक single commit पर pinned है (b1771ba)। Ground truth उन्हीं exact line numbers के खिलाफ annotate की गई है, इसलिए किसी और checkout को index करने पर ranges खिसक जाएँगी और scores चुपचाप टूट जाएँगे। पहले pin करें, फिर index करें।
Ground truth कैसे बनी, यह मायने रखता है, क्योंकि एक लापरवाह answer key किसी भी benchmark को झूठा बना देती है:
- AI-generated candidates हर बड़े module और doc फ़ाइल में।
- Source verification — हर referenced फ़ाइल और line range को पढ़ा गया और असली code के खिलाफ जाँचा गया।
- Multi-agent validation — parallel agents ने स्वतंत्र रूप से line ranges, paths और relevance grades को फिर से जाँचा।
- Search-informed corrections — अगर search को वही logic किसी valid alternate location में मिली, तो उस location को secondary result के रूप में जोड़ा गया, हटाया नहीं गया।
कठिन queries
127 में से आख़िरी 27 जानबूझकर adversarial हैं: natural language जो किसी function name या comment को मिरर नहीं करती। ये keyword luck नहीं, semantic समझ परखती हैं। कुछ:
| Query का इरादा | यह कठिन क्यों है |
|---|---|
| overlapping chunks में infinite loops रोकना | 5-line guard clause, query में कोई code keyword नहीं |
| repo unchanged होने पर indexing छोड़ना | 900-line function के अंदर 100+ lines गहराई में दबा हुआ |
| tokenizer के बिना rough token estimation | जवाब एक ही line है: s.len() / 4 |
| MCP server में concurrent reindexing रोकना | AtomicBool + compare_exchange, एक concurrency pattern |
अगर standard queries ~1.0 के पास स्कोर करती हैं पर कठिन queries पिछड़ती हैं, तो benchmark अपना काम कर रहा है: यह टूल की चापलूसी करने के बजाय असली retrieval कमज़ोरियाँ उजागर करता है।
Metrics
चार standard IR metrics, सभी में "ज़्यादा बेहतर है":
- Hit@k — क्या कोई भी सही result top k में आया? (coverage)
- MRR — पहले सही result का reciprocal rank। (पहला hit कितना ऊपर है?)
- NDCG@10 — सबसे relevant results को सबसे ऊपर रखने पर इनाम देता है, relevance grade और position दोनों को weight करते हुए। (ranking quality)
- Recall@k — सभी ground-truth blocks का कितना हिस्सा मिला? (completeness)
Definitions और एक worked example benchmark/README.md में हैं।
Numbers: एक local, no-key floor
ये results पूरी तरह local, no-API-key stack इस्तेमाल करते हैं — fastembed के ज़रिए jina-embeddings-v2-base-code, कोई reranker नहीं। यह उन्हें एक floor बनाता है, ceiling नहीं: एक paid code-aware reranker इससे ऊपर ले जाता है। Octocode के अपने source code के खिलाफ चलाया गया, 127 code queries:
| Config | Hit@5 | Hit@10 | MRR | NDCG@10 | Recall@10 |
|---|---|---|---|---|---|
| सिर्फ़ dense vector | 0.598 | 0.717 | 0.485 | 0.528 | 0.671 |
| Hybrid, default RRF weights (0.7/0.3) | 0.598 | 0.717 | 0.485 | 0.528 | 0.671 |
| Hybrid, keyword-tuned (0.3/0.7) | 0.732 | 0.835 | 0.572 | 0.620 | 0.807 |
दो चीज़ें उभरकर आती हैं।
Default RRF weights सिर्फ़-vector जैसा व्यवहार करते हैं। जब fusion 0.7 के साथ dense signal की ओर झुका हो, vector results हावी रहते हैं और keyword signal मुश्किल से दर्ज होता है — ऊपर की दो rows समान हैं।
Keyword की ओर झुकना code के लिए एक बड़ी, मुफ़्त जीत है। weights को 0.3/0.7 पर पलट दें — BM25/keyword signal को lead करने दें — और Hit@5 +22% और Recall@10 +20% उछलता है, बिना किसी अतिरिक्त लागत के। क्यों? Code exact identifiers से भरा है — compare_exchange, get_code_blocks_by_path, RelationshipDirection — और exact-token matching का weight असमान रूप से ज़्यादा होता है जब आप जो ढूँढ रहे हैं वह खुद एक token हो। शुद्ध semantic similarity इसे धुंधला कर देती है; keyword fusion इसे तीखा करती है।
यह वैसा result है जो आपको सिर्फ़ मापने से मिलता है। यह intuitive नहीं है कि code के लिए आप चाहेंगे कि keyword embedding से ज़्यादा weight पाए।
जो काम नहीं आया (और यह benchmark में क्यों है)
ऐसा benchmark जो सिर्फ़ जीत बताए, marketing है। यह regressions भी बताता है — पूरी 6-variant matrix benchmark/RESULTS.md में है।
एक generic reranker ने चीज़ें बदतर कीं। सबसे अच्छी config के ऊपर एक local off-the-shelf cross-encoder (bge-reranker-base) रखने से मदद नहीं मिली — इसने Hit@5 को 0.732 से वापस 0.598 पर regress कर दिया, पूरी keyword-tuning जीत पलट दी। और यह लगभग 4× धीमा था (run के लिए ≈1900s बनाम ≈490s)।
सबक यह नहीं है कि "rerankers बुरे हैं"। यह है कि code retrieval को एक code-aware reranker चाहिए। prose पर trained reranker fn verify_hmac को "webhook signature validation" के खिलाफ उससे भी बदतर स्कोर करता है जितना hybrid fusion पहले ही कर चुका था। voyage:rerank-2.5 जैसा code-tuned reranker अलग कहानी है — पर आपको इसे अपने eval पर verify करना होगा, मान नहीं लेना। benchmark ही वह चीज़ है जो आपको ऐसा करने देती है।
GraphRAG File-Level Expansion
benchmark के साथ-साथ हेडलाइन फ़ीचर। Dense और keyword search दोनों blocks को अलग-थलग स्कोर करती हैं — उन्हें नहीं पता कि जो फ़ाइल आप चाहते हैं वह उस फ़ाइल को import करती है जो उन्हें मिली, या पास में define किए गए function को call करती है। GraphRAG file-level expansion उस अंतर को पाटता है।
जब initial hybrid search ranked candidates बना लेती है, Octocode सबसे मज़बूत कुछ लेता है, imports, calls या extends से structurally related फ़ाइलों के लिए GraphRAG graph को walk करता है, उन neighbor फ़ाइलों से मुट्ठी भर blocks खींचता है, और बढ़ा हुआ candidate set reranker को सौंप देता है:
// Seeds are already RRF-ranked; only expand from the strongest few.
const SEED_LIMIT: usize = 10; // expand from top 10 hits
const MAX_NEIGHBOR_FILES: usize = 8; // pull at most 8 related files
const BLOCKS_PER_FILE: usize = 3; // 3 blocks per neighbor
Neighbors को सभी seed फ़ाइलों में weight × confidence से स्कोर किया जाता है, सबसे मज़बूत links पहले। यह file-granular है क्योंकि graph file-granular है (CodeNode.id == relative path)। और यह best-effort है: कोई भी graph error original results को सीधे pass करने तक degrade हो जाती है — यह search को कभी नहीं तोड़ता।
इसे config.toml में on करें:
[search]
graph_expansion = false # default; requires [graphrag] enabled
यह जानबूझकर default में off आता है। benchmark से ईमानदार हिस्सा यहाँ है:
+graph= GraphRAG file-level expansion, जो results तभी हिलाता है जब एक reranker बढ़े हुए set को फिर से स्कोर करता है।
reranker के बिना, expansion candidates जोड़ता है पर ranking नहीं बदलता — इसीलिए ऊपर की local, no-key matrix में hybrid_30_70 और hybrid_30_70+graph समान स्कोर करते हैं। expansion का फ़ायदा तब आता है जब एक (code-aware) reranker बड़े pool को फिर से स्कोर करता है और किसी structurally related फ़ाइल को आगे लाता है जिसे raw similarity ने बहुत नीचे rank किया था। Naive expansion precision को पतला भी कर सकता है। इसलिए config comment में गढ़ी गई सलाह दो टूक है: इस पर भरोसा करने से पहले अपने eval पर A/B करें। benchmark ठीक इसीलिए मौजूद है।
Loc-Bench: Issue → Code, कुछ भी self-annotated नहीं
curated benchmark हम annotate करते हैं। एक जायज़ सवाल: क्या queries हमारे अपने टूल के लिए बहुत ज़्यादा मेहरबान हैं? 0.18.0 एक दूसरा harness देती है जो हमें समीकरण से पूरी तरह हटा देता है।
benchmark/locbench.py Octocode को Loc-Bench V1 (czlll/Loc-Bench_V1) पर evaluate करता है: लोकप्रिय Python repos से 560 असली GitHub issues। Query है original issue text। Ground truth वह फ़ाइलों और functions का सेट है जिसे असली merged fix ने वास्तव में edit किया (dataset का curated edit_functions field)। कुछ भी self-annotated नहीं है — यह "एक bug report दिया हो, बदलने वाला code ढूँढो" वाला industry-standard task है।
हर instance पर harness repo को clone करता है (blobless, cached), base commit checkout करता है, octocode index चलाता है, issue text से search करता है, और retrieved फ़ाइलों को असली fix के खिलाफ स्कोर करता है — file level (hit@k, recall@k, MRR, accuracy) और hunk level दोनों पर (क्या कोई retrieved result उन lines से overlap हुआ जिन्हें patch ने वास्तव में छुआ?), issue category के हिसाब से breakdown के साथ:
python3 benchmark/locbench.py --limit 10 --verbose # smoke test
python3 benchmark/locbench.py # full 560
python3 benchmark/locbench.py --category "Bug Report"
यह एक measurement tool है, कोई leaderboard दावा नहीं — यह इसलिए है ताकि आप अपने हार्डवेयर और मॉडल पर real-world issue localization चला सकें, और ताकि Octocode के हर भविष्य के बदलाव को एक ऐसे benchmark के खिलाफ मापा जा सके जो हमने नहीं लिखा।
Variant Matrix
score.py एक config मापता है। run_matrix.py कई को एक shared index पर sweep करता है — तो rows के बीच बदलने वाली एकमात्र चीज़ search-time parameters हैं, corpus या embeddings नहीं। यह एक comparison table RESULTS.md (और raw RESULTS.json) में लिखता है, और runs के बीच accumulate करता है, ताकि एक focused re-run मौजूदा table में merge हो जाए।
# पहले corpus को ground-truth commit पर pin करें — वरना line ranges खिसक जाएँगी
git worktree add /tmp/corpus b1771ba
# पूरी local matrix (fastembed, no API key): vector-only बनाम hybrid weight sweep
CORPUS=/tmp/corpus python3 benchmark/run_matrix.py
# एक local cross-encoder reranker जोड़ें (फिर भी no key) — वही index reuse करता है
CORPUS=/tmp/corpus SKIP_INDEX=1 ONLY=rerank \
RERANK_MODEL=fastembed:bge-reranker-base python3 benchmark/run_matrix.py
Variants: vector_only, hybrid_70_30 (default weights), hybrid_30_70 (keyword-tilted), +graph (GraphRAG expansion), और +rerank (cross-encoder)। अगर आप VOYAGE_API_KEY सेट करते हैं, तो paid code-aware reranker variants अपने आप enable हो जाते हैं — इसी तरह आप local floor के ऊपर असली ceiling ढूँढते हैं।
बाक़ी सब कुछ
MCP registry metadata और server schema update हुआ। यह Octocode के published MCP server descriptor को असली tool surface के साथ कदम मिलाकर रखता है, ताकि registries और clients सही schema देखें। साथ ही सामान्य dependency और tooling housekeeping — कोई behavior change नहीं।
Upgrade
# Homebrew
brew upgrade muvon/tap/octocode
# Universal installer
curl -fsSL https://raw.githubusercontent.com/Muvon/octocode/master/install.sh | sh
# Cargo
cargo install octocode --version 0.18.0
इस रिलीज़ में कुछ भी आपके index या config को नहीं बदलता — upgrade करना safe है, और आपका मौजूदा setup चलता रहता है। आज़माने लायक दो चीज़ें:
- अपने fusion weights को keyword की ओर झुकाएँ। अगर आप prose से ज़्यादा code search करते हैं, तो benchmark कहता है कि keyword-led RRF एक मुफ़्त accuracy जीत है। इसे अपने repo पर मापें।
- Benchmark चलाएँ। Octocode clone करें, corpus pin करें, और अपने embedding model और reranker के खिलाफ
run_matrix.pyचलाएँ। ऊपर के numbers एक local floor हैं — अपना ceiling ढूँढें।
GraphRAG expansion आज़माने के लिए, [graphrag] enable करें, search.graph_expansion = true सेट करें, इसे एक code-aware reranker के साथ pair करें, और on रखने से पहले अपने baseline के खिलाफ A/B करें।
Octocode open source है (Apache 2.0) github.com/Muvon/octocode पर — benchmark, ground truth और raw results शामिल हैं। यह Octomind के पीछे का code-search engine है, और अब इसकी retrieval quality वह चीज़ है जिसे आप खुद माप सकते हैं, सिर्फ़ हमारी बात पर भरोसा नहीं करना पड़ता।



