fix: report provider test upstream errors

This commit is contained in:
2026-06-22 00:38:04 +08:00
parent 8407232dc6
commit f180fff020
6 changed files with 311 additions and 184 deletions
+102 -3
View File
@@ -2,7 +2,7 @@
LLM 提供商 API
"""
import logging
from typing import List, Optional
from typing import Any, List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select, func
@@ -25,6 +25,90 @@ logger = logging.getLogger(__name__)
router = APIRouter(prefix="/provider", tags=["AI-提供商"])
def _pick_message_from_payload(payload: Any) -> Optional[str]:
if isinstance(payload, dict):
for key in ('message', 'detail', 'error_description'):
value = payload.get(key)
if isinstance(value, str) and value:
return value
error = payload.get('error')
if isinstance(error, str) and error:
return error
if isinstance(error, dict):
return _pick_message_from_payload(error)
if isinstance(payload, list):
for item in payload:
message = _pick_message_from_payload(item)
if message:
return message
return None
def _extract_upstream_error(exc: Exception) -> str:
response = getattr(exc, 'response', None)
if response is not None:
status_code = getattr(response, 'status_code', None)
try:
message = _pick_message_from_payload(response.json())
except Exception:
message = None
if not message:
message = (getattr(response, 'text', '') or '').strip()
if status_code and message:
return f'HTTP {status_code}: {message[:240]}'
if status_code:
return f'HTTP {status_code}'
if message:
return message[:240]
return str(exc)[:240]
def _format_provider_test_error(exc: Exception, provider: LLMProvider, api_base: str) -> str:
error_text = f'{type(exc).__name__}: {str(exc)} {_extract_upstream_error(exc)}'
lower_text = error_text.lower()
if (
'401' in lower_text
or '403' in lower_text
or 'unauthorized' in lower_text
or 'forbidden' in lower_text
or 'invalid api key' in lower_text
or 'incorrect api key' in lower_text
or '无效的令牌' in error_text
or '鉴权' in error_text
):
reason = '上游模型鉴权失败,API Key 无效或已过期'
elif '404' in lower_text or 'not found' in lower_text:
reason = '模型接口不存在或 Base URL 路径不正确'
elif 'timeout' in lower_text or 'timed out' in lower_text or '超时' in error_text:
reason = '上游模型接口请求超时'
elif (
'connect' in lower_text
or 'network' in lower_text
or 'name or service not known' in lower_text
or 'connection' in lower_text
):
reason = '无法连接到上游模型接口'
elif '429' in lower_text or 'rate limit' in lower_text or 'quota' in lower_text:
reason = '上游模型限流或额度不足'
else:
reason = '上游模型接口调用失败'
upstream_error = _extract_upstream_error(exc) or ''
return (
f'{reason}:提供商 {provider.name},类型 {provider.provider_type}'
f'Base URL {api_base or "未配置"}'
f'请检查 Base URL、API Key 和上游账号权限。'
f'上游返回:{upstream_error}'
)
@router.get("/types", response_model=List[ProviderTypeResponse], summary="获取提供商类型列表")
async def get_provider_types():
"""获取所有支持的提供商类型"""
@@ -171,7 +255,18 @@ async def test_provider(provider_id: str, db: AsyncSession = Depends(get_db)):
if not provider_instance.validate_config():
raise HTTPException(status_code=400, detail="配置无效,请检查 API Key")
models = await provider_instance.fetch_models_from_api()
try:
models = await provider_instance.fetch_models_from_api_strict()
except Exception as e:
logger.warning(
"Provider online test failed: upstream error "
f"[provider={provider.name}, type={provider.provider_type}, api_base={api_base or '(empty)'}]: {e}"
)
raise HTTPException(
status_code=400,
detail=_format_provider_test_error(e, provider, api_base),
)
if not models:
logger.warning(
"Provider online test failed: no models returned "
@@ -179,7 +274,11 @@ async def test_provider(provider_id: str, db: AsyncSession = Depends(get_db)):
)
raise HTTPException(
status_code=400,
detail="连接失败:模型接口未返回可用模型,请检查 Base URL、API Key 或网络连通性",
detail=(
f"连接失败:模型接口返回为空。提供商 {provider.name}"
f"类型 {provider.provider_type}Base URL {api_base or '未配置'}"
"请检查 Base URL、API Key 和上游账号权限。"
),
)
return {