乐于分享
好东西不私藏

1.4G 会话导致 OpenClaw 回复慢被 sessions.list 卡住

1.4G 会话导致 OpenClaw 回复慢被 sessions.list 卡住

OpenClaw Gateway 健康、模型完成、回复已落盘,Chat 页却死活不显示。一路追下来,问题不是单一故障,而是 Control UI 重连 → 全量 sessions.list → transcript usage fallback → event loop 阻塞 → WebSocket 掉线的慢路径。

我是 AI灵感闪现,致力于让 AI (OpenClaw/小龙虾 和 Claude Code/CC) 全面自主接管我的健康、投资、学习、工作与生活,把节省下来的时间,用于真正体验人生。我只给 AI 想法或目标,全程不陪跑,让 AI 自主运行类似 Tesla FSD 自动驾驶。已上架两款由 AI 自主开发的 App:MoneyMind 省钱思维、HeartPetBond 心宠纽带。健康、投资、学习、工作和生活的 AI 接管路径,正在持续推进,并分享实践在微信公众号 AI灵感闪现 和 网站 

https://www.vibesparking.com

0. 引子

Gateway 健康,模型完成,assistant 回复已经写进 transcript。 但 Chat 页死活不显示新消息。

这是一次很典型的「不是模型问题、不是进程问题」的故障。最后追到根上是一条慢路径:Control UI 重连 → 全量 sessions.list → 后端 transcript usage fallback → event loop 阻塞 → WebSocket 心跳超时

记录如下,给同样跑 OpenClaw Gateway、又恰好被同一条路径绊住的同行参考。

  • 日期:2026-05-04
  • 环境:macOS,OpenClaw 2026.5.2,Gateway 端口 <gateway_port>
  • 目标:排查并缓解 openclaw-gateway 卡住、Control UI 无响应、聊天回复已写入 transcript 但前端未及时显示的问题

1. 现象

用户在 Control UI 访问 Chat 页:

http://localhost:<gateway_port>/chat?session=agent%3Amain%3A<session>

发送 hi 后,页面没有及时显示回复。与此同时,Gateway 日志中出现:

  • sessions.list 存在 19s、23s、26s 级慢请求
  • chat.history 出现 11s 延迟
  • WebSocket 中途断开并重连,断开码包括 10011006
  • liveness diagnostic 报告 event loop delay / utilization 异常

关键日志特征:

sessions.list 19405mssessions.list 19190mssessions.list 18232mssessions.list 26762mssessions.list 23456mschat.history 11262mswebchat disconnected code=1001webchat disconnected code=1006liveness warning: reasons=event_loop_delay,event_loop_utilization,cpu

2. 启动方式确认

最初怀疑 Gateway 不是通过 LaunchAgent 启动。排查后确认当前实际是通过用户级 LaunchAgent 启动:

plist:    ~/Library/LaunchAgents/ai.openclaw.gateway.plistlabel:    ai.ocplatform.gatewaycommand:  /opt/homebrew/bin/node \          /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway \          --port <gateway_port>

重启方式:

launchctl kickstart -k gui/501/ai.openclaw.gateway

健康检查:

curl http://localhost:<gateway_port>/health

结果:Gateway 能启动并通过 /health,问题不是单纯的进程未运行,而是运行期间 event loop 被慢请求和文件 I/O 挤压。

经验:看到「Gateway 卡」第一反应是不是要重启进程,但 /health 通过的时候,重启基本无效。要换一个角度看 event loop 和慢请求。

3. 已执行的修复动作

3.1 关闭高噪音 cron job

修改文件:

~/.openclaw/cron/jobs.json

禁用了多个会定期触发 agent / audit / build / sync 的任务,包括:

  • daily-session-workspace-audit
  • skills-security-audit
  • Memory Dreaming Promotion
  • astro-blog-daily-build
  • claude-code-changelog-watch
  • openclaw-changelog-watch
  • gbrain-live-sync
  • gbrain-dream-cycle

目的:减少 Gateway 后台任务对 CPU、session store、transcript 文件和 WebSocket 的竞争。

3.2 移除不可用 MCP 配置

修改文件:

~/.openclaw/openclaw.json

将不可用的 MCP openchronicle 移除,当前设置为:

"mcp":{"servers":{}}

目的:避免启动和运行期间不断尝试加载不可用 MCP,减少错误噪音和初始化成本。

3.3 增加 session maintenance 配置

