RunAnywhere Flutter SDK 实战指南:在 iOS / Android 上端侧运行 LLM、语音与多模态 AI
2026/9/24 15:49:00 网站建设 项目流程

RunAnywhere Flutter SDK 实战指南:在 iOS / Android 上端侧运行 LLM、语音与多模态 AI

【免费下载链接】runanywhere-sdksProduction ready toolkit to run AI locally项目地址: https://gitcode.com/gh_mirrors/ru/runanywhere-sdks

RunAnywhere Flutter SDK 是 RunAnywhere 跨平台 SDK 家族(Swift / Kotlin / React Native / Web / Flutter)中的 Flutter 绑定,目标是在 iOS 与 Android 设备上直接运行 LLM、语音识别(STT)、语音合成(TTS)、语音活动检测(VAD)、视觉语言模型(VLM)乃至完整的语音 Agent 流水线,全程不依赖云端推理。本文以仓库内 bindings/flutter/README.md 为核心骨架,结合 Flutter 包源码 与 示例应用,系统讲解环境要求、安装配置、命名空间式 API、模型管理与错误处理,帮助你在一小时内跑通第一个端侧 AI 应用,并理解其底层 Dart FFI 与原生 C++ 核心的协作方式。

一、SDK 概览与核心设计

RunAnywhere Flutter SDK 以「本地优先、隐私优先」为设计出发点:推理完全发生在设备本地,用户数据不出设备;网络连接仅用于初始模型下载、目录同步与可选的生产遥测。其公共 API 采用命名空间式设计——每一个能力(LLM、STT、TTS、VAD、VLM、RAG 等)都通过RunAnywhere静态类上的一个静态访问器暴露,形如RunAnywhere.<capability>.<method>(...),这也是 Swift / Kotlin / React Native 各绑定共享的跨平台一致性约定(见 bindings/flutter/docs/Documentation.md)。

从源码结构看,RunAnywhere是一个abstract final class(入口文件),负责生命周期管理(initialize/reset)、就绪状态(isReady)、SDK 版本(version)、稳定设备标识(deviceId)、SDK 事件流(events)以及能力探测(capabilities())。底层通过DartBridge走 FFI 调用 native C++ 核心(rac_*C ABI 符号),再由各命名空间(llmsttttsvadvlmvoicemodelsdownloadsragtoolsembeddingslora等)封装成类型安全的 Dart API。

SDK 包本身(pubspec.yaml)依赖ffiprotobuf(由 IDL 生成的 proto 绑定,见idl/目录)、shared_preferencespath_provideraudioplayers/record(音频采集与播放)、device_info_plus等,构成了一个「核心原生引擎 + Dart 薄封装」的分层架构。

二、环境要求(Requirements)

在开始之前,请先对照以下环境要求确认开发环境达标:

组件最低版本推荐版本
Flutter3.44+3.44.6(见 pubspec.yaml)
Dart3.12+3.12.2(workspace 约束>=3.12.0 <4.0.0
iOS17.5+17.5+
AndroidAPI 24(Android 7.0+)API 28+
Xcode26+26+
RAM2 GB4 GB+(用于更大模型)

几点需要注意:

  • 强烈建议使用 ARM64 设备。iOS 上 Metal 加速、Android 上 NEON 指令集都能带来显著性能提升;Apple MLX 后端则必须在物理 arm64 iOS 设备上运行(模拟器 slice 仅用于编译/链接验证,见下文 FAQ)。
  • iOS 平台配置是强制的:需要静态 CocoaPods 链接和(用于语音功能的)麦克风权限声明,详见 bindings/flutter/docs/DEVELOPMENT.md,第三节会给出完整的 Podfile 与 Info.plist 配置。
  • 工作区使用 melos 管理多包(runanywhererunanywhere_llamacpprunanywhere_mlxrunanywhere_onnxrunanywhere_qhexrt),melos bootstrap负责并行pub get(见 bindings/flutter/pubspec.yaml)。

三、安装与平台配置

3.1 添加依赖

在应用的pubspec.yaml中按需添加包,当前仓库锁定版本为0.20.36(SDK 包 version 字段):

Core + LlamaCpp(LLM / VLM,GGUF 格式):

dependencies: runanywhere: 0.20.36 runanywhere_llamacpp: 0.20.36

Core + ONNX(STT / TTS / VAD):

dependencies: runanywhere: 0.20.36 runanywhere_onnx: 0.20.36

Core + MLX(Apple LLM / VLM / 物理 iOS 设备上的语音):

dependencies: runanywhere: 0.20.36 runanywhere_mlx: 0.20.36

可选 NPU(Snapdragon Android 上的 Qualcomm Hexagon):

runanywhere_qhexrt: 0.20.36

随后执行:

flutter pub get cd ios && pod install && cd .. # iOS only

各包职责一览:

用途
runanywhere核心 SDK —— 必需
runanywhere_llamacppLLM / VLM(GGUF)
runanywhere_onnxSTT、TTS、VAD
runanywhere_mlxApple MLX
runanywhere_qhexrtQualcomm Hexagon NPU(可选)

3.2 iOS 平台配置(必需)

根据 bindings/flutter/docs/DEVELOPMENT.md,添加包之后必须更新 iOS Podfile:

1. 更新ios/Podfile

platform :ios, '17.5' target 'Runner' do use_frameworks! :linkage => :static flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '17.5' config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', 'PERMISSION_MICROPHONE=1', ] end end end

重要:缺少use_frameworks! :linkage => :static会在运行时出现 "symbol not found" 错误。

2. 更新ios/Runner/Info.plist,声明麦克风权限:

<key>NSMicrophoneUsageDescription</key> <string>This app needs microphone access for speech recognition</string>

3. 执行 pod install:

cd ios && pod install && cd ..

3.3 Android 平台配置

android/app/src/main/AndroidManifest.xml中添加录音权限(语音功能需要):

<uses-permission android:name="android.permission.RECORD_AUDIO" />

3.4 从源码构建(可选)

如果要从仓库源码构建 native 产物并本地调试,工作区采用 melos 引导:

# 1. 克隆仓库后,在仓库根目录构建 native 产物 ./bindings/swift/scripts/build-core-xcframework.sh ./scripts/build/build-core-android.sh arm64-v8a # 2. 引导 Flutter 工作区 cd bindings/flutter melos bootstrap

build-core-xcframework.sh会把 XCFramework 构建并放置到各包的ios/<package>/Frameworks/目录;build-core-android.sh <ABI>则生成.so并放置到android/src/main/jniLibs/<ABI>/。注意:发布到 pub.dev 的包不含 native 产物——Android 侧由 Gradle 按 ABI 下载归档并做 SHA-256 校验,Apple 侧由 CocoaPods/SwiftPM 下载带固定校验和的插件。本地消费则通过runanywhere.useLocalNatives=trueandroid/gradle.properties)启用。

四、快速开始(Quick Start)

以下是最小可运行示例:初始化 SDK、注册 LlamaCpp 后端、下载并加载模型、发起一次对话生成。

import 'package:runanywhere/runanywhere.dart'; import 'package:runanywhere_llamacpp/runanywhere_llamacpp.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await RunAnywhere.initialize(); LlamaCpp.register(); await RunAnywhere.downloadModel('smollm2-360m'); await RunAnywhere.llm.load('smollm2-360m'); final response = await RunAnywhere.llm.chat('What is the capital of France?'); print(response); }

要点解读:

  • WidgetsFlutterBinding.ensureInitialized()确保在main()中能安全地等待异步初始化。
  • 必须先注册后端模块LlamaCpp.register()Onnx.register()Mlx.register()),再下载和加载模型。
  • 内置目录模型(如smollm2-360m)会被自动发现,无需手动注册;自定义模型才需要RunAnywhere.models.register()
  • downloadModel/loadModel这类扁平别名与 Swift / Kotlin / RN 各绑定保持一致,用于跨平台代码迁移时对齐 API 形态(见 README)。

4.1 生产环境初始化

默认initialize()以无 API Key 的本地模式运行;生产环境可显式传入 API Key、控制面 Base URL 与环境类型:

await RunAnywhere.initialize( apiKey: '<YOUR_API_KEY>', baseURL: 'https://api.runanywhere.ai', environment: SDKEnvironment.SDK_ENVIRONMENT_PRODUCTION, );

从源码看,initialize的执行流程(runanywhere.dart)包括:解析并校验参数 → 获取设备 ID → 挂载遥测 sink → 通过DartBridge初始化原生核心 → 设置模型基础目录 → 启动本地服务(HTTP 客户端、遥测、模型注册表)→ 异步派发远程服务(鉴权、设备注册、assignment 拉取)。关键设计是:本地推理不会等待网络就绪——远程设置在后台重试,因此initialize()返回后即可开始本地工作。若原生核心无法启动或配置被拒绝,则抛出SDKException

SDKEnvironment(sdk_environment.dart)映射到 C 层的rac_environment_tSDK_ENVIRONMENT_DEVELOPMENTSDK_ENVIRONMENT_PRODUCTION分别对应本地开发与生产控制面。生产环境默认关闭调试日志(LOG_LEVEL_WARNING)、允许遥测;开发环境则使用LOG_LEVEL_DEBUG。对未知的枚举值采取 fail-closed 策略,拒绝静默降级到 DEVELOPMENT(那会关闭鉴权与后端同步)。

五、能力全景(Capabilities)

