DenisovAV/flutter_edge_ai · 上手攻略

§0 速览

  • 仓库定位:把谷歌 LiteRT-LM 推理运行时封装成一个 Flutter 插件,让 Android / iOS / Web / macOS / Windows / Linux 六端 Flutter 应用都能跑 Gemma、Phi-4、DeepSeek、Qwen 等中小尺寸 LLM,全部本地推理、零 API 费用、零数据外传。
  • 核心结构:插件按"核心 + 可选引擎"拆分,主包 flutter_edge_ai 提供模型管理与聊天抽象,运行时要选一个引擎包(如 flutter_edge_ai_litertlm);同一份 Dart 代码跨六端调用,RAG、Agent Skills、Speech 各自独立 opt-in。
  • 一句话价值:把"手机本地跑多模态大模型"从展示 Demo 变成可发布的 Flutter 工程模板——含模型下载、Chat 流式、工具调用、Vision/Thinking、向量检索一条链路。
  • 不适合谁:纯服务端 LLM 场景、对极致延迟不敏感且不愿承担几百 MB 模型下载成本的 App、不在 Flutter 阵营的 Android 原生或 SwiftUI 项目。
  • 成熟度信号:仓库 980 commits、Star 630 / Fork 175、Pub Points 150/160、作者 Sasha Denisov 个人维护,6 周前从 flutter_gemma 重命名为 flutter_edge_ai,pub.dev 0.15.2 → 2.x 主版本号同时抬升 = 工程结构层面是升级式重命名而非单纯改名。

§1 它解决什么问题

过去想在 Flutter 里跑本地 LLM,开发者通常要在 Android 上接入 MediaPipe LLM Inference、在 iOS 上接 Apple Foundation Models 或 llama.cpp Swift bindings、在桌面端另找方案,结果是六端跑出六套 API。本仓库把这条路径压缩成两件事:

  1. 统一的 .litertlm 模型格式:模型以 LiteRT-LM 编译后的 .litertlm 文件分发,跨端同一文件,由 LiteRT-LM 运行时在 GPU / NPU / CPU 上拉起推理,开发者不用为每端各选推理后端。
  2. 可插拔的引擎包:核心包不带推理实现;你要 LiteRT-LM 就加 flutter_edge_ai_litertlm,要旧 MediaPipe .task 模型就加 flutter_edge_ai_mediapipe,每个引擎包只负责把运行时装进 App 包体——体积与责任一并切开。

附加价值: - 隐私与合规:敏感数据从不出设备,适合医疗 / 法律 / 政企内嵌场景。 - 离线可用:模型一旦下载成功,断网仍可工作(飞机模式、出海项目)。 - 零边际成本:不像云端按 token 计费,可以做"自由聊"产品定位而不用担心月底账单爆炸。 - 代理式工作流:内置 Function Calling 与 SKILL.md 形态的 Agent Skills,模型能直接调你的 Dart 函数,也能跑 npm / MCP 风格的技能文件。

§2 快速安装

环境门槛,按官网 codelab 的实测约束写:

# 1) 环境(已是 Flutter 开发可跳过)
flutter --version   # 需要 Flutter 3.44+ / Dart 3.12+,codelab 强制按此声明

# 2) 新建一个只跑 Android/iOS/macOS 的工程(其它平台按需追加)
flutter create --platforms=android,ios,macos gemma_codelab
cd gemma_codelab
rm test/widget_test.dart   # 默认 widget_test 引用 counter,先删否则构建失败

# 3) 加三个包:核心 + LiteRT-LM 引擎 + 一个图选器(Vision 必装)
flutter pub add flutter_edge_ai flutter_edge_ai_litertlm image_picker

写完后 pubspec.yaml 的 dependencies 大致是这样(patch 版本可能更新,按 flutter pub add 实际写出的为准):

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.8
  flutter_edge_ai: ^2.1.1
  flutter_edge_ai_litertlm: ^1.10.1
  image_picker: ^1.2.3

按需追加的 opt-in 包: - flutter_edge_ai_speech — 本地 STT + TTS - flutter_edge_ai_sqlite / flutter_edge_ai_qdrant — RAG 向量库 - flutter_edge_ai_agent — 让模型读取并执行 SKILL.md - flutter_edge_ai_mediapipe — 旧 .task/.bin 模型路径

⚠️ Android 必须改 android/app/build.gradle.kts——.litertlm 推理要求 API 30+,且引擎只发 arm64:

defaultConfig {
    // ...applicationId、targetSdk 等保留原值
    minSdk = 30
    ndk { abiFilters += listOf("arm64-v8a") }
}

