教学架构 · 最近审阅:2026-10。下面的例子完全虚构,不描述任何公司的生产配置。

“用户点刷新”“作者改了帖子”“模型训练完了”都可能改变你看见的内容,但它们不是同一件事。把这 3 件事挤在一条长箭头里,很容易误以为每次请求都会训练模型、重新编码全库。

这一篇先不选模型。先把谁在什么时候做什么,以及结果交给谁讲清楚。

1 · 先按发生时间分开

路径 什么时候运行 产生什么 常见问题
一次刷新 · online 用户打开页面或请求下一屏 在时限内返回合规、有用的一组内容 候选(candidate)不足、服务响应慢、过滤出错
内容更新 · batch / nearline 发布、编辑、删除或定期刷新 较新的特征、向量与索引 旧事件覆盖新内容,删除没有及时生效
模型学习 · offline 一轮数据和实验准备好 新模型与能否发布的证据 标签错误、时间泄漏、只看整体指标

这里的 offline 是“不在这次请求的关键路径上”,不是“模型永远不更新”。nearline 也不是固定的秒数,而是异步响应变化;多快才算够,要由业务需求和成本一起决定。

内容变化后,用已发布的编码器重新计算向量,再更新索引。训练则会改变编码器参数,需要验证查询侧、内容侧和索引能否配套使用。在线请求读取这些准备好的部件,不会每次都重新训练。

2 · 用一条新帖子把 3 条线接起来

想象一个分享摄影和编程教程的小社区。一位作者刚发了“星空延时摄影”,读者随后打开首页。

  1. 作者发帖。 更新路径保存内容版本,生成可复用的表示,让它进入可搜索的集合。这不是为每个读者单独跑一次内容编码。
  2. 读者刷新。 系统结合当前上下文找候选。召回先缩小范围,排序再花更多计算比较,最后组成一屏;资格检查可能不止做一次。
  3. 读者真的看到了。 曝光(exposure)、位置和后续行为进入数据。未展示不是“不喜欢”,没动作也不一定是拒绝。
  4. 下一轮训练。 团队重新定义样本或目标、训练模型、比较新旧结果。通过验证后,再发布兼容的新部件,不直接把 checkpoint 扔给旧索引。

“先召回,再排序”是常见分工,TensorFlow Recommenders 的官方教程有一个可运行的基础例子。这里的社区与更新流程是教学设计,不是该教程的部署配置。

3 · 功能、模型和工程组件,不是同一层概念

你正在决定什么 例子 别和什么混淆
功能职责 找候选、预测行为、控制重复 一项职责不一定是一台服务
模型结构 双塔(dual-encoder)、序列 encoder、多任务 ranker “用了 Transformer”没有说明它放在哪一层
算法与数据结构 点积(inner product)、HNSW、IVF-PQ 近邻搜索准确,不代表用户偏好预测准确
工程实现 批处理任务、缓存、RPC、索引服务 用了某个框架,不等于已有可靠的完整系统

例如,Faiss 可以实现索引搜索,但不自动替你解决权限、事件乱序或发布回滚。先写清功能边界,再选库。索引实现的区别可以查 Faiss 的官方列表;具体的更新、删除和过滤能力要核对所选实现。

4 · 向量能对上维度,还不够

不是双方都输出 256 个数,就能接起来。每一条箭头至少要能回答:

  • 含义是什么? 这是候选 ID、查询向量,还是某个行为的概率?一个余弦分数不是概率。
  • 属于哪个版本? 用户塔(user tower)与内容索引是否在兼容的表示空间?预处理和归一化是否一致?
  • 什么时候有效? 内容编辑之后,旧特征最多能继续用多久?删除能否及时生效?
  • 失败怎么算? 返回空结果、超时和版本不兼容,不应该被记成同一种“没找到”。

例如,旧内容向量搭配新用户向量,点积仍然能算,但分数可能已失去原来的含义。此时效果下降,应该先查版本配套,而不是立刻重新训练。

5 · 改一个组件,会影响哪些地方?

别急着画一个更复杂的框。拿一个小变化做追踪:

变化 会影响哪里 第一项检查
换了内容 encoder 内容向量、查询兼容性、索引 两侧能否仍用同一种分数比较
召回多加一路 合并、去重、候选预算、后续打分成本 固定预算下是否补到独有相关内容
加大多样性(diversity)惩罚 列表选择,不一定改变模型参数 相关性与内容重复分别怎么变
换了训练标签 目标含义、数据覆盖、评估口径 旧指标还能看见新增信号吗

看架构图时,可以拿这些变化逐个追踪。能说清需要连带修改和检查哪些地方,比记住每个框的名字更有用。

用三个时间戳找一次错误

下面是虚构的排错记录。10:00 发帖,10:02 用户刷新,10:05 新版内容向量才进入索引。离线重放 10:02 的请求时,如果直接查“现在的最新特征”,就会拿到当时并不存在的向量。

你记录的时间 含义 这次例子
事件时间(event time) 内容或行为何时发生 10:00 发布
处理完成时间 编码任务何时完成 10:04
可查询时间 索引何时真的能返回它 10:05

因此,“10:02 没找到”可能是更新路径慢,而不是 encoder 不理解内容。先看各环节延迟和失败重试,再决定要不要换 encoder。离线构造训练特征时也一样:只用决策发生前已可用的信息,避免把未来信息带回来。

一个简单做法是保留可重放的索引/特征快照,以及请求所用的版本 ID。代价是存储和维护增加,所以不一定保存每秒全量副本;可以根据业务用周期快照加增量事件。但无论怎么存,都要能回答“当时系统究竟看到了什么”,不能用今天的数据替昨天解释。

自己走一遍

新帖子搜不到,先换更强的 ranker 吗?

先确认它是否进入可检索(retrieval)集合、编码与索引是否更新、资格检查是否通过。ranker 只能比较拿到的候选,不能弥补上游根本没交来的内容。

换了内容塔,但向量维度没变,可以直接沿用用户塔吗?

不能只凭维度判断。要有经过验证的兼容关系、固定样本对照和发布协议;否则看似正常的点积,可能已经不再表达训练时的关系。

接着读 01 · 一次刷新,把这套理解用到公开代码里。想直接动手,去 06 的向量实验或 05 的评估实验。

本页术语 7
候选 candidate
召回阶段捞出来、等待精排挑选的内容
曝光 exposure
内容真的被展示给用户这件事,和「被检索到」不是一回事
双塔 dual-encoder
用户和内容各一个编码器,映到同一向量空间靠内积召回
点积 inner product
两个向量对应分量相乘再求和,双塔的打分方式
用户塔 user tower
双塔检索中把用户信息编码成 query 向量的模型分支
多样性 diversity
结果之间在主题、来源或其他指定维度上有多大差异
检索 retrieval
从外部语料里找出相关内容