这不是另一篇泛泛的 Hybrid Search 教程
市面上已有完整的 Hybrid Search 示例:例如 Vannevar 公开了面向 Markdown 的 FTS5、向量和加权 RRF 方案;Swift 生态的 SearchKit 也提供向量与 BM25/RRF 的端侧检索模式。这意味着,仅解释"关键词和向量需要结合",并不能构成 XBSTACK 新文章的独立价值。本文的差异是以 RecalAI iOS 真实检索实现为依据 ,解释为什么它额外加入 Anchor、严格/宽松词法分支、轻量规则重排、证据分配与引用 ID 检查,以及这种设计哪些地方仍待实验。外部参考:Vannevar 的本地检索设计、SearchKit on-device RAG。
先回答问题:向量检索不是知识库的全部
把 PDF、Word、图片和笔记送入 Embedding 模型,再把查询向量与文本块做相似度匹配,看似已具备"个人知识库"。但用户真正要的往往不是一段语义相近的话,而是找回那一份资料中的准确事实、版本号、金额、专有名词和可打开的来源位置。语义接近不等于事实相同;向量相似度高,也不代表片段足以回答问题。
这就是 RecalAI 所采用的本地优先思路:先保存原件、解析并建立全文检索,使资料尽早可找;后台完成 Embedding 等增强;提问时结合全文和语义候选,融合、去重、重排,再选出有证据的片段给模型。这是架构路径,不是"混合检索一定比单路检索快或准"的未经测试的结论。
相关背景可先阅读 Personal AI Agent 架构 和 Agent Memory 系统设计。前者解释身份、记忆、执行权限和端云边界;本文只聚焦一个更窄的问题:一份私人资料,如何从"被导入"变成"能够被可靠引用"?
第一关:导入完成与能回答,不是同一件事

在个人知识库中,至少有四个应被分离的状态:
- 原件已保存:文件可恢复、可预览;这不等于文字已经可检索。
- 解析和全文索引完成:提取的文字已进入 FTS 索引,可以按词检索;图片型扫描件可能需要 OCR,解析失败必须单独报告。
- 语义增强完成:分块 Embedding、标签与摘要等后台任务已经完成;缺失或失败时不应假装具备语义召回。
- 有证据的问答已就绪:当前知识范围、召回、证据预算与生成结果通过引用校验;找不到足够证据时应回答"当前资料不足"。
这套顺序的意义是把耗时工作移到后台,又不让用户在导入后长期面对一个只能转圈的空资料库。代价是状态管理更复杂:一个文件可以"全文可搜、语义增强进行中";界面和检索器必须使用同一种真实状态,不能误报"AI 已理解全部内容"。
待核证据:RecalAI 各平台当前代码中的导入状态字段、失败重试策略、任务中断恢复及资料库重启后的可见性;未经该检查,不应宣称所有端都实现一致。
第二关:FTS 解决精确命中,向量检索解决不同表达
假设某份资料明确写着 LFM2.5-2.6B-Q4_K_M,用户要查这个模型的兼容性。用户可能直接输入完整型号,也可能问"那个小一点的端侧模型能不能在旧手机运行"。
第一类查询包含准确字符串。全文检索通常更适合保留型号、错误码、接口名、路径和引用原文的能力;第二类查询表达不一样,语义检索可以帮助找到意义相关的段落。两者各有盲区:全文索引受分词、语言、拼写变体影响;Embedding 受模型、语言、切块策略和相似度阈值影响。尤其涉及否定、数字、权限范围与版本差异时,语义相近可能导致严重误判。
SQLite FTS5 官方文档提供 bm25()、snippet() 与 highlight() 等能力;其中 FTS5 的 BM25 分数通常按数值越小越相关来排序,与很多应用对"高分更好"的直觉相反。具体是否使用 SQLite FTS5、采用何种 tokenizer 和字段权重,必须以目标平台真实实现为准。
建议根据实际问题做一张双路召回对照表:
| 查询任务 | 全文检索常见优势 | 语义检索潜在优势 | 风险 |
|---|---|---|---|
| 精确模型名、报错和函数签名 | 字符串定位 | 同义上下文 | 型号误匹配 |
| "哪篇笔记讨论过端云取舍?" | 关键词索引 | 意图与近义表达 | 泛段落压过关键段 |
| 具体日期、金额、版本差异 | 可精确引用 | 辅助发现描述 | 数字和否定语义混淆 |
| 多语言提问找原文 | 依赖分词和词汇覆盖 | 可跨语言召回,依赖模型能力 | 语言能力并非默认保证 |
第三关:为什么采用融合、去重和重排

