Recupere com um fallback de modelo

CloudflareBeginner
Pratique Agora

Introdução

Um modelo de IA pode ficar temporariamente indisponível, sobrecarregado ou receber uma entrada que não consegue entender. Um fallback fornece à aplicação uma alternativa planejada, em vez de retornar um erro imediatamente. Um fallback útil é limitado: ele tem uma lista curta e ordenada, além de um ponto claro de encerramento. Ele não deve tentar novamente indefinidamente nem chamar todos os modelos depois que o primeiro tiver sucesso.

Você implantará um pequeno Cloudflare Worker com dois caminhos. O caminho de fallback envia deliberadamente uma entrada no formato de chat para um modelo de embeddings, captura essa incompatibilidade previsível e, em seguida, chama um modelo de chat. O caminho saudável chama um modelo de chat primário compatível e para. Todas as tentativas passam pelo mesmo AI Gateway, portanto os logs mostram qual modelo falhou e qual modelo concluiu a solicitação.

Se você entrou diretamente neste curso, primeiro conclua Conecte o LabEx à sua conta da Cloudflare. Esse laboratório ensina a usar o terminal do LabEx, a autorização de dispositivo do Wrangler, a seleção da conta e o ID da conta. Conclua também Encaminhe a inferência por um gateway antes deste laboratório, pois este exercício se baseia nos conceitos de gateway e Workers AI apresentados nele.

O laboratório usa modelos do Workers AI hospedados pela Cloudflare e o binding do Workers AI. Ele não precisa do Workers Paid, de uma chave de provedor externo nem do Universal Endpoint descontinuado. A tentativa controlada com falha é rejeitada antes da inferência, e cada caminho bem-sucedido gera apenas uma resposta curta. Se a alocação diária compartilhada do Workers AI estiver indisponível, pare em vez de repetir as tentativas.

A configuração instala o Node.js 22.22.0 e o Wrangler 4.132.0 local do projeto em /home/labex/project/ai-gateway-fallback. Ela prepara verificações independentes, mas não autoriza o Wrangler, não cria recursos na nuvem, não implanta um Worker nem envia tráfego para modelos. O LabEx destrói a VM após o laboratório; mesmo assim, você deverá excluir o Worker remoto, o gateway e o token da API, pois destruir uma VM não remove recursos da nuvem.

Autorize a VM e nomeie o caminho de recuperação

Cada laboratório começa em uma VM nova. Nesta etapa, você autorizará o Wrangler a usar sua conta de aprendizado e salvará nomes exclusivos para um gateway, um Worker e um token temporário.

cd /home/labex/project/ai-gateway-fallback
npx wrangler --version
npx wrangler login --device --browser=false

Abra o link exibido, informe o código e autorize a conta de aprendizado desejada. O Wrangler solicitará as permissões de implantação do Worker e do Workers AI necessárias mais adiante neste laboratório; verifique a conta exibida antes de aprovar. Em seguida, consulte os dados estruturados de identidade:

npx wrangler whoami --json

Espere ver o Wrangler 4.132.0 e loggedIn: true. Substitua YOUR_ACCOUNT_ID pelo ID real de 32 caracteres mostrado para a conta desejada:

GATEWAY_ID="labex-c09-g05-$(openssl rand -hex 6)"
WORKER_NAME="${GATEWAY_ID/g05/g05-worker}"
TOKEN_NAME="$GATEWAY_ID-token"
cat > .labex/state.json <<JSON
{
  "accountId": "YOUR_ACCOUNT_ID",
  "gatewayId": "$GATEWAY_ID",
  "workerName": "$WORKER_NAME",
  "tokenName": "$TOKEN_NAME"
}
JSON
cat .labex/state.json

Esses identificadores não são segredos. Registrá-los faz com que as verificações e a limpeza posteriores tenham como alvo apenas os recursos deste laboratório.

Crie um AI Gateway observável

Nesta etapa, você criará o ponto de controle compartilhado que registra as duas rotas de modelo.

