Agent ArenaClickHouse Workshops

04 ตรวจสอบโดยมนุษย์

เปลี่ยนสัญญาณเชิงลบจากผู้ใช้ให้เป็นการวินิจฉัยและการแก้ไขที่ผ่านการตรวจสอบโดยมนุษย์ โดยไม่นำฟีดแบ็กมาสับสนกับความจริงพื้นฐาน (ground truth)

จุดเริ่มต้น

โมดูล 03 สร้าง Chat trace ที่เชื่อถือได้ หนึ่งรายการสำหรับคำถาม How many active customers do we have? พร้อมความขัดแย้งที่ตั้งใจให้เกิดขึ้น:

หลักฐานค่าที่คาดหวัง
root observationchat_turn
sql-execution-successtrue
user-thumbsfalse
metadata policyversionpolicy-v1

เก็บ trace ID/URL และค่าอ้างอิงทั้งสองจากเวิร์กชีตของคุณไว้ อย่าใช้ curl diagnostic ที่ยังไม่ได้ให้คะแนนจากโมดูล 03

เหตุใดจึงต้องมีการสอบสวนโดยมนุษย์

thumbs-down บอกทีมว่าควรดูที่ไหน แต่ไม่ได้บอกว่าอะไรล้มเหลว ผู้ใช้อาจตั้งใจสื่อความหมายอื่น คำขออาจกำกวม SQL ที่สร้างขึ้นอาจไม่ถูกต้อง หรือคำนิยามทางธุรกิจสองแบบอาจขัดแย้งกัน การเลื่อนสัญญาณเชิงลบทุกรายการ เข้าสู่ golden dataset โดยตรงจะเปลี่ยนการเดาให้กลายเป็นความจริงพื้นฐานไปเสียเปล่า ๆ

ในโมดูลนี้ ผู้ตรวจสอบจะบันทึกสิ่งที่สังเกตได้ก่อน จากนั้นทดสอบคำอธิบาย ที่เป็นไปได้ต่าง ๆ แล้วจึงบันทึกการวินิจฉัยและการแก้ไขในลำดับสุดท้าย การตัดสินใจที่ผ่านการทบทวนนั้น—ไม่ใช่ thumbs-down—คือความจริงพื้นฐานที่ส่งต่อให้โมดูล 05

เป้าหมาย

ทำงาน annotation production-investigation-<session> หนึ่งงานให้เสร็จสมบูรณ์ สำหรับ root chat_turn ของโมดูล 03 งานที่เสร็จสมบูรณ์ต้องมีการสังเกต ประเภทความล้มเหลว SQL ที่แก้ไขแล้วแบบตรงตัว การอนุมัติสำหรับ golden dataset และแหล่งที่มาจากการใช้งานจริง (production provenance)

ขั้นตอนที่ 1 — ค้นหาเหตุการณ์ฟีดแบ็กที่ตรงกัน

ใน Langfuse เปิด Tracing แล้วกรองด้วยคะแนน Boolean user-thumbs = false เปิด trace ที่ตรงกับเงื่อนไขทั้งหมดต่อไปนี้:

  • name/root observation คือ chat_turn;
  • คำถามคือ How many active customers do we have?;
  • config_id ของตัวชนะและ trace ID ที่บันทึกไว้ในโมดูล 03;
  • metadata policyversion=policy-v1; และ
  • คะแนน sql-execution-success=true และ user-thumbs=false

แหล่งที่ให้บริการ (serving source) ส่งค่า policy_version ออกมา แต่ OpenTelemetry adapter จะลบขีดล่างออก ดังนั้นคีย์ metadata ใน Langfuse จึงเป็น policyversion

ให้ annotate ที่ root chat_turn ไม่ใช่ generation ย่อยที่เป็น llm_call root มีคำถามแบบ end-to-end และผลลัพธ์ที่มีโครงสร้าง—SQL, คอลัมน์, แถว, ข้อผิดพลาด, และผลลัพธ์ สุดท้าย—ซึ่งจำเป็นสำหรับการสอบสวน ส่วน child มีเพียง transcript ของโมเดลและ SQL ที่สร้างขึ้นเท่านั้น และไม่ใช่เหตุการณ์ฟีดแบ็กที่เชื่อถือได้