⚠️ Android 14+ 必须在 manifest 加 foreground service 类型,否则首次下模型崩溃(详见 §6 坑 #1)。删除默认注释、加这三行权限 + 一个 service:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<service
    android:name="androidx.work.impl.foreground.SystemForegroundService"
    android:foregroundServiceType="dataSync"
    tools:node="merge" />

⚠️ iOS 在 Xcode 加两条 Capability:Increased Memory Limit + Extended Virtual Addressing——2.6 GB 的 .litertlm 模型文件需要这两把钥匙,否则 OS 杀进程。

§3 核心用法

3.1 五分钟"Hello, on-device" 骨架

import 'package:flutter_edge_ai/flutter_edge_ai.dart';
import 'package:flutter_edge_ai_litertlm/flutter_edge_ai_litertlm.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 1) 注册引擎(一次)
  await FlutterEdgeAi.initialize(
    inferenceEngines: [LiteRtLmEngine()],
    // 如需本地 RAG / Speech 再加对应的 backend / tokenizer
  );

  // 2) 安装模型(HuggingFace 公共 URL 即可,无 token)
  await FlutterEdgeAi.installModel(
    modelType: ModelType.gemma4,
    fileType: ModelFileType.litertlm,
  ).fromNetwork('https://huggingface.co/litert-community/gemma-4-E2B-it-litert-lm')
   .install();

  // 3) 取活动模型 → 开 chat → 流式产出
  final model = await FlutterEdgeAi.getActiveModel(maxTokens: 2048);
  final chat  = await model.createChat();
  await chat.addQueryChunk(Message.text(text: '你好,用三句话介绍 Gemma 4。', isUser: true));

  await for (final chunk in chat.generateChatResponseStream()) {
    chunk.when(
      text:       (t) => stdout.write(t),
      thinking:   (t) => debugPrint('[think] $t'),
      functionCall: (f) => debugPrint('[tool] ${f.name}(${f.args})'),
      parallelFunctionCall: (ps) => ps.forEach((p) => debugPrint('[tool*] ${p.name}')),
      // sealed class,分支不全会编译报错 = 反方工程安全网
    );
  }
}

核心设计的两点可以记一下: - ModelResponse 是 sealed,Dart 3 switch 必须穷举——漏写分支直接编译期报错,对 LLM 多输出类型的代码非常友好。 - 模型文件类型由 ModelFileType 显式声明,运行时按声明的值挑引擎,避免"装了一个 .bin 却想跑 LiteRT 引擎"的隐式歧义。

3.2 Function Calling — 让模型调你的 Dart 函数

final model = await FlutterEdgeAi.getActiveModel();
final chat  = await model.createChat(tools: [
  ToolSpec(
    name: 'get_weather',
    description: '查询某城市当前天气',
    parameters: {
      'city': ParamSpec(type: ParamType.string, required: true),
    },
  ),
]);

// 收到 FunctionCallResponse 时由 Dart 侧真正执行,然后回灌给模型
// 官方 codelab 用"todo 列表 + 改 app bar 颜色"演示一个完整回路

3.3 Vision — 把图喂进去

final picked = await ImagePicker().pickImage(source: ImageSource.gallery);
final bytes  = await picked!.readAsBytes();

await chat.addQueryChunk(Message.multimodal(
  text: '这张图里有什么?',
  image: ImagePart.fromBytes(bytes),
  isUser: true,
));
await chat.generateChatResponse();

3.4 Thinking 模式 — 暴露推理链

Gemma 4 / DeepSeek R1 / Qwen3 系列会把 ThinkingResponse 单独流出来,前端可以直接渲染在折叠面板里给用户看推理过程——这是它相对闭源对话产品的差异化卖点。

3.5 RAG / Agent / Speech

  • RAG:flutter_edge_ai_sqlite 或 flutter_edge_ai_qdrant 提供本地向量库,注册时挂上即可,模型侧只需在 addQueryChunk 时把"上下文块"作为系统角色注入。
  • Agent Skills:把 SKILL.md 放进工程目录,flutter_edge_ai_agent 会让模型自己读 + 执行;设计上借用了 Codex / Claude Skills 的 SKILL.md 模式。
  • Speech:flutter_edge_ai_speech 接管 STT/TTS,可与 Chat 串成语音助手。

§4 典型适用场景

  • 离线 / 隐私优先 App:法律咨询、医疗记录、企业内嵌助手,模型 + 数据全在手机里,零网依赖。
  • 教育 / 语言学习类工具:口语陪练可纯本地跑 0.5 GB 的 SmolLM、Gemma 3 270M,省 token 钱。
  • 跨端 AI 副驾:Mac/Windows 上做个人写作助手,Android/iOS 上做移动伴侣——同一份 Dart 接口,由 LiteRT-LM 在不同设备上调度 GPU/NPU。
  • 演示 / demo / 硬件评测:模型清单覆盖 0.3 GB ~ 3.9 GB,可以做"我们设备能跑多大模型"的演示基线。
  • 车载 / IoT / 嵌入式 Flutter:包体可裁剪,只挑需要的 engine + vector 库塞进 App。

