diff --git a/app/api/ai/claude/route.js b/app/api/ai/claude/route.js index d337f19..47d57aa 100644 --- a/app/api/ai/claude/route.js +++ b/app/api/ai/claude/route.js @@ -5,7 +5,7 @@ export const runtime = 'edge'; export async function POST(request) { try { - const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP } = await request.json(); + const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP, reasoningEffort } = await request.json(); const apiKey = apiConfig?.apiKey; const baseUrl = (apiConfig?.baseUrl || 'https://api.anthropic.com').replace(/\/$/, ''); @@ -23,7 +23,7 @@ export async function POST(request) { // 构造 Messages API 请求体 const requestBody = { model, - max_tokens: maxTokens || 4096, + max_tokens: maxTokens || 8192, system: systemPrompt, messages: [ { role: 'user', content: userPrompt } @@ -33,8 +33,16 @@ export async function POST(request) { ...(topP != null ? { top_p: topP } : {}), }; - // 如果模型支持 extended thinking (claude-3-7-sonnet),可以启用 - // 但默认不启用,因为需要额外的 budget 参数 + // 扩展思考 (extended thinking) — 当 reasoningEffort 不为 auto 时启用 + if (reasoningEffort && reasoningEffort !== 'auto') { + const budgetMap = { low: 2048, medium: 8192, high: 32768 }; + requestBody.thinking = { + type: 'enabled', + budget_tokens: budgetMap[reasoningEffort] || 8192, + }; + // 扩展思考不支持同时设 temperature + delete requestBody.temperature; + } const response = await fetch(url, { method: 'POST', diff --git a/app/api/ai/gemini/route.js b/app/api/ai/gemini/route.js index 7d9e07b..49ad649 100644 --- a/app/api/ai/gemini/route.js +++ b/app/api/ai/gemini/route.js @@ -5,7 +5,7 @@ export const runtime = 'edge'; export async function POST(request) { try { - const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP } = await request.json(); + const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP, reasoningEffort } = await request.json(); const apiKey = apiConfig?.apiKey || process.env.GEMINI_API_KEY; let rawBaseUrl = apiConfig?.baseUrl; @@ -36,9 +36,14 @@ export async function POST(request) { } ], generationConfig: { - temperature: temperature ?? 0.8, - topP: topP ?? 0.9, + ...(temperature != null ? { temperature } : {}), + ...(topP != null ? { topP } : {}), ...(maxTokens ? { maxOutputTokens: maxTokens } : {}), + ...(reasoningEffort && reasoningEffort !== 'auto' ? { + thinkingConfig: { + thinkingBudget: { low: 1024, medium: 8192, high: 32768 }[reasoningEffort] || 8192, + }, + } : {}), }, }; diff --git a/app/api/ai/responses/route.js b/app/api/ai/responses/route.js index 416b865..8b9c3da 100644 --- a/app/api/ai/responses/route.js +++ b/app/api/ai/responses/route.js @@ -32,8 +32,9 @@ export async function POST(request) { ...(topP != null ? { top_p: topP } : {}), }; - // 添加思考等级(默认 medium) - const effort = apiConfig?.reasoningEffort || 'medium'; + // 添加思考等级(默认 medium,不受高级参数面板影响) + const rawEffort = apiConfig?.reasoningEffort; + const effort = (!rawEffort || rawEffort === 'auto') ? 'medium' : rawEffort; if (['low', 'medium', 'high', 'xhigh'].includes(effort)) { requestBody.reasoning = { effort, summary: 'auto' }; } diff --git a/app/api/ai/route.js b/app/api/ai/route.js index 411c80d..4d60c69 100644 --- a/app/api/ai/route.js +++ b/app/api/ai/route.js @@ -5,7 +5,7 @@ export const runtime = 'edge'; export async function POST(request) { try { - const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP } = await request.json(); + const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP, reasoningEffort } = await request.json(); const apiKey = apiConfig?.apiKey || process.env.ZHIPU_API_KEY; const baseUrl = apiConfig?.baseUrl || 'https://open.bigmodel.cn/api/paas/v4'; @@ -33,9 +33,10 @@ export async function POST(request) { { role: 'system', content: systemPrompt }, { role: 'user', content: userPrompt } ], - temperature: temperature ?? 0.8, + ...(temperature != null ? { temperature } : {}), ...(topP != null ? { top_p: topP } : {}), ...(maxTokens ? { max_tokens: maxTokens } : {}), + ...(reasoningEffort && reasoningEffort !== 'auto' ? { reasoning_effort: reasoningEffort } : {}), stream: true, }), }); diff --git a/app/components/AiSidebar.js b/app/components/AiSidebar.js index a9492bc..7b58994 100644 --- a/app/components/AiSidebar.js +++ b/app/components/AiSidebar.js @@ -214,7 +214,8 @@ export default function AiSidebar({ onInsertText }) { maxTokens: apiConfig.maxOutputTokens || 65536, temperature: apiConfig.temperature ?? 1, topP: apiConfig.topP ?? 0.95, - } : { maxTokens: 4096 }), + reasoningEffort: apiConfig.reasoningEffort || 'auto', + } : {}), }), }); diff --git a/app/components/SettingsConflictModal.js b/app/components/SettingsConflictModal.js index fb6ed47..adc7bcb 100644 --- a/app/components/SettingsConflictModal.js +++ b/app/components/SettingsConflictModal.js @@ -139,7 +139,8 @@ ${importedFields} maxTokens: apiConfig.maxOutputTokens || 65536, temperature: apiConfig.temperature ?? 1, topP: apiConfig.topP ?? 0.95, - } : { maxTokens: 4096 }), + reasoningEffort: apiConfig.reasoningEffort || 'auto', + } : {}), }), }); diff --git a/app/components/SettingsPanel.js b/app/components/SettingsPanel.js index 8439df1..f812549 100644 --- a/app/components/SettingsPanel.js +++ b/app/components/SettingsPanel.js @@ -1135,20 +1135,43 @@ function ApiConfigForm({ data, onChange }) {
{t('apiConfig.maxContextLengthDesc')}
- {/* 最大输出 Token */} -
- - update('maxOutputTokens', parseInt(e.target.value) || 4096)} - /> -
{t('apiConfig.maxOutputTokensDesc')}
-
+ {/* 最大输出 Token — Responses API 不适用 */} + {data.provider !== 'openai-responses' && ( +
+ + update('maxOutputTokens', parseInt(e.target.value) || 4096)} + /> +
{t('apiConfig.maxOutputTokensDesc')}
+
+ )} + + {/* 思考层级 — Responses API 有自己的内置思考层级 */} + {data.provider !== 'openai-responses' && ( +
+ + +
{t('apiConfig.reasoningEffortDesc')}
+
+ )} )} diff --git a/app/lib/settings.js b/app/lib/settings.js index 4834844..00aff4b 100644 --- a/app/lib/settings.js +++ b/app/lib/settings.js @@ -123,6 +123,7 @@ const DEFAULT_SETTINGS = { topP: 0.95, // 0 ~ 1 maxContextLength: 200000, // 最大上下文 token maxOutputTokens: 65536, // 最大输出 token + reasoningEffort: 'auto', // 思考层级: auto / low / medium / high }, // 作品基本信息 diff --git a/app/locales/en.json b/app/locales/en.json index fabab3e..961daf2 100644 --- a/app/locales/en.json +++ b/app/locales/en.json @@ -465,7 +465,10 @@ "maxContextLength": "Max Context Length", "maxContextLengthDesc": "Maximum context tokens sent to the model", "maxOutputTokens": "Max Output Tokens", - "maxOutputTokensDesc": "Maximum tokens per model response" + "maxOutputTokensDesc": "Maximum tokens per model response", + "reasoningEffort": "Reasoning Effort", + "reasoningAuto": "Auto (no override)", + "reasoningEffortDesc": "Controls reasoning depth, only affects models that support reasoning" }, "preferences": { "intro": "You can change your language and visual theme preferences here at any time. All changes take effect immediately and are saved locally.", diff --git a/app/locales/ru.json b/app/locales/ru.json index 814a198..72ad163 100644 --- a/app/locales/ru.json +++ b/app/locales/ru.json @@ -465,7 +465,10 @@ "maxContextLength": "Макс. длина контекста", "maxContextLengthDesc": "Максимальное количество токенов контекста, отправляемых модели", "maxOutputTokens": "Макс. токенов вывода", - "maxOutputTokensDesc": "Максимальное количество токенов в одном ответе модели" + "maxOutputTokensDesc": "Максимальное количество токенов в одном ответе модели", + "reasoningEffort": "Уровень рассуждения", + "reasoningAuto": "Авто (без вмешательства)", + "reasoningEffortDesc": "Управляет глубиной рассуждения, работает только с моделями, поддерживающими рассуждение" }, "preferences": { "intro": "Здесь вы можете в любое время изменить язык и визуальную тему. Все изменения вступают в силу немедленно и сохраняются локально.", diff --git a/app/locales/zh.json b/app/locales/zh.json index 48162b6..134a49e 100644 --- a/app/locales/zh.json +++ b/app/locales/zh.json @@ -465,7 +465,10 @@ "maxContextLength": "最大上下文长度", "maxContextLengthDesc": "发送给模型的最大上下文 token 数", "maxOutputTokens": "最大输出 Token", - "maxOutputTokensDesc": "模型单次回复的最大 token 数" + "maxOutputTokensDesc": "模型单次回复的最大 token 数", + "reasoningEffort": "思考层级", + "reasoningAuto": "自动(不干预)", + "reasoningEffortDesc": "控制模型的推理深度,仅对支持推理的模型生效" }, "preferences": { "intro": "在这里可以随时更改应用程序的语言和视觉主题偏好。所有的更改都会实时生效并保存在本地。", diff --git a/app/page.js b/app/page.js index 0fd5419..1300740 100644 --- a/app/page.js +++ b/app/page.js @@ -237,7 +237,8 @@ export default function Home() { maxTokens: apiConfig.maxOutputTokens || 65536, temperature: apiConfig.temperature ?? 1, topP: apiConfig.topP ?? 0.95, - } : { maxTokens: 4096 }), + reasoningEffort: apiConfig.reasoningEffort || 'auto', + } : {}), }), signal, });