4. Flask REST API 服务搭建

将训练好的 XGBoost 模型封装为可对外提供实时预测的 REST API,是模型上线的关键一步。Flask 作为轻量级 Python Web 框架,非常适合快速搭建评分服务。本节将系统讲解 Flask 基础、模型加载、预测接口设计以及请求/响应格式规范。

核心目标:构建一个稳定、可复用的 XGBoost 评分服务端点,接收特征数据并返回预测结果。
Flask XGBoost 评分服务架构图 Flask XGBoost 评分服务架构 客户端 POST /predict Flask 路由 @app.route 模型引擎 XGBoost Booster 特征预处理 predict() JSON 响应 HTTP 200 / 400 / 500 关键设计 全局加载模型 避免重复加载 异常捕获

4.1 Flask 框架基础

Flask 是一个基于 Werkzeug 和 Jinja2 的微框架,核心概念包括路由、视图函数和请求/响应对象。在评分服务中,我们主要使用其 RESTful 能力。

组件说明评分服务中的角色
Flask 应用实例app = Flask(__name__)服务入口,管理路由与配置
路由装饰器@app.route('/predict', methods=['POST'])定义预测端点
请求对象request.get_json()解析客户端传入的特征数据
响应对象jsonify()返回标准 JSON 格式预测结果
最佳实践:使用 app.run(host='0.0.0.0', port=5000, threaded=True) 启动服务,支持多线程并发请求。

4.2 模型加载策略

模型加载是评分服务的性能瓶颈之一。正确的做法是在服务启动时全局加载一次,避免每次请求都重新加载模型文件。

import xgboost as xgb
from flask import Flask, request, jsonify

app = Flask(__name__)

# 全局加载模型(服务启动时执行一次)
model_path = './models/xgb_model.json'
try:
    booster = xgb.Booster()
    booster.load_model(model_path)
    print(f"[INFO] 模型加载成功: {model_path}")
except Exception as e:
    print(f"[ERROR] 模型加载失败: {e}")
    booster = None
注意:模型文件路径建议使用绝对路径或环境变量配置,避免相对路径在不同工作目录下引发 FileNotFoundError。

4.3 预测接口设计

预测接口是服务的核心,需要处理请求解析、特征校验、模型预测和异常捕获四个环节。

@app.route('/predict', methods=['POST'])
def predict():
    # 1. 检查模型是否可用
    if booster is None:
        return jsonify({'error': '模型未加载,服务不可用'}), 500

    # 2. 解析请求 JSON
    data = request.get_json()
    if not data or 'features' not in data:
        return jsonify({'error': '请求格式错误,缺少 features 字段'}), 400

    # 3. 特征校验与转换
    try:
        features = data['features']
        # 假设 features 为二维列表 [[f1, f2, ...]]
        dmatrix = xgb.DMatrix(features)
    except Exception as e:
        return jsonify({'error': f'特征数据格式错误: {str(e)}'}), 400

    # 4. 模型预测
    try:
        preds = booster.predict(dmatrix)
        # 将 numpy 数组转为列表,便于 JSON 序列化
        result = preds.tolist()
        return jsonify({'prediction': result, 'status': 'success'}), 200
    except Exception as e:
        return jsonify({'error': f'预测过程异常: {str(e)}'}), 500
预测接口请求与响应流程 预测接口请求与响应流程 HTTP POST 请求 解析 & 校验 request.get_json() 模型预测 booster.predict() 响应 返回 400 / 500 错误 每个环节都需异常捕获,确保服务在异常输入下返回明确的错误信息

4.4 请求与响应格式规范

统一的请求/响应格式有助于客户端集成和服务维护。推荐遵循以下规范:

请求格式

{
    "features": [
        [5.1, 3.5, 1.4, 0.2],   // 第一条样本
        [6.2, 2.9, 4.3, 1.3]    // 第二条样本
    ],
    "options": {
        "output_margin": false,   // 可选:是否输出原始 margin
        "ntree_limit": 0          // 可选:限制使用的树数量
    }
}

成功响应格式

{
    "status": "success",
    "prediction": [0.982, 0.015],   // 预测结果列表
    "model_version": "v1.0.0",
    "timestamp": "2025-03-21T10:30:00Z"
}

错误响应格式

{
    "status": "error",
    "error": "特征数据格式错误: list index out of range",
    "error_code": "INVALID_FEATURES"
}
HTTP 状态码场景响应体关键字段
200预测成功status: "success", prediction
400请求格式错误、特征缺失或类型错误status: "error", error, error_code
500模型未加载、预测过程异常status: "error", error
生产建议:添加 model_version 和 timestamp 字段便于问题追踪;使用 error_code 枚举值(如 INVALID_FEATURES、MODEL_NOT_LOADED)方便客户端程序化处理。

4.5 完整服务启动脚本

if __name__ == '__main__':
    # 生产环境建议使用 Gunicorn 等 WSGI 服务器
    # 开发调试可直接运行
    app.run(host='0.0.0.0', port=5000, debug=False, threaded=True)
安全提醒:生产环境务必关闭 debug=True,避免泄露敏感信息。使用 threaded=True 提升并发能力,但需注意模型预测的线程安全性(XGBoost 的 predict 方法是线程安全的)。

通过以上步骤,我们完成了一个具备完整错误处理、统一格式规范的 XGBoost 评分 REST API 服务。下一环节将介绍如何对服务进行单元测试与集成测试,确保上线质量。