老周在物流公司做数据。职位写着数据分析师,实际从写 SQL、清洗报关单到替财务拉月报都干。他只会 Python,前端经验停在大学时改过别人给的 HTML 模板。
去年十月,运营总监把他叫进会议室。客户问运费,销售现在都在微信里喊他,他手动跑一遍脚本,一天跑二十来次。总监想要一个网页:销售自己填重量、体积、目的地,页面直接出价格,最好还能导出报价单发给客户。
他回去搜了一晚上。”用纯 Python 写网页”这几个字把他带到 Reflex 官网(https://reflex.dev)。首页写得很动人,前后端都写 Python,不用碰 JavaScript。他 pip install reflex,reflex init,然后卡住了。初始化要拉前端依赖,公司网络对 npm 源不友好,第一次跑了二十分钟报错退出。第二天换了镜像源才算跑起来,localhost:3000 上出现了那个默认页面。他觉得自己成了。
真正的问题是第三天来的。他想在页面上放一个下拉框,选项从数据库读。文档说要把数据放进 State 类,用 computed var,还要注意 yield 和 async。照着抄能跑,改一个字段就报错,错误信息埋在前端编译日志里。一下午过去,他没弄明白为什么一个下拉框要写这么多东西。
那天晚上他停下来,问了自己一句更基本的话:我到底在做什么?
你交付的是一张页面,还是一个一直跑着的东西
这四个框架经常被放进同一张对比表,其实它们对”网页”这件事的理解完全不同。
Streamlit 的理解是:你有一个脚本,我给你一个网页外壳,每次有人动一下,我把你的脚本从头再跑一遍。Gradio 的理解是:你有一个函数,我给你一组输入框和一个输出框,把它包起来。NiceGUI 的理解是:你在后端建一棵界面对象树,浏览器只是这棵树的显示器。Reflex 的理解是:你用 Python 写组件,我把它编译成真正的前端应用,再配一个 Python 后端。
这四种理解,决定了后面几乎所有差异。
所以下面这张表我没有按性能、功能点去排,那些东西在内部工具这个场景里几乎不影响决策。我按真正会卡住人的五件事来排:授权能不能商用、部署要不要自己运维、前后端怎么分工、什么场景下最省事、第一版要花多久。
| Streamlit | Gradio | NiceGUI | Reflex | |
|---|---|---|---|---|
| 授权 | Apache 2.0 | Apache 2.0 | MIT | 框架 Apache 2.0,云服务另计费 |
| 部署方式 | streamlit run,或托管在 Community Cloud |
python app.py;加 share=True 得到临时公网地址;或放 Hugging Face Spaces |
python main.py,可 Docker 部署,也能开成桌面窗口 |
reflex run 本地开发,reflex deploy 上官方云,或自行打包 |
| 前后端怎么分工 | 服务端把整个脚本从头跑一遍,返回页面 | 前端是现成组件,事件直接调用你写的函数 | 后端持有界面对象,事件通过 WebSocket 回到后端 | Python 组件树编译成 React 前端,状态存在 Python 类里 |
| 适合的场景 | 报表、看板、参数调节页 | 模型试用、单函数演示、聊天界面 | 常驻操作台、仪器面板、需要实时刷新的小工具 | 多页面、要登录、要当产品长期维护的东西 |
| 上手成本 | 半天 | 一小时出 demo | 一到三天 | 一周起,取决于要补多少前端概念 |
竖着看每一列会发现,它们不是同一类东西的四个候选。Streamlit 和 Gradio 卖的是最快看到结果,NiceGUI 卖的是控制得住,Reflex 卖的是最后能长成一个正经应用。选错的代价不在写不出来,在你写出来三个月之后发现改不动。
Streamlit:把脚本变成页面,代价是每次都从头跑
最常见的 Streamlit 用法,是运营每天早上要看退货率。写的人是个做商品的小姑娘,三十来行代码:读一张表,st.dataframe 展示,st.slider 选时间范围,st.bar_chart 画图。她没学过 Web,streamlit run 一敲,浏览器自己弹出来,老板当天就在用。
Streamlit 的模型简单到粗暴:整个脚本就是一个函数,任何交互都让它从头执行。这件事在只读场景里几乎是免费的。你不需要理解状态,不需要理解渲染,改一行代码存盘,页面自己刷新,官方 README 管这个叫 live editing。
麻烦也来自这里。脚本重跑意味着每次点击都要把上面的代码再走一遍。老周在 Streamlit 上做第一版报价工具时,读价目表的操作每点一次都要重跑,他只能加 @st.cache_data。再往后,他想加一个”生成报价单编号”的按钮,发现点完页面一重跑,计数器就归零,得把数字塞进 st.session_state。这些坑文档里都写了,但每一个都在提醒你:你在跟一个没有真正状态的模型较劲。
Streamlit 是 Apache 2.0 授权,官方提供 Community Cloud 免费托管(https://streamlit.io/cloud)。规模上它是这四个里社区最大的,GitHub 上数万星(https://github.com/streamlit/streamlit)。有个细节容易忽略:README 里写明他们已经暂停接受维护团队之外的 PR。这不影响你用,但说明迭代节奏由 Snowflake 的团队掌握,碰到深层 bug 时,能做的通常只有等,或者绕过去。
一句话概括,只要你的页面长得像一张报表加几个筛选器,Streamlit 是这四条路里最短的那条。一旦页面开始有流程、有前后依赖的动作,它会开始跟你作对。
Gradio:它解决的是”让人试一下”
Gradio 的场景从来不是内部系统,是模型演示。
一个做图像分割的工程师要给客户看效果,客户不信,非要自己试。他写了二十行:gr.Interface(fn=predict, inputs=gr.Image(), outputs=gr.Image()),然后 demo.launch(share=True)。几秒后终端打印出一个 *.gradio.live 的地址,发给客户,客户在浏览器里传自己的图,看到了结果。整个计算还在他那台笔记本上跑。
这个 share=True 是 Gradio 最锋利的地方,它把一个部署问题压缩成了一个参数。官方文档里列了一整套内置组件,覆盖文本、图像、音频、视频、数据框这些模型最常见的输入输出(https://www.gradio.app/docs)。要复杂布局就用 gr.Blocks,做对话就用 gr.ChatInterface。它还有 gradio_client,别人可以用代码直接调你的应用,把它当接口用。
托管上它有两条现成的路:临时链接,或者 Hugging Face Spaces 免费跑(https://huggingface.co/spaces)。对做研究的人这几乎是最优解,不用买服务器,不用配域名,也不用管 HTTPS 证书。
代价是它的界面基因。Gradio 的组件都是为”输入进去、结果出来”设计的。你让它做带侧边栏、多页面、有用户权限的管理后台,会一路别扭,也能做,但写出来的代码处处透着”这本来是给演示用的”。它用 Apache 2.0 授权,商用没有授权上的障碍。
如果需求里有”让外面的人试一下”,Gradio 就是答案,不用犹豫。如果需求是”我们自己人天天用”,它大概率不是。
NiceGUI:给一台一直开着的机器配个界面
这个框架在国内讨论得少,但它的定位清楚到你看一眼就知道它想服务谁。
做非标自动化的人常遇到这样的场面:一台贴标机卖到食品厂,机器旁边挂一块十五寸的触摸屏,操作工要在上面改速度、改间距、看今天的计数。原来那套界面是别人用 PyQt 写的,改一个参数就得重新打包,装到工控机上。换成 NiceGUI 之后,界面就是一个 Python 文件,进程跑在工控机里,屏幕那头用浏览器打开,或者直接开成 NiceGUI 的桌面窗口。要调参数,远程连上去改两行,重启进程,两分钟的事。
这是 NiceGUI 官方介绍里明确写的适用场景:微型 Web 应用、看板、机器人项目、智能家居(https://nicegui.io)。它的技术栈是 FastAPI 做后端,Vue 和 Quasar 做前端,中间用 socket.io 挂着一条长连接,README 里把这套结构写得很细。你写的 ui.button(...)、ui.label(...) 在后端是真正的对象,浏览器里的 DOM 只是它们的投影。
这个模型带来两个别处没有的能力。一是实时,它内置定时器,官方说最短可以十毫秒刷一次,接串口、接 PLC、接传感器这种数据一直在变的活它接得住。二是它能直接开成桌面窗口,不用浏览器,对没有网络的车间很实用。
它的作者在 README 里写过一段动机:他们喜欢 Streamlit,但觉得它在状态处理上”魔法太多”。这句话解释了 NiceGUI 的全部取舍。你拿到的是显式的对象和显式的事件绑定,一个按钮点击就是一个 Python 函数,函数里改了哪个对象,页面上就变哪一块。没有整页重跑,也就没有”我的变量怎么被重置了”这类问题。
代价在社区规模。NiceGUI 由德国一家叫 Zauberzeug 的公司维护,MIT 授权(https://github.com/zauberzeug/nicegui),体量比 Streamlit 和 Gradio 小一个量级。碰到冷门问题,你能依靠的是 GitHub issue 和它自带的示例目录。工程上该有的它都有,pytest 测试框架、Docker 镜像、conda 包都齐,只是周边插件远没有 Streamlit 那边热闹。
如果你的页面要一直开着、数据一直在动、用的人就站在设备旁边,NiceGUI 是这四个里最对口的。它不负责给你做网站,它负责给你做操作台。
Reflex:它想让你做出一个产品
回到老周。他后来还是回到了 Reflex,因为他想清楚了自己要的不是一张报表。
他那套东西最后长成了这样:销售登录,选客户,填参数,看历史报价,点确认生成 PDF,经理那边能看到所有报价的审批状态。这不是脚本,这是个小系统。Streamlit 能做,但每一页都要重新想状态放哪;Gradio 根本不适合;NiceGUI 能做,可登录、路由、多页面这些得他自己搭。
Reflex 站的位置就在这里。它把你的 Python 组件树编译成真正的前端应用。你写 rx.vstack、rx.input、rx.button,浏览器里跑的是一个正常前端,路由、静态资源、页面标题都在。后端那边,状态就是你定义的 rx.State 子类,字段是普通的 Python 类型标注,改了就同步到前端。
这个设计换来的上限很高。它不像 Streamlit 那样受限于重跑脚本,也不像 Gradio 那样被组件形状绑住。你要做二十个页面、要做权限、要自定义样式,它都接得住。
成本集中在前三天。reflex init 会装一堆前端工具链,网络不好就是老周第一次踩的那个坑。概念上也比别家多:State、event handler、computed var、组件编译、var 操作。你得接受”我在写一个前端框架的 Python 绑定”,而不是”我在写脚本”。
商业上它分得很清楚。框架本身是 Apache 2.0(https://github.com/reflex-dev/reflex),自己部署不花钱。官方云从免费档开始,免费只能挂一个应用、额度有限;Pro 二十五美元起,按月给的额度同时用于 AI 生成和托管(https://reflex.dev/pricing)。这个价对个人开发者不算便宜,对一家公司来说,给内部工具每月付二十五美元,通常比让老周多折腾两周划算。
当你的东西需要像个产品,有账号、有多页、要交给别人长期用,Reflex 多出来的复杂度是值得付的。如果只是一张报表,它就是杀鸡用牛刀,而且这把刀还挺难磨。
怎么选:看交互的形状,不看星数
写完上面这些,选择已经不太需要”决策”了。你只要回答一个问题:用户打开这个页面之后,会做几次动作,这些动作之间有没有依赖。
只有一次动作,填完看结果,那就是 Gradio。gr.Interface 就是为这个形状造的。
动作很多,但都是筛一下看一遍,彼此独立,那就用 Streamlit。它的重跑模型在只读场景下不产生任何成本,你省下的是全部的状态管理。
动作之间互相影响,页面要一直开着,数据自己会变,那就是 NiceGUI。你需要的是对象和事件,不是脚本。
动作组成一条流程,还要分人、分权限、分页面,那就是 Reflex。你要的其实是一个应用框架,只是碰巧用 Python 写。
星数在这个判断里几乎没用。Streamlit 的星最多,因为它门槛最低;Gradio 的星也多,因为做模型的人基数大。星数说明的是多少人曾经试过,不说明多少人还在用,更不说明它适合你的场景。
还有一个常被忽略的变量:这东西要活多久。一次性的分析页面,用 Streamlit 两天写完扔掉,是最优解。要活两年的内部系统,第一版慢一周换来的可维护性,会在第六个月全部还给你。老周第一版用 Streamlit 一周交付,财务用得很开心;三个月后需求变成”客户自己登录查报价”,他重写成了 Reflex。那三个月的代码基本没白写,因为业务逻辑是纯 Python 函数,搬过去只动了界面层。
这也是这四家共同的善意:业务代码都是普通 Python,界面层是可以换的。真正把你锁死的从来不是框架,是你把业务逻辑写进了界面回调里。
老周最后交了什么
他交了两个东西。
给财务的,是一个 Streamlit 页面,四十七行,读一张每天凌晨同步的表,选月份,出汇总,能下载 Excel。写完那天下午就上线,财务在群里发了个大拇指。
给销售的,是一个 Reflex 应用,登录、选客户、算价、出 PDF、留痕。做了三周,中间因为 npm 源的问题多花两天。上线之后销售不再在微信里喊他,改成在系统里提单,出错了他能查到是谁在哪一步改了什么。
他后来的说法是,一开始以为自己是在选框架,选到最后发现是在选这东西算谁的活。用 Streamlit 写的那个,是财务的活;用 Reflex 写的那个,是他的活。
这大概是这类选型里最实在的一条标准。你愿意为它调到晚上十点,就选那个能长成大东西的;你只想明天上午交差,就选那个半小时能跑起来的。
文中的老周是综合几类常见场景虚构的人物。涉及的授权、托管与定价信息分别来自各项目仓库与官网:https://github.com/reflex-dev/reflex、https://github.com/streamlit/streamlit、https://github.com/zauberzeug/nicegui、https://github.com/gradio-app/gradio。



