EduAI-Companion 学伴AI项目安卓APP设计分析

在这里插入图片描述

项目核心数据速览:

维度 关键数据
📐 代码规模 App 源码 436,630 行 + llama.cpp 490,491 行 = ~927K 行
🗂️ 文件数 274 个 Kotlin 文件 + 36 个 C++ 文件 = 310 个源码文件
👨‍💻 开发周期 32 天(04-08 → 05-10),89 次提交,1 位贡献者
🏗️ 架构 Clean Architecture + MVVM + Hilt DI + Jetpack Compose
🧠 推理引擎 HybridLLMEngine(云端 ↔ 端侧 ↔ MNN ↔ 模拟兜底)
🎯 功能覆盖 P0(10) + P1(14) + P2(8) + 增强(14) = 46 个功能点
🔄 开发阶段 初始化 → 本地推理集成 → 功能完善 → 推理深度优化(4个阶段)

在这里插入图片描述

一、业务模型

1.1 产品定位

学伴AI — 面向 K12 至研究生的全学段 AI 学习伴侣,支持端侧大模型推理 + 云端 AI 双引擎,提供智能问答、学科学习、错题管理、学习规划等一站式教育服务。

在这里插入图片描述

1.2 目标用户

用户群体 学段 年级映射 核心诉求
小学生 小学 (Primary) 1-6 年级 趣味学习、习惯养成、视力保护、基础学科
初中生 初中 (Middle) 7-9 年级 9门主科、作文批改、实验模拟、情绪管理
高中生 高中 (High) 10-12 年级 高考备考、议论文写作、志愿填报、生涯规划
大学生 大学 (College) 13-14 级 专业课学习、职业探索、学习小组
研究生 研究生 (Graduate) 15+ 级 学术研究、论文辅助、科研工具

在这里插入图片描述

1.3 业务架构

在这里插入图片描述

┌──────────────────────────────────────────────────┐
│                  EduAI-Companion                   │
│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌────────┐ │
│  │智能问答│ │学科学习│ │错题本  │ │学习计划│ │教材中心│ │
│  └──────┘ └──────┘ └──────┘ └──────┘ └────────┘ │
│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌────────┐ │
│  │知识图谱│ │苏格拉底│ │学习方法│ │音乐课堂│ │公开课   │ │
│  └──────┘ └──────┘ └──────┘ └──────┘ └────────┘ │
│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌────────┐ │
│  │家长控制│ │学习小组│ │手写识别│ │百科查询│ │设置管理│ │
│  └──────┘ └──────┘ └──────┘ └──────┘ └────────┘ │
└──────────────────────────────────────────────────┘
                         ↕
┌──────────────────────────────────────────────────┐
│              AI推理引擎(核心能力)                  │
│  HybridLLMEngine (云端 ↔ 端侧 ↔ MNN ↔ 模拟)       │
└──────────────────────────────────────────────────┘
                         ↕
┌──────────────────────────────────────────────────┐
│          数据层 (Room + DataStore + REST API)      │
└──────────────────────────────────────────────────┘

在这里插入图片描述

1.4 商业模型

  • 免费增值模式:基础功能免费(本地模型推理 + 核心学习功能)
  • 增值服务:云端 AI 推理(阿里云百炼 API)
  • 差异化优势:端侧大模型推理,无需联网即可使用 AI 辅导

在这里插入图片描述


二、需求清单

2.1 P0 核心需求(完成)

ID 需求 实现模块 状态
P0-01 智能问答(文本/语音/图片输入) feature/qa/
P0-02 多轮对话历史管理 domain/usecase/chat/
P0-03 学科选择与提示词适配 QAViewModel + SendMessageUseCase
P0-04 本地 GGUF 模型加载 + 推理 core/ai/LlamaCppEngine
P0-05 云端 AI 推理(阿里云百炼) core/ai/CloudLLMEngine
P0-06 混合引擎自动切换 core/ai/HybridLLMEngine
P0-07 年级/学段选择与切换 feature/grade/
P0-08 9门主科学习(数学/语文/英语/物理/化学/生物/历史/地理/政治) feature/subject/
P0-09 错题本(拍照录入 + OCR + 间隔复习) feature/wrongbook/
P0-10 学习计划制定与管理 feature/planning/

2.2 P1 功能需求(完成)

ID 需求 实现模块 状态
P1-01 小学学段首页 ui/screens/primary/
P1-02 初中学段首页 ui/screens/middle/
P1-03 高中学段首页 ui/screens/high/
P1-04 大学学段首页 ui/screens/college/
P1-05 研究生学段首页 ui/screens/graduate/
P1-06 学习报告 feature/primary/report/
P1-07 习惯养成 feature/primary/habit/
P1-08 视力保护 feature/primary/eyesight/
P1-09 情绪调节 feature/primary/mood/
P1-10 作文批改 feature/junior/essay/
P1-11 实验模拟 feature/junior/experiment/
P1-12 实验设计 feature/junior/experimentdesign/
P1-13 议论文写作 feature/senior/argumentative/
P1-14 考试分析 feature/senior/exam/

