Resumo

  • Varri 17 repositórios do GitHub trending com o script de inventário: 10 chamam modelo, e 6 deles já falam com 5 provedores ou mais — um chega a 16. Chamando direto, sem camada nenhuma no meio.
  • Um gateway resolve três coisas ao mesmo tempo: chave que a aplicação nunca vê, roteamento versionado, e custo atribuível por time.
  • Medi o overhead do LiteLLM contra um upstream local: p50 +10ms sequencial, +45ms com 10 conexões. Contra uma chamada real de modelo isso é ruído; contra um modelo local rápido, é dominante.
  • OpenRouter e gateway auto-hospedado resolvem problemas diferentes. Se a sua trava é para onde o dado vai, o OpenRouter adiciona um salto em vez de remover.
  • O docker-compose.yml completo está no fim.

O que os dados dizem

Peguei os repositórios em alta do GitHub, clonei 17 e rodei o inventário. 38.744 arquivos lidos.

Dez chamam modelo de IA. Sete não. E entre os dez:

repositório arquivos com IA provedores distintos
diegosouzapw/OmniRoute 249 16
bojieli/ai-agent-book 381 13
andrewyng/aisuite 72 11
moeru-ai/airi 40 9
different-ai/openwork 61 7
pingdotgg/t3code 52 5

Seis de dez projetos já falam com cinco provedores ou mais. Não é projeção de futuro, é o presente do código que está em alta esta semana.

A distribuição de provedores, por número de repositórios que os usam: OpenAI em 8, Anthropic em 7, Ollama local em 7, OpenRouter em 6, Together em 5, e depois Google, Mistral, Groq, Bedrock, Replicate, vLLM local.

Repare em duas coisas. Ollama local aparece tanto quanto Anthropic — modelo local já é rotina, não experimento. E OpenRouter aparece em 6 de 10, o que significa que a necessidade de rotear entre provedores já é sentida; a diferença é que a maioria resolveu isso com um serviço de terceiro em vez de uma camada própria.

Outros dois números da varredura: 657 chamadas de inferência sem timeout aparente e 44 servidores MCP declarados — 43 deles num único projeto.

As três coisas que um gateway resolve

Não é uma. São três, e é por isso que a camada se paga.

1. A aplicação nunca vê a chave do provedor. Ela recebe uma chave virtual, com escopo de modelo, teto de gasto e limite de requisição. A chave real vive num lugar só. Dev que sai da empresa perde acesso sem ninguém rotacionar credencial de produção.

2. O roteamento vira configuração versionada. A aplicação pede rapido ou profundo, não gpt-5-mini ou claude-sonnet-5. Trocar de modelo — porque baixou de preço, porque subiu de qualidade, porque o compliance vetou um provedor — vira uma linha num YAML em vez de um pull request em cada repositório.

3. Custo e rastro ficam atribuíveis. Gasto por time, por aplicação, por rota. Sem isso, o relatório mensal é um número só e ninguém consegue dizer de onde veio.

Foi o desenho que o iFood e o Itaú adotaram, de forma independente, quando a escala passou de um certo ponto. Nenhum dos dois deixou as aplicações chamarem provedor direto.

OpenRouter ou auto-hospedado

Essa é a decisão que define o resto, e ela não é sobre features.

OpenRouter é um roteador hospedado: uma API para centenas de modelos, com failover e uma conta só. Não loga prompt por padrão, tem controle de Zero Data Retention que restringe o roteamento a provedores que não retêm nem treinam, e oferece roteamento in-region na União Europeia para conta enterprise. Existe um desconto de 1% em troca de habilitar log de prompt — e habilitar isso concede direito comercial irrevogável sobre entradas e saídas. Não habilite sem ler.

E tem a nuance que decide: zero retention cobre conteúdo, não metadado — contagem de token, latência e timestamp continuam retidos. E a retenção final também depende do provedor para onde ele roteou.

