Rastrear uma solicitação de modelo com falha

CloudflareBeginner
Pratique Agora

Introdução

Quando uma solicitação de IA falha, o chamador vê apenas a resposta HTTP final. Essa resposta informa que algo deu errado, mas nem sempre indica se a solicitação estava malformada, se foi rejeitada pelo gateway ou pelo provedor de modelo upstream. Observabilidade significa coletar evidências suficientes para acompanhar a solicitação depois que ela sai do chamador e explicar qual limite a processou.

O AI Gateway registra uma entrada de log para cada solicitação que chega ao gateway. Um log pode mostrar o provedor, o modelo, o status HTTP, a duração e o uso de tokens. Você também pode anexar alguns itens de metadados personalizados: pequenos rótulos que ajudam a encontrar uma solicitação mais tarde. Metadados não são um cofre privado. Este laboratório usa apenas um ID de rastreamento aleatório, um nome de caso sintético e um sinalizador Booleano — nunca uma credencial, um prompt, um endereço de e-mail ou um ID de conta.

Você criará um gateway autenticado descartável e enviará uma solicitação deliberadamente malformada do Workers AI com um rótulo de rastreamento seguro. Você encontrará o log com falha, comparará falhas de autenticação do gateway e do upstream, corrigirá a entrada e confirmará que o mesmo rastreamento agora tem uma solicitação bem-sucedida. Assim, a solução de problemas passa a se basear em evidências, e não em suposições.

Se você entrou diretamente neste curso, conclua primeiro Connect LabEx to Your Cloudflare Account. Esse laboratório ensina a usar o terminal da VM do LabEx, a autorização de dispositivo do Wrangler, a confirmação da conta de aprendizagem e os IDs de conta explícitos. Conclua também Route Inference Through a Gateway antes deste laboratório, pois este conteúdo depende dos dois cabeçalhos de autorização separados apresentados nele.

O laboratório usa o modelo hospedado pela Cloudflare @cf/meta/llama-3.3-70b-instruct-fp8-fast com o faturamento Standard do Workers AI. Workers Paid, Unified Billing e uma conta de provedor externo não são necessários. As solicitações são pequenas e sintéticas. Se a alocação diária compartilhada do Workers AI estiver indisponível, pare em vez de tentar repetidamente.

A configuração instala Node.js 22.22.0 e o Wrangler 4.132.0, instalado localmente no projeto, em /home/labex/project/ai-gateway-trace. Ela prepara avaliações independentes somente para leitura, mas não autoriza o Wrangler, não cria recursos na nuvem nem envia tráfego ao modelo. O LabEx destrói a VM temporária quando o laboratório termina; mesmo assim, você deverá excluir o gateway e o token antes de sair, porque a destruição da VM não remove recursos da nuvem.

Autorizar a VM e criar um ID de rastreamento seguro

Nesta etapa, você conectará a VM recém-criada à sua conta de aprendizagem e criará nomes para um gateway descartável e um rastreamento sintético.

Um ID de rastreamento é um rótulo compartilhado por observações relacionadas. Ele deve identificar uma solicitação sem expor o que o usuário disse nem quem é o usuário. Este laboratório gera um valor aleatório e o armazena com os nomes dos recursos, não com as credenciais.

Entre no projeto preparado, confirme a CLI fixada e autorize esta VM:

cd /home/labex/project/ai-gateway-trace
npx wrangler --version
npx wrangler login --device --browser=false --scopes account:read user:read ai:write

Abra o link exibido, insira o código e autorize a conta de aprendizagem correta. Confirme a identidade estruturada:

npx wrangler whoami --json

Espere o Wrangler 4.132.0 e loggedIn: true. Substitua YOUR_ACCOUNT_ID abaixo pelo ID real de 32 caracteres exibido para a conta correta:

GATEWAY_ID="labex-c09-g02-$(openssl rand -hex 6)"
TOKEN_NAME="$GATEWAY_ID-token"
TRACE_ID="trace-$(openssl rand -hex 8)"
cat > .labex/state.json <<JSON
{
  "accountId": "YOUR_ACCOUNT_ID",
  "gatewayId": "$GATEWAY_ID",
  "tokenName": "$TOKEN_NAME",
  "traceId": "$TRACE_ID"
}
JSON
cat .labex/state.json

