Gradio — ML 模型 demo 框架
是什么
Gradio 是 Stanford 团队 Abubakar Abid 等五人 2019 年发起的开源 Python 库,配套论文发在 ICML 2019 demo track,2021 年 12 月被 HuggingFace 整体收购,至今以 Apache-2.0 公开开发,GitHub 上约 36k 星。日常类比:你写好了一个 Python 函数(比如”输入图片,返回猫狗概率”),Gradio 替你套一层浏览器外壳——别人在网页里上传图片、点按钮,函数就被调一次,结果回填到页面。
最小例子,5 行:
import gradio as gr
def greet(name): return f"Hello {name}"
gr.Interface(fn=greet, inputs="text", outputs="text").launch()跑起来终端打印 http://127.0.0.1:7860,浏览器自动开一个有输入框、提交键、输出区的页面。没写一行 HTML / JS / FastAPI 路由,就有了一个跑在浏览器里的”函数试用台”。
为什么重要
不理解 Gradio,下面这些事都没法解释:
- 为什么 HuggingFace Spaces 上 70% 以上模型卡都有一个”Try it”按钮——背后就是 push 一个
app.py到 Space repo,CI 自动起容器、暴露 URL,原生 SDK 就是 Gradio - 为什么研究员写完模型敢直接发链接给同事看效果——
launch(share=True)给一个*.gradio.live公网地址,72 小时有效,背后是自建反向隧道 - 为什么 AUTOMATIC1111 Stable Diffusion WebUI 1.x 整套界面、Whisper 早期 demo、各类 LLM 试玩页都长得像同一家——它们底下都是 Gradio 组件
- 为什么 HuggingFace 愿意把整个团队收下——Spaces 平台的活跃 demo 边际成本被 Gradio 压到了 git push
核心要点
Gradio 的设计哲学和 streamlit 不一样。Streamlit 是”整段重跑”,Gradio 是函数即接口:你声明”输入是什么类型、输出是什么类型、要调哪个函数”,框架替你接前后端。理解这一点,整套 API 都顺:
-
两层 API:
gr.Interface是最简包装(函数 + 输入 + 输出三件套),底层用gr.Blocks构建。Blocks是低层 API,可自定义布局、多事件、组件互联、多 tab。简单 demo 用前者,正经应用用后者。 -
组件 = 类型:
Textbox/Image/Audio/Video/File/Dataframe/Slider/Chatbot/Plot/Model3D/Gallery等四十多种内置组件,每个组件既是输入控件、又是输出渲染器。声明inputs="image"等同于inputs=gr.Image()。 -
事件绑定:
Blocks里写btn.click(fn, inputs=[a, b], outputs=[c])就把按钮点击连到函数;可以多个事件绑同一函数、一个事件触发多函数链式更新。比 Streamlit 的”重跑”更接近传统 Web 思维。 -
聊天专用糖:
gr.ChatInterface(fn)一行得到聊天 UI——流式输出、多轮 history、文件上传、思考中状态全自带。LLM 应用原型几乎都从这里起步。 -
队列:内置
queue,concurrency_limit限并发避免显存爆,max_size限排队长度,前端实时显示队伍位置。ML 推理天然慢、天然容易撞 OOM,这一层没它就裸奔。
底层架构:FastAPI(从 3.0 起,之前是 Flask)+ Uvicorn ASGI 起 HTTP server,前端是 Svelte + TypeScript 编译出的 web component(可以直接嵌进任意页面),通信走 REST + WebSocket + SSE,5.0 起音视频走 WebRTC。
实践案例
案例 1:图片分类 demo
import gradio as grfrom transformers import pipeline
clf = pipeline("image-classification")
def predict(img): out = clf(img) return {x["label"]: x["score"] for x in out}
gr.Interface( fn=predict, inputs=gr.Image(type="pil"), outputs=gr.Label(num_top_classes=3),).launch()不到 10 行得到:拖拽上传图片 / 调模型 / 标签 + 概率条形图。gr.Label 自动把 dict 渲染成可视化——这种”组件懂数据形状”的多态在 Gradio 里到处都是。
案例 2:用 Blocks 自定义布局
with gr.Blocks() as demo: gr.Markdown("## 双语翻译") with gr.Row(): src = gr.Textbox(label="原文", lines=4) dst = gr.Textbox(label="译文", lines=4, interactive=False) btn = gr.Button("翻译") btn.click(fn=translate, inputs=src, outputs=dst)
demo.launch()Blocks 像 with-block 拼版式:Row 横排、Column 竖排、Tab 多页。比 Interface 啰嗦,但能放得下”多输入混一个事件、一个函数刷新好几个区域”这种复杂交互。
案例 3:ChatInterface 给 LLM 套壳
def respond(message, history): reply = call_llm(message, history) for chunk in reply: # 假设 LLM 流式返回 yield chunk
gr.ChatInterface(fn=respond).launch()返回 generator 就自动走流式输出。history 是 [(user, bot), ...] 的列表,框架替你维护。配合 additional_inputs=[gr.Slider(...)] 还能在聊天框旁边挂调参面板。
踩过的坑
-
launch(share=True)不是生产部署:share 链接 72 小时过期,且依赖 gradio.live 中转服务器,单点、限速、不能定制域名。生产用 docker 自己起 uvicorn,或者直接 push 到 Spaces。 -
不写
queue上来就崩:默认Interface已开 queue,但Blocks里如果手动demo.queue(concurrency_limit=...)漏写,多个用户同时点会全部塞进同一个 GPU——OOM 几乎必然。 -
组件类型和函数签名要对齐:
inputs=gr.Image(type="pil")给函数的是PIL.Image;改成type="numpy"就是np.ndarray;改type="filepath"是磁盘路径字符串。函数里 assert 一下能少很多奇怪 bug。 -
session 概念隐式:Gradio 默认每个浏览器 tab 一个独立 session,
gr.State()维护 per-session 状态。但服务重启 state 全丢——长会话要落外部存储,框架不替你管。 -
Spaces 部署偶发拉不到依赖:
requirements.txt写了不一定按预期版本——加==锁定;用到系统库(ffmpeg / cuda)要写packages.txt。 -
5.0 升级有 break:Python 最低版本提到 3.10,部分组件 API 改名(
gr.outputs.Label→gr.Label),老教程跑 5.x 会报 ImportError——看官方迁移指南。
适用 vs 不适用场景
适用:
- ML / LLM 模型 demo——HuggingFace Spaces 一键部署、
ChatInterface一行搞定 LLM 试玩 - 研究室内部评测平台——多个模型并排、上传测试集、看混淆矩阵
- 给非工程同事或外部分享原型——
share=True直接发链接、72 小时够看一轮 - 单一函数包装——“输入 X 输出 Y”的封装天然契合
Interface
不适用:
- 复杂多页应用 / 数据探索面板——streamlit 的 rerun 模型在”调一调看一看”场景更顺
- 多用户隔离严格的生产应用——session 模型简单,权限 / 鉴权要自己接
- 高并发面向 C 端——单进程 + queue 不擅长万级 QPS,要前面套 nginx + 多副本
- SEO / 公开内容站——本质是 SPA,搜索引擎友好度差
学到什么
- 接口形态要贴合场景:ML demo 的本质是”函数试用台”,Gradio 的
Interface直接把”函数签名 + 输入输出类型”映射成 UI,比通用 Web 框架短一个数量级 - 组件懂数据形状:
gr.Label接 dict 出条形图、gr.Dataframe接 DataFrame 出表格——多态比类型安全更适合 demo 阶段 - 隧道 + 平台 = 体验飞跃:share 隧道把”本地能跑”和”同事能看”中间那道墙拆了;Spaces 又把”能看”和”能稳定服务”那道墙拆了
- 降低 demo 边际成本释放需求:研究员写完模型不用再求前端帮忙,Gradio 让”模型→可分享 URL”变成 git push——HuggingFace 收购买的就是这条曲线
延伸阅读
- 官方文档:Gradio Docs(Quickstart 一节即学即用)
- 收购公告:Gradio is joining Hugging Face(2021 年 12 月)
- Custom Components:gradio cc create(4.x 起的扩展机制)
- streamlit —— 同代 Python web 应用框架,思路不一样
- fastapi —— Gradio 3.0 起的后端 ASGI 引擎
- svelte —— Gradio 前端实现栈