Uma grande organização de TI corporativa tem cinco aplicações de IA generativa em produção, onze deployments de modelo espalhados por três subscriptions do Azure, uma fatura mensal em torno de 38.000 euros, e nenhuma forma confiável de responder qual das cinco gastou esse valor. Nada está quebrado. Cada app funciona, cada time entregou, cada revisão de segurança passou na época. O que não existe é um lugar único onde um token seja contado, um chamador seja identificado ou um modelo seja aposentado, e é essa ausência que esta série de dez partes constrói: um gateway de GenAI governado no Azure pelo qual toda aplicação passa, e nada passa por fora.

A empresa, e o que ela está pagando de verdade

Chamando a empresa pelo que ela é: uma organização de TI corporativa estabelecida, cerca de 400 engenheiros em aproximadamente 40 times de produto, a maior parte dos workloads no Azure, um grupo de plataforma que já é dono das landing zones e dos templates de CI. A IA generativa chegou do jeito que costuma chegar, das bordas para dentro. Um assistente de atendimento ao cliente saiu primeiro porque um product owner tinha orçamento. Depois vieram um sumarizador de operações de TI, um assistente interno de código, uma busca de conhecimento de varejo sobre documentação de produto, e uma ferramenta de copy de marketing. Cinco times, cinco decisões, cinco integrações diretas contra o Azure OpenAI.

Cada uma dessas decisões estava correta isoladamente. Juntas, elas produzem uma forma específica e agora familiar:

  • Onze deployments de modelo em três subscriptions. Dois deles são duplicatas do mesmo modelo na mesma região, criadas porque um time não conseguiu quota anexada ao recurso que já tinha.
  • Cerca de 38.000 euros por mês de gasto com modelos que o cost management reporta na granularidade de subscription, o que significa que ele consegue dizer o total ao financeiro e não consegue dizer a nenhum product owner o número dele.
  • Quatro dos cinco apps guardam uma chave nas configurações da aplicação. Um guardava a chave em um repositório até um scanner de segredos encontrá-la. Nenhum app pode ser revogado individualmente sem um engenheiro editar a configuração daquele app.
  • Um aviso de aposentadoria de modelo com 60 dias de prazo chegou por e-mail, e o grupo de plataforma passou dois dias rodando grep nos repositórios para descobrir quais aplicações quebrariam, porque nada registrava qual app chamava qual versão de modelo.

Então veio o incidente que de fato forçou a decisão. Um job em lote da ferramenta de copy de marketing consumiu a maior parte da quota de tokens-per-minute de um deployment compartilhado durante cerca de quarenta minutos. O assistente de atendimento ao cliente, que compartilhava aquele deployment, começou a devolver HTTP 429 para clientes reais. Nenhum dos times fez nada errado. Não havia nenhum mecanismo no caminho onde "um chamador não pode exaurir a quota da qual outro chamador depende" pudesse ser expresso, porque não havia caminho compartilhado nenhum.

Esse é o caso honesto a favor de um gateway. Não "controle central é boa arquitetura". É que quota, atribuição de custo, rotação de credencial e ciclo de vida de modelo são todos propriedades da chamada, e se nenhum componente vê todas as chamadas, nenhuma dessas propriedades pode ser imposta em lugar algum, a não ser por convenção.

O que o padrão por app realmente custa

A integração direta é genuinamente mais barata no primeiro dia. Um client de SDK, uma chave, um endpoint, nenhum time de plataforma no caminho crítico. O custo chega depois e cai em outro lugar que não o time que fez a escolha, e é exatamente por isso que ela continua sendo escolhida.

Os custos que se acumulam são três, e todos são o mesmo custo vestindo roupas diferentes. Custo de mudança: uma aposentadoria de modelo, uma mudança de preço, uma migração de região ou uma indisponibilidade do provedor precisa ser tratada uma vez por aplicação, por cinco times com cinco backlogs e cinco níveis diferentes de interesse. Custo de atribuição: o gasto é visível por recurso e invisível por consumidor, então ninguém pode receber um orçamento, o que significa que ninguém pode receber um limite. Custo de governança: cada controle novo, logging de prompts, redação de PII, uma exigência de transparência do EU AI Act, precisa ser implementado cinco vezes e verificado cinco vezes, e o esforço de revisão escala com o número de aplicações em vez do número de controles.

Um gateway não remove esses custos. Ele os move para um único lugar onde um time de plataforma pode pagá-los uma vez só. Esse é o argumento inteiro, e vale desconfiar de qualquer versão mais rica dele.

Construir versus comprar no Azure

O time avaliou três formas, e a resposta não é a que um engenheiro gostaria que fosse.