O ID de rastreamento contém dados sintéticos seguros. O ID da conta e os nomes dos recursos permanecem no arquivo de estado local para que a limpeza posterior atinja somente os recursos deste laboratório.

Criar um gateway autenticado e observável

Nesta etapa, você criará um gateway que registra as solicitações depois que elas passam pelo limite de autenticação do chamador.

Abra o Cloudflare Dashboard e escolha AI → AI Gateway → Create gateway → Custom gateway. Use o gatewayId salvo como nome do gateway. Mantenha o registro de solicitações e a autenticação do gateway ativados. Mantenha o cache, os limites de taxa, os limites de gastos e as tentativas novamente desativados, e mantenha o faturamento do Workers AI definido como Standard.

Depois da criação, confirme o ID exclusivo do gateway na trilha de navegação e abra Settings. O registro cria as evidências usadas neste laboratório; a autenticação garante que um chamador desconhecido não possa criar volume de logs nem consumir uso do modelo.

Escolha Create an AI Gateway authentication token. Use o tokenName salvo, inclua somente a conta de aprendizagem correta e defina exatamente estas permissões:

  • AI Gateway — Run para entrar no gateway autenticado;
  • AI Gateway — Edit para ler logs e excluir este gateway descartável.

Não adicione a permissão do Workers AI. O Wrangler fornece a credencial upstream separada e de curta duração. Crie o token depois de revisar a conta e as permissões e, em seguida, armazene o valor de uso único sem exibi-lo:

bash -c '
while :; do
  read -rsp "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
'

Verifique o recurso exato por meio da API de gerenciamento autenticada:

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" \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s),g=b.result||{};console.log(JSON.stringify({success:b.success,id:g.id,collect_logs:g.collect_logs,authentication:g.authentication},null,2))})'
unset GATEWAY_TOKEN

Espere o ID salvo com collect_logs: true e authentication: true.

Enviar uma solicitação marcada com entrada inválida

Nesta etapa, você criará uma falha controlada de entrada. As credenciais do gateway e do upstream permanecem válidas; somente a entrada do modelo estará malformada.

Os metadados personalizados aceitam no máximo cinco valores simples do tipo string, número ou Booleano. As chaves que começam com cf. são reservadas pela Cloudflare. Esta solicitação usa três valores seguros: o ID de rastreamento aleatório, o nome de caso bad-input e synthetic: true.

O modelo selecionado exige um prompt. Omita-o deliberadamente enquanto salva a resposta e o status HTTP:

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')
TRACE_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).traceId')
MODEL='@cf/meta/llama-3.3-70b-instruct-fp8-fast'
METADATA=$(node -e 'process.stdout.write(JSON.stringify({trace_id:process.argv[1],case:"bad-input",synthetic:true}))' "$TRACE_ID")
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(npx wrangler auth token --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))')
STATUS=$(curl --http1.1 -sS -D .labex/bad-input-headers.txt \
  -o .labex/bad-input-response.json -w '%{http_code}' \
  -H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H "cf-aig-metadata: $METADATA" \
  -H 'Content-Type: application/json' \
  --data '{"max_tokens":16}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset GATEWAY_TOKEN UPSTREAM_TOKEN METADATA
printf '%s\n' "$STATUS" | tee .labex/bad-input-status.txt

Espere HTTP 400 ou 422. Essa é uma falha de entrada do cliente, não uma prova de problema de autorização. O corpo da resposta é preservado para uma análise limitada, mas não é exibido automaticamente.

Correlacionar a falha com o log do gateway

Nesta etapa, você usará o ID de rastreamento para encontrar o registro da solicitação, em vez de pesquisar apenas pelo horário.

Os logs podem levar alguns instantes para aparecer. Leia o inventário de logs existente por meio da API de gerenciamento, analise cada objeto de metadados simples e exiba somente os campos necessários para explicar a falha:

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')
TRACE_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).traceId')
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-after-input.json
unset GATEWAY_TOKEN
node - <<'NODE'
const body = require('./.labex/logs-after-input.json')
const trace = require('./.labex/state.json').traceId
const meta = row => {
  try { return typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata || {}) }
  catch { return {} }
}
const matches = (body.result || []).filter(row => meta(row).trace_id === trace && meta(row).case === 'bad-input')
console.log(matches.map(row => ({
  id: row.id,
  provider: row.provider,
  model: row.model,
  success: row.success,
  status_code: row.status_code,
  duration: row.duration,
  tokens_in: row.tokens_in,
  tokens_out: row.tokens_out,
  metadata: meta(row)
})))
if (!matches.some(row => row.success === false)) process.exit(2)
NODE

