-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: 添加 Provider 级别代理支持及请求失败日志 #4949
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - 我发现了 5 个问题,并给出了一些总体反馈:
- 现在 OpenAI、Anthropic、Gemini、TTS 等的连接错误处理逻辑基本是复制粘贴的,只是字符串检查略有不同(例如有的检查
type(e).__name__,有的检查e.message);建议把这部分逻辑集中到一个共享的 helper 中,这样各个 provider 在代理/连接失败的检测和日志记录上可以保持一致。 - 在
ChatProviderTemplate的 metadata 里,你现在同时在provider.items下和后面与api_base/model同级的位置定义了proxy;建议确认这种重复是有意而为之,并确保这两个定义能保持同步(相同的 description 和 hint),以避免在控制台中出现让人困惑的 schema 行为。 azure_tts_source.py中的日志标签"[Azure TTS OTTS] 使用代理"看起来相比下面的"[Azure TTS Native]"像是一个拼写错误;统一标签名称会让与代理相关的日志更容易检索和理解。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The connection-error handling logic for OpenAI, Anthropic, Gemini, TTS, etc. is now copy‑pasted with slightly different string checks (e.g., checking `type(e).__name__` vs `e.message`); consider centralizing this into a shared helper so providers use consistent detection and logging for proxy/connection failures.
- In `ChatProviderTemplate` metadata you now define `proxy` both under `provider.items` and again later alongside `api_base`/`model`; it would be good to verify this duplication is intentional and that the two definitions stay in sync (same description and hint) to avoid confusing schema behavior in the dashboard.
- The log tag `"[Azure TTS OTTS] 使用代理"` in `azure_tts_source.py` looks like a typo compared with `"[Azure TTS Native]"` below; aligning the tag names would make proxy‑related logs easier to search and interpret.
## Individual Comments
### Comment 1
<location> `astrbot/core/provider/sources/openai_source.py:36-41` </location>
<code_context>
self.set_model(provider_config.get("model", "unknown"))
+ def _create_http_client(self, provider_config: dict) -> httpx.AsyncClient | None:
+ """创建带代理的 HTTP 客户端"""
+ proxy = provider_config.get("proxy", "")
+ if proxy:
+ logger.info(f"[Anthropic] 使用代理: {proxy}")
+ return httpx.AsyncClient(proxy=proxy)
+ return None
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Custom `httpx.AsyncClient` instances passed into SDKs are never explicitly closed, which can leak connections.
This new helper (and similar ones in `anthropic_source`, `openai_embedding_source`, `openai_tts_api_source`) creates an `httpx.AsyncClient` and passes it into the SDK as `http_client`, but nothing ensures the client is ever closed. If providers are created repeatedly (e.g. config reloads), this can accumulate open connections/file descriptors.
Please either:
- Reuse a long‑lived client per provider and close it on app shutdown, or
- Introduce an explicit lifecycle (e.g. context manager / `aclose()` hook) so the SDK/client wrapper reliably closes the underlying `AsyncClient`.
Otherwise this risks resource leaks in long‑running or high‑churn scenarios.
</issue_to_address>
### Comment 2
<location> `astrbot/core/provider/sources/anthropic_source.py:221-230` </location>
<code_context>
- completion = await self.client.messages.create(
- **payloads, stream=False, extra_body=extra_body
- )
+ try:
+ completion = await self.client.messages.create(
+ **payloads, stream=False, extra_body=extra_body
+ )
+ except Exception as e:
+ if "ConnectError" in str(type(e).__name__) or "Connection" in str(e):
+ proxy = self.provider_config.get("proxy", "")
+ if proxy:
+ logger.error(f"[Anthropic] 代理连接失败。代理地址: {proxy},错误: {e}")
+ else:
+ logger.error(f"[Anthropic] 连接失败,未配置代理。错误: {e}")
+ raise
assert isinstance(completion, Message)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Connection error detection via string inspection on `Exception` is brittle and may miss relevant network failures.
The handler infers connection issues via `"ConnectError" in str(type(e).__name__) or "Connection" in str(e)`, which is brittle and depends on message text. It can both miss other relevant `httpx` network errors (timeouts, DNS, etc.) and misclassify unrelated exceptions whose messages contain “Connection”.
Prefer catching the specific `httpx` (or SDK) network exceptions and using `isinstance` checks (e.g. `httpx.ConnectError`, `httpx.NetworkError`, `httpx.ReadTimeout`) instead of string matching so proxy diagnostics are more accurate and resilient.
Suggested implementation:
```python
try:
completion = await self.client.messages.create(
**payloads, stream=False, extra_body=extra_body
)
except httpx.RequestError as e:
proxy = self.provider_config.get("proxy", "")
if proxy:
logger.error(
f"[Anthropic] 网络/代理连接失败 ({type(e).__name__})。代理地址: {proxy},错误: {e}"
)
else:
logger.error(
f"[Anthropic] 网络连接失败 ({type(e).__name__}),未配置代理。错误: {e}"
)
raise
```
To fully apply this change you should also:
1. Ensure `httpx` is imported at the top of `astrbot/core/provider/sources/anthropic_source.py`, e.g.:
- `import httpx`
2. If your project uses a local wrapper or alias around `httpx`, adjust the caught exception type accordingly (e.g. replace `httpx.RequestError` with the appropriate base network error).
</issue_to_address>
### Comment 3
<location> `astrbot/core/provider/sources/gemini_source.py:122-128` </location>
<code_context>
- # f"发生了错误(gemini_source)。Provider 配置如下: {self.provider_config}",
- # )
+
+ # 连接错误处理
+ if "ConnectError" in str(type(e).__name__) or "Connection" in str(e.message):
+ proxy = self.provider_config.get("proxy", "")
+ if proxy:
+ logger.error(f"[Gemini] 代理连接失败。代理地址: {proxy},错误: {e}")
+ else:
+ logger.error(f"[Gemini] 连接失败,未配置代理。错误: {e}")
+
raise e
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Gemini connection error handling also relies on string matching, which may be unreliable across error types.
This branch currently detects connection failures via string checks on the exception type/name. If the client changes exception names/messages (or localizes them), this may stop recognizing real connection errors. Prefer matching on the concrete exception classes provided by the Gemini/HTTP client, or centralize connection-detection logic so all providers share a single, more robust implementation.
Suggested implementation:
```python
# 连接错误处理
# 使用具体异常类型来判断是否为连接类错误,而非依赖异常名称/文案匹配
is_conn_error = isinstance(e, (TimeoutError, OSError))
# 某些 HTTP / 客户端库会把底层连接错误包在 __cause__ 中
cause = getattr(e, "__cause__", None)
if not is_conn_error and cause is not None:
is_conn_error = isinstance(cause, (TimeoutError, OSError))
if is_conn_error:
proxy = self.provider_config.get("proxy", "")
if proxy:
logger.error(f"[Gemini] 代理连接失败。代理地址: {proxy},错误: {e}")
else:
logger.error(f"[Gemini] 连接失败,未配置代理。错误: {e}")
raise e
```
如果项目中已经统一使用某个 HTTP / Gemini 客户端(如 httpx、aiohttp 等),可以进一步改进为:
1. 在公共工具模块中实现一个 `is_connection_error(exc: BaseException) -> bool`,内部基于具体客户端异常类(如 `httpx.ConnectError`, `httpx.ConnectTimeout`, `aiohttp.ClientConnectorError` 等)进行判断,并同时兜底 `TimeoutError` / `OSError`。
2. 在本文件中改为调用该公共方法,例如:
`from astrbot.core.utils.errors import is_connection_error`
然后:
`if is_connection_error(e): ...`
3. 将其他 provider 中的连接错误判断也统一迁移到该公共方法,避免各处重复且不一致的判断逻辑。
</issue_to_address>
### Comment 4
<location> `astrbot/core/provider/sources/azure_tts_source.py:32-35` </location>
<code_context>
self.last_sync_time = 0
self.timeout = Timeout(10.0)
self.retry_count = 3
+ self.proxy = config.get("proxy", "")
+ if self.proxy:
+ logger.info(f"[Azure TTS OTTS] 使用代理: {self.proxy}")
self._client: AsyncClient | None = None
</code_context>
<issue_to_address>
**nitpick (typo):** Log tag `[Azure TTS OTTS]` looks inconsistent and may be a typo, which can hinder log filtering.
The `[Azure TTS OTTS]` prefix is inconsistent with the later `[Azure TTS Native]` tag and existing naming patterns. If this isn’t an intentional acronym, please rename it to something like `[Azure TTS]` or `[Azure TTS API]` to keep log filtering consistent across Azure TTS implementations.
```suggestion
self.proxy = config.get("proxy", "")
if self.proxy:
logger.info(f"[Azure TTS] 使用代理: {self.proxy}")
self._client: AsyncClient | None = None
```
</issue_to_address>
### Comment 5
<location> `astrbot/core/provider/sources/anthropic_source.py:57` </location>
<code_context>
self.set_model(provider_config.get("model", "unknown"))
+ def _create_http_client(self, provider_config: dict) -> httpx.AsyncClient | None:
+ """创建带代理的 HTTP 客户端"""
+ proxy = provider_config.get("proxy", "")
</code_context>
<issue_to_address>
**issue (complexity):** Consider centralizing proxy-aware HTTP client creation and extracting explicit connection-error logging helpers to streamline the Anthropic provider implementation.
You can keep all the new behavior and still simplify by (1) centralizing HTTP client creation and (2) isolating connection‑error handling.
### 1. Centralize HTTP client creation
Instead of a provider‑local `_create_http_client` that duplicates the OpenAI pattern, move this to a shared helper (e.g. on `Provider`) and call it here.
**On the base `Provider` (or a shared utility):**
```python
# provider.py (or a shared utils module)
import httpx
from astrbot import logger
class Provider:
# ...
def _create_http_client(
self,
provider_label: str,
provider_config: dict,
) -> httpx.AsyncClient | None:
proxy = provider_config.get("proxy", "")
if proxy:
logger.info(f"[{provider_label}] 使用代理: {proxy}")
return httpx.AsyncClient(proxy=proxy)
return None
```
**In the Anthropic provider:**
```python
self.client = AsyncAnthropic(
api_key=self.chosen_api_key,
timeout=self.timeout,
base_url=self.base_url,
http_client=self._create_http_client("Anthropic", provider_config),
)
```
This keeps your new proxy behavior but avoids per‑provider duplication.
### 2. Use explicit exception types and extract logging
Separate the connection‑error logging from `_query` and use explicit `httpx` exception classes where possible. You can still fall back to a general `Exception` handler if needed.
```python
import httpx
# inside Anthropic provider
def _log_connection_failure(self, error: Exception) -> None:
proxy = self.provider_config.get("proxy", "")
if proxy:
logger.error(f"[Anthropic] 代理连接失败。代理地址: {proxy},错误: {error}")
else:
logger.error(f"[Anthropic] 连接失败,未配置代理。错误: {error}")
```
Then simplify `_query`:
```python
try:
completion = await self.client.messages.create(
**payloads,
stream=False,
extra_body=extra_body,
)
except (httpx.ConnectError, httpx.ProxyError, httpx.ReadTimeout) as e:
self._log_connection_failure(e)
raise
except Exception:
# keep existing behavior for non-connection errors
raise
```
This preserves all behavior (proxy support + logging) but removes brittle string inspection and keeps `_query` focused on request/response logic.
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进 Review 质量。
Original comment in English
Hey - I've found 5 issues, and left some high level feedback:
- The connection-error handling logic for OpenAI, Anthropic, Gemini, TTS, etc. is now copy‑pasted with slightly different string checks (e.g., checking
type(e).__name__vse.message); consider centralizing this into a shared helper so providers use consistent detection and logging for proxy/connection failures. - In
ChatProviderTemplatemetadata you now defineproxyboth underprovider.itemsand again later alongsideapi_base/model; it would be good to verify this duplication is intentional and that the two definitions stay in sync (same description and hint) to avoid confusing schema behavior in the dashboard. - The log tag
"[Azure TTS OTTS] 使用代理"inazure_tts_source.pylooks like a typo compared with"[Azure TTS Native]"below; aligning the tag names would make proxy‑related logs easier to search and interpret.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The connection-error handling logic for OpenAI, Anthropic, Gemini, TTS, etc. is now copy‑pasted with slightly different string checks (e.g., checking `type(e).__name__` vs `e.message`); consider centralizing this into a shared helper so providers use consistent detection and logging for proxy/connection failures.
- In `ChatProviderTemplate` metadata you now define `proxy` both under `provider.items` and again later alongside `api_base`/`model`; it would be good to verify this duplication is intentional and that the two definitions stay in sync (same description and hint) to avoid confusing schema behavior in the dashboard.
- The log tag `"[Azure TTS OTTS] 使用代理"` in `azure_tts_source.py` looks like a typo compared with `"[Azure TTS Native]"` below; aligning the tag names would make proxy‑related logs easier to search and interpret.
## Individual Comments
### Comment 1
<location> `astrbot/core/provider/sources/openai_source.py:36-41` </location>
<code_context>
self.set_model(provider_config.get("model", "unknown"))
+ def _create_http_client(self, provider_config: dict) -> httpx.AsyncClient | None:
+ """创建带代理的 HTTP 客户端"""
+ proxy = provider_config.get("proxy", "")
+ if proxy:
+ logger.info(f"[Anthropic] 使用代理: {proxy}")
+ return httpx.AsyncClient(proxy=proxy)
+ return None
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Custom `httpx.AsyncClient` instances passed into SDKs are never explicitly closed, which can leak connections.
This new helper (and similar ones in `anthropic_source`, `openai_embedding_source`, `openai_tts_api_source`) creates an `httpx.AsyncClient` and passes it into the SDK as `http_client`, but nothing ensures the client is ever closed. If providers are created repeatedly (e.g. config reloads), this can accumulate open connections/file descriptors.
Please either:
- Reuse a long‑lived client per provider and close it on app shutdown, or
- Introduce an explicit lifecycle (e.g. context manager / `aclose()` hook) so the SDK/client wrapper reliably closes the underlying `AsyncClient`.
Otherwise this risks resource leaks in long‑running or high‑churn scenarios.
</issue_to_address>
### Comment 2
<location> `astrbot/core/provider/sources/anthropic_source.py:221-230` </location>
<code_context>
- completion = await self.client.messages.create(
- **payloads, stream=False, extra_body=extra_body
- )
+ try:
+ completion = await self.client.messages.create(
+ **payloads, stream=False, extra_body=extra_body
+ )
+ except Exception as e:
+ if "ConnectError" in str(type(e).__name__) or "Connection" in str(e):
+ proxy = self.provider_config.get("proxy", "")
+ if proxy:
+ logger.error(f"[Anthropic] 代理连接失败。代理地址: {proxy},错误: {e}")
+ else:
+ logger.error(f"[Anthropic] 连接失败,未配置代理。错误: {e}")
+ raise
assert isinstance(completion, Message)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Connection error detection via string inspection on `Exception` is brittle and may miss relevant network failures.
The handler infers connection issues via `"ConnectError" in str(type(e).__name__) or "Connection" in str(e)`, which is brittle and depends on message text. It can both miss other relevant `httpx` network errors (timeouts, DNS, etc.) and misclassify unrelated exceptions whose messages contain “Connection”.
Prefer catching the specific `httpx` (or SDK) network exceptions and using `isinstance` checks (e.g. `httpx.ConnectError`, `httpx.NetworkError`, `httpx.ReadTimeout`) instead of string matching so proxy diagnostics are more accurate and resilient.
Suggested implementation:
```python
try:
completion = await self.client.messages.create(
**payloads, stream=False, extra_body=extra_body
)
except httpx.RequestError as e:
proxy = self.provider_config.get("proxy", "")
if proxy:
logger.error(
f"[Anthropic] 网络/代理连接失败 ({type(e).__name__})。代理地址: {proxy},错误: {e}"
)
else:
logger.error(
f"[Anthropic] 网络连接失败 ({type(e).__name__}),未配置代理。错误: {e}"
)
raise
```
To fully apply this change you should also:
1. Ensure `httpx` is imported at the top of `astrbot/core/provider/sources/anthropic_source.py`, e.g.:
- `import httpx`
2. If your project uses a local wrapper or alias around `httpx`, adjust the caught exception type accordingly (e.g. replace `httpx.RequestError` with the appropriate base network error).
</issue_to_address>
### Comment 3
<location> `astrbot/core/provider/sources/gemini_source.py:122-128` </location>
<code_context>
- # f"发生了错误(gemini_source)。Provider 配置如下: {self.provider_config}",
- # )
+
+ # 连接错误处理
+ if "ConnectError" in str(type(e).__name__) or "Connection" in str(e.message):
+ proxy = self.provider_config.get("proxy", "")
+ if proxy:
+ logger.error(f"[Gemini] 代理连接失败。代理地址: {proxy},错误: {e}")
+ else:
+ logger.error(f"[Gemini] 连接失败,未配置代理。错误: {e}")
+
raise e
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Gemini connection error handling also relies on string matching, which may be unreliable across error types.
This branch currently detects connection failures via string checks on the exception type/name. If the client changes exception names/messages (or localizes them), this may stop recognizing real connection errors. Prefer matching on the concrete exception classes provided by the Gemini/HTTP client, or centralize connection-detection logic so all providers share a single, more robust implementation.
Suggested implementation:
```python
# 连接错误处理
# 使用具体异常类型来判断是否为连接类错误,而非依赖异常名称/文案匹配
is_conn_error = isinstance(e, (TimeoutError, OSError))
# 某些 HTTP / 客户端库会把底层连接错误包在 __cause__ 中
cause = getattr(e, "__cause__", None)
if not is_conn_error and cause is not None:
is_conn_error = isinstance(cause, (TimeoutError, OSError))
if is_conn_error:
proxy = self.provider_config.get("proxy", "")
if proxy:
logger.error(f"[Gemini] 代理连接失败。代理地址: {proxy},错误: {e}")
else:
logger.error(f"[Gemini] 连接失败,未配置代理。错误: {e}")
raise e
```
如果项目中已经统一使用某个 HTTP / Gemini 客户端(如 httpx、aiohttp 等),可以进一步改进为:
1. 在公共工具模块中实现一个 `is_connection_error(exc: BaseException) -> bool`,内部基于具体客户端异常类(如 `httpx.ConnectError`, `httpx.ConnectTimeout`, `aiohttp.ClientConnectorError` 等)进行判断,并同时兜底 `TimeoutError` / `OSError`。
2. 在本文件中改为调用该公共方法,例如:
`from astrbot.core.utils.errors import is_connection_error`
然后:
`if is_connection_error(e): ...`
3. 将其他 provider 中的连接错误判断也统一迁移到该公共方法,避免各处重复且不一致的判断逻辑。
</issue_to_address>
### Comment 4
<location> `astrbot/core/provider/sources/azure_tts_source.py:32-35` </location>
<code_context>
self.last_sync_time = 0
self.timeout = Timeout(10.0)
self.retry_count = 3
+ self.proxy = config.get("proxy", "")
+ if self.proxy:
+ logger.info(f"[Azure TTS OTTS] 使用代理: {self.proxy}")
self._client: AsyncClient | None = None
</code_context>
<issue_to_address>
**nitpick (typo):** Log tag `[Azure TTS OTTS]` looks inconsistent and may be a typo, which can hinder log filtering.
The `[Azure TTS OTTS]` prefix is inconsistent with the later `[Azure TTS Native]` tag and existing naming patterns. If this isn’t an intentional acronym, please rename it to something like `[Azure TTS]` or `[Azure TTS API]` to keep log filtering consistent across Azure TTS implementations.
```suggestion
self.proxy = config.get("proxy", "")
if self.proxy:
logger.info(f"[Azure TTS] 使用代理: {self.proxy}")
self._client: AsyncClient | None = None
```
</issue_to_address>
### Comment 5
<location> `astrbot/core/provider/sources/anthropic_source.py:57` </location>
<code_context>
self.set_model(provider_config.get("model", "unknown"))
+ def _create_http_client(self, provider_config: dict) -> httpx.AsyncClient | None:
+ """创建带代理的 HTTP 客户端"""
+ proxy = provider_config.get("proxy", "")
</code_context>
<issue_to_address>
**issue (complexity):** Consider centralizing proxy-aware HTTP client creation and extracting explicit connection-error logging helpers to streamline the Anthropic provider implementation.
You can keep all the new behavior and still simplify by (1) centralizing HTTP client creation and (2) isolating connection‑error handling.
### 1. Centralize HTTP client creation
Instead of a provider‑local `_create_http_client` that duplicates the OpenAI pattern, move this to a shared helper (e.g. on `Provider`) and call it here.
**On the base `Provider` (or a shared utility):**
```python
# provider.py (or a shared utils module)
import httpx
from astrbot import logger
class Provider:
# ...
def _create_http_client(
self,
provider_label: str,
provider_config: dict,
) -> httpx.AsyncClient | None:
proxy = provider_config.get("proxy", "")
if proxy:
logger.info(f"[{provider_label}] 使用代理: {proxy}")
return httpx.AsyncClient(proxy=proxy)
return None
```
**In the Anthropic provider:**
```python
self.client = AsyncAnthropic(
api_key=self.chosen_api_key,
timeout=self.timeout,
base_url=self.base_url,
http_client=self._create_http_client("Anthropic", provider_config),
)
```
This keeps your new proxy behavior but avoids per‑provider duplication.
### 2. Use explicit exception types and extract logging
Separate the connection‑error logging from `_query` and use explicit `httpx` exception classes where possible. You can still fall back to a general `Exception` handler if needed.
```python
import httpx
# inside Anthropic provider
def _log_connection_failure(self, error: Exception) -> None:
proxy = self.provider_config.get("proxy", "")
if proxy:
logger.error(f"[Anthropic] 代理连接失败。代理地址: {proxy},错误: {error}")
else:
logger.error(f"[Anthropic] 连接失败,未配置代理。错误: {error}")
```
Then simplify `_query`:
```python
try:
completion = await self.client.messages.create(
**payloads,
stream=False,
extra_body=extra_body,
)
except (httpx.ConnectError, httpx.ProxyError, httpx.ReadTimeout) as e:
self._log_connection_failure(e)
raise
except Exception:
# keep existing behavior for non-connection errors
raise
```
This preserves all behavior (proxy support + logging) but removes brittle string inspection and keeps `_query` focused on request/response logic.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
6a39ca9 to
1e43f02
Compare
|
如果还有没考虑到的地方,请指正 |
| completion = await self.client.messages.create( | ||
| **payloads, stream=False, extra_body=extra_body | ||
| ) | ||
| except httpx.RequestError as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
openai source 我看记录了 os.environ 里面的 proxy 作为provider_config.get("proxy", "")为空时的fallback,但是其他source好像没有。是不是可以考虑把 os.environ 里面的 proxy fallback 放到 log_connection_failure 内。如 proxy 为空的时候,就换成os.environ 里面的 proxy 去输出日志。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okk我看到了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Soulter review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
为 AstrBot 的各个 Provider Source 增加“按提供商级别”的代理配置(proxy),并在网络/代理连接失败时输出更明确的错误日志;同时在 Dashboard 中补齐该字段的展示与 i18n 文案,改善 Docker 场景下代理与内网通信的兼容性。
Changes:
- 后端:在 provider 模板与配置元数据中加入
proxy字段,并为部分 Provider 增加代理注入与连接失败日志能力 - 新增通用网络工具:统一识别连接类异常并输出包含代理信息的失败日志
- 前端:在 Provider 源高级配置中暴露
proxy字段,并添加中英文提示/标签
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
astrbot/core/config/default.py |
扩展默认 no_proxy,并为各 Provider 模板与元数据增加 proxy 字段 |
astrbot/core/utils/network_utils.py |
新增连接错误识别、失败日志、代理 http client 创建 helper |
astrbot/core/provider/sources/openai_source.py |
OpenAI 适配器支持 provider-level 代理并改进连接失败日志 |
astrbot/core/provider/sources/anthropic_source.py |
Anthropic 适配器支持 provider-level 代理并增强连接失败日志 |
astrbot/core/provider/sources/gemini_source.py |
Gemini 适配器支持 provider-level 代理并在连接异常时记录日志 |
astrbot/core/provider/sources/gemini_embedding_source.py |
Gemini Embedding 支持代理并输出启用代理日志 |
astrbot/core/provider/sources/gemini_tts_source.py |
Gemini TTS 支持代理并输出启用代理日志 |
astrbot/core/provider/sources/openai_embedding_source.py |
OpenAI Embedding 支持代理并输出启用代理日志 |
astrbot/core/provider/sources/openai_tts_api_source.py |
OpenAI TTS API 支持代理并输出启用代理日志 |
astrbot/core/provider/sources/fishaudio_tts_api_source.py |
FishAudio TTS API 请求增加 proxy 透传并输出启用代理日志 |
astrbot/core/provider/sources/azure_tts_source.py |
Azure TTS 请求增加 proxy 透传并输出启用代理日志 |
dashboard/src/composables/useProviderSources.ts |
为 proxy 字段补齐 schema 描述/提示的 i18n 映射 |
dashboard/src/i18n/locales/zh-CN/features/provider.json |
增加 proxy 的中文 label/hint 文案 |
dashboard/src/i18n/locales/en-US/features/provider.json |
增加 proxy 的英文 label/hint 文案 |
feat: 添加 Provider 级别代理支持及请求失败日志
Motivation / 动机
issue #4030
为每个 Provider 源添加独立的代理配置支持,允许用户为不同的模型提供商配置不同的代理地址。这对于以下场景特别有用:
Modifications / 改动点
后端更改:
astrbot/core/config/default.py:proxy字段CONFIG_METADATA_2中添加proxy字段的元数据(描述和提示)astrbot/core/provider/sources/openai_source.py: 添加代理支持和连接失败日志astrbot/core/provider/sources/anthropic_source.py: 添加代理支持和连接失败日志astrbot/core/provider/sources/gemini_source.py: 添加代理支持和连接失败日志astrbot/core/provider/sources/openai_embedding_source.py: 添加代理支持和日志astrbot/core/provider/sources/openai_tts_api_source.py: 添加代理支持和日志astrbot/core/provider/sources/gemini_embedding_source.py: 添加代理支持和日志astrbot/core/provider/sources/gemini_tts_source.py: 添加代理支持和日志astrbot/core/provider/sources/fishaudio_tts_api_source.py: 添加代理支持和日志astrbot/core/provider/sources/azure_tts_source.py: 添加代理支持和日志前端更改:
dashboard/src/composables/useProviderSources.ts: 添加 proxy 字段的 i18n 映射dashboard/src/i18n/locales/zh-CN/features/provider.json: 添加中文翻译dashboard/src/i18n/locales/en-US/features/provider.json: 添加英文翻译功能实现:
proxy字段(格式:http://127.0.0.1:7890)[Provider名] 使用代理: {proxy}Screenshots or Test Results / 运行截图或测试结果
前端 UI 显示:

在 Provider 源的"高级配置"中新增"代理地址"字段,带有中文描述和提示。
日志输出示例:
Checklist / 检查清单
requirements.txt和pyproject.toml文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations inrequirements.txtandpyproject.toml.Summary by Sourcery
为多个 AI 和 TTS 服务提供商新增「按提供商级别」的代理配置,并增强连接错误日志记录。
新功能:
增强内容:
no_proxy配置,覆盖常见的私有网络网段,使内部流量绕过 HTTP 代理。Original summary in English
Summary by Sourcery
Add provider-level proxy configuration and enhanced connection error logging for multiple AI and TTS providers.
New Features:
Enhancements: