Skip to content

feat: 为 OpenAI provider 添加可配置的最大重试次数#7959

Open
Blueteemo wants to merge 1 commit intoAstrBotDevs:masterfrom
Blueteemo:feat/issue-7956-configurable-max-retries
Open

feat: 为 OpenAI provider 添加可配置的最大重试次数#7959
Blueteemo wants to merge 1 commit intoAstrBotDevs:masterfrom
Blueteemo:feat/issue-7956-configurable-max-retries

Conversation

@Blueteemo
Copy link
Copy Markdown
Contributor

@Blueteemo Blueteemo commented May 2, 2026

问题描述

OpenAI provider 的 max_retries 硬编码为 10,导致超时时最长等待 20 分钟。

修复方案

添加可配置的 max_retries 选项,允许用户控制最大重试次数(范围 1-50)。默认值保持 10。

修改内容

  • openai_source.py:从 provider 配置读取 max_retries,不再使用硬编码值
  • default.py:在 OpenAI provider 模板中添加 max_retries: 10
  • config-metadata.json:添加中英俄三语翻译

关联 Issue

Fixes #7956

Summary by Sourcery

Make the OpenAI provider’s maximum retry count configurable instead of hard-coded.

New Features:

  • Add a configurable max_retries option for the OpenAI provider with a default of 10 and bounds between 1 and 50.

Enhancements:

  • Validate and clamp the configured max_retries value, emitting warnings when it is invalid or out of range.
  • Expose the max_retries setting in the default OpenAI provider configuration schema for UI/config tooling.

Documentation:

  • Document the new max_retries option for the OpenAI provider in the localized configuration metadata (Chinese, English, Russian).

@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. labels May 2, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • Consider validating max_retries from provider_config (e.g., ensure it is an integer within a sane non-negative range) before using it, to avoid misconfiguration causing unexpected behavior or very long retry loops.
  • Since max_retries is now user-configurable, you may want to explicitly handle edge cases like 0 (no retries) and negative values, rather than relying on implicit behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider validating `max_retries` from `provider_config` (e.g., ensure it is an integer within a sane non-negative range) before using it, to avoid misconfiguration causing unexpected behavior or very long retry loops.
- Since `max_retries` is now user-configurable, you may want to explicitly handle edge cases like `0` (no retries) and negative values, rather than relying on implicit behavior.

## Individual Comments

### Comment 1
<location path="astrbot/core/provider/sources/openai_source.py" line_range="1192" />
<code_context>

         llm_response = None
-        max_retries = 10
+        max_retries = self.provider_config.get("max_retries", 10)
         available_api_keys = self.api_keys.copy()
         chosen_key = random.choice(available_api_keys)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Validate and bound `max_retries` from config to avoid pathological values.

Because this is now user-configurable, invalid values (0, negative, non-numeric, or very large) could lead to no retries or excessively long retry loops. Consider coercing to `int` and clamping to a safe range (e.g., `max(1, min(configured_value, SOME_UPPER_BOUND))`), or at least validating that it’s numeric and > 0 before use.

Suggested implementation:

```python
        llm_response = None

        configured_max_retries = self.provider_config.get("max_retries", 10)
        try:
            max_retries = int(configured_max_retries)
        except (TypeError, ValueError):
            max_retries = 10
        else:
            # Clamp to a safe range to avoid pathological values
            max_retries = max(1, min(max_retries, 10))

        available_api_keys = self.api_keys.copy()
        chosen_key = random.choice(available_api_keys)
        image_fallback_used = False

```

```python
        if func_tool and not func_tool.empty():
            payloads["tool_choice"] = tool_choice

        configured_max_retries = self.provider_config.get("max_retries", 10)
        try:
            max_retries = int(configured_max_retries)
        except (TypeError, ValueError):
            max_retries = 10
        else:
            # Clamp to a safe range to avoid pathological values
            max_retries = max(1, min(max_retries, 10))

        available_api_keys = self.api_keys.copy()
        chosen_key = random.choice(available_api_keys)
        image_fallback_used = False

```

