从“加载模型”界面到端侧推理:拆解一个 React + WebGPU 大模型 Demo
这个项目还没有真正把大模型跑起来但它已经把端侧 AI 应用最重要的 UI 骨架搭好了能力检测、加载状态、错误出口、下载进度和输入交互。本文从现有代码出发梳理它已经完成的部分以及接入真实推理链路还差什么。每次调用云端大模型 API输入内容都要离开浏览器还会受到网络、额度和服务可用性的影响。另一条路线是把模型和推理放在用户设备上模型首次下载到浏览器缓存后续由本机 GPU 或 CPU 执行用户的提示词不必为了推理而发送到业务服务器。deepseek-r1-webgpu正是在探索这条路线。项目的页面描述指向DeepSeek-R1-Distill-Qwen-1.5B-ONNX、Transformers.js、ONNX Runtime Web 和 WebGPU代码则先实现了一个 React TypeScript Vite Tailwind CSS 的交互骨架。先说明本文的边界当前仓库尚未安装或调用huggingface/transformers、onnxruntime-web也没有模型下载与文本生成代码。点击Load Model只会把status从0改为loading。因此它是一个很适合学习前端状态设计的端侧 AI 页面原型而不是已经可推理的完整应用。项目先解决了什么问题入口src/main.tsx使用 React 19 的createRoot挂载App并由 Vite 插件启用 React 与 Tailwind CSS。页面主逻辑在src/App.tsx可先把它看成一台由状态驱动的界面机器const [inputValue, setInputValue] useState(); const [status, setStatus] useState(0); const [error, setError] useState(null); const [loadingMessage, setLoadingMessage] useState(开始加载); const [progressItems, setProgressItems] useState([]); const isWebGpuAvailable !!navigator.gpu;这些变量对应的并不是某几个散落的 DOM 节点而是页面的业务状态状态当前用途应驱动的界面isWebGpuAvailable检测浏览器是否暴露 WebGPU API主界面或“不支持 WebGPU”提示status初始、加载、就绪等模型生命周期按钮可用性、输入框可用性、进度区error失败原因错误文案与重试入口progressItems模型文件下载事件多条下载进度条inputValue用户正在输入的问题受控textarea与 Enter 发送这种写法的价值在于界面不再由“找到某个元素再改样式”的命令式 DOM 操作拼出来。状态变化后React 重新执行组件函数再根据条件渲染对应 UIdisabled{status ! 0 || error ! null} {status loading LoadingPanel /} textarea disabled{status ! ready} /Load Model只有在初始状态且没有错误时可点击模型未就绪时文本框保持禁用。即便真实模型逻辑还没接入这两个约束已经避免了“模型还没加载完用户就发送请求”的无效交互。第一层降级先判断 WebGPU 能力项目使用下面的判断const isWebGpuAvailable !!navigator.gpu;navigator.gpu是浏览器提供 WebGPU 接口时暴露的入口。双重否定把可能为undefined的值转换成清晰的布尔值随后组件在支持与不支持之间选择不同视图return isWebGpuAvailable ? MainPage / : div您的浏览器还不支持 WebGPU/div;这是合理的第一步不过它只回答“浏览器有没有 API”并不保证设备一定能完成模型推理。真实接入时还应调用navigator.gpu.requestAdapter()并处理拿不到 adapter 或设备创建失败的情况。错误状态应该把这些失败呈现给用户而不是只停留在控制台。这里也有一个产品取舍如果应用目标必须依赖 GPU明确告知不支持是最诚实的方案如果希望覆盖更多设备可以把 WebGPU 作为优先后端再提供 WASM/CPU 作为性能较低的回退。是否回退取决于模型体积、内存占用和可接受的响应时间不是一条单纯的 API 判断。进度条为何要拆成组件src/components/Progress.tsx把一条下载项的展示抽成组件Progress key{index} text{text} percentage{percentage} total{total} /组件内部把百分比映射为宽度并将字节数格式化成用户可读的单位percentage ?? 0; div style{{ width: ${percentage}% }} classNamebg-blue-400 h-2 /这对应模型加载的真实形态一个“模型”通常不是一份孤立文件配置、分词器、权重分片和 ONNX 图都可能分别下载。父组件持有下载项数组子组件只按 props 渲染最适合表达这种一对多关系。后续对接运行库时进度回调应只更新父组件的数组。下面是与当前页面结构匹配的示意代码并非仓库已有实现type ProgressItem { text: string; percentage?: number; total?: number; }; function updateProgress(item: ProgressItem) { setProgressItems((previous) { const index previous.findIndex((entry) entry.text item.text); if (index -1) return [...previous, item]; return previous.map((entry, currentIndex) currentIndex index ? { ...entry, ...item } : entry, ); }); }注意这里使用函数式更新。下载事件可能连续到达下一次数组取决于前一次数组时用setProgressItems(previous ...)能避免闭包拿到旧值。渲染列表的key也建议使用稳定的文件名或路径而不是数组下标下载项顺序变化时稳定 key 才能让 React 正确复用节点。受控输入与发送时机底部输入框采用受控组件textarea value{inputValue} disabled{status ! ready} onInput{(event) { const target event.target as HTMLTextAreaElement; setInputValue(target.value); }} onKeyDown{(event) { if (inputValue.length 0 event.key Enter !event.shiftKey) { event.preventDefault(); onEnter(); } }} /它的行为很符合聊天产品普通 Enter 发送Shift Enter 保留换行。代码还在事件中通过类型断言把event.target视为HTMLTextAreaElement这样 TypeScript 才能安全读取value。当前onEnter只将状态设置为loading没有真正把输入交给模型。接上推理后建议把“模型正在下载”和“模型正在生成”拆开而不是共用一个模糊的loading。例如type ModelStatus idle | downloading | ready | generating | error;用联合类型代替字符串0可以让编辑器检查拼写也能让状态分支更易读。生成期间禁用重复发送按钮结束或失败后回到ready聊天体验会更完整。真正的端侧推理链路长什么样要让“Load Model”不再只是切换页面状态需要把页面状态与模型运行时连接起来。结合项目已有的模型链接最小闭环可以拆为六步检查 WebGPU 并请求 adapter/device失败时进入可见的错误或回退状态。首次点击后加载模型配置、分词器和 ONNX 权重利用运行库的进度回调更新progressItems。创建可复用的模型或pipeline实例完成后将状态设为ready。用户提交文本后将 prompt 经过 tokenizer 编码为 token。推理后端在浏览器的本机设备上逐步生成 token生成过程可持续刷新输出区。解码为文本并追加到会话缓存命中时后续访问可跳过或减少下载。“端侧”不等于模型文件永远不接触网络。首次加载仍需从模型托管服务获取资源除非它们已经在浏览器缓存中真正的边界是完成加载后推理提示词和生成计算可留在本机执行。生产应用仍需审视模型来源、资源完整性、缓存策略以及浏览器存储配额。当前工程还需要补的两处基础工作执行npm run build时当前项目会在 TypeScript 检查阶段停止。原因包括App.tsx中setError、setLoadingMessage、setProgressItems还没有被使用Progress.tsx的 props 没有类型并且该文件保留了未使用的zod导入。项目的tsconfig.app.json启用了strict、noUnusedLocals和noUnusedParameters所以这些教学阶段的占位代码会被严格检查出来。这是一个很好的提醒TypeScript 不是等所有功能做完才开启的装饰。把状态模型和组件 props 定义清楚能让“UI 正在等待什么、谁可以修改这个数据”在编译期就被约束。例如进度条可以先定义一个明确的契约type ProgressProps { text: string; percentage?: number; total?: number; }; function Progress({ text, percentage 0, total }: ProgressProps) { // render... }同时未接入的 setter 应暂时移除或在真正的模型加载、报错和回调逻辑接入后再使用。这样npm run build才能成为可信的交付检查。小结这个项目最值得学习的不是“已经在浏览器跑通 DeepSeek-R1”而是它为端侧 AI 建立了正确的前端分层用 WebGPU 能力检测决定入口体验。用 React 状态驱动加载、就绪、错误与交互禁用。用父组件数组和Progress子组件表达多个文件的下载反馈。用受控输入把键盘行为收束为可预测的状态更新。用 TypeScript 严格检查为真实运行时接入留出边界。模型运行时接入以后UI 层不需要推倒重来只需让运行库的下载、加载和生成事件进入现有的状态机。对学习端侧大模型应用而言这正是最可靠的起点先把用户能看见、能恢复、能理解的状态做对再把模型接进去。

相关新闻

如何快速使用TranslucentSM:让Windows开始菜单透明化的完整指南

如何快速使用TranslucentSM:让Windows开始菜单透明化的完整指南

如何快速使用TranslucentSM:让Windows开始菜单透明化的完整指南 【免费下载链接】TranslucentSM A lightweight utility that makes the Windows Start Menu translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentSM 想要为Win…

2026/7/30 4:03:34阅读更多 →
STM32定时器深度解析:从HAL库配置到电机控制与编码器应用实战

STM32定时器深度解析:从HAL库配置到电机控制与编码器应用实战

1. 从“点灯”到“心跳”:为什么定时器是STM32的基石如果你刚开始接触STM32,可能觉得HAL库的定时器(Timer)就是个用来做“精准延时”或者“闪灯”的工具。我最初也是这么想的,直到在一个电机控制项目里,因为…

2026/7/30 4:03:34阅读更多 →
Vue3(篇五)pinia状态管理——跨组件数据共享

Vue3(篇五)pinia状态管理——跨组件数据共享

目录前言一、为什么需要状态管理?1.1 组件通信的困境1.2 状态管理的本质二、Pinia 是什么?2.1 Pinia vs Vuex2.2 Pinia 的核心概念三、安装与配置3.1 安装3.2 挂载到应用四、定义 Store4.1 基本结构4.2 组合式 API 风格(推荐)五、…

2026/7/30 4:03:34阅读更多 →
信赖域优化方法:从核心原理到Python实现详解

信赖域优化方法:从核心原理到Python实现详解

1. 项目概述:从“走一步看一步”到“谋定而后动”的优化哲学在解决工程、金融、机器学习等领域的复杂优化问题时,我们常常面临一个核心矛盾:如何平衡“局部探索”的精度与“全局推进”的效率?想象一下,你在一片浓雾笼罩…

2026/7/30 5:25:52阅读更多 →
基于Apache POI的poi-tl模板引擎:Java动态生成Word文档的声明式解决方案

基于Apache POI的poi-tl模板引擎:Java动态生成Word文档的声明式解决方案

1. 项目概述:为什么我们需要一个“聪明”的Word模板引擎?如果你做过企业级应用开发,尤其是涉及报表、合同、通知单这类需要动态生成Word文档的业务,大概率对Apache POI这个名字不会陌生。它是一个强大的Java库,能让你用…

2026/7/30 5:25:52阅读更多 →
PLC编程指令实战指南:从信号流、数据流到时间流的系统化应用

PLC编程指令实战指南:从信号流、数据流到时间流的系统化应用

1. 项目概述:从“指令”到“逻辑”的桥梁干了十几年自动化,从三菱FX系列玩到西门子S7-1500,再到现在各种国产品牌,我越来越觉得,PLC编程的核心,其实就藏在这些看似枯燥的“指令”里。很多人觉得PLC编程就是…

2026/7/30 5:25:52阅读更多 →
X-AnyLabeling终极指南:免费高效的AI图像标注工具,10倍提升标注效率

X-AnyLabeling终极指南:免费高效的AI图像标注工具,10倍提升标注效率

X-AnyLabeling终极指南:免费高效的AI图像标注工具,10倍提升标注效率 【免费下载链接】X-AnyLabeling Open-source AI-assisted annotation platform for images, videos, text, and multimodal data. 项目地址: https://gitcode.com/gh_mirrors/xa/X-A…

2026/7/30 5:25:52阅读更多 →
逆向实战:深度解析抖音a_bogus参数JSVMP保护与算法还原

逆向实战:深度解析抖音a_bogus参数JSVMP保护与算法还原

1. 项目概述:深入抖音核心加密算法最近在逆向分析领域,抖音的a_bogus参数无疑是一个热门且极具挑战性的目标。这个参数是抖音Web端和部分客户端接口请求中一个至关重要的签名,用于验证请求的合法性,防止未经授权的数据抓取和接口滥…

2026/7/30 5:25:52阅读更多 →
AI教育系统如何优化教学课题设计与实施

AI教育系统如何优化教学课题设计与实施

1. 项目概述:AI如何重塑教育课题设计流程去年帮某师范院校评审研究生开题报告时,我发现一个惊人现象:超过60%的选题要么脱离教学实际,要么缺乏可操作性。直到接触了百考通AI系统,才意识到传统选题模式的根本问题在于缺…

2026/7/30 5:23:52阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/29 9:47:45阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/29 7:00:19阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/29 7:58:51阅读更多 →
3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 [特殊字符]

3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 [特殊字符]

3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 🚀 【免费下载链接】TrollInstallerX A TrollStore installer for iOS 14.0 - 16.6.1 项目地址: https://gitcode.com/gh_mirrors/tr/TrollInstallerX 你是否曾经因为iOS系统的严格…

2026/7/30 0:00:58阅读更多 →
[GESP202606 四级] 扫雷

[GESP202606 四级] 扫雷

B4557 [GESP202606 四级] 扫雷 https://www.luogu.com.cn/problem/B4557 中国计算机学会(CCF)2026年6月C四级讲解——扫雷 https://www.bilibili.com/video/BV1MCMg6AEXR/ B4557 [GESP202606 四级] 扫雷 https://www.bilibili.com/video/BV1ZKTj6ZEVh/ 2…

2026/7/30 0:00:58阅读更多 →
Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 您是否曾因Windows系统盘空间不足而烦恼?是否遇到过设…

2026/7/30 0:00:58阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/30 0:27:26阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/30 4:47:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/29 14:26:42阅读更多 →