---
read_when:
    - การเปลี่ยนการทำงานหรือการทำงานพร้อมกันของการตอบกลับอัตโนมัติ
summary: การออกแบบคิวคำสั่งที่ทำให้การรันตอบกลับอัตโนมัติของข้อความขาเข้าเป็นแบบลำดับเดียว
title: คิวคำสั่ง
x-i18n:
    generated_at: "2026-04-23T05:31:19Z"
    model: gpt-5.4
    provider: openai
    source_hash: 36e1d004e9a2c21ad1470517a249285216114dd4cf876681cc860e992c73914f
    source_path: concepts/queue.md
    workflow: 15
---

# คิวคำสั่ง (2026-01-16)

เรา serialize การรันตอบกลับอัตโนมัติของข้อความขาเข้า (ทุกช่องทาง) ผ่านคิวในโปรเซสขนาดเล็ก เพื่อป้องกันไม่ให้การรันของเอเจนต์หลายรายการชนกัน ขณะเดียวกันก็ยังเปิดให้มีการทำงานขนานกันได้อย่างปลอดภัยข้ามเซสชัน

## ทำไมต้องมี

- การรันตอบกลับอัตโนมัติอาจมีต้นทุนสูง (การเรียก LLM) และอาจชนกันได้เมื่อมีข้อความขาเข้าหลายรายการมาถี่ ๆ
- การ serialize ช่วยหลีกเลี่ยงการแย่งใช้ทรัพยากรที่ใช้ร่วมกัน (ไฟล์เซสชัน, log, stdin ของ CLI) และลดโอกาสเจอ rate limit จากต้นทาง

## วิธีการทำงาน

- คิว FIFO ที่รับรู้ lane จะ drain แต่ละ lane ด้วยเพดานการทำงานพร้อมกันที่ตั้งค่าได้ (ค่าเริ่มต้นคือ 1 สำหรับ lane ที่ไม่ได้ตั้งค่า; `main` ใช้ค่าเริ่มต้น 4, `subagent` ใช้ 8)
- `runEmbeddedPiAgent` จะ enqueue ตาม **session key** (lane `session:<key>`) เพื่อรับประกันว่าจะมีการรันที่ active ได้เพียงรายการเดียวต่อหนึ่งเซสชัน
- จากนั้นการรันของแต่ละเซสชันจะถูกส่งเข้าคิวไปยัง **global lane** (`main` โดยค่าเริ่มต้น) เพื่อจำกัดการทำงานพร้อมกันโดยรวมด้วย `agents.defaults.maxConcurrent`
- เมื่อเปิด verbose logging การรันที่อยู่ในคิวจะส่งข้อความแจ้งสั้น ๆ หากต้องรอนานกว่า ~2 วินาทีก่อนเริ่ม
- ตัวบ่งชี้การพิมพ์ยังคงทำงานทันทีเมื่อ enqueue (ในช่องทางที่รองรับ) ดังนั้นประสบการณ์ผู้ใช้จะไม่เปลี่ยนไประหว่างที่รอคิว

## โหมดคิว (แยกตามช่องทาง)

ข้อความขาเข้าสามารถชี้ทางให้การรันปัจจุบัน รอ turn ติดตามผล หรือทำทั้งสองอย่าง:

- `steer`: inject เข้าไปในการรันปัจจุบันทันที (ยกเลิก tool call ที่รอดำเนินการหลังผ่านขอบเขต tool ถัดไป) หากไม่ได้สตรีม จะ fallback ไปเป็น followup
- `followup`: เข้าคิวเพื่อรอ turn ถัดไปของเอเจนต์หลังจากการรันปัจจุบันจบลง
- `collect`: รวมข้อความที่เข้าคิวทั้งหมดเป็น turn ติดตามผล **เพียง turn เดียว** (ค่าเริ่มต้น) หากข้อความชี้ไปคนละช่องทาง/เธรด ระบบจะ drain แยกกันเพื่อคงการกำหนดเส้นทางไว้
- `steer-backlog` (หรือ `steer+backlog`): steer ตอนนี้ **และ** เก็บข้อความไว้สำหรับ turn ติดตามผลด้วย
- `interrupt` (legacy): ยุติการรันที่ active สำหรับเซสชันนั้น แล้วรันข้อความล่าสุด
- `queue` (ชื่อแทนแบบ legacy): เหมือนกับ `steer`

