Skip to content

Latest commit

 

History

History
169 lines (118 loc) · 21.8 KB

local-semantic-search.md

File metadata and controls

169 lines (118 loc) · 21.8 KB

本地语义检索

使用方式

在 设置 → AI 服务 → 本地检索 按两步准备:选择已下载的模型,再选择聊天与时间范围,点击“开启并开始整理”一次完成保存、启用与建立索引。默认关闭;打开设置、下载完成和 Agent 提问都不会自动扫描全账号。

  • 模型文件由本机账号共享,模型选择、索引和处理记录按微信账号隔离。
  • 模型先下载再选择;“更换模型”打开二级管理弹窗,选择先保留为草稿,点击主按钮后才建立新模型索引,成功后切换;此前的索引继续服务。
  • 从聊天打开范围选择时预选当前聊天;通用设置不默认全选。支持最近 30 天、90 天、自定义日期和全部历史。
  • 普通搜索新增“关键词/智能搜索”。默认关键词;智能搜索融合 FTS5 和语义候选,保留原消息定位、会话、发送者、时间及消息类型过滤。界面展示相关候选数量,相似度不代表正确率。
  • Agent 在已授权会话中自动使用可用索引;索引范围不能扩大 Agent 权限。结果说明未覆盖范围、数据新鲜度及候选截断,GPU 回退原因进入工具记录。
  • 关键词搜索和本地向量推理不调用云端模型。Agent 生成回答仍使用已配置的 AI 服务,相应聊天证据会发送给该服务。 自动总结、关注提醒的判断流程不变。

模块导航统一为“模型服务/本地检索/Agent/用量记录”,附简短用途,支持方向键切换。主页面只保留两步准备与一个主按钮,未满足条件时在按钮旁说明原因。暂停且配置未变时显示“继续整理”;运行中显示真实阶段、数量和用时,完成后提示从哪里使用智能搜索。GPU、自动更新、关闭功能和清理均在高级设置中,CPU 无需安装组件即可使用。

模型卡片提供下载、暂停、继续、重试、离线导入和删除。关闭功能保留模型与索引并停止后台任务;清理索引不删除微信消息。正在被账号配置或现有索引引用的模型不能删除。

尚未选择模型时展示推荐模型,并明确要求下载后点击“使用此模型”。如果要删除最后一个模型,可先关闭功能、清理索引以解除该账号的模型引用;其他账号仍在使用时仍会阻止删除。

Hugging Face 固定来源

清单位于 src/wechat_decrypt_tool/resources/local_search_models.json,包含完整提交 SHA、逐文件大小与 SHA-256、许可证、池化方式、前缀、维度和输入限制。运行时不追踪 main。

模型 Hugging Face 仓库与固定提交 下载字节数 向量
BGE Small 中文,推荐 Xenova/bge-small-zh-v1.5 · 75c43b069aac4d136ba6bc1122f995fedcfd2781 95,401,750 512
BGE Base 中文 Xenova/bge-base-zh-v1.5 · 71e50dc531959f9e04ebf190ea25b00261a0a186 407,503,264 768
Multilingual E5 Small intfloat/multilingual-e5-small · 614241f622f53c4eeff9890bdc4f31cfecc418b3 492,421,556 384

BGE 原作者为 BAAI,ONNX 转换来源为 Xenova;E5 来源为 intfloat。三个仓库清单标注 MIT。只下载 onnx/model.onnx、必要的分词器和配置,不下载训练权重或其他量化版本。当前三份清单均为六个文件,FP32、最大输入 512 Token。

BGE 使用 CLS 池化和 L2 归一化;查询加中文检索前缀,文档不加。E5 使用 attention mask mean pooling、L2 归一化及 query: / passage: 前缀。

官方下载 SDK 固定为 huggingface-hub==1.27.0。所有请求显式传入 token=False,关闭隐式凭据与遥测,不读取用户其他工具的 HF 登录状态。匿名模式支持当前收录的公开、非 gated 资源;不代表 Hugging Face 所有模型均免登录。接口行为参见 官方下载接口与 gated 模型说明。

下载在独立工作进程中执行,全局单模型串行、模型内逐文件下载。HF 的 CDN 重定向允许通过,长期状态只保存仓库、提交和文件标识。没有第三方镜像切换。每轮恢复共享最多五次尝试;429 使用服务端等待时间,临时错误有限退避,CDN 访问拒绝重新解析固定地址。版本不存在、源权限变化、磁盘不足和校验失败单独提示。SDK 内层重试关闭,防止预算叠加。

