问题描述
AstrBot v4.27.2 已提供全局配置 provider_settings.request_max_retries,其代码注释和 WebUI 提示均表示该值是“可重试请求错误的最大尝试次数,包含首次请求”。
但是 OpenAI Compatible provider 在创建 AsyncOpenAI / AsyncAzureOpenAI 客户端时没有显式传入 max_retries,因此仍会继承 OpenAI Python SDK 的默认值 max_retries=2。
结果是 AstrBot 的重试层与 OpenAI SDK 的重试层发生嵌套。即使将:
"provider_settings": {
"request_max_retries": 1
}
设置为只尝试一次,单次 AstrBot provider 请求内部仍可能实际发送 3 次 HTTP 请求:
1 次 AstrBot 尝试 ×(1 次 SDK 首次请求 + 2 次 SDK 重试)= 3 次 HTTP 请求
这会使 request_max_retries=1 无法真正关闭重试,也会显著延迟 fallback provider 的切换。
如何复现
环境:
- AstrBot:
v4.27.2
- 部署方式:Docker / Linux
- Provider: OpenAI Compatible (
openai_chat_completion)
- OpenAI Python SDK:
2.53.0
- 消息平台:OneBot v11(与问题本身无关)
配置:
{
"provider_sources": [
{
"type": "openai_chat_completion",
"timeout": 120
}
],
"provider_settings": {
"request_max_retries": 1
}
}
让兼容 API 的单次请求超过 120 秒,打开 Debug 日志。
尽管 request_max_retries=1,仍可看到 OpenAI SDK 的内部自动重试:
[openai._base_client] 2 retries left
[openai._base_client] Retrying request to /chat/completions ...
[openai._base_client] 1 retry left
[openai._base_client] Retrying request to /chat/completions ...
单个 provider 最终约等待:
之后 AstrBot 才切换到 fallback provider。
若 AstrBot 外层设置为更大的尝试次数,理论请求数还会相乘。例如 request_max_retries=5 时,OpenAI provider 最多可能产生 5 × 3 = 15 次 HTTP 请求。
根因定位
当前 openai_source.py 创建客户端时只设置了 timeout,未覆盖 SDK 的 max_retries:
self.client = AsyncOpenAI(
api_key=self.chosen_api_key,
base_url=provider_config.get("api_base", None),
default_headers=self.custom_headers,
timeout=self.timeout,
http_client=self._create_http_client(provider_config),
)
随后 AstrBot 又在 _query() / _query_stream() 外层使用:
retry_provider_request(
"OpenAI",
...,
max_attempts=request_max_retries,
)
因此形成两层重试。
预期行为
request_max_retries 应表示一次模型请求的真实最大尝试次数,且包含首次请求:
1:只发送一次请求,不重试;
2:首次请求 + 最多一次重试;
3:首次请求 + 最多两次重试。
OpenAI provider 不应再在 AstrBot 重试层内部隐式执行 SDK 自动重试。
建议修复
既然 AstrBot 已通过统一的 retry_provider_request() 控制 OpenAI、Gemini、Anthropic 等 provider 的请求重试,建议在创建 OpenAI 客户端时关闭 SDK 内建重试:
self.client = AsyncOpenAI(
...,
timeout=self.timeout,
max_retries=0,
)
AsyncAzureOpenAI 同样设置 max_retries=0。
这样 provider_settings.request_max_retries 就能成为单一、可预测的重试控制源。建议同时增加测试,断言 OpenAI/Azure OpenAI 客户端的 max_retries == 0,并验证 request_max_retries=1 时 transport 只被调用一次。
如果维护者希望保留 SDK 内建重试,另一种方案是把 SDK 重试次数明确暴露为独立配置,并在 WebUI 说明总请求次数是两层配置的乘积;不过统一由 AstrBot 控制重试的语义会更清晰。
相关 Issue / PR
我愿意在维护者确认预期方案后提交一个包含测试的修复 PR。
问题描述
AstrBot v4.27.2 已提供全局配置
provider_settings.request_max_retries,其代码注释和 WebUI 提示均表示该值是“可重试请求错误的最大尝试次数,包含首次请求”。但是 OpenAI Compatible provider 在创建
AsyncOpenAI/AsyncAzureOpenAI客户端时没有显式传入max_retries,因此仍会继承 OpenAI Python SDK 的默认值max_retries=2。结果是 AstrBot 的重试层与 OpenAI SDK 的重试层发生嵌套。即使将:
设置为只尝试一次,单次 AstrBot provider 请求内部仍可能实际发送 3 次 HTTP 请求:
这会使
request_max_retries=1无法真正关闭重试,也会显著延迟 fallback provider 的切换。如何复现
环境:
v4.27.2openai_chat_completion)2.53.0配置:
{ "provider_sources": [ { "type": "openai_chat_completion", "timeout": 120 } ], "provider_settings": { "request_max_retries": 1 } }让兼容 API 的单次请求超过 120 秒,打开 Debug 日志。
尽管
request_max_retries=1,仍可看到 OpenAI SDK 的内部自动重试:单个 provider 最终约等待:
之后 AstrBot 才切换到 fallback provider。
若 AstrBot 外层设置为更大的尝试次数,理论请求数还会相乘。例如
request_max_retries=5时,OpenAI provider 最多可能产生5 × 3 = 15次 HTTP 请求。根因定位
当前
openai_source.py创建客户端时只设置了timeout,未覆盖 SDK 的max_retries:随后 AstrBot 又在
_query()/_query_stream()外层使用:因此形成两层重试。
预期行为
request_max_retries应表示一次模型请求的真实最大尝试次数,且包含首次请求:1:只发送一次请求,不重试;2:首次请求 + 最多一次重试;3:首次请求 + 最多两次重试。OpenAI provider 不应再在 AstrBot 重试层内部隐式执行 SDK 自动重试。
建议修复
既然 AstrBot 已通过统一的
retry_provider_request()控制 OpenAI、Gemini、Anthropic 等 provider 的请求重试,建议在创建 OpenAI 客户端时关闭 SDK 内建重试:AsyncAzureOpenAI同样设置max_retries=0。这样
provider_settings.request_max_retries就能成为单一、可预测的重试控制源。建议同时增加测试,断言 OpenAI/Azure OpenAI 客户端的max_retries == 0,并验证request_max_retries=1时 transport 只被调用一次。如果维护者希望保留 SDK 内建重试,另一种方案是把 SDK 重试次数明确暴露为独立配置,并在 WebUI 说明总请求次数是两层配置的乘积;不过统一由 AstrBot 控制重试的语义会更清晰。
相关 Issue / PR
request_max_retries实现,但没有覆盖 SDK 内建重试。retry_provider_request()和request_max_retries的 PR。我愿意在维护者确认预期方案后提交一个包含测试的修复 PR。