当前位置: 首页 > news >正文

AI大模型应用部署之Flask框架使用

如何将机器学习算法模型深度学习模型制作、打包成一个可以直接交付的软件、并可以快速部署, 这里就要使用到Flask以及Docker,相关工作流程架构图如下:

相关技术如下:

  • 了解问题解决的工作流程
  • 使用Flask框架将服务封装成接口
  • 使用Docker技术将服务容器化介绍

一.Flask服务接口

如何使用 Flask 框架来实现从浏览器远程访问使用我们的模型服务

1.Flask作用与流程

1.1. 为什么要学习 Flask?

对于模型部署来说,Flask 的作用是什么呢?

当训练好一个模型后,为了能够让它能够对外提供服务,一般会将其部署到某一台存在于互联网的服务器上,想要使用该服务的人可以通过网络来远程和部署在服务器的模型进行交互以获得想要的服务

此时,就需要在服务端去编写一个用于和用户交流的应用程序,而Flask 就是一款可以解决此问题的 Web 框架,它具有轻便、灵活、安全且容易上手,能够在短时间内构建出一个 Web 服务站点,通过 Flask 用户可以提交数据到服务端,服务端可以处理用户请求,并返回处理结果

1.2. 流程

  • Flask 在整个业务流中承担的角色是什么?
  • 用户的请求和响应到底是一个什么样的流程?

简要的流程如下:

(1)浏览器给服务器监听在某个端口上的应用程序发送请求

(2)服务器程序接收到请求之后,将请求转发具体处理该请求的程序

(3)该程序解析请求,然后找到该请求对应的处理函数,并执行该函数

(4)将函数的返回值返回给服务器软件,服务器软件再将返回值返回给浏览器

2.Flask入门

Flask 是使用 Python 语言编写的轻量级的 Web 应用程序框架。使用该技术,可以将训练得到的模型封装一个能够提供预测的网络应用程序,即: 可以对外提供一个服务接口

Flask中文文档:欢迎使用 Flask — Flask 0.10.1 文档

安装命令如下:

pip install Flask==2.1.0

2.1. Flask Hello World

首先,创建一个简单的 Flask 应用程序:

# 1.导入依赖包 from flask import Flask # 2.实例化Flask app = Flask(__name__) # 3.定义路由, 这里使用根路径, 请求方式为Get @app.route('/', methods=['GET']) # 4.请求响应函数, index 代表根路径函数 def index(): return 'Hello World' if __name__ == '__main__': # 5. 启动服务, 监听端口, 这里没有写端口,则默认监听5000 app.run()

运行该程序,发现报错:

ImportError: cannot import name 'url_quote' from 'werkzeug.urls' (D:\ProgramData\anaconda3\envs\my_conda\Lib\site-packages\werkzeug\urls.py). Did you mean: 'unquote'?

上面的错误是由于当前环境中安装的FlaskWerkzeug版本不兼容导致的

在较新的Werkzeug(3.0.0及以上版本)中,url_quote函数被移除或重命名了,而旧版本的Flask仍然尝试从旧路径导入它,从而引发报错。

可以通过以下两种方案之一来解决这个问题:

方案一:降级 Werkzeug 版本(推荐用于旧版 Flask 项目)

如果正在学习或使用较老版本的 Flask 教程,建议将Werkzeug降级到兼容的版本,可以在终端中运行以下命令:

pip install Werkzeug==2.2.2

(注:部分极老版本的 Flask 可能需要降级到Werkzeug==2.0.3,如果 2.2.2 仍报错可以尝试此版本)

方案二:升级 Flask 版本(推荐用于新项目)

如果希望使用最新的依赖库,可以直接将Flask升级到最新版本。新版 Flask 已经修复了依赖关系,能够完美兼容新版Werkzeug

1pip install -U Flask

额外建议:使用虚拟环境

由于使用的是 Anaconda 环境,为了避免全局包版本冲突(例如其他项目依赖不同版本的 Werkzeug),强烈建议为每个 Flask 项目创建独立的虚拟环境
如果使用的是 Conda,可以执行:

conda create -n flask_env python=3.10 conda activate flask_env pip install flask

这样就能彻底隔离依赖,避免后续开发中再次出现类似的版本冲突问题