ขั้นตอนที่ 2 — สร้าง score config สำหรับรีวิวทั้งสามรายการ

การตั้งค่านี้เป็นขั้นตอนตรวจสอบโดยมนุษย์ผ่าน UI เท่านั้นโดยเจตนา repository ของเวิร์กชอปนี้ ไม่มีคำสั่งใดที่จะสร้างหรือทำ annotation task นี้ให้เสร็จแทนคุณได้

ก่อนสร้างคิว เปิด Settings → Scores → Create และสร้าง config เหล่านี้:

ชื่อชนิดข้อมูลค่าที่อนุญาต / วัตถุประสงค์
observed-issueTEXTอธิบายเฉพาะหลักฐานที่มองเห็นได้ใน trace และการเปรียบเทียบเท่านั้น
failure-categoryCATEGORICALstale-business-policy, incorrect-sql, ambiguous-request, not-actionable
approved-for-goldenBOOLEANอนุมัติได้เฉพาะหลังจากตรวจสอบยืนยันการแก้ไขแล้ว

ใช้ชื่อและการใส่ยัติภังค์ตามที่แสดงไว้ทุกตัวอักษร การสร้าง config เหล่านี้ก่อนคือ วิธีที่ปลอดภัยที่สุด เพราะชุด score-config ID ที่ผูกกับคิวจะถูกกำหนดตายตัว ตั้งแต่ตอนสร้างคิว หาก config ใดถูกละไว้จากชุดที่ผูกไว้นั้น ให้สร้างคิวใหม่ ด้วยส่วนต่อท้าย (suffix) ใหม่ ส่วน score config เองสามารถแก้ไขได้: การแก้ไขชื่อ, schema, หรือ category ที่รองรับต้องทำผ่านการอัปเดต score-config ที่มีการตรวจสอบ (audited) และการแก้ไขนั้น จะไม่เขียนทับคะแนนที่มีอยู่แล้ว

ขั้นตอนที่ 3 — สร้างคิวและกำหนดเป้าหมายที่ logical root

เปิด Annotations → Queues → Create แล้ว:

  1. ตั้งชื่อว่า production-investigation-<session> โดยแทน <session> ด้วยตัวระบุ สั้น ๆ ที่ไม่ซ้ำกันของเวิร์กชอป
  2. ผูก score config ทั้งสามรายการจากขั้นตอนที่ 2
  3. สร้างคิว
  4. กลับไปที่ trace ของโมดูล 03 เลือก root observation chat_turn เปิด dropdown Annotate แล้วเลือกคิวนี้
  5. เปิด task ใหม่และตรวจสอบว่าเป้าหมายคือ chat_turn ไม่ใช่ llm_call

คิวไม่สามารถเปลี่ยนชุด score-config ID ที่ผูกไว้ได้หลังสร้างแล้ว ให้สร้างคิวใหม่ เฉพาะเมื่อชุดที่ผูกไว้ผิดพลาดเท่านั้น ส่วนการแก้ไขที่รองรับสำหรับ config ที่ผูกอยู่แล้ว ให้ใช้การอัปเดต score-config ที่มีการตรวจสอบแทน

ขั้นตอนที่ 4 — เขียนสิ่งที่คุณสังเกตได้แบบเปิดเผย (open-code)

โมดูล 03 เปิดเผย seeded setup ให้เห็นโดยเจตนา สำหรับการสอบสวนนี้ ให้พักความรู้ เชิงเวิร์กชอปก่อนหน้านั้นไว้ก่อน แล้วฝึกใช้เวิร์กโฟลว์แบบที่ผู้ตรวจสอบจะใช้กับ เหตุการณ์ที่ยังไม่รู้สาเหตุ: ตรวจสอบคำถาม, SQL ที่สร้างขึ้น, จำนวนที่ส่งกลับมา, โมเดล/พรอมป์, และคะแนนทั้งสองตัว ก่อนที่จะระบุสาเหตุ ให้บันทึกโน้ตที่มีเฉพาะหลักฐานลงใน observed-issue เช่นตัวอย่างนี้:

The answer returned a count and its SQL executed. The observed count differs from the
second reference count recorded in Module 03. The generated query uses a 90-day
customer signup window, and the trace metadata reports policy-v1.

ข้อความนี้ยังไม่ได้กล่าวหาว่าโมเดล, SQL engine, ผู้ใช้ หรือ policy เป็นฝ่ายผิด การแยกเช่นนี้ป้องกันไม่ให้การวินิจฉัยที่ถูก seed ไว้แอบแทรกเข้ามาในการทบทวน ก่อนที่จะได้ตรวจสอบหลักฐานจริง

ขั้นตอนที่ 5 — ตรวจสอบหลักฐานทั้งหมดของ trace

ขณะยังอยู่ที่ root chat_turn ให้ตรวจสอบ:

  • metadata policyversion=policy-v1;
  • SQL ที่สร้างขึ้นใช้ v_customers และหน้าต่างเวลา signup_date 90 วัน;
  • ผลลัพธ์ที่มีโครงสร้างมีจำนวนที่ตรงกับ trace count ที่สังเกตได้จากโมดูล 03;
  • คะแนนด้านการทำงานคือ Boolean sql-execution-success=true; และ
  • สัญญาณจากผู้ใช้คือ Boolean user-thumbs=false

SQL ที่สร้างขึ้นสอดคล้องกับคำสั่งของ policy-v1 ที่มาพร้อม release นี้ คะแนนการรันสำเร็จก็ถูกต้องเช่นกันภายในขอบเขตที่ตั้งใจให้แคบ ณ จุดนี้ ยังไม่มีข้อเท็จจริงใดที่บอกได้ว่า policy ที่ deploy อยู่นั้นตรงกับคำนิยาม ที่อยู่ภายใต้การกำกับดูแลในปัจจุบันหรือไม่

ขั้นตอนที่ 6 — ทดสอบคำนิยาม policy ทั้งสองแบบเทียบกัน

จาก ClickHouse_Demos/workshops/agent_arena ให้รันคำนิยามแบบอ่านอย่างเดียว (read-only) ทั้งสองรายการในสภาพแวดล้อมเดียวกัน:

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

queries = {
    "policy-v1": """SELECT count() FROM v_customers
WHERE signup_date >= today() - INTERVAL 90 DAY""",
    "policy-v2": """SELECT uniqExact(customer_id) FROM v_orders
WHERE order_ts >= now() - INTERVAL 30 DAY
AND status NOT IN ('cancelled', 'returned')""",
}
client = ROClickHouseClient(load_config().clickhouse)
for version, sql in queries.items():
    result = client.query(sql)
    print(f"{version}: {result.rows[0][0]}")
PY

ค่าทั้งสองต้องตรงกับค่าในเวิร์กชีตและต้องแตกต่างกัน ตอนนี้คุณมีหลักฐานเพียงพอที่จะ วินิจฉัยว่าคำนิยามทางธุรกิจที่ deploy อยู่นั้นล้าสมัย (stale): trace ระบุว่าใช้ policy-v1 และ SQL ของมันก็เป็นไปตาม policy นั้น ในขณะที่ query ปัจจุบันที่ได้รับการตรวจสอบแล้ว ใช้ policy-v2

ขั้นตอนที่ 7 — ใส่ annotation, แก้ไข, อนุมัติ, และทำให้เสร็จสมบูรณ์

กลับไปที่ annotation task และบันทึก:

ฟิลด์ค่า
observed-issueเก็บโน้ตแบบหลักฐานก่อนไว้ตามเดิม แล้วเพิ่มการเปรียบเทียบ policy ที่ตรวจสอบแล้วต่อท้าย
failure-categorystale-business-policy
เอาต์พุตที่แก้ไขแล้ว (Corrected Output)SQL ที่ตรงตัวด้านล่าง
approved-for-goldentrue

