Agent ArenaClickHouse Workshops

03 릴리스하고 감지하기

알려진 정책 사각지대를 안은 선택된 에이전트를 릴리스하고, 운영 평가와 실제 사용자 피드백으로 이를 감지합니다.

시작 지점

모듈 02가 완료되었습니다. 실제 Arena 실행에서 선택된 승리 config_id를 기록한 다음, 랩 루트(ClickHouse_Demos/workshops/agent_arena)에서 이를 내보냅니다:

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

검증된 워크숍 실행에서는 qwen3.7-flash__P2_fewshot이 선택되었습니다. 여러분의 방에서 다른 결과가 나왔다면 그 승자를 유지하세요. 측정했던 것과 동일한 모델과 프롬프트를 사용합니다 — 실패만을 위한 특별한 에이전트가 아닙니다.

승자가 Qwen이라면, OpenRouter Settings → Privacy → Data Policies → Zero Data Retention → Non-frontier를 비활성화해야 합니다. non-frontier ZDR이 강제되면 사용 가능한 Alibaba 경로가 거부됩니다. 실제 데이터에 대해 이 설정을 변경하기 전에 여러분의 프라이버시 요구사항을 검토하세요.

통과한 평가자가 사용자 가치를 놓칠 수 있는 이유

온라인 평가자는 설계된 그 차원만을 측정합니다. 여기서 sql-execution-success는 중요한 운영상의 질문에 답합니다: 에이전트가 ClickHouse가 실행할 수 있는 SQL을 생성했는가? 하지만 그 SQL이 활성 고객이라는 현재 비즈니스 정의를 따르는지는 알지 못합니다.

이것은 현실적인 모니터링 공백을 만듭니다:

신호답하는 질문이 인시던트에서 기대되는 값
sql-execution-success생성된 SQL이 성공적으로 실행되었는가?true
user-thumbs이 답변이 이 사용자의 필요를 충족했는가?false

운영 평가는 깨진 SQL, 타임아웃, 실행 오류를 잡아냅니다. 시맨틱 평가 또는 사용자 평가는 실행 가능한 답변이 실제로 유용하고 비즈니스 의미에 부합하는지를 묻습니다. 어느 쪽도 다른 쪽을 대체하지 않습니다. 👎는 우선순위를 정하는 신호일 뿐 근거 진실 (ground truth)이 아닙니다. 사람이 모듈 04에서 이를 조사할 것입니다.

목표

운영 평가자는 통과하지만 사용자는 답변을 낮게 평가하는 실제 chat_turn 트레이스를 하나 만듭니다. 그 트레이스와 서로 상충하는 두 개의 카운트를 사람의 조사를 위해 기록합니다.

1단계 — 시딩된 인시던트가 재현 가능한지 증명하기

데모 서버를 시작하기 전에 랩 루트에서 프리플라이트를 실행하세요:

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"

이 명령은 두 정의를 모두 실행하고 선택된 구성에 세 가지 다른 표현으로 같은 질문을 던집니다. 서로 다른 stale_count와 current_count 값, 세 개의 classification_N=policy-v1 줄, 그리고 다음 문구를 출력해야 합니다:

어떤 표현의 결과가 ok/unknown이면 프리플라이트는 동일한 표현과 구성만 한 번 다시 시도합니다. policy-v2 또는 공급자/모델/에이전트 실패는 재시도하지 않으며, 두 번째 결과도 ok/unknown이면 차단 상태로 남습니다.

OK: seeded online-evaluation incident is reproducible

카운트가 같거나 분류 중 하나라도 policy-v1이 아니라면 멈추세요: 이 데이터/모델 실행에서는 대비가 드러나지 않습니다.

현재 비즈니스 정의는 정확히 이 SQL입니다:

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

이전 policy-v1 정의는 대신 지난 90일 안에 가입한 고객을 셉니다. 따라서 이 모듈에서 모델이 생성하는 SQL은 명시적인 policy-v1 지침에 비추어 보면 유효합니다. 여기서 말하고자 하는 바는 모델이 똑똑하지 않다는 것이 아닙니다. 배포된 정책 컨텍스트가 오래된 상태이고, SQL 실행 평가자는 그것을 알아채기에는 너무 좁은 범위로 설계되어 있다는 것입니다.

2단계 — 운영 평가자 프로비저닝

프로비저닝은 멱등적(idempotent)이므로 다시 실행해도 안전합니다:

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

출력에는 평가자 이름 sql-execution-success와 활성화된 규칙 agent-arena-sql-execution-online이 표시되어야 합니다.

3단계 — 시딩된 오래된 릴리스 시작하기

첫 번째 터미널에서, 랩 루트에서 이전 정책을 명시적으로 선택한 채 서버를 시작하고 계속 실행 상태로 둡니다:

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

