From 6424ad7e75a861240986b9c0b6af9ecff237aa5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Sun, 4 Oct 2026 19:56:16 +0800 Subject: [PATCH] =?UTF-8?q?fix(LLM=20=E4=BB=A3=E7=90=86):=20Chat=20Complet?= =?UTF-8?q?ions=20=E9=80=8F=E4=BC=A0=E7=B1=BB=E5=9E=8B=E5=8C=96=E9=94=99?= =?UTF-8?q?=E8=AF=AF=EF=BC=8C=E4=BF=9D=E7=95=99=E6=9D=83=E9=99=90=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolve_llm_router_client 返回 Result<_, AppError> 而非 String(评审第 17 条) - load_owner_llm_catalog 的 503 + MODEL_ACCESS_UNAVAILABLE 不再被拍平成「模型目录暂不可用」 - resolve_requested_for 错误改走 agc_model_resolve_error,与 proxy_llm_responses / proxy_llm_messages 契约一致 - LlmConfig / LlmClient 构造失败按 500 返回;调用方直接 llm_error_response 透传 --- server-rs/crates/api-server/src/llm/mod.rs | 31 +++++++++++++--------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/server-rs/crates/api-server/src/llm/mod.rs b/server-rs/crates/api-server/src/llm/mod.rs index 0ca4eea09..ab4c6a8db 100644 --- a/server-rs/crates/api-server/src/llm/mod.rs +++ b/server-rs/crates/api-server/src/llm/mod.rs @@ -187,12 +187,7 @@ pub async fn proxy_llm_chat_completions( let (llm_client, key_id) = match resolve_llm_router_client(&state, authenticated.claims().user_id()).await { Ok((client, key_id)) => (client, key_id), - Err(error) => { - return Err(llm_error_response( - &request_context, - AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_message(error), - )); - } + Err(error) => return Err(llm_error_response(&request_context, error)), }; prepare_llm_router_billing(&state, authenticated.claims().user_id()) .await @@ -1518,16 +1513,20 @@ fn is_responses_terminal_sse_event(event: &str) -> bool { async fn resolve_llm_router_client( state: &AppState, owner_user_id: &str, -) -> Result<(platform_llm::LlmClient, String), String> { - let (base_url, api_key, key_id) = resolve_llm_router_credentials(state, owner_user_id).await?; - let catalog = load_owner_llm_catalog(state, owner_user_id) +) -> Result<(platform_llm::LlmClient, String), AppError> { + let (base_url, api_key, key_id) = resolve_llm_router_credentials(state, owner_user_id) .await - .map_err(|_| "模型目录暂不可用".to_string())?; + .map_err(|message| { + AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_message(message) + })?; + // 目录读失败与会员权限读失败(503 + MODEL_ACCESS_UNAVAILABLE)都保留各自的类型化错误, + // 不再拍平成一句中文,与 `proxy_llm_responses` / `proxy_llm_messages` 的契约一致。 + let catalog = load_owner_llm_catalog(state, owner_user_id).await?; // Chat Completions 的 `model` 恒为账号该档的默认模型,不接收客户端选择。 let model = catalog .catalog .resolve_requested_for(None, catalog.access) - .map_err(|error| error.message().to_string())?; + .map_err(agc_model_resolve_error)?; let config = platform_llm::LlmConfig::new( platform_llm::LlmProvider::OpenAiCompatible, base_url.to_string(), @@ -1537,10 +1536,16 @@ async fn resolve_llm_router_client( state.config.llm_max_retries, state.config.llm_retry_backoff_ms, ) - .map_err(|error| error.to_string())?; + .map_err(|error| { + AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR) + .with_message(format!("LLM Router 客户端配置非法:{error}")) + })?; platform_llm::LlmClient::new(config) .map(|client| (client, key_id)) - .map_err(|error| error.to_string()) + .map_err(|error| { + AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR) + .with_message(format!("创建 LLM Router 客户端失败:{error}")) + }) } async fn resolve_llm_router_credentials(