cAST: AST chunking lifts RepoEval Pass@1 by up to 6.7 vs line splits

2026-09-22

cAST recursively splits then merges AST nodes into syntax-aligned chunks. On RepoEval it lifts Recall@5 by up to 4.3 and StarCoder2 Pass@1 by 5.5 on average versus line-based splitting.

What problem this solves

Code RAG still inherits line-based, fixed-window chunking from text RAG. Functions, class bodies, and return signatures get sliced in the middle. The retriever then surfaces a fragment, and the generator invents the wrong interface.

One figure in the paper makes the failure concrete: after computestats is split, the model treats the return value as a dict and the completion does not run. For repo-level completion, cross-file references, and GitHub-issue repair, the chunk boundary decides what the model is allowed to see.

Method

cAST parses source with tree-sitter, then runs a recursive split-then-merge pass.

The design constraints are explicit: keep syntactic units, pack each chunk, avoid language-specific heuristics, and require that concatenating chunks reproduces the original file byte-for-byte so the method can drop into an existing pipeline.

Results

Evaluation covers RepoEval (in-file completion), CrossCodeEval (multilingual cross-file), and SWE-bench Lite (300 single-file GitHub issues). Retrieval is reported as nDCG, Precision, and Recall@5; generation as Pass@1 or exact match.

SetupMetriccASTLine split
RepoEval + GISTRecall@575.070.7
RepoEval + GIST + StarCoder2Pass@157.951.2
RepoEval + CodeSage + StarCoder2Pass@173.267.6
SWE-bench Lite + CodeSage + ClaudePass@116.714.0
CrossCodeEval + CodeSage, code EM29.124.8

The abstract's +4.3 Recall@5 is GIST on RepoEval (70.7 to 75.0). StarCoder2-7B gains 4.2, 6.7, and 5.6 Pass@1 across three retrievers, about 5.5 on average. Claude Pass@1 on SWE-bench Lite rises by at most 2.7. Split-only ablation is harsh: BGE nDCG falls from 71.1 to 53.5 because tiny nodes bloat the index.

Retrieval and generation peak at a 2000–2500 character chunk cap. Doubling context from 4000 to 8000 tokens is not a free win; CodeSage + StarCoder2 drops from 73.2 to 69.2. Downstream quality tracks Precision more than Recall or nDCG. Once the needed evidence is in the top-k, extra lower-ranked chunks add noise.

Why it matters

This is the cheapest stage in a RAG stack. No new retriever, no new generator, only a different splitter. For anyone shipping a code agent, tree-sitter plus recursive merge is a drop-in change, and the code is public. For anyone building code-RAG benchmarks, line splitting systematically understates methods that care about syntax.

The gains are incremental, not an architecture swap. Code-specific retrievers such as CodeSage and Jina benefit more; generic text retrievers still move, but by less.

Limitations

The authors flag three gaps. For a fair comparison they did not inject parent AST nodes as multi-level context, even though textual RAG has shown that hierarchical context helps. Chunking is applied to raw code files only, with no extra views from comments, pseudocode, or I/O specs. There is no query-adaptive use of traces, type inference, or compilation.

SWE-bench is the Lite split with a single-file edit constraint, and Pass@1 still sits in the 13–17% band. In Table 7, BGE-large + Claude scores 13.3 with cAST versus 14.6 with line splits, so not every retriever improves. TypeScript exact match stays well below Python and Java; syntax-aware chunks shrink cross-language scatter without erasing language difficulty.

Terms

Source

What people are saying

All paper explainers