Streamlit vs Gradio:把Python AI模型快速变成Web应用
2026/9/14 9:14:01 网站建设 项目流程

如果你手上已经有一个训练好的 Python AI 模型,想让同事或用户直接在浏览器里上传文本、点一下按钮看到预测结果,Streamlit 和 Gradio 是两条很实用的路线。它们的价值不是替代 Flask、FastAPI,也不要求你掌握 React 或者 Vue,而是把最常见的“网页表单 + 推理函数 + 结果展示”封装成几段 Python 代码,让几小时内出一个能点、能看、能部署的 Web 应用成为现实。

我用这类工具做过不少模型 Demo,最大的感受是:模型本身能不能用,和模型能不能被别人用,完全是两件事。算法文件放在笔记本里,再厉害也只有自己能跑;一旦你想让产品同学、业务同事或者远程用户也能接触到,就一定会需要一个界面。做这个界面,人力成本和迭代速度往往比想象中更关键。Streamlit 和 Gradio 解决的就是这个问题。

这篇内容围绕“怎么把一个 Python AI 模型变成 Web 应用”展开,从环境准备、最小 Demo、模型加载、批量输入一直讲到部署和排查。不是只罗列功能,而是按实际落地顺序拆开讲。

1. 先判断:Streamlit 和 Gradio 到底怎么选

1.1 一个偏“数据应用”,一个偏“模型接口”

第一次接触这两个库的人,很容易被风格差异劝退。Streamlit 给我的感觉更像“用 Python 写数据应用”:页面结构可以自由组合,放标题、放输入框、放图表,然后通过按钮或输入事件触发逻辑。适合做带报表、可视化、多页面跳转的内部工具。

Gradio 更像是“给模型做展示接口”:你把一个 Python 函数告诉它,告诉它输入是什么类型、输出是什么类型,它就能生成一个网页。不需要自己写按钮逻辑,文本、图片、音频、视频这类常见输入输出都有现成组件。

如果你的目标是做一个分类 Demo,给测试者上传图片、语音或文本后看返回结果,G radio 起步更快。如果你的目标是一个数据后台,比如模型训练日志看板、样本标注工具、带着筛选条件的结果分析页面,Streamlit 会更顺手。

1.2 从实际输入输出方式去选,不要只凭热度

结合热度词里经常出现的“Streamlit 菜鸟教程”“Gradio 如何部署本地模型”这类搜索,可以看出大部分人其实不是缺功能文档,而是缺选型判断。

选型时建议明确几个问题:

  • 用户主要输入文本,还是图片、音频、视频、文件?
  • 是单个用户做测试,还是一群人并发访问?
  • 除了推理结果,是否需要展示图表、统计、历史记录?
  • 是否要做登录限制、访问权限、多页面?

如果只是文本输入 + 预测结果,两个都能做。如果涉及图片、音频、视频等多模态输入,Gradio 的组件更贴近模型测试场景,Input 和 Output 都能直接选类型。如果要做复杂的企业后台,则 Streamlit 的布局能力更强。

下面用一个表格做简单对比:

比较点StreamlitGradio
上手难度需要理解页面元素和事件最快一个函数就能出界面
页面布局类似数据应用,可做多页面以单个/多个 Interface 为主
多模态组件通过文件上传等方式处理原生支持文本、图像、音频、视频等
登录控制一般靠应用层或第三方方案launch 时提供 auth 参数可加简单限制
典型场景数据分析、模型看板、内部工具模型 Demo、接口演示、快速共享

实际使用中,两个可以组合:Gradio 负责对外演示,Streamlit 负责复杂业务后台。这不冲突。

2. 开始前把环境理干净:Python、虚拟环境和文件结构

2.1 先确认 Python 版本,再装包

新手最容易卡住的位置不是模型代码,而是 Python 环境。很多报错看起来是某个库不存在,实际是 Python 版本不匹配、pip 装到了错误环境、或者系统里同时存在多个 Python 解释器。

先打开终端确认当前环境:

python --version pip --version

