feat: 接入模型动态 Fallback 与调用审计
This commit is contained in:
@@ -3,7 +3,8 @@ from decimal import Decimal
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.accounts.models import Team, TeamMember, User
|
||||
from apps.ai.models import AITask, ModelConfig, ModelProvider, PromptTemplate, QualityWord
|
||||
from apps.ai.model_routing import model_metadata_errors, provider_metadata_errors
|
||||
from apps.ai.models import AIModelAttempt, AITask, ModelConfig, ModelProvider, PromptTemplate, QualityWord
|
||||
from apps.assets.models import Asset
|
||||
from apps.billing.models import CreditLedger, QuotaPolicy
|
||||
from apps.projects.models import Project
|
||||
@@ -162,11 +163,26 @@ class AdminTaskSerializer(serializers.ModelSerializer):
|
||||
return str((actual / rate - base).quantize(Decimal("0.01")))
|
||||
|
||||
|
||||
class AdminModelAttemptSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = AIModelAttempt
|
||||
fields = [
|
||||
"id", "sequence", "provider_name", "provider_display_name", "model_name", "model_display_name",
|
||||
"public_model_name", "capability", "operation", "status", "is_retry", "is_fallback",
|
||||
"previous_attempt", "provider_task_id", "started_at", "finished_at", "duration_ms", "error_type",
|
||||
"provider_error_code", "raw_error", "safe_error_summary", "usage", "platform_cost", "request_summary",
|
||||
"response_summary",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
class AdminTaskDetailSerializer(AdminTaskSerializer):
|
||||
attempts = AdminModelAttemptSerializer(source="model_attempts", many=True, read_only=True)
|
||||
|
||||
class Meta(AdminTaskSerializer.Meta):
|
||||
fields = AdminTaskSerializer.Meta.fields + [
|
||||
"project", "idempotency_key", "request_payload", "response_payload",
|
||||
"error_message", "submitted_at", "completed_at",
|
||||
"error_message", "submitted_at", "completed_at", "attempts",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
@@ -211,6 +227,12 @@ class AdminModelProviderSerializer(serializers.ModelSerializer):
|
||||
anno = getattr(obj, "model_count_anno", None)
|
||||
return anno if anno is not None else obj.models.count()
|
||||
|
||||
def validate_metadata(self, value):
|
||||
errors = provider_metadata_errors(value)
|
||||
if errors:
|
||||
raise serializers.ValidationError(list(errors))
|
||||
return value
|
||||
|
||||
|
||||
class AdminModelConfigSerializer(serializers.ModelSerializer):
|
||||
provider_name = serializers.CharField(source="provider.name", read_only=True, default=None)
|
||||
@@ -224,6 +246,16 @@ class AdminModelConfigSerializer(serializers.ModelSerializer):
|
||||
# is_default 只经 set-default 端点改,不在普通编辑里直接写
|
||||
read_only_fields = ["id", "provider_name", "is_default", "created_at"]
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs = super().validate(attrs)
|
||||
if self.instance is None or "metadata" in attrs or "capability" in attrs:
|
||||
capability = attrs.get("capability", getattr(self.instance, "capability", ""))
|
||||
metadata = attrs.get("metadata", getattr(self.instance, "metadata", {}))
|
||||
errors = model_metadata_errors(capability, metadata)
|
||||
if errors:
|
||||
raise serializers.ValidationError({"metadata": list(errors)})
|
||||
return attrs
|
||||
|
||||
|
||||
class AdminProjectSerializer(serializers.ModelSerializer):
|
||||
team_name = serializers.CharField(source="team.name", read_only=True, default=None)
|
||||
|
||||
Reference in New Issue
Block a user