feat: 完善模型请求适配与输出限制

This commit is contained in:
2026-07-17 13:52:00 +08:00
parent a24eb1aeb0
commit 5ee267ecbd
31 changed files with 3287 additions and 232 deletions
@@ -3,6 +3,8 @@ package store
import (
"context"
"encoding/json"
"fmt"
"math"
"strings"
"github.com/jackc/pgx/v5"
@@ -116,6 +118,9 @@ func (s *Store) createPlatformModel(ctx context.Context, q platformModelQuerier,
if len(capabilities) == 0 {
capabilities = EffectivePlatformModelCapabilities(base.Capabilities, input.CapabilityOverride)
}
if err := validateEnabledVolcesTextModelCapabilities(ctx, q, input, capabilities); err != nil {
return PlatformModel{}, err
}
billingConfig := input.BillingConfig
if len(billingConfig) == 0 {
billingConfig = mergeObjects(base.BaseBillingConfig, input.BillingConfigOverride)
@@ -262,6 +267,76 @@ RETURNING id::text, platform_id::text, COALESCE(base_model_id::text, ''), model_
return model, nil
}
func validateEnabledVolcesTextModelCapabilities(ctx context.Context, q platformModelQuerier, input CreatePlatformModelInput, capabilities map[string]any) error {
// createPlatformModel enables/upserts models unconditionally, so every text
// model that reaches this path must already satisfy the Volcengine invariant.
if !containsTextOutputModelType(input.ModelType) {
return nil
}
var provider string
var baseURL string
if err := q.QueryRow(ctx, `SELECT provider, COALESCE(base_url, '') FROM integration_platforms WHERE id = $1::uuid`, input.PlatformID).Scan(&provider, &baseURL); err != nil {
return err
}
provider = strings.ToLower(strings.TrimSpace(provider))
baseURL = strings.ToLower(strings.TrimSpace(baseURL))
if provider != "volces-openai" && !strings.Contains(baseURL, "volces.com") && !strings.Contains(baseURL, "byteplus.com") {
return nil
}
seen := map[string]struct{}{}
for _, modelType := range append(append(StringList{}, input.ModelType...), "text_generate") {
modelType = strings.TrimSpace(modelType)
if modelType == "" {
continue
}
if _, ok := seen[modelType]; ok {
continue
}
seen[modelType] = struct{}{}
capability, _ := capabilities[modelType].(map[string]any)
if value, ok := positiveWholeNumber(capability["max_output_tokens"]); ok && value > 0 {
return nil
}
}
return fmt.Errorf("%w: enabled Volcengine text model %q requires a positive integer max_output_tokens capability for its text model type or text_generate fallback", ErrInvalidPlatformModelConfiguration, input.ProviderModelName)
}
func containsTextOutputModelType(values StringList) bool {
for _, value := range values {
switch strings.ToLower(strings.TrimSpace(value)) {
case "text_generate", "chat", "responses", "text":
return true
}
}
return false
}
func positiveWholeNumber(value any) (int64, bool) {
var number float64
switch typed := value.(type) {
case int:
number = float64(typed)
case int32:
number = float64(typed)
case int64:
number = float64(typed)
case float64:
number = typed
case json.Number:
parsed, err := typed.Float64()
if err != nil {
return 0, false
}
number = parsed
default:
return 0, false
}
if number <= 0 || math.Trunc(number) != number || number > math.MaxInt64 {
return 0, false
}
return int64(number), true
}
func (s *Store) DeletePlatformModel(ctx context.Context, id string) error {
tx, err := s.pool.Begin(ctx)
if err != nil {
+3 -2
View File
@@ -7,8 +7,9 @@ import (
)
var (
ErrNoModelCandidate = errors.New("no enabled platform model matches request")
ErrRateLimited = errors.New("rate limit exceeded")
ErrNoModelCandidate = errors.New("no enabled platform model matches request")
ErrRateLimited = errors.New("rate limit exceeded")
ErrInvalidPlatformModelConfiguration = errors.New("invalid platform model configuration")
)
type ModelCandidateUnavailableError struct {