ทำไมฉันจึงเลิกใช้ orchestrator subagent ใน Claude Code — ข้อจำกัดเชิงโครงสร้าง 3 ข้อจากสเปกฮาร์เนสทางการ
บทนำ
ตอนที่ฉันประกอบการตั้งค่าที่แบ่งงานให้ AI หลายตัวเป็นครั้งแรก หนึ่งในบทบาทที่ฉันวางไว้คือ “ผู้กระจายงาน” มันตัดสินว่าใครได้งานอะไรและตามลำดับใด ตรวจสอบผลลัพธ์ แล้วส่งต่อ — ใกล้เคียงกับหัวหน้าโครงการในทีมมนุษย์ การแทรกชั้นของ AI ที่อุทิศให้บทบาทนี้ดูสมเหตุสมผลเมื่อคิดโดยสัญชาตญาณ
แต่พอลองใช้งานจริง บทบาทนี้กลับกลายเป็นว่า ทำงานไม่ได้ในเชิงโครงสร้าง และหลักฐานสำหรับเรื่องนี้ไม่ใช่รสนิยมหรือลางสังหรณ์ แต่ระบุไว้อย่างชัดเจนในสเปกทางการของ Claude Code (สเปกฮาร์เนส) บทความนี้เรียงเหตุผล 3 ข้อของการเลิกใช้ผู้กระจายงาน และบันทึกความผิดพลาดเล็กแต่มองข้ามไม่ได้ ที่ฉันพบหลายสัปดาห์ต่อมาตอนตรวจคำอธิบายของตัวเองเทียบกับต้นฉบับ
ข้อบกพร่องที่ 1: ไม่มีวิธีถามเจ้าของ
กฎการทำงานที่ฉันให้ผู้กระจายงานไว้ มีประโยคว่า “เมื่อไม่แน่ใจในการตัดสิน ให้ถามเจ้าของ” ดูสมเหตุสมผล แต่สเปกทางการเขียนว่า:
The first filter removes these tools, even when listed in the
toolsfield:
AskUserQuestion
เครื่องมือสำหรับตั้งคำถามกับเจ้าของถูก ถอดออกทั้งหมด แม้จะเขียนระบุไว้ในรายการเครื่องมือที่อนุญาตของ AI ลูกน้องแล้วก็ตาม นั่นคือ “การถาม” ไม่มีอยู่เป็นตัวเลือกตั้งแต่แรก คำสั่งที่ว่า “ถามเมื่อไม่แน่ใจ” สำหรับคู่สนทนาที่ไม่มีวิธีถาม จึงมีความหมายเท่ากับ “ตัดสินใจเอง”
ข้อบกพร่องที่ 2: รับผลลัพธ์ไม่ได้
ผลของงานที่มอบหมายไปจะกลับมาเมื่อไหร่ คำอธิบายทางการเขียนว่า:
As of v2.1.198, subagents run in the background by default.
A background subagent’s results reach Claude as a completion notification in a later turn.
โหมดการทำงานตั้งต้นคือ “เบื้องหลัง” — เดินหน้าต่อโดยไม่รอผลลัพธ์ แล้วรายงานจะมาถึงใน “เทิร์นถัดไป” ปัญหาเกิดขึ้น เมื่อฝ่ายที่มอบหมายเองก็เป็น AI ลูกน้อง เมื่อผู้กระจายงานโยนงานลงไปอีกชั้น รายงานควรจะมาถึงใน “เทิร์นถัดไป” ของผู้กระจายงาน แต่ผู้กระจายงานจบเทิร์นของตัวเองไปแล้วตั้งแต่วินาทีที่โยนงาน จึงไม่มีใครอยู่ตรงไหนที่จะรับมันได้ รูปแบบนี้เกิดขึ้นจริงหลายครั้ง งานค้างอยู่และไม่มีรายงานมาถึง
ข้อบกพร่องที่ 3: ตรวจสอบรายงานไม่ได้
นิยามของผู้กระจายงานไม่ได้รวมเครื่องมือสำหรับตรวจสอบสถานะเอาไว้ (สิทธิ์รันคำสั่งเชลล์) ดังนั้นแม้ AI ลูกน้องจะรายงานว่า “เสร็จแล้ว” ก็ไม่มีทางยืนยันได้ และไม่มีทางเลือกอื่นนอกจากส่งต่อขึ้นไปตามที่รายงานมา ในทางปฏิบัติ เมื่อเทียบกับรายงานที่ว่า “ให้สร้างเบรนช์แล้ว” จำนวนไฟล์ที่เปลี่ยน จำนวนเบรนช์ และจำนวนคอมมิตที่วัดได้จริง เป็นศูนย์ทั้งหมด
มีหลักฐานนอกเหนือจากโครงสร้างด้วย
นอกเหนือจากข้อบกพร่อง 3 ข้อ เอกสารที่ Anthropic เขียนเองเกี่ยวกับการออกแบบฮาร์เนส มีประโยคที่ทำให้การออกแบบแบบผู้กระจายงานยากจะสนับสนุนได้
Separating the agent doing the work from the agent judging it proves to be a strong lever … tuning a standalone evaluator to be skeptical turns out to be far more tractable than making a generator critical of its own work.
Out of the box, Claude is a poor QA agent. In early runs, I watched it identify legitimate issues, then talk itself into deciding they weren’t a big deal and approve the work anyway.
ผู้กระจายงานมักลงเอยด้วยการยืนอยู่ในตำแหน่งที่ทำทั้ง “ให้คนอื่นทำงาน” และ “ตรวจสอบงานนั้น” แต่ตามข้อสังเกตทางการ การให้มันประเมินผลงานของตัวเอง หมายถึงมันจะพูดจนตัวเองเชื่อว่าปัญหาที่แท้จริงไม่ใช่เรื่องใหญ่ แล้วอนุมัติงานนั้นไป การแยกเอเจนต์ที่ทำงานออกจากเอเจนต์ที่ตัดสิน คือคานงัดที่ได้ผลในตัวมันเอง และการตั้งค่าที่โหลดทั้งสองอย่างลงบนผู้กระจายงานตัวเดียว หันหน้าไปคนละทางกับข้อค้นพบนั้น
การออกแบบที่ถูกเลิกใช้
ด้วยน้ำหนักของข้อบกพร่องเชิงโครงสร้าง 3 ข้อและข้อค้นพบนั้น ฉันถอดบทบาทที่ทำหน้าที่กระจายงานอย่างเดียวออกไป และกลับไปใช้รูปแบบที่ฝ่ายมอบหมายสั่งการผู้ดำเนินการและผู้ตรวจสอบโดยตรง ฉันยังปรับขอบเขตของอุปกรณ์นิรภัยด้วย เพื่อไม่ให้ไปขวางการทำงานที่มีต้นทางจาก AI ลูกน้องโดยไม่จำเป็น
2026-08-06: การออกแบบที่มอบหมายงานผ่าน "ผู้กระจายงาน" ตัวเดียว
│
├─▶ ข้อบกพร่อง 1: ถามเจ้าของไม่ได้
│ └─ เครื่องมือสำหรับถามถูกถอดออกโดยไม่มีเงื่อนไขจากทุก subagent (ทางการ)
│
├─▶ ข้อบกพร่อง 2: รับผลลัพธ์ไม่ได้
│ └─ โหมดการทำงานตั้งต้นคือ "ผลลัพธ์มาถึงในเทิร์นถัดไป"
│ └─ เมื่อผู้กระจายงานเองเป็น subagent จึงไม่มีปลายทางอยู่
│ (เส้นย้อนกลับ: เกิดขึ้นจริงหลายครั้ง งานค้างและไม่มีรายงาน)
│
└─▶ ข้อบกพร่อง 3: ตรวจสอบรายงานไม่ได้
└─ นิยามของผู้กระจายงานไม่มีสิทธิ์รันเชลล์
└─ ไม่มีทางเลือกอื่นนอกจากส่ง "เสร็จแล้ว" ขึ้นไปตรง ๆ
│
▼
+ หลักฐานเพิ่มเติม: การประเมินตัวเองไม่ได้ผล (ข้อค้นพบจากฮาร์เนสทางการ)
│
▼
เลิกใช้บทบาทผู้กระจายงาน เปลี่ยนไปสั่งการผู้ดำเนินการและผู้ตรวจสอบโดยตรง
│
▼ …(สองสัปดาห์ต่อมา อ่านแหล่งข้อมูลปฐมภูมิเดิมซ้ำ)
2026-08-19: เทียบคำอธิบายที่ฉันเขียนเป็นหลักฐานของ "ถามเจ้าของไม่ได้" กับต้นฉบับทางการทีละตัวอักษร
│
└─▶ พบว่าตกอนุประโยคเงื่อนไขไปหนึ่งข้อ
(เส้นย้อนกลับ: การตัดสินใจเลิกใช้ไม่สั่นคลอน แต่คำอ้างอิงที่รองรับมันบกพร่อง)
วัดตอนนี้ — ผู้กระจายงานหายไปจริงหรือไม่
แทนที่จะปล่อยไว้เป็นแค่คำบรรยาย ฉันตรวจการตั้งค่าปัจจุบันจริง ๆ การนับไฟล์นิยามของ AI ลูกน้องที่งานถูกส่งต่อไปให้ ได้ผลดังนี้ (วัดเมื่อ 2026-08-24 ชื่อไฟล์ถูกแทนที่ด้วยป้ายบทบาท)
$ grep -H "^model:" <定義ファイル群>
<review-agent-1>.md:model: opus
<work-agent-1>.md:model: sonnet
<work-agent-2>.md:model: sonnet
<work-agent-3>.md:model: sonnet
<review-agent-2>.md:model: opus
<work-agent-4>.md:model: sonnet
<work-agent-5>.md:model: sonnet
<review-agent-3>.md:model: opus
<work-agent-6>.md:model: sonnet
$ ls <定義ファイル群> | wc -l
9
ผู้ตรวจสอบ 3 ตัวและผู้ทำงาน 6 ตัว รวม 9 ตัว ไม่มีบทบาทที่ทำหน้าที่กระจายงานอย่างเดียวอยู่ในฐานะไฟล์นิยาม การตัดสินใจเลิกใช้สะท้อนอยู่ไม่เพียงในข้อความ แต่ในการตั้งค่าจริงด้วย
หลายสัปดาห์ต่อมา ข้อบกพร่องกลับอยู่ในคำอ้างอิงของฉันเอง
ราวสองสัปดาห์หลังเลิกใช้ผู้กระจายงาน ฉันมีโอกาสอ่านสเปกทางการฉบับเดิมซ้ำ ครั้งนี้ฉันไม่ได้อ่านในแง่ “การตัดสินก่อนหน้าถูกต้องหรือไม่” แต่ในแง่ “ฉันอ้างอิงมันไว้อย่างไร” โดยเทียบกับต้นฉบับทีละตัวอักษร
คำอธิบายที่ฉันเขียนไว้เป็นหลักฐานของการเลิกใช้ระบุว่า:
AskUserQuestionถูกถอดออกโดยไม่มีเงื่อนไขจากทุก subagentEnterPlanMode/ExitPlanModeก็เช่นกัน
ส่วนต้นฉบับทางการเขียนว่า:
Agent, when the subagent is at the depth limit; in a fork the tool stays listed but returns an error instead of spawningAskUserQuestionEnterPlanModeExitPlanMode, unless the subagent’spermissionModeisplan
AskUserQuestion ไม่มีเงื่อนไขกำกับ แต่ ExitPlanMode มีเงื่อนไขว่า “เว้นแต่โหมดการทำงานคือ plan” และ Agent ก็มีเงื่อนไขเช่นกัน: “เฉพาะเมื่อถึงขีดจำกัดความลึกแล้ว” คำอธิบายของฉันเหมารายการที่มีเงื่อนไขเหล่านั้นเข้าไปว่า “ไม่มีเงื่อนไขเหมือนกัน” แก่นของการตัดสินใจเลิกใช้เองไม่สั่นคลอน — การถอด AskUserQuestion ออกโดยไม่มีเงื่อนไข แต่คำอ้างอิงที่อยู่รายล้อมมันมีความผิดพลาดของการตกอนุประโยคเงื่อนไข
การตกอนุประโยคเงื่อนไขแล้วสรุปกว้างเกินไปตอนอ้างอิงแหล่งข้อมูลปฐมภูมิ ไม่ใช่เรื่องที่เกิดครั้งเดียวในที่นี้ แต่เป็นชนิดของความผิดพลาดที่เกิดซ้ำ ถ้าฉันใช้คำอธิบายที่เคยเขียนไว้ครั้งหนึ่งต่อไปโดยไม่อ่านซ้ำ ด้วยเหตุผลว่า “ตรวจไปแล้ว” ฉันก็คงไม่มีวันสังเกตเห็นสิ่งที่ตกหล่นไป
การตัดสินใจเลิกใช้บางอย่าง ไม่ใช่จุดจบของเรื่อง
การถอดชั้นผู้กระจายงานออกแก้ปัญหาเชิงโครงสร้างเรื่องรายงานที่ไม่มาถึงและคำกล่าวอ้างที่ยืนยันไม่ได้ แต่การตรวจสอบซ้ำคำอธิบายที่รองรับการตัดสินใจนั้นแสดงให้เห็นว่า ความเข้าใจโครงสร้างถูกต้องได้ ในขณะที่ประโยคที่ใช้แสดงมันมีความผิดพลาด การตัดสินใจกับข้อความที่บันทึกการตัดสินใจนั้น ต้องถูกตรวจสอบแยกจากกัน
สไตล์เอาต์พุตของ Claude Code ไม่ถูกสืบทอดไปยัง subagent — สเปกทางการ และการตรวจสอบด้วยการใช้งานจริง
ฉันตัดชั้นหนึ่งออกไม่ใช่เพราะบทบาทนั้นมีกำลังไม่พอ “ส่งให้คนตัดสินเมื่อจำเป็นต้องตัดสิน” เป็นไปไม่ได้เชิงโครงสร้างจากตำแหน่งนั้น — มันคือความผิดพลาดของการวางตำแหน่ง ที่ไปมอบอำนาจสั่งการให้บทบาทซึ่งทำมันไม่ได้ จนถึงตอนนี้ยังไม่มีอะไรผิดพลาดจากการที่เลิกใช้มันไป