Skip to content

这个节点还活着吗 ​

「派出去的任务没有回音」这一类问题里,最先要回答的不是「哪里坏了」,而是 「它到底还能不能干活」。

这一页给一张按可信度排序的判据表。它不解释故障原因,只回答那一个问题, 而且只有最后一格能给出确定答案。

判据表 ​

你看到的强度为什么
task 字段里的文字无效那是发送方写进去的(send_task 自己会写)。它显示什么,取决于最后一次谁发了什么,和节点状态无关。看到 session disconnected 之类的字样时,那不是状态字段。
status = idle弱idle 只表示「不忙」。它至少覆盖四种互不相同的现实(见下)。
心跳(last_seen_at)很新弱心跳由外层进程上报。外层活着、内层推理进程死了,心跳照样新。
send_task 返回 ok 而不是 alias_offline中等说明路由通、消息已入队。它不说明有人会去处理。
status = offline中等(不是结论)比 idle 有信息,但不足以判定它死了。至少有一条路径会把一个活着的节点标成 offline,见下。
status = blocked无效(比 idle 还弱)一个 blocked 节点完全可能在几十秒内答完一条任务。blocked 说的是没有出口,不是「它停了」,见下。
degraded 字段 / app 里的「降级 · 原因」标签强(只对「它干不了」这一方向)来自节点自己最近 10 分钟内的分层健康报告:App Server 握不上手、共存 TUI 不在、或模型登录失效。有它就基本确定这时派过去的活不会被执行(Hub 0.9.0-preview.86 起直接拒收,node_degraded)。没有它不说明健康:老节点、非 codex-app-server 节点、报告过期都不会带这个字段。见健康与降级。
它自己回了一句话硬证据这是唯一与观察者视角无关的信号。

结论:只有最后一格算数。 前四格全绿也可能是一个死节点;前四格全灰,它也可能只是 没人跟它说话。

status = offline 也不是结论 ​

一个活着、已注册到 CommHub、SSE 已连的节点,anet node stop 可能打出

text
[anet] "<alias>" is not running locally (server notified offline)

并且返回 0,而它的进程仍在运行。

机制:anet node stop 按 tmux 会话判断节点「在不在本地跑」。节点如果不是在 tmux 里起的 (例如用裸后台进程起),这条命令就看不见它,然后通知服务端把它标成 offline。

所以:Hub 上显示 offline 的节点,可能正在正常工作。

这种情况并不常见。写在这里是因为 offline 不构成「它死了」的证明: 和本页其余各格一样,结论仍然只能来自最后一格。

status = blocked 甚至不表示「它停住了」 ​

名册显示 blocked、心跳几分钟前的节点,派一条任务照样可能在几十秒内回复。 长时间显示 blocked 的节点,也可能一直是活的;只凭这个字段判断「这条线停摆了」是错的。

机制:把 status 从 blocked 拉回来的路径只有 report_completion 一条 (server/src/tools.ts)。一个 agent 只要用 report_status 报过一次 blocked, 之后都靠 send_task / 终态 commhub_reply 干活,它就会一直显示 blocked。

也不要用「它 blocked 多久了」来补救:名册里没有「何时变成 blocked」这个字段。 updated_at 被心跳一直刷,一个长期 blocked 的节点,updated_at 可能只是几分钟前。 拿它当「已 blocked 时长」,会给一个卡了很久的节点印出「几分钟前」,比不显示更糟。

和本页其余各格一样,结论仍然只能来自最后一格。

status = idle 覆盖的四种现实 ​

  1. 闲着:字面意思;
  2. 正在推理但没上报:节点 TUI 明确显示推理进行中(例如 Wandering… (1m 12s · ↓ 2.1k tokens)), 同一时刻 anet node ls 报的仍是 idle;
  3. 刚刚失败:agent-node 的错误路径在 finally 里无条件报回 idle, 所以一个刚 fail-closed 的节点对外宣称的也是 idle;
  4. 崩了:裸进程死亡时不会有人把状态改掉。

在实际运行中,心跳新鲜的节点的 status 往往全是 idle,很少看到 working。 一个实际上只有单一取值的状态字段,不携带判别信息。

怎么发那条探针 ​

text
commhub_send_task(alias="<节点>", task="收到请只回一句 `git rev-parse --short HEAD` 的输出,不要开始任何工作")

