最近核验:2026-10-09。以下是教学选型思路,不是 Twitter / X 的配置清单,也不是某个工具的性能排名。

不要从“我们应该用什么模型”开始

沿用信息流设计题的虚构社区。先问:最缺的是找不到内容、找到了却排不好,还是新内容迟迟进不来?这三件事,换同一个组件未必都管用。

这里有 2 个层次:逻辑组件负责什么,具体用什么实现。 “向量召回”是职责;用精确扫描、HNSW 还是 IVF-PQ,是实现选择。PyTorch、Faiss、数据库也不在同一个抽象层。

1 · 用户和内容用什么编码?

先代入两个虚构场景:

同样是内容推荐 先试什么 为什么,以及什么时候换
内容库小、变化慢,团队还在验证需求 简单特征与精确搜索基线(baseline) 先把效果和错误看清;测到搜索成本确实成问题,再加近似索引
新内容不断进入,旧 ID 互动少,机器内存有限 内容表示、事件更新,以及精确搜索对照下的压缩索引实验 想改善新内容覆盖,但同时承担编码、更新和近似误差;是否划算要测

它们不是标准答案。比如小库也可能有很高的并发;内存紧也不代表一定要用 PQ。关键是把你这次的约束写出来,别让选型表替你思考。

可选实现 值得考虑的条件 要付出的代价 / 怎么检验
ID embedding + 小 MLP ID 有稳定重复行为,想先建立便宜基线 新 ID 缺少表示;按冷启动(cold start)和低频切片(slice)检查,别只看总体
文本 encoder + 结构化特征 内容文本有信息,希望利用描述迁移到新内容 文本清洗、截断、编码与重算成本;固定标签和候选(candidate)池,看新增语义有没有用
行为序列 encoder 行为顺序、近期变化可能有用 历史读取与计算更贵;对比打乱顺序、缩短历史和简单 pooling,验证是否真需要顺序
图像 / 多模态 encoder 文本确实漏掉图像中的信息 处理成本、缺失模态与缓存失效;遮掉图像再测,检查增量而不是只看中间特征漂亮

这些可以组合,不是互斥的“模型排行榜”。ID 和内容特征都能输入一个塔;序列建模也能只发生在用户侧。先说明缺什么信息,再解释为什么这个模块能补。

例如:如果内容塔(candidate tower)输入的标题本来就是空的,先补数据可能比换更大的文本模型有价值。如果序列打乱后结果没变,就还没有证据为昂贵的顺序建模买单。

2 · 索引怎么选,不只是问哪个最快?

先用同一批向量做精确检索(retrieval),留一份正确的 top-k 对照,再衡量近似方案。这个对照回答“索引有没有找回模型本来会选的东西”,不是“模型理解了用户”。

实现路线 什么时候拿来试 主要取舍
Flat 精确扫描 小规模、验证实现,或硬件吞吐足够时 不丢近邻,但扫描成本随库大小增长
HNSW 想试图搜索的延迟—召回折中 额外图结构占内存;搜索参数、构建时间和更新能力要一起测
IVF / IVF-PQ 想缩小搜索范围,或压缩存储 分区和量化可能丢精度;还要维护训练好的索引参数
已封装的向量服务 需要持久化、过滤、分片(sharding)和运行管理 多一层依赖与运维约束;仍需核对搜索语义与版本能力

具体支持哪些更新和删除操作,依实现而异;不能因为都叫 HNSW 就默认行为一样。Faiss 是向量检索库,不自动等于完整的分布式数据库。Faiss 索引类型 · 官方选型指南

测试至少放在一张图或表里:近邻找回率、p95/p99 延迟、内存、构建/更新时间。不要只报一个 QPS,然后略过数据维度、机器和过滤条件。

一个很常见的坑:训练用 cosine,索引用 inner product

对非零向量,cosine 是归一化后的点积(inner product):

$$\cos(q,v)=\frac{q^\top v}{\|q\|\|v\|}.$$

如果训练与检索没有采用一致的归一化规则,向量范数可能改变排序。向量维度完全匹配,查询也不会报错,结果却不是你以为的那个分数。Faiss 距离定义

用 $q=(1,0)$ 查两个内容向量 $A=(2,0)$、$B=(100,100)$:点积分别是 2、100,会把 B 放前面;cosine 分别是 1、$1/\sqrt{2}\approx0.707$,会把 A 放前面。B 只是更长,不是方向更接近。

也别反过来说“少归一化一步,排名一定变”。若内容向量已经都是单位向量,对同一条非零查询,只改查询的正比例缩放不会改变精确点积排序,只会缩放分数。但如果按绝对阈值过滤,或要跨查询比较分数,这个尺度仍然重要;要返回 cosine 数值,就把两侧都归一化。

检验方法很直接:拿几个固定向量,手算分数,再比较离线代码和线上路径。零向量、NaN、重复 ID 和稳定的 tie-break 也值得测。