A pergunta certa não é qual é melhor. É de que problema você está fugindo.

  • Se o seu problema é operacional — cansei de manter cinco SDKs, quero failover entre provedores, quero uma conta só — o OpenRouter resolve com muito menos trabalho que subir infraestrutura.
  • Se o seu problema é para onde o dado vai — segredo industrial, cláusula de confidencialidade com cliente, setor regulado — o OpenRouter adiciona um salto em vez de remover. Você sai de "meu código vai para a Anthropic" para "meu código vai para o OpenRouter e depois para a Anthropic". Pode ser aceitável, mas é uma decisão a mais para justificar numa auditoria, não a menos.

Para o segundo caso, gateway auto-hospedado. E aí a escolha prática hoje:

  • LiteLLM — MIT, 100+ provedores atrás de um endpoint compatível com OpenAI, chave virtual, teto por time, fallback, painel. É o mais completo em compatibilidade. Escrito em Python, então throughput por processo é limitado pelo GIL.
  • Bifrost — escrito em Go, feito para throughput alto e overhead mínimo. Menos cobertura de provedor.
  • Portkey — o gateway virou Apache 2.0 em março de 2026; a plataforma de governança em volta continua proprietária, com opção de data plane auto-hospedado.
  • Helicone — observabilidade em primeiro lugar, auto-hospedável, mas em modo de manutenção depois da aquisição pela Mintlify.

Fui de LiteLLM porque cobertura de provedor é o que mais dói quando você já tem dezesseis deles no código.

O overhead, medido

Todo mundo diz que precisa de um gateway. Ninguém diz quanto custa em latência.

Coloquei o LiteLLM na frente de um upstream local compatível com OpenAI que responde em 0,36 ms. O upstream é instantâneo de propósito: assim a diferença medida é o custo da camada, não a latência do provedor.

Antes, isolei a rede. De dentro do container até o upstream: p50 de 0,43 ms. Ou seja, o que aparece abaixo é processamento do LiteLLM, não salto de Docker.

cenário direto via LiteLLM overhead
sequencial, p50 0,36 ms 10,43 ms +10,1 ms
sequencial, p95 0,45 ms 51,54 ms +51,1 ms
10 conexões, p50 2,38 ms 46,95 ms +44,6 ms
10 conexões, p95 3,66 ms 57,03 ms +53,4 ms

Condições: imagem main-stable, 4 workers, config padrão com retry e callback ligados, 200 a 300 requisições por cenário após aquecimento, máquina de desenvolvimento Linux. Com 1 worker o p50 sobe para ~49 ms — a paralelização ajuda no caso sequencial e satura rápido sob concorrência.

Como ler esses números. Uma chamada real de modelo leva de centenas de milissegundos a alguns segundos. Somar 10 a 50 ms nisso é entre 1% e 10% — perceptível num gráfico, invisível para o usuário. Agora, se você roteia para um modelo local que responde em 80 ms, a camada passa a ser um terço do tempo total. Aí a conta muda.

Não aceite meu número. O overhead depende de quantos callbacks você liga, se o cálculo de custo está ativo, e do hardware. Meça no seu caso — é uma tarde de trabalho e evita uma surpresa em produção.

O stack

Seis serviços, mas só dois fazem o trabalho.

LiteLLM + Postgres é o gateway. Postgres guarda chave virtual e gasto acumulado.

Langfuse é a observabilidade: rastro completo de requisição e resposta, custo por trace calculado a partir do uso de token, versionamento de prompt, avaliação. Integra nativamente com o LiteLLM — duas linhas de callback no YAML.

E aqui vai a parte que a documentação não coloca em destaque: o Langfuse 3.x precisa de Postgres, ClickHouse, Redis e storage compatível com S3. Quatro serviços só para observabilidade. Não é "mais um container".

Minha recomendação honesta: comece sem o Langfuse. O painel do próprio LiteLLM já mostra gasto por chave, por modelo e por time, que é o que resolve a primeira pergunta que alguém vai fazer. Adicione o Langfuse quando a pergunta que você precisa responder deixar de caber ali — e nesse momento você vai saber exatamente por que está pagando o custo operacional.