Azure API Management como o gateway de IA. O API Management traz um conjunto de capacidades voltadas explicitamente para tráfego de modelos de linguagem, e a lista é mais longa do que a maioria das pessoas imagina antes de lê-la. A policy llm-token-limit impõe tokens-per-minute ou uma quota de tokens por hora, dia, semana, mês ou ano contra qualquer chave de contador, incluindo uma subscription key, um IP de chamador ou uma expressão de policy arbitrária, e consegue pré-calcular os tokens do prompt no próprio gateway, de modo que uma requisição acima do limite nunca chega ao backend. As policies llm-semantic-cache-store e llm-semantic-cache-lookup fazem cache de completions por similaridade vetorial contra o Azure Managed Redis ou outro cache compatível com RediSearch. A policy llm-emit-token-metric emite contagens de tokens para o Application Insights com dimensões customizadas, que é a matéria-prima da atribuição por consumidor. Os backends suportam balanceamento round-robin, ponderado, por prioridade e com afinidade de sessão, além de um circuit breaker cujo tempo de abertura respeita o header Retry-After do próprio backend, então um endpoint pay-as-you-go pode absorver o excedente de um deployment de Provisioned Throughput Unit saturado sem ninguém escrever código de retry.

A cobertura de provedores importa aqui e é fácil errar nela. O API Management faz a mediação de APIs de modelos de linguagem que seguem os schemas OpenAI Chat Completions e Responses, a Anthropic Messages API (nos tiers v2) e a API do Google Vertex AI, contra modelos implantados no Microsoft Foundry ou em provedores fora da Microsoft, incluindo o Amazon Bedrock. Uma unified model API, em preview no momento em que escrevo, expõe vários backends atrás de um único endpoint compatível com OpenAI e traduz os formatos, então um único conjunto de policies de governança vale para todos os provedores. Anthropic Claude, Mistral e Llama ficam acessíveis por essa camada em vez de exigir uma integração separada para cada um.

Um proxy open source no AKS. O LiteLLM e projetos similares entregam tradução de provedores e roteamento em um container totalmente sob seu controle, com um caminho mais rápido até uma feature que você quer e nenhuma dependência de preview. Em troca, você herda uma rotação de plantão para um componente que agora fica na frente de toda requisição de IA da empresa, mais o trabalho de identidade, rede e auditoria que o API Management já tem certificado.

Um serviço FastAPI feito sob medida. Controle máximo, e a única opção em que toda falha é sua. Razoável para um componente com requisitos genuinamente incomuns, o que um reverse proxy que conta tokens não é.

A decisão que esta série segue: o API Management é o data plane, e o que o API Management não faz é construído como um pequeno control plane em Python no AKS. Essa é a divisão que vale internalizar, porque é onde a maioria dos projetos de gateway dá errado. Os times ou tentam expressar tudo como XML de policy, o que produz um artefato que ninguém consegue manter nem testar, ou roteiam o tráfego pelo próprio serviço e reimplementam rate limiting mal feito. O gateway carrega a requisição. O control plane carrega o estado: quais modelos existem, quem pode chamá-los, quanto custa uma chamada, e o que acontece quando um modelo é aposentado.

O que você ainda constrói

Cinco coisas, e cada uma delas é uma parte posterior desta série.

  • Um catálogo de modelos e seu ciclo de vida. Quais nomes lógicos de modelo existem, quais deployments físicos os sustentam, quais estão depreciados e quando desaparecem. As aplicações precisam chamar chat-default, nunca um nome de deployment, ou o e-mail de aposentadoria com 60 dias de prazo volta a ser um projeto de migração de 60 dias.
  • Identidade de tenant e onboarding. Um time recebe uma client credential, uma quota, uma allowlist de modelos e um centro de custo, provisionados como código em vez de como ticket.
  • Atribuição de custo e chargeback. Métricas de token com uma dimensão de tenant são só o insumo. Transformá-las em um número mensal por time que o financeiro aceite é um pipeline de dados com testes próprios.
  • Portões de avaliação no pipeline. Promover uma nova versão de modelo é um deploy. Um deploy que muda o comportamento do modelo sem um resultado de eval anexado é uma indisponibilidade esperando um cliente encontrá-la.
  • Trabalho assíncrono e de longa duração. A sumarização em lote de tickets de suporte não pertence ao mesmo caminho síncrono de um cliente esperando o primeiro token. Essa separação é uma fila, não uma configuração de timeout.

Arquitetura alvo

A plataforma é deliberadamente sem graça e deliberadamente aditiva. Se o control plane cair, o data plane continua servindo tráfego com a última configuração conhecida, porque um gateway que falha fechado numa queda do control plane é uma indisponibilidade da empresa inteira.