针对上面的解决方案,这里使用的是方案二解决: 运行命令pip install -U Flask后, 启动程序,输出结果如下:

* Serving Flask app 'flask_demo' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:5000

在浏览器输入: http://127.0.0.1:5000, 得到如下显示:

这个结果表示: 通过 http://127.0.0.1:5000 访问了定义在服务器端一个服务函数,可以理解为:远程调用了一个 Python 函数,并且该函数返回了函数的运行结果

接下来,详细讲解各部分的含义,方便后续代码的编写

2.2. Flask 应用的创建

# 实例化Flask app = Flask(__name__)

上述代码表示,创建了一个 Flask 应用实例,也可以理解为所有的请求都是由该实例来处理,接下来,调用该实例的 run 方法:

if __name__ == '__main__': app.run() # 还可以修改访问的ip,以及端口 app.run(host='0.0.0.0', port=6000) # host='0.0.0.0' 访问服务端所有ip, port=6000 指定访问的端口为6000

run 方法会启动一个用于开发测试的服务器,该服务器会在某个端口监听,来获得客户端发送过来的请求。其流程如下:

请求 --> 测试服务器 --> Flask 应用

注意:在开发阶段使用该测试服务器,部署时,将会使用 Gunicorn 服务器,后面演示部署时,就暂且使用开发服务器

2.3. Flask 请求处理函数

当 Flask 应用获得了客户的请求,此时就需要将该强求转发给某个具体的业务函数来处理,如何定义不同的请求具体的业务函数之间的映射关系呢?

@app.route('/', methods=['GET']) def index(): return 'Hello World'

上述代码中,index 函数是我们定义的具体业务函数,它的处理结果就是返回一个字符串 "Hello World".

如何将某个请求映射到该函数呢?首先,得清楚,不同的请求对应的 url 是不同的,例如:

看新闻的请求: http://xxx.xxx.xxx.xxx:5000/news 听音乐的请求: http://xxx.xxx.xxx.xxx:5000/music

当请求的 url 是 /news 时,就可以使用news 函数来处理,请求的 url 是 /music 时,就可以使用music 函数来处理

注意:此处的 URL 是由自己定义的。假设,希望用户访问 /phone-price 时,就可以获得模型的预测结果,就可以编写一个函数来和该 URL 对应起来

定义请求 URL 和具体业务函数映射关系就是使用app.route 装饰器,该装饰器第一个参数就是自定义的请求 URL,第二个参数methods 为请求类型

请求类型有多种,主要用到了两种请求类型:GET、POST

(1)GET 请求: 用于只获得数据,而不需要向服务端提交任何数据

(2)POST 请求: 用于向服务端发送请求数据,例如:要进行垃圾邮件分类,需要将邮件数据数据发送给服务端,此时应该使用 POST 方式

3.Flask 表单使用

在进行模型部署时,经常需要用户传递数据,例如: 一张图片、一封邮件、一条新闻等,然后由部署的模型接收数据并预测,最后给出响应。,表单的用途就是客户用于提交数据的内容,在这里,需要学习:

  • 编写表单
  • 处理表单

(1). 编写表单

当用户访问一个指定的 URL 时,需要返回给用户一个表单,让用户在表单中填写相关的内容,并点击某个按钮,将数据提交给服务器处理:步骤如下:

  • (1). 创建 Flask 项目,并创建 app.py 文件,代码内容如下:
  • (2). 在 app.py 同级目录下创建 news_submit.html 文件

app.py 内容如下:

from flask import Flask # 初始化 Flask 应用 app = Flask(__name__) @app.route('/news_submit', methods=['GET']) def news_submit(): with open('news_submit.html', 'rb') as file: content = file.read() return content if __name__ == '__main__': app.run()

news_submit.html 内容如下:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>新闻内容提交</title> </head> <body> <form action="" method="post"> <textarea name="content" cols="40", rows="10"></textarea> <br /> <input type="submit" value="提交新闻" /> </form> </body> </html>

运行 app.py 文件,并打开浏览器输入: http://127.0.0.1:5000/news_submit, 显示内容如下图所示:

(2). 处理表单

