
RunAnywhere Web SDK 的 ONNX WebGPU 双构建方案浏览器端 STT/TTS/VAD 与 Embeddings 的 GPU 加速实战【免费下载链接】runanywhere-sdksProduction ready toolkit to run AI locally项目地址: https://gitcode.com/gh_mirrors/ru/runanywhere-sdks导读本文围绕 RunAnywhere Web SDK 中bindings/web/docs/ONNX_WEBGPU.md描述的CPU WebGPU 双 WASM 构建twins方案展开同一套 RACommons ONNX Runtime Sherpa 代码如何分别产出racommons-onnx-sherpa.{js,wasm}与racommons-onnx-sherpa-webgpu.{js,wasm}两套自包含产物让浏览器中的语音识别STT、语音合成TTS、语音活动检测VAD与 ONNX Embeddings 在具备 WebGPU 能力的浏览器中自动走 GPU 加速并在不可用时诚实地回退到 CPU。读完本文你将掌握这套双构建的目录布局、ONNX.register()的完整参数语义、从 vendoring 到发布验证的完整构建流程以及 ORT WebGPU EP 探针的底层实现原理。为什么需要双胞胎构建而不是一个带开关的 WASM浏览器端跑 ONNX RuntimeORT有两种执行提供者Execution ProviderCPUWASM 线程 SIMD与 WebGPU经由 Dawn/emdawn 桥接到浏览器navigator.gpu。RunAnywhere Web 的做法不是构建一个同时内嵌两套执行路径的巨型模块而是产出两个孪生 WASM 目标维度CPU 构建WebGPU 构建ORT 归档core/third_party/onnxruntime-wasm/core/third_party/onnxruntime-wasm-webgpu/Vendor 脚本bindings/web/wasm/scripts/vendor-onnxruntime-wasm.shbindings/web/wasm/scripts/vendor-onnxruntime-wasm-webgpu.shWASM 产物racommons-onnx-sherpa.{js,wasm}racommons-onnx-sherpa-webgpu.{js,wasm}WASM 产物目录bindings/web/packages/onnx/wasm/bindings/web/packages/onnx/wasm/从 bindings/web/wasm/CMakeLists.txt 可以看到RAC_WASM_ONNX开关控制racommons-onnx-sherpa目标的构建而RAC_WASM_ONNX_WEBGPU额外产出 WebGPU 变体option(RAC_WASM_ONNX Build the ONNX Sherpa Web SDK WASM target OFF) option(RAC_WASM_ONNX_WEBGPU Emit racommons-onnx-sherpa-webgpu (ORT WebGPU EP path) OFF)分离树的原因provenance 与构建缓存采用两棵独立 vendor 树而非一个脚本加个--webgpu标志的理由在文档中有明确交代且与 llama.cpp 的双构建模式保持一致Provenance 可追溯webgpuon这一属性只出现在 GPU 归档的.rac-wasm-provenance文件中CPU 归档绝不携带该标记。vendor 脚本会在归档头部写入componentonnxruntime-wasm-webgpu、threadson、webgpuon、recipe_schema7-webgpu等 provenance 字段见 vendor-onnxruntime-wasm-webgpu.sh构建前可用RAC_WASM_PROVENANCE_CHECK_ONLY1做幂等校验。构建缓存不冲突WebGPU 变体使用独立的 ORT 构建目录build/OS-webgpu/Release与 CPU 的build/MacOS/Release或 Linux分开避免 Dawn/ORT 并行编译时的缓存碰撞。Dawn emdawn JS 的暂存策略WebGPU 变体依赖 ORT 源码树中 Dawn 生成的 emdawn JS 胶水文件library_webgpu_enum_tables.js、library_webgpu_generated_sig_info.js、library_webgpu_generated_struct_info.js、library_webgpu.js等。脚本的write_dawn_link_hints()会把这些文件复制到onnxruntime-wasm-webgpu/emdawn/并生成.rac-webgpu-link-hints提示文件这样 ORT 的源码build/目录在 vendoring 完成后即可安全删除--onnx-webgpu的最终链接不再依赖它。ONNX.register()加速模式与线程的完整语义TS 侧入口是 bindings/web/packages/onnx/src/ONNX.ts 中的ONNX.register()。其核心签名与文档一致ONNX.register({ acceleration: auto | cpu | webgpu, threads })acceleration 三档语义取值行为auto默认浏览器 WebGPU、WebGPU 产物、ORT WebGPU EP 探针三者全部成功时启用 WebGPU任一失败则回退 CPU并通过ONNX.lastFallbackReason暴露原因webgpu强制要求真实 WebGPU EP探针失败直接throw绝不静默降级cpu只加载 CPU 产物不看 GPU 能力关键设计原则是**诚实加速honest accel**ONNX.accelerationMode只有在 ORT 的AppendExecutionProvider(WebGPU)真正成功后才返回webgpu。这一点在 workerOnnxRuntime.ts 的文件头注释中被明确写为纪律Never reportacceleration: webgpuunless the ORT append probe succeeds.threads 徽章的真相不是多 GPUONNX.register({ threads })中的threads是Sherpa/ORT 的 intra-op 线程数pthread被钳制在 1–8 之间UI 上展示的×N徽章指的就是这个线程数而不是多张 GPU 并行。代码中的钳制逻辑clampThreads在两处一致实现// bindings/web/packages/onnx/src/ONNX.ts function clampThreads(value: number | undefined): number { if (value null || !Number.isFinite(value)) return 2; // 默认 2 return Math.max(1, Math.min(8, Math.floor(value))); }默认示例使用threads: 2。线程计数会在加载路径上通过导出函数_rac_onnxrt_set_wasm_thread_counts(intraOp, interOp)写入 WASM 侧interOp 固定为 1并且在 ORT EP 探针之前完成配置见下文原理节。其余注册选项ONNXRegisterOptions还包含wasmUrl/webgpuWasmUrl分别覆盖 CPU 胶水文件racommons-onnx-sherpa.js与 WebGPU 胶水文件racommons-onnx-sherpa-webgpu.js的加载 URLbackendWorkerFactory/preferBackendWorker/requireBackendWorker控制 STT/TTS/VAD 是否在 Web Worker 中执行。浏览器环境默认requireBackendWorker: truefail-closed与 LlamaCPP 一致主桥保持在 CPU 侧以避免双堆 GPU 争用——加速推理归 Worker 所有注册成功后可用ONNX.accelerationMode、ONNX.threads、ONNX.lastFallbackReason、ONNX.lastWorkerDiagnostics做诊断展示。示例用法来自 packages/onnx/README.md 与 ONNX.ts 的注释import { RunAnywhere, SDKEnvironment } from runanywhere/web; import { ONNX } from runanywhere/web-onnx; await RunAnywhere.initialize({ environment: SDKEnvironment.SDK_ENVIRONMENT_DEVELOPMENT }); await ONNX.register({ acceleration: auto, threads: 2 }); await RunAnywhere.completeServicesInitialization(); const transcript await RunAnywhere.transcribe(audioSamples, { sampleRate: 16_000 });构建与发布流程完整构建链路定义在 bindings/web/package.json 的 npm scripts 中# 从 bindings/web 目录执行 source emsdk/emsdk_env.sh npm run vendor:wasm:speech # CPU ORT WebGPU ORT Sherpa 三份 vendor npm run build:wasm:all # 含 --onnx-webgpuvendor:wasm:speech实际展开为三个子步骤vendor:wasm:speech: npm run vendor:wasm:onnxruntime npm run vendor:wasm:onnxruntime-webgpu npm run vendor:wasm:sherpabuild:wasm:all则依次构建核心、llamacpp、onnx、webgpu、rag 与 onnx-webgpu 各目标build:wasm:all: npm run build:wasm -- --core --llamacpp --onnx npm run build:wasm -- --webgpu --rag npm run build:wasm -- --onnx-webgpuvendor 脚本的硬性要求vendor-onnxruntime-wasm-webgpu.sh 是 WebGPU 变体的权威 vendor 入口它有几个值得注意的工程细节Emscripten 版本锁定require_canonical_emscripten()会比对emcc --version与VERSIONS中锁定的EMSCRIPTEN_VERSION不一致直接失败源码 revision 校验ensure_source_checkout()要求 ORT checkout 的 HEAD 必须等于ONNX_COMMIT_WEB防止不可复现构建emsdk 路径陷阱脚本将 canonical emsdk 以 APFS clone或 rsync 回退暂存到 ORT 本地cmake/external/emsdk因为符号链接会让 emcc 的 sanity hash 在 symlink/realpath 间翻转从而中途清空 sysroot 缓存Python 版本门禁Emscripten 6 要求 Python ≥ 3.10脚本会显式导出EMSDK_PYTHON并同时固定PYTHON/Python_EXECUTABLE/Python3_EXECUTABLE防止宿主机 Anaconda 的旧 Python 被 CMake 误发现符号审计构建产物通过llvm-nm审计 protobuf 命名空间遮蔽google::rac_ort_protobuf不允许未遮蔽的google::protobuf符号与 Abseil EM_JS 遮蔽并确认归档包含 WebGPU 符号构建标志--use_webgpu --enable_wasm_simd --enable_wasm_threads --build_wasm_static_lib且通过-Dprotobufrac_ort_protobuf等宏做符号遮蔽避免与主模块冲突。不要回归WebGPU EP 的编译宏纪律文档与 runtimes/onnxrt/CMakeLists.txt 都强调了一条硬性规则WebGPU 孪生目标必须让rac_runtime_onnxrt以RAC_ONNXRT_EP_WEBGPU_ENABLED编译绝不要#define RAC_ONNXRT_EP_WEBGPU——因为RAC_ONNXRT_EP_*是rac_onnxrt_runtime_ep.h中的枚举值用作宏会与枚举冲突。仅靠最终 WASM 可执行文件的COMPILE_DEFS不够。CMake 注释解释了原因最终.js/.wasm可执行文件上的 COMPILE_DEFS不会传播进静态库rac_runtime_onnxrt因此该宏必须落在静态库自身的编译定义上否则probe_webgpu_ep()会被编译成 stub返回CAPABILITY_UNSUPPORTED导致探针永远失败。CMake 侧通过nm扫描归档中是否存在WebGpuExecutionProvider符号来自动决定是否启用# runtimes/onnxrt/CMakeLists.txt (Emscripten 分支摘要) if(_rac_onnxrt_webgpu_ep) target_compile_definitions(rac_runtime_onnxrt PRIVATE RAC_ONNXRT_EP_WEBGPU_ENABLED) else() message(STATUS ONNX Runtime WebGPU EP: unavailable in selected artifact; CPU fallback only) endif()底层原理WebGPU EP 探针与诚实回退Worker 侧加载逻辑位于 workerOnnxRuntime.ts 的WorkerOnnxRuntime类其tryLoadPath()是完整的加载流水线浏览器 WebGPU 预检detectWebGPU()检查navigator.gpu?.requestAdapter是否存在且 adapter 是否支持shader-f16feature——这是 ORT WebGPU 的实际运行前提动态 import 胶水按acceleration选择racommons-onnx-sherpa.js或racommons-onnx-sherpa-webgpu.js与 llama 一致不做 HEAD/Range 预检因为 Vitefs常拒绝这类请求导致误跳过 WebGPU 孪生直接尝试 import、失败再回退WASM ping调用_rac_wasm_ping()验证模块可运行返回值必须为42初始化平台适配器new PlatformAdapter(...)→register()→ 分配rac_config结构 →rac_init()→ 设置模型基目录/opfs线程池先行setThreadCounts()通过_rac_onnxrt_set_wasm_thread_counts(threads, 1)配置 intra-op 线程必须在 SharedOrt / EP 探针之前EP 探针与激活activatePreferredEp(preferWebGPU)调用导出符号_rac_onnxrt_activate_preferred_wasm_ep(1)或_rac_onnxrt_probe_webgpu_ep。这里有一个关键细节WebGPU 孪生是以 Asyncify 方式链接的EP 探针/append 可以穿过 Dawn 的等待并返回 Promise所以代码用Promise.resolve()吸收返回值后再与1比较——如果同步 1检查即使有真实 WebGPU EP 也会永远失败并诚实回退到 CPUSherpa provider 同步_rac_sherpa_set_wasm_compute(threads, provider)把webgpu或cpu字符串传给 Sherpa后端注册依次调用rac_backend_onnx_register与rac_backend_sherpa_registerRAC_ERROR_MODULE_ALREADY_REGISTERED视为成功健康上报Worker 将acceleration、threads、fallbackReason、最近 40 行 diagnostics 回传主线程最终决定ONNX.accelerationMode/ONNX.lastFallbackReason。auto模式下的失败路径会先teardown()卸载 WebGPU 模块释放独立 heap再加载 CPU 产物webgpu强制模式下任何失败都直接抛出附带_rac_onnxrt_last_webgpu_probe_error()读到的探针错误详情。发布门禁Gate与验证文档给出的发布验证要点与 web-lane-e2e.mjs、web-lane-finalize.mjs 等脚本所守护的检查一致产物非空两对 speech WASM 产物CPU 与 WebGPU 的{js,wasm}都必须存在demo release 依赖demo 仓库RunanywhereAI/runanywhere-web与本仓库平级克隆的release.sh要求dist中包含 WebGPU 产物对浏览器 COI 检查在跨源隔离COOP/COEP的浏览器会话中UI 应显示Speech/Embeddings: WebGPU且ONNX.lastFallbackReason null或读取__RUNANYWHERE_ONNX_DIAG__诊断全局强制模式必须失败当 WebGPU 孪生/探针损坏时强制webgpu必须throw而不是假装成功——这是诚实加速在发布链路上的最终保障。注意pthread 支撑的 ONNX BackendWorker WASM 依赖crossOriginIsolatedSharedArrayBuffer 前提。ONNX.register()在发现globalThis.crossOriginIsolated false时会打 warning提示生产环境必须以 COOP/COEP 头提供页面README 也要求按 bindings/web/README.md 配置跨源隔离头。线程浸泡测试可选文档最后建议的可选压力测试在 COOP/COEP 下对 Whisper Tiny、Canary、Nemotron 三组模型分别以线程数 1/2/4 运行测量 wall time 与是否出现Aborted()。这用于验证多线程 WASM 在长语音会话下的稳定性与线程收益曲线——threads的合理取值1–8与具体模型、硬件相关建议按实测数据选择默认值而不是盲目调高。小结RunAnywhere Web SDK 的 ONNX WebGPU 双构建方案用两棵 vendor 树 两个 WASM 孪生 一个诚实探针的组合在浏览器端同时拿到了 CPU 的兼容性与 WebGPU 的加速能力auto模式让支持 WebGPU 的浏览器自动加速语音与 EmbeddingslastFallbackReason让降级原因透明可见强制webgpu模式则为追求确定性的场景提供了失败即报错的严格语义。无论是想快速接入ONNX.register({ acceleration: webgpu })还是想复现整条vendor → build → release流水线本文所梳理的脚本、宏纪律与探针原理都能直接指导你的实践。关键参考路径构建入口与 npm scriptsbindings/web/package.jsonWebGPU ORT vendor 脚本bindings/web/wasm/scripts/vendor-onnxruntime-wasm-webgpu.shWASM 目标与开关定义bindings/web/wasm/CMakeLists.txtEP 编译宏与自动探测runtimes/onnxrt/CMakeLists.txt注册 API 与诊断字段bindings/web/packages/onnx/src/ONNX.tsWorker 侧加载与 EP 探针bindings/web/packages/onnx/src/workerOnnxRuntime.ts包使用示例bindings/web/packages/onnx/README.md【免费下载链接】runanywhere-sdksProduction ready toolkit to run AI locally项目地址: https://gitcode.com/gh_mirrors/ru/runanywhere-sdks创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考