mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 09:50:21 +08:00
fix(orchestration): 处理流式响应中的嵌入式错误
- 新增对 EmbeddedErrorException 的处理逻辑 - 客户端错误(如 prompt too long)停止重试并抛出异常 - 服务端错误允许重试或故障转移 - 将 _is_client_error 改为公开方法 is_client_error
This commit is contained in:
@@ -241,7 +241,7 @@ class ErrorClassifier:
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _is_client_error(self, error_text: Optional[str]) -> bool:
|
def is_client_error(self, error_text: Optional[str]) -> bool:
|
||||||
"""
|
"""
|
||||||
检测错误响应是否为客户端错误(不应重试)
|
检测错误响应是否为客户端错误(不应重试)
|
||||||
|
|
||||||
@@ -471,7 +471,7 @@ class ErrorClassifier:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 400 错误:检查是否为客户端请求错误(不应重试)
|
# 400 错误:检查是否为客户端请求错误(不应重试)
|
||||||
if status == 400 and self._is_client_error(error_response_text):
|
if status == 400 and self.is_client_error(error_response_text):
|
||||||
logger.info(f"检测到客户端请求错误,不进行重试: {extracted_message}")
|
logger.info(f"检测到客户端请求错误,不进行重试: {extracted_message}")
|
||||||
return UpstreamClientException(
|
return UpstreamClientException(
|
||||||
message=extracted_message or "请求无效",
|
message=extracted_message or "请求无效",
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ from src.core.enums import APIFormat
|
|||||||
from src.core.error_utils import extract_error_message
|
from src.core.error_utils import extract_error_message
|
||||||
from src.core.exceptions import (
|
from src.core.exceptions import (
|
||||||
ConcurrencyLimitError,
|
ConcurrencyLimitError,
|
||||||
|
EmbeddedErrorException,
|
||||||
ProviderNotAvailableException,
|
ProviderNotAvailableException,
|
||||||
UpstreamClientException,
|
UpstreamClientException,
|
||||||
)
|
)
|
||||||
@@ -353,6 +354,54 @@ class FallbackOrchestrator:
|
|||||||
)
|
)
|
||||||
return "break"
|
return "break"
|
||||||
|
|
||||||
|
# 处理嵌入式错误(流式响应中检测到的错误)
|
||||||
|
# 需要检查错误消息是否为客户端错误(如 prompt is too long),这类错误不应重试
|
||||||
|
if isinstance(cause, EmbeddedErrorException):
|
||||||
|
error_message = cause.error_message or ""
|
||||||
|
if self._error_classifier.is_client_error(error_message):
|
||||||
|
logger.warning(
|
||||||
|
f" [{request_id}] 嵌入式客户端错误,停止重试: {error_message[:200]}"
|
||||||
|
)
|
||||||
|
# 转换为 UpstreamClientException
|
||||||
|
client_error = UpstreamClientException(
|
||||||
|
message=error_message or "请求无效",
|
||||||
|
provider_name=str(provider.name),
|
||||||
|
status_code=200, # 嵌入式错误的 HTTP 状态码通常是 200
|
||||||
|
upstream_error=error_message,
|
||||||
|
)
|
||||||
|
RequestCandidateService.mark_candidate_failed(
|
||||||
|
db=self.db,
|
||||||
|
candidate_id=candidate_record_id,
|
||||||
|
error_type="UpstreamClientException",
|
||||||
|
error_message=error_message,
|
||||||
|
status_code=200,
|
||||||
|
latency_ms=elapsed_ms,
|
||||||
|
concurrent_requests=captured_key_concurrent,
|
||||||
|
)
|
||||||
|
client_error.request_metadata = {
|
||||||
|
"provider": provider.name,
|
||||||
|
"provider_id": str(provider.id),
|
||||||
|
"provider_endpoint_id": str(endpoint.id),
|
||||||
|
"provider_api_key_id": str(key.id),
|
||||||
|
"api_format": api_format.value if hasattr(api_format, "value") else str(api_format),
|
||||||
|
}
|
||||||
|
raise client_error
|
||||||
|
else:
|
||||||
|
# 非客户端错误(服务端错误),记录失败并允许重试/故障转移
|
||||||
|
logger.warning(
|
||||||
|
f" [{request_id}] 嵌入式服务端错误,尝试重试: {error_message[:200]}"
|
||||||
|
)
|
||||||
|
RequestCandidateService.mark_candidate_failed(
|
||||||
|
db=self.db,
|
||||||
|
candidate_id=candidate_record_id,
|
||||||
|
error_type="EmbeddedErrorException",
|
||||||
|
error_message=error_message,
|
||||||
|
status_code=200,
|
||||||
|
latency_ms=elapsed_ms,
|
||||||
|
concurrent_requests=captured_key_concurrent,
|
||||||
|
)
|
||||||
|
return "continue" if has_retry_left else "break"
|
||||||
|
|
||||||
if isinstance(cause, httpx.HTTPStatusError):
|
if isinstance(cause, httpx.HTTPStatusError):
|
||||||
status_code = cause.response.status_code
|
status_code = cause.response.status_code
|
||||||
# 使用 ErrorClassifier 处理 HTTP 错误
|
# 使用 ErrorClassifier 处理 HTTP 错误
|
||||||
|
|||||||
Reference in New Issue
Block a user