diff --git a/backend/internal/service/gateway_request.go b/backend/internal/service/gateway_request.go index 1cf5728e0c..ff9786431d 100644 --- a/backend/internal/service/gateway_request.go +++ b/backend/internal/service/gateway_request.go @@ -1294,10 +1294,10 @@ func RectifyThinkingBudget(body []byte) ([]byte, bool) { // NormalizeChineseLLMThinking rewrites the top-level `thinking` object for Chinese // LLM providers that use Anthropic-compatible endpoints but have different accepted // values for `thinking.type`. Currently scoped to: -// - MiniMax M3 / M3.x (`MiniMax-m*`): official docs accept only `thinking.type` -// of "adaptive" or "disabled"; "enabled" is not a valid value and may be -// rejected/ignored. Pi-ai and other Anthropic-SDK clients default to "enabled" -// (Anthropic-original) and never auto-rewrite for non-Anthropic models. +// - MiniMax M-series (`MiniMax-m*`, covering M2.x / M3 / M3.x): official docs accept +// only `thinking.type` of "adaptive" or "disabled"; "enabled" is not a valid value +// and may be rejected/ignored. Pi-ai and other Anthropic-SDK clients default to +// "enabled" (Anthropic-original) and never auto-rewrite for non-Anthropic models. // // Non-MiniMax models (Kimi/GLM/DeepSeek) currently accept "enabled" as-is, so this // function is intentionally a no-op for them. New Chinese LLM quirks should be diff --git a/backend/internal/service/gemini_messages_compat_service.go b/backend/internal/service/gemini_messages_compat_service.go index f041292e2f..d56df59e4d 100644 --- a/backend/internal/service/gemini_messages_compat_service.go +++ b/backend/internal/service/gemini_messages_compat_service.go @@ -832,6 +832,9 @@ func (s *GeminiMessagesCompatService) Forward(ctx context.Context, c *gin.Contex var strippedClaudeBody []byte stageName := "" + // 路径说明:本处上游是 Gemini,但被剥离的 body 是 Anthropic 格式。传 originalModel + // (客户端原 Anthropic model)而非 mappedModel(上游 Gemini model),让剥离逻辑按 + // 客户端请求的 Anthropic 子协议族判定(详见 ResolveThinkingProtocol 文档)。 switch signatureRetryStage { case 0: // Stage 1: disable thinking + thinking->text diff --git a/backend/internal/service/thinking_protocol.go b/backend/internal/service/thinking_protocol.go index b7c0f2bc01..686baf467d 100644 --- a/backend/internal/service/thinking_protocol.go +++ b/backend/internal/service/thinking_protocol.go @@ -26,9 +26,15 @@ const ( ThinkingProtocolPassbackRequired ) -// ResolveThinkingProtocol 根据「实际发给上游的模型 ID」推断 thinking 协议族。 -// 必须传入映射后的模型 ID(mappedModel),不要传客户端原始请求模型 ID(reqModel), -// 否则用户配置「claude-sonnet-4-6 → deepseek-v4-pro」时会判错。 +// ResolveThinkingProtocol 根据「作为 thinking block 处理参考的模型 ID」推断 thinking 协议族。 +// +// 传入参数的语义随调用路径不同: +// - **Anthropic gateway**(转发原始 Anthropic 请求):传 mappedModel(账号级 model mapping +// 后的上游 model ID)。例:用户配置「claude-sonnet-4-6 → deepseek-v4-pro」后, +// 传 deepseek-v4-pro 才能被正确判为 passback-required。 +// - **Gemini messages compat**(Anthropic body → Gemini upstream):传 originalModel +// (客户端 Anthropic 请求的 model ID)。原因:此场景下上游是 Gemini,但被剥 +// 离的 body 是 Anthropic 格式,需按客户端请求的 Anthropic 子协议族判定剥离行为。 // // 匹配规则按厂商前缀硬编码: // - anthropic-strict: claude-* / opus-* / sonnet-* / haiku-*