跳转到主要内容
本页将指导你在 Kotlin APP中运行第一个模型,然后再换用另一个模型。如需一个完整的参考应用——包含聊天 UI、模型选择器和 VLM 支持——请参阅示例应用

前置条件

  • 已将 SDK 添加到你的 Gradle 项目——参阅安装
  • 一台搭载 骁龙 8 至尊版骁龙 8 至尊版 Gen 5 的手机。
  • AndroidManifest.xml 中声明 INTERNET 权限(SDK 会在首次使用时从 Hugging Face / Qualcomm AI Hub 拉取权重)。

运行你的第一个模型

无论使用哪个模型,流程都是相同的:初始化 SDK → 拉取权重 → 加载 → 生成。下面是一个使用 unsloth/Qwen3-0.6B-GGUF 的最小端到端示例——这是一个小型的 Qwen3 0.6B 对话模型,可以在任何受支持的芯片组上运行。
1

Init the SDK

在应用启动时调用一次(幂等——可安全地放在 Activity.onCreate 中):
GenieXSdk.getInstance().init(context)
2

Pull the model

pullFlow 会流式推送进度事件。在 Dispatchers.IO 上的协程中运行:
ModelManagerWrapper.pullFlow(
    ModelPullInput(
        model_name = "unsloth/Qwen3-0.6B-GGUF",
        precision  = "Q4_0",
        hub        = HubSource.HUGGINGFACE,
    )
).collect { event ->
    when (event) {
        is ModelManagerWrapper.PullEvent.Progress  -> /* update UI */
        ModelManagerWrapper.PullEvent.Completed    -> /* done */
        is ModelManagerWrapper.PullEvent.Error     -> /* show error */
    }
}
下载支持断点续传——在拉取过程中杀掉应用并重新运行,会从上次中断处继续。
3

Load the model

解析磁盘上的路径并构建一个 LlmWrapper
val paths = ModelManagerWrapper.getPaths("unsloth/Qwen3-0.6B-GGUF")
    ?: error("Model not downloaded")

val llm = LlmWrapper.builder()
    .llmCreateInput(
        LlmCreateInput(
            model_name = paths.model_name,
            model_path = paths.model_path,
            config     = ModelConfig(nCtx = 4096),
            runtime_id  = "llama_cpp",
            compute_unit  = null,   // null → NPU on Snapdragon (recommended)
        )
    )
    .build()
    .getOrThrow()
4

Generate

应用 chat template,然后从流式 flow 中收集 token:
val chat = arrayListOf(ChatMessage("user", "What is AI?"))
val templated = llm.applyChatTemplate(chat.toTypedArray(), null, false).getOrThrow()

llm.generateStreamFlow(
    templated.formattedText,
    GenerationConfig(maxTokens = 2048),
).collect { result ->
    when (result) {
        is LlmStreamResult.Token     -> print(result.text)
        is LlmStreamResult.Completed -> println("\nDone")
        is LlmStreamResult.Error     -> println("Error: ${result.throwable}")
    }
}
始终将 templated.formattedText(经过 chat template 处理的 prompt)传入 generateStreamFlow,而 不是 原始用户文本。原生工作流期望接收一个已经过 template 处理的 prompt。

切换模型

切换模型主要就是更改 model_nameruntime_id。这里有两种运行环境:
  • llama_cpp —— 运行任意 GGUF 模型。通过 compute_unit 支持 NPU / GPU / CPU 计算单元。
  • qairt(Qualcomm AI Engine Direct)—— 运行 Qualcomm AI Hub 模型。仅支持 NPU,在 Android 上需要显式指定 chipset

另一个 GGUF 模型 (llama.cpp)

只需更改 model_name(如果想要不同精度,再更改 precision)——其余流程完全相同:
ModelPullInput(
    model_name = "unsloth/Qwen3-VL-2B-Instruct-GGUF",
    precision  = "Q4_0",
    hub        = HubSource.HUGGINGFACE,
)
对于 VLM,还需将 paths.mmproj_path 传入 VlmCreateInput——参阅 API 参考 → VLM

Qualcomm AI Hub 模型(通过 Qualcomm AI Engine Direct 使用 NPU)

Qualcomm AI Hub 模型会按芯片组预编译,且仅在 NPU 上运行。在 Android 上你 必须 传入 chipset
ModelManagerWrapper.pullFlow(
    ModelPullInput(
        model_name = "ai-hub-models/Qwen3-4B-Instruct-2507",
        hub        = HubSource.AUTO,   // routes ai-hub-models/* to Qualcomm AI Hub
        chipset    = "SM8750",         // SM8750 = 8 Elite, SM8850 = 8 Elite Gen 5
    )
).collect { /* … */ }
然后在 LlmCreateInput 中切换为 runtime_id = "qairt"。受支持的 Qualcomm AI Hub 仓库参阅 API 参考

切换计算单元 (NPU / GPU / CPU)

仅适用于 llama_cpp——在 LlmCreateInput 上设置 compute_unit
compute_unit计算单元
null or "npu"Hexagon NPU(骁龙上推荐)。
"gpu"通过 OpenCL 使用 Adreno GPU。
"cpu"纯 CPU。可在任意 ARM64 芯片组上运行。
Qualcomm AI Engine Direct 会忽略此设置——cpu/gpu 会带警告地被强制转换为 NPU。

使用本地模型