首先需要接收到表单的数据,然后进行处理,当接收到表单数据之后,给用户显示到浏览器内

在 .html 文件内,修改 form 表单的 action 属性如下:

<form action="/news_handle" method="post"> <textarea name="content" cols="40", rows="10"></textarea> <br /> <input type="submit" value="提交新闻" /> </form>

在 app.py 中增加额外的业务处理函数 news_handle, 专门用来接收表单发来的数据

from flask import Flask from flask import request # 初始化 Flask 应用 app = Flask(__name__) @app.route('/news_submit', methods=['GET']) def news_submit(): with open('news_submit.html', 'rb') as file: content = file.read() return content # 表单提交 @app.route('/news_handler', methods=['POST']) def news_handler(): data = request.form.get('content') print(data) return 'Received News Data!' if __name__ == '__main__': app.run()

重新运行程序,在浏览器输入 http://127.0.0.1:5000/news_submit,并在页面内填写任意文本内容,如下图所示:

点击提交,就可以在后台看到以下内容:

这就表示后台获得了用户提交的数据内容

响应给前端的数据内容如下:

注意: 客户如果需要提交数据给后台,一般都是通过表单的形式提交

(3). 获得其他形式的数据

上面编写了一个用于获得一大串文本内容的表单,假设: 需要用户提交给后台很多数据,就可以编写如下表单:

app.py 内容:

from flask import Flask from flask import request # 初始化 Flask 应用 app = Flask(__name__) @app.route('/userinfo_submit', methods=['GET']) def userinfo_submit(): with open('userinf_submit.html', 'rb') as file: content = file.read() return content @app.route('/userinfo_handle', methods=['POST']) def userinfo_handle(): name = request.form.get('name') age = request.form.get('age') sex = request.form.get('sex') print('姓名:', name) print('年龄:', age) print('性别:', sex) return 'Received UserInfo Data!' if __name__ == '__main__': app.run()

userinfo_submit.html 内容如下:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户信息内容提交</title> </head> <body> <form action="/userinfo_handle" method="post"> 姓名: <input type="text" name="name" /> <br /> 年龄: <input type="text" name="age" /> <br /> 男:<input type="radio" name="sex" value="男" /> 女:<input type="radio" name="sex" value="女" /> <br /> <input type="submit" value="提交" /> </form> </body> </html>

4.Flask 服务交付

在进行模型部署时,首先用户传递给后台数据,大部分情况是json格式的,例如:

{ "content":"新闻内容" }

然后由部署的模型接收数据,并预测,最后返回一个json格式的输出,在这里,需要学习:

  • json格式数据接收
  • json格式数据返回

首先需要接收到json格式的数据,然后进行处理,当接收到数据之后,就给用户返回对应的json格式的输出

在 .html 文件内,修改 form 表单的 action 属性如下:

<form action="/news_handle" method="post"> <textarea name="content" cols="40", rows="10"></textarea> <br /> <input type="submit" value="提交新闻" /> </form>

在 app.py 中增加额外的业务处理函数 news_handler, 专门用来接收表单发来的数据:

from flask import Flask, Response, json from flask import request # 初始化 Flask 应用 app = Flask(__name__) app.config['JSON_AS_ASCII'] = False # 解决中文乱码问题 @app.route('/news_submit', methods=['GET']) def news_submit(): with open('news_submit.html', 'rb') as file: content = file.read() return content @app.route('/news_handler', methods=['POST']) def news_handler(): # 获取json格式的输入 request_json = request.get_json() data =request_json['content'] # 定义响应数据格式 respose_data = { 'status': 'success', 'content': data, } # 返回请求数据 return Response(status=200, respose=json.dumps(respose_data,sort_keys=False)) if __name__ == '__main__': app.run()
# 客户端Client import requests import time # 定义请求url和传入的data url = "http://127.0.0.1:5000/news_handler" data = {"content": "中国大满贯女单冠军"} start_time = time.time() # 向服务发送post请求 res = requests.post(url, json=data) cost_time = time.time() - start_time # 打印返回的结果 print('文本类别: ', res.text) print('单条样本耗时: ', cost_time * 1000, 'ms')

客户端打印返回结果:

除了使用客户端访问外,实际工作中一般使用Postman/ApiFox进行服务测试