O roteamento, versionado

model_list:
  - model_name: rapido            # classificação, extração, reescrita curta
    litellm_params:
      model: openai/gpt-5-mini
      api_key: os.environ/OPENAI_API_KEY

  - model_name: profundo          # raciocínio, código, tarefa aberta
    litellm_params:
      model: anthropic/claude-sonnet-5
      api_key: os.environ/ANTHROPIC_API_KEY

  - model_name: profundo          # mesmo alias, outro provedor = fallback
    litellm_params:
      model: azure/gpt-5
      api_base: os.environ/AZURE_API_BASE
      api_key: os.environ/AZURE_API_KEY

  - model_name: local             # o que não pode sair da infraestrutura
    litellm_params:
      model: ollama/qwen3:8b
      api_base: http://host.docker.internal:11434

litellm_settings:
  request_timeout: 60             # 657 chamadas da minha varredura não tinham isso
  num_retries: 2
  success_callback: ["langfuse"]

router_settings:
  fallbacks: [{"profundo": ["rapido"]}]

Dois detalhes que valem mais que o resto do arquivo.

O mesmo model_name declarado duas vezes com provedores diferentes é o que faz o fallback existir. Não é configuração extra, é a mesma lista.

E o fallbacks que derruba profundo para rapido: degradar é melhor que ficar indisponível quando a tarefa tolera. Quando não tolera — extração que alimenta um cálculo financeiro, por exemplo — tire essa linha. Fallback silencioso para um modelo mais fraco é pior que erro visível.

Do lado da aplicação

from openai import OpenAI

client = OpenAI(base_url="http://gateway.interno:4000/v1",
                api_key="sk-chave-virtual-do-time")

client.chat.completions.create(model="rapido", messages=[...])

Trocar api.openai.com pelo gateway e o nome do modelo por um alias de tarefa. É a mudança inteira do lado de quem consome.

Chave virtual por time

curl -X POST http://localhost:4000/key/generate \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -d '{"key_alias":"time-faturamento","models":["rapido","profundo"],
       "max_budget":50,"budget_duration":"30d","rpm_limit":60}'

Escopo de modelo, teto de gasto e limite de requisição por time, revogável por uma chamada. É isso que transforma "ninguém sabe quanto gastamos" em uma linha de relatório.

Quando não construir nada disso

Se você tem três aplicações chamando modelo e sabe exatamente quais são, não construa. A camada custa manutenção — Postgres, versão, segredo, mais um ponto de falha no caminho de produção — e não resolve nenhum problema que você tenha hoje. Use a chave do provedor direto e volte a isso quando o número crescer.

Os sinais de que passou da hora são contáveis:

  • mais de cinco aplicações chamando modelo
  • mais de uma chave por provedor em circulação
  • alguém consegue criar uma chave sem pedir para ninguém
  • o gasto mensal chega sem quebra por time ou aplicação
  • exigência contratual ou regulatória sobre para onde o dado vai

Se você marcou dois ou mais, a camada se paga. Se marcou nenhum, ela é infraestrutura procurando um problema.

E, em qualquer caso, o passo zero é o mesmo: rodar o inventário e descobrir o número. Discutir arquitetura de gateway sem saber quantas aplicações existem é desenhar solução para um problema que você ainda não mediu.

O stack completo

docker-compose.yml, litellm-config.yaml, .env.example e o README com os comandos estão publicados. Sobe com docker compose up -d.

Como ajudamos times a adotar IA

Trabalhamos com times de engenharia que buscam incorporar IA ao dia a dia de desenvolvimento — não como experimento, mas como parte real do fluxo de trabalho.

Isso passa por escolher as ferramentas certas para o contexto do time, configurá-las de forma que façam sentido para a política de dados da empresa e garantir que os desenvolvedores saibam usá-las de um jeito que realmente aumente a produtividade, em vez de gerar mais fricção.

Se você tem um time de desenvolvimento e está tentando colocar IA para trabalhar de forma séria, fale com a gente.