From Grep to Project Knowledge Base: How AI Coding Assistants Understand Code

    AI coding assistants do not memorize your codebase. They put the right code into a finite context window at the right moment, which makes retrieval — not model size — the main driver of output quality. This article explains why most mainstream coding tools moved from prebuilt vector indexes to model-driven keyword search, how the iterative tool-call retrieval loop works, why scanning an entire repository is fast enough in practice, and where semantic retrieval still earns its place. It closes with a prioritized checklist for organizing a repository so the assistant can search it correctly.

    1. First, a Misconception to Clear Up: AI Coding Assistants Don’t “Memorize” Your Project

    The first time people use an AI coding assistant, they often get the impression that the tool has the whole codebase in its head. It doesn’t. The context window is finite, and tens of thousands of lines of code cannot be loaded in one shot. What we call “understanding” is really putting the right fragments into context at the right moment.

    So what actually determines output quality is not how large the model is, but whether the retrieval step can find the relevant code. If retrieval gets it wrong, even a very strong model can only invent a plausible story from noise. This also explains a common complaint: “Why does it keep editing the wrong file and writing code that doesn’t match our style?” Usually the model isn’t the problem — it simply never saw the critical piece.

    The industry’s first instinct is the classic Retrieval-Augmented Generation (RAG) path: chunk the code, generate embeddings, write them into a vector database, run semantic similarity search at query time, and stitch the top-K chunks into the prompt. This works well for document Q&A. But over the past couple of years, an unexpected shift has appeared in how mainstream AI coding tools have evolved: they dropped the prebuilt vector index in favor of search-driven exploration steered by the model itself. According to public technical talks from several teams working on these tools, early versions did try “vector store + semantic retrieval,” and quickly found that letting the model hunt and read with search tools — like a human developer would — produced better and more stable results.

    That raises two questions worth digging into:

    1. In a code context, why does precise text search beat semantic similarity search?
    2. If the AI mainly relies on searching to understand the project, what should our codebase prepare in advance so it searches correctly the first time?

    2. The Four Costs of the Intuitive Approach

    Before deciding what works better, look at the structural disadvantages of prebuilt vector retrieval for code.

    First, chunking destroys semantic boundaries. In documents, chunking affects paragraph completeness; in code, it affects compilable semantic units. Split a function in half, scatter a class’s methods across chunks, or separate a macro from its expansion site, and the retrieved fragments may not even fit together syntactically. The model is left guessing.

    Second, code semantics depend heavily on exact identifiers. Developers almost never search code with vague descriptions. They search for PaymentService, retry_with_backoff, ERR_TIMEOUT. Those strings are themselves the highest-density carriers of meaning. Doing fuzzy matching on exact strings means approximating with a low-dimensional dense vector something that could have been matched precisely.

    Third, high change frequency makes the index stale fast. A repository can take dozens of commits a day, and on top of that there are unsaved local changes, branches being switched, and build artifacts. Incremental vector index updates are an engineering burden: update too slowly, and search results point at code that no longer exists; update too often, and build overhead eats into development efficiency. Text search always targets the current state of the workspace, so it has no consistency problem by construction.

    Fourth, homonym ambiguity. User, Config, and init mean completely different things in different repositories. Abbreviations and domain terms are routinely overloaded across modules. Dense vectors pull these closer together in semantic space, while what the model needs to know is “which Config does this project mean” — and that has to be judged from directory context and call relationships, not from similarity scores.

    3. The Model-Driven Iterative Retrieval Loop

    The core of a modern AI coding tool is a tool-call loop: the model analyzes the request → selects a search tool and issues a call → reads the results → judges whether the information is sufficient → decides the next step. The model plans the whole process itself, rather than following a fixed retrieval pipeline.

    A typical toolset covers five kinds of capability:

    Capability What it does Typical scenario
    Content regex search Match patterns in file bodies Find all occurrences of an identifier
    File name pattern matching Glob lookup by path Locate config files, tests, migration scripts
    Range read Read a specified line range of one file Fetch a function body precisely without reading the whole file
    Sub-task exploration agent Launch exploration in a separate context Broad investigation that returns only conclusions
    Symbol-level navigation Jump to definition, find references Confirm call relationships across files

    A real retrieval session looks roughly like this. Say the question is: “How does this gateway system trace every tool invocation?”

    1. Round 1 Content search "trace" + "tool" → 4 candidate files (including gateway and call-record modules)
    2. Round 2 Switch to search mode with context lines → get fragments, discover the call chain passes through a mapping table
    3. Round 3 Read the full section of the file containing the mapping table → find the identifier-to-summary mapping definition
    4. Round 4 Search again using the mapping table identifier as the keyword → locate where trace records are actually written; loop closes

    After four rounds, the model is no longer holding a few isolated fragments — it has a call chain it can reason about. This is exactly what single-pass recall-based RAG struggles to reproduce: its recall quality is capped by the first query, while iterative retrieval lets the model “use a clue it just found to construct the next query.”

    Key engineering parameters of the loop include:

    • Termination condition: a sufficiency judgment on the information, typically constrained by both a round limit and a token budget, to prevent endless exploration.
    • Result trimming: search results are truncated by relevance and deduplicated; reads take only the needed line ranges, protecting the context budget.
    • Search scope pruning: exclude dependency directories, build artifacts, binary files, lock files, and generated code, otherwise a single search gets drowned in noise.
    • Parallelism and caching: independent search calls can run concurrently; file contents already read are cached within the session to avoid repeated spending.

    4. Why Brute-Force Search Really Is Fast Enough

    A common objection is that scanning the whole repository must be too slow. Work out the numbers and the concern goes away.

    A medium-sized project of tens of thousands to a bit over a hundred thousand lines is usually tens of MB of source text. Modern search tools run multi-threaded literal scans on SSDs at throughputs in the hundreds of MB to GB per second — a full-repository pass finishes in seconds. By comparison, embedding tens of thousands of lines of code requires calling an embedding model, incurs API cost, and needs index storage to maintain, with unclear payoff.

    What actually makes retrieval accurate are the heuristics that look “primitive”: filter by file extension and directory name, skip version control and dependency directories, honor case-sensitive and whole-word matching, and prefer output that includes context lines around hits. These rules deliver most of the benefit in a few dozen lines of code.

    Further along in engineering practice, you can layer symbol indexes and syntax tree parsing on top for speed and precision: the former supplies cross-file definition/reference relationships, and the latter helps identify function boundaries so code can be split and read accurately. These typically act as accelerators rather than replacements — text search guarantees the baseline, structured indexes improve it.

    5. Vector Search Isn’t Obsolete — It Just Needs the Right Place

    The conclusion is not that vector search is useless, but that it should not be the default backbone. Semantic retrieval still has value in these cases:

    • The intent description is far from the code’s shape: a user says “the fallback handling when an order times out,” while the code calls it degrade_policy, with no literal overlap.
    • Cross-language search: keyword matching breaks down when the query and the comments use different languages.
    • Mixed documentation and code repositories: requirements docs, design notes, comments, and implementations sit together, so semantic recall works better.
    • Very large monorepos or cross-repository searches: when the code exceeds an acceptable scan-time window, coarse filtering is needed.

    The mature approach is hybrid retrieval: use keyword/symbol indexing first to guarantee exact hits and explainability, then use semantic recall to cover cases where you “didn’t think of the keyword,” and finally unify trimming with reranking and context expansion. Be clear about the cost, though: once you introduce a vector layer, the index update pipeline, consistency guarantees, and infrastructure cost are back on the engineering table, and you need an explicit judgment about whether it’s worth it.

    6. The Core Practice: Making Your Project “Retrievable”

    If the AI mainly understands code by searching, then how the project is organized directly sets its ceiling. The measures below are ordered by return on investment.

    1. Make naming carry meaning. Avoid names with no information content such as data, tmp, helper, util2, especially in shared locations that cross module boundaries. Disambiguate overloaded names: user_service_v1 and legacy_user_import are far better than two UserServices.

    2. Let the directory structure express the architecture. Both humans and models should be able to infer responsibility from a path. Packaging by business domain beats stacking technical layers; entry points, public contracts, configuration, and tests each have a stable place. Directory names are themselves the strongest retrieval filter.

    3. Provide a stable “project guide.” Place structured documentation at the repository root and inside key modules, covering: the tech stack and versions, how to start and build, a table of directory responsibilities, core domain concepts and a terminology map, mandatory coding conventions, and common pitfalls. This document is not really for humans to read — it gives retrieval a high-hit entry point: it is the file the model is most likely to hit on its first search, after which it can follow the keywords in it deeper into the code.

    1. # Project Guide (excerpt)
    2. ## Directory responsibilities
    3. - src/gateway/ request ingress and routing
    4. - src/trace/ call-chain recording and reporting
    5. - src/billing/ billing and settlement
    6. ## Terminology map
    7. - "gateway" -> the gateway module; note the distinction from the edge proxy edge-proxy
    8. - "call record" -> the trace module; the write entry point is trace/recorder
    9. ## Conventions
    10. - New external dependencies must be registered in docs/deps.md
    11. - All public interfaces must carry type annotations and contract tests

    4. Pin down context with a rules file. Maintain an AI instruction file in the repository (for example, a conventions file at the root) that spells out the tech stack, code style, prohibited practices, testing requirements, and pre-commit checks. It gets loaded with priority during a session, which reduces repeated groping and keeps behavior consistent across different team members and different tools.

    5. Reduce ambiguous duplicates. Generated code, vendored copies of third-party sources, vendor, build artifacts, and legacy directories all create “same name, different implementation” noise. Mark them explicitly and exclude them from search; move them out of the main repository if necessary.

    6. Use tests and examples as semantic anchors. Test file names and case descriptions are often closer to the business language than the implementation. When a user asks in business vocabulary, tests are the easiest entry point to hit, and from there you can trace back to the implementation.

    7. Strengthen contracts and types. Complete type annotations, interface definitions, and error code tables let the model infer constraints from a single precise search, reducing cross-file jumps.

    8. Keep the workspace clean. Uncommitted experiment files, multiple xxx_old copies, and temporary scripts scattered in the root all lower the signal-to-noise ratio of search.

    9. Make runtime facts searchable too (enterprise scenarios). Code only explains “how it should run”; a production incident also needs “how it actually ran.” Keep the key identifiers in log services, monitoring alerts, distributed tracing, and release records (request IDs, error codes, metric names) consistent with code naming, and expose those capabilities to the assistant in a controlled, read-only way, so it can map an error message directly to a code location. On Baidu AI Cloud, this kind of “observable + searchable” loop can be built on general capabilities such as log service, monitoring and alerting, object storage, and container platform; for exact integration details, refer to each product’s official documentation.

    7. Evaluate and Tune: Don’t Pick a Strategy by Gut

    The quality of a retrieval strategy has to be measured. Build a small evaluation set:

    • Sample construction: pick 30–100 real tasks from historical issues and pull requests, annotated with which files and functions the correct answer involves.
    • Core metrics: recall rate of relevant files, average number of retrieval rounds, context token consumption, and first-pass task success rate.
    • Comparison dimensions: keyword-only iterative retrieval vs. hybrid retrieval vs. pure semantic retrieval, compared head-to-head on the same evaluation set.
    • Regression mechanism: rerun after every directory restructuring or new tool introduction, so a change like “we restructured and the AI got dumber” doesn’t go unnoticed.

    8. Deployment Checklist

    1. Is there structured project documentation and a terminology map at the root?
    2. Do directory names explain their responsibilities?
    3. Are information-free names and overloaded names still present in shared locations?
    4. Are generated code, dependency copies, and build artifacts excluded from search?
    5. Is there an AI instruction file pinning down the tech stack and coding conventions?
    6. Do key modules have type contracts and test anchors in business language?
    7. Are production error identifiers consistent with code naming, and searchable in both directions?
    8. Is there a quantitative evaluation and regression process for retrieval effectiveness?

    In one sentence: half of an AI coding tool’s comprehension comes from the model, and half comes from whether your codebase is searchable. Organizing the project as a knowledge base that gets queried constantly pays off far more than generating a vector index for all your code that goes stale fast.