如果电脑上装了 VSCode、PyCharm、Anaconda 多个工具,很容易出现终端里用的是 Python 3.9,编辑器里却指向另一个环境。建议新建一个虚拟环境,避免依赖互相影响。

python -m venv .venv

Windows 下激活:

.venv\Scripts\activate

macOS 或 Linux 下激活:

source .venv/bin/activate

这里给的是通用做法,Python 版本建议选 3.9 或 3.10 以上。实际兼容范围要以你准备安装的 Streamlit、Gradio 当前版本文档为准。先把版本确认清楚,比一上来就安装库更重要。

激活虚拟环境后,再安装两个库:

pip install streamlit gradio

如果是在已有项目里新增,不要随手动pip install -U把所有依赖全部升级,避免把项目里其他依赖冲掉。

2.2 建议的目录结构

模型代码和页面代码不建议写在一个文件里。虽然几百行的 Demo 也能写成一个 py 文件,但后面扩展批量任务、接口调用、更换模型时,会非常痛苦。

我习惯用这样的目录结构:

my_ai_demo/ ├── app.py # Streamlit 页面 ├── gradio_app.py # Gradio 页面 ├── predictor.py # 模型加载和推理逻辑 ├── models/ # 本地模型文件 │ └── model.pkl └── requirements.txt # 依赖锁定

predictor.py负责加载模型和调用模型,页面文件负责接收用户输入、展示结果。这样无论是换 Streamlit 还是 Gradio,推理层不用重写,只需要替换页面文件的调用方式。

3. Streamlit 版:把模型推理包装成一个可点击的表单页面

3.1 把模型加载与推理独立成模块

先不急着写页面,先让模型跑通一次。以最简单的文本分类模型为例,假设你有一个训练好的model.pkl文件。predictor.py可以长这样:

import joblib _model = None def load_model(): global _model if _model is None: _model = joblib.load("models/model.pkl") return _model def predict(text: str): model = load_model() label = model.predict([text])[0] return str(label)

这是一个通用示例,实际模型可能是 PyTorch、ONNX 或大模型 API。核心思路是把“加载”和“推理”拆开,避免页面每次刷新都重新加载模型。

3.2 用 Streamlit 写第一版 Web 界面

app.py里可以写一个最简版本:

import streamlit as st from predictor import predict st.title("文本分类 Demo") st.write("输入一段文本,点按钮查看模型预测结果。") text = st.text_area("待分类文本", value="") if st.button("开始预测"): if not text.strip(): st.warning("请先输入文本") else: with st.spinner("模型推理中..."): result = predict(text) st.success(f"预测结果:{result}")

页面启动后,用户在输入框输入内容,点击按钮,程序调用predict函数,然后把结果呈现在页面上。没有写任何 HTML、JavaScript,也没有路由和接口层。

这套流程背后的运行逻辑是:Streamlit 每次交互都会重跑整个页面脚本。所以页面里才建议用st.button控制触发范围,避免一上来就自动推理。按钮没有点击时,页面只负责渲染。

3.3 启动命令与验证标准

启动 Streamlit 应用:

streamlit run app.py

默认地址通常是http://localhost:8501,终端会显示完整的本地地址。如果端口冲突,可以手动指定:

streamlit run app.py --server.port 8502

第一次跑通后,用三条标准判断是否成功:

  1. 页面能否正常打开。
  2. 输入一条测试文本后,按钮能否触发推理。
  3. 页面是否显示预期结果,并且没有刷新白屏。

只要这三条都通过,Streamlit 这边的路就算走通了。

4. Gradio 版:几行代码先立一个接口

4.1 Interface 是最快入口

Gradio 写起来通常更短。gradio_app.py可以这样:

import gradio as gr from predictor import predict def classify(text: str): return predict(text) demo = gr.Interface( fn=classify, inputs=gr.Textbox(label="输入文本"), outputs=gr.Label(label="分类结果"), title="文本分类 Demo", ) if __name__ == "__main__": demo.launch()

运行方式:

python gradio_app.py

默认地址一般是http://127.0.0.1:7860。到这里你会发现,Gradio 只需要把一个普通 Python 函数包进Interface,就能自动生成输入框、按钮和结果展示区域。

