mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
fix: 流式响应健壮性增强与候选排序稳定性修复
- test-model 接口优先使用流式请求,失败自动回退非流式 - CLI 流式处理在 StreamClosed/RemoteProtocolError 时 flush 残余 SSE 数据,捕获尾部 usage - 流未正常完成时兜底估算 tokens,避免 usage 记录为 0 - ProviderCandidate 添加 __lt__ 解决 tuple 排序 TypeError - sorted() 添加显式 key 参数避免隐式比较候选对象 - 异常日志改用 logger.opt(exception=e) 替代手动 traceback
This commit is contained in:
@@ -590,7 +590,7 @@ async def test_model(
|
||||
logger.debug(f"[test-model] 端点 API Format: {endpoint.api_format}")
|
||||
logger.debug(f"[test-model] 使用 Key: {api_key.name or api_key.id} (auth_type={auth_type})")
|
||||
|
||||
# 准备测试请求数据
|
||||
# 准备测试请求数据(优先使用流式)
|
||||
check_request = {
|
||||
"model": request.model_name,
|
||||
"messages": [
|
||||
@@ -598,6 +598,7 @@ async def test_model(
|
||||
],
|
||||
"max_tokens": 30,
|
||||
"temperature": 0.7,
|
||||
"stream": True,
|
||||
}
|
||||
|
||||
# 获取端点规则(不在此处应用,传递给 check_endpoint 在格式转换后应用)
|
||||
@@ -619,27 +620,57 @@ async def test_model(
|
||||
# Provider 上下文:auth_type 用于 OAuth 认证头处理,provider_type 用于特殊路由
|
||||
p_type = str(getattr(provider, "provider_type", "") or "").lower()
|
||||
|
||||
response = await adapter_class.check_endpoint(
|
||||
client,
|
||||
endpoint_config["base_url"],
|
||||
endpoint_config["api_key"],
|
||||
check_request,
|
||||
extra_headers if extra_headers else None,
|
||||
# 端点规则(在 check_endpoint 内部格式转换后应用)
|
||||
body_rules=body_rules,
|
||||
header_rules=header_rules,
|
||||
# 用量计算参数(现在强制记录)
|
||||
db=db,
|
||||
user=current_user,
|
||||
provider_name=provider.name,
|
||||
provider_id=provider.id,
|
||||
api_key_id=endpoint_config.get("api_key_id"),
|
||||
model_name=request.model_name,
|
||||
# Provider 上下文
|
||||
auth_type=auth_type,
|
||||
provider_type=p_type if p_type else None,
|
||||
decrypted_auth_config=oauth_meta if oauth_meta else None,
|
||||
)
|
||||
async def _do_check(req: dict) -> dict:
|
||||
return await adapter_class.check_endpoint(
|
||||
client,
|
||||
endpoint_config["base_url"],
|
||||
endpoint_config["api_key"],
|
||||
req,
|
||||
extra_headers if extra_headers else None,
|
||||
body_rules=body_rules,
|
||||
header_rules=header_rules,
|
||||
db=db,
|
||||
user=current_user,
|
||||
provider_name=provider.name,
|
||||
provider_id=provider.id,
|
||||
api_key_id=endpoint_config.get("api_key_id"),
|
||||
model_name=request.model_name,
|
||||
auth_type=auth_type,
|
||||
provider_type=p_type if p_type else None,
|
||||
decrypted_auth_config=oauth_meta if oauth_meta else None,
|
||||
)
|
||||
|
||||
def _response_has_error(resp: dict) -> bool:
|
||||
"""快速判断响应是否包含错误"""
|
||||
if "error" in resp:
|
||||
return True
|
||||
if resp.get("status_code", 0) != 200:
|
||||
return True
|
||||
resp_data = resp.get("response", {})
|
||||
resp_body = resp_data.get("response_body", {})
|
||||
parsed = resp_body
|
||||
if isinstance(resp_body, str):
|
||||
try:
|
||||
parsed = json.loads(resp_body)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
pass
|
||||
if isinstance(parsed, dict) and "error" in parsed:
|
||||
return True
|
||||
return False
|
||||
|
||||
# 策略:优先流式,若失败回退到非流式
|
||||
used_stream = True
|
||||
logger.debug("[test-model] 尝试流式请求...")
|
||||
response = await _do_check(check_request)
|
||||
|
||||
if _response_has_error(response):
|
||||
logger.info(
|
||||
"[test-model] 流式请求失败 (status={}),回退到非流式请求",
|
||||
response.get("status_code", "?"),
|
||||
)
|
||||
check_request["stream"] = False
|
||||
used_stream = False
|
||||
response = await _do_check(check_request)
|
||||
|
||||
# 记录提供商返回信息
|
||||
logger.debug("[test-model] 端点测试结果:")
|
||||
@@ -745,7 +776,7 @@ async def test_model(
|
||||
return {
|
||||
"success": is_success,
|
||||
"data": {
|
||||
"stream": False,
|
||||
"stream": used_stream,
|
||||
"response": response,
|
||||
},
|
||||
"provider": {
|
||||
|
||||
Reference in New Issue
Block a user