共计 3445 个字符,预计需要花费 9 分钟才能阅读完成。
背景痛点
在安卓设备上部署大型语言模型(LLM)如 ChatGPT 时,开发者常遇到几个核心问题:

- 模型体积庞大:完整的 GPT 模型可能占用数 GB 存储空间,远超移动设备可用容量
- 计算资源限制:移动端 CPU/GPU 算力有限,推理延迟可能达到秒级甚至更高
- 内存压力:加载模型时容易触发 OOM(Out Of Memory)导致应用崩溃
- 网络依赖:API 调用方案受网络质量影响显著,弱网环境下体验下降
技术选型
方案一:本地部署模型
优点:
– 完全离线运行,不依赖网络
– 数据全程保留在设备端,隐私性好
缺点:
– 需要处理模型量化(如 8bit/4bit 压缩)
– 推理速度较慢(移动端 CPU 单次推理可能需要 5 -10 秒)
– 应用安装包体积暴增
方案二:API 远程调用
优点:
– 实时获取最新模型能力
– 设备资源占用极低
– 响应速度稳定(通常 1 - 3 秒)
缺点:
– 持续产生 API 调用费用
– 需要处理网络异常情况
– 存在隐私合规风险
推荐策略:对大多数应用场景,建议采用 API 方案;仅在绝对需要离线的特殊场景(如军工、涉密应用)考虑本地部署。
核心实现
API 调用方案(Kotlin 实现)
- 添加依赖项:
// build.gradle.kts
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.squareup.moshi:moshi-kotlin:1.14.0")
- 封装 HTTP 请求:
class ChatGptService(private val apiKey: String) {private val client = OkHttpClient()
private val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
suspend fun query(prompt: String): String {val requestBody = """{"model":"gpt-3.5-turbo","messages": [{"role":"user","content":"$prompt"}]
}
""".trimIndent()
val request = Request.Builder()
.url("https://api.openai.com/v1/chat/completions")
.addHeader("Authorization", "Bearer $apiKey")
.post(requestBody.toRequestBody("application/json".toMediaType()))
.build()
return try {client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code: $response")
val adapter = moshi.adapter(ApiResponse::class.java)
val apiResponse = adapter.fromJson(response.body!!.source())!!
apiResponse.choices.first().message.content}
} catch (e: Exception) {"请求失败: ${e.localizedMessage}"
}
}
}
@JsonClass(generateAdapter = true)
data class ApiResponse(val choices: List<Choice>)
data class Choice(val message: Message)
data class Message(val content: String)
本地部署方案关键步骤
- 模型转换:
- 使用
transformers库将 PyTorch 模型转换为 ONNX 格式 -
通过
onnxruntime-android进行量化压缩 -
NDK 集成:
android {
defaultConfig {
ndk {abiFilters 'armeabi-v7a', 'arm64-v8a'}
}
}
dependencies {implementation 'com.microsoft.onnxruntime:onnxruntime-android:1.14.0'}
- 推理代码示例:
val ortEnv = OrtEnvironment.getEnvironment()
val sessionOptions = OrtSession.SessionOptions()
// 加载量化后的模型
val modelBytes = assets.open("chatgpt_quantized.onnx").readBytes()
val session = ortEnv.createSession(modelBytes, sessionOptions)
fun generateText(input: String): String {val inputs = mapOf("input_ids" to createInputTensor(input))
val results = session.run(inputs)
return processOutput(results)
}
性能优化
内存管理三板斧
- 分块加载:对于本地模型,实现按需加载参数模块
- 对象池复用:预分配 Tensor 内存避免频繁 GC
- 低精度计算:使用 FP16 或 INT8 量化(性能损失约 2 -5%,内存减少 50-75%)
延迟优化技巧
- 预加载模型:在 SplashScreen 阶段初始化模型
- 缓存机制:对常见问题缓存标准回答
- 请求合并:当用户连续输入时,合并多个查询为一个批次
安全实践
API 密钥保护
- 禁止硬编码在客户端
- 通过后端服务中转请求(最佳实践)
- 若必须前端存储,使用 Android Keystore 加密
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)
keyGenerator.init(
KeyGenParameterSpec.Builder(
"chatgpt_key",
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).apply {setBlockModes(KeyProperties.BLOCK_MODE_GCM)
setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
}.build())
用户数据隐私
- 匿名化处理用户输入(移除手机号、地址等 PII 信息)
- 提供「不存储对话」的选项
- 遵守 GDPR 等数据保护法规
避坑指南
高频问题解决方案
- OOM 崩溃:
- 在 AndroidManifest 中启用
largeHeap="true" -
添加
android:hardwareAccelerated="false"到特定 Activity -
网络中断处理:
// 指数退避重试机制
suspend fun <T> withRetry(
times: Int = 3,
initialDelay: Long = 1000,
maxDelay: Long = 10000,
block: suspend () -> T): T {
var currentDelay = initialDelay
repeat(times - 1) { attempt ->
try {return block()
} catch (e: Exception) {delay(currentDelay)
currentDelay = (currentDelay * 2).coerceAtMost(maxDelay)
}
}
return block() // 最后一次尝试}
- 冷启动延迟:
- 使用 WorkManager 预加载模型
- 显示渐进式加载动画
进阶思考
当基础功能实现后,可以考虑:
- 如何实现模型动态更新(不发布新版本更新模型)?
- 混合部署方案:简单问题本地处理,复杂问题回源 API
- 针对安卓 TV 或车载设备的特殊优化
希望这篇指南能帮你避开我们踩过的坑。如果你尝试过模型量化或在端侧部署有独特经验,欢迎分享你的实践心得——移动端 LLM 部署还有哪些值得探索的方向?
正文完
