File size: 6,119 Bytes
cda8be4 c801c74 cda8be4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
// 统一参数处理模块
// 将 OpenAI、Claude、Gemini 三种格式的参数统一转换为内部格式
import config from '../config/config.js';
import { REASONING_EFFORT_MAP } from '../constants/index.js';
/**
* 内部统一参数格式
* @typedef {Object} NormalizedParameters
* @property {number} max_tokens - 最大输出 token 数
* @property {number} temperature - 温度
* @property {number} top_p - Top-P 采样
* @property {number} top_k - Top-K 采样
* @property {number|undefined} thinking_budget - 思考预算(undefined 表示使用默认值)
*/
/**
* 从 OpenAI 格式提取参数
* OpenAI 格式参数:
* - max_tokens: number
* - temperature: number
* - top_p: number
* - top_k: number (非标准,但支持)
* - thinking_budget: number (扩展)
* - reasoning_effort: 'low' | 'medium' | 'high' (扩展)
*
* @param {Object} params - OpenAI 格式的参数对象
* @returns {NormalizedParameters}
*/
export function normalizeOpenAIParameters(params = {}) {
const normalized = {
max_tokens: params.max_tokens ?? config.defaults.max_tokens,
temperature: params.temperature ?? config.defaults.temperature,
top_p: params.top_p ?? config.defaults.top_p,
top_k: params.top_k ?? config.defaults.top_k,
};
// 处理思考预算
if (params.thinking_budget !== undefined) {
normalized.thinking_budget = params.thinking_budget;
} else if (params.reasoning_effort !== undefined) {
normalized.thinking_budget = REASONING_EFFORT_MAP[params.reasoning_effort];
}
return normalized;
}
/**
* 从 Claude 格式提取参数
* Claude 格式参数:
* - max_tokens: number
* - temperature: number
* - top_p: number
* - top_k: number
* - thinking: { type: 'enabled' | 'disabled', budget_tokens?: number }
*
* @param {Object} params - Claude 格式的参数对象
* @returns {NormalizedParameters}
*/
export function normalizeClaudeParameters(params = {}) {
const { max_tokens, temperature, top_p, top_k, thinking, ...rest } = params;
const normalized = {
max_tokens: max_tokens ?? config.defaults.max_tokens,
temperature: temperature ?? config.defaults.temperature,
top_p: top_p ?? config.defaults.top_p,
top_k: top_k ?? config.defaults.top_k,
};
// 处理 Claude 的 thinking 参数
// 格式: { "type": "enabled", "budget_tokens": 10000 } 或 { "type": "disabled" }
if (thinking && typeof thinking === 'object') {
if (thinking.type === 'enabled' && thinking.budget_tokens !== undefined) {
normalized.thinking_budget = thinking.budget_tokens;
} else if (thinking.type === 'disabled') {
// 显式禁用思考
normalized.thinking_budget = 0;
}
}
// 保留其他参数
Object.assign(normalized, rest);
return normalized;
}
/**
* 从 Gemini 格式提取参数
* Gemini 格式参数(在 generationConfig 中):
* - temperature: number
* - topP: number
* - topK: number
* - maxOutputTokens: number
* - thinkingConfig: { includeThoughts: boolean, thinkingBudget?: number }
*
* @param {Object} generationConfig - Gemini 格式的 generationConfig 对象
* @returns {NormalizedParameters}
*/
export function normalizeGeminiParameters(generationConfig = {}) {
const normalized = {
max_tokens: generationConfig.maxOutputTokens ?? config.defaults.max_tokens,
temperature: generationConfig.temperature ?? config.defaults.temperature,
top_p: generationConfig.topP ?? config.defaults.top_p,
top_k: generationConfig.topK ?? config.defaults.top_k,
};
// 处理 Gemini 的 thinkingConfig 参数
if (generationConfig.thinkingConfig && typeof generationConfig.thinkingConfig === 'object') {
if (generationConfig.thinkingConfig.includeThoughts === false) {
// 显式禁用思考
normalized.thinking_budget = 0;
} else if (generationConfig.thinkingConfig.thinkingBudget !== undefined) {
normalized.thinking_budget = generationConfig.thinkingConfig.thinkingBudget;
}
}
return normalized;
}
/**
* 自动检测格式并规范化参数
* @param {Object} params - 原始参数对象
* @param {'openai' | 'claude' | 'gemini'} format - API 格式
* @returns {NormalizedParameters}
*/
export function normalizeParameters(params, format) {
switch (format) {
case 'openai':
return normalizeOpenAIParameters(params);
case 'claude':
return normalizeClaudeParameters(params);
case 'gemini':
return normalizeGeminiParameters(params);
default:
return normalizeOpenAIParameters(params);
}
}
/**
* 将规范化参数转换为 Gemini generationConfig 格式
* @param {NormalizedParameters} normalized - 规范化后的参数
* @param {boolean} enableThinking - 是否启用思考
* @param {string} actualModelName - 实际模型名称
* @returns {Object} Gemini generationConfig 格式
*/
export function toGenerationConfig(normalized, enableThinking, actualModelName) {
const defaultThinkingBudget = config.defaults.thinking_budget ?? 1024;
let thinkingBudget = 0;
let actualEnableThinking = enableThinking;
if (enableThinking) {
if (normalized.thinking_budget !== undefined) {
thinkingBudget = normalized.thinking_budget;
// 如果用户显式设置 thinking_budget = 0,则禁用思考
if (thinkingBudget === 0) {
actualEnableThinking = false;
}
} else {
thinkingBudget = defaultThinkingBudget;
}
}
const generationConfig = {
topP: normalized.top_p,
topK: normalized.top_k,
temperature: normalized.temperature,
candidateCount: 1,
maxOutputTokens: normalized.max_tokens || normalized.max_completion_tokens,
thinkingConfig: {
includeThoughts: actualEnableThinking,
thinkingBudget: thinkingBudget
}
};
// Claude 模型在启用思考时不支持 topP
if (actualEnableThinking && actualModelName && actualModelName.includes('claude')) {
delete generationConfig.topP;
}
return generationConfig;
}
export default {
normalizeOpenAIParameters,
normalizeClaudeParameters,
normalizeGeminiParameters,
normalizeParameters,
toGenerationConfig
}; |