59 lines
1.5 KiB
Go
59 lines
1.5 KiB
Go
|
|
package modeladapter
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"regexp"
|
|||
|
|
"strconv"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
func maxAnthropicTokens(req StreamRequest) int {
|
|||
|
|
if req.AnthropicMaxTokens > 0 {
|
|||
|
|
return req.AnthropicMaxTokens
|
|||
|
|
}
|
|||
|
|
if req.MaxTokens > 0 {
|
|||
|
|
return req.MaxTokens
|
|||
|
|
}
|
|||
|
|
return 65536
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// anthropicOutputLimitPattern 匹配 one-api/new-api 风格网关在 max_tokens 超限时的 400 错误:
|
|||
|
|
// "Requested token count exceeds the configured maximum output length of 131072 tokens."
|
|||
|
|
var anthropicOutputLimitPattern = regexp.MustCompile(`exceeds the configured maximum output length of (\d+) tokens`)
|
|||
|
|
|
|||
|
|
// anthropicOutputLimitFromError 从网关错误文本中提取其声明的最大输出上限;不匹配或解析失败返回 0。
|
|||
|
|
func anthropicOutputLimitFromError(err error) int {
|
|||
|
|
if err == nil {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
matches := anthropicOutputLimitPattern.FindStringSubmatch(err.Error())
|
|||
|
|
if len(matches) < 2 {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
limit, parseErr := strconv.Atoi(matches[1])
|
|||
|
|
if parseErr != nil || limit <= 0 {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
return limit
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// anthropicBodyMaxTokens 读取既有请求体中实际发送的 max_tokens;
|
|||
|
|
// 常规构造为 int,RequestBodyOverride 反序列化产物为 float64,两者都兼容。
|
|||
|
|
func anthropicBodyMaxTokens(body map[string]any) int {
|
|||
|
|
switch value := body["max_tokens"].(type) {
|
|||
|
|
case int:
|
|||
|
|
return value
|
|||
|
|
case int64:
|
|||
|
|
return int(value)
|
|||
|
|
case float64:
|
|||
|
|
return int(value)
|
|||
|
|
default:
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func maxThinkingBudget(req StreamRequest) int {
|
|||
|
|
if req.ThinkingBudgetTokens > 0 {
|
|||
|
|
return req.ThinkingBudgetTokens
|
|||
|
|
}
|
|||
|
|
return anthropicThinkingBudget(maxAnthropicTokens(req))
|
|||
|
|
}
|