目录 展开 收起
搜索为空或报错时,不要先把所有问题归为“索引损坏”。ChatCrystal 把笔记状态、SQLite 中的 embedding 记录、Vectra 文件和删除清理任务分开维护;先确定是哪一层不一致,才能选择修复范围。
本文依据固定提交 7642768 的 向量索引、embedding 流程 和 数据库初始化。完整恢复示例会移走索引目录;执行前停止所有写入,包括共享目录的桌面应用,并备份整个数据目录。命令中的 <note-id> 必须替换为实际 ID。
先记录症状与状态
空结果可能来自没有笔记、笔记仍在 pending、向量生成失败、索引目录不存在,或查询与当前模型不匹配。crystal status 只能帮助确认总体数据量;要查看笔记的 embedding_status,用 API 返回的笔记详情:
curl 'http://localhost:3721/api/notes?limit=100'
curl 'http://localhost:3721/api/notes/<note-id>'
列表默认按时间排序,limit 最大为 100,响应里的笔记对象包含状态字段。done 是数据库状态,不足以证明文件索引完整:启动时,只要笔记仍有 embedding 行,初始化代码就会将它标为 done,不会检查 Vectra 中是否存在对应项。pending、failed 和 syncing 则需要进一步检查。不要把 GET /api/notes?embedding_status=pending 当成过滤器:这个路由没有这个查询参数。
了解索引和数据库的边界
getIndex() 首次访问时创建 vectra-index 下的 LocalIndex;它不会扫描 SQLite 的 embedding 表并自动补建所有向量。数据库记录和文件索引因此可能暂时不一致。
一次笔记重建大致按这个顺序执行:先向模型请求向量,在 Vectra 更新批次中插入新项,把 SQLite 的 embedding 行换成新 ID 并标为 syncing,删除旧项,提交更新,最后标为 done。异常时会尝试 cancelUpdate();如果数据库已经换过行,状态会保存为 failed,供后续重试。强制终止进程仍可能留下需要人工判断的中间状态。
删除笔记产生的 Vectra 清理记录写在 vector_cleanup_tasks 表。每次语义搜索会尝试处理最多 25 条待处理清理任务;清理失败会保留任务并等待下次重试,搜索本身不会因这一步失败而直接停止。这是删除任务的重试机制,不是对任意损坏文件的通用修复。
先尝试低风险的单篇重建
如果只有一条笔记状态异常,保留索引目录并调用同步入口,观察响应和状态:
curl --request POST \
'http://localhost:3721/api/notes/<note-id>/embed'
curl 'http://localhost:3721/api/notes/<note-id>'
这个接口通常会生成向量,但有一个快速确认分支:若笔记为 syncing 且数据库中的向量 ID 全部已在 Vectra 提交,就直接标为 done 返回,不再请求模型。因此它不是无条件强制重建接口,也不会重写笔记摘要。实际生成时,模型、地址和向量维度必须仍然可用;若切换了 provider 或 embedding model,先按 Embedding 配置指南确认清空与重建范围。
再决定是否清空整个索引
只有在确认文件索引不可读、而数据库笔记仍是可用来源时,才考虑完整重建。下面是默认 CLI 目录的示例;备份位置用 mktemp 创建,避免覆盖或嵌套进已有备份:
crystal serve stop &&
recovery_backup=$(mktemp -d "$HOME/.chatcrystal/vectra-recovery.XXXXXX") &&
mv "$HOME/.chatcrystal/data/vectra-index" "$recovery_backup/vectra-index" &&
crystal serve --daemon &&
curl --request POST 'http://localhost:3721/api/notes/<note-id>/embed'
打包应用的数据目录由运行时路径决定,不能无条件套用上面的默认路径;先从应用配置和日志确认实际目录。通过 GET /api/notes?limit=100&offset=0 分页列出受影响笔记,为每个 ID 重复单篇重建请求并检查响应,直到覆盖全部目标。
clearEmbeddingIndex() 只会删除索引并清空进程内缓存,不会自动把已有 done 笔记改为待处理。POST /api/embeddings/batch 只选择 pending、failed、syncing,而重启还可能把有 embedding 行的笔记改为 done;仅移走索引再调用批量接口,可能得到 queued: 0。逐篇显式重建才能避免漏掉这些笔记。
用可重复的结果验收
恢复后记录三类证据:
- 目标笔记的
embedding_status变为done,并且批量队列中的失败数不再增加。 - 用一个已知答案、一个同义问题和一个无答案问题搜索;检查笔记是否出现、顺序是否变化、是否有误匹配。
- 重启服务后再次查询,确认新索引可以被重新打开。
索引可读只证明文件结构能访问,不证明检索质量。若重建后仍为空,转而检查模型配置、实际输入字段和查询条件;参见 语义搜索流程。