Ollama em produção: rodando LLMs locais em ambientes privados e offline

1. Por que rodar LLMs localmente em produção

A adoção de Large Language Models (LLMs) em ambientes corporativos enfrenta desafios críticos de privacidade, conformidade e custos. Rodar modelos localmente com Ollama elimina a dependência de APIs externas, garantindo que dados sensíveis nunca deixem o perímetro da organização. Em setores regulados como saúde, finanças e governo, onde a LGPD e o GDPR exigem controle rigoroso sobre informações, essa abordagem não é apenas vantajosa — é obrigatória.

Além da conformidade, a eliminação de latência de rede e a previsibilidade de custos (sem taxas por token) tornam o Ollama uma escolha estratégica para produção. Você controla exatamente qual modelo está sendo executado, quando será atualizado e como os recursos de hardware serão alocados.

2. Instalação e configuração do Ollama em servidores offline

Para ambientes sem acesso à internet, o processo exige preparação. Primeiro, faça o download do binário do Ollama em uma máquina com internet e transfira-o via mídia física ou rede interna.

# Download do Ollama (em máquina com internet)
curl -fsSL https://ollama.com/install.sh | sh

# Transferir o binário para o servidor offline
# Exemplo via SCP:
scp ollama user@server-offline:/usr/local/bin/

No servidor offline, instale e configure:

# Instalação manual
sudo cp ollama /usr/local/bin/
sudo chmod +x /usr/local/bin/ollama

# Baixar modelos em máquina com internet e transferir
# Em máquina online:
ollama pull llama3.2:3b
# Local do modelo: ~/.ollama/models/blobs/
scp -r ~/.ollama/models/ user@server-offline:~/.ollama/

# Configurar variáveis de ambiente para diretório personalizado
export OLLAMA_MODELS=/data/ollama/models
export OLLAMA_HOST=0.0.0.0:11434

3. Otimização de modelos para hardware limitado

A escolha do modelo certo é crucial. Para servidores com 8GB de RAM e sem GPU, modelos quantizados em Q4 ou Q5 oferecem o melhor equilíbrio entre qualidade e desempenho.

# Listar modelos disponíveis localmente
ollama list

# Exemplo de seleção com base em hardware:
# - 4GB RAM: modelos 1B-3B (quantizados Q4)
# - 8GB RAM: modelos 3B-7B (quantizados Q4/Q5)
# - 16GB RAM + GPU: modelos 7B-13B (Q8 ou FP16)

# Criar um modelo customizado com quantização
ollama pull llama3.2:3b-q4_K_M

# Verificar o tamanho do modelo
ls -lh ~/.ollama/models/blobs/ | grep llama3

Para balancear qualidade e desempenho em produção, teste diferentes níveis de quantização:

# Teste de inferência com diferentes quantizações
ollama run llama3.2:3b-q4_K_M "Explique o conceito de privacidade de dados"
ollama run llama3.2:3b-q8_0 "Explique o conceito de privacidade de dados"

4. Deploy e escalabilidade com contêineres

A dockerização do Ollama permite ambientes isolados e reproduzíveis, essenciais para produção.

# Dockerfile para Ollama
FROM ollama/ollama:latest

COPY ./models /root/.ollama/models

EXPOSE 11434

CMD ["ollama", "serve"]

Para múltiplas instâncias com Docker Compose:

# docker-compose.yml
version: '3.8'
services:
  ollama-1:
    image: ollama/ollama:latest
    ports:
      - "11434:11434"
    volumes:
      - ./models-1:/root/.ollama/models
    environment:
      - OLLAMA_HOST=0.0.0.0

  ollama-2:
    image: ollama/ollama:latest
    ports:
      - "11435:11434"
    volumes:
      - ./models-2:/root/.ollama/models
    environment:
      - OLLAMA_HOST=0.0.0.0

Para balanceamento de carga com Nginx:

# nginx.conf
upstream ollama_backend {
    server localhost:11434;
    server localhost:11435;
}

server {
    listen 80;
    location / {
        proxy_pass http://ollama_backend;
    }
}

5. Integração com pipelines offline e RAG