`steer-backlog` หมายความว่าคุณอาจได้คำตอบติดตามผลหลังจากการรันที่ถูก steer ไปแล้ว ดังนั้น
บนพื้นผิวการใช้งานที่สตรีมได้อาจดูเหมือนมีข้อความซ้ำ ควรใช้ `collect`/`steer` หากคุณต้องการ
หนึ่งคำตอบต่อหนึ่งข้อความขาเข้า
ส่ง `/queue collect` เป็นคำสั่งเดี่ยว ๆ (แยกตามเซสชัน) หรือตั้ง `messages.queue.byChannel.discord: "collect"`

ค่าเริ่มต้น (เมื่อไม่ได้ตั้งในคอนฟิก):

- ทุกพื้นผิวการใช้งาน → `collect`

ตั้งค่าแบบ global หรือแยกตามช่องทางผ่าน `messages.queue`:

```json5
{
  messages: {
    queue: {
      mode: "collect",
      debounceMs: 1000,
      cap: 20,
      drop: "summarize",
      byChannel: { discord: "collect" },
    },
  },
}
```

## ตัวเลือกของคิว

ตัวเลือกเหล่านี้ใช้กับ `followup`, `collect` และ `steer-backlog` (รวมถึง `steer` เมื่อ fallback ไปเป็น followup):

- `debounceMs`: รอให้เงียบก่อนเริ่ม turn ติดตามผล (ป้องกัน “continue, continue”)
- `cap`: จำนวนข้อความสูงสุดที่เข้าคิวได้ต่อเซสชัน
- `drop`: นโยบายเมื่อเกินเพดาน (`old`, `new`, `summarize`)

`Summarize` จะเก็บรายการหัวข้อสั้น ๆ ของข้อความที่ถูกทิ้ง และ inject เข้าไปเป็น prompt ติดตามผลแบบสังเคราะห์
ค่าเริ่มต้น: `debounceMs: 1000`, `cap: 20`, `drop: summarize`

## การ override แยกตามเซสชัน

- ส่ง `/queue <mode>` เป็นคำสั่งเดี่ยว ๆ เพื่อเก็บโหมดสำหรับเซสชันปัจจุบัน
- สามารถรวมตัวเลือกได้: `/queue collect debounce:2s cap:25 drop:summarize`
- `/queue default` หรือ `/queue reset` จะล้าง override ของเซสชัน

## ขอบเขตและการรับประกัน

- ใช้กับการรันเอเจนต์แบบตอบกลับอัตโนมัติในทุกช่องทางขาเข้าที่ใช้ pipeline ตอบกลับของ Gateway (WhatsApp web, Telegram, Slack, Discord, Signal, iMessage, webchat ฯลฯ)
- lane เริ่มต้น (`main`) ใช้ทั้งโปรเซสสำหรับข้อความขาเข้า + Heartbeat หลัก; ตั้ง `agents.defaults.maxConcurrent` เพื่อให้หลายเซสชันทำงานขนานกันได้
- อาจมี lane เพิ่มเติม (เช่น `cron`, `subagent`) เพื่อให้งานเบื้องหลังทำงานขนานกันได้โดยไม่บล็อกการตอบกลับขาเข้า การรันแบบแยกส่วนเหล่านี้จะถูกติดตามเป็น [งานเบื้องหลัง](/th/automation/tasks)
- lane แยกตามเซสชันรับประกันว่าจะมีการรันของเอเจนต์เพียงรายการเดียวเท่านั้นที่แตะเซสชันใดเซสชันหนึ่งในเวลาเดียวกัน
- ไม่มี dependency ภายนอกหรือ worker thread เบื้องหลัง ใช้เพียง TypeScript + promises

## การแก้ไขปัญหา

- หากดูเหมือนว่าคำสั่งค้างอยู่ ให้เปิด verbose logs แล้วมองหาบรรทัด “queued for …ms” เพื่อยืนยันว่าคิวกำลัง drain
- หากคุณต้องการดูความลึกของคิว ให้เปิด verbose logs และดูบรรทัดเกี่ยวกับเวลาในคิว
