04-01-02 — Arquitetura RAG clássica
TL;DR
RAG clássico tem dois momentos distintos: indexação offline (chunkar documentos → embeddar → armazenar no vector store) e query online (embeddar a pergunta → buscar chunks similares → montar prompt com contexto → chamar o LLM). Entender essa separação é fundamental para diagnosticar problemas de performance e escalar o sistema.
Os dois tempos do RAG
RAG não é só "busca + LLM". É um pipeline com duas fases temporais bem distintas que rodam em momentos diferentes:
Fase 1: Indexação offline
Esta fase acontece quando você adiciona ou atualiza documentos. Não fica no caminho crítico das queries dos usuários.
1.1 Chunking — dividir para conquistar
Documentos completos são grandes demais para virar um único embedding. Um contrato de 80 páginas precisa ser cortado em trechos menores (chunks) antes de ser indexado. A estratégia de corte afeta diretamente a qualidade do retrieval.
Regra de bolso inicial: chunks de 512 tokens com 10% de overlap. Veremos estratégias avançadas em 04-03-01.
1.2 Embedding — texto vira número
Cada chunk passa por um embedding model — uma rede neural que transforma texto em um vetor de números de alta dimensão (ex: 1536 dimensões para text-embedding-3-small). Textos semanticamente similares ficam próximos nesse espaço vetorial.
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint="https://seu-recurso.openai.azure.com/",
api_key="SUA_CHAVE",
api_version="2024-02-01"
)
def embed(text: str) -> list[float]:
response = client.embeddings.create(
input=text,
model="text-embedding-3-small" # nome do deployment no Azure
)
return response.data[0].embedding # lista de 1536 floats
1.3 Vector Store — armazenar com índice
O vetor gerado é armazenado junto com metadados (nome do arquivo, página, data, permissões) num banco de dados otimizado para busca por similaridade. Esse é o componente que diferencia RAG de um simples grep.
Fase 2: Query online
Esta fase acontece em tempo real a cada pergunta do usuário. Latência importa aqui.
2.1 Embed da query
A pergunta do usuário passa pelo mesmo modelo de embedding usado na indexação. Isso é crítico: modelos diferentes geram espaços vetoriais incompatíveis.
2.2 Retrieval — buscar os chunks certos
O vetor da query é comparado com todos os vetores no store. Os top-k chunks mais próximos (tipicamente k=5 a 20) são retornados. "Próximos" aqui significa semanticamente similares, não textualmente idênticos.
2.3 Augmentation — montar o prompt
Os chunks recuperados são inseridos no prompt enviado ao LLM. Um template típico:
def build_prompt(question: str, chunks: list[str]) -> str:
context = "\n\n---\n\n".join(chunks)
return f"""Você é um assistente especializado. Responda à pergunta abaixo
usando SOMENTE o contexto fornecido. Se a resposta não estiver no contexto,
diga "Não encontrei essa informação nos documentos disponíveis."
CONTEXTO:
{context}
PERGUNTA: {question}
RESPOSTA:"""
2.4 Generation — o LLM responde
O LLM recebe o prompt aumentado e gera a resposta. Agora ele tem os documentos relevantes na "mesa de trabalho" — muito menos chance de alucinar sobre o assunto específico.
A qualidade da resposta RAG tem um teto: se o chunk certo não foi recuperado, nem o melhor LLM vai gerar uma boa resposta. Por isso 80% do esforço em sistemas RAG de produção está no retrieval, não no LLM.
O pipeline completo em código
def rag_query(question: str, vector_store, llm_client, k: int = 5) -> str:
# 1. Embed a pergunta
query_vector = embed(question)
# 2. Buscar chunks similares
chunks = vector_store.similarity_search(query_vector, k=k)
# 3. Montar o prompt
prompt = build_prompt(question, [c.text for c in chunks])
# 4. Chamar o LLM
response = llm_client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
Não misture modelos de embedding na indexação e na query. Se você indexou com text-embedding-3-small e na hora da query usou text-embedding-ada-002, os vetores são incompatíveis e o retrieval vai falhar silenciosamente — retornando resultados aleatórios sem lançar erro.
No ecossistema Azure, esse pipeline se traduz em: Azure Blob Storage (documentos) → Azure AI Document Intelligence (extração de texto) → Azure OpenAI Embeddings → Azure AI Search (vector store) → Azure OpenAI GPT-4o (LLM). Cada componente tem SLA e integração nativa.
Como isso se conecta
- 04-02-01 — Modelos de embedding — qual modelo escolher para o passo de embedding
- 04-02-02 — Vector databases — opções para o vector store
- 04-03-01 — Estratégias de chunking — como dividir documentos de forma inteligente
- 04-06-01 — Azure AI Search + OpenAI — pipeline completo no Azure
Fontes
- Lewis, P. et al. (2020). Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. arxiv.org/abs/2005.11401
- LangChain. RAG — Conceptual Guide. python.langchain.com/docs/concepts/rag
- Microsoft. Build a RAG solution using Azure AI Search. learn.microsoft.com
- OpenAI. Embeddings API Reference. platform.openai.com