graph TD
  subgraph consumers["Consumer apps"]
    A1["customer-service assistant"]
    A2["IT-ops summarizer"]
    A3["code assistant"]
    A4["retail knowledge search"]
    A5["marketing copy tool"]
  end

  subgraph gw["Data plane: API Management"]
    POL["policies:
llm-token-limit, semantic cache,
emit-token-metric, JWT validate"] LB["backend pool:
priority + weighted, circuit breaker"] end subgraph cp["Control plane: Python on AKS"] CAT["model catalog"] TEN["tenant registry"] COST["cost attribution job"] end subgraph models["Model layer"] FDRY["Microsoft Foundry:
GPT deployments, PTU + PAYG"] ANTH["Anthropic Claude"] OSS["Mistral, Llama"] end ID["Microsoft Entra ID"] RED["Azure Managed Redis
semantic cache"] SRCH["Azure AI Search
retrieval"] MON["Azure Monitor +
Application Insights"] A1 --> POL A2 --> POL A3 --> POL A4 --> POL A5 --> POL ID -. "OAuth2 client credentials" .-> POL POL --> LB POL <--> RED LB --> FDRY LB --> ANTH LB --> OSS POL -- token metrics, prompt logs --> MON CAT -. "backend + policy config" .-> gw TEN -. "subscriptions, quotas" .-> gw MON --> COST A4 -. "grounding data" .-> SRCH

Duas propriedades desse diagrama sustentam o peso. Primeira: toda seta que entra na camada de modelos se origina dentro do API Management, o que significa que as regras de rede nos recursos do Foundry negam todo o resto. O gateway não é uma sugestão, é a única rota com caminho. Segunda: o control plane escreve configuração no gateway e lê telemetria do Azure Monitor, mas nunca fica no caminho da requisição. Ele pode ser reimplantado ao meio-dia.

A stack, em um só lugar

O que as dez partes tocam, para que a forma da série fique visível desde já. Infraestrutura como código em Terraform, com a comparação com Bicep e ARM feita honestamente na Parte 2 em vez de assumida de antemão. Imagens Docker e AKS para o control plane. Azure DevOps para pipelines, versionamento e gestão de releases. Python em todo lugar onde a lógica vive. Microsoft Entra ID com OAuth2 client credentials e chaves de API onde um chamador legado não consegue fazer melhor. Azure AI Search e um banco vetorial dedicado para retrieval, comparados em vez de decretados. Azure Managed Redis para cache semântico. Azure Monitor e Application Insights para telemetria, ao lado de observabilidade específica de LLM com LangSmith e Openlayer, e Dataiku onde um time de data science já mora. LangChain para orquestração na única parte em que um framework merece o lugar, e nas partes em que não merece. Streaming por server-sent events, WebSockets onde uma sessão é genuinamente bidirecional, e uma fila de mensagens para tudo que não precisa de resposta agora.

As dez partes, em ordem: o caso a favor de um gateway; Terraform contra Bicep e ARM; a abstração de provedores e streaming; trabalho assíncrono e orientado a eventos; identidade, quota e chargeback; cache semântico; retrieval com Azure AI Search contra um banco vetorial de verdade; orquestração em cima do gateway; CI/CD e ciclo de vida de modelos no Azure DevOps; e observabilidade com governança de IA.

Como é o resultado bom

A parte final volta a estes pontos, que são os quatro números do inventário de trabalho manual tornados mensuráveis:

  • Todo product owner consegue ver o próprio gasto de tokens do mês corrente, no máximo um dia depois de ele ser incorrido, sem pedir ao time de plataforma.
  • Nenhuma aplicação guarda uma credencial de modelo de longa duração. Revogar o acesso de um time é uma mudança de configuração no registro de tenants, não uma edição nas configurações do app daquele time.
  • Um aviso de aposentadoria de modelo produz uma consulta, não uma investigação: o catálogo já sabe quais tenants resolveram para aquele deployment nos últimos 30 dias.
  • Um tenant não consegue exaurir a quota de outro tenant, verificado ao reproduzir o incidente de 429 acima como um teste de carga contra o gateway.
  • A latência mediana adicionada pelo gateway fica abaixo de 60 milissegundos no percentil 95 para chamadas sem cache, e acertos do cache semântico retornam em uma fração de uma chamada de modelo.

Modos de falha para observar desde o primeiro dia

Três, e vale nomeá-los antes de qualquer Terraform ser escrito. O gateway vira um ponto único de falha no momento em que é a única rota, o que é justamente o objetivo, então a meta de disponibilidade dele precisa ser mais alta que a da aplicação mais exigente atrás dele, e o deployment dele precisa ser redundante entre zonas desde o primeiro apply, não depois do primeiro incidente. A proliferação de policies chega em silêncio: XML de policy é código, executa em toda requisição, e é fácil de escrever num lugar onde ninguém revisa. Ele pertence ao controle de versão junto com o resto da plataforma, aplicado por pipeline, nunca editado no portal. E o caminho de bypass derrota todo o resto, porque um único time que mantém uma chave direta para um endpoint do Foundry torna aproximado cada número de atribuição e cada garantia de quota. Isso é uma regra de rede e um alerta, não um documento de política.

Leia isso a seguir

Para o lado de infraestrutura e plataforma de rodar isso em escala, as notas de campo estão em ercan.cloud, e o hub fica em ercanermis.com.

Referências