如果权重已经在设备上——通过 adb push 侧载、打包进应用的 files 目录,或由其他工具生成——只需让模型管理器指向该目录,而不是某个 hub。设置 hub = HubSource.LOCALFS,并将 local_path 指向磁盘上的位置。pullFlow 会将其导入到 SDK 缓存中(不联网),之后 getPaths / LlmWrapper 的用法与下载的模型完全一致。 这里的 model_name 只是缓存键——任意 org/repo 风格的字符串都可以,常见约定是加上 local/ 前缀。运行时由导入的目录布局决定,而不是由你指定:GGUF 目录导入为 llama_cpp,AI Hub 目录/zip 导入为 qairt。当你导入混合类型的模型时,请优先使用 paths.runtime_id(权威值),而不是硬编码 runtime_id

本地 GGUF 模型 (llama.cpp)

local_path 是一个包含 .gguf 文件的目录。如果存在 geniex.json manifest 则会使用它,否则会根据文件名推断布局。对于 VLM,将 mmproj-*.gguf 放入同一目录即可。
ModelManagerWrapper.pullFlow(
    ModelPullInput(
        model_name = "local/qwen3-0.6b",
        hub        = HubSource.LOCALFS,
        local_path = "/data/local/tmp/qwen3-0.6b",   // 包含 *.gguf 的目录
    )
).collect { event ->
    when (event) {
        is ModelManagerWrapper.PullEvent.Progress  -> /* update UI */
        ModelManagerWrapper.PullEvent.Completed    -> /* imported */
        is ModelManagerWrapper.PullEvent.Error     -> /* show error */
    }
}
然后使用 runtime_id = "llama_cpp" 加载——与下载模型的流程完全相同:
val paths = ModelManagerWrapper.getPaths("local/qwen3-0.6b")
    ?: error("Model not imported")

val llm = LlmWrapper.builder()
    .llmCreateInput(
        LlmCreateInput(
            model_name = paths.model_name,
            model_path = paths.model_path,
            config     = ModelConfig(nCtx = 4096),
            runtime_id  = "llama_cpp",
            compute_unit  = null,   // null → 骁龙上使用 NPU(推荐)
        )
    )
    .build()
    .getOrThrow()

本地 Qualcomm AI Hub 模型 (qairt)

local_path 指向以下两者之一:已解压的 AI Hub 目录(一个 metadata.json 加上一个或多个 .bin 分片),或从 Qualcomm AI Hub 下载的 AI Hub .zip。插件会被强制设为 qairt,模态(LLM 还是 VLM)会从 metadata.json 中读取。无需 chipset——该 bundle 已经针对特定芯片组编译完成。
ModelManagerWrapper.pullFlow(
    ModelPullInput(
        model_name = "local/qwen3-4b-2507",
        hub        = HubSource.LOCALFS,
        local_path = "/data/local/tmp/Qwen3-4B-Instruct-2507",  // 已解压目录或 .zip
    )
).collect { /* Progress / Completed / Error */ }
然后使用 runtime_id = "qairt" 加载:
val paths = ModelManagerWrapper.getPaths("local/qwen3-4b-2507")
    ?: error("Model not imported")

val llm = LlmWrapper.builder()
    .llmCreateInput(
        LlmCreateInput(
            model_name = paths.model_name,
            model_path = paths.model_path,
            config     = ModelConfig(max_tokens = 2048, enable_thinking = false),
            runtime_id  = "qairt",
            compute_unit  = null,   // qairt 仅支持 NPU
        )
    )
    .build()
    .getOrThrow()
本地导入时你无需自己编写 geniex.json——模型管理器会在导入过程中于其缓存中生成一份。它从 local_path 读取的内容取决于布局:GGUF 目录需要一个 *.gguf(若存在 geniex.json 则会被采用,否则会根据文件名推断 manifest);QAIRT 目录则通过 metadata.json + .bin 分片(或 .zip)来识别。对于 QAIRT,请按 Qualcomm AI Hub 提供的原样导入已解压的 bundle 或 .zip——一个只含零散 .bin 文件、缺少 metadata.json 的目录将无法被识别。

使用示例应用

示例应用是一个完整连通的聊天客户端,构建在上述代码片段之上。当你构建自己的 UI 时,有几个值得借鉴的模式:
  • 模型选择器 UI —— 下拉菜单由 app/src/main/assets/model_list.json 驱动。每个条目固定了一个 model_namehub,以及一个 chipset(对于 Qualcomm AI Engine Direct)。编辑此文件即可添加新模型而无需改动代码。
  • 带进度的断点续传下载 —— 来自 pullFlowProgress 事件携带每个文件的字节计数;示例将它们直接接入 LinearProgressIndicator
  • 运行环境感知的计算单元选择器 —— 当所选模型使用 Qualcomm AI Engine Direct 时,选择器会隐藏 GPU/CPU 选项。参阅 LoadDialog.kt
  • VLM 图片选择器 —— 对于 VLM,示例会将绝对文件路径传入 VlmContent("image", path)。不要传入 content URI——原生侧会直接读取文件。
克隆 qualcomm/ai-hub-apps,在 Android Studio 中打开并点击 Run ▶

下一步

API 参考

Wrapper 类、运行环境 / 计算单元选择与数据结构。

平台与运行环境

骁龙平台,以及何时选择 llama.cpp 或 Qualcomm AI Engine Direct。