乐于分享
好东西不私藏

OpenClaw Session 并发设计详解:从单线程到多 Session 排队

OpenClaw Session 并发设计详解:从单线程到多 Session 排队

OpenClaw 不是一个多租户 SaaS 平台。它是一个个人 AI 助手基础设施——跑在你自己的机器上,连接你自己的消息渠道,用你自己的 API key。

但"个人助手"不意味着"一次只能做一件事"。你可能同时在 WhatsApp 上问它天气、在 Slack 群里让它写代码、在 Telegram 上让它查日程。这就涉及到并发——多个对话同时进行时,OpenClaw 怎么处理?

这篇把 OpenClaw 的 session 并发模型、消息队列、限制和瓶颈讲清楚。


核心模型:Session 内串行,Session 间可并行

这是理解 OpenClaw 并发的关键一句话。

单个 session 内:消息严格串行。一条消息处理完(LLM 调用结束、工具执行完毕、回复发出),才处理下一条。不存在同一个对话里两条消息同时被 LLM 处理的情况。

不同 session 之间:可以并行。你在 WhatsApp 的私聊(session A)和 Slack 某个群(session B)同时发消息,两个 session 可以同时调 LLM,互不干扰。

并行的上限由一个配置项控制:

{
  agents: {
    defaults: {
      maxConcurrent: 3, // 默认值是 1
    }
  }
}

maxConcurrent 的含义:同一时刻,最多允许几个 session 同时进行 LLM 调用

默认值是 1。也就是说,开箱即用的 OpenClaw 在任意时刻只有一个 session 在跑 LLM 调用。其他 session 的消息不会丢——它们进入队列,等当前 session 处理完再轮到下一个。

设成 3 就是最多 3 个 session 同时调 LLM。设成 10 就是 10 个。

为什么默认是 1? 因为 OpenClaw 的定位是个人助手。一个人同时需要 agent 并行处理多件事的场景不多,而且默认 1 能最大程度避免 API rate limit 问题。多人使用场景再调高。


Session 是什么?怎么创建的?

Session 是 OpenClaw 中一段独立的对话上下文。每个 session 有自己的消息历史、token 计数和状态。Session 自动创建,规则取决于消息来源:

私聊(DM):由 session.dmScope 配置决定

  • main
    (默认):所有私聊共享一个 main session
  • per-peer
    :每个发送者一个独立 session
  • per-channel-peer
    :每个渠道+发送者一个 session(推荐多人场景)
  • per-account-channel-peer
    :每个账号+渠道+发送者一个 session

默认 main 意味着你从 WhatsApp 和 Telegram 分别给 agent 发私信,它们进入同一个 session——agent 在两个渠道看到的是同一段对话。这对单人使用很方便(跨设备连续对话),但多人使用时会泄露上下文,所以多人场景必须改成 per-channel-peer

群聊:每个群自动一个独立 session。

话题/Thread:每个话题自动一个独立 session(Slack thread、Discord thread、Telegram topic)。

Session key 的格式长这样:

  • 私聊(main 模式):agent:main:main
  • 私聊(per-channel-peer):agent:main:slack:dm:U0AKT6SESGY
  • 群聊:agent:main:slack:group:C0AJZ7120AE
  • Cron 任务:cron:daily-cleanup
  • Webhook:hook:abc123

当 Session 正忙时:消息队列机制

如果你在 agent 正在处理一条消息时又发了一条,会发生什么?

由 messages.queue.mode 决定,默认是 collect

{
messages: {
queue: {
mode:"collect"//默认
debounceMs:1000,
cap:20,
drop:"summarize",
    }
  }
}

6 种队列模式

  • collect
    (默认):收集等待中的消息,当前 run 结束后合并处理
  • steer
    :新消息直接注入当前运行中的对话(steering)
  • followup
    :当前 run 结束后作为 follow-up 处理
  • queue
    :严格排队,一条一条处理
  • interrupt
    :新消息打断当前 run,重新开始
  • steer-backlog
     / steer+backlog:steer 的变体

collect 是最常用的:agent 在忙的时候,你连续发了 3 条消息,agent 处理完当前任务后把这 3 条合并成一个上下文一起处理,而不是分开跑 3 次 LLM。

steer 更激进:新消息直接中途插入正在进行的对话。适合你想在 agent 工作过程中给它补充指令的场景。

