Projetos
IA Generativa · RAG · Desenvolvimento

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.

Nível Intermediário Stack Python · Streamlit · ChromaDB · LangChain Tipo Projeto técnico
Visão geral

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.

Passo a passo

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.

Resultado

O caminho da pergunta

O que dá pra levar daqui

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.