RAG para PME em 2026: Vector Databases e Embeddings
✎ Duarte Spínola | 2026-07-18
As pequenas e médias empresas (PME) portuguesas que adoptam modelos de linguagem (LLM) como GPT-4o, Claude ou Llama 3 deparam-se rapidamente com um problema: o modelo “não sabe” nada sobre os contratos, manuais internos, tickets de suporte ou políticas de RH da organização. Alimentar tudo no prompt é caro (limite de contexto), arriscado (dados confidenciais) e frágil (alucinação). A solução madura em 2026 chama-se Retrieval-Augmented Generation (RAG) — uma arquitectura que combina um LLM com um índice de pesquisa semântica alimentado por embeddings e armazenado numa vector database. A causa técnica do problema é simples: um LLM é um modelo estático treinado numa image (Snapshot) da web até uma data de corte; não tem acesso à memória da empresa. A solução é indexar os documentos internos como vectores densos, recuperar os mais relevantes por semântica (não por palavra-chave) e inseri-los no prompt antes da geração. Este artigo cobre o que é RAG, as alternativas open-source e comerciais de embeddings e vector databases, a arquitectura típica e uma implementação prática em Python com LangChain ou LlamaIndex, validada contra documentação oficial a 18 de Julho de 2026.
⚠ ⚠️ **Atenção
** Antes de implementar RAG com dados confidenciais de clientes ou funcionários, verifique a política de processamento de dados do seu provedor LLM (OpenAI, Anthropic, Cohere). Para dados sensíveis, considere inferência local com Ollama ou Llama.cpp — ver secção 8.
1. O que Está a Acontecer — RAG, Embeddings e Vector Databases
RAG (Retrieval-Augmented Generation) é um padrão introduzido pela Facebook AI em 2020 e tornado padrão de facto em 2024-2026 que combina um modelo de geração de texto (LLM) com um sistema de recuperação de informação externo. Em vez de depender apenas do conhecimento paramétrico aprendido em treino, o LLM recebe, no prompt, excertos relevantes recuperados de uma base de conhecimento externa. Em 2026, a documentação da Pinecone descreve-o como “the process of optimizing the output of a large language model so it references an authoritative knowledge base outside of its training data sources before generating a response” (Pinecone Learn — RAG).
Embeddings são representações numéricas densas de texto (ou imagens, áudio, código) num espaço vectorial de alta dimensão — tipicamente 384, 768, 1024, 1536 ou 3072 dimensões, consoante o modelo. Textos semanticamente próximos ficam próximos nesse espaço. A recuperação semântica faz-se calculando a distância (cosseno, euclidiana ou produto interno) entre o embedding da pergunta e os embeddings dos documentos. O modelo text-embedding-3-large da OpenAI produz 3072 dimensões por token-chunk (OpenAI Platform — Embeddings Guide).
Vector databases são sistemas de armazenamento optimizados para: (1) guardar milhões de vectores de alta dimensão, (2) fazer busca aproximada de vizinhos mais próximos (ANN — Approximate Nearest Neighbors) em milissegundos, (3) filtrar por metadados (data, autor, departamento, categoria) e (4) oferecer persistência, multi-tenancy e update incremental. O pipeline típico é documentado nas referências da Qdrant (Qdrant Documentation) e da Chroma (Chroma Documentation).
A “chave” que torna o RAG útil: o retrieval semântico resolve o problema de sinonímia que a pesquisa BM25/TF-IDF clássica não resolve. “Como fecho a sessão?” e “Logout” são a mesma intenção mas não partilham tokens. Um embedding bem treinado coloca-os próximos.
2. Cenários em que o RAG é a Resposta Certa
- Chatbot de suporte técnico interno — empresa de 50 funcionários com 200 manuais e FAQs internas; o chatbot responde “como configuro VPN no Mac” citando o manual interno, não a resposta genérica da web.
- Pesquisa semântica em conhecimento não-estruturado — gabinete de contabilidade com 5 000 PDFs de legislação e pareceres; RAG permite perguntar “quais os prazos para entrega do IVA no setor da construção” e obter respostas com citações.
- Document Q&A sobre contratos e propostas — equipa comercial com 300 propostas comerciais; query “qual o desconto médio que demos ao cliente X em 2025” devolve excertos relevantes, não a busca literal.
- Helpdesk IT com base de tickets — PME com 10 000 tickets Resolvidos; RAG sugere soluções anteriores para tickets novos, reduzindo tempo de resolução (MTTR).
- Assistente de recursos humanos — empregados perguntam ao bot “quantos dias de licença me restam” e “qual a política de teletrabalho”, com resposta fundamentada no manual de RH.
- Pesquisa em notas de reuniões e actas — equipa de direcção com 500 actas em Markdown; query semântica “decisões sobre o orçamento de marketing” recupera todas as actas relevantes mesmo sem a palavra exacta.
Nota sobre maturidade: RAG em 2026 é tecnologia madura, não hype. As vector databases listadas neste artigo estão em produção em empresas desde 2022-2023. O que mudou em 2026 é o custo (embeddings OpenAI baixaram 80% desde 2022) e a simplicidade (LangChain e LlamaIndex reduzem o código de dias para horas).
3. Passo 1 — Diagnosticar se RAG é Mesmo Necessário
Antes de implementar RAG, confirme que o problema é mesmo “o LLM não sabe X” e não “o LLM é mau a raciocinar”. Para PME, três testes rápidos:
Teste A — Prompt directo: coloque no GPT-4o / Claude a pergunta de negócio com a máxima informação de contexto possível no prompt. Se a resposta for correcta, RAG não é necessário — basta um prompt melhor.
Teste B — Keyword search existente: execute a query na pesquisa actual da empresa (SharePoint Search, Elasticsearch, grep num directório). Se 90% das queries resultam em 1 clique no documento certo, RAG adiciona pouco; se 40%+ falham, RAG resolve o problema.
Teste C — Volume de documentos: se o corpus for <20 documentos curtos, copie-os todos para o prompt (janela de contexto de 128k tokens do GPT-4o comporta ~100 páginas A4). Se for >50 documentos, >50 000 palavras ou se cresce semanalmente, RAG justifica-se.
import os, tiktoken
enc = tiktoken.encoding_for_model(“gpt-4o”)
total_tokens = 0
for root, _, files in os.walk(“./documentos”):
for f in files:
if f.endswith((“.md”, “.txt”, “.pdf.txt”)):
with open(os.path.join(root, f), encoding=”utf-8″) as fh:
total_tokens += len(enc.encode(fh.read()))
print(f”Tokens totais: {total_tokens:,}”)
print(f”Cabe num prompt de 128k? {total_tokens < 128_000}”) print(f”Recomendação RAG: {‘Sim’ if total_tokens > 50_000 else ‘Talvez não’}”)
Esperado: para 200 documentos médios (5 KB cada), verá algo como Tokens totais: ~250 000 e Cabe num prompt de 128k? False — o que confirma que RAG é a abordagem correcta. O tiktoken é a biblioteca oficial da OpenAI para contagem de tokens e está validada contra o comportamento dos modelos GPT (OpenAI Cookbook no GitHub).
4. Passo 2 — Escolher o Modelo de Embeddings
Os embeddings são a espinha dorsal do RAG. Escolher mal o modelo degrada a qualidade de retrieval sem que o utilizador perceba — o chatbot “responde” mas com fontes irrelevantes. Em 2026, as três famílias viáveis para PME:
4.1 Modelo comercial — OpenAI text-embedding-3
A OpenAI lançou em 2024 os modelos text-embedding-3-small (1536 dimensões) e text-embedding-3-large (3072 dimensões), que em 2026 continuam a ser a referência comercial por relação custo/qualidade. Documentação: OpenAI Platform — Embeddings Guide.
from openai import OpenAI
client = OpenAI() # lê OPENAI_API_KEY do ambiente
resp = client.embeddings.create(
model=”text-embedding-3-small”,
input=”Como fecho a sessão no portal da empresa?”,
)
print(len(resp.data[0].embedding)) # 1536
Custo em 2026: $0.02 por 1M tokens (small) e $0.13 por 1M tokens (large), confirmado na documentação de modelos da OpenAI. Para 10 000 documentos de 1000 tokens cada, o índice inicial custa ~$0.20 (small) ou ~$1.30 (large).
4.2 Modelo open-source — sentence-transformers / BGE / E5
Para PME que querem inferência local, dados confidenciais ou sem dependência de API externa, a família sentence-transformers é o padrão open-source. O modelo BAAI/bge-m3 (multilingue, 1024 dimensões) e intfloat/multilingual-e5-large são os mais recomendados em 2026 no MTEB Leaderboard da Hugging Face (Hugging Face — MTEB, Sentence-Transformers).
from sentence_transformers import SentenceTransformer
model = SentenceTransformer(“BAAI/bge-m3”) # 1024 dims, multilingue
vectors = model.encode([“Como fecho a sessão?”, “Logout”, “Encerrar conta”])
print(vectors.shape) # (3, 1024)
4.3 Modelo local via Ollama — nomic-embed-text, mxbai, bge
O Ollama permite correr modelos de embedding localmente sem GPU dedicada, ideal para PME com restrições de privacidade. O modelo nomic-embed-text (768 dims, 1.3 GB) é o ponto de entrada típico. Configuração e integração com RAG local é detalhada em artigos kbase.pt sobre o stack Ollama + Open WebUI (artigo relacionado: Ollama + Open WebUI stack avançado 2026).
ollama pull nomic-embed-text
# Inferência local via curl (sem cloud)
curl http://localhost:11434/api/embeddings -d ‘{
“model”: “nomic-embed-text”,
“prompt”: “Como fecho a sessão?”
}’
4.4 Quadro comparativo de modelos em 2026
| Modelo | Dimensões | Custo (por 1M tokens) | Local? | Idioma | Melhor para |
|---|---|---|---|---|---|
| OpenAI text-embedding-3-small | 1536 | $0.02 | Não | EN + multilingue | PME com orçamento API e volume médio |
| OpenAI text-embedding-3-large | 3072 | $0.13 | Não | EN + multilingue | Qualidade máxima, retrieval preciso |
| BAAI/bge-m3 (open-source) | 1024 | Grátis (self-host) | Sim | 100+ idiomas, PT forte | PME com dados sensíveis, on-prem |
| intfloat/multilingual-e5-large | 1024 | Grátis (self-host) | Sim | 100+ idiomas | Multilingue em produção |
| nomic-embed-text (via Ollama) | 768 | Grátis (self-host) | Sim | EN + multilingue | Local sem GPU, protótipo rápido |
| Cohere embed-v4 | 1536 | $0.10 | Não | 100+ idiomas | PME que prefere alternativa à OpenAI |
A escolha prática em 2026: se pode cloud, OpenAI text-embedding-3-small para começar; se tem dados sensíveis, BAAI/bge-m3 via sentence-transformers ou Ollama. Evite text-embedding-ada-002 (legacy, 1536 dims, superseded pelo 3-small em qualidade e custo).
5. Passo 3 — Escolher a Vector Database
Em 2026 existem cinco vector databases mainstream para PME. A escolha determina custos operacionais, complexidade de DevOps e capacidade de escala.
5.1 Pinecone — managed serverless (commercial)
Pinecone é a oferta managed serverless mais madura, sem infraestrutura para gerir. Ideal para PME que preferem pagar para não operar. A documentação oficial descreve a arquitectura serverless com storage em camadas e cálculo on-demand (Pinecone Learn, Pinecone Pricing).
from pinecone import Pinecone
pc = Pinecone() # lê PINECONE_API_KEY
idx = pc.Index(“kbase-rag”)
idx.upsert(vectors=[
{“id”: “doc-1”, “values”: emb, “metadata”: {“fonte”: “manual-vpn.pdf”}}
])
res = idx.query(vector=pergunta_emb, top_k=5, filter={“fonte”: {“$eq”: “manual-vpn.pdf”}})
5.2 Qdrant — open-source, production-grade
Qdrant é escrito em Rust, open-source (Apache 2.0) e oferece uma versão managed cloud e self-hosted. A documentação oficial cobre payloads, filtros e quantização (Qdrant Documentation, Qdrant Pricing). É a escolha preferida em 2026 para PME que querem self-host com performance alta e baixo consumo de memória.
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams
client = QdrantClient(host=”localhost”, port=6333) # self-host via Docker
client.recreate_collection(
collection_name=”kbase”,
vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
)
client.upsert(collection_name=”kbase”, points=[
{“id”: 1, “vector”: emb, “payload”: {“fonte”: “manual-vpn.pdf”}}
])
5.3 Chroma — lightweight, dev-friendly
Chroma é a opção mais simples para começar — corre em processo (embedded), sem servidor separado, ideal para protótipos e PME com <100k documentos. Documentação: Chroma Documentation. Em 2026 o Chroma evoluiu para uma arquitectura client-server, mas mantém o modo embedded.
import chromadb
client = chromadb.PersistentClient(path=”./vector_db”) # persistência local
col = client.get_or_create_collection(“kbase”)
col.add(
ids=[“doc-1”],
embeddings=[emb],
documents=[“Manual VPN: para fechar a sessão, clique em Logout.”],
metadatas=[{“fonte”: “manual-vpn.pdf”}],
)
res = col.query(query_embeddings=[pergunta_emb], n_results=5)
5.4 Weaviate — schema-first, GraphQL
Weaviate é open-source (BSD-3) e distingue-se por ser “schema-first” e oferecer uma API GraphQL nativa. A documentação oficial descreve módulos para multimodal e hybrid search (Weaviate Developer Docs, Weaviate Pricing). Recomendado quando se quer combines keyword + vector search (hybrid) out-of-the-box.
5.5 pgvector — extensão PostgreSQL
Para PME que já usam PostgreSQL, pgvector é a via mais económica: adicionar a extensão a uma base de dados existente em vez de instalar uma vector database nova. O repositório oficial está em pgvector no GitHub. Em 2026, suporta índices HNSW e IVFFlat em 1536+ dimensões, com bom desempenho até ~1M vectores por instância.
CREATE EXTENSION vector;
— Criar tabela
CREATE TABLE documentos (
id SERIAL PRIMARY KEY,
conteudo TEXT,
embedding VECTOR(1536),
fonte TEXT
);
— Índice HNSW para busca rápida
CREATE INDEX ON documentos USING hnsw (embedding vector_cosine_ops);
— Query de similaridade
SELECT conteudo, fonte, embedding <=> $1::vector AS distancia
FROM documentos
ORDER BY embedding <=> $1::vector
LIMIT 5;
5.6 Quadro comparativo — Vector Databases para PME em 2026
| Vector DB | Open-source? | Managed? | Self-host fácil? | Escalabilidade | Custo inicial PME | Melhor para |
|---|---|---|---|---|---|---|
| Pinecone | Não | Sim (serverless) | N/A | Auto | Free tier 100k vectores | Quem não quer DevOps |
| Qdrant | Sim (Apache 2.0) | Sim | Sim (Docker) | Milhões | Grátis self-host | PME on-prem, performance |
| Chroma | Sim (Apache 2.0) | Em desenvolvimento | Sim (embedded) | ~1M docs | Grátis | Protótipos, <100k docs |
| Weaviate | Sim (BSD-3) | Sim | Sim (Docker) | Milhões | Grátis self-host | Hybrid search, multimodal |
| pgvector | Sim (PostgreSQL) | Via provedores PG | Sim (extensão) | ~1M vectores | Grátis se já tem PG | PME com PostgreSQL existente |
Recomendação 2026 para PME portuguesas: começar com Chroma para protótipo (zero DevOps), migrar para Qdrant ou pgvector em produção. Escolher Pinecone apenas se a equipa não tem competências de infraestrutura. A documentação oficial da Qdrant documenta bem a transição Chroma→Qdrant (Qdrant Quick Start).
6. Passo 4 — Arquitectura Típica de um Pipeline RAG
A arquitectura canónica documentada em 2026 pela Pinecone, LangChain e LlamaIndex segue seis fases. Esta secção descreve-as conceptualmente; a implementação em código está na secção 7.
↓
LLM ← [6] Geração ← [5] Retrieval ← Query (embedding)
6.1 Ingestão de documentos
Carregar PDFs, Word, Markdown, HTML, e-mails, tickets, páginas web. Em 2026, LangChain oferece loaders para >80 fontes (LangChain Data Connection) e LlamaIndex inclui centenas de conectores (LlamaIndex Docs). Para PDFs com layout complexo, considere unstructured, marker-pdf ou pymupdf — a extração correcta é responsável por 40-60% da qualidade final do RAG.
6.2 Chunking — segmentação em passagens
Não se pode embedding de um PDF de 50 páginas inteiro: perde-se granularidade. Dividir em chunks de 500-1500 tokens com overlap de 50-200 tokens é o padrão. Estratégias:
- RecursiveCharacterTextSplitter (LangChain) — divide por parágrafo, depois frase, depois palavra. É o padrão de facto.
- Semantic chunker — divide quando a semântica muda (via embeddings). Mais caro mas superior em documentos densos.
- Markdown/HTML structural splitter — preserva headers como metadados. Recomendado para documentação técnica.
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200,
separators=[“\n## “, “\n### “, “\n\n”, “\n”, “. “, ” “],
)
chunks = splitter.split_text(documento_markdown)
6.3 Embedding
Cada chunk é convertido num vector pelo modelo escolhido (secção 4). Para PT-PT, modelos multilingues (bge-m3, multilingual-e5, OpenAI 3-small) têm desempenho equivalente ao inglês em benchmarks MTEB (Hugging Face MTEB).
6.4 Storage
Os vectores + metadados + texto são inseridos na vector database escolhida (secção 5). Em produção, armazenar também: fonte, data_criacao, autor, categoria, pagina, hash_chunk — estes metadados habilitam filtros (ex: “só manuais de 2025”) e auditoria.
6.5 Retrieval — recuperação por similaridade
Quando o utilizador faz uma pergunta: (1) gera o embedding da pergunta, (2) procura na vector database os K vectores mais próximos (K=3 a 10), (3) retorna os chunks correspondentes com metadados. Técnicas avançadas em 2026: hybrid search (combina vector + BM25), re-ranking com um modelo cross-encoder (bge-reranker-v2-m3) para reordenar os top-K, e query expansion (LLM reformula a pergunta em 3 variantes).
6.6 Geração — prompt + LLM
Os K chunks recuperados são inseridos no prompt como contexto. O prompt típico: “Responde à pergunta usando apenas o contexto abaixo. Cita a fonte. Se não souberes, diz que não encontraste.”
[chunk 1 — fonte: manual-vpn.pdf, p.12]
[chunk 2 — fonte: faq-it.docx]Pergunta: Como fecho a sessão no portal?
Resposta: Para fechar a sessão no portal da empresa, clica no botão “Logout” no canto superior direito (fonte: manual-vpn.pdf, p.12). Se a opção não aparecer, limpa as cookies do navegador (fonte: faq-it.docx).
O LLM gera a resposta com citações — mais fiável que geração livre e auditável.
7. Passo 5 — Implementação Prática com LangChain
A implementação mais rápida em 2026 usa LangChain, que abstrai ingestion, chunking, embedding, storage e retrieval numa API de alto nível. Documentação oficial: LangChain RAG Tutorial.
7.1 Instalação
langchain-chroma chromadb sentence-transformers tiktoken
7.2 Pipeline mínimo com Chroma + OpenAI
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_chroma import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
import os# 1. Ingestão — carregar todos os .md de ./documentos
loader = DirectoryLoader(“./documentos”, glob=”**/*.md”, loader_cls=TextLoader)
docs = loader.load()
# 2. Chunking
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = splitter.split_documents(docs)
# 3+4. Embedding + Storage (Chroma em modo persistente)
embeddings = OpenAIEmbeddings(model=”text-embedding-3-small”)
vectorstore = Chroma.from_documents(
chunks, embeddings, persist_directory=”./vector_db”
)
retriever = vectorstore.as_retriever(search_kwargs={“k”: 5})
# 5+6. Retrieval + Geração
llm = ChatOpenAI(model=”gpt-4o-mini”, temperature=0)
template = “””Responde à pergunta em PT-PT usando apenas o contexto abaixo.
Cita a fonte entre parêntesis. Se não souberes, diz “Não encontrado no conhecimento base”.
Contexto:
{context}
Pergunta: {question}
“””
prompt = ChatPromptTemplate.from_template(template)
rag_chain = (
{“context”: retriever, “question”: RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# Query
resposta = rag_chain.invoke(“Como fecho a sessão no portal?”)
print(resposta)
Esperado: resposta em PT-PT com citação (fonte: manual-vpn.md, p.12). Se a pergunta não estiver coberta, o modelo devolve “Não encontrado no conhecimento base” em vez de alucinar — o comportamento pretendido.
Testado em: 2026-07-18 — sintaxe verificada contra python.langchain.com/docs/tutorials/rag e docs.trychroma.com. Versões de referência: langchain 0.3.x, langchain-chroma 0.1.x, langchain-openai 0.2.x.
7.3 Variante com LlamaIndex
LlamaIndex é a alternativa a LangChain, com focus em indexing sofisticado e retrieval avançado. Documentação: LlamaIndex Docs.
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAISettings.embed_model = OpenAIEmbedding(model=”text-embedding-3-small”)
Settings.llm = OpenAI(model=”gpt-4o-mini”, temperature=0)
docs = SimpleDirectoryReader(“./documentos”).load_data()
index = VectorStoreIndex.from_documents(docs)
query_engine = index.as_query_engine(similarity_top_k=5)
print(query_engine.query(“Como fecho a sessão no portal?”))
7.4 Variante 100% open-source (sem cloud, para dados sensíveis)
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_chroma import Chroma
from langchain_ollama import ChatOllama
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser# Modelo de embedding local (bge-m3 multilingue, 1024 dims)
embeddings = HuggingFaceEmbeddings(model_name=”BAAI/bge-m3″)
# LLM local via Ollama (llama3.1 ou qwen2.5)
llm = ChatOllama(model=”llama3.1″, temperature=0)
loader = DirectoryLoader(“./documentos”, glob=”**/*.md”, loader_cls=TextLoader)
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = splitter.split_documents(docs)
vectorstore = Chroma.from_documents(chunks, embeddings, persist_directory=”./vector_db”)
retriever = vectorstore.as_retriever(search_kwargs={“k”: 5})
template = “””Responde em PT-PT usando só o contexto. Cita a fonte.
Contexto: {context}
Pergunta: {question}”””
prompt = ChatPromptTemplate.from_template(template)
rag_chain = (
{“context”: retriever, “question”: RunnablePassthrough()}
| prompt | llm | StrOutputParser()
)
print(rag_chain.invoke(“Como fecho a sessão no portal?”))
Vantagem: todos os dados e inferência ficam na rede interna — zero envio para cloud. Trade-off: a qualidade do Llama 3.1 8B local é inferior ao GPT-4o; para tarefas exigentes, use Llama 3.1 70B via Ollama num servidor com 48 GB de RAM ou modelo via provedor de inferência open-source (artigo relacionado: Hermes AI Agent + Ollama instalação).
8. Passo 6 — Custos e Orçamento para PME
Em 2026, RAG deixou de ser caro. Os custos deprimem-se em três eixos: embeddings, vector DB e LLM.
8.1 Embeddings
| Cenário PME | Volume | Custo OpenAI 3-small | Custo bge-m3 self-host |
|---|---|---|---|
| 100 documentos curtos (prova de conceito) | 100k tokens | $0.002 | $0 (apenas CPU) |
| 1 000 documentos (catálogo de manuais) | 1M tokens | $0.02 | $0 |
| 10 000 documentos (base completa) | 10M tokens | $0.20 | $0 |
| 100 000 documentos (escala) | 100M tokens | $2.00 | $0 |
| Re-indexação mensal incremental | 1M tokens/mês | $0.02/mês | $0 |
A indexação é amortizada: paga-se uma vez, re-paga-se só no delta de novos documentos. Embeddings de queries (pergunta do utilizador) são 100-300 tokens cada — custo negligenciável mesmo em alto tráfego.
8.2 Vector Database
| Vector DB | Custo PME (100k vectores) | Custo produção (1M vectores) |
|---|---|---|
| Chroma self-host | Grátis (disco local) | Grátis |
| Qdrant self-host (Docker) | Grátis | Grátis |
| pgvector (PostgreSQL existente) | Grátis (extensão) | Grátis |
| Pinecone serverless | Free tier até 100k | ~$70/mês (Starter) |
| Qdrant Cloud | Free tier 1GB | ~$40/mês (Cluster S1) |
| Weaviate Cloud | Free tier 10M dims | ~$25/mês (Standard) |
Para 95% das PME portuguesas com <100k documentos, Chroma ou pgvector self-host são zero custo.
8.3 LLM (geração)
| Provedor | Modelo | Custo por 1M tokens (input) | Custo por 1M tokens (output) |
|---|---|---|---|
| OpenAI | GPT-4o-mini | $0.15 | $0.60 |
| OpenAI | GPT-4o | $2.50 | $10.00 |
| Anthropic | Claude 3.5 Haiku | $0.80 | $4.00 |
| Anthropic | Claude 3.5 Sonnet | $3.00 | $15.00 |
| Gemini 1.5 Flash | $0.075 | $0.30 | |
| Gemini 1.5 Pro | $1.25 | $5.00 | |
| Ollama local | Llama 3.1 8B | $0 | $0 |
| Ollama local | Llama 3.1 70B | $0 (hardware ~$2k) | $0 |
| Groq hosted | Llama 3.1 8B | $0.05 | $0.08 |
Cenário PME típico (chatbot interno, 100 queries/dia, 500 tokens de contexto cada): ~50k tokens input + 5k output por dia = ~$0.01/dia com GPT-4o-mini ou $0 com Ollama. Para 30 dias = $0.30/mês. RAG é, em 2026, acessível a qualquer PME.
9. Outras Causas e Armadilhas Comuns em RAG
O RAG “funciona” mas pode dar respostas erradas sem que o utilizador perceba. Lista das armadilhas mais frequentes e onde se resolvem:
- Chunk size mal calibrado — chunks demasiado pequenos perdem contexto semântico; demasiado grandes diluem a relevância. Solução: começar com 1000 tokens + 200 overlap, testar com 20 queries reais e ajustar. Erro típico descrito em Pinecone Learn — chunking.
- Embedding com modelos diferentes para query e indexação — vector DB fica incompatível. Cada mudança de modelo obriga a re-indexar. Manter o modelo numa constante no código.
- Sem re-ranking — top-K por cosine pode ter falsos positivos. Em 2026, adicionar um cross-encoder
bge-reranker-v2-m3aumenta precisão em 15-30%. - Sem metadados filtráveis — não conseguir limitar retrieval a “documentos de 2025” ou “categoria: RH”. Metadados são grátis e cruciais.
- Falta de gestão de versões do índice — quando se actualiza um manual, o chunk antigo permanece na vector DB. Solução: hash por chunk, fazer upsert (substituir) não insert.
- Alucinação apesar de RAG — prompt mal construído (“Responde à pergunta”) permite ao LLM ignorar o contexto. Prompt correcto: “Se a resposta não estiver no contexto, diz que não encontraste.”
- Dados confidenciais em APIs comerciais — OpenAI, Anthropic, Cohere têm políticas de retenção. Para PII, financeiro, jurídico, usar Llama 3.1 local via Ollama ou provedores com DPA (Data Processing Agreement).
- PDFs mal extraídos — PDFs com colunas, tabelas, scans produzidos por OCR mau degradam retrieval. Validar a extração manualmente nos primeiros 20 documentos.
- Monolingual embedding em corpus PT — modelos só em inglês (ex: original OpenAI ada) perdem nuances em PT. Usar multilingue: bge-m3, multilingual-e5, ou OpenAI 3-small (multilingue).
⚠ ⚠️ **Atenção
Nunca implemente RAG em produção sem um conjunto de testes de avaliação** com 30-50 queries reais e as respostas esperadas (golden set). Sem avaliação, não há forma de detectar regressões ao alterar modelo, chunk size ou prompt.
10. Como Evitar Problemas em Implementações Futuras
- Definir um golden set antes de começar — 30-50 perguntas reais com a resposta esperada. Serve de teste de regressão a cada alteração.
- Versionar o pipeline — guardar versão do modelo de embedding, chunk size, prompt e vector DB em metadata. Permite reproduzir resultados e rollback.
- Fazer retrieval evaluation, não só end-to-end — medir recall@5 e precision@5 dos chunks recuperados, não só a qualidade da resposta final. A causa de respostas más é frequentemente retrieval falhado, não o LLM.
- Monitorizar drift — logs de queries + chunks recuperados + satisfação do utilizador (thumbs up/down). Quando a satisfação cai, investigar retrieval primeiro.
- Planeamento de re-indexação — agenda mensal ou trigger on-update para re-embeddings de novos documentos. Sem isto, o índice fica desactualizado.
- Backup do índice — vector DB é dados. Replicar como qualquer base de dados (snapshot Qdrant, dump Chroma, pg_dump para pgvector).
- Começar pequeno, depois escalar — Chroma + 50 documentos + GPT-4o-mini para prova de conceito em 1 dia. Migrar para Qdrant/pgvector em produção só quando o padrão estiver validado.
- Documentar o “porquê” — porque se escolheu bge-m3 em vez de OpenAI, porque chunk de 800 e não 1500. RAG é 70% de decisões de engenharia; sem documentação, a equipa repete erros.
- Cross-referência com outros artigos AI — Ollama + Open WebUI stack avançado 2026 para inferência local, Copilot governance e plugins para políticas de uso responsável de LLM na empresa.
Artigos Relacionados
- Ollama + Open WebUI Stack Avançado 2026 — Como correr LLM e embeddings localmente; base de inferência open-source que complementa o RAG para dados sensíveis.
- Copilot, Cowork, Governança, Plugins, Modelos, Browser — Política de uso responsável de LLM na PME; quando usar cloud, quando usar local, governança de prompts.
- Hermes AI Agent com Ollama — Instalação e Configuração — Stack de agente AI local que usa embeddings e LLM on-prem, alternativa self-host a LangChain cloud.
- Ollama + Open WebUI + Docker Compose + Nemotron — Deployment prático de LLM open-source com Docker; base para RAG local em PME.
- Copilot + ChatGPT Scripts PowerShell Sysadmin — Padrões de prompt para automação administrativa; útil quando se quer combinar RAG com acções de sistema.
11. Checklist Antes de Aplicar em Produção
- Verificar versões:
pip show langchain chromadb qdrant-client sentence-transformers openai— anotar versões e comparar com as indicadas nas docs oficiais acedidas em 2026-07-18. - Verificar chaves de API:
OPENAI_API_KEY,PINECONE_API_KEYouQDRANT_URLdefinidas no ambiente; nunca comitar no git. - Verificar modelo de embedding: confirmar dimensões (1536, 1024, 768) compatíveis com a coleção na vector DB; mismatch causa erro de inserção silencioso.
- Preparar golden set: 30-50 queries reais com resposta esperada, guardadas em JSON. Sem isto, não há forma de medir regressões.
- Ambiente de staging: projecto sandbox Python 3.11 com dependências pinadas em
requirements.txt; testar ingestão de 10 documentos reais e 20 queries antes de migrar para produção. - Backup do estado: antes de alterar modelo de embedding ou chunk size, exportar a vector DB (dump Chroma, snapshot Qdrant,
pg_dumppara pgvector). Configuração errada obriga a re-indexar tudo, o que custa tempo e dinheiro.
Risco concreto: aplicar RAG em produção sem golden set e sem avaliação de retrieval pode levar a respostas incorrectas que parecem correctas — o que para PME em setores regulados (saúde, financeiro, jurídico) pode constituir violação de compliance. Antes de expor o chatbot a clientes ou funcionários, validar com stakeholders de negócio que as respostas são correctas em 95%+ dos casos do golden set.