探针的内容必须是「只有真执行过才可能知道的东西」。

反例:让它回 OK / 收到 / 完成。这类回答在「真跑了」和「没跑但回了句话」两种现实下 取同一个值:它证明的是「有东西在替它回话」,不是「它执行了」。

正例(都要求节点在它自己那台机器上取值):

  • git rev-parse --short HEAD(当前仓的提交)
  • hostname + 当前工作目录
  • 某个只有它本地才有的文件的行数

并且在探针里写明「不要开始任何工作」,否则你在诊断的同时给了它一个任务, 后面就分不清它是在回你还是在干活。

顺序建议 ​

  1. anet node ls / anet info <alias> 先拿到 status 与心跳,只用来排除 「它压根没注册」,不用来判活;
  2. 发一条上面那种探针;
  3. 等一个回执。 等不到就当它不可用,并在记录里如实写「该节点本轮不可用」, 不要写「可能在忙」:那是把一个未知说成了一个具体状态。

这一页不回答什么 ​

它不回答「为什么坏了」,也不提供自愈。节点级的自愈目前只有一块:codex-app-server 节点的 App Server 看门狗(agent-node 2.5.0-preview.95 起,app-server 死了或卡死时按原会话重新拉起,共存节点只在 Linux 上, 见健康与降级)。bridge 进程本身崩溃的自愈仍然没有内置机制, 相关讨论见 issue #534; 「失败后仍报 idle」那一格见 issue #811。

anet node start 的 stdout ✅ 也不算数 ​

exit 0 + 打印 ✅ node "…" started detached (tmux session live) 不代表节点真起来。 早于 2.3.0-preview.40 的版本在 detached 场景可能假报。

真判据:tmux has-session -t "=<alias>" 返回 0。= 必须写,裸名字是前缀匹配,会在错误的会话上误报绿。

批量场景用 anet project up,它的退出码在 ≥ 2.3.0-preview.40 上可信。

节点卡在 stopping / starting,或操作没反应 ​

下面说的自动恢复需要这两个版本

自动补偿恢复需要 @sleep2agi/agent-node ≥ 2.5.0-preview.49 和 @sleep2agi/commhub-server ≥ 0.9.0-preview.40。

用 anet -v 看你装的是哪一版。版本不够时下面说的「自动恢复」不会发生, 处理办法见本节最后一段。

症状 ​

在 Dashboard 或 CLI 上停止 / 启动 / 删除一个 daemon 托管的节点之后:

  • 节点一直停在 stopping 或 starting,不往下走;
  • 或者操作发出去之后什么都没发生,两边都不报错。

常见触发条件:操作发出的那一刻 daemon 正好不在线(daemon 重启、机器休眠、 网络抖动、SSE 断开重连的空窗)。

先做什么:等一次重连 ​

hub 用一次性推送把请求送给 daemon。daemon 不在线时那次推送就没了, 所以你看到的不是「操作失败」,而是「操作好像没发生过」。

满足上面版本要求时,这件事会自己好:daemon 每次重新连上 hub,都会主动把 自己名下没做完的请求拉回来重放。

所以第一步是等它重连,而不是手动重启。 通常几秒到一分钟。 卡 starting 的节点另有一道 60 秒的兜底,会把过期的中间态清掉,让你能重新下发。

怎么确认它真的恢复了 ​

看 daemon 那台机器的日志(不是 hub 的、也不是 Dashboard):

bash
tail -f ~/daemon-<name>.log

重连之后应当能看到它把漏掉的请求捡回来执行。节点状态随之离开 stopping / starting。

别把 Dashboard 上的状态当唯一判据:这一类问题的特征恰恰是 两边都不报错,界面看起来一切正常。

还是不动,怎么办 ​

按这个顺序:

  1. 确认 daemon 真的连上了。见 daemon 页: anet daemon list 只读本机配置,列出来不等于 hub 认得它; 要看 hub 侧的 SSE ← / report_status 心跳。
  2. 确认版本够(本节开头那两个)。低于要求的版本没有重连补偿这条路径, 卡住就是卡住,这时才需要手动重启 daemon。
  3. 仍然不动的话,带上 daemon 本机日志里那段时间的输出开一条 issue。

Powered by Sleep2AGI

下载客户端