暂停保留 HF 临时数据,继续复用已校验文件;“取消并清理”只删除本应用的模型版本目录。下载完成需通过完整哈希、模型加载和小样本推理才可选择。完整模型启动只访问本地文件;损坏文件不能伪装成 CUDA 错误。

离线导入

在可联网电脑准备表中同一提交版本的清单文件,保留 onnx/model.onnx 等目录结构。目标电脑点击模型卡片“离线导入”,填写该目录;应用校验固定文件哈希并执行本地推理。无需 HF Token,不执行模型仓库代码。

NVIDIA 组件离线导入目录需包含当前 CPython 架构对应的 ORT GPU wheel,以及四个 NVIDIA wheel,文件名和哈希见 GPU 清单。不接受任意模型、任意 ONNX、仓库脚本或第三方 CUDA 安装包。

CPU / NVIDIA 兼容矩阵

CPU 随基础程序打包:Windows 使用 onnxruntime==1.28.0,macOS 使用 onnxruntime==1.23.2(同时有 macOS 13+ arm64 / x86_64 wheel)。分词器固定 tokenizers==0.23.1,向量扩展固定 sqlite-vec==0.1.9。Mac 的自动模式使用 CPU,隐藏 Windows NVIDIA 组件入口。详见 macOS AI 兼容性与验收。

Windows x64 GPU 加速组件独立于 CPU 和语音 CTranslate2 环境,清单位于 src/wechat_decrypt_tool/resources/local_search_gpu.json:

组件 固定版本
ONNX Runtime GPU 1.26.0,CPython 3.11 / 3.12 / 3.13 Windows x64
CUDA Runtime 12.8.90
cuBLAS 12.8.4.1
cuDNN 9.8.0.87
cuFFT 11.3.3.83
应用采用的 Windows 驱动基线 572.61 或更新

CPython 3.11 对应组件下载量为 1,671,874,915 字节;解压还需要额外磁盘空间。组件来自官方项目的 PyPI wheel,与检索模型的 Hugging Face 来源分开管理。wheel 内许可证随组件保留。

驱动基线采用 CUDA 12.8 Update 1 对应驱动,并非宣称低于该版本的所有 CUDA 12 程序均不能运行。本应用保守回退 CPU。ORT 1.27 起默认 GPU 包切换至 CUDA 13,因此不能直接升级 GPU 包;见 ORT CUDA 要求。

场景 当前验证情况
RTX 4070 SUPER,驱动 596.49,Windows x64 / Python 3.11 三个模型真实 CUDA 推理通过
同机强制 CPU 三个模型通过;固定样例检索通过
打包后的 Windows EXE CPU、外置 CUDA 组件、sqlite-vec 扩展通过冒烟测试
RTX 30 系 / RTX 50 系 目标支持范围,尚无对应实机,标记未验证
干净 Windows / 无独显实体电脑 尚未实机验收;已覆盖无组件与模拟 GPU 故障的 CPU 路径
Python 3.12 / 3.13 GPU wheel 清单已固定,未进行对应解释器实机验收
macOS 26.3.1 / Apple M4 / CPU 三个模型匿名完整下载、推理与混合检索、冻结程序推理、源码桌面启动通过;真实账号端到端流程尚未验收,见验收记录
Intel Mac / Linux CPU 未实机验收;Intel Mac 已核对依赖 wheel;首版不提供其他 GPU 后端

设备策略为自动、CPU、NVIDIA GPU,多 GPU 可选设备编号。检查包括驱动基线、组件加载、所选模型真实推理,以及 profiling 中实际执行的 CUDA 节点;仅有 Provider 名称不算成功。CPU/GPU 同一份 FP32 模型,GPU 关闭 TF32,不修改系统 PATH,也不要求全局 CUDA Toolkit。

GPU 进程故障、超时、缺库或显存不足时销毁故障进程,在独立 CPU 进程重做未提交批次;该应用会话暂时禁用故障 GPU,手动重新检测或重启后可再尝试。用户取消不触发回退,CPU 失败暂停并保留游标。GPU 回退成功仍是智能搜索;本地推理整体失败才回到关键词分页。

