Ia
RAG - Retrieval-Augmented Generation
RAG e uma tecnica que combina busca de informacoes com geracao de texto, permitindo que LLMs respondam com base em dados atualizados e especificos.
Por que usar RAG?
LLMs tem limitacoes:
| Limitacao | Como RAG resolve |
|---|---|
| Conhecimento desatualizado | Busca em dados atuais |
| Alucinacoes | Ancora respostas em fatos |
| Dados privados | Acessa bases proprietarias |
| Contexto limitado | Recupera apenas o relevante |
Arquitetura RAG
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Pergunta │────▶│ Retriever │────▶│ Documentos │
└─────────────┘ └──────────────┘ │ Relevantes │
└──────┬──────┘
│
┌──────────────┐ │
│ LLM │◀───────────┘
│ + Contexto │
└──────┬───────┘
│
┌──────▼──────┐
│ Resposta │
└─────────────┘Etapas
- Indexacao: Documentos sao processados e armazenados
- Retrieval: Busca documentos relevantes para a pergunta
- Generation: LLM gera resposta usando os documentos
Implementacao Basica
1. Preparar Documentos
from langchain_community.document_loaders import (
PyPDFLoader,
TextLoader,
DirectoryLoader
)
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Carregar documentos
loader = DirectoryLoader("./docs", glob="**/*.pdf", loader_cls=PyPDFLoader)
documents = loader.load()
# Dividir em chunks
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
separators=["\n\n", "\n", ".", " "]
)
chunks = splitter.split_documents(documents)2. Criar Embeddings e Indexar
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)3. Criar Chain de RAG
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 4}
)
template = """Responda a pergunta baseado apenas no contexto fornecido.
Se a informacao nao estiver no contexto, diga que nao sabe.
Contexto:
{context}
Pergunta: {question}
Resposta:"""
prompt = ChatPromptTemplate.from_template(template)
model = ChatOpenAI(model="gpt-4o")
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)
# Usar
resposta = chain.invoke("Qual e a politica de reembolso?")Bancos Vetoriais
Opcoes Populares
| Banco | Tipo | Caracteristica |
|---|---|---|
| Chroma | Local/Cloud | Simples, bom para desenvolvimento |
| Pinecone | Cloud | Escalavel, gerenciado |
| Weaviate | Self-hosted/Cloud | GraphQL, hibrido |
| Qdrant | Self-hosted/Cloud | Alto desempenho, Rust |
| Milvus | Self-hosted | Escalabilidade massiva |
| pgvector | PostgreSQL | Integrado ao Postgres |
Exemplo com Pinecone
from langchain_pinecone import PineconeVectorStore
from pinecone import Pinecone
pc = Pinecone(api_key="sua-chave")
vectorstore = PineconeVectorStore.from_documents(
documents=chunks,
embedding=embeddings,
index_name="meu-indice"
)Exemplo com pgvector
from langchain_community.vectorstores import PGVector
CONNECTION_STRING = "postgresql://user:pass@localhost:5432/db"
vectorstore = PGVector.from_documents(
documents=chunks,
embedding=embeddings,
connection_string=CONNECTION_STRING,
collection_name="documentos"
)Estrategias de Retrieval
Similarity Search
Busca por similaridade semantica (padrao):
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 5}
)MMR (Maximal Marginal Relevance)
Equilibra relevancia com diversidade:
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={"k": 5, "fetch_k": 20}
)Busca Hibrida
Combina busca semantica com keyword:
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 5
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.4, 0.6]
)Self-Query
Filtra baseado em metadados:
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
metadata_field_info = [
AttributeInfo(
name="autor",
description="O autor do documento",
type="string"
),
AttributeInfo(
name="ano",
description="Ano de publicacao",
type="integer"
)
]
retriever = SelfQueryRetriever.from_llm(
llm=model,
vectorstore=vectorstore,
document_contents="Documentos tecnicos",
metadata_field_info=metadata_field_info
)Tecnicas Avancadas
Re-Ranking
Reordena resultados com modelo especializado:
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CohereRerank
compressor = CohereRerank(model="rerank-english-v3.0")
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=retriever
)Parent Document Retriever
Retorna documentos maiores apos buscar em chunks:
from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
store = InMemoryStore()
retriever = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=store,
child_splitter=child_splitter,
parent_splitter=parent_splitter
)Multi-Query Retriever
Gera variantes da pergunta para melhor cobertura:
from langchain.retrievers.multi_query import MultiQueryRetriever
retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(),
llm=model
)Avaliacao de RAG
Metricas
| Metrica | O que mede |
|---|---|
| Faithfulness | Resposta e fiel aos documentos? |
| Relevance | Documentos recuperados sao relevantes? |
| Answer Quality | Resposta atende a pergunta? |
| Context Precision | Proporcao de contexto util |
Usando Ragas
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision
result = evaluate(
dataset=dataset,
metrics=[faithfulness, answer_relevancy, context_precision]
)Boas Praticas
- Chunk Size: Experimente diferentes tamanhos (500-1500 tokens)
- Overlap: Use 10-20% de sobreposicao entre chunks
- Metadados: Inclua informacoes uteis (data, autor, tipo)
- Prompt Engineering: Instrua o modelo a dizer "nao sei"
- Monitoramento: Acompanhe qualidade das respostas
- Cache: Cache embeddings e queries frequentes