RAG com Embeddings
RAG (Retrieval-Augmented Generation) permite que o modelo responda perguntas sobre seus proprios documentos — contratos, manuais, FAQs, bases de conhecimento — sem fine-tuning. O fluxo: carregar documentos, dividir em chunks, vetorizar, buscar os trechos relevantes, e gerar a resposta com contexto.
Pre-requisitos
bash
pip install openai numpyUsamos o SDK OpenAI oficial + NumPy para similaridade vetorial. Em producao, troque o vetor store in-memory por FAISS, Pinecone, Qdrant ou pgvector.
1. Carregar e dividir documentos
python
def chunk_text(text: str, max_chars: int = 500, overlap: int = 50) -> list[str]:
chunks = []
start = 0
while start < len(text):
end = start + max_chars
chunks.append(text[start:end])
start = end - overlap
return chunks
with open("manual.txt", "r", encoding="utf-8") as f:
texto = f.read()
chunks = chunk_text(texto)
print(f"{len(chunks)} chunks criados")2. Vetorizar com embeddings do Tokia
python
from openai import OpenAI
client = OpenAI(
base_url="https://api.usetokia.com/v1",
api_key="sk-...",
)
def embed(texts: list[str]) -> list[list[float]]:
response = client.embeddings.create(
model="text-embedding-3-small",
input=texts,
)
return [item.embedding for item in response.data]
vectors = embed(chunks)3. Buscar chunks relevantes
python
import numpy as np
def cosine_similarity(a: list[float], b: list[float]) -> float:
a_arr, b_arr = np.array(a), np.array(b)
return float(np.dot(a_arr, b_arr) / (np.linalg.norm(a_arr) * np.linalg.norm(b_arr)))
def search(query: str, top_k: int = 3) -> list[str]:
query_vec = embed([query])[0]
scores = [(i, cosine_similarity(query_vec, v)) for i, v in enumerate(vectors)]
scores.sort(key=lambda x: x[1], reverse=True)
return [chunks[i] for i, _ in scores[:top_k]]
relevantes = search("Qual o prazo de garantia?")4. Gerar resposta com contexto
python
def ask(question: str) -> str:
context_chunks = search(question)
context = "\n---\n".join(context_chunks)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": (
"Responda APENAS com base no contexto fornecido. "
"Se a resposta nao estiver no contexto, diga que nao encontrou.\n\n"
f"Contexto:\n{context}"
),
},
{"role": "user", "content": question},
],
)
return response.choices[0].message.content or ""
print(ask("Qual o prazo de garantia do produto?"))Adaptacoes para producao
- Vetor store persistente: substitua a lista in-memory por FAISS, Qdrant, Pinecone ou pgvector. Evita re-vetorizar a cada restart.
- Chunking inteligente: divida por paragrafos ou secoes do documento, nao por tamanho fixo. Mantenha overlap de 10-20%.
- Modelo de embeddings:
text-embedding-3-smalle o melhor custo-beneficio. Para maior precisao, usetext-embedding-3-large. - Modelo de geracao:
gpt-4o-minie suficiente para a maioria dos casos. Para documentos tecnicos complexos, useclaude-sonnet-46. - Batch de embeddings: a API aceita ate 2048 textos por chamada. Envie em lote em vez de um por um.
Com frameworks
Para uma implementacao mais robusta com menos codigo manual, use LangChain ou LlamaIndex. Ambos suportam o Tokia como backend.
Proximos passos
- API de Embeddings — referencia completa do endpoint
- Chatbot com memoria — adicionar historico de conversa ao RAG