Skip to main content

Benchmarks

graphlens-mcp ships with a reproducible A/B benchmark (benchmarks/) that drives an identical pydantic-ai agent against four interchangeable code-context arms — graphlens (this project), codegraph (graph index), semble (semantic search), and a no-tools control that measures how much any of them adds over the model's own memory — across ten real open-source repositories (Go / Rust / Python / TypeScript), graded deterministically against oracle gold answers (no LLM judge).

Scope

  • 10 projects: gin, echo, ripgrep, clap, fastapi, click, httpx, hono, zod, superset.
  • 3 models, spanning strong to genuinely weak: deepseek-v4-flash, gemma-4-26b, gpt-oss-20b.
  • 2 difficulty tiers: SIMPLE (symbol/definition lookups, single-hop) and HARD (impact analysis, disambiguation, multi-hop cross-file questions).
  • ~2,400 graded runs, each with token/tool-call/dollar cost recorded alongside accuracy.

Headline result

SIMPLE accuracyHARD accuracyHARD tokens (median)HARD completion
graphlens0.980 – 1.0000.899 – 0.92122.4k – 34.1k≥ 0.959 on every model
codegraph0.912 – 0.9900.655 – 0.93923.2k – 70.0kdrops to 0.765 on the weakest model
semble0.647 – 0.9610.555 – 0.85021.6k – 74.9kdrops to 0.688 on the weakest model
none (control)0.366 – 0.6810.453 – 0.6850.1k – 0.9k

Accuracy alone hides the number that maps directly to a bill: tokens paid per task. graphlens's HARD-tier token spend stays flat (22k–34k) across the whole model range; codegraph's and semble's balloon past 70k on the weakest model — more than double graphlens's ceiling — for a worse answer, not a better one. Accuracy and token cost are both worth reading, and reading together: a tool that's marginally more accurate but burns 2× the tokens per task isn't obviously the better deal once that scales to a real workload.

graphlens is the only arm that stays clearly ahead of the no-tools control and keeps completion above 0.95 at every model tier. The gap over codegraph widens, not narrows, as the driving model gets weaker: on the weakest model tested (gpt-oss-20b), graphlens holds 0.900 HARD accuracy at 0.959 completion, while codegraph drops to 0.655 accuracy with completion falling to 0.765 — roughly 1 in 4 of its runs never produce an answer at all, most often by exhausting its own output-token budget mid-answer. graphlens gets there at roughly half the token cost (34k vs 70k median tokens per HARD task).

Full breakdown

SIMPLE tasks — accuracy · completion · median tokens · median cost
armmodelaccuracycompletiontokenscost
graphlensdeepseek-v4-flash0.9801.0008,396$0.00077
graphlensgemma-4-26b1.0001.0004,060$0.00026
graphlensgpt-oss-20b0.9801.0004,033$0.00014
codegraphdeepseek-v4-flash0.9901.0009,662$0.00090
codegraphgemma-4-26b0.9120.9417,588$0.00048
codegraphgpt-oss-20b0.9711.00011,150$0.00035
sembledeepseek-v4-flash0.9610.96112,934$0.00121
semblegemma-4-26b0.6470.6965,800$0.00038
semblegpt-oss-20b0.8240.84312,038$0.00041
nonedeepseek-v4-flash0.6811.000243$0.00004
nonegemma-4-26b0.3660.901115$0.00001
nonegpt-oss-20b0.5490.961466$0.00005
HARD tasks — accuracy · completion · median tokens · median cost
armmodelaccuracycompletiontokenscost
graphlensdeepseek-v4-flash0.9211.00023,436$0.00226
graphlensgemma-4-26b0.8991.00022,430$0.00138
graphlensgpt-oss-20b0.9000.95934,064$0.00106
codegraphdeepseek-v4-flash0.9391.00023,212$0.00214
codegraphgemma-4-26b0.8470.95925,287$0.00156
codegraphgpt-oss-20b0.6550.76569,991$0.00223
sembledeepseek-v4-flash0.8500.90860,804$0.00582
semblegemma-4-26b0.6150.72421,555$0.00136
semblegpt-oss-20b0.5550.68874,937$0.00244
nonedeepseek-v4-flash0.6851.000246$0.00003
nonegemma-4-26b0.4530.898133$0.00001
nonegpt-oss-20b0.5290.917944$0.00011

Why report accuracy and completion separately

A run that never finishes — a turn-limit cutoff, a timeout, the model exhausting its own output-token budget — is graded as wrong, same as a run that answered confidently and incorrectly. Reporting only accuracy hides why a tool scored low: a wide gap between accuracy and completion means the tool isn't being out-reasoned so much as it's failing to finish at all. This is exactly the failure mode that dominates codegraph's and semble's weak-model numbers above, and it's invisible in a bare accuracy column.

Statistical significance

Every arm answers the identical task set, so this is a repeated-measures design — the right significance test is a paired, non-parametric one, not an unpaired comparison of pooled means. The benchmark's metrics.ipynb runs:

  • a Friedman test (omnibus): are the four arms different at all, ranked within each task?
  • a Wilcoxon signed-rank test (pairwise): for graphlens vs. each rival specifically, matched by task_id, with a rank-biserial effect size alongside the p-value.

The pairwise gap between graphlens and codegraph is not statistically significant on deepseek-v4-flash (the strongest model — the two are a real tie there) but becomes significant, with a large effect size, on both weaker models — exactly where the headline table above shows the widest gap. A per-project heatmap in the same notebook confirms graphlens ranks first among all four arms on HARD accuracy in all ten projects, so the result isn't one favorable repo carrying the average.

Why none (no tools) is in the comparison

none answers from the model's own parametric memory alone, with zero tools available. It's not a competitor — it's the contamination-robust floor every real arm needs to clear. A popular open-source repo a model already memorized during training would inflate every arm's raw accuracy equally; each arm's lift over none is what isolates the tool's actual contribution from that noise.

Reproducing this

cd benchmarks
uv sync
cp .env.example .env # add your OPENROUTER_API_KEY
uv run main.py # full sweep (slow, costs real API spend)
uv run main.py --projects gin echo # a quick subset
uv run scripts/report.py # headline table + Friedman test, from the CLI
jupyter notebook metrics.ipynb # the fuller analysis on this page

See benchmarks/README.md for the full harness design: task authoring, oracle grading, cost accounting, and the exact arm/model registry.

Data hygiene note

A benchmark cell that times out or hits its turn limit gets retried; the retry is appended to that project's result file rather than replacing the failed attempt in place. Any analysis over this data must dedupe on (project, arm, model, task_id, seed), keeping the last row, before computing an aggregate — scripts/report.py's load() does this automatically. Skipping it double-counts every retried failure and measurably distorts the result: an earlier, un-deduped pass of this data reported codegraph's gpt-oss-20b / HARD accuracy at 0.373 (apparently worse than the no-tools control); properly deduped, it's 0.655.