3 · 召回之后,排序器还能选什么?

选项 主要多看了什么 为什么不一开始就上最重的
规则 / 线性模型 / 树模型 清楚定义的特征与组合 易做基线;能否表达任务需要的交互仍要检验
小 MLP / 多任务 ranker 用户—内容特征交互、多个行为目标 标签缺失、任务冲突、校准(calibration)和 loss 权重都需要处理
序列或联合编码模型 更细的历史—候选、文本—文本匹配 输入读取与交互计算更贵,适合先在小候选集检验增量

不是“越往下越好”。召回先缩小范围、排序再多花一些计算,是历史上已经存在的分工;具体阶段怎么划,要看你的工作量和目标。YouTube 2016 论文

排序器也不能凭空修复召回遗漏。反过来,召回集合已经包含足够多相关内容时,继续追求更大候选池可能只是在把成本转给下一层。

4 · 特征和表示在哪算?

位置 适合什么 容易漏掉什么
批处理 稳定特征、全量回填 新内容或编辑后的内容会等下一轮
事件驱动 / nearline 发布、编辑后尽快刷新表示 重复与乱序事件、失败重试、积压监控
请求时 online 只有这次请求才知道的信息 尾延迟、超时、特征缺失和降级(fallback)策略

这不是三选一。可以批量建立基础索引,事件更新处理变化,在线只补必要上下文。代价是多条路径必须对同一个字段有同一种解释。

5 · 合并、过滤和多样性别塞成一个黑盒

  • 合并与预算:先去重,保留全部来源。不同模型的原始分数别直接混排;可以验证统一打分、来源配额或 rank-based fusion。
  • 资格与权限:便宜的限制尽量提前处理,返回前再确认关键资格;内容被删除时,不能只等下一次向量回填。
  • 列表体验:作者上限、主题重复或探索预算属于列表选择。它们和单条相关性有关,但不是同一个问题。

过滤太晚可能让最终列表不足;盲目增加 overfetch 又会增加成本。应该记录每层淘汰数量,检查哪些来源、哪些人群最容易被淘空。

把选择写成一句能被推翻的话

别写:“采用先进的多模态推荐架构。”

可以写:“我们怀疑文本缺少某类视觉信息,先在固定候选池和标签协议下比较带图与不带图;只有相关性增量覆盖重算和存储成本,才考虑加入内容侧。”

这句话有观察、改动、对照和退出条件。别人能质疑它,也能接着做实验。

把一次选型走完,而不是只留一张表

假设教学服务的症状是“新帖子搜不到”。先抽取失败样本:原文存在,向量任务成功,但索引里没有对应版本;旧帖子检索和排序正常。此时换更强的 encoder,并不解决已定位的更新延迟。

我们先比较两个改法:缩短批处理间隔,或增加事件驱动更新。前者改动小,但会反复扫描,最坏等待仍受批次约束;后者能更快响应编辑,但要处理重复、乱序、积压和补偿。若团队规模小、更新需求也不急,批处理可能已经够用,不能因为 nearline 听起来更高级就选它。

验证时固定内容与 encoder,分别测“发布到可检索”的分布、漏更率、重复事件后的幂等性,以及编码/索引写入成本。设一个具体的 freshness 目标,再判断哪个方案满足它。上线后还要确认旧内容的查询延迟没有因频繁写入而恶化。

反过来,如果最新版本已经在索引中,精确搜索也把它排很低,就继续查训练信号和表示;如果精确搜索靠前而 ANN 找不到,再查索引参数。同一句“搜不到”,可以对应三种完全不同的改动。

自测

ANN 找回率很高,但用户相关性很低,先查哪里?

索引可能忠实找回了模型的错误近邻。先检查表示、训练信号和任务评估,不要把“近似精确搜索”当成“近似真实偏好”。

要更新帖子内容,只换数据库里的文本够吗?

不够。还要考虑对应向量、特征缓存、索引版本,以及旧结果多久失效。更新路径和允许的新鲜度(freshness)需要明确。

下一篇:从组件图到可以上线的请求链

本页术语 11
基线 baseline
用来比较新方法的参考方法或配置
冷启动 cold start
用户或内容缺少历史证据,模型只能靠先验
切片 slice
按内容或用户属性划分的子群体,用来检查平均值掩盖了什么
候选 candidate
召回阶段捞出来、等待精排挑选的内容
内容塔 candidate tower
双塔检索中把候选内容编码成可预计算向量的模型分支
检索 retrieval
从外部语料里找出相关内容
分片 sharding
把参数、梯度或优化器状态切开分给多张卡,每张只存其中一份
点积 inner product
两个向量对应分量相乘再求和,双塔的打分方式
校准 calibration
模型给出的置信度是否等于真实正确率
降级 fallback
主路径不可用时切换到较简单但语义明确的备用行为
新鲜度 freshness
内容产生到可被检索之间的延迟