索引与恢复

  • 主操作区提供“从头整理”,按页面当前选择的模型、聊天和时间范围重新生成全部向量;暂停任务也可选择放弃续传、从头处理。模型变化时主按钮显示“使用新模型从头整理”,普通建立接口也会自动创建独立索引,绝不复用旧模型向量;新索引失败时保留旧索引,完成后才切换。
  • SQLite 业务记录保存配置、下载任务、索引任务和本地审计;账号使用独立 sqlite-vec 数据库。索引 generation 隔离模型切换,数据与游标在同一事务提交。
  • 内容包括文字、引用、卡片标题、已有语音转写和已缓存的本地附件提取文字。新的语音识别、OCR、视觉描述和视频分析不会由建索引触发。旧版只保存混合视觉输出的附件缓存不会直接冒充本地提取文本。
  • 相邻聊天按会话及十分钟间隔组织片段,目标 384 Token、重叠 64 Token,保留逐消息来源映射;超长正文分段。
  • 首次任务固定截止时间。手动整理和每分钟自动更新都默认增量读取最近提交截止时间前十分钟起的窗口,处理同秒与短期补写;按聊天复用已覆盖范围,新增聊天或向前扩展历史时补齐对应范围。重复保存相同设置不改变配置版本和断点,设备等偏好变化不使已有覆盖失效;缩小范围清理后同步覆盖记录,重新扩大时补回。转写/本地附件缓存版本变化时重新核对选中范围,每天另做一次范围校对。长期历史补写可能等待下一次校对;界面显示本次整理原因与已复用消息数。
  • 未改变内容不重复生成向量;原文变化时重建相关片段,保留相邻未修改消息。缩小范围立即约束检索并清理被移除部分。
  • 后台建索引单并发、每批最多 8 个片段、CPU 两个推理线程;交互查询优先于后续后台批次。语音模型处于活动状态时,后台索引改用 CPU 让出 GPU。空闲五分钟释放模型进程。
  • 每个会话在专用线程内保持连续消息流,正常翻页不重新扫描前缀;SQLite 连接、原生游标的推进和关闭在同一线程内完成。新断点将最后提交时间及该秒已提交消息身份与数据一起事务保存,恢复直接从该时间读取并跳过已保存身份,保留同秒尚未提交消息。旧版只有 offset 的断点首次恢复仍需跳过一次前缀,下一次提交后自动迁移。
  • 默认自动批量(read_batch_size=0)。总内存不超过 4 GiB 或可用内存不足 1 GiB 时最多 100 条;总内存不超过 8 GiB 或可用内存不足 3 GiB 时最多 500 条;其余情况自动使用 1,000 条。高级设置可选 100/500/1,000/2,000 条,手动选择仍受内存保护,每批重新检查。不依赖 NVIDIA 显卡是否存在。
  • 单批累计文本达到 128,000 字符时提前处理,避免少量长文本积累过多片段;保留完整单条消息,因此此阈值不是进程内存的硬上限。推理仍按最多 8 个片段执行,不随读取批量扩大显存需求。低内存策略通过模拟测试,其他硬件、系统和磁盘速度仍需实机验证。
  • 读取数量约每 250 ms(有新消息时)上报一次,页尾立即上报;SSE 每秒传递事件,1.5 秒轮询兜底。界面直接更新读取数、片段数、实际批量和已保存进度,较旧事件或轮询响应不得让进度倒退。设备状态不变时不重复写入相同事件。
  • 整理采用固定轮次:先显示「正在统计消息总量」,按任务开始时的聊天目录、截止时间和本轮范围准备完整清单并去重,再显示「已读取 / 本轮总量」。统计中的临时数量不会作为分母展示;统计失败则保留断点并等待重试,不提前进入推理。
  • 本轮总量发布后不再增长、隐藏或在完成时校准,进度条按「已保存消息数 / 本轮总量」计算。后台发现的新会话不会打断未完成轮次;统计完成后收到或补入的消息留到下一轮。
  • 为避免统计与实际读取之间的数据变化,准备清单时会分页暂存本轮消息,之后直接从本地暂存数据整理,不再第二次读取微信正文。内存按分页条数和字符数限制;首次整理需等待全部统计完成,并临时占用额外磁盘空间。暂存文件位于本地检索数据目录的 plans/ 下,按账号与任务隔离。
  • 暂停或重启保留统计断点及已固定的消息清单;旧任务迁移时将已保存数量纳入本轮总量。完成后自动清理临时清单,调整配置、清理索引或删除账号时也会清理。已固定清单丢失时提示从头整理,不静默重新统计成另一个总量。
  • 最小化继续处理;退出停止。重启恢复此前运行任务,主动暂停保持暂停。数据和断点仍在同一事务提交,读取中的数量不用于恢复;失败或暂停只保留已提交批次,大批写入期间每 100 条检查取消。恢复时会重读尚未保存的一批。
  • members(source,chunk) 索引保证按原消息查找关联片段时不扫描整张关联表,适用于新建及已有索引。批量去重和关联查询在后台线程执行。
  • 关键词及向量分别最多召回 200 条,按来源去重、RRF(常数 60)融合。查询票据固定账号、权限版本、范围及候选顺序,有效十分钟,最多缓存 32 次查询。检索文本返回前再次按原消息权限和过滤条件约束,不返回片段内越权相邻原文。
  • 清理索引不会删除微信记录,账号删除清理账号索引和业务记录;SQLite 文件空闲页可能保留以供复用。

