硬件:Windows11电脑+Linux服务器+3588Android12开发板  

软件:vscode+Android studio+adb

目录

模型下载

模型转换为RKLLM格式(Linux服务器端)

APK开发(Windows PC端)

连接开发板并调试

方法一:在Android studio中选择3588开发板,进入调试​编辑

方法二:也可以通过adb命令直接安装在板子(推荐方法一)

补充:理解这些文件间的关系


模型下载

模型链接Qwen3-1.7b-医疗微调微调 · 模型库

通过modelscope工具下载到服务器上

pip install modelscope #下载工具包

进入目标下载目录,下载模型到当前目录

modelscope download --model testUser/Qwen3-1.7b-Medical-R1-sft model.safetensors --local_dir .

最终下载的文件 也可以直接拉取整个文件夹到目标目录下

模型转换为RKLLM格式(Linux服务器端)

RKLLM-Toolkit 支持将 Hugging Face 格式模型转为 RK3588 适配的.rkllm格式,核心是「加载→校准→量化→编译→打包」。

https://modelscope.cn/models/testUser/Qwen3-1.7b-Medical-R1-sft/file/view/master/model.safetensors?status=2 这个格式模型是SafeTensors格式,是Hugging Face的。

1.准备量化校准数据(dataset.json):
量化需要少量真实数据来校准精度。由于是医疗模型,放入一些医疗相关的问题。                       在模型转换目录下创建 dataset.json

[
    {"input": "你可以帮我写一份病历吗?", "target": "当然可以,请提供患者的症状。"},
    {"input": "感冒了应该吃什么药?", "target": "建议多喝水,可以服用感冒灵。"},
    {"input": "什么是高血压?", "target": "高血压是一种常见的心血管疾病。"},
    {"input": "肚子疼怎么办?", "target": "请详细描述疼痛的位置和持续时间。"},
    {"input": "头痛医头脚痛医脚是什么意思?", "target": "这是一个成语,指只做表面文章。"}
]

2.编写转换脚本 脚本流程 :加载 -> 试跑(校准) -> 压缩(量化) -> 翻译(编译) -> 打包                  (参考官方rknn-llm/doc/Rockchip_RKLLM_SDK_CN_1.2.3.pdf at main · airockchip/rknn-llm)

3.运行转换脚本python convert_qwen3_medical_w8a8.py

# 确保RKLLM-Toolkit已安装(参考官方文档)
pip install rknn-llm==1.2.3

# 执行转换
python convert_qwen3_medical_w8a8.py

4.交叉编译demo,验证模型可用性

推送文件到板子上并赋予权限运行

APK开发(Windows PC端)

下载安装Android Studio

1.创建 Native C++ 项目

  • 打开 Android Studio,新建项目→选择「Native C++」→下一步;
  • 配置项目:
    • 名称:qwen3_medical;
    • 包名:com.example.qwen3_medical;
    • 语言:Java;
    • 最小 SDK:Android 12(API 31);
    • C++ 标准:C++17;
  • 完成创建,自动生成基础工程结构。

2.集成 RKLLM Runtime 资源https://github.com/airockchip/rknn-llm/tree/main

在app/src/main下新建jniLibs/arm64-v8a目录,将 RKLLM SDK 中的librkllmrt.so,libomp.so(路径:rkllm-runtime/Android/arm64-v8a/)复制到该目录。

复制 RKLLM 头文件rkllm.h到app/src/main/cpp目录(与native-lib.cpp 同目录)

项目结构如下图:

3.配置 CMakeLists.txt(这个文件告诉编译器,去哪里找 rkllmrt.so 和 libomp.so 这些工具,然后将它们和 native-lib.cpp 链接到一起)

cmake_minimum_required(VERSION 3.22.1)
project("qwen3_medical")

# 1. 导入预编译的 librkllmrt.so
add_library(rkllmrt SHARED IMPORTED)
set_target_properties(rkllmrt PROPERTIES
    # 路径对应你的文件结构:从cpp目录向上到main,再进入jniLibs/arm64-v8a
    IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/librkllmrt.so"
)