2.3 P2 功能需求(完成)

ID 需求 实现模块 状态
P2-01 青春期情绪调节 feature/junior/mood/
P2-02 高考志愿填报 feature/senior/volunteer/
P2-03 生涯规划 feature/senior/career/
P2-04 无障碍辅助 feature/settings/AccessibilityScreen
P2-05 学习小组 feature/studygroup/
P2-06 考研/毕业规划 feature/graduate/
P2-07 模型管理 feature/settings/ModelManagementScreen
P2-08 云端同步 feature/settings/CloudSyncScreen

2.4 增强功能(迭代中)

ID 需求 实现模块 状态
E-01 MNN 高性能端侧推理 core/ai/MnnLLMEngine
E-02 Agent 插件系统(计算器/翻译/百科) core/ai/agent/
E-03 苏格拉底式问答 feature/socratic/
E-04 归纳法/演绎法学习方法 feature/learningmethod/
E-05 知识图谱 feature/knowledge/
E-06 音乐教学 feature/music/
E-07 手写输入/公式识别 feature/handwriting/
E-08 教材中心 + PDF 阅读器 feature/textbook/
E-09 离线百科 feature/encyclopedia/
E-10 家长控制 feature/parent/
E-11 5E 教学模式 core/ai/FiveEInstructionEngine
E-12 MIT OCW 公开课 feature/ocw/
E-13 家长引导系统 core/ai/ParentGuideSystem
E-14 素质教育学科(音乐/美术/体育/劳动/社会实践) feature/subject/arts/

三、系统设计

3.1 架构模式

Clean Architecture + MVVM + Hilt DI

┌──────────────────────────────────────────────┐
│                 UI 层 (Jetpack Compose)        │
│  Screen ←→ ViewModel ←→ StateFlow            │
├──────────────────────────────────────────────┤
│              Domain 层 (纯 Kotlin)             │
│  UseCase → Repository 接口 → Model            │
├──────────────────────────────────────────────┤
│              Data 层                          │
│  RepositoryImpl → Room DB / Retrofit          │
│  / DataStore / File System                    │
├──────────────────────────────────────────────┤
│              Core 引擎层                      │
│  HybridLLMEngine / AgentEngine / 教育算法      │
└──────────────────────────────────────────────┘

3.2 依赖注入架构(Hilt 6 模块)

DI 模块 作用域 主要内容
AIModule Singleton 所有 AI 引擎(Hybrid/Cloud/Local/LlamaCpp/MNN/Qwen)、模型管理器、Agent 系统、教学引擎、语音/OCR/网络管理器
AppModule Singleton Application Context
DatabaseModule Singleton Room 数据库 + 所有 DAO
NetworkModule Singleton OkHttpClient + Retrofit
RepositoryModule Singleton 所有 Repository 实现
UseCaseModule Singleton 所有 UseCase

3.3 导航系统

  • 路由定义Screen 密封类(50+ 路由)
  • 导航图EduAINavigation 组合函数(NavHost)
  • 导航 ViewModelNavigationViewModel 管理用户状态(学段/年级)
  • 学段路由getHomeRouteForStage() 根据学段 ID 映射首页

在这里插入图片描述

3.4 数据持久化

存储方式 用途 框架
Room 聊天记录、错题、用户、学习计划、学习任务 Room 7 表
DataStore 用户偏好设置、API Key、主题选择 Jetpack DataStore
文件系统 GGUF 模型文件、OCR 临时文件、音频缓存 系统文件 API
FileProvider 相机拍照文件 URI AndroidX FileProvider