在 ~/.openclaw/openclaw.json 中加入:

"session":{"dmScope":"per-channel-peer","maintenance":{"mode":"warn","pruneAfter":"90d","maxEntries":80,"maxDiskBytes":"200mb","highWaterBytes":"150mb"}}

目的:让 OpenClaw 对 session store 膨胀发出警告,并为后续 cleanup 提供上限策略。

3.4 先备份再清理 session 数据

按用户要求,先备份目录,再执行清理。

备份目录:

~/.openclaw/backups/session-cleanup-20260504-0859/agents

备份大小约:

1.4G

执行清理命令:

/opt/homebrew/bin/openclaw sessions cleanup --all-agents --enforce --json

清理结果摘要:

  • vs-openclaw-mgr 删除 1904 个未引用 session 文件
  • 释放空间约 453,080,258 bytes
  • vs-sites-astro session store 从 139 条裁剪到 80 条
  • ~/.openclaw/agents 从约 1.4G 降到约 941M

清理后重启 Gateway。

4. 用户测试会话排查

用户测试 session:

agent:main:<session>

实际 session id:

44ce243a-e9eb-4331-8a22-290f375836ec

transcript 文件:

~/.openclaw/agents/main/sessions/44ce243a-e9eb-4331-8a22-290f375836ec.jsonl

检查结果:

  • 用户消息 hi 已写入 transcript,时间约 2026-05-04 09:01:39 +08:00
  • assistant 回复也已写入 transcript,时间约 2026-05-04 09:01:46 +08:00
  • runtime 日志显示 run_completed,没有模型调用失败
  • session store 状态已变为 done,并写入 endedAt

结论:模型和 agent run 本身完成了。前端没显示不是「没有生成回复」,而是 Gateway/WebSocket/Control UI 的刷新链路在慢请求期间断开或延迟。

5. 关键根因

5.1 Control UI 在 Chat 页面触发昂贵的 sessions.list

排查安装包中的 Control UI bundle:

/opt/homebrew/lib/node_modules/openclaw/dist/control-ui/assets/index-<hash>.js

发现 Chat 页面和重连路径多次调用:

activeMinutes0,limit0,includeGlobaltrue,includeUnknowntrue

而前端请求组装函数会把 activeMinutes:0 和 limit:0 省略掉,最终后端收到的是:

{includeGlobaltrue,includeUnknowntrue}

这会变成无时间限制、无数量限制的 session 列表请求,并跨 agent 扫描 session store。

5.2 后端 sessions.list 会触发 session store 和 transcript 文件读取

排查后端实现:

/opt/homebrew/lib/node_modules/openclaw/dist/server-methods-<hash>.js/opt/homebrew/lib/node_modules/openclaw/dist/session-utils-<hash>.js

相关实现:

  • sessions.list 调用 listSessionsFromStoreAsync
  • listSessionsFromStoreAsync 虽然会分批 yield,避免一次性完全卡死 event loop
  • 但它仍然需要扫描 session store
  • 构建 session row 时,如果缺少 token / cost / context 字段,会读 transcript 做 usage fallback
  • 对派生标题和 last-message preview,也可能读取 transcript

代码注释本身也指出,readSessionTitleFieldsFromTranscript 的同步文件 I/O 是主要阻塞来源。

5.3 多个 WebSocket 连接放大了问题

日志中同时出现多个连接 ID 发起 sessions.listnode.listchat.history

conn=<conn-id-1>conn=<conn-id-2>conn=<conn-id-3>

这说明浏览器可能存在多个 Control UI tab,或重连过程中重复触发初始化请求。多个连接同时刷新,会把 session store 扫描、node list、chat history 叠加在一起。

5.4 大 MEMORY.md 和 cleanup timeout 是次要因素

日志中还有:

workspace bootstrap file MEMORY.md is 21493 chars (limit 12000); truncatingagent cleanup timed out: step=pi-trajectory-flush timeoutMs=10000

影响:

  • MEMORY.md 过大导致 agent bootstrap 成本高,本次 run 的 bootstrap-context 约 7.2s
  • pi-trajectory-flush cleanup timeout 发生在回复之后,会影响最终收尾和状态传播

但这两个不是 sessions.list 19s/26s 的主因。主因仍是 Control UI 的 chat 刷新路径触发昂贵 session 列表请求。

6. 当前状态

