Post

Um endpoint para modelos locais e cloud: por que usei LiteLLM como gateway

Se preferir começar por um resumo, peça um TL;DR ao Claude .

Como um gateway compatível com OpenAI reduz o acoplamento entre aplicações, modelos locais, provedores cloud e políticas de custo.

Quando uma aplicação chama um único modelo, apontar diretamente para o provedor parece a solução mais simples. O problema começa quando o mesmo ambiente passa a combinar um modelo local para tarefas baratas, um serviço remoto para demandas maiores e um provedor cloud para casos em que qualidade ou capacidade importam mais que o custo.

Sem uma camada intermediária, cada aplicação precisa saber qual URL chamar, como autenticar, qual SDK usar, quais nomes de modelo existem e o que fazer quando um provedor falha. A troca de modelo deixa de ser uma decisão operacional e passa a exigir mudanças distribuídas no código.

No meu homelab, a decisão foi colocar o LiteLLM Proxy entre as aplicações e os provedores. Ele oferece uma API compatível com OpenAI e pode encaminhar chamadas para modelos locais, outras instâncias do próprio LiteLLM e serviços cloud.

1
2
3
4
5
Aplicações, scripts e ferramentas
             ↓
        LiteLLM local
       ↙       ↓       ↘
modelo local  gateway remoto  provedor cloud

O objetivo não era esconder a infraestrutura por completo. Era concentrar decisões que não deveriam estar espalhadas por cada cliente: qual modelo usar, onde ele está, quem pode chamá-lo, quanto custa e como observar o que está acontecendo.

O acoplamento aparece antes de percebermos

É comum uma aplicação começar com variáveis como estas:

1
2
3
export OPENAI_BASE_URL="https://provedor-a.exemplo/v1"
export OPENAI_API_KEY="..."
export DEFAULT_MODEL="modelo-do-provedor-a"

Para um experimento isolado, isso é adequado. Mas, quando existem vários consumidores, a configuração se multiplica:

  • um script escolhe um modelo local;
  • uma ferramenta de linha de comando aponta diretamente para a nuvem;
  • um serviço usa outro SDK porque o provedor pede uma interface diferente;
  • uma chave de alto privilégio aparece em mais ambientes do que deveria;
  • mudar um modelo exige alterar configurações em vários repositórios.

O custo dessa dispersão não é apenas manutenção. Ela reduz a capacidade de responder a perguntas básicas: qual aplicação usou qual modelo? Quanto custou? O que falhou? Quais clientes ainda dependem do provedor antigo?

Um gateway não resolve automaticamente essas perguntas, mas cria o lugar onde elas podem ser tratadas de maneira consistente.

A fronteira que eu queria criar

O LiteLLM funciona como tradutor e proxy. A aplicação fala uma interface conhecida, e o gateway converte a chamada para o provedor configurado. A documentação do projeto descreve suporte a múltiplos provedores, respostas no formato OpenAI, roteamento, fallbacks e rastreamento de uso. A página oficial é a melhor referência para verificar a lista de integrações e recursos da versão em uso.

No meu caso, a fronteira ficou assim:

1
2
3
4
5
Cliente
  → POST /v1/chat/completions
  → alias de modelo
  → LiteLLM
  → implementação escolhida para aquele alias

O cliente não precisa saber se chat-rapido é atendido por uma instância local ou por um provedor externo. Ele precisa saber que há limites de capacidade e que o alias tem uma finalidade clara.

Essa última parte é importante. Eu evitaria expor aliases que apenas repetem o nome do fornecedor, como modelo-x-provedor-y. Isso só desloca o acoplamento de lugar.

Prefiro nomes ligados à intenção de uso:

1
2
3
4
chat-rapido
codigo-padrao
raciocinio
embedding-local

O alias é uma promessa operacional. chat-rapido, por exemplo, pode priorizar custo e tempo de resposta. Se o backend mudar, a promessa precisa continuar válida ou o alias deve ganhar uma nova versão.

Um arquivo de configuração torna a decisão visível

