研究员:黄山(wairesearch) 日期:2026-04-23 版本:1.0 基于 OpenClaw v2026.4.12 源码 + 官方文档 + GitHub Issues
执行摘要
如果你用过 OpenClaw 一段时间,大概率遇到过这个场景:Bot 显示”输入中”,然后……就没有然后了。
这篇文章系统分析了 OpenClaw Session 的状态管理机制,梳理了 7 种已确认的 Stuck 模式和 3 种死锁场景,并提供了一份实用的排查手册。无论你是 OpenClaw 的日常用户还是深度定制者,这篇都能帮你理解”为什么 Bot 会卡住”以及”怎么快速恢复”。
Session 状态管理机制
完整生命周期
一条消息从发出到得到回复,经过以下流程:
消息到达 → 路由(sessionKey) → 入队(Command Queue) → 获取 Session 锁
→ 加载 SessionManager → 构建 System Prompt → LLM 推理
→ 工具执行 → 流式回复 → Compaction 检查 → 释放锁 → 排队下一个
状态机模型如下:
┌──────────┐
新消息到达 ──→ │ queued │ ← 在 Command Queue 等待
└────┬─────┘
│ lane 空闲,获取 session 写锁
▼
┌──────────┐
│ running │ ← LLM 推理 + 工具执行
└────┬─────┘
│
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│complete│ │aborted │ │ error │
└────────┘ └────────┘ └────────┘
│ │ │
└──────────┴──────────┘
│
Compaction(可选)→ 释放锁
| 状态 | 含义 |
|---|---|
queued |
消息入队,等待 lane 空闲 |
running |
Agent 正在执行(LLM 推理 + 工具调用) |
aborted |
被用户或超时中止 |
complete |
成功完成 |
error |
执行出错 |
compacting |
自动压缩进行中 |
两层持久化架构
| 层 | 文件 | 用途 |
|---|---|---|
| Session Store | sessions.json |
sessionKey → SessionEntry 映射 |
| Transcript | <sessionId>.jsonl |
追加写入的对话树(JSONL 格式) |
三层并发控制
OpenClaw 使用三层机制防止并发冲突:
-
Command Queue(Lane 系统):
main(入站消息,并发上限 4)、subagent(子 Agent,上限 8)、cron(定时任务)、nested(嵌套调用),每个 session 同一时间只有一个 active run。 -
Session 文件锁:
.jsonl.lock锁文件,超时 10 秒。 -
Gateway 进程级隔离:单进程模型,restart 时有 30 秒 drain 机制。
7 种 Stuck 模式
通过分析 GitHub Issues 和源码,我们确认了以下 7 种 Session 卡死模式:
模式 1:LLM API 流式挂起 — 最高频 🔴
Issue: #17258
上游 LLM API 接受了流式请求但不产生任何 token。HTTP 连接保持打开,系统一直等到绝对超时(默认 600s)。
T+0s 流式请求开始,API 返回 HTTP 200
T+2s ...静默,无 token 到达...
T+120s Typing indicator 过期,用户看到 Bot "离线"
T+300s 超时触发,session abort
解决方案:v2026.2.x 引入了 llm.idleTimeoutSeconds,建议设为 90 秒。
模式 2:Compaction 死循环 + 锁文件残留 🔴
Issue: #21621
Browser Tool 执行后触发 compaction,compaction 进入 retry 循环永不完成。关键特征:日志中有 compaction retry 但没有 embedded run done。
模式 3:Gateway 自请求死锁 🔴
Issue: #18470
Agent 在 active turn 中调用 openclaw sessions --json → CLI 需要查询 Gateway → Gateway 在等 agent turn 完成 → 经典死锁。
模式 4:Session 文件锁超时 🟡
Issue: #31489
.jsonl.lock 文件因崩溃残留,10 秒后锁获取失败,agent 无法回复。
模式 5:Gateway Restart 时 Compaction 中断 🟡
Issue: #17635
config.apply 触发 SIGUSR1 restart,但 30 秒 drain timeout 不够 compaction 完成。
模式 6:Context 超限导致 Compaction 死循环 🔴
Issue: #25620
Context 超过模型 token 限制 → /compact 的 summarization 请求本身也超限 → 无法压缩 → 死循环。
模式 7:工具调用失败无恢复 🔴
Issue: #8288
工具调用挂起后无超时、无恢复、无 fallback。唯一恢复方式是 /new 或 /reset,但会丢失全部上下文。
Stuck 原因分类汇总
| 类别 | 根因 | 频率 | 严重度 |
|---|---|---|---|
| LLM 挂起 | API 流式不活跃 | 极高 | 🔴 |
| Compaction 死锁 | Lock 残留 + retry 循环 | 高 | 🔴 |
| 自请求死锁 | Gateway 循环依赖 | 中 | 🔴 |
| 文件锁超时 | .lock 残留 | 中 | 🟡 |
| Restart 中断 | Drain timeout 不够 | 低 | 🟡 |
| 工具无超时 | 无 timeout/fallback | 中 | 🔴 |
| Sub-agent 未返回 | 子 agent 卡住 | 中 | 🟡 |
3 种死锁场景
死锁经典四条件
| 条件 | OpenClaw 中的表现 | 是否成立 |
|---|---|---|
| 互斥 | Session 写锁、文件锁、per-session lane 串行 | ✅ |
| 占有且等待 | Agent turn 占 session lane,同时等 LLM/工具 | ✅ |
| 不可剥夺 | 锁只在 turn 完成后释放 | ✅ |
| 循环等待 | Gateway 自请求:turn 等命令 → 命令等 turn | ✅ |
死锁 1:Gateway 自请求死锁
┌──────────────┐ ┌──────────────┐
│ Agent Turn │ ──等待─→ │ 内部命令 │
│ (lane 被占) │ │ (需查 Gateway)│
│ │ ←─阻塞── │ │
└──────────────┘ └──────────────┘
Agent 通过 exec 调用 openclaw CLI,CLI 需通过 WebSocket 查询 Gateway,但 Gateway 被 active session lane 阻塞。
死锁 2:Compaction Lock 死锁
Compaction 过程中 Gateway crash → lock 文件残留 → 所有后续操作 10 秒超时失败。
死锁 3:Compaction 超限悖论
Context 过大 → 触发 Compaction → summarization 也超限 → 失败 → 仍然过大 → 循环
排查手册
症状速查表
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| Bot 显示”输入中”然后消失 | LLM API 挂起 | 设置 llm.idleTimeoutSeconds: 90 |
| Bot 完全无响应 | Session lock 残留 | 删除 lock 文件 + 重启 Gateway |
| Compaction 后卡住 | Compaction retry 循环 | 重启 Gateway + 删 lock |
| 内部命令 10 分钟超时 | Gateway 自请求死锁 | 改用 session tools API |
| 费用异常高 | Stuck → timeout → retry 风暴 | 缩短 timeout + 设 spend limit |
/compact 失败 |
Context 超限悖论 | /new 重建 session |
| Sub-agent 不返回 | 子 agent 卡在工具调用 | subagents kill all |
手动恢复命令
# 1. 检查 session 状态
openclaw sessions --json
openclaw sessions --active 120
# 2. 在 chat 中重置
/stop # 停止当前 agent run
/new # 新建 session
/reset # 重置当前 session
# 3. 清除锁文件(确保无活跃 run)
ls ~/.openclaw/agents/*/sessions/*.lock
rm -f ~/.openclaw/agents/*/sessions/*.lock
# 4. 重启 Gateway
openclaw gateway restart
# 5. Session 清理
openclaw sessions cleanup --dry-run
openclaw sessions cleanup --enforce
# 6. 核弹选项(完整重置)
openclaw reset --scope config+creds+sessions --yes
日志关键词速查
grep -i "stuck\|timeout\|abort\|compaction retry\|lock\|deadlock\|drain" \
~/.openclaw/logs/*.log
推荐配置调优
以下配置可显著降低 Stuck 发生概率:
{
agents: {
defaults: {
// 从默认 48h 缩短到 30min
timeoutSeconds: 1800,
llm: {
// API 90s 无响应则中止
idleTimeoutSeconds: 90,
},
compaction: {
enabled: true,
reserveTokens: 20000,
reserveTokensFloor: 20000,
memoryFlush: { enabled: true, softThresholdTokens: 4000 },
},
},
},
session: {
maintenance: {
mode: "enforce",
pruneAfter: "30d",
maxEntries: 500,
},
reset: {
idleMinutes: 120, // 2h 无活动自动重置
},
},
messages: {
queue: {
mode: "collect",
debounceMs: 1000,
cap: 20,
drop: "summarize",
},
},
}
预防最佳实践
- 避免 Agent Turn 中调用内部 CLI 命令 — 改用
session_status等内部 RPC 工具 - 设置合理超时 —
timeoutSeconds: 1800,idleTimeoutSeconds: 90 - 监控 lock 文件 — 定期检查并清除超过 5 分钟的
.lock文件 - 用 systemd/launchd 监管 Gateway — 异常退出自动重启
- 开启 memoryFlush — 压缩前保存关键上下文
- Sub-agent 用
sessions_yield— 不要 poll 循环等待
架构洞察
通过这次分析,我们发现几个值得关注的架构层面问题:
-
默认 48h 超时是 Stuck 的放大器 — 即使出了问题,系统也要等很久才超时。缩短到 30 分钟可以显著改善用户体验。
-
自请求死锁是设计缺陷 — Agent 能通过
exec调用openclawCLI 并触发 Gateway 自查询,形成循环依赖。应在架构层面让内部命令走独立通道。 -
文件锁机制脆弱 — 基于文件锁的并发控制在进程崩溃时必然残留。建议改为带 PID + 时间戳的锁,或在单进程架构下使用进程内锁。
-
Compaction 是高频触发器 — 多个 Issue 都与 compaction 相关,它涉及 LLM 调用 + 文件锁 + retry,任一环节卡住都导致 session 不可用。
-
缺少主动死锁检测 — 建议添加 session 活跃时间 watchdog、lock 文件 TTL、自请求检测等机制。
相关 GitHub Issues
| Issue | 标题 | 状态 |
|---|---|---|
| #17258 | Streaming inactivity timeout | ✅ 已修复 |
| #21621 | Browser Tool Triggers Compaction Deadlock | 报告中 |
| #18470 | Gateway Deadlock: Internal Commands Hang | 报告中 |
| #31489 | Session file locked (timeout 10000ms) | 报告中 |
| #17635 | Gateway restart during compaction | 报告中 |
| #25620 | Compaction fails on context overflow | 报告中 |
| #8288 | Agent hangs on failed tool calls | 报告中 |
总结
Session Stuck 和死锁是 OpenClaw 用户最常遇到的痛点之一。理解其背后的状态机模型、并发控制机制和已知的 7 种 Stuck 模式,能帮助你在问题发生时快速定位和恢复。更重要的是,通过合理的配置调优和最佳实践,大部分 Stuck 问题可以被预防。
记住这个优先级:先 /stop,再看 lock 文件,最后 restart Gateway。大多数情况下,前两步就能解决问题。