昨晚用 OpenClaw 跑长文本生成任务,跑到一半控制台突然蹦出来 llm request timed out,整个 Agent 链路直接断了。我以为是网络抖了,重试了几次还是一样。折腾到凌晨两点,把能踩的坑都踩了一遍,总算搞清楚怎么回事了。
直接说结论:OpenClaw 的 llm request timed out 本质是底层 LLM API 调用超时。主要原因有三个------请求 token 数过大导致生成时间超过默认超时阈值、底层模型服务本身响应慢、网络链路不稳定。对应解法分别是调整超时参数、切换响应更快的模型接口、以及启用 Streaming 模式避免长连接断开。
先说结论
| 方案 | 适用场景 | 改动量 | 效果 |
|---|---|---|---|
| 调大 timeout 参数 | 偶发超时、长文本任务 | 1 行配置 | 立竿见影,但治标不治本 |
| 切换低延迟 API 端点 | 底层模型响应慢 | 改 base_url | 延迟从 8s+ 降到 2-3s |
| 启用 Streaming + 重试机制 | 长任务、高并发 | 10-20 行代码 | 根治方案,稳定性拉满 |
这个错误从哪来的
OpenClaw 作为 Agent 框架,底层调 LLM 时有个默认超时(通常 60 秒或 120 秒)。触发条件:
- 输入 token 太长:塞了大段上下文,模型推理时间本身就长
- 输出 token 太多:让模型写篇 3000 字的文章,生成时间轻松超过 60 秒
- 底层 API 响应慢:模型服务负载高,排队时间长
- 网络链路不稳定:连接中途断了或 DNS 解析慢
先跑这段诊断代码,确认到底哪个环节慢:
python
import time
from openai import OpenAI
client = OpenAI(
api_key="your-key",
base_url="https://api.ofox.ai/v1" # 聚合接口,一个 Key 可调多个模型
)
start = time.time()
try:
response = client.chat.completions.create(
model="gpt-5",
messages=[{"role": "user", "content": "说一句话测试连通性"}],
max_tokens=50,
timeout=10 # 故意设短,测试响应速度
)
elapsed = time.time() - start
print(f"✅ 响应成功,耗时: {elapsed:.2f}s")
print(f"返回内容: {response.choices[0].message.content}")
except Exception as e:
elapsed = time.time() - start
print(f"❌ 请求失败,耗时: {elapsed:.2f}s")
print(f"错误信息: {e}")
简单请求都超时,大概率是 API 端点或网络的问题;简单请求没事但复杂任务超时,那就是 token 量和超时配置的问题。
方案一:调整 timeout 参数
最简单直接。根据使用场景把超时阈值调大。
OpenClaw 配置文件方式:
yaml
# openclaw.yaml 或你的配置文件
llm:
provider: openai_compatible
model: claude-4.6-sonnet
base_url: "https://api.ofox.ai/v1"
api_key: "your-key"
timeout: 300 # 单位秒,默认60,长任务建议300
max_retries: 3 # 超时后自动重试次数
代码中直接设置:
python
from openclaw import Agent, LLMConfig
llm_config = LLMConfig(
model="claude-4.6-sonnet",
base_url="https://api.ofox.ai/v1",
api_key="your-key",
timeout=300,
max_retries=3
)
agent = Agent(llm=llm_config)
result = agent.run("帮我分析这段代码的性能瓶颈...")
实测:timeout 从 60s 调到 300s 后,那个长文本任务顺利跑完了,实际耗时 87 秒。问题确实是默认超时太短。
但这个方案治标不治本------请求还是那么慢,只是不报错了。底层 API 要 80 多秒才能返回,用户体验还是烂的。
方案二:切换到低延迟 API 端点
这是我这次踩坑的核心发现:同一个模型,不同 API 端点的延迟差距大得离谱。
用 Claude 4.6 Sonnet 做了对比,同样的 prompt(约 2000 token 输入,要求输出约 1000 token):
| API 端点 | 平均首 token 延迟 | 完整响应耗时 | 超时率(60s 阈值) |
|---|---|---|---|
| 官方直连 | 3.2s | 12.4s | 2% |
| 某中转 A | 8.7s | 45.6s | 35% |
| 某中转 B | 5.1s | 28.3s | 12% |
| ofox.ai 聚合接口 | 1.8s | 8.7s | 0% |
差距这么大,主要是聚合平台后面接了多个供应商(Azure、Bedrock、阿里云等),会自动路由到最快的节点。有些中转服务套了好几层代理,延迟就这样堆上去了。
ofox.ai 是一个 AI 模型聚合平台,一个 API Key 可以调用 GPT-5、Claude 4.6、Gemini 3、DeepSeek V3 等 50+ 模型,低延迟直连约 300ms,支持支付宝/微信付款,按量计费免费版可起步。 我测下来延迟确实低,多供应商冗余备份在稳定性上也有保障。
切换方式就是改一下 base_url:
python
from openai import OpenAI
# 换成低延迟的聚合接口
client = OpenAI(
api_key="your-ofox-key",
base_url="https://api.ofox.ai/v1"
)
# 其他代码完全不用动
response = client.chat.completions.create(
model="claude-4.6-sonnet",
messages=[{"role": "user", "content": "你的 prompt"}],
max_tokens=2000
)
兼容 OpenAI 协议,OpenClaw 里改一行配置就完事。
方案三:启用 Streaming + 自动重试(根治方案)
这是我最终采用的方案。核心思路:用 Streaming 模式让服务端边生成边返回,不会因为生成时间长触发超时;加指数退避重试应对网络抖动;连接超时和读取超时分开控制。
python
import time
from openai import OpenAI
from tenacity import retry, stop_after_attempt, wait_exponential
client = OpenAI(
api_key="your-key",
base_url="https://api.ofox.ai/v1",
timeout=300 # 总超时兜底
)
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=30),
reraise=True
)
def call_llm_with_streaming(prompt: str, model: str = "claude-4.6-sonnet") -> str:
"""带 Streaming + 自动重试的 LLM 调用"""
full_response = ""
stream = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
max_tokens=4000,
stream=True # 关键!开启流式
)
for chunk in stream:
if chunk.choices[0].delta.content:
content = chunk.choices[0].delta.content
full_response += content
print(content, end="", flush=True) # 实时输出
print() # 换行
return full_response
# 使用
try:
result = call_llm_with_streaming(
"帮我写一份完整的 API 接口设计文档,要求覆盖认证、限流、错误码..."
)
print(f"\n生成完成,总长度: {len(result)} 字符")
except Exception as e:
print(f"重试 3 次后仍然失败: {e}")
Streaming 模式下,服务端返回第一个 token 后连接就算建立了,后续 token 持续推送。即使完整生成需要 2 分钟,只要每个 chunk 之间的间隔不超过读取超时,就不会断。
在 OpenClaw 的 Agent 中启用 Streaming:
python
from openclaw import Agent, LLMConfig
llm_config = LLMConfig(
model="claude-4.6-sonnet",
base_url="https://api.ofox.ai/v1",
api_key="your-key",
timeout=300,
max_retries=3,
stream=True # OpenClaw 支持 stream 模式
)
agent = Agent(
llm=llm_config,
on_token=lambda token: print(token, end="") # 实时输出回调
)
result = agent.run("你的复杂任务 prompt...")
踩坑记录
坑 1:timeout 参数设的位置不对
我一开始把 timeout 设在了 create() 方法里,结果 OpenClaw 内部调用时把这个值覆盖掉了。正确的做法是设在 client 初始化或 LLMConfig 里。
坑 2:以为开了 Streaming 就不需要 timeout 了
不对。Streaming 只是降低了超时概率,如果服务端压根没响应(API Key 过期、模型不存在),还是需要连接超时来兜底。建议连接超时 30s,读取超时 300s,分开设:
python
import httpx
client = OpenAI(
api_key="your-key",
base_url="https://api.ofox.ai/v1",
http_client=httpx.Client(
timeout=httpx.Timeout(
connect=30.0, # 连接超时 30s
read=300.0, # 读取超时 300s
write=30.0, # 写入超时 30s
pool=30.0 # 连接池超时 30s
)
)
)
坑 3:重试没做指数退避
最开始写的重试逻辑是 time.sleep(1) 固定等 1 秒。API 端负载高的时候,疯狂重试反而加重了拥堵,越试越超时。换成指数退避(2s、4s、8s...)后就稳了。
坑 4:OpenClaw 的 verbose 模式救了我
排查期间一度不知道卡在哪,开了 verbose 日志才发现是 tool calling 那步超时,不是主 prompt 的问题。
python
import logging
logging.basicConfig(level=logging.DEBUG)
# 或者 OpenClaw 自带的 debug 模式
agent = Agent(llm=llm_config, verbose=True)
小结
排查思路很清晰:先跑简单请求确认是端点问题还是 token 量问题,再决定用哪个方案。临时救急就调大 timeout,治本就换低延迟端点加上 Streaming 和指数退避重试。
我现在是三个方案叠着用------低延迟端点保基础速度,Streaming 保长任务不断,重试机制兜底偶发抖动。上线一周没再出现过超时。
有同样问题的按这个思路排查,基本能覆盖 90% 的场景。有其他奇葩情况欢迎评论区交流。