# 2. 导入预编译的 libomp.so
add_library(libomp SHARED IMPORTED)
set_target_properties(libomp PROPERTIES
    IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libomp.so"
)

# 3. 编译当前项目的C++源码为动态库
add_library(${CMAKE_PROJECT_NAME} SHARED
    native-lib.cpp
)

# 4. 链接所有依赖库到目标库
target_link_libraries(${CMAKE_PROJECT_NAME}
    # 刚才导入的两个预编译库
    rkllmrt
    libomp
    # 系统基础库
    android
    log
)
配置段作用
add_library(rkllmrt SHARED IMPORTED)声明导入外部预编译的 librkllmrt.so,而非编译新库
IMPORTED_LOCATION指定 so 库的实际路径,${CMAKE_SOURCE_DIR}是当前 CMakeLists.txt 所在目录
target_link_libraries将所有依赖库链接到项目的动态库中,确保运行时能调用到 RKLLM 的函数

CMakeLists.txt 修改完成后,需同步配置

  • 点击顶部菜单栏的 File → Sync Project with Gradle Files(或点击右上角的「大象 + 刷新」图标);
  • 等待同步完成,若控制台无「CMake 配置错误」「找不到 so 文件」等提示,说明基础配置生效;

 4..配置build.gradle.kts

确保 Android Studio仅编译 arm64-v8a 架构的 so 库,否则它可能尝试构建 x86 版本,但找不到对应的 .so 库而报错。

打开 app/build.gradle.kts (或 build.gradle),确保有以下配置,强制 APK 只包含 64 位 ARM 代码

android {
    // ... 其他配置
    defaultConfig {
        // ...
        externalNativeBuild {
            cmake {
                cppFlags("")
                // 强制指定只编译 64位 ARM 架构
                abiFilters("arm64-v8a") 
            }
        }
        
        ndk {
            // 打包 APK 时只包含 arm64-v8a 的库
            abiFilters += "arm64-v8a" 
        }
    }
}

5.编写 C++ JNI (native-lib.cpp)层代码

JNI 层是 Java 与 C++ 的 “桥梁”,让 Java 层(MainActivity)能调用 C/C++ 写的底层功能(如项目中要调用 RKLLM 模型的加载、推理)。

  • rkllm.h :
    这是瑞芯微官方提供的头文件。相当于说明书,规定了可以使用哪些功能、需要传入什么参数、结构体长什么样。它是标准,不能修改。

  • native-lib.cpp 必须严格遵守 rkllm.h 的定义,函数名、参数类型,否则会报错。

6.编写 Java 层逻辑 (MainActivity.java)

注意其中的module path 路径需为开发板上真实的模型路径(需将模型上传到开发板此路径下)

7.编写UI布局(activity_main.xml)

需确保控件的 ID 和 Java 代码里的一致

连接开发板并调试

开发板连接网络,并进入开发者模式,打开开发板的无线调试和网络adb调试。通过adb工具连接到开发板

方法一:在Android studio中选择3588开发板,进入调试
  • 点击 Android Studio 顶部 Run,运行项目 。
  • 打开 Logcat:

    • 在 Android Studio 底部栏打开 Logcat 标签页。

    • 在 Logcat 的搜索框里输入:RKLLM_JNI (这是在 C++ 代码里定义的日志标签)。

可以看到模型初始化成功,开发板连接显示器,可在桌面上看到应用,并正常对话交互

方法二:也可以通过adb命令直接安装在板子(推荐方法一)

点击generate apks

在下方可看到build output

项目路径下查看生成的apk文件 通过adb窗口install

之后可以开发板连接显示器,双击桌面的apk运行,并可在PC机cmd命令行中通过logcat命令查看日志。

补充:理解这些文件间的关系