AGENT_ARENA_POLICY_VERSION을 빠뜨리지 마세요. 이를 생략하면 서비스는 기본적으로 현재의 policy-v2를 사용하게 되는데, 이는 취소되거나 반품된 주문을 정확히 제외합니다.

4단계 — Chat을 통해 질문하고 평가하기

다른 터미널에서, 아직 실행 중이 아니라면 대시보드를 시작합니다:

scripts/arena.sh serve

http://localhost:5174를 열고, Chat 탭과 $WINNER_CONFIG_ID를 선택한 다음 질문합니다:

How many active customers do we have?

생성된 SQL과 결과를 읽어보세요. policy-v1의 시딩된 90일 가입 정의를 따라야 합니다. 이 답변에 👎를 클릭하고 UI에서 feedback sent라고 표시될 때까지 기다립니다.

이 Chat 루트 트레이스는 여러분이 점수를 매기고 모듈 04로 넘길 단 하나의 근본(authoritative) 인시던트입니다.

5단계 — Chat 트레이스 찾고 검증하기

Langfuse에서 Tracing을 열고 user-thumbs = false로 필터링합니다. 질문이 How many active customers do we have?이고, 구성이 $WINNER_CONFIG_ID와 일치하며, 메타데이터가 policyversion=policy-v1을 보여주는 가장 최근의 루트 chat_turn을 엽니다. 트레이스 ID와 트레이스 URL을 복사한 다음, 로컬에서 ID를 설정합니다:

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

user-thumbs가 숫자나 텍스트 점수가 아니라 Boolean false인지 확인하세요. 서빙 소스는 메타데이터 필드를 policy_version이라고 부르며, OpenTelemetry 어댑터는 이를 정제하여 Langfuse에 전달되는 키인 policyversion으로 만듭니다.

6단계 — 평가되지 않은 curl로 재현하기

원시 API 호출은 명령줄 수준에서 반드시 수행해야 하는 재현 및 진단입니다. 별도의 트레이스를 만들지만, 이것은 피드백 인시던트가 아니며 평가되어서는 안 됩니다:

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)')

응답에는 outcome: "ok", 비어 있지 않은 trace_id, policy_version: "policy-v1"이 있어야 합니다.

비동기 평가자를 기다렸다가 그 운영 점수만 검증합니다:

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

CURL_TRACE_ID에 대해 /feedback을 호출하지 말고 워크시트에도 넣지 마세요. 이는 재현 가능한 API 진단일 뿐이며, CHAT_TRACE_ID가 여전히 인계할 트레이스로 남습니다.

7단계 — 현재 정책과 비교하기

에이전트와 동일한 읽기 전용 ClickHouse 클라이언트를 통해 현재 정책 SQL을 실행한 다음, 그 단일 결과를 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

방금 실행한 쿼리는 정확히 이것입니다:

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

다른 카운트가 사용자가 겪는 실패입니다. SQL은 실행되었습니다. 다만 잘못된 비즈니스 정의에 답한 것입니다. 이 카운트를 근본 Chat 트레이스 증거와 함께 기록하세요.

조사 워크시트

모듈 04를 위해 이 인계 정보를 보관하세요:

증거여러분의 값
승자 config_id
근본 Chat 트레이스 ID
근본 Chat 트레이스 URL
오래된 policy-v1 카운트
현재 policy-v2 카운트
sql-execution-successtrue
user-thumbsfalse

완료 여부 확인하기

  • 프리플라이트에서 오래된/현재 카운트가 서로 달랐고, 시딩된 세 질문 모두 policy-v1로 분류되었습니다.
  • 서비스가 AGENT_ARENA_POLICY_VERSION=policy-v1로 실행되었고 /ask가 outcome: "ok"를 반환했습니다.
  • 근본 Chat 트레이스에 Langfuse에서 sql-execution-success=true와 user-thumbs=false가 있습니다.
  • 필수 curl 진단이 outcome: "ok"를 반환하고, 별도의 CURL_TRACE_ID를 생성했으며, 평가되거나 인계되지 않았습니다.
  • 자격 증명을 공유하지 않고 근본 Chat 트레이스 ID/URL과 두 카운트를 기록했습니다.
  • SQL 실행 성공이 왜 시맨틱 정확성을 증명하지 못하는지 설명할 수 있습니다.

이 신호를 사람이 검토한 진단으로 바꾸려면 모듈 04 — 사람과 함께 조사하기로 계속하세요.

이 페이지의 내용

Track your progress?

Optional. We email a link to confirm your address; progress records once you open it.

Please use your work email address, not a personal one.

Progress tracking also requires accepting the current Terms of Service in Privacy settings.

KO