AI Gateway
Construa um gateway local para um assistente que prepara tickets de suporte. O primário e o secundário serão serviços simulados, permitindo testar indisponibilidade, erro definitivo e fallback. A execução da ferramenta ficará fora do roteador, com chave de idempotência, para que mudanças de provedor não multipliquem efeitos.
Use Node e arquivos gateway.cjs, routes.json e report.json. O exercício é offline. Para integrar LiteLLM ou OpenRouter, use um ambiente de teste com credenciais locais, modelos disponíveis e autorização de dados explícita. Registre versões e chamadas reais separadamente. O critério de aceitação é mostrar quotas, limite de tentativas e ausência de ticket duplicado em cenários controlados.
JavaScriptIA & MLAo terminar esta aula
- Fallback preserva capacidade, autorização e limites.
- Retries não devem duplicar efeitos de ferramentas.
- Gateway comum não elimina diferenças entre provedores.
Antes de continuar: Leitura: AI Gateway
Definir o envelope e as capacidades das rotas
FundamentosCrie um envelope com requestId, tenant autenticado, taskClass, deadline e requiredCapabilities. Defina duas rotas de fixture, uma com ferramentas e outra somente textual. Faça o selecionador rejeitar a rota sem ferramentas quando a tarefa exigir proposta estruturada. Acrescente uma política de destinos permitidos por tenant. Uma chave de API válida não autoriza enviar qualquer dado a qualquer provedor. Guarde a decisão em um evento estruturado, incluindo a razão de rejeição. Teste uma requisição válida e outra sem capacidade compatível; a segunda deve terminar sem chamar nenhum serviço.
Executar fallback e impedir efeito duplicado
FundamentosRode o código e confirme effects igual a um mesmo com duas execuções da mesma chave. Depois use a mesma chave com proposta diferente e espere idempotency-conflict. Faça o primário responder com erro definitivo sem retryable: o secundário não deve ser chamado. Conte tentativas em um array de auditoria. Acrescente um timeout simulado depois do efeito e demonstre que a consulta ao ledger retorna o ticket existente. Não mova execute para dentro de cada tentativa do gateway, porque isso mistura repetição de geração e repetição de escrita.
const assert=require('node:assert/strict');
const ledger=new Map();let effects=0;
const primary=async()=>{const e=new Error('unavailable');e.retryable=true;throw e;};
const secondary=async()=>({action:'create_ticket',subject:'consulta'});
async function generate(){
for(const provider of [primary,secondary]){
try{return await provider();}catch(e){if(!e.retryable)throw e;}
}
throw new Error('no-route');
}
function execute(key,proposal){
const signature=JSON.stringify(proposal);
if(ledger.has(key)){
const old=ledger.get(key);
if(old.signature!==signature)throw new Error('idempotency-conflict');
return old.result;
}
const result={ticketId:'ticket-'+(++effects)};
ledger.set(key,{signature,result});return result;
}
(async()=>{
const proposal=await generate();
const a=execute('request-1',proposal),b=execute('request-1',proposal);
assert.deepEqual(a,b);assert.equal(effects,1);
assert.throws(()=>execute('request-1',{action:'other'}),/conflict/);
console.log({a,effects});
})();Aplicar quotas e orçamento total de tentativas
FundamentosImplemente uma quota de duas requisições por tenant na fixture e um máximo de duas rotas por operação. A terceira requisição deve falhar antes da chamada. Uma requisição com deadline vencido deve ter zero tentativas. Para testar backoff sem espera real, injete um relógio e uma função de espera que acumula milissegundos. Verifique que a soma de espera e duração não passa o deadline. Defina política para 429, 503, 401 e esquema inválido. Apenas erros declarados recuperáveis devem continuar, e toda tentativa precisa aparecer no relatório.
Simular balanceamento e falha persistente
FundamentosAdicione duas instâncias equivalentes de uma rota e faça round-robin em seis pedidos, esperando três por instância. Marque uma instância como indisponível e confira que a política evita novas chamadas após o limite de falhas definido. Teste uma sondagem de recuperação antes de reabrir tráfego. Mantenha essa lógica separada da escolha de modelo por qualidade. Insira um erro comum de rede que afeta as duas rotas e confirme término limitado, em vez de loop infinito. O teste comprova o mecanismo local, não uma taxa de disponibilidade externa.
Comparar fallback com baseline e entregar diagnóstico
FundamentosExecute o conjunto de avaliação em modo primário e em modo fallback forçado. Compare schema validity, conclusão, autorização e fundamentação por classe. Nas fixtures, inclua um secundário que retorna prazo incorreto para mostrar que disponibilidade não basta. Para APIs reais, registre tokens, preço consultado e latência de todas as tentativas. Entregue uma tabela de cenários com número de chamadas, rota final, efeito e motivo de parada. A conclusão deve indicar quais classes podem degradar para o secundário e quais são encaminhadas quando o principal falha.
Exercício aplicado
O primário dá timeout após preparar uma proposta, o secundário retorna outra e a ferramenta de ticket recebe a mesma requestId duas vezes. Defina o contrato que evita duplicação e conflito.
- Separe proposta e efeito em etapas distintas.
- Associe idempotencyKey à operação lógica.
- Persista assinatura e resultado do efeito.
- Recuse a mesma chave com proposta diferente.
Abrir resolução comentada
O fallback pode repetir geração, mas a escrita é deduplicada pelo executor. A mesma intenção retorna o ticket já criado; intenção diferente com a mesma chave é conflito e precisa de resolução explícita. Não execute a segunda proposta silenciosamente.
O Map demonstra a regra apenas durante a vida do processo. Para sobreviver a reinício e concorrência, use armazenamento durável, unicidade e transação ou protocolo equivalente. Também preserve orçamento e deadline para que resiliência não se transforme em tentativas ilimitadas.
const assert=require('node:assert/strict');
const ledger=new Map();let effects=0;
const primary=async()=>{const e=new Error('unavailable');e.retryable=true;throw e;};
const secondary=async()=>({action:'create_ticket',subject:'consulta'});
async function generate(){
for(const provider of [primary,secondary]){
try{return await provider();}catch(e){if(!e.retryable)throw e;}
}
throw new Error('no-route');
}
function execute(key,proposal){
const signature=JSON.stringify(proposal);
if(ledger.has(key)){
const old=ledger.get(key);
if(old.signature!==signature)throw new Error('idempotency-conflict');
return old.result;
}
const result={ticketId:'ticket-'+(++effects)};
ledger.set(key,{signature,result});return result;
}
(async()=>{
const proposal=await generate();
const a=execute('request-1',proposal),b=execute('request-1',proposal);
assert.deepEqual(a,b);assert.equal(effects,1);
assert.throws(()=>execute('request-1',{action:'other'}),/conflict/);
console.log({a,effects});
})();Como conferir seu resultado
- Erro definitivo não dispara fallback.
- Quota recusada produz zero chamadas.
- Mesma chave e mesma proposta geram um efeito.
- Chave reaproveitada com proposta alterada falha.
Aplique em um problema novo
Primeiro resolva sem consultar a resposta. Explique suas decisões e guarde a evidência. A conclusão de leitura é independente desta autoavaliação.
Confira seus pré-requisitos
- Definir contrato comum e limites dos provedores.
- Separar fallback de efeito externo.
Primário falha leitura transitoriamente; secundário retorna prioridade: 'extrema' fora do enum normal/alta; terceiro retorna normal. Ticket J8 grava recibo e perde resposta; chega J8 novamente.
Conferir raciocínio e critérios de domínio
Primário não forneceu classificação; secundário é rejeitado por schema; terceiro pode ser aceito se ainda couber no orçamento de tentativas declarado.
O executor consulta J8 e devolve o recibo já gravado. O segundo J8 não cria outro ticket; payload diferente na mesma intenção seria conflito.
Se o limite for 2 tentativas, o terceiro não é chamado e a classificação termina com falha controlada. Mocks não medem disponibilidade/custo de provedores reais.
Evidências para autoavaliação ou revisão por pares
- Schema e fallback: Primário não forneceu classificação; secundário é rejeitado por schema; terceiro pode ser aceito se ainda couber no orçamento de tentativas declarado.
- Reconciliação do ticket: O executor consulta J8 e devolve o recibo já gravado. O segundo J8 não cria outro ticket; payload diferente na mesma intenção seria conflito.
- Limite de tentativas: Se o limite for 2 tentativas, o terceiro não é chamado e a classificação termina com falha controlada. Mocks não medem disponibilidade/custo de provedores reais.
Um erro frequente
Gateway torna todos provedores semanticamente iguais.
Gateway pode padronizar interface sem igualar semântica ou capacidades.
Teste sua compreensão
Responda com suas palavras antes de abrir o comentário. Saber explicar uma decisão é parte do domínio.
1. Um timeout prova que a operação não ocorreu?
2. Balancear instâncias equivale a escolher modelos por qualidade?
3. Dois provedores garantem resiliência?
Não.
Falhas compartilhadas e contratos incompatíveis podem afetar ambas as rotas.
Seu progresso fica salvo neste navegador. Concluir a leitura não substitui demonstrar o domínio nos exercícios.
Referências e aprofundamento
Documentação oficial e trabalhos originais. As referências registram o escopo e as limitações para você conferir o que sustentam.
- Router - Load Balancing
LiteLLM • consulta: 2026-10-06
FundamentosBalanceamento, estratégias por uso/latência/custo, retries, cooldowns e fallbacks entre deployments.
Limites: Routing operacional não garante qualidade sem evals por classe de tarefa; fallback pode mudar comportamento e recursos.
- Provider Routing
OpenRouter • consulta: 2026-10-06
FundamentosSeleção e preferências de provedores, fallback e restrições de roteamento.
Limites: Recursos e políticas dependem do provedor; avaliar qualidade, dados enviados e compatibilidade por rota.
- Budgets, Rate Limits
LiteLLM • consulta: 2026-10-06
FundamentosOrçamentos e limites de requisições/tokens por usuário, chave e equipe.
Limites: Configuração e persistência importam; não citar valores de preço como permanentes.
- Retry pattern
Microsoft • consulta: 2026-10-06
FundamentosRetries de falhas transitórias, política de atrasos, logging e impacto em transações.
Limites: Retries de operações não idempotentes e camadas aninhadas podem duplicar efeitos e ampliar carga.