
React Native 端侧 AI:使用 llama.rn 集成指南
如何在 React Native 应用中直接在用户手机上运行语言模型。使用 llama.rn 进行设置、模型加载、流式生成和跨平台注意事项。
llama.rn 是一个 React Native 库,提供 llama.cpp 的 JavaScript 绑定。它通过相同的 JavaScript API 在 iOS(Metal)和 Android(CPU/Vulkan)上原生运行 GGUF 语言模型。
对于 React Native 开发者来说,这意味着一套代码库、一个 API,零云端依赖的端侧 AI。
安装
npm install llama.rn
# 或
yarn add llama.rn
对于 iOS,运行 pod install:
cd ios && pod install
对于 Android,原生库通过 autolinking 自动包含。
Expo
如果您使用 Expo,由于 llama.rn 包含原生代码,需要开发构建(不能使用 Expo Go):
npx expo prebuild
npx expo run:ios # 或 run:android
加载模型
import { initLlama, LlamaContext } from "llama.rn";
let context: LlamaContext | null = null;
async function loadModel(modelPath: string) {
context = await initLlama({
model: modelPath,
n_ctx: 2048, // 上下文窗口
n_threads: 4, // CPU 线程数
n_gpu_layers: 99, // 卸载到 GPU (Metal/Vulkan)
use_mlock: true, // 锁定模型在内存中
});
console.log("Model loaded successfully");
}
模型路径
模型路径必须 指向设备文件系统上的本地文件。如何将文件放到设备上取决于您的分发策略:
与应用打包:
// iOS:复制到应用 bundle,通过 RNFS 引用
import RNFS from "react-native-fs";
const modelPath = `${RNFS.MainBundlePath}/model.gguf`;
// Android:首次启动时从 assets 复制到 files 目录
const modelPath = `${RNFS.DocumentDirectoryPath}/model.gguf`;
安装后下载:
import RNFS from "react-native-fs";
const modelUrl = "https://cdn.example.com/model.gguf";
const modelPath = `${RNFS.DocumentDirectoryPath}/model.gguf`;
const download = RNFS.downloadFile({
fromUrl: modelUrl,
toFile: modelPath,
progress: (res) => {
const percentage = (res.bytesWritten / res.contentLength) * 100;
setDownloadProgress(percentage);
},
});
await download.promise;
生成文本
简单生成
async function generate(prompt: string): Promise<string> {
if (!context) throw new Error("Model not loaded");
const result = await context.completion({
prompt: prompt,
n_predict: 256,
temperature: 0.7,
top_p: 0.9,
stop: ["</s>", "<|eot_id|>"], // 停止标记
});
return result.text;
}
流式生成
async function generateStream(
prompt: string,
onToken: (token: string) => void
): Promise<string> {
if (!context) throw new Error("Model not loaded");
const result = await context.completion(
{
prompt: prompt,
n_predict: 256,
temperature: 0.7,
stop: ["</s>", "<|eot_id|>"],
},
(data) => {
// 每个生成的 token 都会调用
onToken(data.token);
}
);
return result.text;
}
对话补全
对于多轮对话,使用模型的聊天模板格式化提示:
interface Message {
role: "system" | "user" | "assistant";
content: string;
}
function formatChat(messages: Message[]): string {
// Llama 3.2 聊天模板
let prompt = "<|begin_of_text|>";
for (const msg of messages) {
prompt += `<|start_header_id|>${msg.role}<|end_header_id|>\n\n${msg.content}<|eot_id|>`;
}
prompt += "<|start_header_id|>assistant<|end_header_id|>\n\n";
return prompt;
}
async function chat(messages: Message[], onToken: (token: string) => void) {
const prompt = formatChat(messages);
return generateStream(prompt, onToken);
}
React Hook 模式
import { useState, useCallback, useRef } from "react";
import { initLlama, LlamaContext } from "llama.rn";
export function useLlama(modelPath: string) {
const contextRef = useRef<LlamaContext | null>(null);
const [isLoaded, setIsLoaded] = useState(false);
const [isGenerating, setIsGenerating] = useState(false);
const [response, setResponse] = useState("");
const load = useCallback(async () => {
contextRef.current = await initLlama({
model: modelPath,
n_ctx: 2048,
n_threads: 4,
n_gpu_layers: 99,
});
setIsLoaded(true);
}, [modelPath]);
const generate = useCallback(async (prompt: string) => {
if (!contextRef.current) return;
setIsGenerating(true);
setResponse("");
await contextRef.current.completion(
{
prompt,
n_predict: 256,
temperature: 0.7,
stop: ["</s>", "<|eot_id|>"],
},
(data) => {
setResponse((prev) => prev + data.token);
}
);
setIsGenerating(false);
}, []);
const unload = useCallback(() => {
contextRef.current?.release();
contextRef.current = null;
setIsLoaded(false);
}, []);
return { load, generate, unload, isLoaded, isGenerating, response };
}
在组件中使用
function AiChat() {
const { load, generate, unload, isLoaded, isGenerating, response } =
useLlama(modelPath);
const [input, setInput] = useState("");
useEffect(() => {
load();
return () => unload();
}, []);
return (
<View style={styles.container}>
<ScrollView style={styles.responseArea}>
<Text>{response}</Text>
</ScrollView>
<View style={styles.inputRow}>
<TextInput
value={input}
onChangeText={setInput}
style={styles.input}
editable={!isGenerating}
/>
<Button
title="Send"
onPress={() => {
generate(input);
setInput("");
}}
disabled={!isLoaded || isGenerating}
/>
</View>
</View>
);
}
跨平台注意事项
性能一致性
llama.rn 在两个平台上运行原生代码。JavaScript 桥接仅用于传递提示和接收 token。实际推理性能与原生 Swift/Kotlin 集成一致:
| 设备 | 1B 模型 (tok/s) | 3B 模型 (tok/s) |
|---|---|---|
| iPhone 15 Pro | 35-45 | 18-25 |
| iPhone 14 | 25-32 | 14-18 |
| Galaxy S24 | 35-45 | 18-25 |
| 中端 Android | 18-25 | 8-12 |
JS 桥接每个 token 增加不到 1 毫秒的开销。可忽略不计。
模型文件路径差异
iOS 和 Android 将文件存储在不同位置。使用 react-native-fs 获取平台对应的路径:
import RNFS from "react-native-fs";
import { Platform } from "react-native";
const modelDir = Platform.OS === "ios"
? RNFS.DocumentDirectoryPath
: RNFS.DocumentDirectoryPath; // 相同 API,不同底层路径
内存管理
React Native 不暴露直接的内存 API。如果需要在加载前验证可用 RAM,可以通过原生模块进行平台特定检查。或者,捕获加载失败并显示适当的消息。
React Native 中的模型分发
策略 1:小模型打包
对于 1B 模型(约 600MB),与应用打包是可行的:
- iOS:作为资源添加到 Xcode 项目
- Android:超过 150MB 的文件使用 Android Asset Delivery
策略 2:所有模型下载安装
对于 3B 模型(约 1.7GB)或希望保持初始下载较小:
async function ensureModelReady(): Promise<string> {
const modelPath = `${RNFS.DocumentDirectoryPath}/model.gguf`;
const exists = await RNFS.exists(modelPath);
if (exists) return modelPath;
// 带进度的下载
await RNFS.downloadFile({
fromUrl: MODEL_CDN_URL,
toFile: modelPath,
progress: (res) => {
updateProgress(res.bytesWritten / res.contentLength);
},
}).promise;
// 验证完整性
const hash = await RNFS.hash(modelPath, "sha256");
if (hash !== EXPECTED_HASH) {
await RNFS.unlink(modelPath);
throw new Error("Model download corrupted");
}
return modelPath;
}
生产最佳实践
- 延迟加载模型。 仅在用户访问 AI 功能时加载。
- 失焦时卸载。 当 AI 界面不在焦点时释放模型内存。
- 优雅处理错误。 低内存设备可能加载失败。显示清晰的消息。
- 验证下载。 下载后进行 SHA256 哈希检查。损坏的模型会导致崩溃。
- 缓冲 token。 每 2-3 个 token 批量更新 UI 以获得更流畅的文本显示。
- 支持取消。 允许用户中途停止生成。
模型质量取决于微调。基础模型给出通用回复。在您的领域数据上微调的模型(通过 Ertas 等平台)给出针对应用特定用例的定制回复,在相同硬件上以相同速度运行。
Ship AI that runs on your users' devices.
Early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.
Keep reading

AI in React Native: From Cloud APIs to On-Device Models
How to add AI features to React Native apps. Cloud API integration with fetch, on-device inference with llama.cpp bindings, and a practical migration path from one to the other.

AI in iOS Apps: CoreML, Cloud APIs, and On-Device LLMs Compared
Three paths to AI in your iOS app. CoreML for Apple's ecosystem, cloud APIs for capability, and on-device LLMs via llama.cpp for cost and privacy. A practical comparison for Swift developers.

AI in Android Apps: ML Kit, Cloud APIs, and On-Device LLMs Compared
Three paths to AI in your Android app. Google ML Kit for common tasks, cloud APIs for full LLM capability, and on-device models via llama.cpp for cost and privacy. A practical comparison for Kotlin developers.