Espere o ID de rastreamento salvo, case: "bad-input", o provedor Workers AI e um status de falha. As contagens de tokens podem estar vazias porque uma entrada inválida pode falhar antes do início da geração. Se a entrada ainda não estiver visível, aguarde cerca de 20 segundos e execute novamente este mesmo bloco somente para leitura.

Abra a visualização Logs do gateway no Dashboard. Use o filtro de metadados ou o horário visível para encontrar a linha com falha e abra o painel de detalhes. Confirme que o modelo, o status de falha e os metadados personalizados descrevem a mesma solicitação sintética.

Uma linha de log do Workers AI com falha, correlacionada por metadados personalizados seguros

Os detalhes do log com falha exibindo status, duração e os metadados sintéticos de rastreamento

Diferenciar falhas de autorização do gateway e do upstream

Nesta etapa, você alterará uma credencial por vez. Ambos os testes podem retornar 401 ou 403, portanto o status sozinho não é suficiente; a localização do log fornece o contexto que falta.

Primeiro, mantenha a credencial upstream válida, mas use uma credencial de gateway inválida. Um gateway autenticado rejeita essa solicitação antes que ela possa entrar e criar o log marcado do provedor:

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')
TRACE_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).traceId')
MODEL='@cf/meta/llama-3.3-70b-instruct-fp8-fast'
METADATA=$(node -e 'process.stdout.write(JSON.stringify({trace_id:process.argv[1],case:"bad-gateway-auth",synthetic:true}))' "$TRACE_ID")
UPSTREAM_TOKEN=$(npx wrangler auth token --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))')
STATUS=$(curl --http1.1 -sS -o .labex/bad-gateway-auth-response.json -w '%{http_code}' \
  -H 'cf-aig-authorization: Bearer deliberately-invalid-gateway' \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H "cf-aig-metadata: $METADATA" \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"This request must not reach Workers AI.","max_tokens":8}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset UPSTREAM_TOKEN METADATA
printf '%s\n' "$STATUS" | tee .labex/bad-gateway-auth-status.txt

Agora, mantenha a credencial do gateway válida, mas substitua somente a credencial upstream do Workers AI. Essa solicitação entra no gateway e pode deixar um registro de provedor com falha:

METADATA=$(node -e 'process.stdout.write(JSON.stringify({trace_id:process.argv[1],case:"bad-upstream-auth",synthetic:true}))' "$TRACE_ID")
GATEWAY_TOKEN=$(cat .labex/gateway-token)
STATUS=$(curl --http1.1 -sS -o .labex/bad-upstream-auth-response.json -w '%{http_code}' \
  -H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
  -H 'Authorization: Bearer deliberately-invalid-upstream' \
  -H "cf-aig-metadata: $METADATA" \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"This request should reach the upstream authorization check.","max_tokens":8}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset GATEWAY_TOKEN METADATA
printf '%s\n' "$STATUS" | tee .labex/bad-upstream-auth-status.txt

Espere 401 ou 403 em ambos os casos. Aguarde brevemente e leia — não gere novamente — os logs para comparar as duas tags:

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-after-auth.json
unset GATEWAY_TOKEN
node - <<'NODE'
const rows = require('./.labex/logs-after-auth.json').result || []
const trace = require('./.labex/state.json').traceId
const meta = row => { try { return typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata || {}) } catch { return {} } }
for (const name of ['bad-gateway-auth', 'bad-upstream-auth']) {
  const found = rows.filter(row => meta(row).trace_id === trace && meta(row).case === name)
  console.log(name, found.map(row => ({status_code: row.status_code, success: row.success, provider: row.provider})))
}
NODE

