模型 / 数据集
callstackincubator/ai avatar
callstackincubator/ai

react-native-ai:把 Vercel AI SDK 的调用面搬到手机本地推理上

On-device LLM execution in React Native with Vercel AI SDK compatibility

1,398 个 Star59 个 ForkTypeScriptMIT

秒懂

它是什么?
这个库把 Apple Foundation Models、llama.rn 和 MLC LLM 三种运行时包装成 AI SDK 的 provider,让 generateText、embed、transcribe 这类调用在设备上直接执行。判断点在于:你要的是零服务端成本的本地推理,还是可控的模型选择,这两件事它只各满足一半。
适合谁用?
如果你的应用是 iOS 且目标设备支持 Apple Intelligence,只想用系统模型做文本生成、嵌入、转写和语音合成,@react-native-ai/apple 是当前门槛最低的路径,装完即用,没有模型下载和内存规划问题。如果必须支持 Android,或者需要指定某个 GGUF 模型,就得走 Llama 或 MLC 分支,代价是自己承担模型下载、prepare 加载、unload 释放这一整套生命周期,以及 Xcode 的 Increased Memory Limit 配置。
能商用吗?
可以。MIT 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
还在维护吗?
在维护。仓库最近一次提交在 71 天前。
用什么语言写的?
主要是 TypeScript(依据 GitHub 的语言统计)。

以上回答依据项目的 GitHub 数据(最近同步于 2026年9月15日)和我们的分析,不构成法律意见。

开源项目深度解析

它解决的是调用面的问题,不是推理引擎的问题

端侧跑模型在 React Native 里一直有个尴尬:推理能力其实已经存在,llama.rn 和 MLC LLM 都能在手机上加载模型,但每个库有自己的 API 形状、自己的加载流程、自己的错误处理方式。业务代码里一旦混进这些细节,换模型或换运行时就要重写调用层。react-native-ai 做的事情是把这层差异收进 provider,对外暴露 Vercel AI SDK 的 generateText、streamText、embed、experimental_transcribe、experimental_generateSpeech 这些函数。README 里的示例统一写成 generateText({ model: apple(), prompt: '...' }) 或者 generateText({ model, messages: [...] }),模型对象从哪来由 provider 决定。

目标读者因此很明确:已经在用 AI SDK 写 Web 或服务端逻辑、现在要把同一套交互搬到 App 里、并且不愿意在客户端重新发明一套推理调用的团队。反过来说,如果你的项目根本不用 AI SDK,这个库的主要价值就只剩下 provider 封装本身,收益会小很多。

三种 provider 对应三种完全不同的取舍

README 的 provider 表格把差异摆得很清楚。Apple 一栏标着 Built-in 为是,平台只有 iOS,运行时是 Apple 自己的 Foundation Models,描述里写明无需下载模型。Llama 和 MLC 都是 Built-in 为否,同时支持 iOS 和 Android,前者走 llama.rn 跑 GGUF,后者走 MLC LLM 的优化运行时。

这个划分意味着选型第一步不是比较性能,而是回答两个问题:要不要 Android,以及能不能接受模型下载。Apple 路径省掉了下载和内存规划,但把平台锁死在 iOS,把能力锁死在系统模型上,你无法换成一个更小的模型去适配低端机。Llama 路径给了模型自由度和双平台,代价是安装命令变成 npm install @react-native-ai/llama llama.rn react-native-blob-util,多出两个依赖,其中 react-native-blob-util 负责下载环节的文件处理。MLC 路径同样是双平台加下载,但运行时换成 MLC LLM,README 特别提到它需要在 Xcode 里打开 Increased Memory Limit 能力,这一条直接说明 MLC 的内存占用比另外两条路更吃紧。

模型 ID 就是 HuggingFace 路径,下载和加载是两件事