队列有容量上限(cap,默认 20 条)。超出后的行为由 drop 决定:

  • old
    :丢弃最旧的消息
  • new
    :丢弃最新的消息
  • summarize
    :用 LLM 总结被丢弃的消息

入站防抖(Inbound Debounce)

在消息进入队列之前,还有一层防抖:

{
messages: {
inbound: {
debounceMs:2000,
byChannel: {
whatsapp:5000,
slack:1500,
      }
    }
  }
}

同一个人在 2 秒内连续发了 3 条纯文本消息 → 合并成一条再处理。WhatsApp 上是 5 秒(因为用户习惯分段发消息),Slack 上是 1.5 秒。

注意:带附件的消息(图片、文件)会立即触发处理,不参与防抖。控制命令(/new/model 等)也绕过防抖。


Session 数量有没有上限?

Session 数量本身没有硬上限。 每个群、每个话题、每个 DM 对话都可以创建独立 session,数量不限。

但有管理层面的软限制,防止 session 无限增长吃满磁盘:

{
  session: {
    maintenance: {
      mode: "enforce",        //warn | enforce
      pruneAfter: "30d",      //30 天未活跃的 session 自动清理
      maxEntries: 500,        // sessions.json 最多保留 500 条记录
      rotateBytes: "10mb",    // sessions.json 超过 10MB 自动轮转
      maxDiskBytes: "500mb",  // 可选:session 目录的硬盘上限
    }
  }
}

默认行为:

  • mode: "warn"
    :只警告,不实际清理(你得改成 enforce 才会自动清理)
  • pruneAfter: "30d"
    :30 天没活跃的 session 标记为可清理
  • maxEntries: 500
    :超过 500 个 session 记录后,从最旧的开始清理
  • 清理不会删除 JSONL 对话历史文件——只是从 sessions.json 索引中移除。历史文件会被归档。

对于大规模部署,可以设置 maxDiskBytes 作为硬上限,比如 "2gb",配合 highWaterBytes: "1.6gb" 在达到上限前开始清理。


并发的四层瓶颈

把 maxConcurrent 调到 100 就能同时服务 100 个用户吗?不一定。实际并发受四层瓶颈限制:

1)LLM API Rate Limit(主瓶颈)

你的 API key 决定了你能发多少请求。不管 maxConcurrent 设多高,被 Anthropic/OpenAI 限速了就是被限速了。

  • Anthropic:RPM(每分钟请求数)+ TPM(每分钟 token 数)
  • OpenAI:RPM + TPM,不同模型限制不同
  • 自托管模型:取决于你的 GPU 算力

OpenClaw 支持 model failover(主模型被限速时切到备用模型),但这只是缓解,不是解决。

2)Node.js 单进程

OpenClaw Gateway 是单进程 Node.js 应用。LLM 调用本身是异步 I/O,不会阻塞事件循环。10 个并发 LLM 请求在 Node.js 层面完全没问题。

但工具执行(尤其是 exec 跑 shell 命令)会吃系统资源——每个 exec 是一个子进程。大量并发 session 同时跑 bash 命令可能导致 CPU/内存压力。

大量并发 session 的上下文序列化和磁盘 I/O 也会增加延迟。每个 session 的对话历史是一个 JSONL 文件,高频读写会产生 I/O 竞争。

3)Sub-agent 并发

每个 session 可以 spawn sub-agent。Sub-agent 有自己独立的并发限制:

{
  agents: {
    defaults: {
      subagents: {
        maxConcurrent: 1  // 每个 session 最多同时跑 1 个 sub-agent
      }
    }
  }
}

如果一个 session 让 agent 同时派出 3 个 sub-agent 做研究,它们也要排队执行(除非你调高这个值)。

4)Cron 任务并发

定时任务有自己的并发上限:

{
  cron: {
    maxConcurrentRuns: 2  // 默认最多 2 个 cron job 同时跑
  }
}

Cron 任务也占用 maxConcurrent 的配额。如果你有 2 个 cron 在跑,maxConcurrent 设的 3,那用户消息就只剩 1 个并行槽位。


并发全景图