Uma configuração reduzida pode começar assim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
model_list:
  - model_name: chat-rapido
    litellm_params:
      model: ollama/modelo-local
      api_base: os.environ/OLLAMA_BASE_URL

  - model_name: raciocinio
    litellm_params:
      model: vertex_ai/modelo-gerenciado
      vertex_ai_project: os.environ/VERTEX_PROJECT
      vertex_ai_location: os.environ/VERTEX_LOCATION

  - model_name: codigo-padrao
    litellm_params:
      model: openai/codigo-remoto
      api_base: os.environ/REMOTE_GATEWAY_BASE_URL
      api_key: os.environ/REMOTE_GATEWAY_API_KEY

Os valores são genéricos de propósito. O ponto é mostrar as três classes de destino que eu precisava tratar:

  • um servidor local, apropriado quando a tarefa cabe no hardware disponível;
  • um provedor cloud, para modelos que não fazem sentido hospedar;
  • outro gateway compatível, que permite delegar uma parte do catálogo a uma instância remota.

O arquivo de configuração não deve carregar chaves reais. Ele referencia variáveis de ambiente ou um mecanismo de segredos. Assim, o mesmo manifesto pode ir para o controle de versão sem transformar credenciais em conteúdo do repositório.

Encadear gateways tem um uso específico

O LiteLLM também pode usar outra instância compatível com OpenAI como destino. Na configuração, isso aparece como um modelo com prefixo openai/, uma URL base e uma credencial limitada para o gateway remoto.

1
2
3
4
5
6
model_list:
  - model_name: codigo-padrao
    litellm_params:
      model: openai/codigo-remoto
      api_base: os.environ/REMOTE_GATEWAY_BASE_URL
      api_key: os.environ/REMOTE_GATEWAY_API_KEY

Esse encadeamento é útil quando uma instância local precisa manter o contrato para seus clientes, mas não deve conhecer todos os provedores, políticas e credenciais disponíveis em outro ambiente.

Eu o usaria para separar responsabilidades, não para construir uma cadeia arbitrária de proxies. Cada salto adiciona latência, novos modos de falha e uma etapa extra de diagnóstico. Se o cliente pode chamar o destino certo com uma política clara, um proxy adicional talvez seja apenas complexidade.

A aplicação muda pouco

Depois de configurar o gateway, um cliente compatível com OpenAI aponta para uma única URL:

1
2
3
4
5
6
7
8
9
10
11
12
13
from openai import OpenAI

client = OpenAI(
    base_url="https://llm.interno/v1",
    api_key="chave-do-cliente"
)

response = client.chat.completions.create(
    model="chat-rapido",
    messages=[
        {"role": "user", "content": "Resuma estes pontos."}
    ]
)

O ganho é que o código do cliente fica concentrado na interação: mensagem, resposta, streaming, ferramentas e tratamento de erro. Roteamento, chaves de provedores e escolha de backend ficam no gateway.

Isso também ajuda quando ferramentas antigas já entendem o protocolo OpenAI, mas não têm suporte nativo a um determinado provedor. Em vez de trocar a ferramenta, eu configuro a URL do gateway e um alias permitido para aquele uso.

Fallback não é sinônimo de trocar qualquer modelo

Um dos recursos mais atraentes de um gateway é poder configurar fallback. Quando um modelo fica indisponível, o proxy pode tentar outro destino. Essa capacidade é útil, mas precisa ser aplicada com critério.

Eu separaria as tarefas em dois grupos.

No primeiro, estão as operações que toleram variação: resumir texto, classificar conteúdo, extrair um campo simples, gerar uma primeira versão. Um fallback para um modelo equivalente pode reduzir indisponibilidade sem comprometer o resultado.

No segundo, estão tarefas em que o comportamento do modelo faz parte do requisito: uma resposta com ferramenta específica, uma análise que exige um contexto grande, uma decisão com política sensível ou uma geração de código que será aplicada automaticamente. Nesses casos, trocar o modelo sem avisar pode criar uma resposta formalmente bem-sucedida, mas errada para o produto.

