Phase 19 - Lesson 02
Capstone 02 — RAG over Codebase (Cross-Repo Semantic Search)
Em 2026, qualquer organização de engenharia madura executa uma busca de código interna que compreende o significado, e não apenas correspondências de strings. Sourcegraph Amp, busca em bases de código do Cursor, grafo empresarial da Augment, repomap do Aider, MCP interno do Pinterest — todos seguem o mesmo padrão. Ingerir múltiplos repositórios, analisar com tree-sitter, gerar embeddings de trechos baseados em funções e classes, realizar busca híbrida, reordenar (re-rank), e responder com citações. Este projeto prático (capstone) desafia você a construir uma ferramenta que suporte 2 milhões de linhas de código em 10 repositórios e sobreviva a reindexações incrementais a cada git push.
Type: Capstone Languages: Python (ingestion), TypeScript (API + UI) Prerequisites: Phase 5 (NLP foundations), Phase 7 (transformers), Phase 11 (LLM engineering), Phase 13 (tools), Phase 17 (infrastructure) Phases exercised: P5 · P7 · P11 · P13 · P17 Time: 30 hours
Problem
Em 2026, todo agente de programação de fronteira é distribuído com uma camada de recuperação de base de código, pois apenas as janelas de contexto não resolvem dúvidas que envolvem múltiplos repositórios. O contexto de 1 milhão de tokens do Claude ajuda, mas não elimina a necessidade de uma recuperação ordenada e relevante. A busca por cosseno ingênua sobre blocos de texto puros envenena os resultados em códigos gerados automaticamente, em duplicidades de monorepositórios e na cauda longa de símbolos raramente importados. A solução em produção é a busca híbrida (densa + BM25) sobre blocos estruturados de forma ciente da AST (árvore de sintaxe abstrata) com um reordenador (re-ranker), apoiada por um grafo de referências de símbolos.
Você aprenderá isso ao indexar uma frota real de repositórios — e não um repositório fictício de tutorial — e medir MRR@10, fidelidade das citações e o frescor da indexação incremental. Os modos de falha são de nível de infraestrutura: um monorepositório de 100 mil arquivos, um push que altera metade dos arquivos, uma consulta que precisa cruzar quatro repositórios para responder corretamente.
Concept
Uma pipeline de ingestão ciente da AST analisa cada arquivo com o tree-sitter, extrai nós de funções e classes e realiza a divisão em blocos (chunking) nos limites dos nós, em vez de usar janelas fixas de tokens. Cada bloco recebe três representações: um embedding denso (Voyage-code-3 ou nomic-embed-code), termos esparsos BM25 e um pequeno resumo em linguagem natural. O resumo adiciona uma terceira modalidade recuperável — os usuários perguntam "como X é autorizado" e o resumo menciona "authz", mesmo que o código utilize apenas check_permission.
A recuperação é híbrida. Uma consulta dispara buscas densas e esparsas (BM25) em paralelo, mescla os melhores resultados e envia essa união para um reordenador de codificação cruzada (cross-encoder re-ranker, como Cohere rerank-3 ou bge-reranker-v2-gemma-2b). A lista reordenada é fornecida para um sintetizador de contexto longo (Claude Sonnet 4.7 com cache de prompt ou Llama 3.3 70B hospedado localmente) com instruções para citar cada afirmação por arquivo e intervalo de linhas. Respostas sem citações são rejeitadas por um pós-filtro.
O frescor incremental é o grande desafio de infraestrutura. Um git push dispara um webhook de diff indicando quais arquivos e símbolos mudaram. Apenas os blocos afetados passam pelo processo de geração de novos embeddings. As arestas de símbolos compartilhados entre arquivos (importações, chamadas de métodos) são recalculadas. O índice permanece consistente sem a necessidade de reprocessar as 2 milhões de linhas de código a cada commit.
Architecture
git push --> webhook --> ingest worker (LlamaIndex Workflow)
|
v
tree-sitter parse + AST chunk
|
+--------------+----------------+
v v v
dense BM25 index summary (LLM)
(Voyage / bge) (Tantivy) (Haiku 4.5)
| | |
+------> Qdrant / pgvector <----+
|
v
symbol graph (Neo4j / kuzu)
|
query --> LangGraph agent (retrieve -> rerank -> synth)
|
v
Claude Sonnet 4.7 1M context
|
v
answer + file:line citations
Stack
- Análise sintática: tree-sitter com gramáticas para 17 linguagens (Python, TS, Rust, Go, Java, C++, etc.)
- Embeddings densos: Voyage-code-3 (hospedado) ou nomic-embed-code-v1.5 (hospedagem local), fallback para bge-code-v1
- Índice esparso: Tantivy (escrito em Rust) com BM25F, com pesos diferenciados por campos (nome do símbolo vs corpo)
- Banco de dados vetorial: Qdrant 1.12 com busca híbrida, ou pgvector + pgvectorscale para equipes com menos de 50 milhões de vetores
- Modelo de resumo de blocos: Claude Haiku 4.5 ou Gemini 2.5 Flash, com cache de prompt
- Reordenador (re-ranker): Cohere rerank-3 or bge-reranker-v2-gemma-2b hospedado localmente
- Orquestração: LlamaIndex Workflows para ingestão, LangGraph para o agente de consulta
- Sintetizador: Claude Sonnet 4.7 (contexto de 1M) com cache de prompt
- Grafo de símbolos: Neo4j (gerenciado) ou kuzu (embarcado) para arestas de importação e chamada
- Observabilidade: spans do Langfuse por etapa de recuperação + síntese
Build It
Varredor de ingestão. Percorra o histórico do git a cada webhook de push. Colete os arquivos alterados. Para cada arquivo, analise com o tree-sitter, extraindo nós de funções e classes com seus respectivos intervalos de linhas de origem. Emita registros de blocos contendo
{repo, path, start_line, end_line, symbol, body}.Resumidor de blocos. Agrupe os blocos em chamadas para o Haiku 4.5 com cache de prompt no preâmbulo do sistema. Prompt: "Resuma esta função em uma frase, indicando seu contrato público e efeitos colaterais." Armazene o resumo junto ao bloco de código correspondente.
Pool de embeddings. Duas filas paralelas: densa (lotes de 128 com Voyage-code-3) e resumo (mesmo modelo, porém sobre a string do resumo). Grave os vetores no Qdrant com os metadados
{repo, path, start_line, end_line, symbol, kind}.Índice BM25. Índice Tantivy com pesos por campo: peso 4 para nome do símbolo, peso 1 para o corpo do símbolo, peso 2 para o resumo. Isso permite consultas do tipo "encontre a função chamada X" junto com "encontre a função que faz X".
Grafo de símbolos. Para cada bloco, registre as arestas correspondentes: importações (este arquivo usa o símbolo Y do repositório Z), chamadas (esta função chama o método M na classe C), herança. Armazene no kuzu. Utilizado no momento da consulta para expandir a busca além das fronteiras de um único repositório.
Agente de consulta. Estrutura LangGraph com três nós.
retrievedispara buscas densas e BM25 em paralelo, deduplicando por (repo, path, symbol).rerankexecuta a ordenação cruzada (cross-encoder) nos top-50 resultados e mantém os top-10.synthchama o Claude Sonnet 4.7 com os blocos reordenados no contexto, utiliza cache de prompt e exige citações no formato arquivo:linha.Validação de citações. Analise a saída do modelo; qualquer alegação sem uma âncora no formato
(repo/path:start-end)é sinalizada para reprocessamento ou descartada. Retorne apenas respostas devidamente citadas ao usuário.Reindexação incremental. Em cada webhook, calcule a diferença (diff) no nível do símbolo. Gere novos embeddings apenas para blocos cujo texto foi alterado. Recalcule as arestas de símbolos para blocos cujas importações foram modificadas. Métrica: um push de 50 arquivos deve ser reindexado em menos de 60 segundos para uma frota de 2M de linhas de código.
Avaliação. Rotule 100 perguntas multirrepositório com suas respectivas respostas padrão no formato arquivo:linha. Meça MRR@10, nDCG@10, fidelidade das citações (proporção de alegações com âncoras verificáveis) e latência p50/p99.
Use It
$ code-rag ask "how is S3 multipart abort wired into our retry budget?"
[retrieve] 12 chunks dense + 7 chunks bm25, 16 unique after dedup
[rerank] top-5 kept (cohere rerank-3)
[synth] claude-sonnet-4.7, cache hit rate 68%, 2.1s
answer:
Multipart aborts are triggered by `AbortMultipartOnFail` in
services/uploader/retry.go:122-148, which decrements the per-bucket
retry budget defined in config/budgets.yaml:34-51 ...
citations: [services/uploader/retry.go:122-148, config/budgets.yaml:34-51,
libs/s3client/multipart.ts:44-61]
Ship It
A habilidade entregável é detalhada em outputs/skill-codebase-rag.md. Dado um conjunto de repositórios, ela monta a pipeline de ingestão, o índice híbrido e o agente de consulta, e retorna respostas citadas para qualquer dúvida que cruze os repositórios. Critérios de avaliação:
| Weight | Criterion | How it is measured |
|---|---|---|
| 25 | Retrieval quality | MRR@10 e nDCG@10 em um conjunto de teste de 100 perguntas |
| 20 | Citation faithfulness | Proporção de alegações nas respostas contendo âncoras arquivo:linha válidas |
| 20 | Latency and scale | Latência de consulta p95 em 10k QPS no tamanho do corpus indexado |
| 20 | Incremental indexing correctness | Tempo desde o git push até que as alterações sejam localizáveis em um commit de 50 arquivos |
| 15 | UX and answer formatting | Citações clicáveis, pré-visualização de trechos de código e facilidade de perguntas de acompanhamento |
Exercises
Substitua o Voyage-code-3 pelo nomic-embed-code hospedado localmente. Meça a diferença no MRR@10. Relate se a diferença diminui quando a reordenação (re-ranking) está ativada.
Injete 20% de código gerado por IA (código repetitivo gerado por LLMs) no corpus de código e refaça a avaliação. Observe o envenenamento da recuperação de dados. Adicione uma tag "gerado" nos metadados e reduza o peso desses resultados na busca.
Faça um benchmark da busca híbrida do Qdrant versus pgvector + pgvectorscale no tamanho real de sua base de código. Relate a latência p99 para um tamanho de lote igual a 1.
Adicione uma verificação semanal contra desvios de desempenho: reexecute semanalmente a avaliação das 100 perguntas. Dispare alertas caso ocorra queda de MRR@10 > 5%.
Estenda o sistema para resolução de símbolos multilinguagem: uma função em Python que chama um serviço em Go via gRPC. Utilize o grafo de símbolos para mapear essa conexão.
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| AST-aware chunking | "Divisão em nível de função" | Divisão do código nos limites dos nós estruturais do tree-sitter em vez de limites de janelas de tokens fixas |
| Hybrid search | "Densa + esparsa" | Execução paralela de buscas vetoriais e BM25, mesclando e reordenando os melhores resultados |
| Cross-encoder rerank | "Classificação de segunda etapa" | Modelo que avalia conjuntamente o par (consulta, candidato), oferecendo maior precisão do que a similaridade por cosseno simples |
| Prompt caching | "Cache de prompt do sistema" | Funcionalidade do Claude / OpenAI que desconta até 90% do custo de tokens repetidos no início do prompt |
| Symbol graph | "Grafo de código" | Mapeamento de conexões de importações, chamadas de funções e heranças entre arquivos e repositórios |
| Citation faithfulness | "Taxa de aterramento da resposta" | Proporção de afirmações que o usuário pode verificar diretamente clicando no link e lendo o trecho referenciado |
| Incremental re-index | "Tempo de disponibilização na busca" | Tempo decorrido desde o git push até que as alterações nos símbolos estejam disponíveis para consulta |
Further Reading
- Sourcegraph Amp — inteligência de código multirrepositório em produção
- Sourcegraph Cody RAG architecture — análise técnica de referência para este capstone
- Aider repo-map — mapa de repositórios estruturado por relevância via tree-sitter
- Augment Code enterprise graph — RAG baseado em grafos de símbolos comercial
- Qdrant hybrid search docs — implementação de referência
- Voyage AI code embeddings — detalhes sobre o Voyage-code-3
- Cohere rerank-3 — referência sobre reordenadores cross-encoder
- Pinterest MCP internal search — referência de arquitetura interna de plataforma