§5 与同类对比

项目 推理后端 平台数 Flutter 一致性 模型生态 维护活跃度
DenisovAV/flutter_edge_ai LiteRT-LM / MediaPipe 6(Android/iOS/Web/macOS/Windows/Linux) 一套 Dart API 跨六端 Gemma 4/3/3n、Phi-4 Mini、DeepSeek R1、Qwen3/2.5、SmolLM、FastVLM、FunctionGemma 980 commits / 175 forks,重命名 + 主版本抬升近期
谷歌官方 ai_edge_flutter / 早期 MediaPipe Tasks GenAI MediaPipe Tasks 2~3(Android/iOS 为主) 与本仓库生态相近 Gemma 系为主 谷歌维护
llama.cpp 包装方案(如 gpt4all_dart 系社区包) llama.cpp 多 多套 API、需自己写平台分支 全开源(Llama、Mistral、Qwen…) 社区分散
flutter_llama / llama_flutter llama.cpp / 自带 多端 各自 API 全开源 社区,版本跟得快但缺统一治理

定位结论:它在"覆盖端最多 + API 最一致 + 官方 LiteRT 路线"的交集上最强;若你只需要 Android 上的简单问答,社区 llama 包装会更轻便;如果你已经在用 MediaPipe 旧栈且不打算切到 .litertlm,留在原 MediaPipe 路线成本更小。

§6 坑与注意(7 条工程坑,每条三段式:现象 / 影响 / 修复)

坑 1 — Android 14 上一启动就崩"ForegroundServiceTypeMissing"

  • 现象:release 包首次下载模型时 app 闪退,控制台抛 ForegroundServiceTypeNotAllowedException 或 requires foregroundServiceType dataSync。
  • 影响:debug 构建没事、release 必崩;模型下载链路彻底走不通,用户只看一次"打开就崩"。
  • 修复:按 §2 manifest 段加 FOREGROUND_SERVICE_DATA_SYNC 权限 + <service … android:foregroundServiceType="dataSync" tools:node="merge"/>;Play Console 上架会被审核这条权限,建议在隐私页明示用途。

坑 2 — iOS 上模型解压到一半被 jetsam 杀掉

  • 现象:iPhone(尤其 ≤4GB 内存机)下完 2.6 GB 模型,加载时 app 直接被 OS kill。
  • 影响:Vision 演示在 iPhone 上"偶发成功"——开发者本机是 Pro Max,QA 用常规机型就崩,体验落差巨大。
  • 修复:Xcode → Runner → Signing & Capabilities → + Capability → 加 Increased Memory Limit + Extended Virtual Addressing,并确认 Minimum Deployments ≥ iOS 15.0;codelab 也明确写了这条。

坑 3 — macOS 上"dylib not loaded" 或 OpenCL 加速器找不到

  • 现象:本地跑 macOS 端,引擎加载时报 Library not loaded: @rpath/libGemmaModelConstraintProvider.dylib,或 GPU 加速不可用退化成 CPU。
  • 影响:开发体验差、模型加载时间翻倍;CI 上跑 macOS runner 极易踩。
  • 修复:在 macOS Podfile 注入 CocoaPods post_install 阶段(codelab 给出整段 ruby),由它自动把 libGemmaModelConstraintProvider.dylib 与 libLiteRtLmMetalAccelerator.dylib 拷进 Contents/Frameworks 并修复引用;同时 pubspec.yaml 里关 SwiftPM——flutter.config.enable-swift-package-manager: false,否则 CocoaPods 不会生成。

坑 4 — pubspec.lock 被吞掉,团队成员各自下到不同小版本

  • 现象:同事 clone 后模型行为略有差异、报错栈不同。
  • 影响:PR review 困难、模型产物非确定性放大。
  • 修复:仓库自带 .fvmrc 锁 Flutter 版本,按官方推荐用 fvm use 进工程;依赖锁文件必须进 git;同时建议把 flutter pub get 的输出 diff 进 PR。

坑 5 — Web 端音频输入不可用

  • 现象:平台矩阵里 Web 行只对 Vision/Embeddings 打 ✅,Audio ❌。
  • 影响:想在浏览器跑语音 demo 的预期会落空,临时切换 STT 方案又会破坏"一套 API 跨端"承诺。
  • 修复:要么把语音部分降级到原生平台,要么在 web 上额外接 WebSpeech API / Whisper WASM 自己包一层;不要硬塞 flutter_edge_ai_speech 到 web 目标。

