为AI模型提供HTTP接口并不是简单地把推理函数暴露出去。Django REST Framework本身提供了一套完整的请求处理链路,其中Serializer负责把不可信的外部输入转换成模型可接受的结构化数据,ViewSet则通过权限与限流机制控制谁能访问以及访问频率。把这两块做扎实,AI API才能在真实流量中稳定运行。

一、为什么AI接口必须把Serializer验证放在首位
模型推理和传统Web接口有个明显区别:推理服务对输入格式极度敏感,且单次计算成本高。一个字段类型错误、一段超长文本、一个缺失的必填参数,轻则让模型返回无意义结果,重则直接触发推理进程异常退出。如果把这些校验逻辑散落在视图函数里,多个接口会重复造轮子,代码很快失控。DRF的Serializer把输入验证集中到声明式字段定义中,所有请求在进入视图逻辑之前就完成类型转换与合法性检查,这就把不可信的外部JSON变成了可信的Python字典。
Serializer字段定义本身就是一份请求契约。CharField可以限制最大长度,IntegerField和FloatField能约束数值范围,BooleanField和ChoiceField明确可选值,required和default则处理缺失参数。除了字段级校验,还可以重写validate开头的方法做跨字段检查,例如当stream为True时限制max_tokens不能超过某个阈值。如果请求里混入了模型不需要的字段,也可以在Meta中配置忽略或拒绝未知字段,避免多余数据进入后续业务逻辑。
from rest_framework import serializers
class InferenceRequestSerializer(serializers.Serializer):
prompt = serializers.CharField(max_length=2048, allow_blank=False)
max_tokens = serializers.IntegerField(min_value=1, max_value=1024, default=128)
temperature = serializers.FloatField(min_value=0.0, max_value=1.5, default=0.7)
stream = serializers.BooleanField(default=False)
def validate_prompt(self, value):
if len(value.strip()) < 2:
raise serializers.ValidationError("prompt内容过短")
return value.strip()
经过Serializer校验后的validated_data可以直接传给推理函数,模型侧就不再需要防御式判断参数类型。这样做还带来一个额外好处:错误响应统一由DRF生成,字段错误会返回结构化JSON,调用方可以准确知道哪个参数有问题,而不是面对笼统的500错误。对于AI API来说,输入不合法应当返回400而不是500,这也是生产环境可观测性的基本要求。
二、用ViewSet权限守住模型调用边界
AI推理接口通常比普通查询接口贵得多,尤其是GPU推理场景,每一次调用都消耗显存、电力和时间。如果没有权限控制,接口一旦暴露到公网,可能很快被脚本扫到并滥用,造成成本飙升。DRF的ViewSet提供了permission_classes属性,可以在请求进入action之前执行认证和授权逻辑。DRF还允许自定义权限类,实现比IsAuthenticated更细粒度的访问控制。
from rest_framework import permissions
from django.conf import settings
class APIKeyPermission(permissions.BasePermission):
def has_permission(self, request, view):
api_key = request.headers.get("X-API-Key")
return api_key == settings.AI_API_KEY
权限解决的是能不能调,限流解决的是能调多快。可以为推理接口单独配置UserRateThrottle或AnonRateThrottle,比如限制匿名请求每分钟5次,登录用户每分钟20次。DRF的throttle_classes属性配合settings里的DEFAULT_THROTTLE_RATES即可生效。对AI服务而言,限流不只是防滥用,还能保护模型推理队列不被瞬时流量打爆。自定义Throttle类可以基于API Key或IP做更精准的流控。
from rest_framework.throttling import UserRateThrottle
class InferenceRateThrottle(UserRateThrottle):
rate = "10/minute"
三、整合Serializer与ViewSet:一个可落地的AI API视图
将前面两个组件放进同一个ViewSet后,一个完整的AI推理接口就成型了。ViewSet继承GenericViewSet,指定serializer_class、permission_classes和throttle_classes,然后提供一个POST action接收数据。action内部先调用get_serializer读取request.data,执行is_valid(raise_exception=True),验证通过后取出validated_data传给推理函数。因为验证异常已经在Serializer层被捕获,推理函数可以保持纯粹,只处理合法的结构化输入。
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.decorators import action
class InferenceViewSet(viewsets.GenericViewSet):
serializer_class = InferenceRequestSerializer
permission_classes = [APIKeyPermission]
throttle_classes = [InferenceRateThrottle]
@action(detail=False, methods=["post"])
def predict(self, request):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
result = run_model_inference(serializer.validated_data)
return Response(result, status=status.HTTP_200_OK)
这个结构把输入验证、访问控制、业务推理三个层次分得很清楚。后续如果要增加新的推理任务,只需要再写一个Serializer和对应action,不用改权限和限流配置。如果要支持异步推理,可以在action里把请求数据丢给Celery任务队列,立即返回任务ID,Serializer仍然负责入口参数校验,权限和限流逻辑也完全复用。这样的分层在AI服务逐渐变多时能显著降低维护成本。
实际部署时还需要注意两点:一是不要在生产环境开启DEBUG,否则验证错误可能暴露模型内部参数;二是对于超长文本或批量请求,可以在Serializer里设置更严格的max_length和批量大小上限,把资源消耗控制在可接受范围。把Serializer验证和ViewSet权限当成AI API的第一道防线,后面的模型推理链路才会更稳定、更可控。
四、常见误区与调优建议
一个常见误区是把大量业务逻辑塞进Serializer的validate方法,导致序列化器臃肿。Serializer应该只负责契约校验,模型推理准备和业务判断应该放在服务层或action里。另一个误区是忘记给不同接口设置独立的限流桶,导致多个AI接口共用同一个频率限制,互相影响。DRF支持throttle_scope,可以对每个action单独指定限流规则。
调优方面,建议利用DRF的context传递请求信息,当Serializer需要根据当前用户做校验时,不要直接访问全局状态,而是通过self.context["request"]获取。此外,AI推理通常没有直接对应的数据库模型,继承GenericViewSet比ModelViewSet更合适,避免生成无用的CRUD路由。对于异常响应,可以通过自定义exception_handler统一记录请求体、用户标识和模型任务ID,方便后续定位问题。
还要注意不要把所有异常都吞掉。Serializer验证错误应该直接交给DRF返回400,但推理函数内部的模型加载失败、显存不足等情况应当捕获后返回503或500,并输出结构化错误信息。这样调用方可以区分请求本身有问题还是服务端资源不可用,减少无效重试。
Django REST FrameworkSerializer验证ViewSet权限修改时间:2026-10-05 07:49:54