Equipes B2B costumam pular direto para RAG quando precisam responder perguntas sobre documentos internos. Mas nem todo caso exige um pipeline de vetorização. Este tutorial mostra um caminho mínimo: primeiro testar prompt longo, depois montar RAG com chunking e reranking simples, e avaliar com 20 perguntas antes de escalar.
Cenário ilustrativo: uma empresa mantém manuais de operação, políticas de reembolso e FAQs de atendimento, totalizando cerca de 200 páginas. O time quer que um assistente responda dúvidas de colaboradores e clientes internos.
Quando um prompt longo resolve
Se o volume de documentos cabe no contexto do modelo com folga para instruções e resposta, incluir o conteúdo inteiro no prompt é a solução mais simples e com menos pontos de falha. Para bases pequenas — até algumas dezenas de milhares de tokens, como um manual de 30 páginas — não há necessidade de indexar, dividir ou recuperar trechos.
Vantagens do prompt longo:
- Zero manutenção de índice ou embeddings.
- O modelo enxerga o documento todo, o que reduz erros de contexto fragmentado.
- Latência previsível: uma única chamada.
Desvantagens:
- Custo de tokens cresce linearmente com o tamanho do documento a cada consulta.
- Pode estourar o limite de contexto se o documento crescer.
- Não permite citações por trecho de forma natural (embora o modelo possa tentar).
Código de exemplo com SDK compatível com OpenAI:
import os
from openai import OpenAI
client = OpenAI(
base_url=os.environ["BASE_URL"],
api_key=os.environ["API_KEY"],
)
with open("politica_reembolso.txt", encoding="utf-8") as f:
documento = f.read()
resposta = client.chat.completions.create(
model=os.environ.get("LLM_MODEL", "default"),
messages=[
{"role": "system", "content": "Responda com base apenas no documento fornecido."},
{"role": "user", "content": f"Documento:\n{documento}\n\nPergunta: Qual o prazo para solicitar reembolso?"},
],
)
print(resposta.choices[0].message.content)
Quando o documento é grande demais, muda com frequência ou exige controle de acesso por usuário, vale montar um RAG mínimo.
Chunking sem exagero
O objetivo do chunking é dividir o texto em trechos que caibam no contexto e preservem o sentido. Não existe tamanho mágico; para documentos internos, um intervalo de 500 a 1000 tokens por chunk costuma funcionar bem (exemplo hipotético). Mais importante que o tamanho é respeitar fronteiras naturais: parágrafos, seções, listas.
Evite cortar no meio de uma frase ou de uma tabela. Uma função simples separa por títulos Markdown:
def chunk_por_secoes(texto: str, max_chars: int = 4000) -> list[str]:
chunks = []
atual = ""
for linha in texto.splitlines():
if linha.startswith("#") and atual.strip():
chunks.append(atual)
atual = linha + "\n"
else:
atual += linha + "\n"
if len(atual) > max_chars:
chunks.append(atual)
atual = ""
if atual.strip():
chunks.append(atual)
return chunks
Adicione sobreposição de 10% a 20% entre chunks adjacentes se houver risco de perder contexto entre fronteiras. Para documentos com muitas referências cruzadas, prefira chunks maiores e menos sobreposição.
Reranking simples com embeddings e LLM
O fluxo mínimo de RAG tem duas etapas: recuperar candidatos com embeddings e rerankear com um LLM para escolher o trecho mais relevante. Isso evita depender apenas da similaridade de cosseno, que pode falhar em perguntas com vocabulário diferente do documento.
Primeiro, gere embeddings dos chunks uma única vez e guarde-os em memória ou banco vetorial simples (ex.: SQLite com extensão vetorial ou até mesmo lista em Python para protótipo).
import numpy as np
import os
def similaridade_cosseno(a, b):
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
def recuperar(pergunta: str, chunks: list[str], embeddings: list[list[float]], k: int = 10):
emb_pergunta = client.embeddings.create(
input=pergunta,
model=os.environ["EMBEDDING_MODEL"],
).data[0].embedding
scores = [similaridade_cosseno(emb_pergunta, emb) for emb in embeddings]
indices_top = np.argsort(scores)[-k:][::-1]
return [(chunks[i], scores[i]) for i in indices_top]
Depois, use o LLM para rerankear os top-k candidatos. Uma abordagem simples é pedir ao modelo que escolha o índice do trecho mais relevante para a pergunta:
def rerankear(pergunta: str, candidatos: list[tuple[str, float]]) -> int:
prompt = "Dada a pergunta e os trechos abaixo, retorne apenas o número do trecho mais relevante.\n\n"
for i, (trecho, _score) in enumerate(candidatos):
prompt += f"{i}: {trecho[:800]}\n"
prompt += f"\nPergunta: {pergunta}\nTrecho mais relevante:"
resp = client.chat.completions.create(
model=os.environ.get("LLM_MODEL", "default"),
messages=[{"role": "user", "content": prompt}],
)
try:
return int(resp.choices[0].message.content.strip())
except ValueError:
return 0 # fallback para o primeiro candidato
Se precisar de mais robustez, peça ao modelo para dar uma nota de 0 a 10 para cada trecho e escolha o de maior nota. O importante é que o reranking seja barato e não dependa de um modelo externo de cross-encoder.
Avaliação com 20 perguntas antes de escalar
Antes de investir em infraestrutura, crie um conjunto de 20 perguntas que representem o uso real. Inclua categorias variadas:
- Factuais: “Qual o prazo para cancelamento?”
- Comparativas: “Qual a diferença entre reembolso total e parcial?”
- Multi-hop: “Se um pedido foi cancelado após o envio, quem paga o frete?”
- Permissões: “Um estagiário pode aprovar descontos acima de 10%?”
- Ambíguas: “O que fazer quando o cliente não responde?”
Rode o pipeline (prompt longo ou RAG) para cada pergunta e registre resposta, trechos usados e avaliação manual. Uma planilha simples serve:
| Pergunta | Tipo | Resposta gerada | Trecho usado | Avaliação (correta/parcial/errada) |
|---|---|---|---|---|
| ... | ... | ... | ... | ... |
Defina um critério de aceite. Por exemplo: 80% de respostas corretas e nenhuma resposta errada em perguntas de permissão. Se o critério não for atingido, ajuste chunking, modelo de embedding ou prompt do reranker e rode de novo.
Esse conjunto de 20 perguntas vira seu teste de regressão. Toda mudança no pipeline deve ser validada com ele antes de ir para produção. Só depois disso vale escalar: adicionar banco vetorial gerenciado, cache, telemetria e monitoramento.
Custo não é desculpa para pular a avaliação: estime o custo por consulta multiplicando tokens de entrada e saída pelo preço unitário do modelo (sem números aqui, apenas método). Compare o custo do prompt longo versus RAG para as 20 perguntas e projete para o volume esperado. Muitas vezes o RAG só se paga em escala, mas a decisão deve ser baseada em dados, não em hype.
A TokenRecarga fornece acesso a modelos de IA para empresas brasileiras, com atendimento comercial local e faturamento em reais.
Quer entender como a sua empresa pode usar modelos de IA com atendimento e faturamento no Brasil? Fale com a gente — a equipe da TokenRecarga responde em português.