Um AI Gateway é um ponto de controle nomeado entre uma aplicação e as chamadas de modelos. Ele concentra os logs e metadados de várias tentativas, mesmo quando a aplicação muda de modelo.

Abra o Cloudflare Dashboard e escolha AI → AI Gateway → Create a custom gateway. Use o gatewayId salvo. Mantenha Collect Logs e Authenticated Gateway habilitados. Mantenha o cache, os limites de taxa, as tentativas e os limites de gastos desativados, e mantenha o faturamento do Workers AI em Standard. Em seguida, crie o gateway.

O gateway salvo mantém o registro de logs e o acesso autenticado habilitados

Abra My Profile → API Tokens, escolha Create Token → Create Custom Token e use o tokenName salvo. Adicione as permissões da conta AI Gateway — Edit e AI Gateway — Run, limitadas à conta de aprendizado desejada. Esse token temporário permite que o laboratório leia e depois exclua apenas o gateway dele; o binding de IA do Worker implantado não o incorpora.

Depois de criar o token, copie somente o valor após Bearer do comando de verificação de uso único da Cloudflare e armazene-o usando uma entrada oculta:

bash -c '
while :; do
  read -ersp "Paste the AI Gateway token: " GATEWAY_TOKEN
  printf "\n"
  [ -n "$GATEWAY_TOKEN" ] && break
  printf "Token cannot be empty; paste it again.\n" >&2
done
umask 077
printf "%s" "$GATEWAY_TOKEN" > .labex/gateway-token
unset GATEWAY_TOKEN
chmod 600 .labex/gateway-token
'

Leia novamente apenas as configurações importantes que não são secretas:

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
  > .labex/gateway.json
unset GATEWAY_TOKEN
node -e 'const g=require("./.labex/gateway.json").result; console.log({id:g.id,collect_logs:g.collect_logs,authentication:g.authentication})'

Espere ver o ID do gateway salvo, com os dois valores definidos como true.

Defina um Worker com duas tentativas

Nesta etapa, você escreverá a política de recuperação no código comum de um Worker. A política faz duas chamadas explícitas em vez de usar um loop, portanto o custo e a latência máximos ficam fáceis de visualizar.

A primeira chamada do caminho de fallback usa um modelo de embeddings. Modelos de embeddings transformam texto em vetores numéricos; eles não aceitam messages de chat. Fornecer uma entrada no formato de chat cria uma falha de compatibilidade segura e determinística antes da inferência. O bloco catch registra essa falha e faz uma chamada para um modelo de chat compatível.

GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
WORKER_NAME=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).workerName')
cat > wrangler.jsonc <<JSON
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-09-17",
  "ai": { "binding": "AI" }
}
JSON
cat > src/index.js <<JS
export default {
  async fetch(request, env) {
    const healthy = new URL(request.url).pathname === "/healthy";
    const attempts = [];
    const gateway = {
      gateway: {
        id: "$GATEWAY_ID",
        metadata: {
          lab: "g05-fallback",
          mode: healthy ? "healthy" : "fallback",
          synthetic: true
        }
      }
    };

    if (!healthy) {
      try {
        await env.AI.run(
          "@cf/baai/bge-small-en-v1.5",
          { messages: [{ role: "user", content: "Reply with ROUTE OK" }] },
          gateway
        );
        attempts.push({ model: "@cf/baai/bge-small-en-v1.5", status: "unexpected-success" });
      } catch (error) {
        attempts.push({
          model: "@cf/baai/bge-small-en-v1.5",
          status: "failed",
          reason: String(error).slice(0, 180)
        });
      }
    }

    const selectedModel = healthy
      ? "@cf/meta/llama-3.3-70b-instruct-fp8-fast"
      : "@cf/meta/llama-3.2-3b-instruct";
    const result = await env.AI.run(
      selectedModel,
      { prompt: "Reply with exactly: ROUTE OK", max_tokens: 12 },
      gateway
    );
    attempts.push({ model: selectedModel, status: "succeeded" });

    return Response.json({
      mode: healthy ? "healthy-primary" : "fallback-recovery",
      usedFallback: !healthy,
      selectedModel,
      attempts,
      response: result.response
    });
  }
};
JS
npx wrangler deploy --dry-run