已经完成:

  • Gateway 由 LaunchAgent 管理,能正常启动
  • 多个高噪音 cron 已禁用
  • 不可用 MCP 已移除
  • session maintenance 配置已加入
  • session 数据已备份并清理
  • 用户测试消息的 assistant 回复确认已写入 transcript
  • Gateway 清理后 CPU 下降到低水平,sessions.list 多数降到约 600ms ~ 1.1s,但冷启动 / 重连阶段仍可出现 20s 级慢请求

尚未完成:

  • 尚未修改 /opt/homebrew 下的 Control UI 安装包
  • 曾准备备份并 patch index-<hash>.js,但用户中断了该步骤,因此没有继续写入全局安装目录

7. 建议的最终修复

7.1 前端 Chat 页面不要做全量 sessions.list

应将 Chat 页面和 WebSocket 重连路径中的 session 刷新参数从:

{activeMinutes0,limit0,includeGlobaltrue,includeUnknowntrue}

改成类似:

{agentId: currentAgentId,activeMinutes120,limit20,includeGlobalfalse,includeUnknownfalse}

目的:

  • 只查当前 agent 的近期会话
  • 避免聊天页为了显示当前对话而跨所有 agent 扫 session store
  • 减少 WebSocket reconnect 时的初始化负载

7.2 前端请求组装函数要支持 agentId

当前 _u() / vu() 请求组装逻辑只传:

includeGlobalincludeUnknownactiveMinuteslimit

建议补上:

if (n?.agentId) c.agentId = n.agentId;

否则即使调用方传了 agentId,后端也收不到。

7.3 后端应避免 sessions.list 读取 transcript usage fallback

建议后端将 sessions.list 的 transcript usage fallback 改成惰性或可选:

  • 列表页默认只返回 store 中已有 metadata
  • 缺失 token / cost 字段时不在列表请求里读 transcript
  • 需要详情时再用 sessions.describe 或单独 endpoint 补充

这是更彻底的上游修复。

7.4 运营侧建议

短期规避:

  • 只保留一个 Control UI tab
  • 修复期间避免打开 Sessions / Usage 等会触发大量列表刷新或统计的页面
  • 如果页面没有显示回复,先刷新 Chat 页面;因为 transcript 里很可能已经有回复

中期配置:

  • 将 session maintenance 从 warn 改为 enforce,防止 session store 再次膨胀
  • 定期执行 openclaw sessions cleanup --all-agents --enforce
  • 缩短或拆分过大的 MEMORY.md,降低 agent bootstrap 成本

8. 回滚信息

session 数据备份:

~/.openclaw/backups/session-cleanup-20260504-0859/agents

如果后续对 Control UI asset 打补丁,应先备份:

/opt/homebrew/lib/node_modules/openclaw/dist/control-ui/assets/index-<hash>.js

建议备份名:

index-<hash>.js.bak-chat-sessions-scope-20260504

注意:/opt/homebrew/lib/node_modules/openclaw 是全局 npm 安装目录,OpenClaw 升级后本地补丁可能被覆盖。

9. 总结

本次问题不是单一的 LaunchAgent 或模型失败。实际链路是:

  1. Control UI Chat 页面和重连逻辑反复触发昂贵的 sessions.list
  2. sessions.list 在当前实现下会扫描 session store,并可能读取 transcript
  3. 清理前 session 数据量和历史锁竞争已经很重,导致 event loop 被长时间占用
  4. event loop 被占用后,WebSocket 心跳和 chat.history 响应延迟
  5. assistant 回复已经写入 transcript,但前端连接断开或刷新延迟,因此用户看不到及时显示

已经通过关闭噪音任务、移除失效 MCP、配置 maintenance、备份并清理 session 数据显著降低压力。剩余的根治点是修改 Control UI chat 路径,避免聊天页面进行跨 agent、无时间限制、无数量限制的 session 列表刷新。

工程师的口头禅有时挺准:「能跑就行」,但「能跑」不等于「跑得起」——尤其当 event loop 是单线程、transcript 是 .jsonl、还掺着同步 I/O 的时候。下一次看到 Chat 页不显示新消息,不要先怀疑模型,先去翻 sessions.list 的耗时分布。

OpenClaw 小龙虾(点击跳转合集)

加入 AI灵感闪现 微信群

长按下图二维码进入 AI灵感闪现 微信群

长按下图二维码添加微信好友 VibeSparking 加群

关注 AI灵感闪现 微信公众号