fix(orchestration): 处理流式响应中的嵌入式错误

- 新增对 EmbeddedErrorException 的处理逻辑
- 客户端错误(如 prompt too long)停止重试并抛出异常
- 服务端错误允许重试或故障转移
- 将 _is_client_error 改为公开方法 is_client_error
This commit is contained in:
fawney19
2026-01-14 15:43:02 +08:00
parent 1f6e384d2b
commit ec3c5994d9
2 changed files with 51 additions and 2 deletions

View File

@@ -241,7 +241,7 @@ class ErrorClassifier:
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 错误:检查是否为客户端请求错误(不应重试)
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}")
return UpstreamClientException(
message=extracted_message or "请求无效",

View File

@@ -33,6 +33,7 @@ from src.core.enums import APIFormat
from src.core.error_utils import extract_error_message
from src.core.exceptions import (
ConcurrencyLimitError,
EmbeddedErrorException,
ProviderNotAvailableException,
UpstreamClientException,
)
@@ -353,6 +354,54 @@ class FallbackOrchestrator:
)
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):
status_code = cause.response.status_code
# 使用 ErrorClassifier 处理 HTTP 错误