A tag de autenticação do gateway não deve ter um log de provedor; a tag de autenticação upstream deve mostrar uma linha com falha do Workers AI. Por isso, um diagrama de limites e logs correlacionados são mais informativos do que um status HTTP isolado.

Os logs do gateway distinguem a falha upstream registrada da rejeição anterior à entrada

Corrigir a solicitação e confirmar o sucesso

Nesta etapa, você restaurará as duas credenciais válidas e fornecerá o prompt obrigatório. Uma correção só estará concluída quando a saída em tempo de execução e a observabilidade estiverem de acordo.

Use o mesmo ID de rastreamento com um novo nome de caso repaired:

METADATA=$(node -e 'process.stdout.write(JSON.stringify({trace_id:process.argv[1],case:"repaired",synthetic:true}))' "$TRACE_ID")
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(npx wrangler auth token --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))')
STATUS=$(curl --http1.1 -sS -o .labex/repaired-response.json -w '%{http_code}' \
  -H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H "cf-aig-metadata: $METADATA" \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"In one short sentence, explain why trace IDs help debugging.","max_tokens":48}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset GATEWAY_TOKEN UPSTREAM_TOKEN METADATA
printf '%s\n' "$STATUS" | tee .labex/repaired-status.txt
node -e 'const b=require("./.labex/repaired-response.json"); console.log(b.result?.response ?? b.result)'

Espere HTTP 200 e um texto gerado não vazio. Se necessário, aguarde o log e execute novamente o inventário de logs somente para leitura da etapa anterior. No Dashboard, filtre pelo ID de rastreamento e compare bad-input, bad-upstream-auth e repaired. A linha corrigida deve indicar sucesso, status 200 e uso de tokens.

A solicitação corrigida aparece como um log bem-sucedido sob o mesmo rastreamento sintético

Excluir o gateway descartável

Nesta etapa, você removerá o recurso da nuvem enquanto a credencial de gerenciamento ainda pode comprovar sua ausência.

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 -X DELETE \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s);if(!b.success)process.exit(1);console.log("gateway deletion accepted")})'
unset GATEWAY_TOKEN

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
node -e 'const b=require("./.labex/gateways-after-delete.json"),id=process.argv[1],found=(b.result||[]).some(g=>g.id===id);console.log("gateway absent:",!found);if(found)process.exit(1)' "$GATEWAY_ID"

Espere gateway absent: true. Esse inventário autenticado diferencia uma exclusão real de uma página ausente causada por logout ou falha de rede.

Excluir o token e sair

Nesta etapa, você revogará a credencial restante na nuvem e desconectará a VM.

No Cloudflare Dashboard, abra My Profile → API Tokens. Encontre o tokenName salvo exatamente, abra Actions, escolha Delete, revise a confirmação e exclua somente esse token. Agora é seguro revogá-lo porque a exclusão do gateway já foi comprovada.

Apague a cópia na VM e encerre a autorização separada do Wrangler:

shred -u .labex/gateway-token
npx wrangler logout
npx wrangler whoami --json || true
test ! -e .labex/gateway-token && echo "local gateway token removed"

Espere loggedIn: false e local gateway token removed. A sessão do Dashboard é separada e continua conectada. Quando o laboratório terminar, o LabEx destruirá esta VM temporária em vez de salvá-la.

Resumo

Você usou metadados personalizados seguros para correlacionar uma solicitação malformada do Workers AI com seu log no AI Gateway. Aprendeu que um status HTTP precisa de contexto de limite: uma autenticação de gateway inválida é rejeitada antes de gerar um log do provedor, enquanto uma autorização upstream inválida aparece como um registro do Workers AI com falha. Em seguida, você corrigiu a entrada, confirmou o texto gerado e um log correlacionado bem-sucedido e removeu todas as credenciais e recursos descartáveis.

O próximo laboratório usa a mesma abordagem baseada em evidências para o cache. Você repetirá uma solicitação pública limitada, diferenciará um acerto de cache de uma nova chamada ao modelo e ignorará o cache quando precisar de uma saída atualizada.