Skip to content

Conversation

kawayiYokami
Copy link
Contributor

@kawayiYokami kawayiYokami commented Sep 18, 2025

在 load_provider 方法中,对 provider_config 进行预处理,确保 'key' 字段存在且不为空列表,从而避免在实例化 OpenAI 兼容的 Provider 时因缺少 API Key 而抛出异常。

fixes #2763


修复因缺少 key 导致 provider 无法加载的问题" --body "

问题根源

新增 Provider 时,如果配置不合法(如 key 字段为空列表),ProviderManagerload_provider 方法会因为底层的 Provider 类(如 ProviderOpenAIOfficial)在 __init__ 中抛出异常而提前终止。

这导致负责将新实例注册到 inst_map 的代码行永远不会被执行,使得 inst_map 中从始至终都没有这个新 Provider 的条目,最终在运行时导致“找不到提供商”的错误。

解决方案

本 PR 采用了一个简单、直接且从根源上解决问题的方案:

ProviderManager.load_provider 方法的入口处,对传入的 provider_config 进行预处理。如果发现 key 字段不存在或是一个空列表,就强制为其设置一个包含空字符串的列表 ['']

# astrbot/core/provider/manager.py

async def load_provider(self, provider_config: dict):
    if not provider_config.get(\"enable\", False):
        return

    provider_config = provider_config.copy()

    # 关键修复:确保 provider_config 中有 'key' 字段,且不为空列表
    if not provider_config.get(\"key\"):
        provider_config[\"key\"] = [\"\"]
    
    # ... 后续逻辑 ...

效果

  1. 保证实例化成功:这个预处理确保了 Provider 类的 __init__ 方法不会因为 key 为空而抛出异常。
  2. 保证状态一致load_provider 总是能成功执行到底,并将新的实例注册到 inst_map 中,从而保证了配置与运行时实例地图的一致性。
  3. 正确的错误提示:当用户使用这个 key\"\" 的 Provider 时,底层的 API 客户端会返回一个明确的“无效 API Key”错误,而不是误导性的“找不到提供商”错误。

这个修改以最小的代价,从根源上解决了问题,并提高了系统的健壮性。"

Compatibility & Breaking Changes / 兼容性与破坏性变更

  • 这不是一个破坏性变更。/ This is NOT a breaking change.

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Sourcery 总结

Bug 修复:

  • 当 API 密钥缺失时,预先添加一个默认的空 API 密钥,以防止提供商加载失败
Original summary in English

Summary by Sourcery

Bug Fixes:

  • Preemptively add a default empty API key when missing to prevent provider loading failures

在 load_provider 方法中,对 provider_config 进行预处理,确保 'key' 字段存在且不为空列表,从而避免在实例化 OpenAI 兼容的 Provider 时因缺少 API Key 而抛出异常。
@kawayiYokami
Copy link
Contributor Author

这是我能想到的最优雅,最精炼,并且最少侵入性的修复方案。

因为几乎所有的openai格式,默认apikey都至少是一个空文本,而不应该是不存在这个属性。

Copy link
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.

你好 - 我已审阅了你的更改 - 这里有一些反馈意见:

  • 考虑将 provider_config.copy() 移动到 load_provider 的最顶部(在任何提前返回之前),以避免在启用检查后就地修改原始配置。
  • 当你自动注入空的 API 密钥时,记录日志或发出警告可能很有帮助,这样用户就能轻松发现底层的错误配置。
  • 与其默默地替换一个空字符串,不如验证是否存在非空密钥并引发明确的配置错误来引导用户。
AI 代理的提示
请处理此代码审查中的评论:

## 总体评论
- 考虑将 provider_config.copy() 移动到 load_provider 的最顶部(在任何提前返回之前),以避免在启用检查后就地修改原始配置。
- 当你自动注入空的 API 密钥时,记录日志或发出警告可能很有帮助,这样用户就能轻松发现底层的错误配置。
- 与其默默地替换一个空字符串,不如验证是否存在非空密钥并引发明确的配置错误来引导用户。

Sourcery 对开源免费 - 如果你喜欢我们的评论,请考虑分享它们 ✨
帮助我更有用!请点击每个评论上的 👍 或 👎,我将利用这些反馈来改进你的评论。
Original comment in English

Hey there - I've reviewed your changes - here's some feedback:

  • Consider moving the provider_config.copy() to the very top of load_provider (before any early returns) to avoid mutating the original config in-place after the enable check.
  • It could be helpful to log or warn when you auto-inject an empty API key so users can easily spot the underlying misconfiguration.
  • Rather than silently substituting an empty string, you might validate the presence of a non-empty key and raise a clear configuration error to guide users.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider moving the provider_config.copy() to the very top of load_provider (before any early returns) to avoid mutating the original config in-place after the enable check.
- It could be helpful to log or warn when you auto-inject an empty API key so users can easily spot the underlying misconfiguration.
- Rather than silently substituting an empty string, you might validate the presence of a non-empty key and raise a clear configuration error to guide users.

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.

@kawayiYokami
Copy link
Contributor Author

你好 - 我已审阅了你的更改 - 这里有一些反馈意见:

  • 考虑将 provider_config.copy() 移动到 load_provider 的最顶部(在任何提前返回之前),以避免在启用检查后就地修改原始配置。
  • 当你自动注入空的 API 密钥时,记录日志或发出警告可能很有帮助,这样用户就能轻松发现底层的错误配置。
  • 与其默默地替换一个空字符串,不如验证是否存在非空密钥并引发明确的配置错误来引导用户。

AI 代理的提示

请处理此代码审查中的评论:

## 总体评论
- 考虑将 provider_config.copy() 移动到 load_provider 的最顶部(在任何提前返回之前),以避免在启用检查后就地修改原始配置。
- 当你自动注入空的 API 密钥时,记录日志或发出警告可能很有帮助,这样用户就能轻松发现底层的错误配置。
- 与其默默地替换一个空字符串,不如验证是否存在非空密钥并引发明确的配置错误来引导用户。

Sourcery 对开源免费 - 如果你喜欢我们的评论,请考虑分享它们 ✨

帮助我更有用!请点击每个评论上的 👍 或 👎,我将利用这些反馈来改进你的评论。
Original comment in English

你懂个屁,没启动为什么要拷贝一份。
apikey为空是大多数配置的日常情况。不应该提醒。
因为很多本地模型密码本来就是空的,比如llmstudio。

apikey默认为空才是正确的实现。

@kawayiYokami
Copy link
Contributor Author

这个问题是什么情况呢?
就是只有新增的时候会检查合法性,判断是否加入提供商地图。
后续更新的时候是不会触发的。
导致只要新增的时候不合法,后续就算合法也永远无法加入提供商地图,导致新增了一个永远不可能被使用的提供商。

之前我写了一个每次reload都重新加入提供商地图,但是显然没这个优雅。

@kawayiYokami
Copy link
Contributor Author

kawayiYokami commented Sep 21, 2025

@Soulter

根源1、如果新增供应商的时候初始化失败就是不加入,然后后续再也没有加入的方法,除非重启,并且重启之后合法了才能加入。而导致这个原因是,apikey默认是空列表,而不是空字符串。空列表就会导致不存在这个字段导致无法初始化。
根源2、reload的时候,不会重新尝试加入提供商列表。

已有
解决方案1 pull/2810,默认apikey为0字符串,二不是空列表,成本极小。既本pr。
解决方案2 reload的时候重新尝试初始化并加入列表。之前被你批判了。
解决方案3 实例化的时候不应该检查参数是否合法,只在使用的时候提醒,而不是直接实例化失败。我没有去研究。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug] 服务提供商不可用
3 participants