O binding de IA dá ao Worker acesso direto ao Workers AI. A opção gateway encaminha cada chamada pelo gateway salvo e adiciona apenas metadados sintéticos — nunca um prompt, uma credencial ou um identificador de pessoa.

Implante e exercite o caminho de fallback

Nesta etapa, você implantará o Worker e acionará uma vez o caso de recuperação controlada.

Implante o Worker e salve a saída do Wrangler para que o teste use a URL exata atribuída à sua conta:

npx wrangler deploy 2>&1 | tee .labex/deploy-output.txt
WORKER_URL=$(grep -Eo 'https://[^ ]+\.workers\.dev' .labex/deploy-output.txt | tail -1)
printf '%s\n' "$WORKER_URL" | tee .labex/worker-url.txt

A rota workers.dev pode levar alguns segundos para ser propagada após uma implantação bem-sucedida. Consulte a URL sem enviar tráfego adicional para modelos: um 404 indica apenas que a rota de borda ainda não está pronta, e o loop para na primeira resposta 200.

WORKER_URL=$(cat .labex/worker-url.txt)
for attempt in $(seq 1 12); do
  STATUS=$(curl --http1.1 -sS -o .labex/fallback-response.json -w '%{http_code}' "$WORKER_URL/fallback")
  printf 'attempt %s: HTTP %s\n' "$attempt" "$STATUS"
  [ "$STATUS" = 200 ] && break
  [ "$attempt" -eq 12 ] && exit 1
  sleep 5
done
python3 -m json.tool < .labex/fallback-response.json

Espere ver usedFallback: true, duas tentativas, o modelo de embeddings marcado como failed e @cf/meta/llama-3.2-3b-instruct marcado como succeeded. O texto gerado não é avaliado exatamente; o que importa é a decisão de roteamento.

Comprove que um modelo primário saudável para cedo

Nesta etapa, você mostrará que um modelo primário bem-sucedido impede uma chamada de fallback desnecessária.

Um fallback só está correto se não interferir quando o caminho primário funciona. O caminho /healthy começa com um modelo de chat compatível, portanto deve produzir uma tentativa e parar.

WORKER_URL=$(cat .labex/worker-url.txt)
curl --http1.1 -fsS "$WORKER_URL/healthy" \
  | tee .labex/healthy-response.json \
  | python3 -m json.tool

Espere ver usedFallback: false, @cf/meta/llama-3.3-70b-instruct-fp8-fast como selectedModel e exatamente uma tentativa bem-sucedida. Esse é o comportamento de short-circuit: o sucesso encerra a rota imediatamente.

Leia a rota nos logs do gateway

Nesta etapa, você conectará os resultados JSON do Worker a evidências independentes do AI Gateway.

A resposta do Worker descreve o comportamento da aplicação. Os logs do AI Gateway fornecem evidências independentes do lado do provedor. Os logs podem levar alguns segundos para aparecer; aguarde brevemente e exiba apenas os campos relevantes para o roteamento:

sleep 8
ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID/logs?per_page=50" \
  > .labex/logs.json
unset GATEWAY_TOKEN
node - <<'NODE'
const rows=require('./.labex/logs.json').result||[];
const meta=row=>{try{return typeof row.metadata==='string'?JSON.parse(row.metadata):(row.metadata||{})}catch{return {}}};
console.table(rows.filter(row=>meta(row).lab==='g05-fallback').map(row=>({
  mode:meta(row).mode, model:row.model, success:row.success, status:row.status_code
})));
NODE

Abra a página Logs do gateway no Dashboard. O grupo de fallback deverá conter uma linha do modelo de embeddings com falha e uma linha do modelo de fallback bem-sucedida. O grupo saudável deverá conter apenas o modelo de chat primário bem-sucedido.