4.2 理解 inputs、outputs 和 fn 的关系

Gradio 的核心逻辑是“函数包装”:页面是把fn接到界面上的桥梁。你给fn一个输入,它返回一个输出,Gradio 负责把前端交互和 Python 调用之间的转换处理好。

常见参数:

  • inputs:接收用户输入的类型,比如 Textbox、Image、Audio、Video、File。
  • outputs:展示结果的类型,比如 Textbox、Label、Image、Audio。
  • title:页面标题。
  • examples:提供几个示例输入,方便用户一键测试。

实际用的时候,不要照抄复杂例子,先从一个基础函数开始。函数返回类型和outputs类型不一致,是 Gradio 最常见的报错来源之一。

例如文本分类函数返回一个字符串,outputsgr.Textbox没问题;如果返回一个字典或列表,就要用对应的组件类型。遇到输出为空或显示异常,优先检查这里。

4.3 launch 参数和本地部署注意点

本地运行时可能需要关注几个launch参数:

demo.launch( server_name="0.0.0.0", server_port=7860, )

server_name设置为"0.0.0.0",代表监听服务器上所有网络地址,这样局域网内其他设备可以通过服务器 IP 访问。默认"127.0.0.1"时只能本机访问,安全但不够方便。

如果你暂时不打算部署公网,先用127.0.0.1测试即可。需要给同事演示时,可以在同一个局域网下改成0.0.0.0,并注意访问路径是否是http://你的IP:端口。实际网络环境不同,这一步需要以现场条件为准。

注意:不要一上来就试公网部署。先在本地和局域网跑通,确认输入输出正常,再考虑外网访问。

5. 本地模型加载:代码之外最常出问题的环节

5.1 加载和推理的分离为什么重要

很多 Demo 把模型加载写在函数外面,页面脚本每次交互都会执行一遍。Streamlit 中这不是小问题,因为页面脚本会在按钮点击后重跑,模型加载如果写在顶层,就会重复加载,耗时和内存都会成倍增加。

Streamlit 提供了缓存装饰器:

import streamlit as st @st.cache_resource def load_model(): return joblib.load("models/model.pkl")

这样模型加载一次后,后续调用直接复用缓存结果。页面交互不再重复读模型文件。

在 Gradio 中,模型加载可以放在predict函数外部做一次,也可以借助 Python 模块的全局变量。关键是让模型只初始化一次,不要在每次推理时都重新加载。

5.2 输入格式不对的隐蔽坑

模型代码本身跑通过,不代表网页调用就能成功。Web 界面拿到用户输入的文本,有可能带额外换行、前后空格、编码不同。图片输入更敏感,上传图片的尺寸、通道、格式、色彩空间都可能和训练时不匹配。

我遇到过一个案例:离线测试时图片正常,上传到 Gradio 后模型返回形状错误。排查到最后,不是推理逻辑问题,而是页面组件输出的是 RGB 图片,模型内部却按 BGR 处理。这个坑必须在封装推理函数时提前处理,而不是等报错再回头找。

稳妥的做法是在predict函数入口统一做数据校验:

  • 文本先strip(),空输入直接返回提示。
  • 图片先转换尺寸和通道格式,再做预测。
  • 文件上传类任务先检查扩展名,再读取内容。

这样即使输入不干净,函数也能给出明确提示,而不是抛一个看不懂的底层报错。

5.3 模型体积和资源占用怎么估算

如果模型文件只有几十 MB,CPU 环境下几秒内能完成加载。如果是大语言模型或视觉模型,几个 GB 的权重文件加载后,内存或显存占用会很高,第一次打开页面可能要等很长时间。

判断标准不是“能不能跑”,而是:

  • 加载耗时是否还在可接受范围。
  • 推理时内存、显存是否被打满。
  • 多个用户同时请求时,服务器是否还能响应。

低配机器可以跑通,但不代表适合做多人并发。如果只是学习或做内部演示,默认配置通常够用;如果要持续服务,就得考虑独立显卡、足够的内存、以及任务队列。

6. 批量场景:从 Demo 走向真实任务

6.1 文件上传批量预测

