Dua angka membawa saya kembali ke benchmark ini. README codebase-memory-mcp, graf kode berbasis tree-sitter yang disajikan lewat MCP, menjanjikan token 99% lebih sedikit. Run saya sendiri sebelumnya mengatakan bahwa cbm-lean, wrapper tipis yang saya tulis di sekelilingnya, membuat agen coding 26% lebih murah daripada grep biasa di haiku dan 18% lebih murah di sonnet. Angka pertama tidak pernah bisa saya reproduksi, dan angka kedua berasal dari cacat dalam susunan eksperimen saya. Ini adalah run ulang di repositori publik, dengan cacat itu sudah diperbaiki.
Susunan
Setiap pertanyaan dijalankan dalam tiga varian:
- cbm-lean, ditambah aturan perutean di system prompt: pertanyaan struktural ke graf, string yang persis ke Grep;
- server codebase-memory-mcp mentah, ditambah aturan yang sama;
- hanya Read, Grep, dan Glob.
Setiap repositori mendapat dua belas pertanyaan. Enam bersifat struktural: siapa yang memanggil sebuah fungsi, apa yang dipanggilnya, rantai panggilan dari sebuah endpoint HTTP sampai penulisan ke database, susunan modul. Enam lainnya bersifat persis: sebuah nilai konfigurasi, di mana sebuah variabel lingkungan dibaca, sebuah pesan error, baris tempat sebuah kelas didefinisikan. Setiap pertanyaan mencantumkan substring yang harus ada dalam jawaban yang benar, dan semuanya saya cocokkan dengan kode secara manual.
Repositorinya adalah tiga yang kecil (template full-stack FastAPI, ltx-2-mlx, dan avoid-ai-writing, 1,6 ribu hingga 5 ribu node graf) dan dub, monorepo Next.js dengan 25 ribu node. Haiku 4.5 dijalankan di semuanya dan sonnet 5 di dub: 252 run, US$14,69 dengan harga API.
Biaya diukur sebagai tokenEquiv: token input, ditambah 1,25 × penulisan cache, ditambah 0,1 × pembacaan cache. Input mentah yang ditagih menyesatkan begitu prompt caching aktif, karena varian yang kebetulan berjalan di cache yang hangat tampak murah karena alasan yang tidak ada hubungannya dengan varian itu.
Hasil
Median tokenEquiv per run, dengan jumlah jawaban benar dalam kurung:
| kondisi | run | cbm-lean | graf mentah | grep |
|---|---|---|---|---|
| Repositori kecil, haiku 4.5 | 108 | 30.321 (28/36) | 43.846 (32/36) | 31.159 (33/36) |
| dub, haiku 4.5 | 72 | 18.791 (22/24) | 20.687 (22/24) | 14.955 (20/24) |
| dub, sonnet 5 | 72 | 17.227 (22/24) | 23.085 (22/24) | 13.348 (22/24) |
Tiga hasil bertahan:
- Dalam hal token, graf tidak pernah menang. Dibandingkan grep, tidak ada perbedaan yang terukur di repositori kecil (p = 0,13) maupun di dub dengan haiku (p = 0,18), dan di dub dengan sonnet grep lebih murah pada 11 dari 12 pertanyaan (p = 0,034) dengan akurasi yang sama, 22 dari 24 di setiap varian.
- Wrapper mengalahkan server mentah di setiap kondisi (p ≤ 0,021). Server mentah mengembalikan sekitar 1,3 KB per hit pencarian, sebagian besar berupa dump identifier dan vektor hash, dan cbm-lean memangkas satu hit menjadi sekitar 250 byte.
- Satu-satunya kemenangan jelas graf adalah akurasi model kecil di repositori besar. Haiku menjawab pertanyaan struktural di dub dengan benar 12 dari 12 kali dengan graf dan 8 dari 12 kali dengan grep, dengan median 23,5 ribu token berbanding 16,0 ribu.
Nilai p berasal dari uji peringkat bertanda Wilcoxon atas median per pertanyaan.
Di mana setiap varian keliru
- Nomor baris dari graf. Ditanya baris sebuah pesan error, varian graf membaca jawabannya dari keluaran graf dan memberi login.py:33; raise-nya ada di baris 34, dan 33 adalah if di atasnya. Ia melaporkan config.py:74 untuk kelas yang oleh graf itu sendiri disimpan di baris 15 sampai 88, dan client.ts:129 untuk kelas yang didefinisikan di baris 59. Aturan perutean menyuruhnya memakai grep untuk pertanyaan yang persis, dan haiku tidak selalu mengikutinya.
- Nama kembar. Template FastAPI punya dua handler bernama create_user. Ditanya endpoint admin, kedua varian graf menelusuri yang tanpa autentikasi pada 5 dari 6 run. Grep selalu menemukan yang berada di balik pemeriksaan superuser.
- Berhenti terlalu dini. Di dub, haiku dengan grep dua kali melewatkan penulisan database yang sebenarnya di ujung rantai panggilan.
- Penilaian saya sendiri. Setiap run sonnet, di setiap varian, tidak menyertakan packages/tinybird dalam jawaban arsitektur dub. Folder itu berisi file data Tinybird dan tidak punya package.json, jadi bisa dibilang modelnya benar dan pemeriksaan saya yang salah. Keenam kesalahan sonnet semuanya ada di satu pertanyaan itu, dan membuangnya tidak mengubah perbandingan apa pun.
Memasang graf tidak sama dengan memakainya
Hasil paling berguna datang dari pilot, bukan dari run utama. Claude Code 2.1.283 secara bawaan menunda skema tool MCP di balik langkah ToolSearch: model melihat nama-nama tool dan harus mengambil skemanya sebelum bisa memanggil apa pun. Haiku headless tidak melakukannya. Dalam enam run pilot, graf tidak pernah dipanggil, dengan atau tanpa aturan perutean. Pada dua belas pertanyaan repositori kecil:
| susunan | memanggil graf | benar | median tokenEquiv |
|---|---|---|---|
| Pemuatan bawaan, dengan aturan | 2 dari 12 | 11 dari 12 | 41.008 |
| Skema dimuat, tanpa aturan | 4 dari 12 | 9 dari 12 | 62.008 |
| Skema dimuat, dengan aturan | 22 dari 36 | 28 dari 36 | 30.321 |
Dengan skema dimuat (ENABLE_TOOL_SEARCH=false), pertanyaan tentang pemanggil yang sama melewati dua panggilan graf dalam tiga giliran. Graf yang terpasang tanpa aturan adalah susunan termahal dari semuanya: setiap sesi membayar skemanya, dan model sebagian besar membiarkannya tak terpakai.
Kalau Anda merilis server MCP dan mengujinya dengan pengaturan bawaan, pertama-tama periksa apakah model memanggilnya sama sekali.
Mengapa angka sebelumnya salah
Benchmark pertama berjalan di dalam folder proyek saya. CLAUDE.md di sana menyuruh agen memakai graf untuk pertanyaan struktural, dan Claude Code memuat file CLAUDE.md dari direktori induk, sehingga instruksi itu sampai ke setiap varian, termasuk yang tanpa graf. Kelompok kontrol diberi instruksi kelompok perlakuan, artinya perbandingan itu mengukur aturannya sama banyaknya dengan tool-nya.
Run ulang menaruh repositori di luar pohon mana pun yang di atasnya ada CLAUDE.md, melewatkan pengaturan dan hook
pengguna (--setting-sources project), dan memberi aturan hanya kepada varian yang punya graf. Kontrol-kontrol lainnya
masing-masing memperbaiki kesimpulan keliru di putaran sebelumnya. Bash dan Agent ditolak di setiap varian, karena izin
Bash yang dibatasi tidak cocok dengan perintah yang disambung pipe, dan subagen menyembunyikan giliran sambil tetap
menghabiskan token. Urutan varian dirotasi di antara pengulangan, sehingga tidak ada varian yang selalu berjalan di
cache hangat. Run yang memanggil tool yang bukan milik variannya dibuang. Dan jawaban dinilai, karena token yang
dihemat untuk jawaban yang salah bukanlah penghematan.
Yang akan saya katakan kepada tim yang menghubungkan graf ke agen
- Jangan berharap ada penghematan token dari graf kode dengan model Claude di repositori sampai 25 ribu node. Ukur dulu dengan pertanyaan Anda sendiri.
- Kalau tetap memasangnya, pangkas keluarannya, muat skemanya, dan beri agen aturan perutean. Tanpa dua yang terakhir, graf itu beban mati di setiap prompt.
- Jangan percaya nomor baris yang dibaca model dari hasil graf, dan periksa dengan grep.
- Graf layak dipakai ketika model kecil menjawab pertanyaan struktural di basis kode yang besar: arsitektur dan rantai panggilan.
Batasan
Dua model, empat repositori sampai 25 ribu node, dua atau tiga pengulangan, masing-masing dua belas pertanyaan. Tanpa Opus, tanpa sesi interaktif yang panjang, tidak ada yang melebihi 25 ribu node. Yang dilaporkan adalah median karena run berulang untuk pertanyaan yang sama sangat bervariasi.
Reproduksi
Semuanya ada di code-graph-vs-grep: pertanyaan dengan commit yang dipatok, driver benchmark, run mentah beserta setiap jawabannya, dan cbm-lean itu sendiri.
bash bench/setup.sh
node bench/run.mjs --reps 3
python3 bench/stats.py results/*.json