From 2361c1b211ec11f2c4a21e4bb4161966357bf1eb Mon Sep 17 00:00:00 2001 From: SuYao Date: Sat, 6 Sep 2025 22:29:36 +0800 Subject: [PATCH] fix: implement Anthropic thinking budget calculation in reasoning logic (#9991) --- .../aiCore/prepareParams/parameterBuilder.ts | 16 +++++++-- src/renderer/src/aiCore/utils/reasoning.ts | 34 ++++++++++++------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/renderer/src/aiCore/prepareParams/parameterBuilder.ts b/src/renderer/src/aiCore/prepareParams/parameterBuilder.ts index d72010d03b..58b57792fb 100644 --- a/src/renderer/src/aiCore/prepareParams/parameterBuilder.ts +++ b/src/renderer/src/aiCore/prepareParams/parameterBuilder.ts @@ -9,17 +9,19 @@ import { isOpenRouterBuiltInWebSearchModel, isReasoningModel, isSupportedReasoningEffortModel, + isSupportedThinkingTokenClaudeModel, isSupportedThinkingTokenModel, isWebSearchModel } from '@renderer/config/models' import { getAssistantSettings, getDefaultModel } from '@renderer/services/AssistantService' -import type { Assistant, MCPTool, Provider } from '@renderer/types' +import { type Assistant, type MCPTool, type Provider } from '@renderer/types' import type { StreamTextParams } from '@renderer/types/aiCoreTypes' import type { ModelMessage } from 'ai' import { stepCountIs } from 'ai' import { setupToolsConfig } from '../utils/mcp' import { buildProviderOptions } from '../utils/options' +import { getAnthropicThinkingBudget } from '../utils/reasoning' import { getTemperature, getTopP } from './modelParameters' const logger = loggerService.withContext('parameterBuilder') @@ -55,7 +57,7 @@ export async function buildStreamTextParams( const model = assistant.model || getDefaultModel() - const { maxTokens } = getAssistantSettings(assistant) + let { maxTokens } = getAssistantSettings(assistant) // 这三个变量透传出来,交给下面启用插件/中间件 // 也可以在外部构建好再传入buildStreamTextParams @@ -88,6 +90,16 @@ export async function buildStreamTextParams( enableGenerateImage }) + // NOTE: ai-sdk会把maxToken和budgetToken加起来 + if ( + enableReasoning && + maxTokens !== undefined && + isSupportedThinkingTokenClaudeModel(model) && + (provider.type === 'anthropic' || provider.type === 'aws-bedrock') + ) { + maxTokens -= getAnthropicThinkingBudget(assistant, model) + } + // 构建基础参数 const params: StreamTextParams = { messages: sdkMessages, diff --git a/src/renderer/src/aiCore/utils/reasoning.ts b/src/renderer/src/aiCore/utils/reasoning.ts index 507b2cd9ce..385d8183c5 100644 --- a/src/renderer/src/aiCore/utils/reasoning.ts +++ b/src/renderer/src/aiCore/utils/reasoning.ts @@ -310,6 +310,26 @@ export function getOpenAIReasoningParams(assistant: Assistant, model: Model): Re return {} } +export function getAnthropicThinkingBudget(assistant: Assistant, model: Model): number { + const { maxTokens, reasoning_effort: reasoningEffort } = getAssistantSettings(assistant) + if (maxTokens === undefined || reasoningEffort === undefined) { + return 0 + } + const effortRatio = EFFORT_RATIO[reasoningEffort] + + const budgetTokens = Math.max( + 1024, + Math.floor( + Math.min( + (findTokenLimit(model.id)?.max! - findTokenLimit(model.id)?.min!) * effortRatio + + findTokenLimit(model.id)?.min!, + (maxTokens || DEFAULT_MAX_TOKENS) * effortRatio + ) + ) + ) + return budgetTokens +} + /** * 获取 Anthropic 推理参数 * 从 AnthropicAPIClient 中提取的逻辑 @@ -331,19 +351,7 @@ export function getAnthropicReasoningParams(assistant: Assistant, model: Model): // Claude 推理参数 if (isSupportedThinkingTokenClaudeModel(model)) { - const { maxTokens } = getAssistantSettings(assistant) - const effortRatio = EFFORT_RATIO[reasoningEffort] - - const budgetTokens = Math.max( - 1024, - Math.floor( - Math.min( - (findTokenLimit(model.id)?.max! - findTokenLimit(model.id)?.min!) * effortRatio + - findTokenLimit(model.id)?.min!, - (maxTokens || DEFAULT_MAX_TOKENS) * effortRatio - ) - ) - ) + const budgetTokens = getAnthropicThinkingBudget(assistant, model) return { thinking: {