接口前缀 /api/ai/local-search 包含 status、settings、conversations、模型操作、device/list、device/recheck、组件操作、索引任务和 events。修改操作仅允许本机访问。SSE 配合 1.5 秒轮询兜底,重连支持 Last-Event-ID。/api/chat/search 增加 retrieval_mode 和 search_ticket,原定位字段保持兼容。

2026-09-08 验收记录

真实账号完整流程复测(效率与完成状态修复后)

  • 使用用户已选择的两个聊天、最近 30 天、BGE Small 中文和 CUDA,通过正在运行的桌面应用本地后端完成重建;未扩大聊天范围。tools/verify_local_search_live.py 可复测重建、暂停继续、检索与重复检查,报告仅记录统计量,不保存聊天正文。
  • 本轮重建处理 6,622 条消息,生成 554 个片段,任务计时约 10.6 秒,实际设备为 CUDA。在保存 1,000 条消息后暂停,再继续同一任务,最终完成;读取数和生成数均有中间进度。
  • 检查落库向量全部有限且已归一化,没有非空消息缺少片段关联。两个聊天分别通过真实本地搜索接口的原文命中前十、会话和类型过滤、分页不重复,以及原文定位接口返回目标消息的检查。
  • 再次完整检查处理 6,622 条未变化消息,本次生成 0 个片段,现有索引仍有 6,622 条消息和 554 个片段。修复设置页将“本次生成”误写为索引总量的提示;现在独立显示当前索引总数,无变化时说明复用已有数据,空索引不再提示可搜索。
  • 实际 Windows 桌面设置页已复核:自动更新继续读取新增聊天,显示本次检查/生成数量及当前索引总量;因此用户稍后看到的总数可能比上述测试快照更多。
  • 修复同一片段的多条消息共享向量时,原文精确匹配被相邻消息挤到后面的排序问题,并增加回归。
  • 最终相关后端 70 项回归通过;本地检索 Vue 30 项通过。CPU 补测三款模型,每款使用 48 条合成消息及 8 个标注查询,混合 Recall@20 均为 1.00;该小样本结果不代表所有真实聊天的准确率或其他实体机性能。
  • 本地报告:tmp/local-search-live-e2e.json。本轮验证的是源码桌面应用与当前选定范围;其他显卡实体机、干净系统与安装包仍需分别验收。

连续读取与大数据量

tools/benchmark_local_search_reading.py --messages 300000 使用独立临时目录中的合成 SQLite 聊天,复用实际快照读取、消息解析和索引存储代码;不读取真实账号。向量使用固定的 512 维数据,以隔离数据库吞吐,结果不代表完整模型推理或实时微信数据库速度。

  • 3,399 条相同消息:旧式 100 条 offset 分页打开数据源 34 次,遍历 59,532 条;连续读取只打开 1 次,遍历 3,399 条,结果校验一致。最终测量读取耗时 0.97 秒 → 0.19 秒。
  • 30 万条合成消息全部读取并写入索引,来源只打开 1 次、遍历 30 万条;最终测量耗时约 156 秒,进程峰值 RSS 约 106 MiB,较本轮开始增加约 42 MiB,首次进度约 0.21 秒,共 594 次进度回调。此结果仅代表当前 Windows 实机,不作为其他电脑的速度承诺。
  • 回归覆盖同秒消息、无 server ID、跨页重复、动态缩小批量、长文本提前分批、读页中途上报、推理失败恢复、事务中途取消、低内存及系统信息读取失败。前端覆盖实时增长、轮询旧响应和旧事件防倒退、批量配置及草稿隔离。
  • 本次相关后端回归 115 项、前端回归 51 项通过;最终修改后的本地检索前端 28 项再次通过。

验证目录独立于真实账号:tmp/local-search-validation,已加入 Git 忽略。未向云端发送聊天,也未消耗回答模型 Token。

