docs/docs/th/tools/subagents.md
2026-05-04 02:30:14 +00:00

56 KiB
Raw Blame History

read_when sidebarTitle summary title x-i18n
คุณต้องการทำงานเบื้องหลังหรือทำงานแบบขนานผ่านเอเจนต์
คุณกำลังเปลี่ยนแปลง sessions_spawn หรือนโยบายของเครื่องมือตัวแทนย่อย
คุณกำลังนำเซสชันเอเจนต์ย่อยที่ผูกกับเธรดไปใช้ หรือกำลังแก้ไขปัญหาเซสชันดังกล่าว
Sub-agents สร้างการรันเอเจนต์พื้นหลังแบบแยกอิสระ ซึ่งประกาศผลลัพธ์กลับไปยังแชตของผู้ร้องขอ เอเจนต์ย่อย
generated_at model provider source_hash source_path workflow
2026-05-04T02:27:42Z gpt-5.5 openai d0df39e06b952def3eb0b296f36c7dc8c0b0a115785d865236a970c5d453fc37 tools/subagents.md 16

เอเจนต์ย่อยคือการรันเอเจนต์เบื้องหลังที่ถูกสร้างจากการรันเอเจนต์ที่มีอยู่ เอเจนต์เหล่านี้รันในเซสชันของตัวเอง (agent:<agentId>:subagent:<uuid>) และ เมื่อเสร็จสิ้น จะประกาศผลลัพธ์กลับไปยังช่องแชตของผู้ร้องขอ การรันเอเจนต์ย่อยแต่ละครั้งจะถูกติดตามเป็น งานเบื้องหลัง

เป้าหมายหลัก:

  • ทำให้งาน "วิจัย / งานยาว / เครื่องมือที่ช้า" รันแบบขนานได้โดยไม่บล็อกการรันหลัก
  • แยกเอเจนต์ย่อยออกจากกันตามค่าเริ่มต้น (การแยกเซสชัน + sandboxing แบบเลือกได้)
  • ทำให้พื้นผิวเครื่องมือใช้งานผิดได้ยาก: เอเจนต์ย่อยจะไม่ได้รับเครื่องมือเซสชันตามค่าเริ่มต้น
  • รองรับความลึกของการซ้อนที่กำหนดค่าได้สำหรับรูปแบบ orchestrator
**หมายเหตุด้านต้นทุน:** เอเจนต์ย่อยแต่ละตัวมีบริบทและการใช้โทเค็นของตัวเองตามค่าเริ่มต้น สำหรับงานหนักหรืองานซ้ำ ให้ตั้งโมเดลที่ถูกกว่าสำหรับเอเจนต์ย่อยและคงเอเจนต์หลักไว้บนโมเดลคุณภาพสูงกว่า กำหนดค่าผ่าน `agents.defaults.subagents.model` หรือการ override รายเอเจนต์ เมื่อลูกต้องการ transcript ปัจจุบันของผู้ร้องขอจริง ๆ เอเจนต์สามารถขอ `context: "fork"` สำหรับการ spawn ครั้งนั้นได้ เซสชัน subagent ที่ผูกกับเธรดมีค่าเริ่มต้นเป็น `context: "fork"` เพราะจะแตกกิ่งบทสนทนาปัจจุบันไปยังเธรดติดตามผล

คำสั่ง slash

ใช้ /subagents เพื่อตรวจสอบหรือควบคุมการรันเอเจนต์ย่อยสำหรับเซสชันปัจจุบัน:

/subagents list
/subagents kill <id|#|all>
/subagents log <id|#> [limit] [tools]
/subagents info <id|#>
/subagents send <id|#> <message>
/subagents steer <id|#> <message>
/subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]

ใช้ /steer <message> ระดับบนสุดเพื่อ steer การรันที่ใช้งานอยู่ของเซสชันผู้ร้องขอปัจจุบัน ใช้ /subagents steer <id|#> <message> เมื่อเป้าหมายเป็นการรันลูก

/subagents info แสดงข้อมูลเมตาของการรัน (สถานะ, timestamp, id เซสชัน, พาธ transcript, cleanup) ใช้ sessions_history สำหรับมุมมองการเรียกดูย้อนหลังที่มีขอบเขตและผ่านการกรองความปลอดภัยแล้ว; ตรวจสอบพาธ transcript บนดิสก์เมื่อคุณต้องการ transcript ฉบับเต็มแบบดิบ

การควบคุมการผูกเธรด

คำสั่งเหล่านี้ทำงานบนช่องที่รองรับการผูกเธรดแบบคงอยู่ ดู ช่องที่รองรับเธรด ด้านล่าง

/focus <subagent-label|session-key|session-id|session-label>
/unfocus
/agents
/session idle <duration|off>
/session max-age <duration|off>

พฤติกรรมการ spawn

/subagents spawn เริ่มเอเจนต์ย่อยเบื้องหลังในฐานะคำสั่งของผู้ใช้ (ไม่ใช่ relay ภายใน) และส่งการอัปเดตการเสร็จสิ้นขั้นสุดท้ายหนึ่งครั้งกลับไปยังแชตของผู้ร้องขอเมื่อการรันเสร็จสิ้น