Os logs do gateway mostram a tentativa do modelo primário com falha seguida pela conclusão bem-sucedida do fallback

A solicitação saudável contém um único log bem-sucedido do modelo primário

Os metadados mode conectam as linhas sem incluir um prompt ou segredo. O modelo, o sucesso e o status explicam a rota; o texto gerado, por si só, não explica.

Inspecione o contrato de recuperação limitado

Nesta etapa, você comparará os dois caminhos e informará o número máximo de tentativas de modelo.

Agora você tem três formas correspondentes de evidência:

  • o código-fonte contém duas chamadas explícitas a env.AI.run() e nenhum loop de repetição;
  • /fallback informa uma falha seguida de um sucesso;
  • /healthy informa um sucesso e para.

Exiba uma comparação compacta a partir das respostas salvas:

node - <<'NODE'
for (const name of ['fallback','healthy']) {
  const body=require(`./.labex/${name}-response.json`);
  console.log(name, {
    usedFallback: body.usedFallback,
    selectedModel: body.selectedModel,
    attemptCount: body.attempts.length,
    statuses: body.attempts.map(item=>item.status)
  });
}
NODE

O máximo é de duas tentativas. Se o fallback também falhar, o Worker retornará um erro em vez de reiniciar a rota. Em uma aplicação de produção, você poderia adicionar um tempo limite, um disjuntor ou um erro amigável para o usuário, mas cada mecanismo de recuperação adicional deverá continuar limitado e observável de forma independente.

Remova os recursos descartáveis

Nesta etapa, você excluirá todos os recursos remotos pertencentes a este laboratório e removerá a autorização local.

Exclua primeiro o Worker para impedir que ele crie novo tráfego no gateway. Em seguida, exclua apenas o gateway registrado em state.json:

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
WORKER_NAME=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).workerName')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
npx wrangler delete --name "$WORKER_NAME" --force
curl --http1.1 -fsS -X DELETE \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
  > .labex/delete-gateway.json
unset GATEWAY_TOKEN
node -p 'require("./.labex/delete-gateway.json").success'

Espere ver true. Enquanto as duas autorizações temporárias ainda existirem nesta VM, salve evidências independentes da ausência do Worker e do gateway:

set +e
npx wrangler deployments list --name "$WORKER_NAME" --json \
  > .labex/worker-after-delete.json 2> .labex/worker-absent.err
printf '%s\n' "$?" > .labex/worker-absent-status.txt
set -e
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways" \
  > .labex/gateways-after-delete.json
unset GATEWAY_TOKEN
GATEWAY_ID="$GATEWAY_ID" node - <<'NODE'
const rows=require('./.labex/gateways-after-delete.json').result||[];
console.log('gateway absent:', !rows.some(row=>row.id===process.env.GATEWAY_ID));
NODE
grep -Ei '10090|10007|script_not_found|does not exist' .labex/worker-absent.err

Espere ver gateway absent: true e uma resposta indicando a ausência do Worker, como script_not_found, o código 10090, o código 10007 ou does not exist. O Wrangler pode usar formatos de erro diferentes para o mesmo script ausente; erros de rede e autenticação não comprovam a exclusão.

Agora abra My Profile → API Tokens e exclua exatamente o tokenName salvo. Por fim, remova a cópia dele na VM e encerre a sessão:

shred -u .labex/gateway-token
npx wrangler logout
npx wrangler whoami --json

Espere ver loggedIn: false. Excluir a VM posteriormente removerá os arquivos locais, mas somente esses comandos removem os recursos remotos e revogam a autorização.

Resumo

Você criou um caminho de recuperação limitado com dois modelos hospedados pela Cloudflare. Uma tentativa primária incompatível e controlada falhou, um modelo de fallback recuperou a solicitação e um modelo primário saudável parou após uma única chamada. Os logs do AI Gateway conectaram as decisões da aplicação às evidências do modelo e do status no lado do provedor. Você também aprendeu por que limites explícitos de tentativas, metadados seguros e uma limpeza verificada fazem parte de um design confiável de fallback.