4. Flask 基础:框架介绍、路由与视图函数、GET 与 POST 请求处理
在精算模型上线流程中,Flask 是最轻量、最常用的 Python Web 框架之一。它允许我们将训练好的模型(如 GLM、GBM、神经网络)包装成一个 HTTP 服务,从而被前端应用、批处理调度器或下游系统调用。本章将系统讲解 Flask 的核心概念:框架定位、路由与视图函数的映射机制,以及 GET/POST 请求的处理方式。
4.1 Flask 框架概述
Flask 是一个基于 Werkzeug(WSGI 工具库)和 Jinja2(模板引擎)的微框架。其核心设计哲学是“微内核 + 扩展”,即框架本身只提供路由、请求/响应对象、会话管理等基础能力,数据库 ORM、表单验证、认证等功能通过第三方扩展按需集成。
| 特性 | 说明 |
|---|---|
| 轻量级 | 核心代码仅约 2000 行,无强制依赖,适合快速搭建 API 服务 |
| 路由灵活 | 支持动态 URL 参数、HTTP 方法绑定、蓝图模块化 |
| 开发模式 | 内置调试器与自动重载,开发效率高 |
| 生产就绪 | 配合 Gunicorn / uWSGI + Nginx 可承载高并发生产流量 |
| 模型服务场景 | 单进程加载模型,通过路由分发预测请求,响应延迟通常在 10~100ms 级别 |
4.2 路由与视图函数
路由(Route)是 URL 到 Python 函数的映射关系。Flask 使用 @app.route() 装饰器将视图函数绑定到指定 URL 路径。当客户端请求该 URL 时,Flask 自动调用对应的视图函数,并将返回值作为 HTTP 响应返回。
4.2.1 基本路由定义
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '精算模型服务已启动'
@app.route('/health')
def health_check():
return {'status': 'healthy', 'model_version': 'v2.1.0'}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
4.2.2 动态路由与类型转换器
精算模型服务中,经常需要根据模型版本、保单 ID 或产品代码动态构造 URL。Flask 支持在路由中使用 <variable> 捕获 URL 片段,并可指定类型转换器:
| 转换器 | 说明 | 示例 |
|---|---|---|
string |
默认,接受任意字符串(不含斜杠) | /model/<string:name> |
int |
接受正整数 | /policy/<int:policy_id> |
float |
接受浮点数 | /score/<float:amount> |
path |
接受字符串(含斜杠) | /files/<path:subpath> |
uuid |
接受 UUID 字符串 | /session/<uuid:session_id> |
@app.route('/api/v1/model/<string:model_name>/predict')
def predict_by_model(model_name):
# 根据 model_name 加载对应模型并执行推理
return {'model': model_name, 'prediction': 0.85}
@app.route('/api/v1/policy/<int:policy_id>')
def get_policy(policy_id):
# 查询保单信息
return {'policy_id': policy_id, 'premium': 12500.0}
4.2.3 路由与视图函数映射关系(SVG)
下图展示了客户端请求到达 Flask 服务后,路由匹配与视图函数调用的完整流程:
4.3 GET 与 POST 请求处理
在模型服务中,GET 和 POST 是最常用的两种 HTTP 方法。GET 通常用于查询状态、获取元数据;POST 用于提交特征数据并获取预测结果。
4.3.1 方法对比
| 对比维度 | GET | POST |
|---|---|---|
| 数据位置 | URL 查询参数(?key=value) |
请求体(Body),支持 JSON / Form / 文件 |
| 数据长度限制 | 受 URL 长度限制(通常 2KB~8KB) | 无理论限制(受服务器配置约束) |
| 安全性 | 参数暴露在 URL 中,不适合敏感数据 | 数据在请求体中,相对更安全 |
| 幂等性 | 幂等,多次请求结果相同 | 非幂等,每次可能改变服务状态 |
| 模型服务典型用途 | 健康检查、模型元信息查询、批量状态轮询 | 单条/批量预测、模型重载、特征上传 |
4.3.2 处理 GET 请求
Flask 默认路由只响应 GET 请求。通过 request.args 获取 URL 查询参数:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/v1/score')
def score():
# 从查询参数中获取特征值
age = request.args.get('age', type=int)
income = request.args.get('income', type=float)
credit_score = request.args.get('credit_score', type=float)
if None in (age, income, credit_score):
return jsonify({'error': '缺少必要参数: age, income, credit_score'}), 400
# 模拟模型预测
risk_score = 0.3 * (age / 100) + 0.5 * (income / 100000) + 0.2 * (1 - credit_score / 1000)
return jsonify({'risk_score': round(risk_score, 4)})
4.3.3 处理 POST 请求
POST 请求是模型推理的标准方式。通过 request.get_json() 解析 JSON 请求体:
@app.route('/api/v1/predict', methods=['POST'])
def predict():
# 解析 JSON 请求体
data = request.get_json()
if not data:
return jsonify({'error': '请求体必须为 JSON 格式'}), 400
features = data.get('features')
if not features:
return jsonify({'error': '缺少 features 字段'}), 400
# 模拟模型推理
prediction = sum(features) / len(features) if features else 0
return jsonify({
'prediction': prediction,
'model': 'demo_glm_v1',
'status': 'success'
})
4.3.4 GET 与 POST 请求处理对比(SVG)
下图展示了两种请求方法在模型服务中的数据处理路径差异:
4.4 综合示例:精算模型预测 API
以下代码整合了本章知识点,实现一个完整的精算模型预测服务:
from flask import Flask, request, jsonify
import joblib
import numpy as np
app = Flask(__name__)
# 模拟加载预训练模型(实际项目中替换为真实模型文件)
# model = joblib.load('models/glm_premium_v2.pkl')
@app.route('/')
def index():
return '精算模型服务 v1.0'
@app.route('/api/v1/model/info', methods=['GET'])
def model_info():
"""GET 请求:返回模型元信息"""
return jsonify({
'model_name': 'GLM_Premium_v2',
'version': '2.1.0',
'features': ['age', 'vehicle_value', 'driving_exp', 'claim_history'],
'target': 'annual_premium'
})
@app.route('/api/v1/predict/premium', methods=['POST'])
def predict_premium():
"""POST 请求:接收特征数据,返回保费预测"""
try:
data = request.get_json()
if not data:
return jsonify({'error': '请求体为空'}), 400
# 提取特征向量
features = [
data.get('age', 0),
data.get('vehicle_value', 0),
data.get('driving_exp', 0),
data.get('claim_history', 0)
]
# 模型推理(此处用模拟计算代替)
# prediction = model.predict([features])[0]
prediction = 5000 + 200 * features[0] + 0.05 * features[1] - 150 * features[2] + 300 * features[3]
return jsonify({
'predicted_premium': round(prediction, 2),
'currency': 'CNY',
'model_version': '2.1.0'
})
except Exception as e:
return jsonify({'error': f'推理失败: {str(e)}'}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
- 生产环境中必须关闭
debug=True,使用 Gunicorn 或 uWSGI 作为 WSGI 服务器。 - 模型加载应在应用启动时完成(全局变量),避免每次请求都重新加载模型。
- 建议添加请求日志、超时控制、输入校验等中间件,防止恶意请求导致服务崩溃。
- 对于高并发场景,可配合 Nginx 反向代理实现负载均衡。
4.5 本章小结
- Flask 框架:轻量、灵活,适合精算模型服务的快速搭建与迭代。
- 路由与视图函数:通过
@app.route()将 URL 映射到 Python 函数,支持动态参数和类型转换器。 - GET 请求:通过
request.args获取查询参数,适用于状态查询和元数据获取。 - POST 请求:通过
request.get_json()解析 JSON 请求体,是模型推理的标准方式。 - 生产化要点:关闭 debug、全局加载模型、添加输入校验和错误处理。