Introducción
Cuando falla una solicitud de IA, el cliente solo ve la respuesta HTTP final. Esa respuesta indica que algo salió mal, pero no siempre permite saber si la solicitud estaba mal formada, si el gateway la rechazó o si la rechazó el proveedor del modelo ascendente. La observabilidad consiste en recopilar suficientes pruebas para seguir la solicitud después de que abandona el cliente y explicar qué límite de autorización la gestionó.
AI Gateway registra una entrada por cada solicitud que llega al gateway. Un registro puede mostrar el proveedor, el modelo, el estado HTTP, la duración y el uso de tokens. También puede adjuntar algunos elementos de metadatos personalizados: etiquetas pequeñas que ayudan a localizar una solicitud más adelante. Los metadatos no son una bóveda privada. Este laboratorio solo utiliza un ID de traza aleatorio, un nombre de caso sintético y un valor booleano; nunca una credencial, un prompt, una dirección de correo electrónico ni un ID de cuenta.
Creará un gateway autenticado desechable y después enviará una solicitud de Workers AI deliberadamente mal formada con una etiqueta de traza segura. Localizará su registro fallido, comparará los fallos de autenticación del gateway y del proveedor ascendente, reparará la entrada y confirmará que la misma traza ahora tiene una solicitud correcta. Así, la solución de problemas se basa en pruebas y no en suposiciones.
Si accedió directamente a este curso, complete primero Conectar LabEx con su cuenta de Cloudflare. Esta práctica enseña a usar el terminal de la máquina virtual de LabEx, la autorización del dispositivo de Wrangler, la confirmación de la cuenta de aprendizaje y los ID de cuenta explícitos. Complete también Inferencia de rutas a través de un gateway, porque este laboratorio se basa en sus dos encabezados de autorización independientes.
El laboratorio utiliza el modelo alojado por Cloudflare @cf/meta/llama-3.3-70b-instruct-fp8-fast con la facturación Standard de Workers AI. No se requieren Workers Paid, Unified Billing ni una cuenta de proveedor externo. Las solicitudes son pequeñas y sintéticas. Si la asignación diaria compartida de Workers AI no está disponible, deténgase en lugar de repetir los intentos.
La configuración instala Node.js 22.22.0 y Wrangler 4.132.0 local al proyecto en /home/labex/project/ai-gateway-trace. Prepara evaluaciones independientes de solo lectura, pero no autoriza Wrangler, no crea recursos en la nube ni envía tráfico al modelo. LabEx destruye la máquina virtual temporal cuando termina el laboratorio; aun así, debe eliminar el gateway y el token antes de cerrar sesión, porque la destrucción de la máquina virtual por sí sola no puede eliminar recursos en la nube.
Autorizar la máquina virtual y crear un ID de traza seguro
En este paso, conectará la máquina virtual nueva con su cuenta de aprendizaje y creará los nombres de un gateway desechable y de una traza sintética.
Un ID de traza es una etiqueta compartida por observaciones relacionadas. Debe identificar una solicitud sin revelar lo que dijo el usuario ni quién es. En este laboratorio se genera un valor aleatorio y se almacena junto con los nombres de los recursos, no junto con las credenciales.
Entre en el proyecto preparado, confirme la versión fijada de la CLI y autorice esta máquina virtual:
cd /home/labex/project/ai-gateway-trace
npx wrangler --version
npx wrangler login --device --browser=false --scopes account:read user:read ai:write
Abra el enlace mostrado, introduzca el código y autorice la cuenta de aprendizaje correcta. Confirme la identidad estructurada:
npx wrangler whoami --json
Espere ver Wrangler 4.132.0 y loggedIn: true. Sustituya YOUR_ACCOUNT_ID en el siguiente bloque por el ID real de 32 caracteres que aparece para la cuenta correcta:
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
El ID de traza contiene datos sintéticos seguros. El ID de cuenta y los nombres de los recursos permanecen en el archivo de estado local para que las tareas posteriores de limpieza afecten únicamente a los recursos de este laboratorio.
Crear un gateway autenticado y observable
En este paso, creará un gateway que registre las solicitudes después de que atraviesen su límite de autenticación del cliente.
Abra Cloudflare Dashboard y seleccione AI → AI Gateway → Create gateway → Custom gateway. Use el gatewayId guardado como nombre del gateway. Mantenga activados el registro de solicitudes y la autenticación del gateway. Mantenga desactivados la caché, los límites de velocidad, los límites de gasto y los reintentos, y mantenga activada la facturación de Workers AI en Standard.
Después de crear el gateway, confirme su ID único en la ruta de navegación y abra Settings. El registro crea las pruebas que utilizará en este laboratorio; la autenticación garantiza que un cliente desconocido no pueda generar registros ni consumir uso del modelo.
Seleccione Create an AI Gateway authentication token. Use el tokenName guardado, incluya únicamente la cuenta de aprendizaje correcta y establezca exactamente estos permisos:
- AI Gateway — Run para acceder al gateway autenticado;
- AI Gateway — Edit para leer los registros y eliminar este gateway desechable.
No añada permisos de Workers AI. Wrangler proporciona la credencial ascendente independiente y de corta duración. Cree el token después de revisar la cuenta y los permisos, y guarde su valor de un solo uso sin mostrarlo en pantalla:
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 el recurso exacto mediante la API de administración 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 ver el ID guardado con collect_logs: true y authentication: true.
Enviar una solicitud etiquetada con una entrada no válida
En este paso, creará un fallo controlado de entrada. Las credenciales del gateway y del proveedor ascendente seguirán siendo válidas; solo la entrada del modelo estará mal formada.
Los metadatos personalizados aceptan como máximo cinco valores planos de tipo cadena, número o booleano. Las claves que comienzan por cf. están reservadas por Cloudflare. Esta solicitud utiliza tres valores seguros: el ID de traza aleatorio, el nombre de caso bad-input y synthetic: true.
El modelo seleccionado requiere un prompt. Omítalo deliberadamente mientras guarda la respuesta y el estado 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 o 422. Este es un fallo de entrada del cliente, no una prueba de que exista un problema de autorización. El cuerpo de la respuesta se conserva para una solución de problemas limitada, pero no se muestra automáticamente.
Correlacionar el fallo con su registro del gateway
En este paso, utilizará el ID de traza para encontrar el registro de la solicitud en lugar de buscar únicamente por hora.
Los registros pueden tardar unos instantes en aparecer. Lea el inventario de registros existente mediante la API de administración, analice cada objeto de metadatos plano y muestre solo los campos necesarios para explicar el fallo:
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 ver el ID de traza guardado, case: "bad-input", el proveedor Workers AI y un estado fallido. Los recuentos de tokens pueden estar vacíos porque una entrada no válida puede fallar antes de comenzar la generación. Si la entrada todavía no aparece, espere unos 20 segundos y vuelva a ejecutar este mismo bloque de solo lectura.
Abra la vista Logs del gateway en el Dashboard. Use el filtro de metadatos o la marca de tiempo visible para encontrar la fila fallida y, después, abra su panel de detalles. Confirme que el modelo, el estado fallido y los metadatos personalizados describen la misma solicitud sintética.


