使用 Command Queue 解決 Agent 併發衝突
你有沒有遇過這種狀況?當多個使用者同時傳訊息給你的 Agent,或是同一個人在短時間內連發好幾封訊息,你的後台就開始打架了。LLM 呼叫不只昂貴,如果多個程序同時搶著讀寫同一個 session 檔案或 log,很容易導致系統混亂,甚至讓你直接撞上 API 的 rate limit。
我們透過一個輕量化的 in-process 佇列來序列化 inbound 的自動回覆流程。這能確保同一個 session 內的操作乖乖排隊,同時又允許不同 session 之間保持安全的並行運作。
需要準備的東西
Section titled “需要準備的東西”- 使用 Gateway 回覆管線的 inbound 頻道(如 WhatsApp, Telegram, Slack, Discord, Signal, iMessage, webchat 等)
- 專案中已實作
runEmbeddedPiAgent
預設情況下,所有頻道都會使用 collect 模式。如果你想自定義全域設定或特定頻道的行為,可以在設定檔中加入以下內容:
{ messages: { queue: { mode: "collect", debounceMs: 1000, cap: 20, drop: "summarize", byChannel: { discord: "collect" }, }, },}如果你想在特定對話中即時切換模式,直接在對話框輸入指令即可:
/queue collect/queue steer/queue reset(恢復預設值)
這個佇列採用 lane-aware FIFO 機制,根據 session key(lane session:<key>)來排隊,保證同一個 session 同一時間只有一個活動中的 run。
接著,這些 session run 會被放入 global lane(預設名稱為 main),整體的並行數量受到 agents.defaults.maxConcurrent 的限制。當訊息進入佇列時,如果該頻道支援,系統會立即觸發「輸入中」狀態(typing indicators),所以使用者不會覺得 Agent 沒反應。
佇列模式 (Queue Modes)
Section titled “佇列模式 (Queue Modes)”你可以根據需求決定新訊息如何影響目前的執行流程:
collect(預設):將所有排隊中的訊息合併成一次後續回覆。如果訊息來自不同頻道,則會分開處理以確保路由正確。steer:立即介入目前的執行(在下一個 tool 邊界後取消掛起的工具呼叫)。如果不支援 streaming,則會退回到 followup 模式。followup:在目前的執行結束後,再排隊進行下一次 Agent turn。steer-backlog:立即介入目前的執行,同時保留該訊息供後續回覆使用。interrupt(舊版):中止該 session 目前的執行,直接跑最新的訊息。
進階設定選項
Section titled “進階設定選項”這些選項適用於 followup、collect 與 steer-backlog:
debounceMs: 等待一段安靜時間後才開始後續動作,避免 Agent 不斷回覆「請繼續」。cap: 每個 session 允許排隊的最大訊息數。drop: 當超過容量上限時的處理策略,可選擇old(丟棄舊訊息)、new(丟棄新訊息)或summarize。summarize: 會將被丟棄的訊息整理成簡短的點列清單,作為合成的提示詞加入後續回覆中。
- 指令看起來卡住了:開啟 verbose logs,尋找 “queued for …ms” 字樣。這能幫你確認佇列是否正在消耗中。
- 想確認佇列深度:同樣開啟 verbose logs,觀察佇列的時間線資訊。
這套機制完全基於 TypeScript 與 Promise 實作,不依賴外部資料庫或背景 worker 執行緒,非常輕量。
如果你在設定過程中遇到問題,可以詢問 AI Setup Assistant 獲取即時協助。
OpenClaw Expert
還是卡住了?
如果這篇文件沒有解決你的情境,直接問 OpenClaw Expert,拿到可執行步驟。