Llama provider 的模型标识格式是 owner/repo/filename.gguf,README 给的例子包括 ggml-org/SmolLM3-3B-GGUF/SmolLM3-Q4_K_M.gguf 和 bartowski/Llama-3.2-3B-Instruct-GGUF/Llama-3.2-3B-Instruct-Q4_K_M.gguf。这个格式本身就说明了数据来源:模型从 HuggingFace 拉取,本地不预置任何权重。

调用流程被拆成三步,顺序不能颠倒。先 llama.languageModel(...) 拿到模型实例,再 await model.download((progress) => {...}) 下载,回调里能读到 progress.percentage;然后 await model.prepare() 把模型加载进内存;推理结束后 await model.unload() 释放。这个拆分是必要的,因为下载可能几分钟,加载可能几秒,两者失败原因完全不同,合并成一个调用会让错误处理无从下手。但它也意味着业务层必须自己管理这套状态机:下载中断怎么办、用户切后台时 prepare 到一半怎么办、unload 之后模型对象还能不能复用。README 没有展开这些,示例只覆盖了顺利路径。

文档里举的三个模型都是 3B 或 1.5B 量级的量化版本,选 Q4_K_M 这类量化档位是端侧常见的做法。但 README 没有给出任何内存占用数字或设备兼容列表,所以能不能在具体机型上跑起来,只能自己实测。

Apple 路径的版本门槛比想象中高

Apple provider 的可用性表格是这份材料里信息密度最高的一段。文本生成要求 iOS 26+ 并且是 Apple Intelligence 设备;嵌入要求 iOS 17+,没有附加条件;转写要求 iOS 26+;语音合成 iOS 13+ 即可,但要用 Personal Voice 得 iOS 17+。

把这四行放在一起看,结论是:唯一能在较老系统上稳定使用的是嵌入和基础语音合成,真正代表本地大模型能力的文本生成被卡在 iOS 26 和特定硬件上。README 里那句「works immediately on iOS devices」在文本生成场景下需要加上这两个限定条件才成立。如果你的用户群里有相当比例的旧机型,Apple provider 能提供的实际上只有 512 维的 NLContextualEmbedding 和系统 TTS,聊天功能仍然得靠 Llama 或 MLC 兜底。

嵌入维度 512 这个数字值得记一下,它决定了向量库的存储开销和检索策略,也决定了你不能直接套用那些默认按 1536 维设计的方案。

0.12 是一次会打断升级的 AI SDK 版本切换

兼容性表格只有两行:0.11 及以下对应 AI SDK v5,0.12 及以上对应 AI SDK v6。这不是渐进式的适配,而是一条分界线。v0.12.0 发布于 2026-01-28,也就是说从 0.11 升到 0.12,你同时要处理这个库的 API 变化和 AI SDK 从 v5 到 v6 的变化,两边的改动叠在同一批调用代码上。

从发布节奏看,v0.10.0 在 2025-09-27,v0.11.0 在 2025-10-14,间隔不到三周,然后到 v0.12.0 隔了三个多月,之后到 2026-07 有持续提交但没有新版本。这个节奏配合 0.x 的版本号,说明 API 稳定性还没有承诺。把 react-native-ai 引入生产项目时,锁版本比平时更重要,因为跨越 0.11 和 0.12 的升级不是改个依赖号就能完成的。

另外要留意 experimental_transcribe 和 experimental_generateSpeech 这两个前缀,它们来自 AI SDK 的命名,说明转写和语音合成在 AI SDK 侧本身还不是稳定 API,这层不确定性会传导到 react-native-ai 上。

DevTools 面板空着的时候,问题可能不在你的代码

调试支持走的是 @react-native-ai/dev-tools,它捕获 Vercel AI SDK 请求产生的 OpenTelemetry span,在 Rozenite DevTools 里以 AI SDK Profiler 面板呈现。README 强调 DevTools 是 runtime agnostic 的,端侧和远程运行时都能用,这一点对混合架构有意义:你可以用同一套面板对比本地推理和远程调用的耗时。

使用前提是 Rozenite 已经装好并在应用里启用,仓库里的 apps/expo-example 包含了 native-development 的 Rozenite 接线,可以直接参照。

README 里有一段容易被忽略但很实用的排障说明:如果 AI SDK Profiler 面板可见,但发完一条聊天消息后仍然是空的,就关掉当前 React Native DevTools 窗口重新开一个。文档的解释是陈旧的调试器会话会让 Rozenite 面板保持挂载状态,却收不到当前应用的遥测流。这类问题如果不知道,很容易被误判成自己的 span 没有正确产生,从而在错误的方向上排查。

什么时候它不合适

最直接的不合适场景是 Android 加系统模型的组合。Apple provider 只有 iOS,想在 Android 上用系统级模型,这个库不提供路径,你只能落到 Llama 或 MLC 上自己带模型。

第二种是模型体积超出设备内存的情况。README 对 MLC 明确要求 Xcode 的 Increased Memory Limit 能力,这等于承认默认内存上限不够用。Llama 路径虽然在文档里没写这条,但同样要把权重加载进内存,3B 的 Q4 量化模型加 KV cache 的实际占用需要自己估算。低端机或者内存紧张的后台场景下,端侧推理可能直接触发系统回收。

第三种是团队已经有一套稳定的服务端推理链路,且对延迟不敏感。这种情况下端侧带来的收益主要是隐私和离线可用,但如果你的场景本身要求联网、或者需要远大于 3B 的模型能力,把推理放在服务端仍然更简单,因为模型更新不需要发版,设备兼容也不需要逐个验证。react-native-ai 解决的是「必须在设备上算」的问题,不是「在设备上算更好」的问题。

和直接使用底层运行时相比,多出来的是哪一层

真正的替代方案不是某个同类库,而是绕过 react-native-ai 直接用 llama.rn。llama.rn 本身就是 react-native-ai 的 Llama provider 所依赖的运行时,README 的表格里写得很直白。

两者的差别在于抽象层次。直接用 llama.rn,你拿到的是它的原生接口,模型加载、上下文管理、token 回调都由它定义,你需要自己写一套和业务对接的封装,但换来的是对采样参数、上下文长度、线程数这些细节的完全控制,也不用跟随 AI SDK 的版本节奏。用 react-native-ai,你得到的是 generateText、streamText 这类已经标准化的函数签名,以及和 Web 端一致的调用体验,代价是中间多了一层映射,某些底层参数可能无法透传,而且升级路径被 AI SDK 的版本绑定。

判断标准可以很具体:如果你的代码里已经大量使用 AI SDK 的 message 格式和工具调用,接入 react-native-ai 能省掉一整层适配;如果只是想让手机跑一个 GGUF 做单点推理,直接调 llama.rn 反而更短的路径。MLC 路径同理,它包装的是 MLC LLM,而 MLC LLM 本身有完整的模型编译和部署流程。

编辑结论

如果你的应用是 iOS 且目标设备支持 Apple Intelligence,只想用系统模型做文本生成、嵌入、转写和语音合成,@react-native-ai/apple 是当前门槛最低的路径,装完即用,没有模型下载和内存规划问题。如果必须支持 Android,或者需要指定某个 GGUF 模型,就得走 Llama 或 MLC 分支,代价是自己承担模型下载、prepare 加载、unload 释放这一整套生命周期,以及 Xcode 的 Increased Memory Limit 配置。上项目之前先确认三件事:目标设备的 iOS 版本是否落在表格里那一行(文本生成要 iOS 26+ 且是 Apple Intelligence 设备),你依赖的 AI SDK 版本对应的是 0.11 及以下还是 0.12 及以上,以及你打算跑的那个 GGUF 文件在真机内存里能不能装下。这三条任何一条对不上,改造成本都会超过接入成本。

官方来源

  1. callstackincubator/ai on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
社区笔记

社区笔记