Agent ArenaClickHouse Workshops

05 Cerrar el ciclo

Convierte un fallo de producción revisado en datos dorados, un evaluator calibrado de políticas de negocio y protección para el tráfico futuro.

Punto de partida

El Módulo 04 terminó con una anotación humana completada para el chat_turn autoritativo del Módulo 03. Ten a mano el SQL corregido y la hoja de procedencia:

source=production-feedback
source_trace_id=<authoritative Chat trace ID>
failure_category=stale-business-policy
source_policy_version=policy-v1
annotation_id=<completed task ID when available>

La traza original de producción tiene sql-execution-success=true y user-thumbs=false. El pulgar hacia abajo encontró una traza que merecía revisión; la anotación completada aportó el diagnóstico y la verdad de referencia corregida.

El ciclo continuo de evaluación y mejora

Este módulo completa una vuelta del ciclo:

  1. el feedback del usuario revela un punto ciego del evaluator online actual;
  2. una persona investiga y aprueba una corrección;
  3. el incidente revisado amplía el dataset dorado;
  4. las versiones de referencia y candidata se ejecutan sobre el mismo dataset ampliado;
  5. un evaluator general se calibra offline antes de habilitarlo online; y
  6. el tráfico futuro sigue recopilando tanto puntuaciones del evaluator como feedback de usuarios.

El último paso es importante: publicar un evaluator mejor no pone fin al feedback. Un evaluator solo puede medir las dimensiones representadas en su catálogo de políticas y su prompt. Un futuro 👎 puede revelar otra política ausente, una petición ambigua o un nuevo modo de fallo, e iniciar el mismo ciclo otra vez.

Objetivo

Superar cinco puertas de pruebas: promover, referencia, candidato, calibrar y, por último, habilitar y reproducir. Usa el ganador del Módulo 02 en ambos experimentos, de modo que la versión de política sea el único cambio de tratamiento intencionado.

Ejecuta todos los comandos siguientes desde ClickHouse_Demos/workshops/agent_arena:

cd ClickHouse_Demos/workshops/agent_arena
source .env
export WINNER_MODEL="${WINNER_MODEL:-qwen3.7-flash}"
export WINNER_PROMPT="${WINNER_PROMPT:-P2_fewshot}"
export WINNER_CONFIG_ID="${WINNER_CONFIG_ID:-qwen3.7-flash__P2_fewshot}"

Los valores predeterminados corresponden al ganador verificado del taller. Si tu grupo eligió otro config_id, ajusta los tres valores al modelo y prompt correspondientes y no los cambies en ninguna puerta.

Puerta de pruebas 1 — Promover el incidente revisado

Crea reviewed.json en la raíz del laboratorio con los tres registros siguientes. Sustituye en todas partes los dos valores de ejemplo antes de ejecutar la promoción. Si Langfuse no muestra un ID de tarea de anotación, elimina annotation_id de los tres registros en vez de dejar el placeholder; ese campo es opcional, mientras que los demás campos de procedencia de producción son obligatorios.

[
  {
    "id": "prod-active-001",
    "question": "How many active customers do we have?",
    "golden_sql": "SELECT uniqExact(customer_id) FROM v_orders WHERE order_ts >= now() - INTERVAL 30 DAY AND status NOT IN ('cancelled', 'returned')",
    "tier": 2,
    "ordered": false,
    "source": "production-feedback",
    "source_trace_id": "<paste the Module 03 Chat trace ID>",
    "failure_category": "stale-business-policy",
    "source_policy_version": "policy-v1",
    "annotation_id": "<paste the completed task ID>"
  },
  {
    "id": "prod-active-002",
    "question": "What is our active customer count right now?",
    "golden_sql": "SELECT uniqExact(customer_id) FROM v_orders WHERE order_ts >= now() - INTERVAL 30 DAY AND status NOT IN ('cancelled', 'returned')",
    "tier": 2,
    "ordered": false,
    "source": "production-feedback",
    "source_trace_id": "<paste the Module 03 Chat trace ID>",
    "failure_category": "stale-business-policy",
    "source_policy_version": "policy-v1",
    "annotation_id": "<paste the completed task ID>"
  },
  {
    "id": "prod-active-003",
    "question": "How many customers qualify as active under our business definition?",
    "golden_sql": "SELECT uniqExact(customer_id) FROM v_orders WHERE order_ts >= now() - INTERVAL 30 DAY AND status NOT IN ('cancelled', 'returned')",
    "tier": 2,
    "ordered": false,
    "source": "production-feedback",
    "source_trace_id": "<paste the Module 03 Chat trace ID>",
    "failure_category": "stale-business-policy",
    "source_policy_version": "policy-v1",
    "annotation_id": "<paste the completed task ID>"
  }
]