RunAnywhere通过静态访问器暴露全部能力。下表为 README 中能力矩阵的完整版,并补充了源码中可确认的方法形态:

访问器用途示例方法
RunAnywhere.llm文本生成llm.chat()llm.generate()llm.generateStream()
RunAnywhere.stt语音转文字stt.transcribe()stt.transcribeStream()
RunAnywhere.tts文字转语音tts.synthesize()tts.speak()
RunAnywhere.vad语音活动检测vad.detectVoiceActivity()vad.streamVAD()
RunAnywhere.vlm视觉语言模型vlm.processImage()
RunAnywhere.voice语音 Agent 流水线voice.initializeWithLoadedModels()
RunAnywhere.models模型注册表models.register()models.available()
RunAnywhere.downloads下载生命周期downloads.start()downloads.delete()
RunAnywhere.rag检索增强生成rag.query()
RunAnywhere.tools工具 / 函数调用tools.generateWithTools()

5.1 LLM:文本生成(RunAnywhere.llm

LLM 命名空间(llm.dart)提供完整的方法集:

  • generate(prompt, {options}):单轮补全,返回GenerationResult
  • generateChat(messages, {options}):多轮对话——最后一条消息是当前回合,前面的消息作为历史,开头的 system 消息作为系统提示词;
  • generateStream(prompt):流式生成,返回Stream<GenerationEvent>,逐 token 消费:
    await for (final e in RunAnywhere.llm.generateStream('Say hello')) { // 处理流式事件 }
  • options中挂载了工具定义时,generate会自动切换到工具执行会话(tool-execution loop),回调已注册的 executor 并继续生成(llm.dart#L55-L62)。

5.2 语音三件套:STT / TTS / VAD

  • STT(stt.dart):transcribe(audio, {options})返回TranscriptionopenStream(...)建立持续识别会话,支持实时流式转写。
  • TTS(tts.dart):synthesize(text, {options})返回Audiospeak()直接播放;voices()枚举可用音色;stop()停止播放。
  • VADdetectVoiceActivity()streamVAD()用于检测语音端点,是语音 Agent 流水线的底层依赖。

5.3 语音 Agent(RunAnywhere.voice

voice命名空间(voice.dart)提供语音到语音的 Agent 会话:

final session = await RunAnywhere.voice.createSession(...); await session.start(); // 监听会话事件 await for (final e in session.events) { ... } await session.interrupt(); await session.close();

createSession内部会按需确保 VAD 组件就绪(必要时自动下载),将 STT → LLM → TTS 串成完整的端侧语音对话流水线。

5.4 RAG 与工具调用

  • RAG(rag.dart):search(query, {topK})做检索,query(question, {options})执行「检索 + 生成」的完整 RAG 查询,返回RagResult
  • 工具调用tools.generateWithTools()支持函数调用(function calling)与结构化输出,可配合 LLM 命名空间的options.tools使用。

5.5 模型与下载管理

models命名空间(models.dart)负责模型注册表:

final llms = await RunAnywhere.models.list( const ModelFilter(category: ModelCategory.MODEL_CATEGORY_LANGUAGE)); final model = await RunAnywhere.models.get('smollm2-360m'); await RunAnywhere.models.refresh( rescanLocal: true, includeRemoteCatalog: false, pruneOrphans: false, );

downloads命名空间(runanywhere_downloads.dart)管理下载与存储生命周期:

  • plan(request):预计算下载计划(DownloadPlanResult);
  • start(modelId):返回Stream<DownloadProgress>,可实时观察进度,直到终态(terminal state)为止;
  • cancel(modelId)/cancelDownload(modelId):取消下载;
  • delete(modelId)/deleteAllModels():删除模型与数据;
  • clearCache()getStorageInfo()list():存储信息与用量统计。

5.6 更多能力

SDK 还通过RunAnywhere暴露了embeddings(文本嵌入)、rerank(交叉编码器重排)、images(扩散图像生成)、diarization(说话人分离)、segmentation(语义分割)、lora(LoRA 适配器)、cua(计算机使用 Agent 脚手架)与hybrid(端侧/云端语音路由)等命名空间。capabilities()会基于当前构建的原生符号导出情况动态报告哪些能力可用、哪些不可用(SDKCapabilities.unavailable),例如当某个 commons 二进制未导出rac_diarization_diarize_lifecycle_proto符号时,diarization会被如实标记为不可用而非虚报(runanywhere.dart#L174-L209)。agentswakewordrealtime三个命名空间则明确不属于 v4 公共 API 面,不会被宣称支持。

六、支持的模型格式与后端

格式用途后端包
GGUFLLM、部分 VLMrunanywhere_llamacpp
ONNX / Sherpa 归档STT、TTS、VADrunanywhere_onnx
MLX bundlesApple silicon 上的 LLM、VLM、语音runanywhere_mlx
QHexRT bundlesSnapdragon 上的 NPU 模型runanywhere_qhexrt

内置目录模型(如smollm2-360m)注册后自动发现,无需手动注册;对于自定义模型,通过RunAnywhere.models.register()注册 GGUF、ONNX/Sherpa 或 MLX 模型包即可。后端模块的注册 API 形态可参考 runanywhere_llamacpp 包 README:await LlamaCpp.register()之后即可通过核心 SDK 的 API 使用其能力。

七、错误处理(Error Handling)

SDK 所有错误统一抛出SDKException,其内部携带 proto 生成的ErrorCode(sdk_exception.dart),并可从messagecodecategory三个维度读取错误详情;ErrorCode与 C ABI 的rac_result_t负值一一对应(正 proto code ↔ 负 C ABI code,见源码注释中的 round-trip 逻辑)。

try { final result = await RunAnywhere.llm.generate( 'Hello!', LLMGenerationOptions(maxTokens: 64), ); } on SDKException catch (error) { print('SDK error [${error.errorCode}]: ${error.message}'); }

常见工厂构造器包括SDKException.notInitialized()(未调用initialize())、validationFailed(...)(参数校验失败,可携带fieldPath定位到具体字段,如"STTOptions.sampleRate")、invalidConfiguration(...)等,便于在业务层做细粒度区分。

八、生命周期、事件与状态管理

initialize之外,RunAnywhere还提供:

  • reset():整体拆卸——卸载模型、关闭会话、清理状态(内部按顺序冲刷遥测、重置模型生命周期、关闭模型注册表,最后才 shutdown 原生桥,以保证 flush 时原生侧仍可用)。
  • isReady:本地推理可用时为 true(DartBridge.isInitialized && _localServicesReady)。
  • version:SDK semver 字符串。
  • deviceId:稳定设备标识(初始化前访问会抛SDKException.notInitialized)。
  • events:返回Stream<SdkEvent>,订阅生命周期、模型与错误面包屑事件,底层由EventBus+SdkEventMapper映射(runanywhere.dart#L137-L140)。

九、示例应用(Example App)

仓库自带一个功能完整的跨平台参考应用,位于 bindings/flutter/example/,覆盖了 LLM 聊天(含工具调用与 LoRA 面板)、语音(STT / TTS / VAD / 语音助手)、视觉(VLM 相机视图)、RAG 文档问答、模型管理(下载/选择/状态)、基准测试(LLM/STT/TTS benchmark)、Solutions 面板与 Hexagon NPU 卡片等功能模块(见 example/lib/features)。其pubspec.yaml通过path:依赖引用本地 SDK 包。

运行方式:

cd bindings/flutter/example flutter pub get cd ios && pod install && cd .. # iOS flutter run

注意:由于示例应用依赖本地 SDK 包,干净克隆后需先构建并 staging 原生产物(Android JNI 库与 iOS XCFramework),详见 bindings/flutter/example/README.md。

十、常见问题(FAQ)

是否需要联网?仅在初次下载模型时需要网络。之后推理完全在设备本地执行。

用户数据会被发送到云端吗?不会。所有推理均在本地进行。生产模式可能收集匿名遥测(可配置,见SDKEnvironmentshouldSendTelemetry判定)。

可以使用自定义模型吗?可以。通过RunAnywhere.models.register()注册 GGUF、ONNX/Sherpa 或 MLX 模型包。

如何测试 Apple MLX?MLX 执行需要物理 arm64 iOS 设备。模拟器 slice 仅用于编译/链接验证,无法运行真实推理。

更多资料

  • API 参考:bindings/flutter/docs/Documentation.md
  • 平台配置与构建指南:bindings/flutter/docs/DEVELOPMENT.md
  • Flutter 架构说明:bindings/flutter/docs/ARCHITECTURE.md
  • 示例应用:bindings/flutter/example/
  • 许可证:LICENSE

结语

RunAnywhere Flutter SDK 用一个统一的RunAnywhere命名空间把 LLM、语音、视觉、RAG、工具调用与模型管理全部收敛为类型安全的 Dart API,配合 LLamaCpp / ONNX / MLX / QHexRT 多后端注册机制,让 Flutter 开发者无需接触原生 C++ 即可在 iOS 与 Android 上构建离线优先、隐私安全的端侧 AI 应用。本文覆盖的安装配置、平台设置、命名空间 API、模型管理与错误处理,已经足够支撑你从零开始接入;更深层的原生桥接与 IDL 生成细节,可从 bindings/flutter/packages/runanywhere/ 源码与 idl/ 协议定义继续深入。

【免费下载链接】runanywhere-sdksProduction ready toolkit to run AI locally项目地址: https://gitcode.com/gh_mirrors/ru/runanywhere-sdks

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询