2.7 KiB
2.7 KiB
MNN 前缀 KV Cache 调研(2026-06-10)
结论
当前打包的 MNN.xcframework 已暴露 prefix cache 能力,技术上可以把每个场景固定的 system prompt + few-shot 模板的 prefill 结果缓存到磁盘,二次调用跳过这部分 prefill。 建议 W6 polish 阶段、用性能自检卡量化 prefill 占比之后再决定是否接入;当前瓶颈在 decode 而非二次 prefill,优先级低于 C1/C2/Live Activity。
依据(Frameworks/MNN.xcframework/ios-arm64/MNN.framework/Headers/llm/llm.hpp)
| API | 行号 | 含义 |
|---|---|---|
bool setPrefixCacheFile(const std::string& filename, int flag = 0) |
:161 | 指定前缀缓存文件;配套私有成员 mPrefixCacheMode / mPrefixLength / mIsPrefixFileExist / completePrefixWrite()(:250-255)印证:命中时 prefill 只算增量部分 |
bool reuse_kv() |
:171 | 读 config 开关 reuse_kv,多轮对话内复用 KV(同一会话增量 prefill) |
void syncPromptCache(const ChatMessages&) |
:176 | decode 结束后同步缓存文本——注释明确说明 cache 在 generate() 后自更新,此接口供做过后处理(如 deleteThinkPart)的调用方提供更准确版本 |
void setKVCacheInfo(size_t add, size_t remove, ...) / eraseHistory(begin, end) |
:158-160 | 更底层的 KV 区间管理,可做部分历史擦除 |
对本项目的适用性
- 我们所有调用都是「固定模板前缀 + 可变数据后缀」的单轮
response(),与 prefix cache 的模型吻合。 - 模板体量(估):报告识别 ~900 tok、导出报告 ~700 tok、意图抽取
300 tok。 按性能自检卡实测的 prefill 速率推算,每次调用预计省 **13s**。 - 多场景共用一个 cache 文件是否支持多前缀未知;最坏情况只对单一场景(建议选「报告识别」, 模板最长、调用最频繁)生效。
风险
flag参数语义在头文件无注释,需读 MNN 源码或实验确认。- OMNI(多模态)分支下行为未验证——我们的 MNN 模型是 Omni 构建。
- cache 文件与模型权重版本绑定:模型更新/重下载后必须失效,否则可能输出乱码。
<img>标签在 prompt 前部(analyzeImages把图片标签拼在最前),意味着报告识别场景的 "固定前缀" 实际不固定 —— 文本场景(导出/意图抽取)才是干净的 prefix cache 候选。
建议的接入步骤(W6,如性能自检显示 prefill 占比 >30%)
MNNLLMBridgeinit 后调setPrefixCacheFile(<AppSupport>/mnn-prefix.cache)(仅文本场景)。- 真机 A/B:同一导出报告各跑 3 次,对比
LlmContext.prefill_us。 - 异常处理:加载失败或输出劣化时删除 cache 文件并禁用,回退现状。
ModelDownloadService.importModel/ 重下载路径上顺手删除旧 cache 文件。