上一篇把建库与分布对齐讲完了:多参考图、clear / lowres 双版本、letterbox 同一套规则。索引侧准备好之后,查询侧要回答的是另一件事——在「纸品陈列审核 09 月批次」约三百个候选里,用哪些信号把 sku_101、sku_207 这类目标先捞出来,并让人看见依据,再复制检索键回 SaaS。
单通道向量检索在闭集里很快碰壁:同一批糊图,有时包装轮廓对但配色换季了,有时图义接近但规格区被挡,有时图完全救不了、要靠手打「12 卷」或别名里的片段。第一篇强调「缩小范围、给出证据」;本篇只谈召回层:每种典型失败模式配一条通路,每条通路独立产出有序候选 id 列表,不在此写融合公式——加权 RRF 与弱匹配降级见第 4 篇。
一、失败模式:先分类,再选通道
POC 里我们把「搜不到 / 排不对」先归成四类,再决定开哪些通道(与第一篇的非目标一致:查询热路径仍保持本地编码 + 可选文字,不做查询 VLM)。
| 失败模式 | 典型表现 | 更该信谁 |
|---|---|---|
| 结构不像 | 角度、裁切、局部遮挡导致轮廓对不上;换季前后包装布局相似但细节偏移 | 偏形状与布局的视觉结构通道 |
| 语义不像 | 轮廓勉强像,但色系、品类感、画面语义对不上(例如同系列不同规格摆在一起) | 偏图义对齐的跨模态视觉通道 |
| 要靠规格字 | 图糊到 OCR 不可靠,但标注员知道规格片段(卷数、克重、段数) | 字符与规范化匹配;可选文字→图 |
| 靠别名 | 主名称里 token 太泛,平台别名或 OCR 建档里有更区分性的写法 | 字符匹配 + 别名;文本语义通道作后续能力 |
四类不是互斥:一次查询可以同时开多条通路,各自给出排序,再由下一篇融合。业务上不追求「一个万能分数」,而是让每种失误都有专门的对症路径。
二、通道分工(阶段一为主)
以下命名与 POC 设计一致,便于和实现对照;公开模型名可直接写:DINOv2 负责结构、SigLIP 负责图义与文字→图、BGE 留给文本语义(阶段二再默认启用)。
| 通道 | 查询输入 | 索引侧匹配对象 | 阶段 |
|---|---|---|---|
| V1 视觉结构 | 查询图 → DINOv2 向量 | 各 SKU 多参考图、多版本(含 lowres)的 DINOv2 向量 | 一 |
| V2 图像语义 | 查询图 → SigLIP 图像向量 | 同上 SigLIP 图像向量 | 一 |
| T1 文字→图 | 用户文字 → SigLIP 文本向量 | SKU 参考图 SigLIP 图像向量 | 一 |
| T2 字符与别名 | 用户文字 | 名称按分隔 token、别名、建库 OCR 文本;精确 / 片段 / 模糊;数字与单位规范化 | 一 |
| T3 文本语义 | 用户文字 → BGE 向量 | SKU 聚合可搜文本(含离线建档描述) | 二 |
说明几条边界:
- 兜底 SKU 不参与各通道排序,只在产品层固定展示;正常候选都在当前批次闭集内算。
- 某 SKU 缺某路索引(例如尚无 VLM 建档句)不惩罚,该通道只是跳过该条特征,不拉低其它通道。
- 查询图 OCR 在百像素级截图上噪声大,POC 里不作为一等通道;需要字时优先标注员输入,与第一篇一致。
- T3 在阶段一可不参与默认融合,但索引里可以先行写入,避免日后加通道要重导全库。
场景化直觉
sku_101:端架局部图,结构通道若因裁切吃亏,图义通道有时仍能把同系列拉进前列;若两路都弱,手打包装上的规格 token 往往由 T2 救场。sku_207:糊图里规格区不可读,但别名或名称里带区分性片段时,T2 可以单独把排名拉起来——这正是「失败模式不同,通路不同」要保留多条路的原因。
三、输入模式:没输入就关通道
查询约定:图片与文字至少一项;批次由页面当前选中闭集决定。
| 输入模式 | 关闭的通道 | 仍开启的通道 |
|---|---|---|
| 仅图片 | T1、T2、T3(及依赖文字的后续能力) | V1、V2 |
| 仅文字 | V1、V2 | T1、T2;(阶段二)T3 |
| 图文都有 | 无因「缺输入」而关的通道 | 全部已实现的通道 |
实现上不要在「仅图」时仍跑空文字向量,也不要在「仅文」时伪造一张黑图去骗视觉编码器——无输入即返回空列表,下游融合按「该通道未参与」处理(细节在第 4 篇)。
四、多参考图:SKU 内取 max,并记下命中图
第 2 篇已约定:同一 SKU 下标准图、SaaS 参考图、确认回流图,以及 clear / lowres 等版本,各自有向量。检索时不以单张图代表 SKU,而是:
- 对该 SKU 在某一通道下,遍历所有可用参考图与版本,算相似度或匹配分。
- 取最大值作为该 SKU 在此通道的得分。
- 记录得分来自哪张参考图、哪个版本——UI 上「为什么在这里」要能指向具体证据图,而不是只显示一个抽象分数。
这与建库侧的分布对齐是同一套故事:lowres 版本常常拉高糊查询在 V1/V2 上的 max,而 clear 版本在字符或建档文本上仍可能更有用。聚合在 SKU 维度,比较在「该 SKU 最强的一张图」维度。
五、通道接口:只产出有序 id 列表
融合层需要一种稳定契约:每个通道只负责在当前批次候选 id 上排序,返回降序列表;不负责跨通道算最终名次。
from typing import Protocol
class RecallChannel(Protocol):
name: str
def rank(self, query: object, candidate_ids: list[str]) -> list[str]:
"""返回按相关度降序的候选 id;无输入时应返回空列表。"""
...
工程上 query 可携带裁剪后的图张量、用户文字、批次 id 等;candidate_ids 即闭集内待排 SKU 标识(与业务主键一致)。单测可以对固定小批次断言:给定输入模式,某通道是否应为空、max 聚合是否选对参考图 id——仍不必在此引入 RRF。
一次搜索的典型数据流可以概括为:
闭集 candidate_ids
→ 各 RecallChannel.rank → channel_name → ordered list[id]
→ (第 4 篇)融合 + 弱匹配状态 + 兜底区展示
六、召回之后才是融合
本篇停在「通道 → 有序 list[id]」。多条路并行、等权还是调权、弱匹配如何提示,都属于加权 RRF:多通道怎么融、弱匹配怎么降级——那里会写 K、权重表与按输入禁用通道的规则,此处不重复公式。
调效果时建议顺序仍与第 2 篇衔接:先确认 letterbox 与 lowres 进索引 → 再看多参考图覆盖率与各通道是否误关 → 最后才怀疑 backbone 不够大。闭集三百候选里,多通路对症往往比「换一个更大的单向量模型」更划算。
本系列
- 闭集多模态检索:为什么不是再做一个 RAG
- 多模态检索建库:分布对齐比换模型更重要
- 多通道召回:每种失败模式配一条检索路径
- 加权 RRF:多通道怎么融、弱匹配怎么降级
- 人机闭环:确认如何把检索变成可迭代资产
- 闭集检索评测与「刻意不做」清单