A arquitetura RAG: indexação e recuperação
Mapeie as duas fases de RAG: a fase de indexação offline, que divide, transforma em embeddings e armazena documentos, e a fase de recuperação online, que encontra o contexto relevante para cada consulta.
A arquitetura RAG: indexação e recuperação é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.
O RAG Tem Duas Fases Distintas
Um sistema RAG opera em duas fases fundamentalmente diferentes, executadas em momentos distintos. A fase de indexação offline processa seus documentos uma vez (ou quando eles são alterados) e prepara um índice pesquisável. A fase de recuperação online é executada em tempo real para cada consulta do usuário. Compreender essa separação é essencial para projetar sistemas rápidos no momento da consulta e fáceis de manter ao longo do tempo.
A Fase de Indexação: Etapa Um — Carregar
A indexação começa com o carregamento de documentos: a leitura de arquivos brutos provenientes dos seus sistemas de origem. Os documentos podem ser PDFs, arquivos do Word, páginas HTML, arquivos Markdown, linhas de bancos de dados ou qualquer fonte de texto. Cada documento é carregado na memória como texto simples, preservando a estrutura sempre que possível. Bibliotecas como pypdf, python-docx e unstructured cuidam da maior parte da análise específica de cada formato.
from pypdf import PdfReader
def load_pdf(path):
reader = PdfReader(path)
pages = []
for i, page in enumerate(reader.pages):
text = page.extract_text()
pages.append({'text': text, 'page': i + 1, 'source': path})
return pages
docs = load_pdf('company_policy.pdf')
print(f'Loaded {len(docs)} pages')A Fase de Indexação: Etapa Dois — Dividir em Trechos
Os LLMs têm janelas de contexto finitas, e recuperar documentos inteiros é ineficiente. O texto carregado é dividido em trechos menores, com aproximadamente 200 a 1.000 tokens cada. Uma boa divisão preserva a coerência semântica: um trecho deve expressar uma ideia completa. Uma estratégia comum usa janelas sobrepostas, fazendo com que as frases próximas aos limites dos trechos apareçam em dois trechos e evitando a perda de informações nos pontos de divisão.
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # characters per chunk
chunk_overlap=50, # overlap between chunks
separators=['\n\n', '\n', '. ', ' ']
)
for page in docs:
chunks = splitter.split_text(page['text'])
for chunk in chunks:
# Each chunk carries metadata from its source page
print(f'Chunk ({len(chunk)} chars): {chunk[:80]}...')A Fase de Indexação: Etapa Três — Gerar Embeddings
Cada trecho de texto é convertido em um embedding vetorial denso que representa numericamente seu significado semântico. O senhor chama um modelo de embeddings — como o text-embedding-3-small da OpenAI — para cada trecho e recebe uma matriz de números de ponto flutuante de alta dimensionalidade. Trechos com significado semelhante produzem vetores próximos nesse espaço de alta dimensionalidade, o que possibilita a pesquisa por similaridade semântica.
from openai import OpenAI
client = OpenAI()
def embed_chunks(chunks):
texts = [c['text'] for c in chunks]
response = client.embeddings.create(
model='text-embedding-3-small',
input=texts
)
for i, chunk in enumerate(chunks):
chunk['embedding'] = response.data[i].embedding
return chunks
# Batch up to 2048 texts per API call
embedded = embed_chunks(all_chunks)A Fase de Indexação: Etapa Quatro — Armazenar
Os trechos transformados em embeddings são armazenados em um banco de dados vetorial junto com seus metadados (arquivo de origem, número da página, título da seção). O repositório vetorial cria uma estrutura de índice (normalmente HNSW) que permite uma pesquisa rápida aproximada pelos vizinhos mais próximos. Esse índice é persistido em disco para sobreviver a reinicializações. A indexação normalmente ocorre uma vez durante a configuração e de forma incremental quando novos documentos são adicionados.
import pinecone
pc = pinecone.Pinecone(api_key='YOUR_KEY')
index = pc.Index('rag-documents')
# Upsert vectors with metadata
vectors_to_upsert = [
(
chunk['id'],
chunk['embedding'],
{'text': chunk['text'], 'source': chunk['source'], 'page': chunk['page']}
)
for chunk in embedded_chunks
]
# Upsert in batches of 100
for i in range(0, len(vectors_to_upsert), 100):
index.upsert(vectors=vectors_to_upsert[i:i+100])
print('Indexing complete')A Fase de Recuperação: Embedding da Consulta
Quando um usuário envia uma consulta, começa a fase de recuperação online. A primeira etapa é gerar o embedding da pergunta do usuário usando o mesmo modelo de embeddings empregado durante a indexação. Isso é fundamental: se o senhor indexou com text-embedding-3-small, também deve consultar com text-embedding-3-small. O embedding da consulta é um vetor que codifica o significado semântico daquilo que o usuário está perguntando.
def embed_query(question):
response = client.embeddings.create(
model='text-embedding-3-small', # MUST match indexing model
input=[question]
)
return response.data[0].embedding
user_question = 'What is our parental leave policy?'
query_vector = embed_query(user_question)
print(f'Query embedded: {len(query_vector)}-dim vector')A Fase de Recuperação: Pesquisa ANN
O embedding da consulta é enviado ao repositório vetorial, que realiza uma pesquisa aproximada pelos vizinhos mais próximos (ANN) para encontrar os K trechos cujos embeddings são mais semelhantes ao vetor da consulta. Essa pesquisa é extremamente rápida (normalmente leva menos de 10 ms), pois os índices HNSW trocam uma pequena parcela da revocação por ganhos enormes de velocidade em relação à pesquisa por força bruta. O senhor recupera os K principais trechos — normalmente, de K=5 a K=20.
results = index.query(
vector=query_vector,
top_k=5,
include_metadata=True
)
print(f'Retrieved {len(results.matches)} chunks:')
for match in results.matches:
print(f' Score: {match.score:.3f} | Source: {match.metadata["source"]}')
print(f' Text: {match.metadata["text"][:100]}...')
print()Conectando as Duas Fases
A principal conclusão é que a indexação e a recuperação são projetadas para funcionar em conjunto. O modelo de embeddings deve ser idêntico nas duas fases, pois o espaço matemático onde os vetores ficam é específico do modelo. Se o senhor trocar de modelo de embeddings, deverá reindexar todos os documentos. O repositório vetorial é a ponte: ele aceita vetores durante a indexação e retorna vetores durante a recuperação, desacoplando as duas fases no tempo e mantendo-as alinhadas no espaço vetorial.
Filtragem de Metadados Durante a Recuperação
A pesquisa vetorial encontra trechos semanticamente semelhantes, mas às vezes o senhor também precisa filtrar por metadados. Por exemplo: recuperar apenas trechos de documentos enviados em 2025 ou apenas da pasta do departamento de RH. Os repositórios vetoriais oferecem pré-filtragem ou pós-filtragem nos campos de metadados. A pré-filtragem (compatível com Pinecone e Qdrant) aplica o filtro antes da pesquisa ANN, sendo mais rápida e precisa do que a pós-filtragem dos resultados principais, até K.
# Retrieve only from HR department documents
results = index.query(
vector=query_vector,
top_k=5,
filter={'department': {'$eq': 'HR'}},
include_metadata=True
)
# Or filter by date range
results = index.query(
vector=query_vector,
top_k=5,
filter={
'upload_year': {'$gte': 2024},
'doc_type': {'$eq': 'policy'}
},
include_metadata=True
)Indexação Incremental para Atualizações
Em produção, seu conjunto de documentos muda ao longo do tempo. Uma arquitetura de indexação eficaz oferece atualizações incrementais: quando um documento é editado, exclua seus vetores existentes pelo ID e faça upsert dos novos. Quando documentos forem excluídos, remova seus vetores. Atribua a cada trecho um ID determinístico baseado no caminho do documento de origem e na posição do trecho, para que o senhor possa sempre encontrar e atualizar os vetores corretos sem reindexar tudo.
import hashlib
def make_chunk_id(source_path, chunk_index):
# Deterministic, stable ID for each chunk
key = f'{source_path}::chunk_{chunk_index}'
return hashlib.md5(key.encode()).hexdigest()
def update_document(source_path, index):
# Delete old vectors for this document
index.delete(filter={'source': source_path})
# Re-index the updated document
new_chunks = load_and_chunk(source_path)
new_embedded = embed_chunks(new_chunks)
index.upsert(vectors=new_embedded)
print(f'Updated {source_path}: {len(new_chunks)} chunks')Todo o Pipeline do RAG em Resumo
A arquitetura completa do RAG é assim: Offline: Documentos → Carregador → Divisor em Trechos → Modelo de Embeddings → Repositório Vetorial. Online: Consulta do Usuário → Modelo de Embeddings → Repositório Vetorial (pesquisa ANN) → Principais Trechos, até K → Montagem do Prompt → LLM → Resposta. O pipeline offline é executado uma vez a cada atualização de documento. O pipeline online é executado em milissegundos para cada consulta do usuário, e o LLM vê apenas o contexto relevante, não todo o conjunto de documentos.
Verificação Rápida
Teste sua compreensão dos conceitos de Engenharia de IA desta lição.
Recapitulação da Lição
Nesta lição, o senhor aprendeu: a fase de indexação offline, composta pelas etapas de carregar, dividir em trechos, gerar embeddings e armazenar, executadas uma vez por documento; a fase de recuperação online, que gera o embedding da consulta, realiza uma pesquisa ANN e retorna os principais trechos, até K, em milissegundos; e estratégias de indexação incremental para manter o repositório vetorial atualizado à medida que os documentos mudam. A seguir, exploraremos como criar prompts aumentados eficazes que usem bem o contexto recuperado.
Perguntas Frequentes
A aula “A arquitetura RAG: indexação e recuperação” é grátis?
Sim — o texto completo de “A arquitetura RAG: indexação e recuperação” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.
O que vou aprender em “A arquitetura RAG: indexação e recuperação”?
Mapeie as duas fases de RAG: a fase de indexação offline, que divide, transforma em embeddings e armazena documentos, e a fase de recuperação online, que encontra o contexto relevante para cada consu… Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Engineering Academy?
Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “A arquitetura RAG: indexação e recuperação”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Engineering Academy?
Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- O problema que RAG resolve
- A arquitetura RAG: indexação e recuperação
- Criando o prompt aumentado
- RAG versus ajuste fino: quando usar cada um