From cbacd9461a85de32ee3d47b68160844bfa3bc0b1 Mon Sep 17 00:00:00 2001 From: link2026 Date: Mon, 8 Jun 2026 20:28:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(AI):=20MNN=20=E6=96=87=E6=9C=AC=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E5=8D=87=E5=88=B0=20Qwen3.5-4B(taobao-mnn=20=E9=A2=84?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现场机 iPhone 17(A19/SME2)内存与加速均可承载 4B,质量优于 2B。 - ModelKind.mnnLLM rawValue → "Qwen3.5-4B-MNN",displayName → Qwen3.5-4B (MNN/SME2) - ModelManifest:7 个运行时文件(llm.mnn.weight ~2.45GB + 拆分的 visual.mnn.weight 188MB),总计 2,836,770,850 bytes(~2.64GiB) - ModelManifestTests:文件数 7 / 总字节 / URL 更新到 Qwen3.5-4B-MNN - CLAUDE.md §2:MNN 主模型记为 Qwen3.5-4B,MLX 兜底仍 2B 模拟器 ModelManifestTests TEST SUCCEEDED。 Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 2 +- 康康/AI/ModelManifest.swift | 13 +++++++------ 康康/AI/ModelStore.swift | 6 +++--- 康康Tests/ModelManifestTests.swift | 8 ++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 62eb7a1..c20856e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -24,7 +24,7 @@ | 图表 | Swift Charts | iOS 16+ 原生 | | **AI 运行时(主)** | **MNN (alibaba) + Arm SME2 + CPU** | 挑战赛考核点:Qwen + MNN + SME2 端侧 CPU 推理。device-only(xcframework 见 `scripts/build-mnn-xcframework.sh`),A19/iPhone17 启用 SME2、A17 回退 NEON。经 `MNNLLMBridge`(ObjC++)→ `MNNBackend` | | **AI 运行时(兜底)** | **MLX Swift (Apple 官方,Metal GPU)** | 双后端:`InferenceEngine` 切换,模拟器/兜底用 MLX。不要建议 Core ML / llama.cpp / Ollama | -| LLM | Qwen3.5-2B 4bit(MNN 格式 + MLX `mlx-community/Qwen3.5-2B-4bit`) | 文本生成、关键词抽取、趋势解读 | +| LLM | MNN 主:Qwen3.5-4B(`taobao-mnn/Qwen3.5-4B-MNN`,~2.64GiB);MLX 兜底:Qwen3.5-2B-4bit | 文本生成、关键词抽取、趋势解读 | | VL | Qwen3-VL-4B-Instruct 4bit (MLX `mlx-community/Qwen3-VL-4B-Instruct-4bit`) | 拍照→结构化指标。MNN VL 需 OMNI 构建,暂走 MLX | | 文档扫描 | VisionKit `VNDocumentCameraView` | 不要自己写透视校正 | | Face ID | LocalAuthentication | | diff --git a/康康/AI/ModelManifest.swift b/康康/AI/ModelManifest.swift index 951d07e..ee16173 100644 --- a/康康/AI/ModelManifest.swift +++ b/康康/AI/ModelManifest.swift @@ -60,17 +60,18 @@ nonisolated enum ModelManifest { ModelFile(path: "video_preprocessor_config.json", bytes: 817), ] case .mnnLLM: - // taobao-mnn/Qwen3.5-2B-MNN 预转换 MNN 格式(HF API 实测,2026-06)。 + // taobao-mnn/Qwen3.5-4B-MNN 预转换 MNN 格式(HF API 实测,2026-06)。 // 运行时必需:config.json(MNN llm 配置)+ llm_config.json(超参)+ llm.mnn(图) - // + llm.mnn.weight(量化权重 ~1.1GB)+ tokenizer.txt + visual.mnn(多模态,文本路径不用但配置含 mllm)。 - // 排除 README/.gitattributes 与可读 dump(llm.mnn.json / export_args.json)。 + // + llm.mnn.weight(量化权重 ~2.45GB)+ tokenizer.txt + visual.mnn/visual.mnn.weight(多模态, + // 文本路径不用但配置含 mllm,带上避免缺文件)。排除 README/.gitattributes 与可读 dump。 return [ ModelFile(path: "config.json", bytes: 652), - ModelFile(path: "llm_config.json", bytes: 8_692), - ModelFile(path: "llm.mnn", bytes: 2_148_136), - ModelFile(path: "llm.mnn.weight", bytes: 1_176_647_702), + ModelFile(path: "llm_config.json", bytes: 8_693), + ModelFile(path: "llm.mnn", bytes: 3_651_096), + ModelFile(path: "llm.mnn.weight", bytes: 2_629_387_626), ModelFile(path: "tokenizer.txt", bytes: 6_465_727), ModelFile(path: "visual.mnn", bytes: 488_096), + ModelFile(path: "visual.mnn.weight", bytes: 196_768_960), ] } } diff --git a/康康/AI/ModelStore.swift b/康康/AI/ModelStore.swift index c325ae5..1245694 100644 --- a/康康/AI/ModelStore.swift +++ b/康康/AI/ModelStore.swift @@ -4,16 +4,16 @@ nonisolated enum ModelKind: String, CaseIterable { /// 也是沙盒 Models/ 下的子目录名 / CDN 路径段。 /// - llm:MLX(GPU)文本兜底,Qwen3.5-2B(多模态权重,走 qwen3_5 文本路径)。 /// - vl :MLX(GPU)拍照识别,Qwen3-VL-4B。 - /// - mnnLLM:MNN(CPU/SME2,挑战赛考核路径)文本,Qwen3.5-2B 预转换 MNN 格式(taobao-mnn)。 + /// - mnnLLM:MNN(CPU/SME2,挑战赛考核路径)文本,Qwen3.5-4B 预转换 MNN 格式(taobao-mnn)。 case llm = "Qwen3.5-2B-4bit" case vl = "Qwen3-VL-4B-Instruct-4bit" - case mnnLLM = "Qwen3.5-2B-MNN" + case mnnLLM = "Qwen3.5-4B-MNN" var displayName: String { switch self { case .llm: return "Qwen3.5-2B (MLX)" case .vl: return "Qwen3-VL-4B" - case .mnnLLM: return "Qwen3.5-2B (MNN/SME2)" + case .mnnLLM: return "Qwen3.5-4B (MNN/SME2)" } } diff --git a/康康Tests/ModelManifestTests.swift b/康康Tests/ModelManifestTests.swift index eaecdaf..3ff6713 100644 --- a/康康Tests/ModelManifestTests.swift +++ b/康康Tests/ModelManifestTests.swift @@ -20,12 +20,12 @@ struct ModelManifestTests { #expect(ModelManifest.totalBytes(for: .vl) == 3_109_729_929) } - @Test func mnnHasSixFunctionalFiles() { - #expect(ModelManifest.files(for: .mnnLLM).count == 6) + @Test func mnnHasSevenFunctionalFiles() { + #expect(ModelManifest.files(for: .mnnLLM).count == 7) } @Test func mnnTotalBytesMatchesManifest() { - #expect(ModelManifest.totalBytes(for: .mnnLLM) == 1_185_759_005) + #expect(ModelManifest.totalBytes(for: .mnnLLM) == 2_836_770_850) } @Test func mnnHasEssentialRuntimeFiles() { @@ -39,7 +39,7 @@ struct ModelManifestTests { @Test func mnnFileURLUsesRepoPath() { let file = ModelFile(path: "config.json", bytes: 652) let url = ModelManifest.fileURL(for: .mnnLLM, file: file) - #expect(url.absoluteString == "https://file.myv0.com/Qwen3.5-2B-MNN/config.json") + #expect(url.absoluteString == "https://file.myv0.com/Qwen3.5-4B-MNN/config.json") } @Test func excludesReadmeAndGitattributes() {