Agent ArenaClickHouse Workshops

03 Publier et détecter

Publiez l'agent sélectionné avec un angle mort connu, puis utilisez l'évaluation opérationnelle et le feedback réel pour le détecter.

Point de départ

Le Module 02 est terminé. Notez le config_id gagnant de l'exécution réelle, puis exportez-le depuis la racine du laboratoire (ClickHouse_Demos/workshops/agent_arena) :

source .env
export WINNER_CONFIG_ID="${WINNER_CONFIG_ID:-qwen3.7-flash__P2_fewshot}"

L'exécution vérifiée a choisi qwen3.7-flash__P2_fewshot ; conservez le gagnant de votre salle s'il diffère. Vous utiliserez le même modèle et prompt que ceux mesurés, pas un agent spécial conçu pour échouer.

Si Qwen a gagné, OpenRouter Settings → Privacy → Data Policies → Zero Data Retention → Non-frontier doit être désactivé. La route Alibaba est refusée lorsque le ZDR non-frontier est imposé. Examinez vos exigences de confidentialité avant ce changement sur de vraies données.

Pourquoi un evaluator qui réussit peut manquer la valeur utilisateur

Un evaluator en ligne ne mesure que la dimension pour laquelle il a été conçu. Ici, sql-execution-success répond à une question opérationnelle importante : l'agent a-t-il produit un SQL exécutable par ClickHouse ? Il ignore si ce SQL suit la définition métier actuelle d'un client actif.

Cela crée un angle mort réaliste :

SignalQuestionValeur attendue dans cet incident
sql-execution-successLe SQL généré s'est-il exécuté ?true
user-thumbsLa réponse répond-elle au besoin de cet utilisateur ?false

L'évaluation opérationnelle détecte SQL cassé, timeouts et erreurs. L'évaluation sémantique ou utilisateur vérifie l'utilité et l'alignement métier. Aucune ne remplace l'autre. Un 👎 est un signal de priorité, pas une vérité de référence ; un humain l'examinera au Module 04.

Objectif

Créer une vraie trace chat_turn où l'evaluator opérationnel réussit mais l'utilisateur rejette la réponse. Consignez la trace et les deux décomptes contradictoires pour l'enquête humaine.

Étape 1 — Prouver que l'incident préparé est reproductible

Exécutez le preflight depuis la racine avant le serveur :

source .env
export WINNER_CONFIG_ID="${WINNER_CONFIG_ID:-qwen3.7-flash__P2_fewshot}"
.venv/bin/python -m schema.gen_schema_context
.venv/bin/python -m scripts.check_online_eval_scenario \
  --config-id "$WINNER_CONFIG_ID"

La commande exécute les deux définitions et pose trois paraphrases à la configuration. Elle doit afficher des stale_count et current_count différents, trois lignes classification_N=policy-v1, puis :

Si une paraphrase renvoie ok/unknown, le preflight ne réessaie qu'une fois cette même paraphrase et configuration. Il ne réessaie ni policy-v2 ni les échecs de fournisseur, modèle ou agent ; un second ok/unknown bloque toujours.

OK: seeded online-evaluation incident is reproducible

Si les décomptes sont identiques ou une classification diffère de policy-v1, arrêtez : le contraste ne serait pas visible.

La définition métier actuelle correspond exactement à :

SELECT uniqExact(customer_id) FROM v_orders
WHERE order_ts >= now() - INTERVAL 30 DAY
AND status NOT IN ('cancelled', 'returned')

L'ancienne définition policy-v1 compte les clients inscrits dans les 90 derniers jours. Le SQL généré est donc valide selon les instructions policy-v1. Le problème n'est pas l'intelligence du modèle : le contexte publié est obsolète et l'evaluator d'exécution trop étroit pour le remarquer.

Étape 2 — Provisionner l'evaluator opérationnel

Le provisionnement est idempotent :

source .env
.venv/bin/python -m scripts.provision_online_evaluators --operational

La sortie doit nommer l'evaluator sql-execution-success et la règle activée agent-arena-sql-execution-online.

Étape 3 — Démarrer la publication obsolète préparée

Dans le premier terminal, démarrez le serveur avec l'ancienne politique explicite :

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

N'omettez pas AGENT_ARENA_POLICY_VERSION. Sinon, le service emploie policy-v2, qui exclut correctement les commandes annulées et retournées.

Étape 4 — Interroger et noter dans Chat

Dans un autre terminal, démarrez le dashboard si nécessaire :

scripts/arena.sh serve

Ouvrez http://localhost:5174, sélectionnez Chat et $WINNER_CONFIG_ID, puis demandez :

How many active customers do we have?

Lisez le SQL et le résultat. Ils doivent suivre la définition policy-v1 des inscriptions sur 90 jours. Cliquez sur 👎 et attendez feedback sent.

Cette trace racine Chat est l'unique incident de référence transmis au Module 04.

