技术支持 wechatapi.net
最近我在做一件比较实际的事情:
把微信接到 OpenClaw,让用户直接在微信里和 Agent 对话。
这个过程里,我碰到一个非常明显的现象:
- OpenClaw 前端里,同样一句话,大概 8~10 秒
- 微信里通过
openclaw agent --session-id --message去调,常常要 20~30 秒,甚至更久
一开始我以为是微信回调慢、网络慢、或者回消息慢。
后来把日志拆开以后,我确认了一个事实:
真正慢的,不是微信网关,而是 OpenClaw CLI 模式本身。
先看我最后是怎么定位的
我在网关里打印了两个关键时间点:
logger.info("[OpenClaw CHAT] sid=%s | %s", sid, short_text(message))
# ...
logger.info("[发送文本] TO=%s | %s", to_wxid, short_text(text))
结果非常清楚:
- 收到微信消息时间:09:58:56
- 发回微信时间:09:59:28
中间大约 32 秒。
而且这 32 秒不是卡在回调,也不是卡在 reply_text(),
而是卡在:
subprocess.run(
["openclaw", "agent", "--session-id", sid, "--message", message],
capture_output=True,
text=True,
timeout=180
)
所以问题一下就明确了:
CLI 调用链本身很重。
为什么 CLI 会比前端慢这么多
1. 每条消息都是一次冷启动
前端通常是已经打开着的,很多状态是热的。
但 CLI 模式下,每来一条消息都要重新做一遍:
- 启动进程
- 读取配置
- 恢复 session
- 初始化 provider
- 再去请求模型
- 然后退出
这和前端的运行方式根本不是一个级别。
2. Session 恢复也有成本
我在调用时用了 --session-id:
openclaw agent --session-id wechat_dm_xxx --message "你现在都会什么技能"
这意味着 OpenClaw 不只是单纯问模型,
还要恢复这个会话的历史上下文。
如果这个 session 已经比较长,恢复成本会更明显。
3. 某些问题会触发更多内部处理
比如“你现在都会什么技能”这种问题,本身就容易让系统去读取:
- 技能列表
- 工具定义
- workspace
- 说明文件
所以它天然比一句“你好”更重。
我后来怎么验证这个判断
最有效的方式其实很简单:
绕过微信,直接在终端测同样的 CLI 命令。
time openclaw agent --session-id test123 --message "你好"
time openclaw agent --session-id test123 --message "你现在都会什么技能"
如果 CLI 自己都慢,那微信层再怎么优化,也不可能把整体体感做得很快。
这个测试做完以后,我基本就不再怀疑微信回调了。
这件事对网关设计有什么启发
启发 1:不要把“微信慢”误判成“网关慢”
很多人一看到微信里回复慢,就先怀疑:
- 回调没处理好
- 发消息接口慢
- 本地网络慢
但真正拆日志后,经常会发现:
- 回调几乎是秒收
- 发送接口也很快
- 真正慢的是 AI 内核调用链
这就是为什么我建议一定要在网关里把阶段耗时打出来。
启发 2:CLI 模式适合验证,不适合长期追求低延迟
CLI 模式的优点是接入非常直接:
cmd = ["openclaw", "agent", "--session-id", sid, "--message", text]
但它的问题也同样直接:
- 冷启动
- 上下文恢复
- 无流式返回
- 无常驻状态
所以它非常适合做 MVP、做验证、做第一版。
但如果你后面真的要追求更低延迟,还是得往常驻化方向走。
启发 3:要区分“入口层优化”和“内核层优化”
入口层能做的优化包括:
- 回调立即返回
- 多 worker 并发
- 同 session 顺序处理
- 去重
- 更清晰的 session 设计
这些都值得做,但它们解决的是入口层问题。
CLI 冷启动是 内核层问题,这两个不能混在一起看。
我现在在代码里是怎么处理的
虽然 CLI 模式无法从根上解决,但外围还是可以做得更合理。
1. 按 session 分片
def shard_index_for_session(session_id: str, worker_count: int) -> int:
h = int(hashlib.md5(session_id.encode("utf-8")).hexdigest(), 16)
return h % worker_count
2. 限制单会话积压
if session_pending[session_id] >= config["MAX_PENDING_PER_SESSION"]:
reply_text(chat_id, "⚠️ 当前会话任务过多,请稍后再试。", config)
return {"status": "too_many_pending"}
3. 日志分阶段
logger.info("[收到消息] chat_id=%s text=%s", chat_id, short_text(actual_text))
logger.info("[OpenClaw CHAT] sid=%s | %s", sid, short_text(message))
logger.info("[发送文本] TO=%s | %s", to_wxid, short_text(reply))
这些改动不能让 CLI 变成前端那种速度,
但至少能让你知道问题到底卡在哪。
我的结论
如果你现在也在做“微信 + OpenClaw”这种接法,那我会给你一个很直接的判断:
微信网关可以做好,但只要底层还是“每条消息起一次 openclaw agent”,它的延迟就很难和前端一样。
这不是代码写错了,而是调用方式决定的。
所以正确的预期应该是:
- 第一阶段:CLI 接法,先验证场景
- 第二阶段:如果场景成立,再想办法做常驻化、服务化、热状态化
最后一句话
很多人会把“AI 入口慢”归因到入口层。
但我这次做下来最大的体会是:
入口层最多帮你减少混乱,真正决定体感上限的,往往还是内核调用方式。