返回博客

Android 端侧 AI 实战:Gemini Nano 集成指南

2026 年是端侧 AI 从概念走向落地的关键之年。从 Google 的 Gemini Nano 到 Apple 的端侧模型,各厂商都在推动 AI 能力「走出云端」。本文基于我的实际集成经验,深入解析 Android 端侧 AI 的核心方案:Gemini Nano + AICore + ML Kit GenAI API,并提供一个完整的实战案例。

📌 前置要求:本文适用于 Android 14+ 设备,需要支持 AICore(Android 16/17 原生支持)。部分功能可能因设备硬件差异而表现不同。

为什么选择端侧 AI?

在将 AI 能力集成到移动应用时,传统方案存在几个显著痛点:

端侧 AI(On-Device AI)完美解决以上问题:

Gemini Nano 架构解析

Gemini Nano 是 Google 专为端侧运行优化的轻量级模型通过 Android 系统层的 AICore 运行时提供服务。理解这个架构是成功集成的关键。

三层架构

层级组件职责
应用层ML Kit GenAI API高级封装提供简洁的调用接口
系统层AICore模型管理、推理调度、NPU 加速
模型层Gemini Nano实际的 AI 推理计算

AICore 的核心职责

AICore 是 Android 16/17 引入的系统级 AI 运行时它充当 App 与 Gemini Nano 模型的 broker:

💡 关键点:你的应用不需要直接与 AICore 交互而是通过 ML Kit 的高级 API。ML Kit 会自动处理与 AICore 的通信。

环境配置

1. 添加依赖

build.gradle (app) 中添加 ML Kit 生成式 AI 依赖:

dependencies {
    // ML Kit GenAI API (powered by Gemini Nano)
    implementation 'com.google.mlkit:genai-common:0.1.0'
    implementation 'com.google.mlkit:text-generation:16.0.0'
    
    // 如果需要图像描述功能
    implementation 'com.google.mlkit:image-labeling:17.0.7'
}

2. 检查设备兼容性

在调用前检查设备是否支持端侧 AI 能力:

import com.google.mlkit.common.MlKitException
import com.google.mlkit.common.model.RemoteModelManager
import com.google.mlkit.textgeneration.TextGeneration

// 检查设备是否支持
fun checkDeviceSupport(): Boolean {
    return try {
        // 尝试获取模型管理器
        val manager = RemoteModelManager.getInstance()
        // 如果能正常获取说明支持
        true
    } catch (e: MlKitException) {
        // 不支持的设备会抛出异常
        false
    }
}

3. 配置权限

AICore 不需要特殊权限但首次调用会触发模型下载。建议:

功能一:文本摘要

ML Kit 提供文本摘要功能可以将长文本压缩为简洁摘要:

import com.google.mlkit.textgeneration.TextGeneration
import com.google.mlkit.textgeneration.TextGenerator
import com.google.mlkit.textgeneration.TextGeneratorOptions

// 创建生成器
val options = TextGeneratorOptions.Builder()
    .setModelType(TextGeneratorOptions.LOCAL_LITE)
    .build()

val textGenerator = TextGeneration.getClient(options)

// 生成摘要
fun summarizeText(longText: String) {
    val input = "Provide a brief summary of the following text: $longText"
    
    textGenerator.generate(input)
        .addOnSuccessListener { result ->
            val summary = result.text
            Log.d("GeminiNano", "Summary: $summary")
        }
        .addOnFailureListener { e ->
            Log.e("GeminiNano", "Error: ${e.message}")
        }
}

完整示例:摘要功能

class Summarizer(private val context: Context) {
    
    private val textGenerator: TextGenerator by lazy {
        val options = TextGeneratorOptions.Builder()
            .setModelType(TextGeneratorOptions.LOCAL_LITE)
            .build()
        TextGeneration.getClient(options)
    }
    
    fun summarize(
        text: String,
        onSuccess: (String) -> Unit,
        onError: (Exception) -> Unit
    ) {
        // 构建提示词
        val prompt = buildPrompt(text)
        
        textGenerator.generate(prompt)
            .addOnSuccessListener { result ->
                onSuccess(result.text.trim())
            }
            .addOnFailureListener { e ->
                onError(e)
            }
    }
    