把所有配额放在一起看:

                    ┌─────────────────────────────────────┐
                    │        maxConcurrent = N             │
                    │    (全局 LLM 调用并行上限)           │
                    └──────────┬──────────────────────────┘
                               │
              ┌────────────────┼────────────────┐
              ▼                ▼                ▼
    ┌─────────────┐   ┌─────────────┐   ┌─────────────┐
    │  Session A   │   │  Session B   │   │  Cron Job   │
    │  (串行处理)   │   │  (串行处理)   │   │  (独立run)   │
    │  ┌────────┐  │   │  ┌────────┐  │   └─────────────┘
    │  │Sub-agent│  │   │  │消息队列 │  │
    │  │(独立限制)│  │   │  │(排队中) │  │
    │  └────────┘  │   │  └────────┘  │
    └─────────────┘   └─────────────┘

消息进入 OpenClaw 的完整流程:

  1. 入站防抖
    :同一个人的连续消息在 N 秒内合并
  2. Session 路由
    :根据来源(私聊/群聊/话题)分配到对应 session
  3. 并发控制
    :如果活跃 session 数已达 maxConcurrent,新 session 的消息排队
  4. 队列模式
    :同一 session 内的新消息按 queue.mode 处理(collect/steer/queue/interrupt)
  5. LLM 调用
    :调用模型,执行工具,生成回复
  6. 回复发出
    :通过对应渠道返回给用户

Session 生命周期

Session 不是永久的。OpenClaw 有一套自动重置机制来避免上下文无限增长:

每日重置(Daily Reset)

{
  session: {
    reset: {
      mode: "daily",
      atHour: 4,  // 凌晨 4 点重置
    }
  }
}

每天凌晨 4 点后的第一条消息会触发 session 重置——清空上下文,开始新会话。旧的对话历史不会丢失,JSONL 文件会被归档。

空闲重置(Idle Reset)

{
  session: {
    reset: {
      mode: "idle",
      idleMinutes: 120,  // 2 小时没活跃就重置
    }
  }
}

按类型设置

{
  session: {
    resetByType: {
      direct: { mode: "idle", idleMinutes: 240 },   // 私聊 4 小时
      group: { mode: "idle", idleMinutes: 120 },     // 群聊 2 小时
      thread: { mode: "daily", atHour: 4 },           // 话题每日
    }
  }
}

预压缩记忆刷写

当 session 接近自动压缩阈值时,OpenClaw 会先跑一轮静默的"记忆刷写"——提醒 agent 把重要信息写入文件(比如 memory/YYYY-MM-DD.md),然后再做 compaction。这样压缩后 agent 不会"失忆"。


多人使用场景怎么办?

如果你想让 OpenClaw 服务多个人(比如家庭成员、小团队),需要注意:

1)打开 Session 隔离

{
  session: {
    dmScope: "per-channel-peer",
  }
}

不设这个,所有人的私聊共享同一个对话上下文。 A 的隐私信息 B 能看到。

2)调高并发

{
  agents: {
    defaults: {
      maxConcurrent: 5,
    }
  }
}

默认 1 意味着同时只有一个人的消息在被处理,其他人要等。多人场景至少设到人数级别。

3)注意 API 预算

5 个人同时使用 = 5 倍的 API 调用。确保你的 API key 额度够用。

4)大规模不适用

OpenClaw 的架构是单实例个人助手,不是多租户 SaaS。要服务 100+ 用户,需要在外面加一层调度:多 Gateway 实例 + 负载均衡,或者用其他架构(LangGraph、Celery 等)。


总结:关键数字速查

配置项
默认值
含义
maxConcurrent
1
全局最大并行 LLM 调用数
subagents.maxConcurrent
1
每个 session 的 sub-agent 并行上限
cron.maxConcurrentRuns
2
Cron 任务并行上限
messages.queue.cap
20
每个 session 的消息队列容量
messages.inbound.debounceMs
2000
入站消息防抖窗口
session.maintenance.maxEntries
500
Session 索引最大条目数
session.maintenance.pruneAfter
30d
Session 过期时间
session.reset.atHour
4
每日重置时间(凌晨)

一句话:Session 数量无硬上限,并发由 maxConcurrent 控制(默认 1),真正天花板是你的 API key rate limit。


[1] OpenClaw Session Management:https://docs.openclaw.ai/concepts/session

[2] OpenClaw Configuration Reference:https://docs.openclaw.ai/gateway/configuration-reference