一、Pydantic 是什么?
Pydantic 是一个 Python 数据验证库 ,核心作用是 校验数据类型、结构和约束,同时自动完成数据解析与转换,常用来处理 API 请求参数、配置文件、模型输入输出等场景。
简单说:它能帮你 "把关" 数据 ------ 比如确保传入 vLLM 的推理请求中,prompt 是字符串、max_tokens 是正整数,避免无效数据导致服务报错,让代码更健壮、更易维护。
二、BaseModel 是什么?
BaseModel 是 Pydantic 库中 最核心的类 ,你可以把它理解为一个 数据模型模板,通过继承 BaseModel,就能快速定义一个带校验功能的数据结构。
核心作用(结合你的 Tornado+vLLM 场景):
- 定义数据结构:比如定义 vLLM 推理请求的参数模板(prompt、max_tokens、temperature 等);
- 自动数据校验:传入参数不符合定义时,会自动抛出清晰的错误提示,不用手动写校验逻辑;
- 自动类型转换:比如传入字符串格式的 "100",会自动转换成整数 100,适配模型需求;
- 便捷序列化 / 反序列化:轻松将数据转换成字典、JSON,适配 Tornado API 的请求 / 响应处理。
最简示例(适配 vLLM 场景):
python
from pydantic import BaseModel
# 定义 vLLM 推理请求的参数模型(继承 BaseModel)
class VllmInferenceRequest(BaseModel):
prompt: str # 必须是字符串,必填
max_tokens: int = 1024 # 必须是整数,默认值1024
temperature: float = 0.7 # 必须是浮点数,默认值0.7
top_p: float = 0.9 # 可选参数,默认0.9
# 使用模型校验数据
request_data = {"prompt": "什么是 vLLM?", "max_tokens": "2048"} # max_tokens 是字符串
request = VllmInferenceRequest(**request_data) # 自动将 "2048" 转为整数2048
# 错误示例(自动校验报错)
error_data = {"prompt": 123, "max_tokens": -100} # prompt是整数、max_tokens是负数
request = VllmInferenceRequest(**error_data) # 直接抛出错误,提示参数不符合要求
三、 Pydantic BaseModel 在API服务中的应用
你用 Tornado 启动 API 服务时,可通过 Pydantic BaseModel 定义 请求参数模板,避免无效请求(比如传入非字符串 prompt、负数 max_tokens)导致 vLLM 服务崩溃,同时让 API 接口更规范、更易维护。
四、代码示例
4.1 适配 vLLM(Qwen3-8B)+ Tornado 接口的 Pydantic 模型示例
核心适配 Qwen3-8B 模型、vLLM 推理服务,无缝集成到 Tornado 接口中,包含 请求参数校验、响应格式化、异常处理,贴合技术栈(vLLM + Tornado + Qwen3-8B),无需修改可直接运行。
这里定义了两个参数校验模型,一个是输入参数校验模型 VllmInferenceRequest(BaseModel),一个是输出参数校验模型VllmInferenceResponse(BaseModel)
python
# 1. 导入依赖(必导,缺一不可)
from pydantic import BaseModel, Field, validator
from typing import Optional, List
import tornado.web
import tornado.ioloop
from vllm import AsyncEngineArgs, AsyncLLMEngine
from vllm.entrypoints.openai import OpenAICompatible
import json
# 2. 定义 Pydantic 模型(适配 Qwen3-8B + vLLM 推理请求/响应)
# 核心:校验 Tornado 接口接收的请求参数,避免无效请求导致 vLLM 崩溃
class VllmInferenceRequest(BaseModel):
"请求参数模型"
requestId: str
logId: str
messages: Optional[list[dict]] = []
prompt: str = Field(..., description="推理提示词(必传),对应 Qwen3-8B 的输入")
max_tokens: int = Field(
default=1024,
ge=128, # 最小生成 tokens 数,避免过少导致推理不完整
le=4096, # 最大生成 tokens 数(适配 Qwen3-8B 模型上限)
description="生成响应的最大 tokens 数"
)
temperature: float = Field(
default=0.7,
ge=0.0,
le=1.0,
description="推理温度,0.0 更严谨,1.0 更随机,适配 Qwen 模型特性"
)
top_p: float = Field(
default=0.9,
ge=0.0,
le=1.0,
description="采样阈值,控制生成内容的多样性"
)
stream: bool = Field(
default=False,
description="是否开启流式响应(适配 Tornado 异步接口)"
)
# 自定义校验:确保 prompt 不为空(避免空请求传入 vLLM)
@validator('prompt')
def prompt_not_empty(cls, v):
if not v.strip():
raise ValueError("推理提示词(prompt)不能为空")
return v
# 自定义处理方法
def converMessages(self):
res = ""
if self.messages !=None:
res = ",".join(self.messages)
return res
class VllmInferenceResponse(BaseModel):
"""vLLM 推理响应模型(适配 Tornado 接口返回格式)"""
code: int = Field(default=200, description="响应状态码")
msg: str = Field(default="success", description="响应信息")
data: Optional[dict] = Field(
default=None,
description="推理结果:包含生成文本、消耗 tokens 数"
)
error: Optional[str] = Field(default=None, description="错误信息(无错误则为 None)")
# 3. Tornado 接口定义(集成 Pydantic 校验 + vLLM 推理)
class VllmInferenceHandler(tornado.web.RequestHandler):
"""Tornado 接口处理器,接收请求、校验参数、调用 vLLM 推理"""
def initialize(self, vllm_engine: AsyncLLMEngine):
self.vllm_engine = vllm_engine # 注入 vLLM 异步引擎
# 处理 POST 请求(前端/客户端调用的核心接口)
async def post(self):
try:
# 1. 解析请求体,用 Pydantic 校验参数
request_body = json.loads(self.request.body)
inference_request = VllmInferenceRequest(**request_body)
# 2. 调用 vLLM 异步推理(适配 Qwen3-8B 模型)
result = await self.vllm_engine.generate(
prompt=inference_request.prompt,
max_tokens=inference_request.max_tokens,
temperature=inference_request.temperature,
top_p=inference_request.top_p,
stream=inference_request.stream
)
# 3. 格式化响应(适配 Tornado 接口返回格式)
response = VllmInferenceResponse(
data={
"generated_text": result.outputs[0].text,
"used_tokens": result.usage.total_tokens
}
)
self.write(response.model_dump_json())
self.set_header("Content-Type", "application/json")
except Exception as e:
# 异常处理:避免单个请求报错导致整个 Tornado 服务崩溃
error_response = VllmInferenceResponse(
code=500,
msg="推理失败",
error=str(e)
)
self.write(error_response.model_dump_json())
self.set_status(500)
# 4. 初始化 vLLM 引擎 + Tornado 服务(可直接运行)
def start_tornado_vllm_service():
# 初始化 vLLM 异步引擎(适配 Qwen3-8B)
vllm_args = AsyncEngineArgs(
model_path="/path/to/qwen3-8b", # 替换为你的 Qwen3-8B 模型路径
tensor_parallel_size=1, # 单卡/多卡可调整,此处适配单卡基础配置
gpu_memory_utilization=0.9 # 对应 A10/A100 显存配置
)
vllm_engine = AsyncLLMEngine.from_engine_args(vllm_args)
# 启动 Tornado 应用
app = tornado.web.Application([
# 定义 Tornado 接口路径,对应 vLLM 推理请求
(r"/vllm/inference", VllmInferenceHandler, {"vllm_engine": vllm_engine})
])
# 绑定端口(和你之前的 vLLM 服务端口一致,避免冲突)
app.listen(9000) # 替换为你的目标端口
tornado.ioloop.IOLoop.current().start()
if __name__ == "__main__":
# 启动服务(可结合 numactl 绑定 CPU,优化性能)
start_tornado_vllm_service()