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 回答的 是一个重要的运营问题:代理生成的 SQL 是否能被 ClickHouse 执行?它并不知道这段 SQL 是否遵循了当前业务定义的活跃客户。

这就造成了一个真实存在的监控盲区:

信号它回答的问题在此事件中的期望值
sql-execution-success生成的 SQL 是否成功执行?true
user-thumbs这个答案是否满足了该用户的需求?false

运营评估能捕获损坏的 SQL、超时和执行错误。语义或用户评估问的是:一个可执行的答案 是否有用,是否符合业务含义。两者互不替代。点差评是一个优先级信号,不是最终结论; 人类会在模块 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,也不会重试提供商、模型或 Agent 故障;若第二次结果仍为 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 — 配置运营评估器

配置是幂等的,因此重新运行是安全的:

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 天注册定义。点击这个 答案上的 👎,并等待界面显示 feedback sent。

这条 Chat 根追踪记录就是你将要打分并交给模块 04 的唯一权威事件。

步骤 5 — 找到并验证 Chat 追踪记录

在 Langfuse 中打开 Tracing,筛选 user-thumbs = false。打开最新的一条根 chat_turn,其问题为 How many active customers do we have?,配置匹配 $WINNER_CONFIG_ID,且元数据显示 policyversion=policy-v1。复制它的追踪 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 是一个布尔值 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.

ZH