Solo prod-active-001 es la pregunta exacta de la traza de feedback. prod-active-002 y prod-active-003 son paráfrasis escritas por el revisor a partir del mismo incidente investigado. Usan la misma traza de origen y la misma anotación completada para mantener la auditabilidad; no son dos trazas adicionales de feedback de producción. Las tres entradas invocan intencionadamente la métrica gobernada de clientes activos, de modo que la referencia no pueda parecer correcta gracias a recuentos no relacionados.

Promueve el lote revisado:

source .env
.venv/bin/python -m scripts.promote_to_golden reviewed.json

Espera tres líneas prepared prod-active-* seguidas de:

promoted 3 question(s) into the 'arena-golden' dataset

Abre Langfuse → Datasets → arena-golden e inspecciona los metadatos de cada elemento nuevo. Verifica source=production-feedback, el mismo source_trace_id real, failure_category=stale-business-policy y source_policy_version=policy-v1.

El corpus fuente contiene 20 preguntas YAML. q019 y q020 son ejemplos few-shot reservados, por lo que un proyecto limpio comienza con 18 elementos de experimento en arena-golden. Esta promoción de tres elementos lleva el dataset limpio a 21. Un proyecto reutilizado puede contener más elementos aprobados; registra su procedencia en vez de eliminarlos para forzar un número y exige que referencia y candidato usen los mismos ID.

reviewed.json es estado mutable e ignorado del operador y constituye la ruta principal del taller. El archivo versionado --synthetic-fixture es únicamente una alternativa reproducible para ensayos. No representa una anotación humana ni satisface esta puerta. Ambos modos son mutuamente excluyentes; nunca ejecutes la alternativa sintética después de una promoción auténtica.

La promoción valida el lote completo, el SQL de solo lectura y la procedencia requerida antes de consultar ClickHouse o escribir elementos. Después lee los metadatos existentes y rechaza un ID que colisione con otra procedencia de producción. Si ese preflight autenticado no puede establecer la procedencia con seguridad, se detiene sin escribir. Repetir una promoción auténtica solo es seguro cuando la procedencia que colisiona es idéntica.

Puerta de pruebas 2 — Ejecutar la referencia policy-v1

Primero aprovisiona el juez basado en catálogo para los experimentos. Esto crea su regla online de observaciones en estado deshabilitado:

source .env
.venv/bin/python -m scripts.provision_online_evaluators \
  --business-policy-experiments

Espera experiment rule enabled=True; online rule enabled=False. Antes de continuar, confirma en Langfuse que la regla online sigue deshabilitada.

Asigna a este intento un sufijo único y ejecuta el modelo y prompt seleccionados sobre el dataset ampliado con la política obsoleta:

export LOOP_RUN_SUFFIX="${LOOP_RUN_SUFFIX:-$(date +%Y%m%d-%H%M%S)}"
export BASELINE_RUN_ID="online-loop-baseline-${LOOP_RUN_SUFFIX}"
export CANDIDATE_RUN_ID="online-loop-candidate-${LOOP_RUN_SUFFIX}"

.venv/bin/python -m eval.harness --run-id "$BASELINE_RUN_ID" \
  --policy-version policy-v1 --models "$WINNER_MODEL" --prompts "$WINNER_PROMPT" \
  --wait-for-score business-policy-adherence