Eu começaria com roteamento explícito e só adicionaria fallback depois de definir:

  • quais modelos são realmente equivalentes para aquela tarefa;
  • quais parâmetros e ferramentas precisam existir nos dois destinos;
  • como o cliente será informado de que houve troca;
  • qual teste de qualidade protege a mudança;
  • quando a falha deve chegar ao usuário em vez de ser mascarada.

O gateway torna a mudança possível. Ele não transforma modelos diferentes em componentes intercambiáveis por definição.

A governança começa pela chave certa

Um erro comum é colocar a credencial administrativa do gateway em todos os consumidores. Isso transforma qualquer script em um cliente com poder de administrar modelos, chaves e orçamento.

Eu separaria pelo menos três níveis de acesso:

  • uma credencial administrativa, reservada à operação do gateway;
  • credenciais de aplicação, limitadas aos aliases e aos limites necessários;
  • credenciais dos provedores, mantidas apenas pelo gateway.

O LiteLLM oferece recursos de chaves virtuais, limites e rastreamento por projeto; esses recursos são úteis quando há mais de um consumidor ou quando o custo precisa ser atribuído. Mesmo em um ambiente pequeno, a separação vale a pena porque reduz o impacto de um vazamento e deixa claro quem usa o quê.

Também decidiria com cuidado o que registrar. Logs de latência, status, modelo, contagem de tokens e custo costumam ser suficientes para operar o serviço. Registrar prompts e respostas integralmente pode ser útil para depurar, mas precisa de uma política de retenção e acesso compatível com o conteúdo processado.

O que eu observaria antes de adicionar mais modelos

Com muitos modelos disponíveis, o problema muda de integração para escolha. Colocar todos no catálogo não ajuda se ninguém sabe qual usar.

Eu acompanharia, por alias e por consumidor:

  • taxa de sucesso e categorias de erro;
  • latência, especialmente p50 e p95;
  • tokens de entrada e saída;
  • custo estimado para os destinos pagos;
  • volume de fallbacks;
  • concentração de uso em um único modelo;
  • falhas por limite de taxa ou timeout.

Esses dados tornam uma conversa abstrata em uma decisão operacional. Se chat-rapido começa a receber solicitações que exigem contexto maior ou ferramentas indisponíveis localmente, isso aparece como erro, fallback ou latência. A resposta pode ser ajustar o alias, criar outro mais específico ou orientar o cliente a escolher uma capacidade diferente.

Quando eu não criaria esse gateway

Para uma aplicação pequena, um único provedor e uma única credencial bem protegida, adicionar LiteLLM pode ser mais infraestrutura do que benefício. O proxy precisa ser atualizado, monitorado, autenticado e incluído no caminho crítico da requisição.

Também não o trataria como substituto para avaliação de modelos. O gateway consegue encaminhar uma chamada; ele não demonstra que o modelo escolhido atende à qualidade, à privacidade ou ao custo necessário para a tarefa.

Eu consideraria introduzi-lo quando pelo menos uma destas condições aparecer:

  • duas ou mais aplicações consomem modelos diferentes;
  • existe intenção real de alternar entre local e cloud;
  • custos precisam ser medidos por projeto ou cliente;
  • a equipe quer retirar credenciais de provedores das aplicações;
  • ferramentas distintas já suportam uma interface compatível com OpenAI.

Conclusão

O LiteLLM resolveu um problema de organização: separar o que a aplicação quer fazer da infraestrutura que executa o modelo.

Para começar, eu exporia dois ou três aliases com finalidades bem definidas, manteria as credenciais de provedores dentro do gateway e instrumentaria latência, erro e custo desde o primeiro cliente. Depois de observar o uso real, adicionaria roteamento, fallback ou novos destinos quando houvesse uma necessidade clara.

O endpoint único não elimina as escolhas de IA. Ele as coloca em um lugar onde podem ser revisadas, testadas e operadas sem modificar cada aplicação a cada mudança de modelo.