Ollama Embedding na prática: busca vetorial local e RAG

Eu estava procurando, em mais de 200 PDFs no meu computador, um detalhe de uma solução técnica que havia lido seis meses antes. Busca por palavras-chave? Não adiantava: eu lembrava o sentido do conteúdo, não as palavras exatas. Levei quase uma hora para encontrar o documento e pensei que seria muito melhor ter uma ferramenta de busca capaz de “entender o significado”.
Havia outro problema: esses documentos tratavam da arquitetura interna da empresa. Enviá-los para a nuvem a fim de fazer uma busca vetorial estava fora de cogitação. A exigência de privacidade era incontornável.
Foi então que descobri que o recurso de embeddings do Ollama resolvia justamente esse caso. Ele roda localmente, mantém os dados no seu ambiente e permite fazer busca semântica. Passei alguns dias testando mxbai, nomic e Qwen3, além de comparar as opções de banco de dados vetorial. Há várias armadilhas: escolher o modelo errado piora a recuperação, enquanto começar com um banco pequeno pode complicar uma expansão futura.
Este artigo reúne o que aprendi nesses testes. Ao final, você poderá montar um sistema RAG local completo, do processamento dos documentos à busca semântica, com todo o código necessário.
Modelos de embedding disponíveis no Ollama
O Ollama oferece vários modelos de embedding, e no começo eu também não sabia qual escolher. A documentação oficial afirma que o mxbai supera o text-embedding-3-large da OpenAI. Parece ótimo, mas como ele funciona na prática? Testei as opções e cheguei a uma resposta direta.
Comece por esta tabela comparativa:
| Modelo | Dimensão do vetor | Tamanho do contexto | Tamanho do modelo | Características |
|---|---|---|---|---|
| mxbai-embed-large | 1024 | 512 tokens | 670M | Opção geral recomendada, entre os primeiros do ranking MTEB |
| nomic-embed-text | 768 | 8192 tokens | 274M | Suporte a textos longos e extensão de contexto |
| Qwen3 Embedding | 1024 | 8192 tokens | cerca de 600M | Lançado em 2026 e adequado para chinês |
mxbai-embed-large é o modelo que mais usei. O motivo é simples: ele funciona bem e entrega resultados consistentes. Seus vetores de 1024 dimensões bastam para a maioria dos cenários, e o modelo aparece nas primeiras posições do MTEB (Massive Text Embedding Benchmark), com uma pontuação um pouco superior à do text-embedding-3-large da OpenAI. Para tarefas cotidianas, como busca em documentos ou em código, ele é uma escolha segura.
O destaque do nomic-embed-text é o contexto de 8192 tokens. Isso ajuda quando você precisa processar um artigo inteiro ou registros longos de conversas. Ele também é menor, com 274 milhões de parâmetros, e roda mais rápido que o mxbai. Em contrapartida, a dimensão vetorial cai para 768, o que em teoria reduz um pouco a capacidade de representação semântica. Nos meus testes, a diferença em textos curtos foi pequena, e o nomic levou vantagem com textos longos.
O Qwen3 Embedding foi lançado pela Alibaba em abril de 2026. Seu desempenho com chinês é realmente bom. Em testes com alguns artigos técnicos, ele conseguiu relacionar “mecanismo de tolerância a falhas em sistemas distribuídos” e “projeto tolerante a falhas”, enquanto o mxbai ficou um pouco atrás. Se o conteúdo for principalmente em chinês, vale a pena testá-lo.
Minha recomendação é direta: quem está começando pode escolher o mxbai sem perder tempo; para textos longos, use nomic; para conteúdo em chinês, priorize Qwen3. Testar os três leva cerca de meia hora, e o resultado real deve orientar a decisão.
Como escolher um banco de dados vetorial
Depois de escolher o modelo, onde armazenar os dados? É ainda mais fácil errar na escolha do banco de dados vetorial. Uma opção pequena demais dificulta a expansão; uma solução grande demais desperdiça recursos. Comparei três alternativas conhecidas:
| Banco de dados | Caso de uso | Volume de dados | Características |
|---|---|---|---|
| ChromaDB | Desenvolvimento inicial e projetos pessoais | < 100 mil registros | Pronto para usar, sem configuração |
| FAISS | Alto desempenho em uma máquina e experimentos de pesquisa | 100 mil a 1 milhão de registros | Código aberto da Meta e muito rápido |
| Milvus | Implantação em produção e uso empresarial | milhões de registros ou mais | Distribuído, escalável e completo |
ChromaDB é a opção que mais recomendo para começar. A instalação exige apenas um comando: pip install chromadb. A API é simples; armazenar e consultar dados leva poucas linhas de código. Ele usa um índice HNSW (Hierarchical Navigable Small World), cujo desempenho é mais do que suficiente para conjuntos pequenos. A desvantagem é a implantação em uma única máquina: acima de 100 mil registros, o desempenho começa a cair.
FAISS é uma ferramenta consolidada e de código aberto da Meta. Sua implementação em C++ é realmente rápida. Em um teste com 500 mil registros, a latência de busca se manteve na casa dos milissegundos. Porém, ele se parece mais com uma biblioteca de busca vetorial do que com um banco de dados completo: você precisa gerenciar o armazenamento e os arquivos de índice. É indicado para quem quer mais controle ou precisa do máximo de desempenho.
Milvus pertence a outra categoria e foi projetado para produção. Ele aceita implantação distribuída, armazenamento persistente, vários tipos de índice e também tem uma versão em nuvem, o Zilliz Cloud. Em contrapartida, a configuração é mais complexa e o custo de implantação é maior. Só vale esse investimento quando há milhões de registros, exigência de alta disponibilidade ou colaboração em equipe.
Minha estratégia: uso ChromaDB para projetos pessoais e protótipos rápidos; FAISS em pesquisas ou cenários sensíveis a desempenho; Milvus ou um serviço em nuvem quando o sistema realmente vai para produção. Não conte com uma migração simples do ChromaDB para o Milvus no futuro: os formatos de dados e as APIs são diferentes, e o custo da mudança não é pequeno.
Implementação completa do fluxo RAG
É melhor partir para o código do que continuar na teoria. O exemplo abaixo implementa um RAG local completo, do PDF à busca semântica, com Ollama e ChromaDB.
Preparação do ambiente
Primeiro, instale as dependências:
pip install ollama chromadb langchain langchain-community pypdf
Verifique se o Ollama está em execução e baixe os modelos:
ollama pull mxbai-embed-large
ollama pull qwen2.5:7b # Usado para gerar respostas
Implementação em código
import ollama
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
import chromadb
# 1. Carregar o documento PDF
loader = PyPDFLoader("./your_document.pdf")
docs = loader.load()
# 2. Dividir o documento — esta etapa exige atenção: blocos grandes prejudicam a precisão, e blocos pequenos perdem informações
splitter = RecursiveCharacterTextSplitter(
chunk_size=800, # 800 caracteres por bloco
chunk_overlap=100, # Sobreposição de 100 caracteres para preservar informações nas bordas
)
chunks = splitter.split_documents(docs)
# 3. Gerar embeddings e armazená-los no ChromaDB
client = chromadb.Client()
collection = client.create_collection("my_docs")
for i, chunk in enumerate(chunks):
# Chamar a API do Ollama para gerar o vetor
response = ollama.embed(
model="mxbai-embed-large",
input=chunk.page_content,
)
embedding = response["embeddings"][0]
# Armazenar no banco de dados vetorial
collection.add(
ids=[str(i)],
embeddings=[embedding],
documents=[chunk.page_content],
metadatas=[{"source": chunk.metadata.get("source", "unknown")}],
)
print(f"Foram armazenados {len(chunks)} trechos de documentos")
# 4. Busca semântica
query = "O que é tolerância a falhas em sistemas distribuídos?"
query_embedding = ollama.embed(
model="mxbai-embed-large",
input=query,
)["embeddings"][0]
results = collection.query(
query_embeddings=[query_embedding],
n_results=3, # Retornar os três trechos mais relevantes
)
# 5. Gerar uma resposta com os resultados recuperados
context = "\n\n".join(results["documents"][0])
response = ollama.chat(
model="qwen2.5:7b",
messages=[
{
"role": "system",
"content": "Responda com base no conteúdo dos documentos abaixo. Se eles não contiverem a informação, diga isso com clareza.",
},
{"role": "user", "content": f"Conteúdo dos documentos: {context}\n\nPergunta: {query}"},
],
)
print(f"Resposta: {response['message']['content']}")
Agora execute o código. O fluxo não é complicado: dividir os documentos → gerar vetores → armazenar → consultar → montar a resposta.
Algumas armadilhas importantes:
A primeira é definir chunk_size sem critério. Testei blocos de 200 caracteres, mas o resultado da recuperação trazia apenas fragmentos que não formavam uma resposta completa. O intervalo de 500 a 1000 é mais consistente.
A segunda é o processamento em lote. Quando há muitos documentos, chamar a API do Ollama uma vez por entrada fica lento. Você pode acumular um lote e processá-lo de uma só vez:
# Gerar embeddings em lote melhora bastante o desempenho
batch_texts = [chunk.page_content for chunk in chunks[:50]]
batch_embeddings = ollama.embed(
model="mxbai-embed-large",
input=batch_texts,
)["embeddings"]
A terceira é o limiar de similaridade. Por padrão, o ChromaDB retorna a quantidade definida em n_results, mesmo quando os resultados não são relevantes. Em alguns cenários, é preciso filtrar o conteúdo sem relação com a consulta:
# Filtrar com um limiar de distância personalizado
results = collection.query(
query_embeddings=[query_embedding],
n_results=10,
)
# Manter apenas resultados com distância inferior a 0,3 (quanto menor, maior a similaridade)
filtered = [
doc for doc, dist in zip(results["documents"][0], results["distances"][0])
if dist < 0.3
]
Depois de executar esse código, você terá seu próprio RAG local. Troque o arquivo PDF pelo seu documento e altere query para a pergunta desejada; o restante pode permanecer igual.
Ajustes de desempenho e recomendações práticas
Com o sistema em funcionamento, começa a etapa de ajuste. Alguns parâmetros afetam diretamente o resultado; estas são as conclusões dos meus testes.
Qual valor usar para chunk_size?
Minha referência é de 500 a 1000 caracteres. Blocos pequenos demais não preservam o sentido: uma frase pode ser cortada ao meio e deixar de corresponder à pergunta. Blocos grandes demais adicionam ruído à busca: um único trecho passa a conter vários assuntos e perde limites claros.
Também há diferenças entre tipos de documento. Documentação técnica costuma ter uma estrutura clara e pode ser dividida por parágrafo. Registros de conversas são mais fragmentados e funcionam melhor em blocos de 500 caracteres. Teste no seu cenário; não existe um valor universal.
Acelere o processamento com lotes
Ao chamar a API do Ollama para cada entrada, cada solicitação espera uma ida e volta pela rede. Reunir de 50 a 100 entradas em um lote pode multiplicar a velocidade. Não exagere no tamanho: modelos de embedding têm limites de entrada e retornam erro quando eles são ultrapassados.
Como definir o limiar de similaridade
O intervalo de 0,7 a 0,85 depende da precisão esperada. Um limiar alto, como 0,85, mantém apenas resultados muito relacionados, com menor recuperação e maior precisão. Um valor baixo, como 0,7, recupera mais conteúdo, mas pode adicionar ruído. Se a base estiver limpa e a pergunta for clara, aumente o valor; se a pergunta for vaga e exigir mais contexto, reduza-o.
Uma recomendação prática: comece com 50 a 100 registros e observe a qualidade da recuperação antes de decidir os parâmetros. Ajustar depois de carregar todo o conjunto custa muito mais tempo. Faça ajustes iterativos enquanto testa.
Conclusão
Os pontos principais são poucos:
A escolha do modelo depende do cenário: mxbai para uso geral, nomic para textos longos e Qwen3 para chinês. Para o banco de dados, ChromaDB é adequado para começar, FAISS atende casos sensíveis a desempenho e Milvus é voltado à produção. O código do fluxo inteiro está disponível acima e pode ser adaptado diretamente.
As vantagens são claras: a implantação local mantém o controle sobre a privacidade dos dados; os modelos do Ollama são gratuitos; e o ChromaDB é simples, com uma curva de aprendizado pequena. Também há limitações: o desempenho de uma única máquina tem um teto e conjuntos com mais de um milhão de registros exigem outra solução.
Minha sugestão é executar primeiro o código deste artigo com 50 documentos. A qualidade da recuperação e a precisão das respostas precisam ser avaliadas na prática. Só amplie para todos os dados depois de ajustar os parâmetros.
Para avançar na integração entre LangChain e Ollama e criar aplicações mais complexas, consulte o artigo anterior, “Integração entre LangChain e Ollama na prática”. Ele trata de cadeias de conversa e chamadas de ferramentas, enquanto este artigo se concentra na busca vetorial. Juntos, os dois formam um caminho completo para desenvolver aplicações locais com LLM.
Montar um sistema RAG local
Use Ollama e ChromaDB para montar um sistema local de busca vetorial
⏱️ Estimated time: 30 min
- 1
Step 1: Instalar as dependências e preparar os modelos
Execute os comandos abaixo para instalar as dependências:
```bash
pip install ollama chromadb langchain langchain-community pypdf
ollama pull mxbai-embed-large
ollama pull qwen2.5:7b
```
Verifique se o serviço do Ollama está em execução. - 2
Step 2: Carregar e dividir o documento
Use PyPDFLoader para carregar o PDF e RecursiveCharacterTextSplitter para dividi-lo:
```python
loader = PyPDFLoader("./your_document.pdf")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=100,
)
chunks = splitter.split_documents(docs)
```
O valor recomendado para chunk_size fica entre 500 e 1000 caracteres. - 3
Step 3: Gerar vetores e armazená-los no banco de dados
Chame a API do Ollama para gerar embeddings e armazená-los no ChromaDB:
```python
client = chromadb.Client()
collection = client.create_collection("my_docs")
for i, chunk in enumerate(chunks):
response = ollama.embed(
model="mxbai-embed-large",
input=chunk.page_content,
)
embedding = response["embeddings"][0]
collection.add(
ids=[str(i)],
embeddings=[embedding],
documents=[chunk.page_content],
)
```
Use processamento em lote quando houver muitos documentos. - 4
Step 4: Fazer a busca semântica e gerar a resposta
Converta a consulta em vetor, recupere os documentos relacionados e use um LLM para gerar a resposta:
```python
query_embedding = ollama.embed(
model="mxbai-embed-large",
input=query,
)["embeddings"][0]
results = collection.query(
query_embeddings=[query_embedding],
n_results=3,
)
context = "\n\n".join(results["documents"][0])
response = ollama.chat(
model="qwen2.5:7b",
messages=[
{"role": "system", "content": "Responda à pergunta com base no conteúdo dos documentos"},
{"role": "user", "content": f"Documentos: {context}\nPergunta: {query}"},
],
)
```
Ajuste o limiar de similaridade conforme necessário para filtrar os resultados.
FAQ
Qual é o melhor modelo de embedding do Ollama?
• mxbai-embed-large: opção geral recomendada, com resultados consistentes na maioria dos casos
• nomic-embed-text: indicado para textos longos, com suporte a 8192 tokens
• Qwen3 Embedding: funciona bem com chinês e foi lançado em 2026
Vale a pena testar os três e decidir com base nos resultados reais.
Qual escolher entre ChromaDB, FAISS e Milvus?
• ChromaDB: melhor opção para começar, sem configuração, indicado para até 100 mil registros
• FAISS: prioriza desempenho, suporta milhões de registros em uma única máquina, mas exige que você gerencie o armazenamento
• Milvus: indicado para produção, com implantação distribuída e conjuntos acima de milhões de registros
Use ChromaDB em projetos pessoais e Milvus em ambientes de produção.
Qual valor usar para chunk_size?
Como acelerar a geração de embeddings?
Qual limiar de similaridade devo usar?
Quais são as principais vantagens e desvantagens de um RAG local?
Desvantagens: desempenho limitado em uma única máquina, necessidade de outra solução para conjuntos acima de milhões de registros e responsabilidade pela manutenção do serviço.
10 min de leitura · Publicado em: 8 abr 2026 · Atualizado em: 4 set 2026
Guia Ollama LLM local
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
LangChain + Ollama na prática: guia completo para criar aplicações com LLM local
Aprenda a integrar LangChain e Ollama com exemplos de Chat, RAG e Agent, além de estratégias para alternar entre modelos locais e a OpenAI.
Parte 10 de 13
Próximo
Monitoramento do Ollama em produção: logs e alertas com Prometheus
Guia completo para monitorar o Ollama em produção, com configuração de logs, coleta de métricas no Prometheus, regras de alerta no AlertManager e dashboards no Grafana, incluindo monitoramento de múltiplas GPUs e recuperação automática de falhas.
Parte 12 de 13



Comentários
Entre com GitHub para comentar