    private fun buildPrompt(text: String): String {
        return """
            请用不超过 100 字总结以下内容:
            
            $text
            
            摘要:
        """.trimIndent()
    }
    
    fun close() {
        textGenerator.close()
    }
}

功能二:文本校对

校对功能可以检测并修正文本中的语法错误和用词问题:

import com.google.mlkit.textgeneration.TextGeneration

// 文本校对
fun proofreadText(text: String) {
    val prompt = """
        请校对以下文本修正语法错误和用词问题只返回修正后的文本:
        
        $text
    """.trimIndent()
    
    textGenerator.generate(prompt)
        .addOnSuccessListener { result ->
            val corrected = result.text.trim()
            Log.d("Proofread", "Corrected: $corrected")
        }
        .addOnFailureListener { e ->
            Log.e("Proofread", "Error: ${e.message}")
        }
}
⚠️ 注意:校对功能同样使用本地 Lite 模型响应质量可能不如云端版本。对于正式场景建议人工复核。

功能三:文本重写

重写功能可以将文本改写成不同风格(如正式、口语化、简洁):

// 风格重写示例
fun rewriteToStyle(text: String, style: String) {
    val stylePrompt = when (style) {
        "formal" -> "正式"
        "casual" -> "口语化"
        "concise" -> "简洁"
        else -> "保持原样"
    }
    
    val prompt = """
        请将以下文本改写成$stylePrompt 风格只返回改写后的文本:
        
        $text
    """.trimIndent()
    
    textGenerator.generate(prompt)
        .addOnSuccessListener { result ->
            val rewritten = result.text.trim()
            // 处理结果
        }
}

功能四:图像描述(进阶)

虽然 ML Kit 的主 API 是文本能力但可以通过组合实现图像理解:

📌 说明:原生 Gemini Nano 主要面向文本任务。对于图像理解推荐结合 ML Kit 的图像标注 API 或使用云端 API + 本地缓存的混合方案。
// 结合图像标注实现图像理解
import com.google.mlkit.image labeling.ImageLabeling
import com.google.mlkit.image labeling.defaultImageLabeler

class ImageDescriber(private val context: Context) {
    
    private val imageLabeler = ImageLabeling.getClient(
        defaultImageLabelerOptions {
            setConfidenceThreshold(0.7f)
        }
    )
    
    private val textGenerator = TextGeneration.getClient(
        TextGeneratorOptions.Builder()
            .setModelType(TextGeneratorOptions.LOCAL_LITE)
            .build()
    )
    
    // 获取图像标签后生成描述
    fun describeImage(bitmap: Bitmap) {
        imageLabeler.process(bitmap)
            .addOnSuccessListener { labels ->
                // 提取标签
                val tags = labels.joinToString("、") { it.text }
                
                // 使用 Gemini Nano 生成自然语言描述
                val prompt = "用一句话描述这张图片包含的要素:$tags"
                
                textGenerator.generate(prompt)
                    .addOnSuccessListener { result ->
                        val description = result.text.trim()
                        Log.d("ImageDesc", description)
                    }
            }
            .addOnFailureListener { e ->
                Log.e("ImageDesc", e.message ?: "Error")
            }
    }
}

设备兼容性与踩坑记录

集成过程中我遇到以下问题整理成避坑指南:

常见问题

问题原因解决方案
首次调用特别慢模型需要下载提示用户在 WiFi 下使用或预加载
返回空结果模型未就绪检查 AICore 状态等待模型下载完成
抛出 ModuleNotFoundException设备不支持 AICore回退到云端 API 或提示用户
内存占用高模型运行在 CPU确保设备有足够内存或降低并发

兼容性检查工具

// 完整的兼容性检查
object AICoreChecker {
    