El harness añade --policy-v1 al ID de la versión. Espera tres nombres exactos de puntuación en cada traza: correctness, agent-arena-llm-judge y business-policy-adherence. No continúes si se agota el tiempo o falta alguna puntuación.

En Experiments de Langfuse, registra el número de elementos y la corrección agregada de la referencia. En un proyecto limpio debe haber 21 elementos tras la promoción. Los proyectos reutilizados pueden tener más elementos aprobados y las respuestas del proveedor pueden variar, por lo que la puerta de publicación es la comparación emparejada siguiente y no una cifra agregada fija.

Puerta de pruebas 3 — Ejecutar el candidato policy-v2

Sin cambiar el dataset, el modelo, el prompt ni el sufijo, ejecuta el candidato:

.venv/bin/python -m eval.harness --run-id "$CANDIDATE_RUN_ID" \
  --policy-version policy-v2 --models "$WINNER_MODEL" --prompts "$WINNER_PROMPT" \
  --wait-for-score business-policy-adherence

Registra el agregado real del candidato, compara ambas ejecuciones en Langfuse y exige:

  • ID y recuentos de elementos de dataset idénticos;
  • los tres elementos prod-active-* pasan de correctness=0 con policy-v1 a correctness=1 con policy-v2;
  • se compara por elemento todo lo anterior a prod-active-*, sin ninguna regresión de correctness=1 a correctness=0; y
  • la corrección agregada del candidato no es inferior a la referencia.

Detente si empeora un elemento preexistente. Un candidato que corrige el incidente rompiendo comportamiento conocido no supera la puerta de publicación.

Puerta de pruebas 4 — Calibrar un juez general de políticas

business-policy-adherence no es un «evaluator de clientes activos». Recibe la pregunta, el SQL generado y el catálogo completo de métricas policy-v2. Determina qué métrica gobernada se aplica y devuelve PASS, FAIL o NOT_APPLICABLE. El mismo diseño comprueba clientes activos, ingresos, conversión y margen bruto sin crear un evaluator por formulación.

Antes de habilitarlo para observaciones de producción, inspecciona estos elementos de experimento:

Prueba de calibraciónEjecución/elementobusiness-policy-adherence requerido
SQL obsoleto de clientes activosreferencia prod-active-001FAIL
SQL corregido de clientes activoscandidato prod-active-001PASS
política de ingresoscandidato q005PASS
política de conversión de vista a compracandidato q018PASS
recuento simple de clientescandidato q001NOT_APPLICABLE

Repite la comprobación de clientes activos para prod-active-002 y prod-active-003. Lee tanto el razonamiento como la categoría: debe identificar la política aplicable del catálogo y evaluar respecto de ella el SQL generado. Un recuento sencillo debe seguir siendo NOT_APPLICABLE, lo que demuestra que el juez no fuerza todas las preguntas de recuento a la política de clientes activos.

Mantén deshabilitada la regla online si alguna categoría es incorrecta, falta una puntuación, la salida estructurada está mal formada o la comparación de corrección presenta una regresión. La calibración offline viene primero porque permite inspeccionar aprobaciones y fallos falsos sobre ejemplos conocidos antes de que el evaluator influya en la monitorización de producción.

Puerta de pruebas 5 — Habilitar y reproducir en policy-v2

Solo después de superar todas las puertas de calibración, habilita la regla de observaciones:

source .env
.venv/bin/python -m scripts.provision_online_evaluators \
  --enable-business-policy-online

Espera el nombre exacto agent-arena-business-policy-online con enabled=True. El comando se cierra ante un fallo si no encuentra una puntuación de experimento business-policy-adherence limitada al dataset; las comprobaciones manuales anteriores siguen siendo la puerta de calidad.

Detén el servidor policy-v1. En el primer terminal, inicia el candidato y déjalo activo:

source .env
AGENT_ARENA_POLICY_VERSION=policy-v2 \
  .venv/bin/uvicorn serving.api:app --port 8100

En el segundo terminal, define un auxiliar que reciba una pregunta y devuelva el ID de su traza solo después de confirmar una respuesta policy-v2 correcta:

source .env
export WINNER_CONFIG_ID="${WINNER_CONFIG_ID:-qwen3.7-flash__P2_fewshot}"
ask_trace() {
  local question="$1"
  local body
  body=$(.venv/bin/python -c \
    'import json,sys; print(json.dumps({"question": sys.argv[1], "config_id": sys.argv[2]}))' \
    "$question" "$WINNER_CONFIG_ID")
  curl -fsS http://localhost:8100/ask \
    -H 'content-type: application/json' -d "$body" | \
    .venv/bin/python -c \
    'import json,sys; data=json.load(sys.stdin); assert data["policy_version"] == "policy-v2" and data["outcome"] == "ok"; print(data["trace_id"])'
}

Formula una vez las preguntas de clientes activos e ingresos. Las puntuaciones online de observaciones usan el nombre de regla agent-arena-business-policy-online, no el nombre de puntuación de los experimentos:

ACTIVE_TRACE=$(ask_trace "How many active customers do we have?")
.venv/bin/python -m scripts.verify_online_scores "$ACTIVE_TRACE" \
  sql-execution-success=true agent-arena-business-policy-online=PASS

REVENUE_TRACE=$(ask_trace "What was revenue in the last 30 days?")
.venv/bin/python -m scripts.verify_online_scores "$REVENUE_TRACE" \
  sql-execution-success=true agent-arena-business-policy-online=PASS

La pregunta de conversión tiene un límite estocástico verificado. Formúlala una vez y conserva la traza. Si el resultado del servicio no es ok, o faltan o fallan las puntuaciones exactas, reintenta la misma pregunta y configuración como máximo una vez. Este bloque mantiene visibles ambos intentos:

ask_conversion() {
  local body
  body=$(.venv/bin/python -c \
    'import json,sys; print(json.dumps({"question": sys.argv[1], "config_id": sys.argv[2]}))' \
    "What is our view-to-purchase conversion rate for the last 7 days?" \
    "$WINNER_CONFIG_ID")
  curl -fsS http://localhost:8100/ask \
    -H 'content-type: application/json' -d "$body" | \
    .venv/bin/python -c \
    'import json,sys; data=json.load(sys.stdin); assert data["policy_version"] == "policy-v2"; print("\t".join((data["trace_id"], data["outcome"])))'
}

IFS=$'\t' read -r CONVERSION_TRACE_1 CONVERSION_OUTCOME_1 <<< \
  "$(ask_conversion)"
if .venv/bin/python -m scripts.verify_online_scores "$CONVERSION_TRACE_1" \
  sql-execution-success=true agent-arena-business-policy-online=PASS; then
  CONVERSION_SCORES_1=pass
else
  CONVERSION_SCORES_1=fail
fi
if [ "$CONVERSION_OUTCOME_1" = ok ] && [ "$CONVERSION_SCORES_1" = pass ]; then
  CONVERSION_RESULT_1=pass
else
  CONVERSION_RESULT_1=fail
fi
printf 'conversion_attempt=1 trace_id=%s outcome=%s exact_scores=%s result=%s\n' \
  "$CONVERSION_TRACE_1" "$CONVERSION_OUTCOME_1" \
  "$CONVERSION_SCORES_1" "$CONVERSION_RESULT_1"

CONVERSION_TRACE_2=not-run
CONVERSION_OUTCOME_2=not-run
CONVERSION_SCORES_2=not-run
CONVERSION_RESULT_2=not-run
if [ "$CONVERSION_RESULT_1" != pass ]; then
  IFS=$'\t' read -r CONVERSION_TRACE_2 CONVERSION_OUTCOME_2 <<< \
    "$(ask_conversion)"
  if .venv/bin/python -m scripts.verify_online_scores "$CONVERSION_TRACE_2" \
    sql-execution-success=true agent-arena-business-policy-online=PASS; then
    CONVERSION_SCORES_2=pass
  else
    CONVERSION_SCORES_2=fail
  fi
  if [ "$CONVERSION_OUTCOME_2" = ok ] && [ "$CONVERSION_SCORES_2" = pass ]; then
    CONVERSION_RESULT_2=pass
  else
    CONVERSION_RESULT_2=fail
  fi
