Kaique Mitsuo Silva Yamamoto
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:

LimitacaoComo RAG resolve
Conhecimento desatualizadoBusca em dados atuais
AlucinacoesAncora respostas em fatos
Dados privadosAcessa bases proprietarias
Contexto limitadoRecupera apenas o relevante

Arquitetura RAG

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│   Pergunta  │────▶│   Retriever  │────▶│  Documentos │
└─────────────┘     └──────────────┘     │  Relevantes │
                                         └──────┬──────┘

                    ┌──────────────┐            │
                    │     LLM      │◀───────────┘
                    │  + Contexto  │
                    └──────┬───────┘

                    ┌──────▼──────┐
                    │   Resposta  │
                    └─────────────┘

Etapas

  1. Indexacao: Documentos sao processados e armazenados
  2. Retrieval: Busca documentos relevantes para a pergunta
  3. 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

BancoTipoCaracteristica
ChromaLocal/CloudSimples, bom para desenvolvimento
PineconeCloudEscalavel, gerenciado
WeaviateSelf-hosted/CloudGraphQL, hibrido
QdrantSelf-hosted/CloudAlto desempenho, Rust
MilvusSelf-hostedEscalabilidade massiva
pgvectorPostgreSQLIntegrado 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

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

MetricaO que mede
FaithfulnessResposta e fiel aos documentos?
RelevanceDocumentos recuperados sao relevantes?
Answer QualityResposta atende a pergunta?
Context PrecisionProporcao 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

  1. Chunk Size: Experimente diferentes tamanhos (500-1500 tokens)
  2. Overlap: Use 10-20% de sobreposicao entre chunks
  3. Metadados: Inclua informacoes uteis (data, autor, tipo)
  4. Prompt Engineering: Instrua o modelo a dizer "nao sei"
  5. Monitoramento: Acompanhe qualidade das respostas
  6. Cache: Cache embeddings e queries frequentes

Recursos