坑 6 — iOS Simulator 上 Metal 内存上限 256 MB

  • 现象:Mac M 系列真机能跑但 Simulator 加载大模型失败,Xcode 控制台出现 MTLBuffer alignment 或 exceeded allocation cap。
  • 影响:CI / 团队内只有 Mac mini 的同事无法本地验收 4B+ 模型。
  • 修复:官方明确 Simulator CPU-only 且 Metal 上限 256 MB——调试用 SmolLM 135M / Gemma 3 270M 这种"放得进 256 MB"的子集做 happy path 冒烟;大模型在真机或 CI 的 macOS Runner(无模拟器)上验证。

坑 7 — 仓库刚完成重命名,老的 flutter_gemma 教程与本仓库名错位

  • 现象:GitHub / pub.dev 上同时存在 flutter_gemma 与 flutter_edge_ai 两个 import path,部分博客 / CSDN / 知乎答案停留在旧名。
  • 影响:新人按教程 import package:flutter_gemma/... 在新版本下找不到符号。
  • 修复:以 flutter pub add flutter_edge_ai 为准,把所有 import 改成 package:flutter_edge_ai/...;旧 0.x 系列仍能 pub,但官方主版本号已抬到 2.x。

§7 与同类相比一句话推荐

"如果你要在 Flutter 里跑本地 LLM 且要 6 端一致 API,选它;如果你只要 Android/iOS 单端、能容忍双栈 API,社区 llama.cpp 包装也可以——但 2026 年这个时点 LiteRT-LM 是谷歌官方主线,flutter_edge_ai 是绕不开的工程基线。" ⚠️ 主版本号刚抬升、生态仍在迁移期(约 6 周前完成重命名),生产项目建议锁死 flutter_edge_ai: ^2.1.x 与 flutter_edge_ai_litertlm: ^1.10.x 等待 2.x 三个 minor 后再放开上界。

§8 不确定 / 诚实标注

  • Pub 版本号:codelab 明确写 flutter_edge_ai: ^2.1.1 / flutter_edge_ai_litertlm: ^1.10.1;pub.dev flutter_gemma 0.15.2(2026-05)是重命名前最后一个老版本号,新 flutter_edge_ai 包没有在搜索结果里直接展示 latest 版本——我按 codelab 的 ^2.1.x / ^1.10.x 写入正文,若上游已发 2.2.x 或 1.11.x,请以 flutter pub outdated 输出为准 ⚠️。
  • Star / Fork 数:630 / 175 / 980 commits 来自 web_search 摘要快照(2026-10-10 fetch),不保证读这篇攻略时仍精确。
  • 模型清单:取自官网首页与 codelab;Gemma 4 E2B / E4B 是 2026 年新系列,HF 上的 litert-community 编译产物是否已稳定"按量产 App 跑"还需自行测——codelab 把 E2B 写为 2.6 GB,真实首屏下载耗时与冷启动内存峰值强烈依赖具体机型,文内数字仅作量级参考 ⚠️。
  • NPU 支持表:网站写"Qualcomm Snapdragon Android + Intel LunarLake/PantherLake Windows",没给具体设备 SKU;遇到非首发机型 NPU 调度失败属正常,回退 GPU 即可。
  • 作者归属:仓库根 LICENSE 署名为 "Copyright (c) 2024 Sasha Denisov" 与官网本人陈述一致;pub.dev 上 flutter_gemma 包归属与 GitHub 同一组织,重命名后归属侧未发现冲突。
  • Built-in AI:首页提到的 Gemini Nano / Apple Foundation Models / Phi Silica / Chrome Prompt API 是否分别在不同封装包里可用,没逐一核 pubspec.yaml;按字面理解是上层抽象,真实端到端可用性需要按目标平台分别验证 ⚠️。
  • License:仓库与官网均声明 MIT;HF 上 litert-community 编译的 Gemma 4 .litertlm 文件本身则承袭 Gemma 4 模型的 Apache 2.0——商业发布请二次确认。

spark · 2026-10-11 · 字数 ≈ 2,950 · 来源:GitHub README(fetch ✓)+ 官网 https://flutteredge.ai/(fetch ✓)+ 第三方 codelab https://akanshajain.dev/codelabs/on-device-ai(fetch ✓)+ tavily web_search(flutter_edge_ai DenisovAV)+ 仓库根 LICENSE 文本(fetch ✓)。边界:仅写 organized/guides/denisovav-flutter_edge_ai.md,未触碰他人目录、未 git。