fi
printf 'conversion_attempt=2 trace_id=%s outcome=%s exact_scores=%s result=%s\n' \
  "$CONVERSION_TRACE_2" "$CONVERSION_OUTCOME_2" \
  "$CONVERSION_SCORES_2" "$CONVERSION_RESULT_2"

if [ "$CONVERSION_RESULT_1" != pass ] && \
   [ "$CONVERSION_RESULT_2" != pass ]; then
  printf '%s\n' \
    'STOP: conversion failed twice; preserve both traces and investigate.' >&2
  false
fi

No reintentes hasta que funcione. Si ambos intentos fallan, conserva las dos trazas, mantén visible el resultado y canaliza las nuevas pruebas mediante anotación humana, mejora de datos dorados y el mismo ciclo de calibración emparejada.

Solo cuando la conversión funcione, formula una vez la pregunta de recuento sencillo:

PRODUCT_TRACE=$(ask_trace "How many products are there?")
.venv/bin/python -m scripts.verify_online_scores "$PRODUCT_TRACE" \
  sql-execution-success=true agent-arena-business-policy-online=NOT_APPLICABLE

El evaluator online se ejecuta de forma asíncrona. El verificador consulta durante un máximo de 180 segundos de forma predeterminada; una puntuación aún pendiente no equivale a un fallo.

Mantener el ciclo en funcionamiento

Deja 👍/👎 habilitado después de la publicación. Monitoriza discrepancias como agent-arena-business-policy-online=PASS junto a user-thumbs=false: son candidatas de gran valor para la siguiente cola de anotación. La revisión humana decide si corregir la política, los prompts, los datos o el evaluator. Los casos aprobados vuelven a arena-golden; después, el siguiente candidato repite la misma secuencia de referencia → candidato → calibración → habilitación protegida.

Las reglas del taller muestrean el 100 % de las trazas válidas para que todos vean pruebas. Es un ajuste didáctico, no un valor predeterminado de producción. El muestreo real debe reflejar el tráfico, el coste y la latencia del evaluator, el riesgo y la cobertura de incidentes necesaria.

Pruebas de finalización

  • La traza raíz de producción sigue mostrando sql-execution-success=true y el Boolean user-thumbs=false.
  • La tarea humana production-investigation-<session> está completada con una corrección verificada y approved-for-golden=true.
  • Existen los tres elementos dorados con procedencia auténtica production-feedback, y puedes distinguir la pregunta del usuario de las dos paráfrasis del revisor.
  • Referencia y candidato usaron el mismo dataset ampliado, modelo y prompt; el candidato corrigió los tres elementos promovidos y no introdujo regresiones de corrección en los existentes.
  • La calibración del experimento produjo FAIL, PASS y NOT_APPLICABLE con el nombre exacto business-policy-adherence.
  • La regla de observación estuvo deshabilitada durante la calibración y solo se habilitó después de superar las puertas.
  • Las trazas de clientes activos, ingresos y conversión tienen agent-arena-business-policy-online=PASS; el recuento sencillo de productos tiene agent-arena-business-policy-online=NOT_APPLICABLE.
  • Puedes explicar por qué la evaluación online y el feedback de usuario siguen mejorándose mutuamente después de publicar.

En esta página

¿Quieres seguir tu progreso?

Opcional. Enviaremos un enlace por correo para confirmar tu dirección; el progreso se registrará cuando lo abras.

Usa tu correo de trabajo, no uno personal.

Para seguir el progreso también debes aceptar los Términos del servicio actuales en la Configuración de privacidad.

ES