สลับ Corrected Output ไปเป็น plain-text mode แล้วป้อน SQL ดิบนี้ตรงตัว:

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

Langfuse จะบันทึกการแก้ไขนี้ไว้ แต่ไม่ได้รัน SQL นั้นจริง ๆ ไคลเอนต์ ClickHouse แบบอ่านอย่างเดียวในขั้นตอนที่ 6 ต้องรันข้อความตรงตัวนี้สำเร็จมาก่อนแล้วจึงจะอนุมัติได้ หากคุณแก้ไขการแก้ไขนี้เพิ่มเติม ให้รันข้อความนั้นผ่านไคลเอนต์ตัวเดียวกันอีกครั้ง จากนั้นเลือก Complete (หรือ Complete + next) การแก้ไขที่ผิดรูปแบบ รันไม่ได้ หรือยังไม่ได้รับการยืนยัน จะต้องไม่ได้รับการอนุมัติให้เป็น golden ground truth

ขั้นตอนที่ 8 — บันทึกที่มา (provenance) สำหรับโมดูล 05

คัดลอกค่าเหล่านี้ไปยังเวิร์กชีตของคุณ เก็บ ID ให้เป็นความลับภายในโปรเจกต์เวิร์กชอป:

ฟิลด์ข้อมูลที่มาค่าที่ต้องบันทึก
sourceproduction-feedback
source_trace_idtrace ID ของ Chat ที่เชื่อถือได้จากโมดูล 03
failure_categorystale-business-policy
source_policy_versionpolicy-v1
annotation_idID ของ annotation task ที่เสร็จสมบูรณ์ เมื่อมีให้ใช้
การแก้ไขที่ผ่านการทบทวนSQL ตามนโยบายปัจจุบันที่ตรงตัวด้านบน

source_trace_id, failure_category, และ source_policy_version เป็นข้อมูลที่จำเป็น สำหรับ golden record ที่มาจากการใช้งานจริง ส่วน annotation_id เป็นทางเลือกในระดับ runtime แต่ให้บันทึกไว้เมื่อ UI แสดงให้เห็น เพื่อให้การตัดสินใจยังตรวจสอบย้อนกลับได้

วิธีตรวจสอบว่าคุณทำเสร็จแล้ว

  • คุณได้สอบสวน Chat trace ของโมดูล 03 รายการเดียวที่มี user-thumbs=false
  • เป้าหมายของ annotation คือ root chat_turn ไม่ใช่ child llm_call ไม่ว่ากรณีใด
  • คิวมีชื่อว่า production-investigation-<session> และมี score config ทั้งสามรายการ ที่พิมพ์ประเภทถูกต้องผูกอยู่ครบ
  • observed-issue บันทึกพฤติกรรมก่อนการวินิจฉัย
  • คุณได้รัน SQL แบบล้าสมัยและแบบปัจจุบันเทียบกัน และยืนยันว่าค่าที่ได้แตกต่างกัน
  • task ที่เสร็จสมบูรณ์บันทึก stale-business-policy, SQL ที่แก้ไขแล้วแบบตรงตัว และ approved-for-golden=true
  • เวิร์กชีตของคุณเก็บรักษา production provenance สำหรับโมดูล 05 ไว้ โดยไม่เผยแพร่ trace ID หรือ URL โปรเจกต์ที่ใช้งานจริง (live)
  • คุณสามารถอธิบายได้ว่าทำไม thumbs-down จึงเป็นตัวจัดลำดับความสำคัญให้มนุษย์ตรวจสอบ แต่ตัวมันเองไม่ได้กลายเป็นความจริงพื้นฐาน

ไปยัง โมดูล 05 — ปิดวงจร เพื่อยกระดับการแก้ไขที่ผ่านการตรวจสอบแล้ว เปรียบเทียบเวอร์ชันของ policy และป้องกัน ความล้มเหลวในคลาสเดียวกันนี้ไม่ให้เกิดขึ้นซ้ำบนระบบจริง

ในหน้านี้

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.

TH