03 ปล่อยใช้งานและตรวจจับ
ปล่อยใช้งานเอเจนต์ที่เลือกไว้พร้อมจุดบอดของนโยบายที่รู้อยู่แล้ว จากนั้นใช้การประเมินระหว่างปฏิบัติงานร่วมกับคำติชมจริงจากผู้ใช้เพื่อตรวจจับจุดบอดนั้น
จุดเริ่มต้น
โมดูล 02 เสร็จสมบูรณ์แล้ว บันทึก config_id ของผู้ชนะที่เลือกจากการรัน Arena
จริง จากนั้นเอ็กซ์พอร์ตค่านี้จากรากของแล็บ (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 เส้นทาง Alibaba ที่มีให้ใช้จะถูก ปฏิเสธเมื่อมีการบังคับใช้ non-frontier ZDR ตรวจสอบข้อกำหนดด้านความเป็นส่วนตัวของคุณ ก่อนเปลี่ยนการตั้งค่านี้กับข้อมูลจริง
เหตุใดผู้ประเมินที่ผ่านการทดสอบยังพลาดคุณค่าของผู้ใช้ได้
ผู้ประเมินออนไลน์วัดเฉพาะมิติที่ถูกออกแบบมาให้วัดเท่านั้น ในที่นี้
sql-execution-success ตอบคำถามด้านการปฏิบัติงานที่สำคัญข้อหนึ่ง: เอเจนต์สร้าง
SQL ที่ ClickHouse รันได้จริงหรือไม่? แต่มันไม่รู้ว่า SQL นั้นเป็นไปตามคำนิยาม
ทางธุรกิจปัจจุบันของคำว่า ลูกค้าที่ยังใช้งานอยู่ หรือเปล่า
นั่นทำให้เกิดช่องว่างในการเฝ้าตรวจที่สมจริงมาก:
| สัญญาณ | คำถามที่มันตอบ | ค่าที่คาดหวังในเหตุการณ์นี้ |
|---|---|---|
sql-execution-success | SQL ที่สร้างขึ้นรันสำเร็จหรือไม่ | true |
user-thumbs | คำตอบนี้ตอบสนองความต้องการของผู้ใช้รายนี้หรือไม่ | false |
การประเมินระหว่างปฏิบัติงานจับได้เฉพาะ SQL ที่พัง การหมดเวลา และข้อผิดพลาดในการ รัน ส่วนการประเมินเชิงความหมายหรือการประเมินโดยผู้ใช้จะถามว่าคำตอบที่รันได้นั้นมี ประโยชน์และตรงกับความหมายทางธุรกิจหรือไม่ ทั้งสองอย่างไม่สามารถแทนที่กันได้ การกดยกนิ้วโป้งลงเป็นสัญญาณสำหรับจัดลำดับความสำคัญ ไม่ใช่ความจริงที่ยืนยันได้ในตัวเอง มนุษย์จะเป็นผู้สืบสวนเรื่องนี้ต่อในโมดูล 04
เป้าหมาย
สร้าง chat_turn trace จริงหนึ่งรายการ ซึ่งผู้ประเมินระหว่างปฏิบัติงานผ่าน
แต่ผู้ใช้ให้คะแนนคำตอบว่าไม่ดี บันทึก trace นั้นพร้อมค่านับสองค่าที่ขัดแย้งกัน
เพื่อส่งต่อให้มนุษย์สืบสวน
ขั้นตอนที่ 1 — พิสูจน์ว่าเหตุการณ์ที่ปลูกไว้สามารถทำซ้ำได้
รัน preflight จากรากของแล็บก่อนเริ่มเซิร์ฟเวอร์สาธิต:
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 การตรวจสอบ preflight จะลองซ้ำเฉพาะคำถาม
รูปแบบเดิมและคอนฟิกเดิมเพียงหนึ่งครั้ง จะไม่ลองซ้ำเมื่อผลเป็น 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-execution นั้น
มองแค่มุมแคบเกินกว่าจะสังเกตเห็นความล้าสมัยนี้
ขั้นตอนที่ 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 เพราะไม่เช่นนั้น service จะใช้ค่าเริ่ม
ต้นเป็น policy-v2 ปัจจุบัน ซึ่งจะตัดคำสั่งซื้อที่ยกเลิกและคืนสินค้าออกอย่าง
ถูกต้อง
ขั้นตอนที่ 4 — ถามและให้คะแนนผ่าน Chat
ในอีกเทอร์มินัลหนึ่ง เริ่มแดชบอร์ดหากยังไม่ได้รันอยู่:
scripts/arena.sh serveเปิด http://localhost:5174 เลือกแท็บ Chat และ $WINNER_CONFIG_ID จากนั้นถาม
ว่า:
How many active customers do we have?อ่าน SQL ที่ถูกสร้างขึ้นและผลลัพธ์ ควรเป็นไปตามคำนิยามแบบลงทะเบียน 90 วันที่ปลูก
ไว้จาก policy-v1 คลิก 👎 ที่คำตอบนี้ และรอจนกว่า UI จะแสดงข้อความ
feedback sent
trace รากของ Chat นี้คือเหตุการณ์ที่เชื่อถือได้เพียงเหตุการณ์เดียวที่คุณจะให้ คะแนนและส่งต่อให้โมดูล 04
ขั้นตอนที่ 5 — ค้นหาและตรวจสอบ trace ของ Chat
ใน Langfuse เปิด Tracing และกรองด้วย user-thumbs = false เปิด root
chat_turn ล่าสุดที่คำถามคือ How many active customers do we have? ที่คอนฟิก
ตรงกับ $WINNER_CONFIG_ID และมี metadata แสดง policyversion=policy-v1
คัดลอก trace ID และ trace 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 ไม่ใช่สกอร์ตัวเลขหรือข้อความ
ต้นทางฝั่ง serving เรียกฟิลด์ metadata นี้ว่า policy_version ส่วน adapter ของ
OpenTelemetry จะแปลงให้เป็นคีย์ที่ปล่อยออกมาใน Langfuse คือ policyversion
ขั้นตอนที่ 6 — ทำซ้ำด้วย curl ที่ไม่ให้คะแนน
การเรียก API แบบตรงนี้เป็นการทำซ้ำและตรวจสอบระดับคำสั่งที่จำเป็นต้องทำ มันจะ สร้าง trace แยกต่างหากขึ้นมา แต่ ไม่ใช่ เหตุการณ์ที่มีคำติชม และต้องไม่ให้ คะแนนกับมัน:
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"
รอผู้ประเมินแบบ asynchronous แล้วตรวจสอบเฉพาะสกอร์ด้านการปฏิบัติงานของมันเท่านั้น:
.venv/bin/python -m scripts.verify_online_scores "$CURL_TRACE_ID" \
sql-execution-success=trueอย่าเรียก /feedback สำหรับ CURL_TRACE_ID และอย่านำมันไปใส่ในเวิร์กชีต มันเป็น
เพียงการวินิจฉัยผ่าน API ที่ทำซ้ำได้เท่านั้น CHAT_TRACE_ID ยังคงเป็น trace ที่
ใช้ส่งต่อ
ขั้นตอนที่ 7 — เปรียบเทียบกับนโยบายปัจจุบัน
รัน SQL ตามนโยบายปัจจุบันผ่าน read-only ClickHouse client ตัวเดียวกันกับที่
เอเจนต์ใช้ จากนั้นเปรียบเทียบผลลัพธ์เดี่ยวของมันกับผลลัพธ์แบบนโยบายเก่าใน
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 รันสำเร็จ แต่มันตอบ ตามคำนิยามทางธุรกิจที่ผิด บันทึกค่านับนี้ไว้ควบคู่กับหลักฐาน trace ของ Chat ที่ เชื่อถือได้
เวิร์กชีตการสืบสวน
เก็บข้อมูลส่งต่อนี้ไว้สำหรับโมดูล 04:
| หลักฐาน | ค่าของคุณ |
|---|---|
config_id ของผู้ชนะ | |
| Trace ID ของ Chat ที่เชื่อถือได้ | |
| Trace URL ของ Chat ที่เชื่อถือได้ | |
ค่านับแบบ policy-v1 เก่า | |
ค่านับแบบ policy-v2 ปัจจุบัน | |
sql-execution-success | true |
user-thumbs | false |
วิธีตรวจสอบว่าคุณทำเสร็จแล้ว
- preflight แสดงค่านับ stale/current ที่ต่างกัน และคำถามที่ปลูกไว้ทั้งสามข้อถูก
จำแนกเป็น
policy-v1 - service รันด้วย
AGENT_ARENA_POLICY_VERSION=policy-v1และ/askคืนค่าoutcome: "ok" - trace ของ Chat ที่เชื่อถือได้มี
sql-execution-success=trueและuser-thumbs=falseใน Langfuse - การวินิจฉัยด้วย curl ที่จำเป็นคืนค่า
outcome: "ok"สร้างCURL_TRACE_IDที่ แยกจากกัน และไม่ได้ถูกให้คะแนนหรือส่งต่อ - คุณบันทึก trace ID/URL ของ Chat ที่เชื่อถือได้ และค่านับทั้งสองค่าไว้แล้ว โดย ไม่มีการแบ่งปัน credential ใดๆ
- คุณสามารถอธิบายได้ว่าทำไมการรัน SQL สำเร็จจึงไม่ได้พิสูจน์ความถูกต้องเชิง ความหมาย
ไปยัง โมดูล 04 — ตรวจสอบ เพื่อ เปลี่ยนสัญญาณนี้ให้เป็นการวินิจฉัยที่ผ่านการตรวจสอบโดยมนุษย์