单个输入框适合测试,但真实业务里用户往往有一批文本或图片需要处理。这时可以加一个文件上传组件,读入后逐条推理,并把结果合并导出。

Streamlit 里可以用st.file_uploader接收文件,再逐行处理。示例逻辑:

uploaded_file = st.file_uploader("上传文本文件", type=["txt", "csv"]) if uploaded_file is not None: content = uploaded_file.read().decode("utf-8") lines = [line.strip() for line in content.splitlines() if line.strip()]

Gradio 里可以用gr.File接收文件。处理完结果后,可以同时输出一个结果文本或文件。

这个阶段要注意的不是推理本身,而是输出一致性。批量任务必须考虑:

  • 输入顺序是否保持。
  • 某一条数据失败时,是跳过、重试还是中断。
  • 输出文件命名是否唯一。
  • 是否有日志记录,方便定位哪一条失败。

很多批量坑不是模型问题,而是“几百万条数据跑完后不知道哪些成功哪些失败”。建议从一开始就加上计数和日志。

6.2 队列、缓存和并发控制

Gradio 中,可以在Interface上启用队列:

demo.queue().launch()

队列的作用是把同时发来的请求排队处理,避免服务器瞬间被打满。对于重量级模型推理,这很重要。

并发参数不要一上来就调最大。Gradio 里concurrency_count之类的参数如果设置太大,CPU、内存、显存会同时被多个任务占满,最终导致集体超时。正确顺序是先在低并发下测试单个任务耗时,再逐步加并发。

判断标准很简单:单条推理耗时多少,单个任务占用多少内存,然后倒推可以同时跑几个任务。假设单条任务需要 2 秒、占用 2GB 内存,服务器只有 8GB 内存,那同时处理 2 到 3 个任务已经算冒险,不能直接把并发调到 10。

6.3 失败记录落到本地

批量演示和批量生产之间,差的往往不是模型精度,而是错误处理。

建议统一返回结构化结果,例如每条数据包含indexinputresultstatuserror。前端页面展示进度条,后台把失败项单独写成一份 CSV 或日志文件。这样跑完后,不需要人肉从页面复制结果。

7. 部署:从本地可见变成“别人也能访问”

7.1 三条常见部署路线

本地 Demo 只在开发机上运行,如果想给团队或公网用户访问,通常有三种路线。

第一种:部署到一台有公网 IP 的云服务器,用streamlit runpython gradio_app.py后台运行,再通过 Nginx 或应用托管方式对外提供服务。模型文件较大时,这种方案最可控,资源自己掌握。

第二种:使用 Streamlit Community Cloud 或 Hugging Face Spaces 这类托管平台,把项目推到代码仓库,平台自动构建并分配访问地址。适合演示项目,但公开平台会有访问限制,具体以平台规则为准。

第三种:如果模型必须跑在内网,不做公网暴露,只供内部同事使用,可以在内网服务器上监听固定端口,配合权限系统或简单认证。

建议顺序是本地跑通、内网验证、云服务器部署、再做公网访问。不要跳过中间步骤。

7.2 依赖固定、密钥保护和简单认证

部署时最容易踩的坑是“本地能跑,服务器一启动就报错”。原因基本集中在依赖版本不一致、系统差异、模型路径不对。

在项目目录生成依赖清单:

pip freeze > requirements.txt

部署时使用同一份requirements.txt安装。如果模型依赖复杂,可以考虑 Docker 打包,但这不是必须的,先保证版本一致即可。

密钥、Token、数据库连接串不要直接写死在代码里。G radio 的launch里可以加简单认证参数,用于内部演示:

demo.launch(auth=("admin", "your_password"))

Streamlit 侧通常靠应用层认证或第三方组件处理。注意,通过认证参数写进代码的做法只适合低风险内部场景,生产环境要用更规范的鉴权和 HTTPS,不要把生产密码明文提交到代码仓库。

注意:部署前先把鉴权、端口、日志目录确认清楚。直接暴露公网且没有任何访问控制的 Demo,很容易被人顺手扫掉。

7.3 后台运行与日志查看