1. If you prefer a different upper bound than `10`, adjust the `min(max_retries, 10)` expression in both places.
2. If this pattern is used in other providers, consider refactoring the coercion/clamping logic into a shared helper (e.g., a method on the base provider) to keep behavior consistent across providers.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread astrbot/core/provider/sources/openai_source.py Outdated
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a configurable max_retries setting for OpenAI-compatible providers, updating the default configuration, the source logic, and the dashboard localization files. Feedback includes a bug fix to prevent crashes when max_retries is set to zero or less, a suggestion to refactor the retrieval logic into a helper function to avoid duplication, and a reminder to update the metadata definitions and other provider templates to ensure the new setting is correctly exposed and validated in the dashboard.

Comment thread astrbot/core/provider/sources/openai_source.py Outdated
Comment thread astrbot/core/config/default.py
Comment thread astrbot/core/provider/sources/openai_source.py Outdated
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. and removed size:XS This PR changes 0-9 lines, ignoring generated files. labels May 2, 2026
@Blueteemo Blueteemo changed the title feat: add configurable max_retries for OpenAI provider feat: 为 OpenAI provider 添加可配置的最大重试次数 May 2, 2026
@Blueteemo
Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • Consider logging or surfacing a warning when max_retries is invalid and the default of 10 is used, so misconfigurations are easier to diagnose in production.
  • The hardcoded upper bound of 50 in _get_max_retries may be surprising to users; it might be clearer to either document this constraint via a named constant or configuration hint, or avoid clamping unless there's a strong reason.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider logging or surfacing a warning when `max_retries` is invalid and the default of 10 is used, so misconfigurations are easier to diagnose in production.
- The hardcoded upper bound of 50 in `_get_max_retries` may be surprising to users; it might be clearer to either document this constraint via a named constant or configuration hint, or avoid clamping unless there's a strong reason.

## Individual Comments

### Comment 1
<location path="astrbot/core/config/default.py" line_range="2514-2518" />
<code_context>
                         "type": "int",
                         "hint": "超时时间,单位为秒。",
                     },
