上周用 OpenClaw 跑批量文本分析,控制台疯狂刷 LLM request timed out,整个 pipeline 直接瘫了。
如果你也踩到这个坑,核心原因通常是这几个:单次请求 token 量太大导致推理超时、并发打满了速率限制、或者 OpenClaw 底层调用的模型服务本身不稳。解决方向包括调整超时参数和重试策略、拆分长文本、做请求队列控流、换一个更稳定的 API 通道。下面是我排查两天后整理的 4 种方案,亲测有效。
OpenClaw 本质上是个 token 消耗型工具,底层调大模型 API 做推理。LLM request timed out 的意思就是:它发出去的请求,在规定时间内没拿到响应,直接断了。
常见触发场景:
graph LR A[你的代码] –>|请求| B[OpenClaw] B –>|转发| C[底层 LLM API] C –>|推理| D[模型响应] D –>|返回| B B –>|返回| A
style B fill:#f9a825,stroke:#f57f17 C -.->|超时风险点1: 模型推理慢| E[Timeout!] B -.->|超时风险点2: 速率限制排队| E A -.->|超时风险点3: 网络延迟| E
最直接的方案。很多时候不是真挂了,就是默认超时太短。
import time import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry
def call_openclaw_with_retry(payload, max_retries=3, timeout=120): """带重试和超时控制的 OpenClaw 调用""" session = requests.Session()
# 配置重试策略:遇到 429/500/502/503/504 自动重试 retry_strategy = Retry( total=max_retries, backoff_factor=2, # 指数退避:2s, 4s, 8s status_forcelist=[429, 500, 502, 503, 504], ) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("https://", adapter)
try: response = session.post( "https://api.openclaw.example/v1/chat/completions", json=payload, timeout=timeout, # 从默认30s调到120s headers={"Authorization": "Bearer your-key"} ) response.raise_for_status() return response.json() except requests.exceptions.Timeout: print(f"请求超时({timeout}s),已重试 {max_retries} 次") return None except requests.exceptions.RequestException as e: print(f"请求失败: {e}") return None
使用
result = call_openclaw_with_retry({ "model": "gpt-5", "messages": [{"role": "user", "content": "你的 prompt"}], "max_tokens": 2000 })
把超时从 30s 调到 120s,加上 3 次指数退避重试后,我的批量任务成功率从 60% 涨到 85% 左右。但还有 15% 会失败,说明不只是超时的问题。
这个才是我排查到的真正元凶。之前图省事,把整篇文档(大概 8000 token)一次性丢进去让模型做摘要 + 分析,推理时间直接飙到 40-60 秒,超时概率极高。
def chunk_text(text, max_chunk_size=2000): """按段落拆分文本,每块不超过 max_chunk_size 字符""" paragraphs = text.split(‘
’) chunks = [] current_chunk = ""
for para in paragraphs: if len(current_chunk) + len(para) < max_chunk_size: current_chunk += para + "
" else: if current_chunk: chunks.append(current_chunk.strip()) current_chunk = para + "
"
if current_chunk: chunks.append(current_chunk.strip())
return chunks
def process_long_document(document, system_prompt): """分块处理长文档,最后合并结果""" chunks = chunk_text(document, max_chunk_size=2000) results = []
for i, chunk in enumerate(chunks): print(f"处理第 {i+1}/{len(chunks)} 块…") result = call_openclaw_with_retry({ "model": "gpt-5", "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": chunk} ], "max_tokens": 1000 # 控制输出长度 }) if result: results.append(result["choices"][0]["message"]["content"]) time.sleep(1) # 块间加间隔,避免触发速率限制
return "
".join(results)
把单次请求的 token 控制在 3000 以内(输入 2000 + 输出 1000),超时率直接降到 5% 以下。代价是需要多次请求,但胜在稳定。
同时发 20 个请求,基本上是在找死。OpenClaw 底层的速率限制会让大部分请求排队,排着排着就超时了。
import asyncio from asyncio import Semaphore
async def call_with_semaphore(semaphore, payload, session): """带并发控制的异步调用""" async with semaphore: try: async with session.post( "https://api.openclaw.example/v1/chat/completions", json=payload, timeout=aiohttp.ClientTimeout(total=120) ) as resp: return await resp.json() except asyncio.TimeoutError: print("单个请求超时,跳过") return None
async def batch_process(payloads, max_concurrent=3): """批量处理,限制最大并发数""" semaphore = Semaphore(max_concurrent) # 最多同时 3 个请求
import aiohttp async with aiohttp.ClientSession( headers={"Authorization": "Bearer your-key"} ) as session: tasks = [call_with_semaphore(semaphore, p, session) for p in payloads] results = await asyncio.gather(*tasks)
return results
使用:20 个任务,但同时只跑 3 个
asyncio.run(batch_process(my_payloads, max_concurrent=3))
并发从 20 降到 3,超时率从 40% 降到 8%。总耗时变长了,但结果是完整的,不用反复补跑失败任务。
前三个方案说白了都是在"忍"。如果 OpenClaw 底层调用的模型服务本身就不稳定,怎么调参数都是治标不治本。
对超时敏感的任务,我后来直接走稳定性更好的 API 聚合通道。
改动量极小,只换 base_url 和 api_key:
from openai import OpenAI
原来调 OpenClaw 底层模型经常超时
换成聚合接口,一个 Key 用所有模型
client = OpenAI( api_key="your-聚合平台-key", base_url="https://your-api-provider.com/v1" )
response = client.chat.completions.create( model="gpt-5", # 或 claude-opus-4.6、deepseek-v3 等 messages=[ {"role": "user", "content": "你的 prompt"} ], max_tokens=2000, timeout=60 # 正常 60s 绰绰有余 )
print(response.choices[0].message.content)
同样的 prompt,同样的模型,走聚合接口的平均响应时间在 3-8 秒,跑了 200 条数据零超时。就是通道稳定性的差距。
我现在用的是方案二 + 方案四:长文本先拆块,然后走稳定的聚合 API 通道。跑了一周批量任务,超时报错从每天几十条降到了零。
最后说句掏心窝的:LLM request timed out 看起来简单,背后可能是 token 量、并发、网络链路、模型服务稳定性几个问题叠在一起。别只盯着一个方向调,先加日志把每次请求的 token 数和响应时间记下来,定位到真正的瓶颈再动手,能省不少时间。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/265289.html