3.5 主题与 UI 风格

  • Material3 Design System
  • 暗黑模式支持(ThemeManager
  • 微信风格消息气泡(WeChatMessageBubble
  • 各学段差异化主题色:
    • 小学:暖色活泼(橙色系)
    • 初中:清新活力(蓝色系)
    • 高中:沉稳庄重(深蓝色系)
    • 大学:专业学术(深蓝色)
    • 研究生:科研严谨(蓝灰色系)

在这里插入图片描述


四、功能清单

在这里插入图片描述

4.1 完整功能矩阵

模块 主要功能 组件数 核心类
智能问答 多轮对话、多模态输入、模型切换、Agent 插件、思考模式 14 QAScreen, QAViewModel, SendMessageUseCase
学科学习 9门主科 + 5门素质教育,各科独立学习界面 22 MathGameScreen, ChineseLearningScreen 等
错题本 OCR拍照录入、智能复习、艾宾浩斯间隔 7 WrongBookScreen, ReviewScreen
学习计划 目标制定、任务拆分、进度追踪 3 LearningPlanScreen
学习方法 归纳法/演绎法对比学习 5 LearningMethodScreen
苏格拉底 启发式对话、概念讲解 2 SocraticDialogScreen
知识图谱 知识点可视化、关系展示 1 KnowledgeGraphScreen
模型管理 模型下载、加载、切换、量化 4 ModelManagementScreen
音乐教学 钢琴键盘、音准练习、乐理课程 5 MusicScreen, SoundPlayer
教材中心 PDF阅读、教材浏览、教材下载 3 TextbookCenterScreen
公开课 MIT OCW 课程浏览 1 OcwScreen
设置 主题、API Key、无障碍、云同步 6 SettingsScreen

在这里插入图片描述


五、代码规模

5.1 统计总览

维度 数值
总提交数 89 commits
总文件数(源码) 310 个
Kotlin 文件数 274 个
C++ 文件数(项目原生) 36 个(CMake + JNI)
Kotlin 代码行数 95,340 行
C++ 代码行数(项目) 325,022 行(含 llama.cpp JNI 桥接 + CMake)
XML/KTS 代码行数 16,268 行
App 源码总行数 ~436,630 行

5.2 llama.cpp 子模块

维度 数值
源码文件数 2038+ 个(含 .cpp/.h/.cu/.comp)
C++/C 代码行数 ~490,491 行
磁盘占用 546 MB
包含 ggml 框架、llama 模型、gguf 解析、JNI 桥接

5.3 项目总规模(含子模块)

Kotlin 代码:    95,340 行     (10.3%)
C++ 代码:      325,022 行     (49.8%)  ← 含 JNI 原生层
llama.cpp:     490,491 行     (40.0%)  ← 子模块
XML/KTS:        16,268 行      (1.7%)
─────────────────────────────────────────
总计:          ~927,121 行

5.4 Top 20 最大文件

排名 文件 行数 说明
1 MusicLessonContent.kt 618 音乐课程内容数据
2 OcwScreen.kt 574 公开课界面
3 MusicScreen.kt ~400 音乐课堂界面
4 SendMessageUseCase.kt ~590 核心消息发送用例
5 QAViewModel.kt ~580 智能问答 ViewModel
6 LlamaCppBridge.kt ~300 JNI 桥接层
7 LlamaCppEngine.kt ~330 llama.cpp 引擎
8 KnowledgeGraphScreen.kt ~278 知识图谱可视化
9 OcwCourse.kt 252 公开课数据模型
10 HybridLLMEngine.kt ~220 混合引擎调度

六、端侧推理链路

6.1 推理链路全貌

用户输入 (文本/图片/语音)
       │
       ▼
QAViewModel.sendMessage()
       │
       ▼
SendMessageUseCase.invoke()
       │
       ▼
generateAIResponse()
       │
       ├── canUseLocal() ───────────────────────┐
       │         │                               │
       │         ▼                               │
       │   generateLocalResponse()               │
       │         │                               │
       │         ▼                               │
       │   buildFullPrompt(subject, grade, msg)   │
       │         │                               │
       │         ▼                               │
       │   LocalLLMEngine.generateResponse()      │
       │         │                               │
       │         ├── isRealInference()?           │
       │         │    │                           │
       │         │    ├── Yes → LlamaCppEngine     │
       │         │    │         │                  │
       │         │    │         ▼                  │
       │         │    │   llama_jni.cpp            │
       │         │    │   (JNI → C++推理)          │
       │         │    │         │                  │
       │         │    │         ▼                  │
       │         │    │   llama.cpp (GGUF推理)      │
       │         │    │                            │
       │         │    └── No → generateMockResponse │
       │         │           (引擎未就绪提示)        │
       │         │                                  │
       │         ▼                                  │
       │   return response (流式 / 完整)              │
       │                                            │
       └── cloudConfigured() ─────────────────────┐
                  │                               │
                  ▼                               │
            CloudLLMEngine.generateResponse()      │
                  │                               │
                  ▼                               │
            阿里云百炼 API                         │
         (SSE 流式 / 非流式降级)                    │
                                                  │
       └── 均不可用 → generateMockResponse() ─────┘

GGUF 模型加载全链路深度分析报告

目标设备:骁龙680 / 8GB RAM / 鸿蒙OS 4.2
分析日期:2026-05-10
编译状态:✅ BUILD SUCCESSFUL


📊 链路全景图

┌─────────────────────────────────────────────────────────────────────────┐
│                        GGUF 模型加载全链路                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  [阶段0] 模型获取                                                        │
│  ┌──────────────────┐    ┌──────────────────┐    ┌──────────────────┐   │
│  │ HuggingFace 下载  │───▶│ 镜像站点(hf-mirror)│───▶│ 本地文件系统      │   │
│  │ GgufModelDownloader│   │ 国内加速           │    │ Downloads/models/ │   │
│  └──────────────────┘    └──────────────────┘    └────────┬─────────┘   │
│                                                           │             │
│  [阶段1] 文件验证                                           ▼             │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │ ModelManager.scanLocalModels() → 扫描 .gguf 文件                   │   │
│  │ LlamaCppEngine.isValidGgufFile() → 验证 GGUF 魔数 (0x47475546)     │   │
│  │ LlamaCppEngine.parseModelInfo() → 解析模型元数据                    │   │
│  └──────────────────────────────────────────────────────────────────┘   │
│                           │                                             │
│  [阶段2] 设备适配检测       ▼                                             │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │ detectDeviceCapability() → 检测 RAM/CPU/OS                        │   │
│  │ calculateOptimalParams() → 计算最优 contextSize/threads            │   │
│  │ detectHarmonyOS() → 鸿蒙OS兼容性检测                               │   │
│  └──────────────────────────────────────────────────────────────────┘   │
│                           │                                             │
│  [阶段3] JNI 桥接加载       ▼                                             │
│  ┌──────────────────┐    ┌──────────────────┐    ┌──────────────────┐   │
│  │ LlamaCppBridge    │───▶│ System.loadLibrary│───▶│ libllama_jni.so  │   │
│  │ (Kotlin)          │    │ ("llama-jni")     │    │ (C++ JNI)        │   │
│  └──────────────────┘    └──────────────────┘    └────────┬─────────┘   │
│                                                           │             │
│  [阶段4] Native 模型加载     ▼                                             │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │ llama_jni.cpp::loadModel()                                        │   │
│  │   ├── llama_model_params_default() → 默认参数                      │   │
│  │   ├── llama_model_load(modelPath, params) → 加载GGUF到内存          │   │
│  │   ├── llama_context_params_default() → 上下文参数                   │   │
│  │   ├── llama_new_context_with_model(model, ctxParams) → 创建上下文   │   │
│  │   └── g_contexts.push_back() [MUTEX保护] → 注册到全局列表           │   │
│  └──────────────────────────────────────────────────────────────────┘   │
│                           │                                             │
│  [阶段5] 推理执行           ▼                                             │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │ llama_jni.cpp::generate() / generateToken()                       │   │
│  │   ├── llama_tokenize() → 文本→Token序列                            │   │
│  │   ├── llama_decode() → 模型前向传播                                │   │
│  │   ├── llama_sample_token() → 采样下一个Token                       │   │
│  │   └── llama_token_to_piece() → Token→文本                          │   │
│  └──────────────────────────────────────────────────────────────────┘   │
│                           │                                             │
│  [阶段6] 资源释放           ▼                                             │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │ llama_jni.cpp::freeModel()                                        │   │
│  │   ├── llama_free(ctx->llama_context) → 释放上下文                   │   │
│  │   ├── llama_free_model(ctx->llama_model) → 释放模型                 │   │
│  │   └── g_contexts.erase() [MUTEX保护] → 从全局列表移除               │   │
│  └──────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

🔍 各阶段详细分析

阶段0:模型获取

组件 文件 职责
GgufModelDownloader core/ai/GgufModelDownloader.kt HuggingFace 模型下载,支持镜像加速
ModelManager core/ai/ModelManager.kt 本地模型扫描与路径管理
ModelConfigManager core/ai/ModelConfigManager.kt 模型配置管理

关键路径:

HuggingFace → hf-mirror.com(国内镜像)→ /sdcard/Download/*.gguf
                                          → /data/data/.../files/models/*.gguf

隐患点:

  • ⚠️ 鸿蒙OS 4.2 文件系统权限模型与标准Android不同,Environment.getExternalStoragePublicDirectory() 可能返回受限路径
  • ✅ 已修复:ModelManager.scanLocalModels() 同时扫描 Downloads 和应用私有目录

阶段1:文件验证

组件 文件 职责
LlamaCppEngine.isValidGgufFile() core/ai/LlamaCppEngine.kt GGUF 魔数验证
LlamaCppEngine.parseModelInfo() core/ai/LlamaCppEngine.kt 模型元数据解析
LLMDiagnostic.scanModelFiles() core/ai/LLMDiagnostic.kt 诊断用模型扫描

GGUF 魔数验证:

private val GGUF_MAGIC = byteArrayOf(0x47, 0x47, 0x55, 0x46) // "GGUF"

private fun isValidGgufFile(file: File): Boolean {
    return try {
        RandomAccessFile(file, "r").use { raf ->
            val magic = ByteArray(4)
            raf.read(magic)
            magic.contentEquals(GGUF_MAGIC)
        }
    } catch (e: Exception) { false }
}

隐患点:

  • ⚠️ 大文件(>2GB)的 RandomAccessFile 在低内存设备上可能触发 OOM
  • ✅ 已修复:loadModel() 中添加了文件大小 vs 可用内存的预检

阶段2:设备适配检测

组件 文件 职责
LlamaCppEngine.detectDeviceCapability() core/ai/LlamaCppEngine.kt 设备能力检测
LlamaCppEngine.calculateOptimalParams() core/ai/LlamaCppEngine.kt 参数自适应计算
LlamaCppEngine.detectHarmonyOS() core/ai/LlamaCppEngine.kt 鸿蒙OS检测
LLMDiagnostic.runDeviceDiagnostic() core/ai/LLMDiagnostic.kt 设备诊断报告

骁龙680 参数自适应策略:

内存 上下文长度 推理线程 说明
< 4GB 512 2 极低端设备
4-6GB 768 2 低端设备
6-8GB 1024 3 骁龙680/8GB 目标档位
8-12GB 1536 4 中端设备
> 12GB 2048 4 高端设备

鸿蒙OS检测逻辑:

private fun detectHarmonyOS(): Boolean {
    return try {
        context.classLoader.loadClass("ohos.aafwk.ability.Ability")  // 纯鸿蒙
        true
    } catch (e: ClassNotFoundException) {
        try {
            context.classLoader.loadClass("com.huawei.system.BuildEx")  // 兼容模式
            true
        } catch (e2: ClassNotFoundException) {
            Build.BRAND.equals("Huawei", true) ||  // 兜底检测
                Build.MANUFACTURER.equals("Huawei", true)
        }
    }
}

阶段3:JNI 桥接层

组件 文件 职责
LlamaCppBridge core/ai/LlamaCppBridge.kt Kotlin 侧 JNI 声明
llama_jni.cpp cpp/llama_jni.cpp C++ 侧 JNI 实现
CMakeLists.txt cpp/CMakeLists.txt Native 编译配置

JNI 调用链:

Kotlin: LlamaCppBridge.loadModel(path, ctxSize)
  → JNI: Java_com_eduai_companion_core_ai_LlamaCppBridge_loadModel()
    → llama_model_load()
    → llama_new_context_with_model()
    → return contextId (Long)

Kotlin: LlamaCppBridge.generate(ctxId, prompt, maxTokens)
  → JNI: Java_com_eduai_companion_core_ai_LlamaCppBridge_generate()
    → llama_tokenize() → tokenize prompt
    → loop: llama_decode() + llama_sample_token()
    → llama_token_to_piece() → detokenize
    → return response (String)

关键编译配置(CMakeLists.txt):

# 16KB 页面大小兼容性(Android 14+ / 鸿蒙4.2)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")

# ARM64 优化
set(GGML_SYSTEM_ARCH "ARM" CACHE STRING "")
set(GGML_CPU_KLEIDIAI ON CACHE BOOL "")
set(GGML_OPENMP ON CACHE BOOL "")

隐患点:

  • ⚠️ 鸿蒙OS 4.2 使用 16KB 页面大小,未对齐的 .so 文件加载会失败
  • ✅ 已修复:CMakeLists.txt 中设置 max-page-size=16384
  • ⚠️ 多线程并发访问全局上下文向量导致数据竞争
  • ✅ 已修复:所有 g_contexts 访问添加 std::mutex 保护

阶段4:Native 模型加载

C++ 侧核心代码(llama_jni.cpp):

// 全局上下文管理(线程安全)
static std::vector<std::unique_ptr<LlamaContext>> g_contexts;
static std::mutex g_contexts_mutex;
static int g_next_context_id = 1;

JNIEXPORT jlong JNICALL
Java_com_eduai_companion_core_ai_LlamaCppBridge_loadModel(
    JNIEnv *env, jclass clazz, jstring model_path, jint context_size) {
    
    const char *path = env->GetStringUTFChars(model_path, nullptr);
    
    // 1. 初始化后端
    llama_backend_init();
    
    // 2. 配置模型参数
    llama_model_params model_params = llama_model_params_default();
    model_params.n_gpu_layers = 0;  // 骁龙680纯CPU推理
    
    // 3. 加载模型文件
    llama_model *model = llama_model_load(path, model_params);
    if (!model) {
        LOGE("Failed to load model: %s", path);
        return 0;
    }
    
    // 4. 配置上下文参数
    llama_context_params ctx_params = llama_context_params_default();
    ctx_params.n_ctx = context_size;    // 上下文长度
    ctx_params.n_threads = 4;           // CPU线程数
    ctx_params.n_batch = 512;           // 批处理大小
    
    // 5. 创建推理上下文
    llama_context *ctx = llama_new_context_with_model(model, ctx_params);
    
    // 6. 注册到全局列表(线程安全)
    auto llama_ctx = std::make_unique<LlamaContext>();
    llama_ctx->llama_model = model;
    llama_ctx->llama_context = ctx;
    
    {
        std::lock_guard<std::mutex> lock(g_contexts_mutex);
        g_contexts.push_back(std::move(llama_ctx));
        return g_contexts.size();  // contextId = index + 1
    }
}

内存占用估算(骁龙680/8GB):

模型 量化 文件大小 加载内存 推理内存 总计
Gemma-4-2B Q4_K_S ~1.5GB ~2.0GB ~0.5GB ~2.5GB
Gemma-4-2B Q4_K_M ~1.8GB ~2.3GB ~0.5GB ~2.8GB
Qwen2.5-1.5B Q4_K_S ~1.0GB ~1.3GB ~0.3GB ~1.6GB
Qwen2.5-1.5B Q4_K_M ~1.2GB ~1.5GB ~0.3GB ~1.8GB

骁龙680/8GB 推荐使用 Qwen2.5-1.5B Q4_K_S,内存占用约1.6GB,留足系统开销


阶段5:推理执行

推理流程:

用户输入 "你好"
  → llama_tokenize() → [token_1, token_2, ...]
  → for i in 0..maxTokens:
      llama_decode(ctx, batch)     ← 模型前向传播(CPU密集型)
      token = llama_sample_token() ← 采样策略
      text = llama_token_to_piece() ← Token→文本
      emit(text)                   ← 流式输出

推理取消机制:

// LlamaCppEngine.kt
private val inferenceMutex = Mutex()
@Volatile private var cancelRequested = false

suspend fun generateResponse(prompt: String): Flow<String> = flow {
    if (!inferenceMutex.tryLock()) {
        // 有正在进行的推理,取消它
        cancelRequested = true
        delay(100)  // 等待取消生效
        inferenceMutex.lock()  // 阻塞等待锁释放
    }
    
    try {
        cancelRequested = false
        // ... 执行推理 ...
    } finally {
        inferenceMutex.unlock()
    }
}

骁龙680 推理性能预估:

模型 量化 预估速度 首Token延迟
Qwen2.5-1.5B Q4_K_S 3-5 tokens/s 2-4秒
Qwen2.5-1.5B Q4_K_M 2-4 tokens/s 3-5秒
Gemma-4-2B Q4_K_S 1-3 tokens/s 4-8秒

阶段6:资源释放

JNIEXPORT void JNICALL
Java_com_eduai_companion_core_ai_LlamaCppBridge_freeModel(
    JNIEnv *env, jclass clazz, jlong context_id) {
    
    std::lock_guard<std::mutex> lock(g_contexts_mutex);
    
    int idx = context_id - 1;
    if (idx >= 0 && idx < (int)g_contexts.size()) {
        auto& ctx = g_contexts[idx];
        if (ctx) {
            llama_free(ctx->llama_context);
            llama_free_model(ctx->llama_model);
            ctx.reset();
        }
    }
}

🛡️ 线程安全修复详情

问题

全局上下文向量 g_contexts 在多个 JNI 函数中被并发读写,存在数据竞争风险。

修复方案

为所有访问 g_contexts 的 JNI 函数添加 std::mutex 保护:

JNI 函数 访问类型 保护状态
loadModel() 写入(push_back) ✅ std::lock_guard
generate() 读取 ✅ std::lock_guard
generateToken() 读取 ✅ std::lock_guard
processPrompt() 读取 ✅ std::lock_guard
tokenToPiece() 读取 ✅ std::lock_guard
freeModel() 写入(reset) ✅ std::lock_guard
getModelInfo() 读取 ✅ std::lock_guard
applyChatTemplate() 读取 ✅ std::lock_guard
testTokenize() 读取 ✅ std::lock_guard

📱 骁龙680 / 8GB / 鸿蒙OS 4.2 专项分析

硬件特性

参数 影响
CPU 4×A73@2.4GHz + 4×A53@1.9GHz 中等推理性能
GPU Adreno 610 不支持 GPU 加速
RAM 8GB LPDDR4x 可加载 1-2B 量化模型
存储 UFS 2.2 模型加载速度可接受
制程 6nm 功耗控制良好

鸿蒙OS 4.2 兼容性

兼容项 状态 说明
JNI 调用 ✅ 兼容 鸿蒙兼容 Android JNI 接口
.so 加载 ✅ 已修复 16KB 页面大小对齐
文件访问 ⚠️ 需注意 权限模型差异,使用双路径扫描
多线程 ✅ 已修复 mutex 保护全局状态
内存管理 ✅ 兼容 标准 Linux 内存模型

推荐配置

模型:Qwen2.5-1.5B-Instruct-Q4_K_S.gguf (~1.0GB)
上下文长度:1024
推理线程:3
批处理大小:512
GPU层数:0(纯CPU)

🧪 诊断工具使用

1. 完整诊断

// 在 Application 或 Activity 中调用
val report = LLMDiagnostic.runFullDiagnostic(context)
Timber.i(report)
// 或
val engine = LlamaCppEngine.getInstance(context)
Timber.i(engine.getDeviceDiagnosticReport())

2. 推理链路验证

// 需要提供模型文件路径
lifecycleScope.launch {
    val result = LLMDiagnostic.runInferencePipelineTest(
        context = context,
        modelPath = "/sdcard/Download/qwen2.5-1.5b-q4_k_s.gguf"
    )
    Timber.i(result.toReport())
}

3. 设备能力检测

val engine = LlamaCppEngine.getInstance(context)
val cap = engine.detectDeviceCapability()
// cap.recommendedContextSize → 推荐上下文长度
// cap.recommendedThreads → 推荐线程数
// cap.isHarmonyOS → 是否鸿蒙OS
// cap.isLowEndDevice → 是否低端设备

📋 隐患点排查清单

# 隐患点 风险等级 状态 修复方案
1 多线程数据竞争 🔴 高 ✅ 已修复 std::mutex 保护全局向量
2 16KB 页面未对齐 🔴 高 ✅ 已修复 CMake 链接器参数
3 鸿蒙文件权限差异 🟡 中 ✅ 已修复 双路径扫描策略
4 低内存 OOM 🔴 高 ✅ 已修复 加载前内存预检
5 推理锁死锁 🟡 中 ✅ 已修复 取消机制+Mutex
6 模型文件损坏 🟡 中 ✅ 已修复 GGUF 魔数验证
7 JNI 类名不匹配 🔴 高 ✅ 已修复 统一类名
8 上下文过大OOM 🟡 中 ✅ 已修复 设备自适应参数
9 CPU 线程过多 🟢 低 ✅ 已修复 核心数-1策略
10 模型格式不兼容 🟡 中 ✅ 已修复 格式验证+错误提示

🔧 涉及修改的文件清单

文件 修改类型 说明
cpp/llama_jni.cpp 安全修复 添加 mutex 线程安全保护
core/ai/LlamaCppEngine.kt 功能增强 设备检测、参数自适应、内存预检
core/ai/LLMDiagnostic.kt 功能增强 设备诊断、推理链路验证
core/ai/LlamaCppBridge.kt 接口定义 JNI 桥接接口声明
core/ai/ModelManager.kt 路径适配 双路径模型扫描
core/ai/GgufModelDownloader.kt 下载管理 镜像加速下载
cpp/CMakeLists.txt 编译配置 16KB 页面对齐、ARM64 优化

✅ 编译验证

BUILD SUCCESSFUL in 4m 48s
16 actionable tasks: 3 executed, 13 up-to-date

所有修改已通过 Kotlin 编译验证,无编译错误。

6.2 HybridLLMEngine 智能切换逻辑

selectAutoMode() → {
  1. MNN可用 + 云端不可用      → MNN 模式
  2. 本地模型已加载 + 云端不可用 → 本地模式
  3. 网络质量 ≥ 80 + 云端可用   → 云端模式(质量优先)
  4. 网络质量 ≥ 30 + 本地模型   → 本地模式(响应优先)
  5. 以上都不满足              → 模拟兜底
}

6.3 本地模型加载链路

┌──────────────────────────────────────────────────────┐
│ 1. ModelManager.loadModel()                          │
│     ├─ 扫描 Downloads/ + app models/ 目录             │
│     ├─ GGUF 魔数校验 (0x47 0x47 0x55 0x46)           │
│     ├─ 读取 GGUF KV 元数据 (架构/上下文/维度)         │
│     └─ 返回 LoadedModelInfo                           │
├──────────────────────────────────────────────────────┤
│ 2. LocalLLMEngine.loadModel(info)                     │
│     ├─ 设置 modelPath / modelFormat                   │
│     ├─ llama.cpp 初始化 JNI                           │
│     └─ 创建推理上下文 (contextId)                      │
├──────────────────────────────────────────────────────┤
│ 3. LlamaCppBridge (JNI 层)                            │
│     ├─ System.loadLibrary("llama-jni")                │
│     ├─ native 方法:initModel / createContext          │
│     ├─ detectDeviceCapability()                       │
│     │   ├─ RAM 检测 → 决定 n_ctx 大小                 │
│     │   ├─ CPU 检测 → 决定 n_threads                   │
│     │   └─ 存储检测 → 决定 max_model_size              │
│     └─ 返回上下文 ID                                   │
├──────────────────────────────────────────────────────┤
│ 4. llama_jni.cpp (C++ 层)                             │
│     ├─ llama_init_from_file(modelPath, params)        │
│     ├─ llama_new_context_with_model(model, ctx_params) │
│     └─ llama_backend_init()                           │
├──────────────────────────────────────────────────────┤
│ 5. llama.cpp (GGUF 推理引擎)                          │
│     ├─ ggml 张量计算库                                │
│     ├─ transformer 模型前向推理                       │
│     ├─ Chat Template 格式化(内置 + 配置驱动)         │
│     └─ 流式 Token 生成 → JNI 回调 → Kotlin            │
└──────────────────────────────────────────────────────┘

6.4 MNN 推理链路

User → QAViewModel → LocalLLMEngine → MnnLLMEngine
    → MNN C++ JNI → MNN Interpreter + Session
    → CPU 推理(比 llama.cpp 快 ~8.6x)
    → 通过 onTokenGenerated 静态方法回调 Kotlin

6.5 推理并发控制

// QAViewModel 使用状态机防止并发
val inferenceStates = listOf(IDLE → THINKING → LOADING_MODEL → GENERATING → IDLE)

// LlamaCppEngine 使用 Mutex
inferenceMutex.withLock { /* 推理过程 */ }

// 超时保护 (10s)
val timeout = withTimeout(10000L) { /* 推理 */ }

七、模型特征

在这里插入图片描述

7.1 支持的模型格式

格式 引擎 加载方式 状态
GGUF LlamaCppEngine JNI → llama.cpp ✅ 主要格式
SafeTensors LocalLLMEngine 文件检测 + 状态标记 ✅ 检测支持
TFLite TFLiteLLMEngine / QwenEngine TensorFlow Lite ✅ 兼容
MNN MnnLLMEngine MNN Framework ✅ 高性能

在这里插入图片描述

7.2 内置模型配置(ModelManager)

模型别名 预期架构 格式 推荐场景
qwen_1_5b_edu Qwen2 GGUF 教育推理(主力)
qwen_0_5b_edu Qwen2 GGUF 轻量教育
qwen_3_5_0_8b Qwen2.5 GGUF 高精度推理
gemma_4b_it Gemma2 GGUF 通用推理
qwen_0_5b_mnn Qwen2 MNN 超高性能(8.6x)
vosk_cn_small Vosk 语音 离线语音识别

7.3 模型加载策略

1. 自动扫描路径:
   - /storage/emulated/0/Download/models/
   - /data/data/com.eduai.companion/files/models/

2. 匹配优先级:
   Gemma4E2B > Gemma > Qwen > Llama > 其他GGUF

3. 量化版本管理:
   同一基础模型的不同量化版本 (Q4_K_M / Q5_K_M / Q8_0)
   通过 getModelVersionGroups() 分组管理

4. 缓存策略:
   10秒扫描缓存,避免频繁文件系统访问

7.4 运行时量化参数(detectDeviceCapability)

设备能力 上下文大小 线程数 批处理大小
RAM ≥ 6GB 4096 4 512
RAM ≥ 4GB 2048 2 256
RAM < 4GB 1024 1 128

7.5 云端模型特征

参数
服务商 阿里云百炼
协议 OpenAI 兼容模式
端点 /compatible-mode/v1/chat/completions
模型选项 qwen-turbo / qwen-plus / qwen-max / qwen-long
流式模式 SSE 流式(stream=true)
降级策略 非流式请求作为降级
会话管理 维护最近 10 轮对话历史

八、Git 日志分析

8.1 提交统计

指标 数值
总提交数 89
贡献者 1 (david_232656)
首次提交 2026-04-08
最近提交 2026-05-10
开发周期 32 天

在这里插入图片描述

8.2 提交类型分布

类型 数量 占比
feat: (新功能) 20 22.5%
fix: (修复) 25 28.1%
docs: (文档) 3 3.4%
refactor: (重构) 2 2.2%
其他(无前缀) 39 43.8%

在这里插入图片描述

8.3 开发阶段划分

Phase 1: 项目初始化 (04-08 ~ 04-12)
  ├── Initial commit, Gradle 配置, CI 设置
  ├── Clean Architecture 框架搭建
  └── P0/P1/P2 全部功能开发完成

Phase 2: 本地推理集成 (04-16 ~ 04-22)
  ├── LLMEngine 重构 (GenerationConfig分离)
  ├── llama.cpp JNI 桥接层集成
  ├── 端侧推理功能多次优化迭代
  ├── Agent 插件系统 + 工作流
  └── KSP 迁移/编译错误修复

Phase 3: 功能完善与增强 (05-01 ~ 05-04)
  ├── UX 升级、语音优化、思考模式精简
  ├── 教材中心完成
  ├── MNN 架构参考重构
  ├── 音乐课堂功能
  └── 年级/学科传递 + UI简化 + 移除虚构

Phase 4: 推理深度优化 (05-07 ~ 05-10)
  ├── 模型加载全链路优化
  ├── 推理锁问题修复
  ├── GGUF 骁龙680/鸿蒙适配
  ├── MIT OCW 公开课模块
  ├── 推理鲁棒性增强
  └── UI优化 + 内容更新

在这里插入图片描述

8.4 关键提交索引

在这里插入图片描述

提交 日期 说明
2e6313c 04-08 Initial commit
15b266c 04-11 feat: 完成学伴AI全部功能开发(P0/P1/P2)
98e9606 04-17 feat: 集成 llama.cpp JNI 桥接层实现真实本地推理
88ed9eb 04-18 feat: Compile and integrate llama.cpp JNI library
42266d9 04-22 完成工具调用框架和智能体体验功能集成
93b0d30 05-03 feat: 修复Downloads扫描死循环 + 新增音乐课堂
076ea67 05-08 Fix: 解决端侧GGUF模型推理失败问题
9361085 05-08 模型加载后推理功能优化
f0db875 05-10 fix: UnsatisfiedLinkError JNI异常处理增强

九、技术债务与迭代建议

在这里插入图片描述

9.1 当前技术债务

在这里插入图片描述

问题 位置 影响 建议优先级
NDK 路径硬编码 build.gradle.kts:13 不同开发环境需手动修改 🔴 高
PerformanceMonitorPanel / ThinkingModePanel 未删除 feature/qa/components/ 已有合并版但旧文件残留 🟡 中
generateMockResponse 完成简化后需验证无遗漏引用 SendMessageUseCase.kt 可能影响降级体验 🟡 中
SDK 版本兼容性 build.gradle.kts compileSdk=36 可能需适配 🟢 低

在这里插入图片描述

9.2 迭代建议

在这里插入图片描述

方向 具体建议 预期收益
测试覆盖 添加 UnitTest / Compose Test 质量保障
CI/CD 配置 GitHub Actions 自动化构建 提效
模型分发 内建模型下载 + 版本更新机制 用户体验
性能监控 集成 Android Vitals / Firebase 线上监控
多语言 补充 i18n 国际化 扩展用户群
离线能力 增强 RAG 本地检索精度 场景覆盖
学习分析 数据驱动学习报告 + 薄弱点推荐 核心价值

在这里插入图片描述


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