┌─────────────────────────────────────────────────────────────────┐
│ 层级         │ 核心文件                                      │ 核心职责                          │
├──────────────┼─────────────────────────────────────────────┼─────────────────────────────────┤
│ UI层         │ activity_main.xml                           │ 定义界面布局(控件、样式)        │
├──────────────┼─────────────────────────────────────────────┼─────────────────────────────────┤
│ Java业务层   │ MainActivity.java                           │ 处理UI交互、调用JNI、管理对话逻辑 │
├──────────────┼─────────────────────────────────────────────┼─────────────────────────────────┤
│ JNI桥接层    │ native-lib.cpp + rkllm.h                    │ 连接Java与C++,调用RKLLM接口     │
├──────────────┼─────────────────────────────────────────────┼─────────────────────────────────┤
│ RKLLM运行时  │ librkllmrt.so + libomp.so                   │ 提供NPU加速推理的底层实现        │
├──────────────┼─────────────────────────────────────────────┼─────────────────────────────────┤
│ 模型文件     │ qwen3_medical_rk3588_w8a8.rklm              │ 医疗模型的权重与编译指令(NPU可执行)│
├──────────────┼─────────────────────────────────────────────┼─────────────────────────────────┤
│ 编译配置层   │ CMakeLists.txt + app/build.gradle           │ 控制代码编译、依赖链接、APK打包 │
└─────────────────────────────────────────────────────────────────┘

1.Java 层负责 UI 交互,调用 JNI 接口,实现多轮对话逻辑

  • 调用 C++ 的 initModel 和 chat 接口。

  • 接收 C++ 回调回来的文字,显示在屏幕上。

  • 负责拼接历史对话(Prompt Engineering),保证多轮对话连贯。

RKLLM 的 chat 接口是无状态的。要实现多轮对话,需要在 Java 里把历史对话拼接到一起

  • 多轮对话状态维护:

    • 在 Java 层维护一个 StringBuilder promptBuilder。

    • 用户发消息 -> promptBuilder.append(用户格式)。

    • 调用推理 -> 模型生成文本 -> 存入 currentAiResponse。

    • 推理结束 -> promptBuilder.append(currentAiResponse + IM_END)。

    • 下一轮 -> 再次发送整个 promptBuilder.toString()。

2.native-lib.cpp 的核心作用

  • 让 Java 能调用 C++ 函数(正向调用);
  • 让 C++ 能回调 Java 方法(反向调用);
  • 完成跨语言的数据类型转换;
  • 封装底层 C++ 库的调用逻辑(屏蔽 RKLLM 的复杂接口)。

我们可以把开发这个 App 比作 “开一家餐厅”:

  • build.gradle.kts (总管/施工队队长)

    • 作用:它负责指挥整个编译过程。它告诉编译器:“我们要造一个 Android App,请把 Java 代码编译好,然后去调用 CMake 把 C++ 代码也编译好,最后打包成一个 APK 安装包。”

    • .so 库只有 arm64-v8a (RK3588 专用) 的版本。如果不告诉总管“只做 arm64 的菜”,总管默认会尝试做 x86(电脑模拟器)或 32位 ARM 的菜,结果发现没有配料,就会报错。

  • CMakeLists.txt (后厨装修图纸)

    • 作用:它告诉 C++ 编译器:“去哪里找 rkllmrt.so 和 libomp.so 这些工具,然后把它们和 native-lib.cpp 焊接到一起。”

  • native-lib.cpp (后厨大厨/翻译官)

    • 作用:这是连接 Java (前台) 和 .so 库 (核心引擎) 的桥梁。

    • Android Studio 生成的默认代码只会说一句 “Hello from C++”。需要把它删掉,重写成调用 RKLLM 模型初始化、推理、对话的代码。如果不改,App 虽然能运行,但没有任何 AI 功能。

  • MainActivity.java (前台服务员/菜单)

    • 作用:负责把用户的输入(菜单)传给后厨,并把后厨做好的结果(AI 回复)端给用户看。

    • 需要在这里写逻辑去调用 native-lib.cpp 里的函数。

更多推荐