使用Postman向 http://127.0.0.1:5000/news_handler发送请求,并返回响应结果

请求体:

{ "content":"新闻内容" }

响应体:

{ "Status": "success", "content": "新闻内容" }

Postman下载地址:Download Postman | Get Started for Free

ApiFox下载地址:Apifox官网

操作如下图所示:

5.Flask 服务封装

接下来将通过自己训练的《投满分项目-新闻文本分类器》通过 Flask 进行部署,使得用户能够通过浏览器提交新闻文本数据,模型能够对新闻进行分类,并返回给用户结果, 业务实现代码见: 【NLP自然语言处理-投满分项目】2.模型训练与测试之随机森林&FastText模型的应用

http://www.rkmt.cn/news/1489171.html

相关文章:

  • 迁移学习实战:用预训练模型做图像分类
  • 第四篇:数据库国产化与信创替代的守护者:基于CLup的异构数据库一站式运维平台构建
  • 3步自动化搞定黑苹果配置:OpCore-Simplify零基础EFI生成工具终极指南
  • 2026 徐州防水补漏服务商口碑测评榜单|全屋渗漏维修机构优选指南 - 宅安选房屋修缮
  • 2026年 哈尔滨/深圳高端婚礼策划推荐榜:海外韩式及老钱风、布幔草坪与秀场风极简婚礼口碑优选 - 品牌发掘
  • Palantir Gotham背后的‘数据炼金术’:大规模图分析、实时融合与可视化技术拆解
  • 【字节跳动】本文系统阐述了SEED技术体系在人工智能领域的49项核心创新,涵盖容错架构(六进程热备)、权重管理(4096KB固定粒度)、注意力机制(24头时序锁相)、专属会话保护(次元壁垒)、字符处理
  • 视频字幕提取,5款工具实测对比
  • MATLAB一键运行的灰狼算法调参SVM分类工具:15维输入、4类识别,带数据和结果图
  • 中小型工厂自动化选型:低价开源产品为何难扛高频数据需求?实在Agent以非侵入式AI智能体打破数字化僵局
  • 沉迷 Vibe coding 后我幡然醒悟:为什么可持续开发要回归半古法编程
  • 5分钟掌握AI短视频创作:Pixelle-Video让你的创意轻松起飞
  • 全自动定向评价系统和全自动评价系统作用不同
  • 2026 绍兴防水补漏服务商口碑测评榜单|全屋渗漏维修机构优选指南 - 宅安选房屋修缮
  • ComfyUI-FramePackWrapper:8GB显存实现高质量AI视频生成的完整指南
  • LPC845 I2C SBL实战:嵌入式固件远程更新与内存布局解析
  • Zotero-GPT插件API调用故障排查:3步解决AI功能失效问题
  • 《置身钉内》原文-可播放阅读
  • OpenDroneMap:开源无人机摄影测量系统的架构解析与技术实现
  • 2026年 HC600/980QP高强钢厂家推荐榜单:汽车轻量化核心板材与冲压性能深度解析 - 品牌发掘
  • 如何高效使用BBDown:B站视频下载的终极命令行方案
  • HR外包工具横向评测:单租户SaaS真的难解差异化规则?实在Agent以非侵入式AI重构企业数字化转型
  • 2026实力厂商推荐:超越创新LED 球形屏、球幕 LED 显示屏、异型屏、全息沉浸式屏、LED 圆形屏定制供应商深度解 - 栗子测评
  • Jasminum茉莉花:5分钟掌握Zotero中文文献管理终极方案
  • BetterNCM 插件管理器实战:Rust 架构设计与 Windows 自动化安装深度解析
  • 2026 珠海防水补漏服务商口碑测评榜单|全屋渗漏维修机构优选指南 - 宅安选房屋修缮
  • 基于LPC51U68与SCTimer的I2C总线鲁棒性测试与错误注入实战
  • Lathe:利用大语言模型生成技术教程,助力实践学习!
  • 2026年 抗穿刺地面保护膜品牌/厂家推荐排行榜:高抗撕裂/加厚耐磨/装修防刮擦优质产品精选榜单 - 企业推荐官【官方】
  • IINA:macOS上最强大的免费视频播放器终极指南