Distinguir los fallos de autorización del gateway y del proveedor ascendente
En este paso, cambiará una credencial cada vez. Ambas pruebas pueden devolver 401 o 403, por lo que el estado por sí solo no basta; la ubicación del registro aporta el contexto que falta.
Primero, mantenga válida la credencial ascendente, pero use una credencial no válida del gateway. Un gateway autenticado rechaza esta solicitud antes de que pueda acceder a él y crear el registro etiquetado del proveedor:
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
Ahora mantenga válida la credencial del gateway, pero sustituya únicamente la credencial ascendente de Workers AI. Esta solicitud entra en el gateway y puede dejar un registro fallido del proveedor:
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 o 403 en ambos casos. Espere unos instantes y lea los registros, sin volver a generar solicitudes, para comparar las dos etiquetas:
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
La etiqueta de autenticación incorrecta del gateway no debería tener ningún registro del proveedor; la etiqueta de autenticación incorrecta del proveedor ascendente debería mostrar una fila fallida de Workers AI. Por eso un diagrama de límites y los registros correlacionados proporcionan más información que un estado HTTP por sí solo.

Reparar la solicitud y confirmar que funciona
En este paso, restaurará ambas credenciales válidas y proporcionará el prompt obligatorio. La reparación solo estará completa cuando la salida de ejecución y la observabilidad coincidan.
Use el mismo ID de traza con un nuevo nombre 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 y texto generado no vacío. Si es necesario, espere a que aparezca el registro y vuelva a ejecutar el inventario de registros de solo lectura del paso anterior. En el Dashboard, filtre por el ID de traza y compare bad-input, bad-upstream-auth y repaired. La fila reparada debería mostrar un resultado correcto, un estado 200 y uso de tokens.

Eliminar el gateway desechable
En este paso, eliminará el recurso de la nube mientras la credencial de administración todavía puede demostrar que ya no existe.
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. Este inventario autenticado distingue una eliminación real de una página que no se puede cargar por haber cerrado sesión o por un fallo de red.
Eliminar el token y cerrar sesión
En este paso, revocará la credencial restante en la nube y desconectará la máquina virtual.
En Cloudflare Dashboard, abra My Profile → API Tokens. Busque el tokenName guardado, abra Actions, seleccione Delete, revise la confirmación y elimine únicamente ese token. Ahora es seguro revocarlo porque la eliminación del gateway ya está comprobada.
Borre la copia de la máquina virtual y finalice la autorización independiente de 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 y local gateway token removed. La sesión del Dashboard es independiente y permanece abierta. Cuando termine el laboratorio, LabEx destruirá esta máquina virtual temporal en lugar de guardarla.
Resumen
Utilizó metadatos personalizados seguros para correlacionar una solicitud mal formada de Workers AI con su registro de AI Gateway. Aprendió que un estado HTTP necesita contexto del límite: una autenticación no válida del gateway se rechaza antes de crear un registro del proveedor, mientras que una autorización ascendente no válida aparece como un registro fallido de Workers AI. Después reparó la entrada, confirmó el texto generado y un registro correlacionado correcto, y eliminó todas las credenciales y los recursos desechables.
En el siguiente laboratorio aplicará el mismo enfoque basado en pruebas a la caché. Repetirá una solicitud pública acotada, distinguirá un acierto de caché de una nueva llamada al modelo y omitirá la caché cuando necesite una salida nueva.



