ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RunAnywhere Flutter SDK 深度解析:基于 Dart FFI 的端侧 AI 多后端架构与实战指南

RunAnywhere Flutter SDK 深度解析:基于 Dart FFI 的端侧 AI 多后端架构与实战指南 AI模型推理服务推理引擎本地部署多模态【免费下载链接】runanywhere-sdksProduction ready toolkit to run AI locally项目地址https://gitcode.com/gh_mirrors/ru/runanywhere-sdks点击查看免费下载RunAnywhere Flutter SDK 是 RunAnywhere 项目在 iOS / Android 上提供的端侧 AI SDK它通过 Dart FFI 直连共享 C 核心runanywhere-commons/RACommons与各后端引擎实现了 LLM、VLM、STT、TTS、VAD、RAG 等能力的纯本地推理。本文以 bindings/flutter/AGENTS.md 为主线骨架结合仓库源码与配套文档系统讲解其多包仓库结构、FFI 分层架构、两阶段初始化、四大后端注册机制、平台原生库加载、流式回调安全模型以及完整的开发命令与版本清单帮助读者理解如何接入、如何扩展、以及踩坑时该往哪里查。一、SDK 是什么无平台通道的端侧 AI 基础设施RunAnywhere Flutter SDK 的定位是生产可用的端侧 AI SDK。它的设计目标在 bindings/flutter/docs/ARCHITECTURE.md 中有明确表述可以归纳为四条模块化后端每个后端LlamaCpp、Apple MLX、ONNX/Sherpa、QHexRT都是一个独立的 Flutter 插件包通过共享的 C ABI 注册到 C 核心。原生层干活C 核心拥有注册表registry、事件events、路由router、HTTP 与下载等基础设施Dart 只做编排把 proto 消息在 C 与 App 之间搬运。AI 推理不走平台通道所有推理调用都经过dart:ffi没有 MethodChannel / EventChannel 参与。Proto 是唯一的跨端类型契约所有跨平台类型在idl/*.proto中定义代码生成到lib/generated/没有手写枚举。从调用链上看一次推理请求的路径是Flutter App → RunAnywhere 静态命名空间17 个能力命名空间 getter → lib/native/dart_bridge_*.dart38 个 FFI slice每个对应一个 C 子系统 → NativeFunctions / PlatformLoader缓存的符号查找 DynamicLibrary 加载 → RACommons C 核心模块注册表、服务注册表、事件、路由 → 后端引擎 vtableLlamaCpp / Sherpa-ONNX / QHexRT完整的架构图与每个模式的设计取舍见 bindings/flutter/docs/ARCHITECTURE.md 的 §2.2 与 §4。二、仓库结构Melos 管理的五包 Monorepobindings/flutter/是一个由 Melos 管理的 Dart workspace monorepo包含5 个 Flutter 插件包全部通过 Dart FFI 包装共享的 C 核心RACommonsAI 推理不走平台通道bindings/flutter/ ├── pubspec.yaml # Dart workspace Melos 配置 ├── analysis_options.yaml # 严格 lint 规则 ├── scripts/package-sdk.sh # 打包/校验脚本 ├── docs/ # ARCHITECTURE.md、Documentation.md、DEVELOPMENT.md └── packages/ ├── runanywhere/ # 核心 SDKFFI 桥、公共 API、事件、模型 ├── runanywhere_llamacpp/ # LlamaCpp 后端LLM VLM ├── runanywhere_mlx/ # Apple MLX 后端LLM VLM embeddings STT TTS仅真机 iOS ├── runanywhere_onnx/ # Sherpa/ONNX Runtime 后端STT TTS VAD └── runanywhere_qhexrt/ # QHexRT Qualcomm Hexagon NPU 后端仅 Android其中四个后端包都依赖runanywhere ^0.20.36核心包内置了RACommons每个后端包各自内置自己的 XCFramework /.so文件。示例应用位于bindings/flutter/example/其example/scripts/verify.sh是干净克隆场景下的构建门禁。从源码布局看bindings/flutter/packages/runanywhere/lib/核心包的lib/native/目录下存在 41 个 Dart 文件38 个一个 C 子系统一个 slice的dart_bridge_*.dart、1 个dart_bridge.dart协调器、以及native_functions.dart缓存 FFI 函数指针查找注册表和platform_loader.dart平台相关的DynamicLibrary加载策略两个支撑模块。slice 集合已经超出早期文档记载的33 个——diarization、segmentation、rerank、secure_storage、hf_auth、cua是配合 ABI v9 基础类型集新增的判断当前 slice 数量应以ls lib/native/为准。核心包源码布局速览packages/runanywhere/lib/ ├── runanywhere.dart # Barrel约 150 个 re-export ├── runanywhere_protos.dart # Proto re-export 枢纽 ├── core/native/rac_native.dart # 手写 FFI 绑定约 2.1K 行 ├── features/ │ ├── stt/services/audio_capture_manager.dart # SDK 自持麦克风采集PCM16基于 package:record │ └── tts/services/audio_playback_manager.dart # SDK 自持 speak() 播放基于 audioplayers ├── foundation/ # constants/、errors/sdk_exception.dart、logging/ ├── generated/ # 运行时 proto 文件DO NOT EDIT ├── native/ # dart_bridge_*.dart slices native_functions platform_loader types/ type_conversions/ └── public/ ├── runanywhere.dart # RunAnywhere 静态入口 ├── api/ # namespaces/NameApi 类 types/ internal/ —— 较新的 v3-spec 层 ├── capabilities/ # 较旧的 RunAnywhereName 单例类cua、solutions、hybrid 内部实现 └── events/ # event_bus.dart纯 dart:async特别提醒不要在源码中寻找以下路径——不存在顶层lib/capabilities/、lib/infrastructure/、dart_bridge_hardware.dart、dart_bridge_llm_streaming.dart、native_backend.dart。这些是历史文档中的旧布局已经不存在。三、公共 API17 个能力命名空间与退役访问器核心包的公共入口是 RunAnywhere 静态类它是当前命名空间集合的唯一事实来源——任何其他列表包括本文都只是快照。当前RunAnywhere暴露17 个能力命名空间 getter15 个 v3 spec 命名空间llm、vlm、stt、tts、vad、embeddings、rerank、images、diarization、segmentation、voice、rag、models、lora、cua2 个 超出 v3 spec 命名空间solutions、hybrid保留给规格尚未覆盖但已发布的特性。大部分 v3 命名空间是lib/public/api/namespaces/下的无状态const NameApi类如LlmApi、SttApi、TtsApi、VlmApi通过RunAnywhere.llm这样的静态 getter 访问而cua/solutions/hybrid则是旧版lib/public/capabilities/布局下的RunAnywhereName单例.shared例如RunAnywhereCUA.shared。已退役的顶层访问器不要假定它们存在downloads、tools、modelLifecycle、pluginLoader、diffusion、hardware。它们的职责已经重新归并工具调用并入了llmimages取代了diffusion模型注册表/生命周期/下载归入models。在 runanywhere.dart 的源码中可以确认这 17 个 getter 的实际形态。能力探测capabilities()RunAnywhere.capabilities()会返回SDKCapabilities包含可用模态列表、后端、音频格式、流式与工具能力。它的实现很有意思初始化完成后会逐个探测 commons 二进制是否导出可选 ABI 符号如rac_diarization_diarize_lifecycle_proto、rac_segmentation_segment_lifecycle_proto、rac_diffusion_generate_lifecycle_proto、rac_rerank_component_create。当当前构建的 commons 二进制早于这些符号时对应模态会从modalities中移除并带着缺失符号名上报到unavailable而不是虚报已安装但未测试。另外agents、wakeword、realtime三个命名空间是 v4 契约明确从所有 SDK 中排除的会恒定出现在unavailable中。四、初始化与生命周期两阶段设计与 fire-and-forgetinitialize()的参数语义await RunAnywhere.initialize({ String? apiKey, // null 表示 keyless 本地模式 String? baseUrl, // null 时使用当前环境的默认控制平面 SDKEnvironment environment SDKEnvironment.SDK_ENVIRONMENT_PRODUCTION, });从 runanywhere.dart 源码 可以看到initialize()是幂等的重复调用返回同一个 future会先等待进行中的reset()完成baseUrl为空时使用RADefaultsEnvironment.developmentPlaceholderUrl的占位符形态交由 commons 解析环境对应的控制平面地址非空时会用Uri.tryParse校验并抛出SDKException.validationFailed。初始化失败时_initialize会执行完整的回滚DartBridge.shutdown()、清理缓存参数、重置_localServicesReady然后rethrow由调用方捕获SDKException。两阶段初始化的真实语义AGENTS.md 特别强调了一个容易踩坑的点Phase 2 是真正的 fire-and-forget。Phase 1同步约 15 步加载原生库 → 注册rac_platform_adapter_t→rac_sdk_init_phase1_proto→ 配置日志 → 注册事件 / 设备 / 文件管理 / 遥测回调 →setBaseDirectory()。Phase 1 完成后离线推理即可使用。Phase 2异步、不等待rac_sdk_init_phase2_proto负责设备注册 认证 模型分配 遥测 flush。它在源码中被赋给_servicesInitFuture即_remoteServicesFuture而不 await与 Swift 的Task.detached对齐。AGENTS.md 明确警告早期实现曾经在一个 doc comment 声称 fire-and-forget 的情况下仍然急切地 await 了它——不要轻信 doc comment要以调用点为准。从当前源码看_runRemoteServices是unawaited(...)调度的失败只记logger.warning(Remote service setup failed (non-critical))本地推理完全不依赖网络。其他生命周期 APIisReadyDartBridge.isInitialized _localServicesReady为 true 表示本地推理可用。versionSDK semver 字符串源自SDKConstants.version。deviceId稳定的一次安装一个的设备标识在initialize()之前访问会抛SDKException.notInitialized。eventsEventBus.shared.allEvents经SdkEventMapper映射的生命周期、模型与错误面包屑流。reset()卸载模型、关闭会话、清空状态会先等待进行中的初始化与远程服务设置best-effort最后DartBridge.shutdown()保证遥测/注册表/HTTP 能在原生侧还存活时完成 flush。setHfToken(String?)提供 Hugging Face bearer token 以拉取私有模型仓库传空字符串清除传 null 回退到HF_TOKEN环境变量。五、四大后端包注册机制与边界条件后端包的本质是薄包装Dart 侧只负责调用 FFI 注册函数把引擎 vtable 挂进 C 插件注册表之后的路由由 commons 按优先级 运行时 格式兼容打分选择。AGENTS.md 对四个后端给出了精确的注册语义runanywhere_llamacppLLM VLM.ggufLlamaCpp.register()→ FFIrac_backend_llamacpp_register()..._vlm_register()。一次调用同时填充llm_ops和vlm_ops两个槽位不存在单独的registerVlm()。源码中register()的默认优先级是 100且重复调用是 no-op幂等。底层 llama.cpp 版本为runanywhere-b10453.4支持的量化覆盖 Q2_K / Q3_K_S/M/L / Q4_0/1 / Q4_K_S/M / Q5_0/1 / Q5_K_S/M / Q6_K / Q8_0 等。runanywhere_onnxSTT TTS VADawait Onnx.register()同时注册通用 ONNX 引擎与 Sherpa STT/TTS/VAD 引擎——一个包两个引擎因为它们共享底层 ONNX Runtime拆分会导致重复内置该运行时。自定义下载器OnnxDownloadStrategy通过rac_extract_archive_native处理.tar.bz2模型包。ONNX Runtime 版本为 1.28.0。runanywhere_mlxApple MLX仅真机 iOSawait MLX.register()→ FFIra_mlx_register_runtime()。其规范实现是 Swift 的RunAnywhereMLX产品Dart 侧没有推理逻辑且只能走 CocoaPodsHub/Crypto 需要 app 根级 bundleFlutter SwiftPM 提供不了。模拟器 slice 只能构建/链接/启动——注册时会上报不可用Android 完全不支持不在 manifest 中。runanywhere_qhexrtQualcomm Hexagon NPU仅 Androidawait QHexRT.register()→ FFIrac_backend_qhexrt_register()只在受支持的 Snapdragon Hexagon NPU 上注册成功。这是私有后端原生库单独 stage源码 checkout 中不包含其 natives。libc_shared.so 重复是故意的AGENTS.md 特别强调四个 Android 包各自内置libc_shared.so是有意为之不要在包层面去重。原因是每个 Flutter 插件都必须是自包含的 AAR——消费者可能只添加runanywhererunanywhere_llamacpp每个传递闭包都需要该库插件包无法传递依赖另一个插件的jniLibs抽到共享子包会破坏独立消费。合并问题在 APK 打包时由 Gradle 解决packaging { jniLibs.pickFirsts **/libc_shared.so }六、原生库加载与平台 HTTP 传输注入按平台的 DynamicLibrary 策略platform_loader.dart 实现了平台差异化的原生库加载平台机制iOSDynamicLibrary.process()在主二进制中解析符号静态链接的RACommons.xcframework需要use_frameworks! :linkage :static-all_load/DEAD_CODE_STRIPPINGNOAndroidDynamicLibrary.open(librac_commons.so)回退librunanywhere_jni.somacOS测试process()→executable()→ 显式 dylib 路径RACommons.xcframework的第三个 slicemacos-arm64专门支持单元测试源码中 Xcode debug 构建会注释说明App 代码可能链接进Runner.debug.dylib而非小的 launcher 可执行文件所以 loader 在 process 级查找失败后才会回退到 executable。此外 Android 上还会幂等地dlopen独立的librac_backend_cloud.soensureCloudBackendLoaded以满足librunanywhere_jni.so中 cloud 后端的未定义符号导入iOS/macOS 上 cloud TU 静态链接进进程镜像该调用是 no-op。所有 C ABI 绑定都是手写的core/native/rac_native.dartnative/native_functions.dart缓存查找注册表不使用 ffigen。HTTP 传输URLSession 与 OkHttp 的 vtable 注入iOSFlutter 插件入口RunAnywherePlugin.swift会在 Dart FFI 发起 HTTP 之前调用URLSessionHttpTransport.register()ObjC 层的URLSessionHttpTransport.mm持有静态rac_http_transport_ops_tSwift façade 用_silgen_name(ra_flutter_register_urlsession_transport)导出、幂等。相关文件packages/runanywhere/ios/runanywhere/下的 Swift 与.mm文件。AndroidRunAnywherePlugin.kt的静态init {}块在 FFI HTTP 触发前通过 JNI 注册 OkHttp 传输OkHttpHttpTransport.kt用 OkHttp 4.12 支撑rac_http_request_send/_stream/_resume采用 30s / 24h / 60s 超时、32 KB 分块、支持 range 的 206 响应并用 in-flight 注册表支撑cancelAllStreams()。RunAnywhere.initialize()里 HTTP client 的配置顺序也很讲究HTTPClientAdapter.shared.configure(...)必须在遥测初始化之前完成且遥测 sink 必须在核心初始化之前挂上——因为 commons 在初始化过程中就会发事件空 sink 会丢事件源码注释原话。七、流式回调安全模型Native-Port Helpers这是 AGENTS.md 中技术含量最高的一节规则只有一条永远不要在 Dart 侧异步读取借来的 C 回调字节。高风险流LLM / VLM / STT / TTS、voice-agent在原生回调内部同步拷贝字节通过插件自持的 native-port helper 把已拥有的Uint8Listpost 到 Dart 的ReceivePort。原因有二NativeCallable.isolateLocal只在注册它的 isolate 线程上安全NativeCallable.listener在事件循环上跑得太晚commons 可能立刻复用缓冲区。因此rac_native.dart优先使用可选的ra_flutter_*_native_port符号存在时仅在文档明确许可的路径回退到同线程的isolateLocal。与之相对的SDK 事件 fan-out 与低风险回调使用NativeCallable.listener 广播StreamController纯dart:asyncrxdart 不是依赖。新增流式回调时应当遵循同一模式而不是在 Dart 侧直接读借来的字节在平台 SDK 层加 native-port helper、在返回 commons 前拷贝字节、在rac_native.dart中暴露为可选 FFI 符号、保持 example app 精简。完整原理、文件地图与 Android 热加载时序见 bindings/flutter/docs/ARCHITECTURE.md 的 §10.3。并发模型的整体面貌是公共 API 全部async/await流式生成/下载进度/voice agent 事件用广播 Stream阻塞 FFI 只有在 C 路径无法通过 isolate-local 回调回发、或回调被证明安全时才允许移到 worker isolateIsolate.run/NativeCallable.listenerCompleter用于把回调桥接成 future。Pointer.fromFunction回调只允许从注册线程调用。八、安全存储与平台原生层细节安全存储 vtable是一个值得注意的跨层模式C 侧会同步调用 Dart 回调Flutter 侧再委托给平台原生 helper——Apple 走 KeychainAndroid 走 Keystore AES-GCM 原子写入的 no-backup 密文文件。回调只有在校验变更完成后才返回成功即成功 变更已落盘。iOS 原生层是一个本地 SwiftPM 包packages/runanywhere/ios/runanywhere/Package.swifttools-version 6.2不是旧的扁平 CocoaPodsClasses/布局。它包含 3 个 target二进制RACommons、ObjCrunanywhere_native、SwiftrunanywhereFlutter 插件。Sources/runanywhere_native/下有 6 个*StreamNativePort.mm流式回调 helper 和SecureStorageBridge.mmKeychain 桥。RACommons.xcframework是 vendored 静态库含 3 个 sliceios-arm64、ios-arm64-simulator、macos-arm64podspec 要求 iOS 17.5链接参数为-lc -larchive -lbz2 -lz -ObjC -all_load -Wl,-export_dynamic且DEAD_CODE_STRIPPINGNO。Android 管道RunAnywherePlugin.kt插件入口 静态 OkHttp 注册、RunAnywhereBridge.ktJNI shimSystem.loadLibrary(runanywhere_jni)、src/main/cpp/NativePortHelpers.cpp构建librunanywhere_flutter_helpers.sobuild.gradle用 AGP 9 Java 17 NDK28.2.13676358ABI 覆盖 arm64-v8a、armeabi-v7a、x86_64binary_config.gradle提供useLocalNatives开关 GitHub release URL 校验和。九、生成代码、Lint 规则与版本清单生成代码packages/runanywhere/lib/generated/存放约 79 个文件、约 39 个 proto schema每个 schema 两个文件.pb.dart.pbenum.dart由protocprotoc-gen-dart从idl/*.proto生成——比早期 58 文件/29 schema 的规模更大因为diarization、segmentation、rerank、cua等随 ABI v9 基础类型集加入。这些文件被排除在 analyzer 之外禁止手改。*.pbjson.dart/*.pbserver.dart/*.pbgrpc.dart会被 idl/codegen/generate_dart.sh 剥离——Flutter 不需要 descriptor / server / gRPC stub。Lint 规则analysis_options.yaml在package:flutter_lints/flutter.yaml基础上启用严格模式strict-casts/strict-inference/strict-raw-typeserror 级dead_code/unused_import/unused_local_variable/unused_element/unused_fieldwarning 级avoid_dynamic_calls/avoid_print/prefer_const_constructors/prefer_final_locals排除**/*.g.dart、**/*.freezed.dart、**/lib/generated/**。版本清单包 / 制品版本runanywhere、runanywhere_llamacpp、runanywhere_mlx、runanywhere_onnx、runanywhere_qhexrt0.20.36五个包完全一致RACommons原生0.1.6llama.cpp 引擎runanywhere-b10453.4ONNX Runtime1.28.0权威版本来源core/VERSION工具链要求Flutter 3.44.6 · Dart3.12.0 4.0.0· iOS 17.5 · Android minSdk 24 / compiletarget SDK 36 · NDK28.2.13676358racFlutterNdkVersion覆盖值· AGP 9.0.1 / Gradle 9.1.0 · Xcode/Swift 26 / 6.2。十、开发命令与平台接入实战Melos 工作流在bindings/flutter/下执行melos bootstrap # 跨 Dart workspace 执行 flutter pub get melos run analyze # 在全部 5 个包中执行 flutter analyze --no-pub melos run format # 在全部 5 个包中执行 dart format melos run test # 在全部 5 个包中执行 flutter test melos run clean # 在全部 5 个包中执行 flutter clean melos version # 升版本 生成 workspace CHANGELOGSDK 打包与校验./scripts/package-sdk.sh # 全部包 pub publish --dry-run ./scripts/package-sdk.sh --natives-from PATH # 先 stage 原生库xcframeworks .so再校验 ./scripts/package-sdk.sh --include-private-qhexrt # 需配合 --natives-from额外 stage 私有 QHexRT 原生库示例应用的命令flutter pub get/run、scripts/verify.sh详见 bindings/flutter/docs/DEVELOPMENT.md。iOS 接入要点ios/Podfile必须使用静态链接否则运行时会报 symbol not foundplatform :ios, 17.5 target Runner do use_frameworks! :linkage :static flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end同时在Info.plist中添加麦克风权限声明keyNSMicrophoneUsageDescription/key stringThis app needs microphone access for speech recognition/stringAndroid 接入要点在android/app/src/main/AndroidManifest.xml中声明录音权限uses-permission android:nameandroid.permission.RECORD_AUDIO /本地 vs 远程原生库源码 checkoutAndroid 在runanywhere.useLocalNativestrue时使用 staged JNIApple 包优先使用 stagedFrameworks/。发布包Pub 归档不含原生负载。Android Gradle 按 ABI 下载带 SHA-256 校验的归档CocoaPods/SwiftPM 为 Apple 插件下载固定校验和。日常开发中改 Dart 代码后flutter run会自动生效改 C commons 后需要从仓库根目录重新构建原生制品./bindings/swift/scripts/build-core-xcframework.sh与./scripts/build/build-core-android.sh ABI。十一、文档地图与排错索引AGENTS.md 为 Flutter SDK 指定了三份权威参考文档阅读优先级建议是bindings/flutter/docs/ARCHITECTURE.md——数据流、扩展性、取舍、原生二进制清单§13精确数量以 AGENTS.md 为准因为它滞后。bindings/flutter/docs/Documentation.md——公共 API 参考同样存在滞后警告。bindings/flutter/docs/DEVELOPMENT.md——平台搭建、首次构建、排错。常见排错速查iOS symbol not found确认 Podfile 有use_frameworks! :linkage :staticcd ios pod install --repo-updateflutter clean flutter run。Android 库加载失败确认 NDK 已装检查jniLibs下有.so从仓库根重新构建原生库。上报问题附上RunAnywhere.version、flutter --version、平台与系统版本、设备型号、复现步骤、期望 vs 实际行为、脱敏日志。结语RunAnywhere Flutter SDK 的架构可以用一句话概括Dart 只做编排原生层干所有重活Proto 是唯一的契约。理解 17 个能力命名空间的入口形态、两阶段初始化的 fire-and-forget 语义、四个后端的单次注册机制、以及永远不要在 Dart 侧异步读借来的回调字节这条流式安全铁律就能在接入端侧 LLM / 语音 / 视觉能力时快速定位问题、避免最常见的架构性陷阱。若需深入某个模式数据流、扩展性取舍、原生二进制清单AGENTS.md 与 ARCHITECTURE.md 的交叉引用就是最好的导航。赞分享AI模型推理服务推理引擎本地部署多模态【免费下载链接】runanywhere-sdksProduction ready toolkit to run AI locally项目地址https://gitcode.com/gh_mirrors/ru/runanywhere-sdks点击查看免费下载相关推荐Kilo VS Code 扩展的 HTTP 请求超时体系健康检查、SSE 心跳与 SDK 调用超时治理实践Kilo VS Code 扩展的 HTTP 请求超时体系健康检查、SSE 心跳与 SDK 调用超时治理实践 导读 本文基于 Kilo 仓库中 packagesAI模型推理服务推理引擎本地部署多模态RunAnywhere Flutter SDK 实战指南在 iOS / Android 上端侧运行 LLM、语音与多模态 AIRunAnywhere Flutter SDK 实战指南在 iOS / Android 上端侧运行 LLM、语音与多模态 AI RunAnywhere FluAI模型推理服务推理引擎本地部署多模态verl 安装与部署全指南uv 工作流、Docker 镜像与多后端环境配置verl 安装与部署全指南uv 工作流、Docker 镜像与多后端环境配置 verlVolcano Engine Reinforcement LearninAI模型推理服务推理引擎本地部署多模态上一篇Windows Agent Arena常见问题解答从本地部署到Azure扩展的15个关键问题下一篇foobox美化方案5步打造你的专业级foobar2000音乐播放器界面创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表