两路检索返回的排名不能直接拿原始分数相加。全文排名与余弦相似度不在同一量纲,不同文本长度也影响结果。Reciprocal Rank Fusion(RRF)通过名次而非原始分数融合候选,基本形式为:
RRF(d) = Σ[1 / (k + rank_i(d))]
其中 rank_i(d) 是片段在第 i 路结果中的名次,k 是平滑参数。RRF 最早由 Cormack、Clarke 和 Büttcher 在 SIGIR 2009 系统研究。这不证明它在 RecalAI 的实际资料上一定优于其他方法;权重、候选数和效果必须由自己的问答集验证。
融合之后还需要去重。同一个文件可能因重叠切块出现多个高度相似的片段。若把它们全部交给模型,可能浪费上下文预算,并让单一资料的重复表述挤掉有反证的另一份文件。
Rerank 则回答不同的问题:候选是否真正支持当前查询?一个片段仅包含"权限"与"云端"等词,不等于它解释了某项权限的具体范围。重排器的输入预算、延迟、离线适配与语言支持,都必须在目标设备上检验。
第四关:生成模型之前,要先做 Evidence Selection
混合检索不是最后一步。真正决定回答质量的,是哪些片段可以进入生成上下文,以及用户能不能回到它们的原文。
建议按以下约束选择证据:优先当前知识范围中可访问、解析成功的片段;保留 source_id、chunk_id、页码或定位信息;控制重复与单文档过度占比;必要时包含相互矛盾的片段,而非只选"最像答案"的一个;按模型上下文和设备内存设置 Token Budget。
引用校验也不能只看模型有没有输出"1"。每个引用至少应对应当前检索结果中真实存在的源片段,并且指向用户仍有权限访问的文件。引用的存在只证明来源可追踪,不自动证明模型对该来源的推理正确。涉及事实一致性时还需独立核对答案与片段是否相符。
以现有 RecalAI 产品页) 为下一步,读者可以看到本地优先、来源引用以及当前尚未开放商店下载的真实状态;这里不应放"立即下载"的虚假 CTA。
第五关:iPhone 13 与高内存设备,为什么不应强制跑同一个配置
端侧检索和生成的瓶颈不只是模型文件体积。导入任务、SQLite/FTS 查询、Embedding、Rerank、推理上下文、图片预览与界面渲染,会竞争有限的内存、CPU/GPU 时间和电量。较低内存设备更需要限制并发、检索候选数与上下文预算;较高配置设备可以评估更大的模型或更多候选,但不代表任何时候都更准确。
更稳妥的设计是把候选召回、证据筛选、生成预算和模型选择分离,以设备能力和当前负载动态调整。设备内存告警时,优先保障资料原件、索引一致性与用户可见进度,而不是为了继续后台增强牺牲前台稳定性。
本文不能提供毫秒延迟、召回率、耗电量或 iPhone 13 与新机型的速度比值,因为尚未从统一数据集、真实设备及固定版本获得可复核结果。
源码核验:RecalAI iOS 当前究竟实现了什么
本节来自 2026-10-23 对 RecalAI iOS 工作区源码的静态检查 ,不代表运行在真实设备上的性能验收。被核查的实现位于 Sources/Core/Search/PMSearchService.swift、Sources/Core/AI/PMContextBuilder.swift、Sources/Core/AI/PMAssistantModels.swift 及 Sources/Core/ModelDelivery/PMModelTechnicalSpecification.swift;发布前需记录具体 Git SHA 和确认这些路径仍存在。源码仓库属于产品内部开发资产,本节只披露非敏感逻辑。
检索实现比"FTS + 向量"更细: searchChunks() 同时建立精准包含匹配、Anchor Terms、严格词法检索、宽松词法检索和 Dense Vector 候选。向量分支需 semanticSearchAvailable 为真,且查询可生成 Embedding;当前代码按余弦相似度筛选候选,阈值为 0.30、密集候选最多 50 个。这些是当前源码常量,不是经测试得出的最佳阈值。
RRF 融合的 k 为 60;五条召回分支的权重分别是精准匹配 3.0、Anchor 2.8、严格词法 1.7、宽松词法 0.9、向量 1.0。之后会叠加查询信号匹配权重。首版没有额外的独立 Reranker 模型 :rerank() 是基于词项覆盖率和精准数值、日期、型号信号的确定性轻量重排。这是低内存设备上的有意取舍,不能称作 Cross-Encoder 实测重排。
证据预算也有具体边界: PMContextBuilder.build() 默认 tokenBudget = 2048、最多 8 个片段、每份知识最多 3 个片段,按可用预算和剩余位置分配内容长度,并清理易变 UI 元数据。这里的 Token 计算是混合文字的保守字符近似,不是模型实际 Tokenizer 的精确计数。
引用并非只靠提示词: PMGroundedResponseParser.parse() 接受允许的 chunk_id 集合;如果模型返回 ANSWER/PARTIAL 但没有有效引用或包含不在集合里的引用,会退回 NOT_FOUND。这个检查能阻止伪造来源 ID,但不能证明答案对原文的理解在语义上一定正确。
源码核验的边界:尚未验证 Android、Windows、macOS 与 iOS 的真实行为一致性;也没有完成真实设备的 FTS-only、Vector-only、Fusion-only、Fusion+规则重排四组对照,因此本文只作代码证据支持的工程实践分析,不称"性能实测"。
源码仓库还包含 Tests/PMRetrievalCoreTests.swift 与 Tests/Fixtures/rag_acceptance.json:前者为分词、余弦相似度、阈值和 Recall 计算设计了单元测试;后者列出中文、英文、跨语言、OCR 错字、长 PDF、数字、日期、版本及无答案场景等 11 条测试问题定义 。这些文件说明项目已有验收设计,不等于这些测试已在本次运行通过,也不构成真实用户语料的统计性能证据。
应该怎样证明"混合检索更有用"
在正式称为"实测"之前,至少建立四组对照:FTS-only、Vector-only、Fusion-only、Fusion + Rerank。测试题要包含精确字符串、同义表达、跨语言问答、否定、相似文件冲突以及答案不存在的情况;切块、资料集、设备和模型版本需保持一致。
建议记录 Recall@k、MRR 或 nDCG 等检索质量指标,以及证据引用准确率、无答案时正确拒答率、P50/P95 查询延迟、峰值内存和导入至可检索耗时。每一项都应保留原始运行记录和复现条件,不能用 GPT 解释图代替。
选择建议:什么时候反而不需要混合检索
如果资料只有几十条、用户只按准确字段搜索,可靠的全文索引可能更简单、更稳定;如果文档是短篇主题段落、查询措辞多变且不要求精确定位,向量检索可以作为主要召回路径。只有在多种文件、语言和查询类型混合、且需要可验证来源时,双路召回和重排的工程复杂度才更有理由被接受。
最终判断:个人 AI 知识库不应把"有一个向量数据库"误当成"能可靠回答私人资料"。真正的质量链路是:原件可靠保存 → 解析可见 → 精确与语义两路寻找候选 → 融合与去重 → 证据筛选 → 受约束生成 → 可回溯引用。架构合理性是起点,真实用户数据与设备实测才是最终验收。
参考资料与说明
- SQLite FTS5 官方文档:查询、BM25 排名、片段与高亮。
- Cormack 等,Reciprocal Rank Fusion,SIGIR 2009:排名融合方法的原始论文。
- XBSTACK Personal AI Agent 架构:本站已记录的系统设计背景,本文另有 iOS 当前源码静态核验。
- XBSTACK Agent Memory 系统:与长期记忆、任务状态的区别。
原文(含源码核验边界与相关资料):www.xbstack.com/ai/recalai-...
相关阅读:
说明:本篇基于 RecalAI iOS 代码静态检查,非跨设备性能实测;不存在已验证的性能提升百分比。