+                    "max_retries": {
+                        "description": "最大重试次数",
+                        "type": "int",
+                        "hint": "API 调用失败时的最大重试次数,默认为 10。",
+                    },
                     "mimo-stt-system-prompt": {
</code_context>
<issue_to_address>
**suggestion:** The hint for `max_retries` doesn't reflect the effective clamping range used in code.

The code clamps `max_retries` to `[1, 50]`, but the hint only states the default (10). Please update the hint to document the valid range so users aren’t surprised when large or non-positive values get clamped.

```suggestion
                    "max_retries": {
                        "description": "最大重试次数",
                        "type": "int",
                        "hint": "API 调用失败时的最大重试次数,范围为 1~50,默认为 10。",
                    },
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread astrbot/core/config/default.py
@Blueteemo
Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The _get_max_retries docstring mentions only ensuring a positive integer but the implementation clamps the value to 1–50; consider updating the docstring (or extracting a named constant for the upper bound) so the behavior and limits are clearly aligned.
  • The default value 10 for max_retries is now duplicated in _get_max_retries and in the OpenAI provider default config; consider centralizing this default (e.g., a module-level constant) to avoid drift if it changes in the future.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `_get_max_retries` docstring mentions only ensuring a positive integer but the implementation clamps the value to 1–50; consider updating the docstring (or extracting a named constant for the upper bound) so the behavior and limits are clearly aligned.
- The default value `10` for `max_retries` is now duplicated in `_get_max_retries` and in the OpenAI provider default config; consider centralizing this default (e.g., a module-level constant) to avoid drift if it changes in the future.

## Individual Comments

### Comment 1
<location path="astrbot/core/provider/sources/openai_source.py" line_range="498-505" />
<code_context>

         self.reasoning_key = "reasoning_content"

+    def _get_max_retries(self) -> int:
+        """获取并验证最大重试次数,确保为正整数。"""
+        raw = self.provider_config.get("max_retries", 10)
+        try:
+            value = int(raw)
+        except (TypeError, ValueError):
+            return 10
+        return max(1, min(value, 50))
+
     def _ollama_disable_thinking_enabled(self) -> bool:
</code_context>
<issue_to_address>
**suggestion:** Consider surfacing or logging when `max_retries` is out of range or invalid instead of silently clamping.

Invalid or out-of-range values are silently coerced into `[1, 50]` (or `10` if they can’t be cast). That makes misconfigurations (e.g., 0, negative, or 100) hard to detect and can lead to surprising behavior. Emitting a log or similar signal when clamping or falling back would make these issues easier to diagnose.

```suggestion
    def _get_max_retries(self) -> int:
        """获取并验证最大重试次数,确保为正整数。"""
        import logging

        logger = getattr(self, "logger", None) or logging.getLogger(__name__)

        raw = self.provider_config.get("max_retries", 10)
        try:
            value = int(raw)
        except (TypeError, ValueError):
            logger.warning(
                "Invalid 'max_retries' value %r in provider_config; falling back to default 10.",
                raw,
            )
            return 10

        if value < 1 or value > 50:
            logger.warning(
                "'max_retries' value %d in provider_config is out of range [1, 50]; "
                "clamping to the nearest value within range.",
                value,
            )

        return max(1, min(value, 50))
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread astrbot/core/provider/sources/openai_source.py Outdated
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:S This PR changes 10-29 lines, ignoring generated files. labels May 2, 2026
@Blueteemo Blueteemo force-pushed the feat/issue-7956-configurable-max-retries branch from 87acffd to 86f2d36 Compare May 2, 2026 17:16
@Blueteemo
Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The allowed range (1–50) for max_retries is now duplicated in _MAX_RETRIES_UPPER_BOUND and the config metadata; consider centralizing this constraint or at least adding a shared constant to avoid divergence in future changes.
  • If provider_config is immutable at runtime, you could compute self.max_retries once in __init__ instead of calling _get_max_retries() for every text_chat/text_chat_stream call to simplify the flow and avoid repeated parsing.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The allowed range (1–50) for `max_retries` is now duplicated in `_MAX_RETRIES_UPPER_BOUND` and the config metadata; consider centralizing this constraint or at least adding a shared constant to avoid divergence in future changes.
- If `provider_config` is immutable at runtime, you could compute `self.max_retries` once in `__init__` instead of calling `_get_max_retries()` for every `text_chat`/`text_chat_stream` call to simplify the flow and avoid repeated parsing.

## Individual Comments

### Comment 1
<location path="astrbot/core/provider/sources/openai_source.py" line_range="501-510" />
<code_context>
+    _MAX_RETRIES_DEFAULT = 10
+    _MAX_RETRIES_UPPER_BOUND = 50
+
+    def _get_max_retries(self) -> int:
+        """获取并验证最大重试次数,确保为 1 到 _MAX_RETRIES_UPPER_BOUND 之间的整数。"""
+        raw = self.provider_config.get("max_retries", self._MAX_RETRIES_DEFAULT)
+        try:
+            value = int(raw)
+        except (TypeError, ValueError):
+            logger.warning(
+                "max_retries 配置无效 (%s),使用默认值 %d。",
+                raw,
+                self._MAX_RETRIES_DEFAULT,
+            )
+            return self._MAX_RETRIES_DEFAULT
+        clamped = max(1, min(value, self._MAX_RETRIES_UPPER_BOUND))
+        if clamped != value:
+            logger.warning(
+                "max_retries 配置值 %d 超出范围,已调整为 %d。",
+                value,
+                clamped,
+            )
+        return clamped
+
     def _ollama_disable_thinking_enabled(self) -> bool:
</code_context>
<issue_to_address>
**issue (performance):** Avoid repeated warning logs on every call to `_get_max_retries` for a bad config value.

This logic will log a warning on every `text_chat` / `text_chat_stream` call when `max_retries` is invalid, which can flood logs in high-traffic usage and hide other issues. It would be better to validate and normalize this config once (e.g., at initialization), cache the result, and log at most once per process/load instead of per request.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread astrbot/core/provider/sources/openai_source.py
- 在 openai_source.py 中添加 _get_max_retries() 方法,支持 1-50 范围验证
- 在 __init__ 中计算一次 max_retries,避免重复调用
- 在 default.py 的 OpenAI provider 模板中添加 max_retries: 10
- 在 config-metadata.json 中添加中英俄三语翻译(含范围提示)
- 无效配置时记录 warning 日志
@Blueteemo Blueteemo force-pushed the feat/issue-7956-configurable-max-retries branch from 86f2d36 to 7695435 Compare May 2, 2026 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 模型提供商设置的超时未生效

1 participant