Imagine que você contrata um assistente extremamente inteligente, mas que nunca leu nenhum documento da sua empresa. Ele responde bem sobre assuntos gerais, mas quando você pergunta sobre uma portaria interna, uma lei específica ou uma ficha funcional, ele chuta. Frustrante, né?
É exatamente esse problema que o RAG — Retrieval-Augmented Generation resolve. Em vez de tentar ensinar tudo ao modelo durante o treinamento, você dá a ele acesso a uma biblioteca particular. Na hora de responder, ele busca o que precisa nessa biblioteca e responde com base no que encontrou — indicando a fonte, sem inventar.
Você tem 500 portarias municipais em PDF. Com RAG, qualquer pessoa pode perguntar: “Qual é o prazo do estágio probatório para Agente Administrativo?” — e a IA responde citando exatamente a portaria correta, sem alucinar.
O fluxo completo de um RAG
Antes de entrar no código, vale visualizar o caminho que um documento percorre até virar conhecimento pesquisável:
Bruto
do Texto
Semânticos
Vetoriais
Vetorial
com Contexto
Por que Python?
Todos os exemplos de código deste artigo estão escritos em Python. Não é uma escolha aleatória — Python se tornou a linguagem padrão do ecossistema de IA por razões práticas e concretas:
| Motivo | O que significa na prática |
|---|---|
| Bibliotecas prontas | ChromaDB, LangChain, PyMuPDF, Ollama — tudo tem suporte nativo em Python |
| Sintaxe simples | O código é legível mesmo para quem não é programador de formação |
| Padrão da indústria | OpenAI, Google, Meta e Anthropic publicam seus SDKs oficiais em Python primeiro |
| Comunidade ativa | Qualquer dúvida ou erro tem documentação, fórum ou exemplo disponível online |
Os scripts deste artigo são diretos e comentados. Com Python instalado e as bibliotecas certas, qualquer pessoa com noção básica de terminal consegue rodar um RAG funcional seguindo estes exemplos.
Quais documentos podem entrar no RAG?
Praticamente qualquer coisa que vira texto. No contexto de gestão pública ou de negócios, os mais comuns são:
| Tipo | Exemplos Reais | Biblioteca Python |
|---|---|---|
| Portarias, editais, leis, pareceres | PyMuPDF | |
| DOCX | Fichas funcionais, contratos, memorandos | python-docx |
| CSV / XLSX | Tabelas de cargos e salários | pandas |
| TXT / MD | Bases de conhecimento internas, wikis | nativo Python |
| Site / HTML | FAQ, regulamentos online | BeautifulSoup |
Dados brutos ou filtrados?
Dúvida mais comum de quem está começando: devo inserir o arquivo direto ou limpar antes? A resposta direta: nunca jogue o texto bruto direto no banco. O problema não é o volume — é o ruído.
Quando você extrai o texto de um PDF de portaria, vem muito mais do que o conteúdo útil:
| Texto Bruto (PDF) | Texto Filtrado | |
|---|---|---|
| ❌ Bruto | Fl. 23 …….. Rubrica …….. PORTARIA Nº 0042/2024 Página 23 de 180 |
— |
| ✓ Limpo | — | PORTARIA Nº 0042/2024 – SMGP Art. 1º Fica autorizado o servidor João Silva, matrícula 12345… |
Se o lixo entra, o lixo é recuperado. A IA vai citar número de página no meio de uma resposta ou confundir marcas d’água com conteúdo real.
Chunking: o passo mais crítico
Chunk é o pedaço de texto que vai para o banco vetorial. Se o chunking for mal feito, o RAG inteiro fica comprometido — mesmo com um ótimo modelo.
A busca vetorial retorna pedaços, não documentos inteiros. Se um chunk cortar um artigo de lei no meio, o contexto vai incompleto para a IA — e ela vai preencher o que falta com imaginação. O tamanho ideal fica entre 300 e 800 caracteres, com um overlap de 15 a 20% entre chunks consecutivos para garantir continuidade.
Um script ou vários? Dois — e cada um tem seu momento
O fluxo de um RAG se divide naturalmente em duas etapas com propósitos distintos. Você não precisa rodar tudo toda vez — cada script tem seu momento de uso:
Roda só quando tem documento novo. Extrai o texto, limpa, divide em chunks e insere no banco com a origem registrada. O banco persiste no disco — os dados ficam lá até você deletar.
Roda sempre que o usuário faz uma pergunta. Busca os chunks mais relevantes, monta o prompt com o contexto encontrado e chama o modelo para gerar a resposta. Não precisa reingerir nada.
📥 ingestao.py — script completo
Este script faz tudo em sequência: extrai o texto do arquivo, limpa o conteúdo removendo ruídos típicos de PDFs públicos, divide em chunks semânticos e insere no ChromaDB. O ponto central é que cada chunk entra no banco junto com a origem do documento — sem isso, a IA responde sem conseguir indicar de onde veio a informação.
🔍 consulta.py — script completo
Este script roda sempre que o usuário faz uma pergunta. Ele busca os chunks mais similares no banco, monta um prompt instruindo o modelo a responder apenas com base no que foi encontrado, e exibe a resposta junto com as fontes consultadas.
O que aparece na tela
Com o script acima, a saída para cada pergunta terá este formato:
📌 Resposta: O estágio probatório para o cargo de Agente Administrativo tem duração de 36 meses, conforme o Art. 1º da Portaria nº 0042/2024. 📂 Fontes consultadas: · Portaria nº 0042/2024 · Lei Complementar nº 68
Os erros que destroem um RAG
| Erro | Efeito | Correção |
|---|---|---|
| Chunk < 100 chars | Perde contexto, resposta fragmentada | Mínimo 300–400 chars |
| Chunk > 1500 chars | Dilui o sinal, busca imprecisa | Máximo 800–1000 chars |
| Texto bruto sem limpeza | IA recupera rodapés e lixo | Sempre pré-processar |
| Ingerir sem registrar a origem | IA responde sem indicar a fonte | Sempre salvar o nome do documento junto ao chunk |
| Prompt sem âncora | LLM alucina fora do contexto | “Responda só com os documentos” |
RAG é infraestrutura, não magia
A diferença entre um RAG que funciona e um que decepciona está quase sempre na qualidade dos dados inseridos — não no modelo. Limpe bem, chunke com critério, registre sempre a origem do documento, e você terá uma IA que responde com a precisão de quem leu cada página dos seus arquivos.
Com dois scripts simples em Python — um para ingestão, um para consulta — qualquer organização consegue transformar sua base de documentos em uma fonte de conhecimento pesquisável por IA, sem depender de nenhuma plataforma externa.