完整匿名下载及模型对照

三款模型在新的应用模型目录中完整匿名下载,通过逐文件 SHA-256、CPU 加载及推理。首轮下载含验证耗时分别约 15.1 / 20.1 / 25.1 秒,该网络速度不能代表其他用户网络。

模型 CPU / GPU 最大向量差异 与 BAAI 原始权重对照
BGE Small 1.565 × 10⁻⁷ 分词一致、最大差异 2.012 × 10⁻⁷、样例排序一致
BGE Base 1.788 × 10⁻⁷ 分词一致、最大差异 2.682 × 10⁻⁷、样例排序一致
E5 Small 7.451 × 10⁻⁸ 使用 intfloat 仓库自带 ONNX,不属于 Xenova 转换对照

原作者权重固定对照提交:Small 7999e1d3359715c523056ef9478215996d62a620;Base f03589ceff5aac7111bd60cfc7d497ca17ecac65。仅在隔离验证环境安装 PyTorch / Transformers,未加入应用运行依赖。

首次 GPU 实测发现缺少 cufft64_11.dll,CPU 回退正常;补齐并固定 cuFFT wheel 后,三款模型均实际使用 CUDA。打包冒烟 EXE 分别报告 CPU ORT 1.28.0、GPU ORT 1.26.0 和 sqlite-vec 0.1.9。

额外完成真实 HF 暂停/重启恢复:约 10,486,476 字节时暂停,保留 10,485,760 字节临时权重;重新创建服务后仍为暂停,手动继续后完整校验成功。将相同文件导入新的本地模型目录并加载成功。脚本为 tools/verify_local_search_download_recovery.py。单元回归另外覆盖 429 等待预算、校验失败、版本缺失和访问拒绝。

合成标注检索集

48 条固定样例、8 个标注查询,涵盖延期、金额、订单编号、模糊回忆和英文表达。复用项目字符 FTS5 查询规则,执行真实 ONNX + sqlite-vec + RRF;测试时设置离线模式。

模型 关键词 Recall@20 混合 Recall@20 查询中位耗时 推理子进程 RSS
BGE Small 0.25 1.00 15 ms 158 MB
BGE Base 0.25 1.00 31.5 ms 465 MB
E5 Small 0.25 1.00 15.5 ms 766 MB

这是小规模合成回归,不代表真实聊天总体准确率,也不代表低配置电脑性能。真实大量聊天、隐含上下文与更多人工标注集仍需要补充评估。

复现脚本:tools/verify_local_search_models.py、tools/verify_local_search_gpu.py、tools/verify_local_search_reference.py、tools/verify_local_search_retrieval.py、tools/verify_local_search_frozen.py。日志在 logs/local-search-*.log。后端与 Vue 回归覆盖账号隔离、过滤、事务恢复、模型切换、GPU 回退、取消、重试上限、离线导入、设置不自动扫描和来源定位;生产构建及桌面模型卡片已复核。

本轮相关后端回归 102 项通过(其中本地检索 23 项),Vue 回归 132 项通过;Nuxt 生产构建完成 34 个路由。打包冒烟再次验证 CPU 与外置 GPU 推理正常。项目已用更新后的源码重新启动,功能仍默认关闭。

尚未完成的发布验证:断网及 CDN 过期的端到端网络故障注入、磁盘耗尽实测、大规模真实账号效果、RTX 30/50、无独显实体机、干净 Windows 安装及语音与 GPU 的长期并行压力测试。不得将这些项目标为已通过。

设置页交互重设计验收(2026-09-08)

  • 聊天选择弹窗提供全选、全选当前搜索结果和清空选择;批量操作只修改草稿,确认后应用,关闭弹窗保留原范围。
  • 高级设置使用独立卡片和明确的展开/收起入口,展示运行设备、GPU 加速、自动更新及数据管理的用途。
  • 修复旧版主按钮依赖顶部启用开关、变灰却没有说明的问题;开启与首次建立索引合并为一次明确提交。
  • 模型选择和聊天选择只修改草稿,下载完成不自动选择;高级设置不会顺带保存主流程草稿。
  • Vue 回归覆盖首次开通、模型选择、范围取消、提交失败、暂停恢复、日期校验、账号切换和导航键盘操作。
  • 使用实际 Vue 组件及虚构数据的独立验收页检查布局与交互,不修改真实账号范围,也不额外启动真实聊天索引。预览位于 frontend/tests/fixtures/local-search.html,仅开发验收使用。