Pular para o conteúdo principal

Capítulo 3: Visão Geral da Arquitetura RAG

Introdução​

Um sistema RAG consiste em três fases principais: Indexação, Recuperação e Geração. Compreender cada fase é fundamental para construir aplicações RAG eficazes.

As Três Fases​


Fase 1: Indexação (Offline)​

A fase de indexação prepara seus documentos para uma recuperação eficiente. Isso ocorre antes de qualquer consulta do usuário.

Passo 1: Carregamento de Documentos​

Carregue documentos de várias fontes:

from langchain.document_loaders import (
PyPDFLoader,
TextLoader,
CSVLoader,
WebBaseLoader
)

# Load a PDF
pdf_loader = PyPDFLoader("company_handbook.pdf")
pdf_docs = pdf_loader.load()

# Load from web
web_loader = WebBaseLoader("https://example.com/docs")
web_docs = web_loader.load()

# Combine all documents
all_docs = pdf_docs + web_docs

Passo 2: Divisão de Texto (Chunking)​

Os documentos são divididos em partes menores para melhor recuperação:

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, # Characters per chunk
chunk_overlap=200, # Overlap between chunks
separators=["\n\n", "\n", ".", " "]
)

chunks = splitter.split_documents(all_docs)
# Result: List of smaller text chunks

Por que dividir em chunks?

  • Unidades menores de texto = recuperação mais precisa
  • Evita recuperar conteúdo irrelevante
  • Se encaixa nas janelas de contexto do LLM

Passo 3: Geração de Embeddings​

Converta os chunks de texto em vetores numéricos:

from langchain.embeddings import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

# Each chunk becomes a vector
# "The return policy states..." → [0.023, -0.891, 0.156, ...]

O que são embeddings?

  • Representações vetoriais densas de texto
  • Capturam o significado semântico
  • Textos semelhantes têm vetores semelhantes
  • Tipicamente de 384 a 3072 dimensões

Passo 4: Armazenamento Vetorial​

Armazene os vetores em um banco de dados especializado:

from langchain.vectorstores import Chroma

# Create vector store
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)

# Now we have an indexed, searchable knowledge base

Resumo do Pipeline de Indexação​

Raw Documents
↓ (Load)
Document Objects
↓ (Split)
Text Chunks
↓ (Embed)
Vectors
↓ (Store)
Vector Database ✓

Fase 2: Recuperação (Online)​

Quando um usuário faz uma pergunta, recuperamos os chunks relevantes da nossa base de conhecimento indexada.

Passo 1: Embedding da Consulta​

A consulta do usuário é convertida para o mesmo espaço vetorial:

user_query = "What is the return policy?"

# Convert to embedding using same model
query_vector = embeddings.embed_query(user_query)
# Result: [0.034, -0.782, 0.234, ...]

Passo 2: Busca por Similaridade​

Encontre os chunks com vetores semelhantes à consulta:

# Search for top 5 most similar chunks
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 5}
)

relevant_chunks = retriever.get_relevant_documents(user_query)

Como funciona a similaridade:

Query Vector: [0.034, -0.782, 0.234, ...]

Chunk 1: [0.038, -0.791, 0.228, ...] → 0.98 similarity ✓
Chunk 2: [0.890, 0.123, -0.456, ...] → 0.23 similarity ✗
Chunk 3: [0.041, -0.768, 0.241, ...] → 0.95 similarity ✓

Estratégias de Recuperação​

EstratégiaDescriçãoCaso de Uso
SimilaritySimilaridade vetorial puraUso geral
MMRMaximum Marginal Relevance (diversidade)Evitar redundância
HybridCombina palavra-chave + semânticaMelhor recall
# MMR - equilibra relevância e diversidade
retriever_mmr = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={
"k": 5,
"fetch_k": 20,
"lambda_mult": 0.7
}
)

Fase 3: Geração (Online)​

Combine a consulta do usuário com o contexto recuperado para gerar uma resposta.

Passo 1: Construção do Prompt​

Monte um prompt que inclua o contexto:

def build_prompt(query, retrieved_chunks):
context = "\n\n".join([
chunk.page_content for chunk in retrieved_chunks
])

prompt = f"""You are a helpful assistant. Use the following context
to answer the question. If you don't know the answer based on the
context, say "I don't have enough information."

Context:
{context}

Question: {query}

Answer:"""

return prompt

Passo 2: Geração com LLM​

Envie o prompt para o LLM:

from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(model="gpt-4", temperature=0)

prompt = build_prompt(user_query, relevant_chunks)
response = llm.invoke(prompt)

print(response.content)

Passo 3: Entrega da Resposta​

A resposta final é fundamentada nos documentos recuperados:

User: "What is the return policy?"

Retrieved Context:
"Our return policy allows returns within 30 days of purchase.
Items must be unused and in original packaging. Refunds are
processed within 5-7 business days."

Generated Response:
"According to the company policy, you can return items within
30 days of purchase, provided they are unused and in their
original packaging. Refunds typically take 5-7 business days
to process."

Código Completo do Pipeline RAG​

from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA

# Phase 1: Indexing
loader = PyPDFLoader("documents/handbook.pdf")
documents = loader.load()

splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
chunks = splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(chunks, embeddings)

# Phase 2 & 3: Retrieval + Generation
llm = ChatOpenAI(model="gpt-4")

qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever()
)

# Query the system
response = qa_chain.invoke("What is the return policy?")
print(response["result"])

Diagrama da Arquitetura​


Principais Métricas​

FaseMétricaMeta
IndexaçãoVazão100+ docs/min
IndexaçãoTamanho do chunk500-1500 caracteres
RecuperaçãoLatência<100ms
RecuperaçãoTop-K3-10 chunks
GeraçãoLatência<3s
GeraçãoContext fit<75% do limite

Resumo​

FaseQuandoO quêSaída
IndexaçãoOffline (uma vez)Processar e armazenar documentosBanco de dados vetorial
RecuperaçãoOnline (por consulta)Encontrar chunks relevantesDocumentos de contexto
GeraçãoOnline (por consulta)Criar respostaResposta final

Principais Pontos​

  1. Três fases distintas com tempos e propósitos diferentes
  2. Indexação é offline – feita uma vez ou periodicamente
  3. Recuperação + Geração são online – acontecem por consulta
  4. O tamanho do chunk importa – afeta tanto a qualidade da recuperação quanto o custo
  5. O pipeline é modular – cada componente pode ser otimizado separadamente

Próximos Passos​

Teste seu conhecimento com o Quiz do Módulo 1!