Skip to content

local embedding

github-actions[bot] edited this page Oct 10, 2026 · 7 revisions

🌐 简体中文 · 繁體中文 · English

🧬 本地嵌入(Local Embedding) {#local-embedding-section-1}

本地嵌入是 Tsukuyomi 的离线语义检索引擎:完全在浏览器内运行嵌入模型,把记忆与章节内容映射成向量,让 AI 能按语义而不是关键词找到相关上下文。向量计算在本机完成,不消耗 AI API 额度。向量属于设备本地状态:Gist 同步只上传记忆内容,不上传向量,每台设备各自生成;实际发送给 AI 的上下文仍按模型请求发送,详见本文隐私说明。

本指南面向想了解或排查本地嵌入功能的用户。设置入口请见设置说明,记忆相关用法见记忆管理。


1. 它能做什么 {#local-embedding-section-2}

启用本地嵌入后,系统会在后台为以下数据建立向量索引:

  • 记忆库:每条记忆的"摘要 + 内容"按段落和句末标点切成 ≤1200 字的短段分别嵌入,再做多分段稳健聚合,避免长记忆被截断后语义漂移。翻译时三信号评分中的「语义相似度」分量(嵌入可用时权重 0.85)由此提供;AI 也能调用 search_memories 工具按自然语言搜索记忆。
  • 章节内容:每章按段落(目标 100 字/chunk)和「标题 + 首段」拆成多个 chunk 分别嵌入,AI 通过 query_chapter 工具按自然语言找到相关段落,无需依赖预先生成的章节摘要。

章节语义向量统一编码原文,避免已译与未译章节的语言差异影响排名;原文缺失时使用目标译文。关键词、预览和全文索引保留原文与当前目标的选用译文。缓存按目标语言及实际输入签名校验,译文变化也会刷新关键词与预览。切换目标后,失效缓存会在后台重建;旧目标的迟到计算不会覆盖新缓存,未完成时可能显示重建状态。术语、角色和别名检索只扩展原名与本次目标译名,缺译名不借用其他语言。记忆内容与记忆向量跨目标共享,不因目标切换清空。

模糊情节查询会对少量候选的原文段落进行本地重排,避免关键情节被前后文稀释。已有明确匹配的查询保留整块上下文,重复查询复用向量缓存;重排计算失败时保留原排名。整个过程在浏览器内完成,不增加 AI API 请求。

未启用时:

  • 三信号评分自动退化为关键词 + 时间衰减(权重 0.75 / 0.25,仍然有效,但语义层面的"意义相近但措辞不同"会漏召)。
  • AI 不再暴露 query_chapter 工具,翻译提示词也会移除对应引导。
  • 「向量索引」入口隐藏,已打开的面板关闭。

2. 模型与运行方式 {#local-embedding-section-3}

默认嵌入模型 {#local-embedding-section-4}

  • 模型:hotchpotch/bekko-embedding-v1-a25m(Bekko a25m 多语言编码器)。
  • 架构:约 123M 总参数、25M 活跃参数,支持中 / 日 / 英等 100+ 语言。
  • 维度:使用完整的 384 维向量,并做 L2 归一化。
  • Pooling:mean pooling — 对有效 token 的表征求平均。query 与 document 共用同一编码路径,不添加任务前缀。
  • 默认文件:官方 onnx/model.onnx,约 190 MiB;静态词表已做 int8 压缩,Transformer 计算保持 fp32。dtype: fp32 选择这个已压缩文件,不表示下载完整 fp32 词表。
  • 模型版本号:bekko-embedding-v1-a25m@384@mean@raw。模型 ID、维度、pooling 或输入方案变化都会更新版本号,旧记忆与章节向量会被判定为 stale,需要重新计算(见第 5 节)。

从 GTE 升级:此前使用 GTE 模型的用户需要重新下载 Bekko 模型,已有向量全部需要重建。模型下载完成前,记忆打分使用关键词 + 时间衰减;模型就绪后,尚未重建向量的旧记忆在关键词强命中(原始置信度 ≥ 0.8)时逐条改用关键词 + 时间衰减评分,仍可被自动注入或被 search_memories 找到;只部分命中的不会被召回。章节语义搜索在重建前暂不可用。打开书籍详情页会自动重建该书向量,建议升级后尽快完成重建。

运行后端 {#local-embedding-section-5}

模型加载、分词和推理都在独立浏览器 Web Worker 中运行,不占用页面主线程,下载或推理期间界面不会卡顿;整个过程仍完全在本机完成,不需要服务器。WASM 在 Worker 内使用单线程,无需跨源隔离。Worker 内优先检查是否能取得 WebGPU 适配器并创建设备;不可用时直接使用 WASM;WebGPU 初始化失败时也会自动回落到 WASM。两个后端共用同一份默认模型文件。

后端 文件与计算 大小 适用场景
WebGPU 默认 ONNX,词表 int8 / Transformer fp32 ~190 MiB 支持 WebGPU 的桌面浏览器
WASM 同一默认 ONNX 文件 ~190 MiB WebGPU 适配器或设备不可用的浏览器

适配器不可用时,本会话使用 WASM;在设置中点击「重新加载」会重新检查 WebGPU。实际推理速度取决于设备、输入长度和运行后端。

移动端强制禁用 {#local-embedding-section-6}

Quasar 检测到物理移动设备时会锁定「启用本地嵌入」开关为关闭:「本地嵌入」设置页仍然可见,但开关灰显不可操作,并显示不支持原因。原因是浏览器 WASM 的内存上限(一般 ~2GB)在模型加载与多 chunk 推理时极易触发崩溃。移动端依然能正常使用关键词匹配 + 时间衰减信号。由于向量不随同步上传,桌面端生成的向量也不会出现在手机上。

该判断只看设备类型,不看窗口宽度:桌面浏览器缩窄窗口不会被当成移动设备。


3. 启用步骤 {#local-embedding-section-7}

  1. 进入 设置 → 本地嵌入。
  2. 打开「启用本地嵌入」总开关。若浏览器尚未缓存模型,会直接开始下载(约 190 MiB,WebGPU 与 WASM 相同),不会弹出确认窗口;之后若状态为「未加载」,也可点击「下载模型」手动开始。下载需要稳定网络,请保留窗口在前台。
  3. 下载期间设置卡片内显示「模型加载进度」及百分比,下方提示当前阶段:「正在准备模型文件…」→「正在下载模型文件…」→「正在初始化模型…」。
  4. 下载完成后模型会被浏览器 Cache Storage 持久化,之后启动会自动预热,无需再次下载。
  5. 状态变为「已就绪」后,便可进入下一步。
  6. 打开任意书籍,点击「向量索引」入口(见第 4 节),查看或按需补建本书的章节 / 记忆向量。

关于进度显示:

  • 百分比只统计 .onnx 权重文件的下载字节,配置、分词器等小文件完成不会让进度虚高。
  • 权重总大小未知时进度条显示为不确定状态(来回滚动),拿到大小后切换为百分比。
  • 下载阶段最多显示到 95%,剩余部分留给模型初始化;初始化完成后进度块收起,状态变为「已就绪」。
  • 进度不会倒退:自动重试或 WebGPU 回落到 WASM 时,进度条沿用已显示的数值。
  • 关闭再重新打开设置页时,会恢复当前加载进度。

4. 向量索引面板 {#local-embedding-section-8}

「向量索引」入口只在书籍详情页、且本地嵌入有效启用时显示;关闭本地嵌入或在物理移动设备上时入口隐藏。入口位置随布局变化:

  • 桌面布局:右侧工具栏。
  • 平板布局:右侧侧轨。
  • 窄屏布局:顶部工具栏。

入口按本地嵌入是否有效启用显示,不以布局断点判断,桌面浏览器缩窄窗口仍可使用。点击后,桌面和平板布局打开右侧抽屉,手机布局打开与助手、翻译进度一致的底部抽屉。已打开的面板在布局切换时保留;切换到另一本书时自动关闭。

面板标题为「本地向量索引」,副标题「浏览器本地运行」,下方显示当前书名和章节数。

状态徽章与统计 {#local-embedding-section-9}

  • 状态徽章:标题栏右侧显示 就绪 / 模型加载中 / 加载失败 / 未就绪 / 已禁用。
  • 「章节向量」:显示「已嵌入 X / Y」(X 为当前模型版本已嵌入的章节数)、进度条,以及「待处理:N」(嵌入队列中等待处理的章节数;队列为全局共享,可能包含其他书籍的任务)。
  • 「记忆向量」:同样显示「已嵌入 X / Y」、进度条和「待处理:N」。
  • 底部状态区:显示模型版本号、运行后端(WebGPU 或「WASM (慢)」)和当前状态。

存在 stale 向量(版本不匹配)时,面板顶部显示「Embedding 空间已升级」横幅,列出旧版章节与记忆数量,并提供「立即重建」按钮。stale 向量不计入"已嵌入",因此升级后数字可能明显回落。

stale 条目不会在所有书籍中自动重算:只有在模型就绪时打开某本书的详情页(或详情页打开期间模型加载完成),才会自动把本书缺失和 stale 的章节 / 记忆入队。其他书籍请打开后自动触发,或在面板中点击「立即重建」/「回填缺失」。

操作 {#local-embedding-section-10}

  • 章节:「回填缺失」把本书未嵌入或 stale 的章节入队;「全部重算」把本书所有章节重新入队计算。
  • 记忆:「回填缺失」把本书未嵌入或 stale 的记忆入队。
  • 「立即重建」:仅在 stale 横幅中出现,一次性把本书 stale 的章节和记忆入队。
  • 以上按钮只在模型「就绪」且队列空闲时可用,避免与正在进行的重建冲突。
  • 「测试向量查询」:打开查询对话框(见下文)。
  • 「暂停」/「恢复」:只在队列运行或已暂停时出现在底部状态区,用于手动挂起或继续队列。

测试向量查询对话框:顶部说明「用自然语言描述剧情、人物关系或关键词,检索本书章节与记忆。」输入查询语句后点击「查询章节」或「查询记忆」(回车默认执行章节查询;记忆查询按当前模型版本的向量匹配,尚无可用向量的记忆在关键词强命中时也会返回)。

  • 未查询时显示「查找书中的情节和记忆」提示。
  • 查询中显示「正在检索章节…」或「正在检索记忆…」加载状态。
  • 结果按相关度排序,每条显示排名序号和相关度分数(鼠标悬停提示「相关度」);点击章节结果跳转到对应章节,点击记忆结果查看详情。
  • 便于调参或排查"为什么这条记忆没被注入"。

进度与当前任务 {#local-embedding-section-11}

队列运行时,进度直接显示在各分区内,面板顶部没有单独的横幅:

  • 「章节向量」与「记忆向量」各自显示「待处理:N」,有待处理条目时同时显示 ETA(基于最近 5 个批次的平均耗时估算)。
  • 当前任务卡片显示队列正在处理的内容:处理本书时显示「本书 {类型} ×{数量}」;处理其他书籍时以醒目颜色显示「其它书籍 · {类型} ×{数量}」并附上该书书名,即便你在另一本书的面板里也能看到队列在哪儿忙。

后台记忆和章节推理每组最多 4 条输入,并按长度拆组,降低长短文本混合时的计算开销;前台查询及段落重排每组最多 8 条,优先于等待中的后台任务。后台批次之间会留出计算空档,因此整书重算可能更慢,以减少 CPU / GPU 持续占用。章节在批次之间响应暂停;未完成的章节保留在队列,继续后重新计算,完成整章后再统一保存。面板关闭时暂停统计读取,打开后合并同批刷新。


5. 模型版本与 stale 重算 {#local-embedding-section-12}

MODEL_ID + 截取维度 + pooling 方案 + 输入方案一起构成「embedding 空间身份」。任意一项变化,旧向量与新向量就落在不同空间,余弦相似度会退化成噪声,必须重算。

应用通过 MODEL_VERSION 常量记录当前空间身份,每条已嵌入的记忆 / chunk 都会同时存这个版本号。检索与统计逻辑会调用统一的 isMemoryEmbeddingStale / isChapterChunkStale 判断版本是否匹配:

  • 匹配(current):参与语义检索 / 计入"已嵌入"。
  • 不匹配(stale):跳过语义评分,并在回填扫描时进入重算队列。模型就绪时其他记忆仍按语义模式打分;stale 条目(以及尚未生成向量的新记忆)关键词原始置信度 ≥ 0.8 时逐条改用关键词 0.75 + 时间衰减 0.25,否则只剩语义模式下的小权重,达不到注入阈值。

这意味着升级模型不会丢数据:旧条目和记忆内容都保留,重建完成前只有关键词强命中的记忆能被检索与注入;重建后回到完整能力。

启用本地嵌入时,应用启动会清理浏览器 Cache Storage 中的历史模型残留(如 embeddinggemma、qwen3-embedding),回收磁盘空间。旧 GTE 模型的缓存(约 340–465 MB)目前有意保留,暂不自动删除;如需回收空间,可在浏览器中清除本站点数据(之后需要重新下载当前模型)。


6. 同步期间的 sync gate {#local-embedding-section-13}

云同步与修订恢复期间,嵌入队列会被一道专用闸门临时挂起:

  • isSyncing 或 isRestoringSyncSnapshot 任一为 true,闸门锁住队列。
  • 闸门解锁后只恢复"由闸门自身挂起"的任务 — 用户在 UI 上主动点击的「暂停」状态完整保留,不会被同步流程意外解除。
  • 闸门生效时正在推理的批次不会写入:记忆与章节向量都会放回队列,闸门解锁后按同步后的内容重新计算。
  • 这避免了同步过程中嵌入写入与 overwriteFromSnapshot 的覆盖竞态,也防止恢复一半的数据上面再叠上半新的向量。

UI 表现:面板没有专门的同步提示;同步期间队列处于暂停,底部状态区显示「恢复」按钮,但按钮不可用,避免在同步过程中写入向量。同步结束后队列自动继续,无需手动点击;如果在同步期间点击了「暂停」,同步结束后队列保持暂停。


7. 故障排查 {#local-embedding-section-14}

进度卡在 0% {#local-embedding-section-15}

  • 检查网络:模型托管在 Hugging Face CDN,若网络不可达会进入自动重试(递增延迟 3s / 8s / 20s,最多 3 次)。可在浏览器开发者工具的 Network 面板看具体请求。
  • 代理 / 反代:企业网络 / VPN 可能拦截 CDN,可在「代理设置」(仅 Web 端)尝试切换或在浏览器层面配置允许列表。
  • 磁盘空间:模型约 190 MiB,请为浏览器 Cache Storage 预留至少约 250 MB 可用空间(另有少量配置文件和向量数据),磁盘紧张时下载会中途失败。

状态停在「加载失败」 {#local-embedding-section-16}

  • 查看浏览器控制台 [EmbeddingService] 前缀的错误日志,常见原因:
    • WebGPU 驱动不兼容 → 应用会自动回落到 WASM;如果连 WASM 也失败,多半是浏览器内存不足。
    • 首次加载时切走标签页太久导致超时 → 重新打开应用即可(模型缓存命中后第二次启动很快)。
  • 在 设置 → 本地嵌入 中,失败状态下点击「重试」,就绪状态下点击「重新加载」,都会释放旧模型并重新检查 WebGPU。向量索引面板中没有重新加载按钮。Worker 崩溃或请求超时后,未完成任务保留在队列;模型恢复后继续,已保存的章节缓存不会被半成品覆盖。

检索结果质量不佳 {#local-embedding-section-17}

  • 用「测试向量查询」对话框直接输入查询语句,看返回结果是否合理。
  • 如果某条记忆/章节"明明应该被找到"却没出现,确认它是否为 stale(面板顶部有「Embedding 空间已升级」横幅时):先点击「立即重建」或「回填缺失」,再测试。
  • 中日英混合查询:模型原生多语言,直接输入纯净查询即可(v0.14.3 起不再为 query 端添加任何前缀)。

已禁用但提示"嵌入队列还在跑" {#local-embedding-section-18}

通常是关闭总开关时正在处理某批次。当前批次完成后队列自然停止,强制中断会丢弃这一批结果。关闭后「向量索引」入口立即隐藏;尚未处理的条目保留在队列中,重新启用后自动继续。


8. 隐私与离线性 {#local-embedding-section-19}

  • 嵌入模型推理在浏览器 Worker 内执行,不调用外部嵌入 API。
  • 模型本身一次性下载到 Cache Storage,之后离线启动也能用。
  • Gist 同步会上传记忆内容,但上传前会剥离记忆向量与模型版本标记(详见 设置说明 → 数据同步)。向量只保存在本机 IndexedDB 中,每台启用本地嵌入的设备各自生成;Tsukuyomi 不持有任何中转服务器。

相关文档 {#local-embedding-section-20}

Clone this wiki locally