Fetching from the wire…
Public story · 2026-07-31 · high
The study isolates corpus size as the only variable and still finds lexical search winning by 20 points at scale.
Why now: Both the retrieval benchmark and the Thoughtworks refactoring study landed July 30, arguing from different angles that what an agent reads matters more than which model reads it.
A corpus-scaling benchmark released July 30 shows BM25 beating dense retrieval by 20 points past 10 million tokens, per USTC and Metastone Technology researchers.
Most enterprise RAG systems ship with dense embeddings as the default retriever. I've built two that way myself. At the benchmark's full scale, 601 million tokens across 511,959 documents, BM25 scored 50.5 against dense retrieval's 29.9. The gap widens the bigger the corpus gets.
The design is why this result holds up where others don't. The benchmark, called EnterpriseRAG-Bench, nests 28 tiers across roughly a 450x range, each 1.25x larger than the last. The relevant documents and distractors stay identical at every tier. Only the background corpus grows, so corpus size is the one thing moving, not the queries or the judgments.
The mechanism is uncomfortable once you see it. Embeddings compress meaning into a fixed number of dimensions, and every document you add crowds that space further. Exact term matching doesn't degrade the same way. A rare part number or ticket ID stays rare no matter how many documents pile up around it.
One caveat: this is one benchmark on enterprise-style documents, dense with proper nouns and IDs. That's exactly where lexical search has the edge. The paper doesn't test conversational or narrative corpora, where embeddings might hold up better.
Any team running pure dense retrieval past 10 million corpus tokens has a measurable accuracy problem, not a theoretical one. The fix is BM25 as a first-class scorer, combined through reciprocal rank fusion, and that's closer to a weekend patch than a rebuild.
A Thoughtworks measurement published the same day points at the same lesson from a different angle. Fifteen refactoring steps on a 17,155-line Rust file cut input tokens per change 83%, from 159,564 to 27,360. The savings came from shrinking what an agent had to read. How you organize what gets retrieved matters more than which model reads it.
Each link below shares sources, entities, or timing with this story.
Claude Code uses Sonnet / Shared entities / Earlier coverage / Tension
Linked by a graph relationship (Claude Code uses Sonnet); both cover IDs, July, Sonnet; earlier IDs coverage from 2026-07-23.
Claude Code uses Sonnet / Shared entities / Shared topic / Earlier coverage
Linked by a graph relationship (Claude Code uses Sonnet); both cover RAG, Rust, Token; overlapping topics (agent, different, token).
Claude Code uses Sonnet / Shared entities / Earlier coverage
Linked by a graph relationship (Claude Code uses Sonnet); both cover July, Rust, Sonnet; earlier July coverage from 2026-07-19.
Codex CLI uses Rust / Shared entity: BM25 / Shared topic / Earlier coverage / Tension
Linked by a graph relationship (Codex CLI uses Rust); both cover BM25; overlapping topics (agent, bm25, token).
Grok uses Rust / Shared entities / Earlier coverage / Tension
Linked by a graph relationship (Grok uses Rust); both cover Bench, July; earlier Bench coverage from 2026-07-14.
Grok uses Rust / Shared entities / Shared topic / Earlier coverage
Linked by a graph relationship (Grok uses Rust); both cover Bench, July, Sonnet; overlapping topics (agent, token).
Codex CLI uses Rust / Shared entity: Rust / Earlier coverage
Linked by a graph relationship (Codex CLI uses Rust); both cover Rust; earlier Rust coverage from 2026-05-17.
Codex CLI uses Rust / Shared entity: Bench / Shared topic / Earlier coverage / Tension
Linked by a graph relationship (Codex CLI uses Rust); both cover Bench; overlapping topics (agent, different).