在服务器上直接跑streamlit run app.py,终端关闭服务就会停。可以用 nohup 或系统服务方式后台运行,但重点不是命令,而是日志。

部署后第一件事不是看页面,而是看启动日志。Streamlit 和 Gradio 都会在终端输出访问地址和报错信息。把日志落盘后,再去处理页面问题。这样遇到卡住、无输出、崩溃时,至少有据可查。

8. 遇到问题别乱改:按这个顺序排查

8.1 报错内容其实给出了七成信息

很多人报错后第一反应是重新安装所有依赖,或者把参数调成网上搜到的组合。这样做容易把原本正常的环境弄坏。

更稳妥的做法是先把终端里的完整报错复制下来,看懂第一行错误类型和最后一行原因。常见报错大致分几类:

  • 模块缺失:ModuleNotFoundError,说明依赖没装对或环境不对。
  • 端口冲突:Address already in use,说明端口被占用。
  • 模型路径错误:FileNotFoundError,说明找不到模型文件。
  • 输入输出类型不匹配:Gradio 的返回类型和组件类型不一致。
  • 显存或内存不足:任务跑到一半被系统杀掉,或者明显变慢。

8.2 各环节排查顺序

我一般按从下往上、从外到内的顺序排查。先看现象,再看输入,最后才怀疑算法和代码:

排查环节先确认什么
现象是直接报错、页面卡住、结果为空,还是网络超时
输入文件路径、格式、编码、尺寸、大小是否符合预期
环境Python 版本、pip 环境、依赖版本、端口占用
参数监听地址、端口、并发数、超时时间
代码模型加载、输入预处理、输出类型是否一致
模型本身模型是否在原生环境下能单独跑通

在这些都没问题之前,不建议直接调大并发、升级硬件或重写页面。

8.3 页面出来了但结果一直为空

这类问题要分成两端看。如果页面能打开,但点击预测没反应,先看终端有没有报错。如果终端也没有日志,多半是按钮事件没有触发,或者前端输入没有传给 Python 函数。

Gradio 里可以先打印函数参数:

def classify(text: str): print("收到输入:", repr(text)) return predict(text)

看到终端输出后,就能判断是参数没传进来,还是模型推理逻辑的问题。Streamlit 里也可以先用st.write临时输出中间变量,确认输入内容到了哪一步。

很多看起来像功能不支持的问题,实际是输入格式不对。所以排查第一步永远是复现并打印输入。

9. 落地之前先想清楚边界

9.1 什么场景建议用,什么场景不建议

Streamlit 和 Gradio 适合模型演示、内部工具、快速原型、课程作业、算法验证。它们最大的优点是快,最大的缺点也很明确:不适合做复杂的生产级业务系统。

如果产品需要精细的权限体系、复杂的前端动效、像 SaaS 一样的管理后台,它们并不是最佳选择。更合适的路线是用 Flask 或 FastAPI 提供接口,再用前端框架搭页面。这样开发周期会长一些,但灵活性和工程边界更清晰。

如果是把大模型接进现有系统,也不一定每个场景都要写 Web 界面。先判断用户是真的需要一个可视页面,还是只需要一个 API 端点。很多企业场景只是内部系统调用模型,封装一个 FastAPI 接口比套 Streamlit 页面更省事。

9.2 最终取舍建议

对于大多数人来说,第一次接触这个选题,最有价值的动作不是对比完所有框架再选,而是先做两个小 Demo:用 Streamlit 写一个带表格和按钮的页面,用 Gradio 写一个能接收文本或图片并返回结果的接口。

做完之后,你自然会感受到两个工具各自的边界。之后再决定正式项目到底用哪个,或者干脆两个都不用,回到 Flask + 前端方案里。这个判断能力,比记住某一个库的具体 API 更有用。

我个人更建议先把单任务跑稳,再考虑批量、并发和部署。模型文件、输入格式、推理函数、页面调用这四层都稳定之后,Web 应用才算是真正立住了。

这个方案真正落地时,最该盯住的不是功能列表,而是输入格式、资源占用和失败重试。只要这三件事处理到位,把 AI 模型变成 Web 应用这件事,就真的能在几小时内从零跑到可用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询