    fun checkCompatibility(context: Context): CompatibilityResult {
        return try {
            // 尝试初始化
            val options = TextGeneratorOptions.Builder()
                .setModelType(TextGeneratorOptions.LOCAL_LITE)
                .build()
            val client = TextGeneration.getClient(options)
            client.close()
            
            CompatibilityResult(
                supported = true,
                message = "设备支持端侧 AI"
            )
        } catch (e: Exception) {
            CompatibilityResult(
                supported = false,
                message = "设备不支持: ${e.message}"
            )
        }
    }
    
    data class CompatibilityResult(
        val supported: Boolean,
        val message: String
    )
}

性能优化建议

1. 模型预加载

// 在 Application 中预加载模型
class MyApp : Application() {
    
    private val textGenerator: TextGenerator by lazy {
        TextGeneration.getClient(
            TextGeneratorOptions.Builder()
                .setModelType(TextGeneratorOptions.LOCAL_LITE)
                .build()
        )
    }
    
    override fun onCreate() {
        super.onCreate()
        // 预热模型
        warmUpModel()
    }
    
    private fun warmUpModel() {
        // 发送一个空请求预热
        textGenerator.generate("Hello")
            .addOnSuccessListener { /* 预热完成 */ }
    }
}

2. 批量处理

对于多个文本处理使用批量模式减少模型加载开销:

// 不要频繁创建和销毁生成器
class TextProcessor {
    // 复用单个生成器实例
    private val generator: TextGenerator by lazy { 
        TextGeneration.getClient(/* options */)
    }
    
    // 批量处理
    fun processBatch(texts: List) {
        // 将多个文本组合成一个请求
        val combined = texts.mapIndexed { index, text ->
            "${index + 1}. $text"
        }.joinToString("\n")
        
        val prompt = "处理以下内容:\n$combined"
        // 一次性调用
    }
    
    // 使用完后统一释放
    fun release() {
        generator.close()
    }
}

3. 异步处理

模型推理是耗时操作务必在后台线程执行:

// 使用协程处理
fun generateAsync(prompt: String): Deferred {
    return CoroutineScope(Dispatchers.IO).async {
        try {
            textGenerator.generate(prompt).await().text.trim()
        } catch (e: Exception) {
            throw e
        }
    }
}

4. 结果缓存

相同输入可以缓存结果避免重复计算:

// 简单的 LRU 缓存
class ResultCache(private val maxSize: Int = 100) {
    
    private val cache = object : LinkedHashMap(maxSize, 0.75f, true) {
        override fun removeEldestEntry(eldest: MutableMap.MutableEntry?): Boolean {
            return size > maxSize
        }
    }
    
    fun get(key: String): String? = cache[key]
    
    fun put(key: String, value: String) {
        cache[key] = value
    }
}

实战案例:智能笔记应用

结合以上所有功能以下是简化的智能笔记应用架构:

class SmartNoteProcessor(
    private val context: Context,
    private val summarizer: Summarizer,
    private val proofreader: Proofreader
) {
    
    // 智能摘要
    fun autoSummarize(note: String): String {
        // 输入验证
        if (note.length < 100) return note
        
        return summarizer.summarize(note)
    }
    
    // 自动校对
    fun autoProofread(note: String): String {
        return proofreader.proofread(note)
    }
    
    // 智能处理流程
    fun processNote(note: String): ProcessedNote {
        val proofread = autoProofread(note)
        val summarized = if (note.length > 500) {
            autoSummarize(note)
        } else null
        
        return ProcessedNote(
            original = note,
            corrected = proofread,
            summary = summarized,
            timestamp = System.currentTimeMillis()
        )
    }
    
    data class ProcessedNote(
        val original: String,
        val corrected: String,
        val summary: String?,
        val timestamp: Long
    )
}

总结

Gemini Nano 代表了移动端侧 AI 的重要方向通过 ML Kit 的高级 API 开发者可以快速将 AI 能力引入应用而无需关心底层模型管理。但需要注意:

随着 Android 系统的演进和芯片能力的提升端侧 AI 将成为移动开发的标配。建议现在就开始尝试为未来做好准备。

💡 扩展方向:如果端侧能力不满足需求可以考虑「本地 + 云端」混合方案使用本地模型处理简单任务复杂任务交给云端。