Étape 5 — Trouver et vérifier la trace Chat

Dans Langfuse, ouvrez Tracing et filtrez user-thumbs = false. Ouvrez la racine chat_turn la plus récente dont la question est How many active customers do we have?, dont la configuration correspond à $WINNER_CONFIG_ID et dont les métadonnées affichent policyversion=policy-v1. Copiez l'ID et l'URL, puis définissez :

export CHAT_TRACE_ID="<paste the Chat trace ID>"
.venv/bin/python -m scripts.verify_online_scores "$CHAT_TRACE_ID" \
  sql-execution-success=true user-thumbs=false

Vérifiez que user-thumbs est un Boolean false, pas un score numérique ou texte. Le code appelle le champ policy_version ; OpenTelemetry le nettoie en policyversion dans Langfuse.

Étape 6 — Reproduire avec un curl non noté

L'appel API brut est un diagnostic obligatoire. Il crée une trace séparée, pas l'incident de feedback, et ne doit pas être noté :

source .env
export WINNER_CONFIG_ID="${WINNER_CONFIG_ID:-qwen3.7-flash__P2_fewshot}"
ASK_BODY=$(.venv/bin/python -c \
  'import json,sys; print(json.dumps({"question": sys.argv[1], "config_id": sys.argv[2]}))' \
  "How many active customers do we have?" "$WINNER_CONFIG_ID")
CURL_RESPONSE=$(curl -fsS http://localhost:8100/ask \
  -H 'content-type: application/json' -d "$ASK_BODY")
printf '%s\n' "$CURL_RESPONSE" | .venv/bin/python -m json.tool
CURL_TRACE_ID=$(printf '%s\n' "$CURL_RESPONSE" | .venv/bin/python -c \
  'import json,sys; data=json.load(sys.stdin); assert data.get("policy_version") == "policy-v1"; assert data.get("outcome") == "ok"; trace_id=data.get("trace_id"); assert isinstance(trace_id, str) and trace_id; print(trace_id)')

La réponse doit avoir outcome: "ok", un trace_id non vide et policy_version: "policy-v1".

Attendez l'evaluator asynchrone et vérifiez uniquement son score opérationnel :

.venv/bin/python -m scripts.verify_online_scores "$CURL_TRACE_ID" \
  sql-execution-success=true

N'appelez pas /feedback pour CURL_TRACE_ID et ne l'inscrivez pas dans la feuille. Ce n'est qu'un diagnostic ; CHAT_TRACE_ID reste la trace transmise.

Étape 7 — Comparer avec la politique actuelle

Exécutez le SQL actuel avec le même client ClickHouse en lecture seule, puis comparez son résultat à celui de CURL_RESPONSE :

.venv/bin/python - <<'PY'
from arena.config import load_config
from agents.chclient import ROClickHouseClient

sql = """SELECT uniqExact(customer_id) FROM v_orders
WHERE order_ts >= now() - INTERVAL 30 DAY
AND status NOT IN ('cancelled', 'returned')"""
result = ROClickHouseClient(load_config().clickhouse).query(sql)
print(result.rows[0][0])
PY

Voici la requête exacte exécutée :

SELECT uniqExact(customer_id) FROM v_orders
WHERE order_ts >= now() - INTERVAL 30 DAY
AND status NOT IN ('cancelled', 'returned')

Le décompte différent est l'échec visible. Le SQL a fonctionné, mais a répondu à la mauvaise définition métier. Notez ce décompte avec les preuves Chat de référence.

Feuille d'enquête

Conservez pour le Module 04 :

PreuveVotre valeur
config_id gagnant
ID de la trace Chat de référence
URL de la trace Chat de référence
Décompte policy-v1 obsolète
Décompte policy-v2 actuel
sql-execution-successtrue
user-thumbsfalse

Comment vérifier que vous avez terminé

  • Le preflight a montré des décomptes différents et trois classifications policy-v1.
  • Le service tournait avec AGENT_ARENA_POLICY_VERSION=policy-v1 et /ask a renvoyé outcome: "ok".
  • La trace Chat de référence a sql-execution-success=true et user-thumbs=false.
  • Le diagnostic curl a renvoyé outcome: "ok", produit un CURL_TRACE_ID distinct et n'a pas été noté ni transmis.
  • Vous avez consigné l'ID, l'URL et les deux décomptes sans partager d'identifiants.
  • Vous pouvez expliquer pourquoi un SQL exécutable ne prouve pas la correction sémantique.

Passez au Module 04 — Enquêter pour transformer ce signal en diagnostic revu par un humain.

Sur cette page

Suivre votre progression ?

Facultatif. Nous envoyons un lien par e-mail pour confirmer votre adresse ; la progression est enregistrée après son ouverture.

Utilisez votre adresse e-mail professionnelle, et non une adresse personnelle.

Le suivi de la progression exige aussi d’accepter les Conditions d’utilisation actuelles dans les Paramètres de confidentialité.

FR