- คำสั่ง spawn ไม่บล็อก; จะคืน id การรันทันที - เมื่อเสร็จสิ้น เอเจนต์ย่อยจะประกาศข้อความสรุป/ผลลัพธ์กลับไปยังช่องแชตของผู้ร้องขอ - การเสร็จสิ้นเป็นแบบ push-based หลังจาก spawn แล้ว อย่า poll `/subagents list`, `sessions_list`, หรือ `sessions_history` เป็นลูปเพียงเพื่อรอให้เสร็จ; ตรวจสอบสถานะเฉพาะเมื่อจำเป็นสำหรับการดีบักหรือการแทรกแซง - เมื่อเสร็จสิ้น OpenClaw จะพยายามปิดแท็บ/โปรเซสเบราว์เซอร์ที่ติดตามไว้ซึ่งเปิดโดยเซสชันเอเจนต์ย่อยนั้นก่อนที่โฟลว์ cleanup ของการประกาศจะดำเนินต่อ - OpenClaw ลองส่งมอบ `agent` โดยตรงก่อนด้วย idempotency key ที่เสถียร - หากการส่งมอบโดยตรงล้มเหลว จะ fallback ไปใช้การ routing ผ่านคิว - หากการ routing ผ่านคิวยังใช้ไม่ได้ การประกาศจะถูก retry ด้วย exponential backoff สั้น ๆ ก่อนยอมแพ้ขั้นสุดท้าย - การส่งมอบเมื่อเสร็จสิ้นจะคง route ของผู้ร้องขอที่ resolve แล้ว: route การเสร็จสิ้นที่ผูกกับเธรดหรือผูกกับบทสนทนาจะชนะเมื่อมีให้ใช้; หากต้นทางการเสร็จสิ้นให้มาเพียง channel, OpenClaw จะเติม target/account ที่หายไปจาก route ที่ resolve แล้วของเซสชันผู้ร้องขอ (`lastChannel` / `lastTo` / `lastAccountId`) เพื่อให้การส่งมอบโดยตรงยังทำงานได้ การ handoff การเสร็จสิ้นไปยังเซสชันผู้ร้องขอเป็นบริบทภายในที่สร้างโดย runtime (ไม่ใช่ข้อความที่ผู้ใช้เขียน) และประกอบด้วย:
- `Result` — ข้อความตอบกลับ `assistant` ที่มองเห็นล่าสุด มิฉะนั้นเป็นข้อความ tool/toolResult ล่าสุดที่ sanitize แล้ว การรันที่ล้มเหลวแบบสิ้นสุดจะไม่นำข้อความตอบกลับที่จับไว้กลับมาใช้ซ้ำ
- `Status` — `completed successfully` / `failed` / `timed out` / `unknown`
- สถิติ runtime/token แบบย่อ
- คำสั่งการส่งมอบที่บอกเอเจนต์ผู้ร้องขอให้เขียนใหม่ด้วยเสียง assistant ปกติ (ไม่ส่งต่อ metadata ภายในแบบดิบ)
- `--model` และ `--thinking` override ค่าเริ่มต้นสำหรับการรันนั้นโดยเฉพาะ - ใช้ `info`/`log` เพื่อตรวจสอบรายละเอียดและเอาต์พุตหลังเสร็จสิ้น - `/subagents spawn` เป็นโหมด one-shot (`mode: "run"`) สำหรับเซสชันแบบคงอยู่ที่ผูกกับเธรด ให้ใช้ `sessions_spawn` พร้อม `thread: true` และ `mode: "session"` - สำหรับเซสชัน harness ของ ACP (Claude Code, Gemini CLI, OpenCode, หรือ Codex ACP/acpx ที่ระบุชัดเจน) ให้ใช้ `sessions_spawn` พร้อม `runtime: "acp"` เมื่อเครื่องมือประกาศ runtime นั้น ดู [โมเดลการส่งมอบของ ACP](/th/tools/acp-agents#delivery-model) เมื่อดีบักการเสร็จสิ้นหรือลูป agent-to-agent เมื่อเปิดใช้งาน Plugin `codex` การควบคุมแชต/เธรดของ Codex ควรเลือกใช้ `/codex ...` แทน ACP เว้นแต่ผู้ใช้จะขอ ACP/acpx อย่างชัดเจน - OpenClaw ซ่อน `runtime: "acp"` จนกว่า ACP จะเปิดใช้งาน ผู้ร้องขอไม่ได้อยู่ใน sandbox และมีการโหลด Plugin backend เช่น `acpx` แล้ว `runtime: "acp"` คาดหวัง id harness ACP ภายนอก หรือรายการ `agents.list[]` ที่มี `runtime.type="acp"`; ใช้ runtime เอเจนต์ย่อยค่าเริ่มต้นสำหรับเอเจนต์ config ของ OpenClaw ปกติจาก `agents_list`

โหมดบริบท

เอเจนต์ย่อยแบบ native จะเริ่มแบบแยกเดี่ยว เว้นแต่ผู้เรียกจะขอ fork transcript ปัจจุบันอย่างชัดเจน

โหมด ควรใช้เมื่อใด พฤติกรรม
isolated การวิจัยใหม่, การ implementation อิสระ, งานเครื่องมือที่ช้า, หรือสิ่งใดก็ตามที่สามารถสรุปในข้อความงานได้ สร้าง transcript ลูกที่สะอาด นี่คือค่าเริ่มต้นและช่วยลดการใช้โทเค็น
fork งานที่ขึ้นกับบทสนทนาปัจจุบัน, ผลลัพธ์เครื่องมือก่อนหน้า, หรือคำสั่งที่ละเอียดอ่อนซึ่งมีอยู่แล้วใน transcript ของผู้ร้องขอ แตกกิ่ง transcript ของผู้ร้องขอไปยังเซสชันลูกก่อนที่ลูกจะเริ่ม

ใช้ fork อย่างประหยัด มีไว้สำหรับการมอบหมายงานที่อ่อนไหวต่อบริบท ไม่ใช่ สิ่งทดแทนการเขียน prompt งานที่ชัดเจน

เครื่องมือ: sessions_spawn

เริ่มการรันเอเจนต์ย่อยด้วย deliver: false บน lane subagent ระดับ global จากนั้นรันขั้นตอนประกาศและโพสต์คำตอบประกาศไปยังช่องแชตของผู้ร้องขอ

ความพร้อมใช้งานขึ้นอยู่กับนโยบายเครื่องมือที่มีผลของผู้เรียก โปรไฟล์ coding และ full เปิดเผย sessions_spawn ตามค่าเริ่มต้น โปรไฟล์ messaging ไม่เปิดเผย; เพิ่ม tools.alsoAllow: ["sessions_spawn", "sessions_yield", "subagents"] หรือใช้ tools.profile: "coding" สำหรับเอเจนต์ที่ควรมอบหมายงานได้ นโยบาย allow/deny ของ channel/group, provider, sandbox และรายเอเจนต์ยังสามารถ ลบเครื่องมือนี้หลังขั้นตอนโปรไฟล์ได้ ใช้ /tools จากเซสชันเดียวกันเพื่อยืนยันรายการเครื่องมือที่มีผล

ค่าเริ่มต้น:

  • โมเดล: สืบทอดจากผู้เรียก เว้นแต่คุณตั้ง agents.defaults.subagents.model (หรือ agents.list[].subagents.model รายเอเจนต์); sessions_spawn.model ที่ระบุชัดเจนยังคงชนะ
  • Thinking: สืบทอดจากผู้เรียก เว้นแต่คุณตั้ง agents.defaults.subagents.thinking (หรือ agents.list[].subagents.thinking รายเอเจนต์); sessions_spawn.thinking ที่ระบุชัดเจนยังคงชนะ
  • ระยะหมดเวลาการรัน: หากละ sessions_spawn.runTimeoutSeconds, OpenClaw จะใช้ agents.defaults.subagents.runTimeoutSeconds เมื่อมีการตั้งค่าไว้; มิฉะนั้นจะ fallback เป็น 0 (ไม่มี timeout)

พารามิเตอร์เครื่องมือ

คำอธิบายงานสำหรับเอเจนต์ย่อย ป้ายกำกับที่มนุษย์อ่านได้แบบเลือกได้ Spawn ภายใต้ id เอเจนต์อื่นเมื่อ `subagents.allowAgents` อนุญาต `acp` ใช้เฉพาะสำหรับ harness ACP ภายนอก (`claude`, `droid`, `gemini`, `opencode`, หรือ Codex ACP/acpx ที่ร้องขออย่างชัดเจน) และสำหรับรายการ `agents.list[]` ที่ `runtime.type` เป็น `acp` เฉพาะ ACP Resume เซสชัน harness ACP ที่มีอยู่เมื่อ `runtime: "acp"`; ถูกละเว้นสำหรับการ spawn เอเจนต์ย่อยแบบ native เฉพาะ ACP สตรีมเอาต์พุตการรัน ACP ไปยังเซสชันแม่เมื่อ `runtime: "acp"`; ละเว้นสำหรับการ spawn เอเจนต์ย่อยแบบ native Override โมเดลเอเจนต์ย่อย ค่าที่ไม่ถูกต้องจะถูกข้ามและเอเจนต์ย่อยจะรันบนโมเดลค่าเริ่มต้นพร้อมคำเตือนในผลลัพธ์เครื่องมือ Override ระดับ thinking สำหรับการรันเอเจนต์ย่อย ค่าเริ่มต้นเป็น `agents.defaults.subagents.runTimeoutSeconds` เมื่อมีการตั้งค่า มิฉะนั้นเป็น `0` เมื่อมีการตั้งค่า การรันเอเจนต์ย่อยจะถูก abort หลัง N วินาที เมื่อเป็น `true` จะขอการผูกเธรดของช่องสำหรับเซสชันเอเจนต์ย่อยนี้ หากละ `thread: true` และ `mode` ค่าเริ่มต้นจะกลายเป็น `session` `mode: "session"` ต้องใช้ `thread: true` `"delete"` archive ทันทีหลังประกาศ (ยังคงเก็บ transcript ไว้ผ่านการเปลี่ยนชื่อ) `require` ปฏิเสธการ spawn เว้นแต่ runtime ลูกเป้าหมายอยู่ใน sandbox `fork` แตกกิ่ง transcript ปัจจุบันของผู้ร้องขอไปยังเซสชันลูก เอเจนต์ย่อยแบบ native เท่านั้น การ spawn ที่ผูกกับเธรดมีค่าเริ่มต้นเป็น `fork`; การ spawn ที่ไม่ใช่เธรดมีค่าเริ่มต้นเป็น `isolated` `sessions_spawn` ไม่รับพารามิเตอร์การส่งมอบผ่านช่อง (`target`, `channel`, `to`, `threadId`, `replyTo`, `transport`) สำหรับการส่งมอบ ให้ใช้ `message`/`sessions_send` จากการรันที่ spawn แล้ว

เซสชันที่ผูกกับเธรด

เมื่อเปิดใช้งานการผูกเธรดสำหรับช่อง เอเจนต์ย่อยสามารถคงการผูกกับเธรดไว้ได้ เพื่อให้ข้อความผู้ใช้ติดตามผลในเธรดนั้นยัง route ไปยังเซสชันเอเจนต์ย่อยเดียวกัน

ช่องที่รองรับเธรด

Discord เป็นช่องเดียวที่รองรับอยู่ในปัจจุบัน รองรับ เซสชัน subagent แบบคงอยู่ที่ผูกกับเธรด (sessions_spawn พร้อม thread: true), การควบคุมเธรดด้วยตนเอง (/focus, /unfocus, /agents, /session idle, /session max-age) และคีย์ adapter channels.discord.threadBindings.enabled, channels.discord.threadBindings.idleHours, channels.discord.threadBindings.maxAgeHours, และ channels.discord.threadBindings.spawnSessions

โฟลว์ด่วน

`sessions_spawn` พร้อม `thread: true` (และ `mode: "session"` แบบเลือกได้) OpenClaw สร้างหรือผูกเธรดกับ target ของเซสชันนั้นในช่องที่ใช้งานอยู่ การตอบกลับและข้อความติดตามผลในเธรดนั้น route ไปยังเซสชันที่ผูกไว้ ใช้ `/session idle` เพื่อตรวจสอบ/อัปเดต auto-unfocus เมื่อไม่มีความเคลื่อนไหว และ `/session max-age` เพื่อควบคุม hard cap ใช้ `/unfocus` เพื่อ detach ด้วยตนเอง

การควบคุมด้วยตนเอง

คำสั่ง ผลลัพธ์
/focus <target> ผูกเธรดปัจจุบัน (หรือสร้างเธรดใหม่) เข้ากับเป้าหมายเอเจนต์ย่อย/เซสชัน
/unfocus ลบการผูกสำหรับเธรดที่ถูกผูกอยู่ในปัจจุบัน
/agents แสดงรายการงานที่ทำงานอยู่และสถานะการผูก (thread:<id> หรือ unbound)
/session idle ตรวจสอบ/อัปเดตการยกเลิกโฟกัสอัตโนมัติเมื่อไม่ได้ใช้งาน (เฉพาะเธรดที่ถูกผูกและโฟกัสอยู่)
/session max-age ตรวจสอบ/อัปเดตขีดจำกัดสูงสุดแบบบังคับ (เฉพาะเธรดที่ถูกผูกและโฟกัสอยู่)

สวิตช์การกำหนดค่า

  • ค่าเริ่มต้นทั่วระบบ: session.threadBindings.enabled, session.threadBindings.idleHours, session.threadBindings.maxAgeHours.
  • คีย์แทนที่ระดับช่องทางและคีย์ผูกอัตโนมัติเมื่อสร้าง ขึ้นอยู่กับอะแดปเตอร์ ดู ช่องทางที่รองรับเธรด ด้านบน

ดู ข้อมูลอ้างอิงการกำหนดค่า และ คำสั่ง Slash สำหรับรายละเอียดอะแดปเตอร์ปัจจุบัน

รายการที่อนุญาต

รายการ ID เอเจนต์ที่สามารถกำหนดเป็นเป้าหมายผ่าน `agentId` แบบชัดเจน (`["*"]` อนุญาตทุกรายการ) ค่าเริ่มต้น: เฉพาะเอเจนต์ผู้ร้องขอ หากคุณตั้งค่ารายการและยังต้องการให้ผู้ร้องขอสร้างตัวเองด้วย `agentId` ให้ใส่ ID ของผู้ร้องขอไว้ในรายการ รายการเอเจนต์เป้าหมายเริ่มต้นที่อนุญาต ซึ่งใช้เมื่อเอเจนต์ผู้ร้องขอไม่ได้ตั้งค่า `subagents.allowAgents` ของตัวเอง บล็อกการเรียก `sessions_spawn` ที่ละ `agentId` (บังคับให้เลือกโปรไฟล์อย่างชัดเจน) การแทนที่รายเอเจนต์: `agents.list[].subagents.requireAgentId`

หากเซสชันของผู้ร้องขออยู่ใน sandbox, sessions_spawn จะปฏิเสธเป้าหมาย ที่จะทำงานแบบไม่อยู่ใน sandbox

การค้นหา

ใช้ agents_list เพื่อดูว่า ID เอเจนต์ใดได้รับอนุญาตสำหรับ sessions_spawn อยู่ในขณะนี้ การตอบกลับมีโมเดลที่มีผลจริงของเอเจนต์แต่ละรายการ และเมทาดาทารันไทม์ที่ฝังอยู่ เพื่อให้ผู้เรียกแยกแยะ PI, เซิร์ฟเวอร์แอป Codex และรันไทม์เนทีฟอื่นที่กำหนดค่าไว้ได้

การเก็บถาวรอัตโนมัติ

  • เซสชันเอเจนต์ย่อยจะถูกเก็บถาวรโดยอัตโนมัติหลังจาก agents.defaults.subagents.archiveAfterMinutes (ค่าเริ่มต้น 60)
  • การเก็บถาวรใช้ sessions.delete และเปลี่ยนชื่อทรานสคริปต์เป็น *.deleted.<timestamp> (โฟลเดอร์เดียวกัน)
  • cleanup: "delete" จะเก็บถาวรทันทีหลังประกาศ (ยังคงเก็บทรานสคริปต์ไว้ผ่านการเปลี่ยนชื่อ)
  • การเก็บถาวรอัตโนมัติเป็นแบบ best-effort; ตัวจับเวลาที่ค้างอยู่จะหายไปหาก Gateway รีสตาร์ท
  • runTimeoutSeconds จะไม่เก็บถาวรอัตโนมัติ; จะหยุดเฉพาะงานที่ทำงานอยู่เท่านั้น เซสชันยังคงอยู่จนกว่าจะเก็บถาวรอัตโนมัติ
  • การเก็บถาวรอัตโนมัติใช้กับเซสชันระดับความลึก 1 และระดับความลึก 2 เท่ากัน
  • การล้างเบราว์เซอร์แยกจากการล้างการเก็บถาวร: แท็บ/โปรเซสของเบราว์เซอร์ที่ติดตามไว้จะถูกปิดแบบ best-effort เมื่องานทำงานเสร็จ แม้จะเก็บระเบียนทรานสคริปต์/เซสชันไว้ก็ตาม

เอเจนต์ย่อยแบบซ้อนกัน

ตามค่าเริ่มต้น เอเจนต์ย่อยไม่สามารถสร้างเอเจนต์ย่อยของตัวเองได้ (maxSpawnDepth: 1) ตั้งค่า maxSpawnDepth: 2 เพื่อเปิดใช้การซ้อนหนึ่งระดับ นั่นคือ รูปแบบตัวประสานงาน: หลัก → เอเจนต์ย่อยตัวประสานงาน → เอเจนต์ย่อยของเอเจนต์ย่อยที่เป็นผู้ปฏิบัติงาน

{
  agents: {
    defaults: {
      subagents: {
        maxSpawnDepth: 2, // allow sub-agents to spawn children (default: 1)
        maxChildrenPerAgent: 5, // max active children per agent session (default: 5)
        maxConcurrent: 8, // global concurrency lane cap (default: 8)
        runTimeoutSeconds: 900, // default timeout for sessions_spawn when omitted (0 = no timeout)
      },
    },
  },
}

ระดับความลึก

ความลึก รูปแบบคีย์เซสชัน บทบาท สร้างได้หรือไม่
0 agent:<id>:main เอเจนต์หลัก เสมอ
1 agent:<id>:subagent:<uuid> เอเจนต์ย่อย (ตัวประสานงานเมื่ออนุญาตความลึก 2) เฉพาะเมื่อ maxSpawnDepth >= 2
2 agent:<id>:subagent:<uuid>:subagent:<uuid> เอเจนต์ย่อยของเอเจนต์ย่อย (ผู้ปฏิบัติงานปลายทาง) ไม่เคย

ลำดับการประกาศ

ผลลัพธ์ไหลย้อนกลับขึ้นตามลำดับ:

  1. ผู้ปฏิบัติงานระดับความลึก 2 เสร็จสิ้น → ประกาศไปยังพาเรนต์ของตัวเอง (ตัวประสานงานระดับความลึก 1)
  2. ตัวประสานงานระดับความลึก 1 ได้รับประกาศ สังเคราะห์ผลลัพธ์ เสร็จสิ้น → ประกาศไปยังหลัก
  3. เอเจนต์หลักได้รับประกาศและส่งให้ผู้ใช้

แต่ละระดับเห็นเฉพาะประกาศจากลูกโดยตรงของตัวเองเท่านั้น

**คำแนะนำด้านการปฏิบัติการ:** เริ่มงานลูกหนึ่งครั้งและรอเหตุการณ์เสร็จสิ้น แทนการสร้างลูปโพลรอบ `sessions_list`, `sessions_history`, `/subagents list` หรือคำสั่ง sleep ของ `exec` `sessions_list` และ `/subagents list` จะคงความสัมพันธ์เซสชันลูก ให้โฟกัสกับงานสด ลูกที่ยังทำงานอยู่ยังคงแนบอยู่ ลูกที่จบแล้วจะยัง มองเห็นได้ในหน้าต่างรายการล่าสุดช่วงสั้น ๆ และลิงก์ลูกที่มีเฉพาะในสโตร์และเก่าแล้วจะ ถูกละเว้นหลังจากหน้าต่างความสดใหม่ของมัน วิธีนี้ป้องกันไม่ให้เมทาดาทา `spawnedBy` / `parentSessionKey` เก่าชุบชีวิตลูกเงาหลัง รีสตาร์ท หากเหตุการณ์เสร็จสิ้นของลูกมาถึงหลังจากคุณส่ง คำตอบสุดท้ายแล้ว การติดตามผลที่ถูกต้องคือโทเคนเงียบตามตัวอักษร `NO_REPLY` / `no_reply`

นโยบายเครื่องมือตามความลึก

  • บทบาทและขอบเขตการควบคุมถูกเขียนลงในเมทาดาทาเซสชันตอนสร้าง ซึ่งทำให้คีย์เซสชันแบบแบนหรือที่กู้คืนมาไม่สามารถได้สิทธิ์ตัวประสานงานกลับคืนโดยไม่ตั้งใจ
  • ความลึก 1 (ตัวประสานงาน เมื่อ maxSpawnDepth >= 2): ได้รับ sessions_spawn, subagents, sessions_list, sessions_history เพื่อให้จัดการลูกของตัวเองได้ เครื่องมือเซสชัน/ระบบอื่นยังคงถูกปฏิเสธ
  • ความลึก 1 (ปลายทาง เมื่อ maxSpawnDepth == 1): ไม่มีเครื่องมือเซสชัน (พฤติกรรมเริ่มต้นปัจจุบัน)
  • ความลึก 2 (ผู้ปฏิบัติงานปลายทาง): ไม่มีเครื่องมือเซสชัน — sessions_spawn ถูกปฏิเสธเสมอที่ความลึก 2 ไม่สามารถสร้างลูกต่อได้

ขีดจำกัดการสร้างรายเอเจนต์

แต่ละเซสชันเอเจนต์ (ทุกระดับความลึก) มีลูกที่ทำงานอยู่ได้สูงสุด maxChildrenPerAgent (ค่าเริ่มต้น 5) ในแต่ละครั้ง วิธีนี้ป้องกันการกระจายงานเกินควบคุม จากตัวประสานงานเดียว

การหยุดแบบลูกโซ่

การหยุดตัวประสานงานระดับความลึก 1 จะหยุดลูกระดับความลึก 2 ทั้งหมดของมันโดยอัตโนมัติ:

  • /stop ในแชตหลักหยุดเอเจนต์ระดับความลึก 1 ทั้งหมดและหยุดแบบลูกโซ่ไปยังลูกระดับความลึก 2 ของพวกเขา
  • /subagents kill <id> หยุดเอเจนต์ย่อยที่ระบุและหยุดแบบลูกโซ่ไปยังลูกของมัน
  • /subagents kill all หยุดเอเจนต์ย่อยทั้งหมดสำหรับผู้ร้องขอและหยุดแบบลูกโซ่

การยืนยันตัวตน

การยืนยันตัวตนของเอเจนต์ย่อยถูกแก้ตาม ID เอเจนต์ ไม่ใช่ตามประเภทเซสชัน:

  • คีย์เซสชันเอเจนต์ย่อยคือ agent:<agentId>:subagent:<uuid>
  • สโตร์การยืนยันตัวตนถูกโหลดจาก agentDir ของเอเจนต์นั้น
  • โปรไฟล์การยืนยันตัวตนของเอเจนต์หลักถูกผสานเข้าเป็น fallback; โปรไฟล์เอเจนต์จะแทนที่โปรไฟล์หลักเมื่อมีข้อขัดแย้ง

การผสานเป็นแบบเพิ่มเข้าไป ดังนั้นโปรไฟล์หลักจึงพร้อมใช้งานเป็น fallback เสมอ ยังไม่รองรับการยืนยันตัวตนแบบแยกขาดต่อเอเจนต์อย่างสมบูรณ์

การประกาศ

เอเจนต์ย่อยรายงานกลับผ่านขั้นตอนประกาศ:

  • ขั้นตอนประกาศทำงานภายในเซสชันเอเจนต์ย่อย (ไม่ใช่เซสชันผู้ร้องขอ)
  • หากเอเจนต์ย่อยตอบกลับตรงกับ ANNOUNCE_SKIP จะไม่มีการโพสต์อะไร
  • หากข้อความผู้ช่วยล่าสุดเป็นโทเคนเงียบตรงตัว NO_REPLY / no_reply เอาต์พุตประกาศจะถูกระงับ แม้จะเคยมีความคืบหน้าที่มองเห็นได้ก่อนหน้านั้น

การส่งมอบขึ้นอยู่กับความลึกของผู้ร้องขอ:

  • เซสชันผู้ร้องขอระดับบนสุดใช้การเรียก agent แบบติดตามผลพร้อมการส่งมอบภายนอก (deliver=true)
  • เซสชันเอเจนต์ย่อยผู้ร้องขอแบบซ้อนกันจะได้รับการฉีดติดตามผลภายใน (deliver=false) เพื่อให้ตัวประสานงานสังเคราะห์ผลลัพธ์ลูกภายในเซสชันได้
  • หากเซสชันเอเจนต์ย่อยผู้ร้องขอแบบซ้อนกันหายไป OpenClaw จะ fallback ไปยังผู้ร้องขอของเซสชันนั้นเมื่อมี

สำหรับเซสชันผู้ร้องขอระดับบนสุด การส่งมอบโดยตรงในโหมดเสร็จสิ้นจะ แก้เส้นทางบทสนทนา/เธรดที่ถูกผูกและการแทนที่ของ hook ก่อน จากนั้นเติม ฟิลด์เป้าหมายช่องทางที่หายไปจากเส้นทางที่เซสชันผู้ร้องขอเก็บไว้ วิธีนี้ทำให้การเสร็จสิ้นอยู่ในแชต/หัวข้อที่ถูกต้อง แม้ต้นทางการเสร็จสิ้น จะระบุเฉพาะช่องทางก็ตาม

การรวมผลการเสร็จสิ้นของลูกถูกจำกัดขอบเขตไว้ที่งานผู้ร้องขอปัจจุบันเมื่อ สร้างข้อค้นพบการเสร็จสิ้นแบบซ้อนกัน เพื่อป้องกันไม่ให้เอาต์พุตลูกจากงานก่อนหน้า ที่เก่าแล้วรั่วไหลเข้าไปในการประกาศปัจจุบัน การตอบกลับประกาศจะคง การกำหนดเส้นทางเธรด/หัวข้อเมื่อมีในอะแดปเตอร์ช่องทาง

บริบทประกาศ

บริบทประกาศถูกทำให้เป็นมาตรฐานเป็นบล็อกเหตุการณ์ภายในที่เสถียร:

ฟิลด์ แหล่งที่มา
แหล่งที่มา subagent หรือ cron
ID เซสชัน คีย์/ID เซสชันลูก
ประเภท ประเภทประกาศ + ป้ายกำกับงาน
สถานะ ได้จากผลลัพธ์รันไทม์ (success, error, timeout หรือ unknown) — ไม่ได้ อนุมานจากข้อความโมเดล
เนื้อหาผลลัพธ์ ข้อความผู้ช่วยล่าสุดที่มองเห็นได้ มิฉะนั้นเป็นข้อความ tool/toolResult ล่าสุดที่ผ่านการทำให้ปลอดภัยแล้ว
การติดตามผล คำแนะนำที่อธิบายว่าเมื่อใดควรตอบกลับหรือคงความเงียบ

งานที่ล้มเหลวในสถานะปลายทางจะรายงานสถานะล้มเหลวโดยไม่เล่นซ้ำข้อความตอบกลับ ที่จับไว้ เมื่อ timeout หากลูกผ่านไปได้เพียงการเรียกเครื่องมือ ประกาศ สามารถยุบประวัตินั้นเป็นสรุปความคืบหน้าบางส่วนแบบสั้น แทนการเล่นเอาต์พุตเครื่องมือดิบซ้ำ

บรรทัดสถิติ

เพย์โหลดประกาศมีบรรทัดสถิติที่ท้ายสุด (แม้ถูกห่อบรรทัด):

  • รันไทม์ (เช่น runtime 5m12s)
  • การใช้โทเคน (อินพุต/เอาต์พุต/ทั้งหมด)
  • ค่าใช้จ่ายประมาณการเมื่อกำหนดราคาของโมเดลไว้ (models.providers.*.models[].cost)
  • sessionKey, sessionId และเส้นทางทรานสคริปต์ เพื่อให้เอเจนต์หลักดึงประวัติผ่าน sessions_history หรือตรวจสอบไฟล์บนดิสก์ได้

เมทาดาทาภายในมีไว้สำหรับการประสานงานเท่านั้น การตอบกลับที่แสดงต่อผู้ใช้ ควรเขียนใหม่ด้วยเสียงผู้ช่วยตามปกติ

เหตุใดจึงควรใช้ sessions_history

sessions_history เป็นเส้นทางการประสานงานที่ปลอดภัยกว่า:

  • การเรียกคืนของผู้ช่วยถูกทำให้เป็นมาตรฐานก่อน: ลบแท็กการคิด; ลบโครง <relevant-memories> / <relevant_memories>; ลบบล็อกเพย์โหลด XML การเรียกเครื่องมือแบบข้อความธรรมดา (<tool_call>, <function_call>, <tool_calls>, <function_calls>) รวมถึงเพย์โหลดที่ถูกตัดทอนและไม่เคยปิดอย่างเรียบร้อย; ลบโครง tool-call/result ที่ถูกลดระดับและมาร์กเกอร์บริบทประวัติ; ลบโทเคนควบคุมโมเดลที่รั่ว (<|assistant|>, ASCII <|...|> อื่น, แบบเต็มความกว้าง <...>); ลบ XML การเรียกเครื่องมือ MiniMax ที่มีรูปแบบผิด
  • ข้อความที่ดูเหมือนข้อมูลประจำตัว/โทเคนจะถูกปกปิด
  • บล็อกยาวสามารถถูกตัดทอนได้
  • ประวัติขนาดใหญ่มากสามารถทิ้งแถวเก่ากว่า หรือแทนที่แถวที่ใหญ่เกินด้วย [sessions_history omitted: message too large]
  • การตรวจสอบทรานสคริปต์ดิบบนดิสก์เป็น fallback เมื่อคุณต้องการทรานสคริปต์เต็มแบบตรงทุกไบต์

นโยบายเครื่องมือ

เอเจนต์ย่อยใช้โปรไฟล์และไปป์ไลน์นโยบายเครื่องมือเดียวกับพาเรนต์หรือ เอเจนต์เป้าหมายก่อน หลังจากนั้น OpenClaw จะใช้เลเยอร์ข้อจำกัด เอเจนต์ย่อย

เมื่อไม่มี tools.profile ที่จำกัด เอเจนต์ย่อยจะได้รับ เครื่องมือทั้งหมด ยกเว้น เครื่องมือเซสชัน และเครื่องมือระบบ:

  • sessions_list
  • sessions_history
  • sessions_send
  • sessions_spawn

sessions_history ยังคงเป็นมุมมองการเรียกคืนที่มีขอบเขตและผ่านการทำให้ปลอดภัยที่นี่ด้วย — ไม่ใช่การดัมป์ทรานสคริปต์ดิบ

เมื่อ maxSpawnDepth >= 2 เอเจนต์ย่อยตัวประสานงานระดับความลึก 1 จะได้รับ sessions_spawn, subagents, sessions_list และ sessions_history เพิ่มเติม เพื่อให้จัดการลูกของตัวเองได้

แทนที่ผ่านการกำหนดค่า

{
  agents: {
    defaults: {
      subagents: {
        maxConcurrent: 1,
      },
    },
  },
  tools: {
    subagents: {
      tools: {
        // deny wins
        deny: ["gateway", "cron"],
        // if allow is set, it becomes allow-only (deny still wins)
        // allow: ["read", "exec", "process"]
      },
    },
  },
}

tools.subagents.tools.allow เป็นตัวกรอง allow-only ขั้นสุดท้าย สามารถจำกัด ชุดเครื่องมือที่ resolve แล้วให้แคบลงได้ แต่ไม่สามารถ เพิ่มกลับ เครื่องมือที่ถูกนำออก โดย tools.profile ได้ ตัวอย่างเช่น tools.profile: "coding" รวม web_search/web_fetch แต่ไม่รวมเครื่องมือ browser หากต้องการให้ sub-agent ที่ใช้ profile แบบ coding ใช้ระบบอัตโนมัติของเบราว์เซอร์ได้ ให้เพิ่ม browser ใน ขั้น profile:

{
  tools: {
    profile: "coding",
    alsoAllow: ["browser"],
  },
}

ใช้ agents.list[].tools.alsoAllow: ["browser"] แบบรายเอเจนต์เมื่อมีเพียง เอเจนต์เดียวที่ควรได้รับระบบอัตโนมัติของเบราว์เซอร์

ภาวะพร้อมกัน

Sub-agent ใช้ lane คิวในโปรเซสเฉพาะ:

  • ชื่อ lane: subagent
  • ภาวะพร้อมกัน: agents.defaults.subagents.maxConcurrent (ค่าเริ่มต้น 8)

สถานะมีชีวิตและการกู้คืน

OpenClaw ไม่ถือว่าการไม่มี endedAt เป็นหลักฐานถาวรว่า sub-agent ยังมีชีวิตอยู่ การรันที่ยังไม่จบซึ่งเก่ากว่าหน้าต่าง stale-run จะหยุดนับเป็น active/pending ใน /subagents list, สรุปสถานะ, gating การเสร็จสมบูรณ์ของ descendant และการตรวจสอบภาวะพร้อมกันต่อ session

หลังจาก Gateway รีสตาร์ต การรันที่ restore แล้วแต่ stale และยังไม่จบจะถูกตัดทิ้ง เว้นแต่ session ลูกของการรันนั้นจะถูกทำเครื่องหมาย abortedLastRun: true session ลูกที่ ถูกยกเลิกจากการรีสตาร์ตเหล่านั้นยังสามารถกู้คืนได้ผ่านโฟลว์กู้คืน orphan ของ sub-agent ซึ่งจะส่งข้อความ resume สังเคราะห์ก่อน ล้างเครื่องหมาย aborted

การกู้คืนอัตโนมัติหลังรีสตาร์ตถูกจำกัดต่อ session ลูก หาก sub-agent ลูกตัวเดิมถูกยอมรับให้กู้คืน orphan ซ้ำ ๆ ภายใน หน้าต่าง rapid re-wedge OpenClaw จะบันทึก recovery tombstone ใน session นั้นและหยุด auto-resume ให้ในการรีสตาร์ตภายหลัง รัน openclaw tasks maintenance --apply เพื่อ reconcile task record หรือ openclaw doctor --fix เพื่อล้าง flag การกู้คืน aborted ที่ stale บน session ที่ถูก tombstone

หากการ spawn sub-agent ล้มเหลวด้วย Gateway `PAIRING_REQUIRED` / `scope-upgrade` ให้ตรวจสอบ RPC caller ก่อนแก้ไขสถานะ pairing การประสานงาน `sessions_spawn` ภายในควรเชื่อมต่อเป็น `client.id: "gateway-client"` พร้อม `client.mode: "backend"` ผ่าน auth แบบ direct loopback shared-token/password เส้นทางนั้นไม่ขึ้นกับ scope baseline ของ paired-device ของ CLI ผู้เรียกจากระยะไกล, `deviceIdentity` แบบ explicit, เส้นทาง device-token แบบ explicit และไคลเอนต์ browser/node ยังต้องได้รับการอนุมัติ device ตามปกติสำหรับ scope upgrade

การหยุด

  • การส่ง /stop ในแชต requester จะยกเลิก session ของ requester และหยุดการรัน sub-agent ที่ active ใด ๆ ที่ spawn จาก session นั้น โดย cascade ไปยังลูกซ้อน
  • /subagents kill <id> หยุด sub-agent เฉพาะตัวและ cascade ไปยังลูกของมัน

ข้อจำกัด

  • การ announce ของ sub-agent เป็นแบบ best-effort หาก Gateway รีสตาร์ต งาน "announce back" ที่ pending จะสูญหาย
  • Sub-agent ยังคงใช้ทรัพยากรของโปรเซส Gateway เดียวกัน ให้ถือว่า maxConcurrent เป็นวาล์วนิรภัย
  • sessions_spawn เป็น non-blocking เสมอ: จะคืน { status: "accepted", runId, childSessionKey } ทันที
  • context ของ sub-agent inject เฉพาะ AGENTS.md + TOOLS.md (ไม่มี SOUL.md, IDENTITY.md, USER.md, HEARTBEAT.md หรือ BOOTSTRAP.md)
  • ความลึกการซ้อนสูงสุดคือ 5 (maxSpawnDepth range: 15) แนะนำให้ใช้ความลึก 2 สำหรับกรณีใช้งานส่วนใหญ่
  • maxChildrenPerAgent จำกัดจำนวนลูกที่ active ต่อ session (ค่าเริ่มต้น 5, range 120)

ที่เกี่ยวข้อง