RAG Chatbot — Como foi feito (explicado fácil)
Imagina um livro de 300 páginas e a professora pedindo "explica o capítulo sobre fotossíntese". Ninguém lê o livro inteiro — você usa o sumário e vai direto na parte certa. RAG faz isso com IA: em vez do modelo "ler tudo", ele encontra os trechos certos antes de responder.
O que é isso, em uma frase?
É um chatbot que aceita um arquivo (PDF ou TXT) e responde perguntas sobre ele só usando o que está escrito ali. Nada de inventar coisa: se a resposta não tá no documento, ele diz "não achei".
A sigla RAG vem de Retrieval-Augmented Generation — "geração com recuperação". Em vez do LLM responder de cabeça (e às vezes mentir), ele primeiro busca os trechos relevantes e SÓ depois escreve a resposta usando aqueles trechos como referência.
Por que importa? Toda empresa tem manuais, contratos, políticas em PDF. Ninguém lê. RAG é a forma honesta de fazer IA responder sobre os documentos da sua empresa sem ela ficar viajando.
Como o chatbot "lê" o documento
1 · Quebrar o documento em pedaços (chunks). Um PDF de 100 páginas é grande demais pra mandar tudo pro LLM (cabe pouco). Então corto em pedaços de ~500 palavras, com sobreposição de 50 palavras entre eles (pra não perder o contexto na "emenda").
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50
)
chunks = splitter.split_text(texto_do_pdf)
2 · Transformar cada pedaço em "números" (embeddings). Aqui mora a parte que parece mágica. Um embedding é um vetor de 384 ou 768 números que representa o significado do texto. Dois pedaços que falam de coisas parecidas têm vetores parecidos — mesmo se as palavras forem diferentes.
from langchain.embeddings import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
# cada chunk vira um vetor de 384 dimensões
Pensa como uma impressão digital do significado. "Cachorro late" e "Dog barks" têm impressões parecidas. "Cachorro late" e "Pizza é boa" têm impressões totalmente diferentes.
3 · Guardar tudo no banco de vetores (ChromaDB). Banco comum guarda texto. Banco vetorial guarda vetores e sabe responder rápido: "me dá os 4 vetores mais parecidos com este aqui". É o oposto do SQL — em vez de WHERE coluna = "valor", é WHERE significado ≈ pergunta.
from langchain.vectorstores import Chroma
vectorstore = Chroma.from_texts(
texts=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
4 · A hora da pergunta — buscar os pedaços certos. Você manda uma pergunta. Eu transformo ela em vetor (mesma "impressão digital"). O ChromaDB me devolve os 4 pedaços mais parecidos com a pergunta. Esses pedaços viram o "contexto" da resposta.
pergunta = "Qual o prazo de entrega previsto no contrato?" trechos_relevantes = vectorstore.similarity_search(pergunta, k=4) # devolve os 4 chunks mais parecidos com a pergunta
5 · Pedir pra IA responder usando só esses pedaços. Monto um prompt tipo: "Olha esses 4 trechos do contrato. Responde a pergunta baseado APENAS neles. Se não souber, diga 'não consta no documento'." O LLM (Llama via Groq) escreve a resposta.
prompt = f"""
Contexto extraído do documento:
{trechos_relevantes}
Pergunta do usuário: {pergunta}
Responda usando APENAS o contexto acima.
Se a resposta não estiver no contexto, diga "não encontrei no documento".
"""
resposta = llm.invoke(prompt)
6 · Tela do usuário (Streamlit). Interface inteira em Python, sem HTML/CSS — Streamlit cuida disso. Upload de arquivo, campo de pergunta, histórico de chat, tudo em ~80 linhas de código.
O caminho da pergunta
Em uma linha: o que esse projeto ensina
Que LLM não precisa saber tudo — ele precisa de boa busca antes. RAG troca "modelo gigante caro" por "busca esperta + modelo razoável" — e o resultado fica até melhor, porque é rastreável (você sabe de onde veio cada pedaço da resposta).
Coisas técnicas que apareceram aqui: chunking com overlap, embeddings (sentence-transformers), vector store (ChromaDB), similarity search (cosine), prompt engineering com contexto injetado, Streamlit para UI rápida.