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.ymlcompleto 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.

