ดีบักการทดสอบที่ล้มเหลวด้วยเอเจนต์
คู่มือนี้แสดงวิธีทำให้เอเจนต์ใช้ดีบักเกอร์กับความล้มเหลวที่คำสั่งพิมพ์อธิบายไม่ได้
เครื่องมือ debug ขับเคลื่อนเซสชัน Debug Adapter Protocol จริง เฟรมที่ถูกหยุดไว้จะตอบทุกคำถามเกี่ยวกับขณะนั้นพร้อมกันในครั้งเดียว — ตัวแปรโลคอลทุกตัว ผู้เรียกทุกชั้น และนิพจน์ที่ประเมินในสโคปของเฟรมเอง — ในขณะที่คำสั่งพิมพ์ตอบได้แค่คำถามที่คุณคิดจะถามก่อนรัน
ก่อนเริ่ม
หัวข้อที่มีชื่อว่า “ก่อนเริ่ม”เครื่องมือนี้ยังคงอยู่บนพื้นผิว เพื่อให้เอเจนต์ถามได้ว่าทำไมจึงใช้งานอะไรไม่ได้ แทนที่จะเดา อะแดปเตอร์จะเริ่มทำงานได้จริงก็ต่อเมื่อเข้าเงื่อนไข ทั้งสอง ข้อนี้:
- มีมาร์กเกอร์โปรเจกต์อยู่ในเช็กเอาต์ และ
- ค้นหาไบนารีของอะแดปเตอร์เจอ
ลองให้เอเจนต์ตรวจสอบ:
debug(op: "adapters")มันจะตอบด้วยสิ่งที่พบ หรืออธิบายว่าอะแดปเตอร์ต้องมีครบทั้งสองส่วน
| ภาษา | อะแดปเตอร์ | มาร์กเกอร์ | การติดตั้ง |
|---|---|---|---|
| Dart / Flutter | dart debug_adapter |
pubspec.yaml |
มาพร้อม SDK — ไม่ต้องทำอะไร |
| Python | python3 -m debugpy.adapter |
pyproject.toml, setup.py, requirements.txt |
pip install debugpy |
| Rust / C / C++ | lldb-dap |
Cargo.toml, CMakeLists.txt |
มาพร้อม LLVM |
| Go | dlv dap |
go.mod |
go install github.com/go-delve/delve/cmd/dlv@latest |
ตั้งเบรกพอยต์ก่อน แล้วค่อยเปิดโปรแกรม
หัวข้อที่มีชื่อว่า “ตั้งเบรกพอยต์ก่อน แล้วค่อยเปิดโปรแกรม”ลำดับสำคัญ และเครื่องมือนี้บังคับใช้มัน: ตั้งเบรกพอยต์ได้ก่อนที่เซสชันจะเกิดขึ้น เพราะนั่นคือลำดับที่โปรโตคอลกำหนดไว้
ลองสั่งเอเจนต์ประมาณนี้:
ฟังก์ชัน
computeในbin/main.dartคืนค่าผิด ตั้งเบรกพอยต์ที่บรรทัดที่กำหนดค่าให้productเปิดมันภายใต้ดีบักเกอร์ แล้วบอกฉันว่าจริง ๆ แล้วaกับbเป็นเท่าไร
มันจะรันประมาณนี้:
debug(op: "breakpoints", file: "bin/main.dart", lines: [7])debug(op: "launch", program: "bin/main.dart")การเปิดโปรแกรมจะรายงานว่าหยุดที่ไหน:
Launched bin/main.dart on dart (session dart-1). Stopped: breakpoint. Use `stack` to see where.อ่านเฟรม
หัวข้อที่มีชื่อว่า “อ่านเฟรม”debug(op: "stack")→ #1 compute (bin/main.dart:7:3) #2 main (bin/main.dart:2:18)จากนั้นไล่เข้าไปข้างใน:
debug(op: "scopes", frame_id: 1)→ Locals (reference 12)
debug(op: "variables", reference: 12)→ a (int) = 6 b (int) = 7 product (int) = 42ออบเจกต์ที่มีสมาชิกลูกจะรายงาน [expand: reference N] — แต่เฉพาะเมื่อมีอะไรอยู่ข้างหลังจริง ๆ เท่านั้น การขยายที่เอเจนต์ใช้งานไม่ได้จึงไม่ถูกเสนอให้เลย
สำหรับอะไรก็ตามที่มองไม่เห็นในฐานะตัวแปรโลคอล:
debug(op: "evaluate", expression: "config.timeout.inSeconds", frame_id: 1)เดินทีละขั้น
หัวข้อที่มีชื่อว่า “เดินทีละขั้น”| สิ่งที่ต้องการ | อ็อป |
|---|---|
| รันไปจนถึงจุดหยุดถัดไป | continue |
| บรรทัดถัดไป เฟรมเดิม | step_over |
| เข้าไปในการเรียก | step_in |
| ออกไปยังผู้เรียก | step_out |
| หยุดโปรแกรมที่กำลังรัน | pause |
แอตแทชกับสิ่งที่รันอยู่แล้ว
หัวข้อที่มีชื่อว่า “แอตแทชกับสิ่งที่รันอยู่แล้ว”สำหรับโปรเซสที่ค้างอยู่ แทนที่จะเป็นโปรเซสที่คุณกำลังเริ่ม:
debug(op: "attach", port: 5858)จบเซสชัน
หัวข้อที่มีชื่อว่า “จบเซสชัน”debug(op: "terminate")ปิดเซสชันเสมอ อะแดปเตอร์ดีบักเป็นเจ้าของโปรเซสที่ถูกหยุดไว้ซึ่งยึดอะไรก็ตามที่โปรเซสนั้นยึดอยู่ — พอร์ต ล็อก หรือการเชื่อมต่อฐานข้อมูล
เอาต์พุตที่มีขอบเขต
หัวข้อที่มีชื่อว่า “เอาต์พุตที่มีขอบเขต”การขยาย variables บนกราฟออบเจกต์ที่ลึกนั้นไร้ขอบเขตโดยธรรมชาติ — วิดเจ็ต Flutter ตัวเดียวแตะถึงทรีอิลิเมนต์ทั้งต้น จำนวนสมาชิกลูกต่อสโคปถูกจำกัดไว้ที่ 50 ค่าต่าง ๆ ที่ 400 ตัวอักษร และเฟรมสแตกที่ 30 ผลลัพธ์ของเครื่องมือที่ถมเต็มหน้าต่างบริบทคือเครื่องมือที่ทำให้การรันที่มันกำลังช่วยอยู่ต้องจบลง
ที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “ที่เกี่ยวข้อง”- ความฉลาดของโค้ด — ทำไมดีบักเกอร์ คอมไพเลอร์ และตัวจับคู่จึงตอบคำถามต่างกัน
- เครื่องมือเอเจนต์ในตัว — ทุกอ็อปและอาร์กิวเมนต์ของ
debug - วินิจฉัยเอเจนต์ — เมื่อปัญหาอยู่ที่เอเจนต์ ไม่ใช่โค้ด