Agent 启动编排问题:表面 Bug 的真实根因
分析 Agent 系统「不稳定」的幕后原因——启动时服务虽在运行但未就绪,导致首次调用失败。
完整中文译文
我的 Agent 并不 flaky—— 它只是在任何东西真正就绪前就启动了 30-60 秒
我不断听到同样的抱怨,来自 24/7 运行 Agent 的人:
不是宕机。不是一致性损坏。只是在第一次、重连后或重启直后随机出现问题。
OpenClaw 忘记了一个工具。n8n 的 worker 丢失了状态。一个自定义的 FastAPI 工具服务器启动了,但第一次调用失败了。然后有人责怪 GPT-5 或 Claude,因为重试奇迹般地解决了问题。
这个模式通常与模型质量无关。
大多数情况下,真正的 bug 存在于启动后的前 30-60 秒内。
如果 Redis、Postgres、OpenClaw Gateway 或生成的配置文件只是在运行,但还没有真正就绪,你的 Agent 会过早获得工作并摔跟头。
这不是 flaky AI。这是启动编排不良。
错误:「容器启动」≠「服务就绪」
这是很多假 LLM bug 的根源。
很多 Agent 栈都假设这个序列是安全的:
运行中的 Postgres 容器仍然可能拒绝查询。运行中的 Redis 容器仍然可能在预热。运行中的 OpenClaw Gateway 仍然可能缺少 profile 或 channel 状态。配置文件可能已经存在于磁盘上,但仍在被写入。
这导致:
- 首次调用工具失败
- 重连时丢失内存
- 随机启动错误,重试后消失
- 「Claude 很奇怪」的报告,实际上是基础设施 bug
如果你自托管 Agent 工作流,启动路径比人们想的更重要。
Docker Compose 已经告诉你了
Compose 不会把「运行」当成「就绪」。
如果你的 Agent 依赖 Postgres,用健康检查把它隔离。
services:
agent:
build: .
depends_on:
db:
condition: service_healthy
restart: true
db:
image: postgres:18
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 10s
retries: 5
start_period: 30s
这里有两个重要细节:
condition: service_healthy 表示 Agent 等待真正的就绪状态
restart: true 帮助依赖在显式依赖重启后正确重连
第二个经常被低估。
很多「会话重置」bug 只是重连 bug 换了个名字。
如果你有 Redis,探测 Redis
别假设 Redis 仅因为进程存在就可用。
示例健康检查:
services:
redis:
image: redis:7
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
如果你的内存层、队列 worker 或 Agent 会话缓存依赖 Redis,这个简单的检查可以消除令人惊讶的大量启动混乱。
Kubernetes 多年前就做对了
如果你在 Kubernetes 中运行 Agent,停止把 liveness probe 当成通用锤子。
有三个不同的概念是有原因的:
startupProbe:应用仍在初始化
readinessProbe:应用现在可以接收流量了
livenessProbe:应用不健康应该重启
这些不是可互换的。
如果你的 OpenClaw worker 或工具服务器需要时间来:
- 预热连接池
- 加载 LLM 模型或配置
- 与外部服务握手
那么你首先需要 startup 和 readiness 检查。
如果你过度积极地使用 liveness,你会创建一个重启循环并称之为「自我修复」。
这不是弹性。这是你自己写的拒绝服务攻击。
有些启动 bug 根本不是网络 bug
这就是事情变得更烦人的地方。
有时依赖不是 Postgres 或 Redis。有时是一个文件。
- 生成的配置文件
- 由另一个进程写入的凭证文件
- 数据库迁移锁
是的,这些完全可能破坏 Agent 启动。
丑陋的版本看起来像这样:
启动脚本看到它 → 文件仍在中途写入 → 所有人责怪模型
这就是为什么文件就绪检查很重要。
当文件状态是依赖时使用监视器
对于 Node.js,我喜欢 Chokidar。
它抚平了一堆 fs.watch 的奇怪之处,并给你实用的选项,比如:
import chokidar from 'chokidar';
const watcher = chokidar.watch('./runtime/config.json', {
persistent: true,
atomic: true,
awaitWriteFinish: true,
});
watcher.on('ready', () => {
console.log('Initial scan complete. Safe to continue startup.');
});
watcher.on('change', (path) => {
console.log(`Config updated: ${path}`);
});
那个 ready 事件是有用的部分。
它给了你一个真正的信号,表示初始文件发现已完成,而不是猜测。
如果你的 Agent 依赖生成的构件,这通常比睡眠 10 秒后祈祷要好。
对于 Python,使用 watchdog。
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import time
class Handler(FileSystemEventHandler):
def on_created(self, event):
print(f"created: {event.src_path}")
observer = Observer()
observer.schedule(Handler(), path="./runtime", recursive=False)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
除非你真的需要,否则不要监视整个仓库。
监视证明就绪的那一个文件或目录。
OpenClaw 给你正确的调试路径
我喜欢 OpenClaw 的一件事是,故障排除流程引导你关注运行时健康,而不是神秘的 prompt 调整。
如果一个 Assistant 感觉坏了,从这里开始:
openclaw status
openclaw status --all
openclaw gateway probe
openclaw gateway status
openclaw doctor
openclaw channels status --probe
openclaw logs --follow
这正是正确的思维方式。
在你问为什么模型表现不好之前,先问控制平面是否真的温暖且连接。
如果 Gateway 启动时有错误的 profile、陈旧的会话状态或缺失的工具,Assistant 会因为与推理无关的原因看起来很笨。
如果你在切换 profile 或依赖特定的工具暴露,这尤其成立。
如果 Assistant 突然看起来「受限」,在接触 prompt 前检查运行时状态。
这也出现在 n8n 和自定义工作流栈中
同样的故事,不同的栈。
如果你使用 n8n 运行 worker、队列、Redis、Postgres 和自定义 AI 节点,你的可靠性在成为模型问题之前首先是一个编排问题。
弱点很无聊:
- worker 在 Redis 可达前启动
- 节点间加密密钥不匹配
- 重启后陈旧的队列连接
- 工具服务器在工作开始时还未就绪
- 生成的 env/config 构件晚到
这些是经典的启动和重连 bug。
它们只是被误诊,因为可见的失败发生在 LLM 驱动的工作流内部。
我明天早上会真正做的事
如果你 24/7 运行 Agent,这是检查清单。
- 用真正的就绪信号隔离每个依赖
Redis:redis-cli ping
HTTP 工具服务器:/health 或 /readyz
OpenClaw Gateway:openclaw gateway probe
- 把启动和 liveness 分开
缓慢预热不等于死进程。
不要仅因为初始化花时间就重启一个健康的服务。
- 如果启动依赖生成的构件,添加一个狭窄的文件监视器
✓ plugin 输出目录
✗ 你的整个单体仓库,因为「也许某些东西在那里重要」
- 让重连行为明确
如果 Postgres、Redis 或 OpenClaw Gateway 重启,你的 Agent 应该干净地重连。
不要假设库会按你想要的方式处理这个。
实际上重启依赖并观察发生了什么。
- 像它重要一样记录第一分钟
启动、重连或会话重置后的前 30-60 秒是很多「随机」失败的诞生地。
记录:
- 依赖探测结果
- 工具注册时间
- 第一个成功的 Postgres/Redis 查询
- 第一个成功的 Gateway 探测
一个小小的 shell 隔离就够了
如果你想要一个简单至极的启动守卫,在启动 Agent 前使用像这样的脚本:
#!/usr/bin/env bash
set -e
until pg_isready -h db -U app -d appdb; do
echo "waiting for postgres..."
sleep 2
done
until redis-cli -h redis ping | grep -q PONG; do
echo "waiting for redis..."
sleep 2
done
until openclaw gateway probe; do
echo "waiting for openclaw gateway..."
sleep 2
done
echo "all dependencies ready, starting agent"
exec python agent.py
这也好得多得多比「启动所有东西然后祈祷」。
当你按 token 付费时,这为什么更重要
这是人们讨论不够的部分:
启动编排不良会燃烧 token。
如果你的 Agent 通过半就绪的依赖崩溃、重试同一步骤三次、不良重连并重放上下文,你不仅在处理可靠性痛苦。你在为可避免的错误付款。
这是可预测 AI 基础设施重要的原因之一。
如果你构建不断运行的自动化,你需要两件事:
启动纪律,所以 Agent 只在栈真正就绪时运行
可预测定价,所以重试和长运行工作流不会变成账单焦虑
这是对这类工作负载使用 Standard Compute 的吸引力。
它给你一个 OpenAI 兼容 API,有固定月度定价,所以你可以运行 Agent、自动化和重试,而不用整天盯着 token 燃烧。如果你已经在连接 OpenAI SDK、n8n 流或自定义 Agent 运行程序,drop-in 部分是要点。
但即使有固定速率计算,工程课程仍然成立:
如果你的启动序列很草率,你的 Agent 仍然会看起来 flaky。
你只是在调试错误的层。
更好的问题要问
当一个 Agent 在第一次失败时,不要从这里开始:
「为什么 GPT-5 会那样做?」
「为什么是那样?」
改为问:
「当模型获得工作时,环境中的真实情况是什么?」
Postgres 就绪了吗?Redis 可达吗?OpenClaw Gateway 温暖吗?加载了正确的工具 profile 吗?配置文件完整吗?liveness probe 是否杀死了仍在预热的进程?
那是大量谜团消失的地方。
老实说,这是个好消息。
因为一旦你意识到你的「flaky」Agent 通常只是一个编排不良的启动序列,问题就变成了正常工程。
正常工程是可修复的。