Construir um pipeline RAG (Retrieval-Augmented Generation) totalmente offline combina Ollama com bases vetoriais locais como Chroma.

# Exemplo: Pipeline RAG offline com Ollama e Chroma
import chromadb
from chromadb.utils import embedding_functions
import requests
import json

# Configurar Chroma local
client = chromadb.PersistentClient(path="./chroma_db")
collection = client.create_collection(
    name="documentos_privados",
    embedding_function=embedding_functions.OllamaEmbeddingFunction(
        model_name="nomic-embed-text"
    )
)

# Adicionar documentos
collection.add(
    documents=["Política de privacidade da empresa versão 2024"],
    metadatas=[{"fonte": "manual_interno"}],
    ids=["doc1"]
)

# Função de consulta RAG
def consultar_rag(pergunta):
    # Embedding local
    results = collection.query(query_texts=[pergunta], n_results=1)
    contexto = results['documents'][0][0]

    # Geração com Ollama
    prompt = f"Contexto: {contexto}\nPergunta: {pergunta}\nResposta:"
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={"model": "llama3.2:3b", "prompt": prompt, "stream": False}
    )
    return response.json()['response']

# Teste
print(consultar_rag("Qual a política de privacidade vigente?"))

6. Monitoramento, logging e manutenção

Para produção, é essencial monitorar métricas de desempenho e manter logs detalhados.

# Script de monitoramento básico
import time
import psutil
import requests

def monitorar_ollama():
    inicio = time.time()
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={"model": "llama3.2:3b", "prompt": "teste", "stream": False}
    )
    latencia = time.time() - inicio

    memoria = psutil.virtual_memory()
    cpu = psutil.cpu_percent()

    log = {
        "timestamp": time.time(),
        "latencia_segundos": latencia,
        "memoria_usada_gb": memoria.used / 1e9,
        "cpu_percent": cpu,
        "tokens_gerados": len(response.json()['response'].split())
    }

    # Salvar em arquivo JSON para análise posterior
    with open("logs_ollama.jsonl", "a") as f:
        f.write(json.dumps(log) + "\n")

    return log

# Executar a cada minuto
while True:
    monitorar_ollama()
    time.sleep(60)

Para logging de requisições:

# Configurar logging no Ollama via variável de ambiente
export OLLAMA_DEBUG=1
export OLLAMA_LOGFILE=/var/log/ollama/requests.log

Estratégias de atualização:

# Rollback para versão anterior do modelo
# Manter snapshots dos modelos
cp -r ~/.ollama/models ~/.ollama/models_backup_$(date +%Y%m%d)

# Restaurar versão anterior
rm -rf ~/.ollama/models
cp -r ~/.ollama/models_backup_20240101 ~/.ollama/models

7. Casos de uso práticos e limitações

Casos de uso reais:

  • Chatbot interno de suporte técnico: Uma empresa de telecomunicações implantou Ollama com modelo Llama 3.2 7B em servidores locais para responder perguntas sobre procedimentos internos, reduzindo o tempo de resposta de 2 horas para 30 segundos.
  • Análise de documentos sigilosos: Um escritório de advocacia utiliza pipeline RAG offline com Ollama + Chroma para consultar contratos e jurisprudências sem expor dados a terceiros.
  • Automação em redes OT: Uma fábrica utiliza Ollama em hardware industrial para gerar relatórios de manutenção preditiva a partir de sensores IoT, tudo em rede isolada.

Limitações conhecidas:

  • Tamanho de contexto: Modelos locais têm contexto limitado (geralmente 4K-32K tokens), insuficiente para documentos muito longos sem chunking.
  • Alucinação: Modelos menores (3B-7B) tendem a alucinar mais que modelos maiores ou APIs especializadas.
  • Latência em hardware modesto: Em CPUs sem GPU, a inferência pode levar de 5 a 30 segundos por resposta, inviabilizando aplicações em tempo real.
  • Atualização de modelos: Modelos locais não são atualizados automaticamente, exigindo processo manual de download e teste.

Para mitigar limitações, combine múltiplos modelos especializados (um para sumarização, outro para classificação) e implemente validação heurística das respostas antes de exibi-las ao usuário final.


Referências