A era da Inteligência Artificial Generativa está se deslocando rapidamente do modelo "tudo na nuvem" para arquiteturas locais e privadas. Para empresas e desenvolvedores que priorizam a soberania dos dados, a latência reduzida e o controle total sobre o ciclo de vida dos modelos, rodar LLMs (Large Language Models) localmente em uma VPS ou servidor dedicado tornou-se uma realidade acessível. No entanto, treinar um modelo do zero ou fazer fine-tuning complexo para cada domínio específico é custoso e demorado.
A solução elegante que uniu a comunidade de IA open-source é o padrão RAG (Retrieval-Augmented Generation). Neste tutorial, vamos explorar como implementar um sistema robusto de RAG utilizando Ollama para gerenciar os modelos e Qdrant como seu vetor store. Esta combinação permite que sua LLM local — seja ela Qwen, Llama ou Mistral — responda com base em documentos atualizados, sem necessidade de retreinamento constante.
O que é RAG e por que usar Qdrant?
O RAG funciona como um sistema de memória externa para sua LLM. Em vez de confiar apenas no treinamento prévio do modelo (que pode estar desatualizado ou ser genérico), o RAG busca informações relevantes em uma base de dados vetorial antes de gerar uma resposta. O processo divide-se em três etapas: ingestão, recuperação e geração.
O Qdrant surge como a escolha ideal para este pipeline. Diferente de bancos de dados relacionais tradicionais, o Qdrant é um banco de dados vetorial escrito em Rust, projetado para alta performance e escalabilidade. Ele armazena embeddings (representações numéricas do significado semântico dos textos) e permite buscas por similaridade extremamente rápidas. Ao integrar o Qdrant com o Ollama, criamos uma infraestrutura que pode ser exposta via API REST, facilitando a integração com interfaces como AnythingLLM ou aplicações customizadas em Python.
Pré-requisitos e Infraestrutura
Para seguir este guia, você precisará de um ambiente Linux (Ubuntu/Debian recomendado) rodando em uma VPS. Certifique-se de ter acesso SSH com privilégios de root ou sudo. Para a execução eficiente dos modelos de linguagem e cálculos vetoriais, recomenda-se pelo menos 8GB de RAM e, idealmente, uma GPU dedicada (NVIDIA) ou um CPU forte com suporte a AVX2 para inferência via CPU.
Vamos instalar dois componentes principais: o Qdrant Server e o Ollama. Utilizaremos contêineres Docker para garantir isolamento e facilidade de manutenção.
Etapa 1: Instalando e Configurando o Qdrant
O primeiro passo é provisionar o banco de dados vetorial. O Qdrant oferece uma imagem oficial no Docker Hub que já vem pré-configurada com a API REST necessária para ingestão e consulta.
- Crie um diretório para persistir os dados do Qdrant. Isso garante que seus embeddings não sejam perdidos ao reiniciar o contêiner.
mkdir -p ~/qdrant/storage
Olha só, manter a persistência é crucial para sistemas de produção. Sem isso, cada reinicialização apagaria seu conhecimento vetorial.
- Inicie o contêiner do Qdrant mapeando a porta padrão 6333 e montando o volume de dados:
docker run -d \
--name qdrant \
-p 6333:6333 \
-v ~/qdrant/storage:/qdrant/storage \
qdrant/qdrant
Após a execução, verifique se o serviço está respondendo. Você pode acessar http://seu-ip:6333/dashboard ou verificar via terminal:
curl http://localhost:6333/healthcheck
Se retornar um JSON com status "ok", seu vetor store está pronto. Agora, vamos criar uma coleção específica para armazenar os embeddings relacionados ao seu domínio.
Etapa 2: Configurando o Ollama e Baixando Modelos
O Ollama simplifica drasticamente a gestão de LLMs locais. Ele lida com o download, versionamento e execução dos modelos em CUDA (GPU) ou CPU.
- Instale o Ollama seguindo a documentação oficial para Linux:
curl -fsSL https://ollama.com/install.sh | sh
Depois da instalação, precisamos de dois modelos distintos para nossa arquitetura RAG:
- Um modelo de Embedding: Responsável por converter texto em vetores. O
nomic-embed-texté leve e performático. - Um modelo LLM (Geração): Pode ser o Llama 3, Qwen 2.5 ou Mistral, dependendo da complexidade das perguntas que você espera processar.
- Baixe o modelo de embedding:
ollama pull nomic-embed-text
- Baixe o modelo LLM principal. Vamos usar o Qwen como exemplo, pois tem excelente suporte a português e raciocínio lógico:
ollama pull qwen2.5:7b
O Ollama expõe uma API local na porta 11434. Teste se o modelo está respondendo corretamente enviando um prompt simples:
curl http://localhost:11434/api/generate -d '{
"model": "qwen2.5:7b",
"prompt": "Qual a capital da França?",
"stream": false
}'
Etapa 3: Ingestão de Dados e Criação de Embeddings
Agora que a infraestrutura está pronta, precisamos popular o Qdrant com dados. Vamos pegar um arquivo de texto simples (por exemplo, um manual técnico ou documentação da sua empresa) e transformá-lo em vetores.
Crie um arquivo chamado documentos.txt e adicione algum conteúdo de teste:
Sou um assistente virtual especializado em suporte técnico.
Posso ajudar com configuração de servidores, Docker e Linux.
Para processar isso, precisamos de um script Python que use a biblioteca qdrant-client e chame o Ollama para gerar os embeddings. Instale as dependências:
pip install qdrant-client ollama
Crie um script chamado ingest.py:
import uuid
import qdrant_client
import ollama
import math
# Configuração dos clientes
qdrant = qdrant_client.QdrantClient(host="localhost", port=6333)
ollama_client = ollama.Client(host="localhost", port=11434)
COLLECTION_NAME = "meus_dados"
EMBEDDING_MODEL = "nomic-embed-text"
# 1. Criar a coleção se não existir
if not qdrant.collection_exists(COLLECTION_NAME):
qdrant.create_collection(
collection_name=COLLECTION_NAME,
vectors_config=qdrant_client.models.VectorParams(
size=768, # Tamanho do embedding do nomic-embed-text
distance=qdrant_client.models.Distance.COSINE
)
)
# 2. Ler e chunkear o texto (dividir em partes menores)
with open("documentos.txt", "r") as f:
content = f.read()
# Chunking simples por linhas para demonstração
chunks = [line.strip() for line in content.split('\n') if line.strip()]
print(f"Processando {len(chunks)} chunks...")
# 3. Gerar embeddings e upsert no Qdrant
for i, chunk in enumerate(chunks):
# Chama o Ollama para gerar o embedding
response = ollama_client.embeddings(model=EMBEDDING_MODEL, input=chunk)
embedding = response["embedding"]
# Cria o ponto de dados no Qdrant
qdrant.upsert(
collection_name=COLLECTION_NAME,
points=[
qdrant_client.models.PointStruct(
id=str(uuid.uuid4()),
vector=embedding,
payload={"text": chunk} # Payload para recuperar o texto original depois
)
]
)
print(f"Chunk {i+1}/{len(chunks)} inserido.")
print("Ingestão concluída com sucesso!")
Rode o script:
python ingest.py
Se tudo correr bem, seu Qdrant agora contém vetores representando semanticamente o texto do seu arquivo. Note que usamos Distance.COSINE, que é padrão para a maioria dos modelos de embedding modernos.
Etapa 4: Consultando e Gerando Respostas (RAG Loop)
A magia do RAG acontece aqui. Precisamos recuperar o trecho mais relevante ao prompt do usuário e injetar esse contexto no prompt da LLM.
Crie o arquivo rag_query.py:
import qdrant_client
import ollama
COLLECTION_NAME = "meus_dados"
EMBEDDING_MODEL = "nomic-embed-text"
LLM_MODEL = "qwen2.5:7b"
qdrant = qdrant_client.QdrantClient(host="localhost", port=6333)
ollama_client = ollama.Client(host="localhost", port=11434)
user_question = "O que eu posso fazer com este assistente?"
# 1. Gerar embedding da pergunta do usuário
print("Gerando embedding da consulta...")
query_embedding = ollama_client.embeddings(model=EMBEDDING_MODEL, input=user_question)["embedding"]
# 2. Buscar os k pontos mais similares no Qdrant
k = 1 # Retornar apenas o top 1 resultado para este exemplo
results = qdrant.search(
collection_name=COLLECTION_NAME,
query_vector=query_embedding,
limit=k
)
if not results:
print("Nenhum dado encontrado.")
else:
# Extrair o texto relevante
context_text = results[0].payload['text']
print(f"Dado recuperado: {context_text}")
# 3. Construir o prompt com contexto (RAG)
system_prompt = f"""Você é um assistente útil. Responda a pergunta do usuário baseada apenas no contexto abaixo. Se não souber a resposta, diga que não encontrou informações.
Contexto: {context_text}
Pergunta: {user_question}"""
# 4. Gerar resposta com a LLM
print("\nGerando resposta...")
response = ollama_client.chat(
model=LLM_MODEL,
messages=[{'role': 'user', 'content': system_prompt}]
)
print(f"Resposta Final: {response['message']['content']}")
Execute a consulta:
python rag_query.py
Você verá que o sistema recuperou a linha específica do texto e pediu ao Qwen para formular uma resposta natural baseada nela. Isso é o RAG em ação: dados específicos + inteligência generalista.
Etapa 5: Integração com AnythingLLM (Opcional)
Se você não deseja escrever código Python para cada interação, pode integrar seu stack Ollama-Qdrant ao AnythingLLM, uma interface web poderosa que gerencia workspaces de RAG.
- Instale o AnythingLLM conforme a documentação do site oficial.
- No painel de configurações, selecione "Ollama" como provedor de LLM e insira
http://localhost:11434. - Para o Vector Store, escolha "Qdrant" e insira
http://localhost:6333. - Crie um novo Workspace, faça upload de seus PDFs ou TXTs e clique em "Build Workspace".
O AnythingLLM fará o chunking, embedding e armazenamento no Qdrant automaticamente, permitindo que você interaja via chat web sem escrever uma linha de código.
Considerações Finais sobre Escalabilidade e Fine-Tuning
Embora o RAG resolva 80% dos problemas de atualização de conhecimento, há cenários onde ele não basta. Se você precisa que a LLM adote um tom de voz específico ou siga regras de negócio complexas que não cabem em prompts, considere fazer fine-tuning. No entanto, o fine-tuning é caro e difícil de manter.
A tendência moderna é usar RAG para dados dinâmicos (documentos, manuais) e fine-tuning apenas para comportamentos estáticos. O stack Qdrant + Ollama oferece a flexibilidade perfeita: você pode adicionar novos documentos ao Qdrant em tempo real sem tocar no modelo base.
Para produção, lembre-se de:
- Segurança: Coloque o Qdrant e o Ollama atrás de um Nginx ou Traefik com autenticação básica se expuser a porta 6333 ou 11433 à internet.
- Chunking Inteligente: Para documentos longos, use bibliotecas como LangChain ou LlamaIndex para fazer chunking semântico (por parágrafos ou tópicos) em vez de apenas por linhas.
- Hidração de Metadados: Armazene metadados (autor, data, tipo de documento) no payload do Qdrant para filtrar buscas antes mesmo de calcular a similaridade vetorial.
Com essa configuração, você tem um sistema de IA local, privado e altamente personalizado rodando em sua VPS. A combinação de RAG com Qdrant e modelos como Llama ou Qwen via Ollama é, hoje, o padrão ouro para implementações empresariais de IA generativa self-hosted.