词向量 / 嵌入Embedding
RAG基础
一句话解释
就像把一句话『hash 到一个 1536 维的空间』——只是这个 hash 不再追求"碰撞越少越好",而是追求"语义越近的句子坐标越接近"。两个向量的余弦距离就是它们的"语义相似度"。
它解决什么问题
传统全文搜索(grep、ElasticSearch)只能匹配"字面",搜"汽车"找不到"轿车",搜"如何省钱"找不到"理财技巧"。Embedding 把语义编码成数值向量后,"找意思相近的文档"就变成了"找坐标相近的点"——一个数据库问题。这是整个 RAG(Retrieval-Augmented Generation)体系的地基。
工作机制(直觉版)
训练时用大量"句子对+相似/不相似标签",让模型学到一个映射 f(text) → vector,使得"语义相近 → 向量靠近"。常见维度是 384 / 768 / 1536 / 3072。用的时候只需一次 API 调用就把任意字符串变成向量。
# 直觉演示:相似度 ≈ 向量夹角的余弦
"猫喜欢吃鱼" → [0.12, -0.34, 0.88, ...] ┐
"我家猫爱吃鱼罐头" → [0.15, -0.30, 0.91, ...] ├ 这两条夹角很小 ⇒ 相似度 ≈ 0.92
"利率上调影响楼市" → [0.71, 0.05, -0.42, ...] ┘ 与上面夹角大 ⇒ 相似度 ≈ 0.08
类比:Word2Vec 那个经典例子——king - man + woman ≈ queen。语义关系被编码成了向量的方向。
代码示例
from openai import OpenAI
import numpy as np
client = OpenAI()
def embed(text):
# 一行调用:字符串 → 1536 维向量
r = client.embeddings.create(model="text-embedding-3-small", input=text)
return np.array(r.data[0].embedding)
def cos_sim(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
a = embed("如何控制孩子玩手机的时间")
b = embed("管理儿童屏幕使用时长的方法")
c = embed("美联储加息对股市的影响")
print(cos_sim(a, b)) # ~0.85 高
print(cos_sim(a, c)) # ~0.12 低
常见误区
Embedding ≠ "理解"。它编码的是"统计上常一起出现的语义模式",所以会把"赞美 X"和"骂 X"判为相似(都是讨论 X)。做 RAG 时如果发现召回的内容"主题对了但立场反了",往往是 embedding 的天然局限,需要 re-ranking 或加分类器二次过滤——而不是换 embedding 模型就能解决。
实践场景
📌 经典:构建"按语义搜索的内部知识库",员工搜"年假怎么请"也能找到标题叫"休假管理制度"的文档。
👩💼 你的场景:把你过去三年的微信收藏/Notes 全部 embedding 入库,将来想找"曾经看过的关于复利的那篇文章",模糊描述就能召回。
English Summary
An embedding maps text into a high-dimensional vector such that semantically similar texts land near each other. It turns "find similar meaning" into a geometry problem — typically cosine similarity between vectors — and is the foundation layer of every modern semantic search and RAG system.
思考题
1. 为什么 embedding 维度不是越高越好?工程上 1536 vs 3072 怎么选?
高维带来三种代价:(a) 存储成本线性翻倍——千万级文档时差好几个 T;(b) 检索延迟变高,向量索引(HNSW、IVF)在高维下效率退化,"维度灾难"开始出现;(c) 边际收益递减,3072 维相比 1536 维在大多数任务上提升不到 2-3 个点。决策法则:先用小维度(如 384/768)跑 baseline,发现召回率确实差再升维。Matryoshka Embedding 是新趋势——训练时让前 N 维就能独立工作,使用时可按需截断维度,兼顾质量和成本。
2. Embedding 和 Day 1 学的 Transformer 内部的"token embedding"是同一回事吗?
同源不同用。Transformer 内部每个 token 都有一个 embedding(查表得到),那是"单词级"的,且每层 Attention 之后还会变化(contextual embedding)。我们说 RAG 里的 embedding 通常指"句子级/段落级"的,是把整段文本压成一个固定向量,通常取最后一层的 [CLS] token 或对所有 token 做 mean pooling。Sentence Transformers 和 OpenAI embedding API 就是专门为这个目的微调的——基础架构是 Transformer,但训练目标是"让相似句子向量靠近"。
3. 把代码当文本 embedding 进知识库,能直接做"语义搜代码"吗?
能但不够好。通用 embedding 在自然语言上训练为主,对代码的语义("这段是不是在做认证"、"是否是反序列化漏洞模式")召回率较弱。生产实践有三层方案:(a) 用专门的 code embedding 模型,如 voyage-code、jina-code-embeddings;(b) embed 前先用 LLM 给代码生成"功能摘要",embed 摘要而非代码本身;(c) 混合检索——代码字面用 BM25/AST,功能描述用 embedding,最后融合。GitHub Copilot 内部的检索就是混合策略。
4. 如果两段文本字面 99% 重复(如法律条款的两个版本),embedding 几乎相同,但用户其实想区分它们,怎么办?
这是 embedding 的盲区——它对"细微差异"不敏感。三种应对:(a) 检索阶段加入 diff 信号,对比两个版本的字符差异并提取出"差异片段"单独 embed;(b) chunking 粒度变细,让"修改的那一句"自成一个 chunk,与未修改部分分开;(c) 把 metadata(版本号、生效日期)入库做硬过滤,先靠 metadata 把候选缩到目标版本再做语义匹配。本质教训:embedding 适合"找相似",不适合"找区别"——做合规、版本对比这类任务要换思路。
5. 一家公司想"用 embedding 找潜在客户的相似企业"——这跟用 embedding 做搜索本质一样吗?商业上有什么需要注意?
技术上一样:把企业的"业务描述、行业、规模"拼成文本 embedding 后做最近邻。但商业上有三个坑:(a) 描述偏差——A 公司自我描述"AI 驱动的数据平台",B 公司只写"数据库厂商",embedding 会判它们不相似,其实可能是直接竞争对手,需要补充 SEC filings、官网爬取等多源信息;(b) 相似度 ≠ 可成交概率,相似企业可能是"已经被同类厂商覆盖的",反而是"低相似但具备某些信号"的更可能转化;(c) 隐私和合规——B2B 数据库要确认数据源合法(GDPR、CCPA)。embedding 是工具,业务决策仍需领域规则做后置筛选。
向量数据库Vector Database
RAG基础设施
一句话解释
就像把 MySQL 的 WHERE 子句从"=、LIKE"换成"按余弦距离 ORDER BY 相似度 LIMIT 10"——专门为"找最近的几百万个向量"做了索引优化的数据库。
它解决什么问题
有了 embedding 之后,"找最相似的 K 个文档"变成"在千万个 1536 维向量里算 cosine similarity 取 top-K"。暴力算每次都要 O(N) 次浮点运算,千万级别就要几秒——线上不可接受。向量数据库(Pinecone、Weaviate、Milvus、pgvector)用近似最近邻(ANN, Approximate Nearest Neighbor)索引把查询压到几毫秒。
工作机制(直觉版)
最常见的索引是 HNSW(Hierarchical Navigable Small World):把向量组织成多层图,上层稀疏只放"枢纽点",下层稠密放所有点。查询时先在上层快速跳到大致区域,再下沉到下层精细比对。类比 skip list 的多层指针。
# 传统 SQL # 向量 DB
SELECT * FROM docs collection.query(
WHERE category = 'finance' ←→ query_vector=embed(q),
ORDER BY title; filter={"category":"finance"},
top_k=10)
# 关键差别:
# 传统 DB 索引 = B+ Tree,按精确字段排序
# 向量 DB 索引 = HNSW/IVF,按"高维空间距离"近似排序
注意"近似"两个字——为了速度它不保证 100% 召回真正的 top-K,但通常 95%+ 召回足够日常使用。
代码示例
import chromadb
from openai import OpenAI
openai = OpenAI()
client = chromadb.Client()
col = client.create_collection("my_notes")
# 1) 写入:每条文本 + 自动 embedding + metadata
docs = ["复利是世界第八大奇迹", "屏幕时间影响儿童注意力", ...]
embeds = [openai.embeddings.create(model="text-embedding-3-small",
input=d).data[0].embedding for d in docs]
col.add(documents=docs, embeddings=embeds,
metadatas=[{"topic": "finance"}, {"topic": "parenting"}],
ids=["n1", "n2"])
# 2) 查询:自然语言 → 找出最相关的 K 条
q_emb = openai.embeddings.create(model="text-embedding-3-small",
input="如何让钱滚钱").data[0].embedding
hits = col.query(query_embeddings=[q_emb], n_results=3,
where={"topic": "finance"}) # metadata 过滤
print(hits["documents"]) # → ["复利是世界第八大奇迹", ...]
常见误区
"上来就要 Pinecone/Milvus"——错。十万条以内文档,用 SQLite + pgvector,甚至内存里一个 numpy 数组+ FAISS,完全够用且零运维。向量数据库的真正价值在亿级数据、低延迟、高 QPS、多租户隔离这些场景。早期项目盲目引入会把架构复杂度提前推到顶。MVP 阶段优先选嵌入式方案(Chroma、LanceDB、sqlite-vec)。
实践场景
📌 经典:客服 bot 的知识库,把所有 FAQ + 工单历史入库,用户问题 → 找相关条目 → 喂给 LLM 生成答案。
💰 你的场景:把所有研报、财报摘要 embedding 入库,做投资决策前用自然语言搜"过去关于半导体周期的判断"——避免你被遗忘的旧观点反复打脸。
English Summary
A vector database stores high-dimensional embeddings and supports approximate nearest-neighbor (ANN) queries in sub-millisecond time. It typically uses HNSW or IVF indexes, supports metadata filtering, and serves as the storage layer for RAG, semantic search and recommendation systems.
思考题
1. 向量数据库的"近似"召回会不会引入安全风险?比如法律 / 医疗场景能用吗?
会,但风险可控。HNSW 通常 95%+ 召回,意味着 5% 的查询可能漏掉真正最相近的条目。对"我国 2024 年关于 X 的最新法规"这种"必须返回唯一正确条目"的场景,召回率漂移可能导致漏返关键法条。对策:(a) 调高索引的 ef_search 参数牺牲速度换召回;(b) 关键场景用 exact search(暴力 brute force),数据量小时完全可行;(c) 混合检索 — 先用 keyword/metadata 精确过滤再做向量搜索。医疗、合规场景一般要求"可解释 + 可审计",所以会再叠加一层规则引擎做最终把关。
2. 把向量存进 PostgreSQL 的 pgvector 跟用专门的 Pinecone,本质差在哪?
三个维度差异:(a) 性能上限——pgvector 在千万级以下表现接近专业向量库,亿级以上需要 sharding,专业向量库为 distributed ANN 做了内核级优化;(b) 一致性模型——pgvector 享受 Postgres 的事务性(向量和业务数据同库强一致),专业向量库一般是最终一致;(c) 运维成本——pgvector 复用现有 Postgres 团队和监控,专业库要新引入一套依赖。决策法则:90% 的项目 pgvector 够用,10% 真正"向量 first"的产品(如百亿级图片搜索)才需要专业库。
3. 如果同一个文档"用户视角下被更新了"(如 wiki 改了一段话),怎么保持向量库同步?
这是 RAG 工程化最容易塌房的地方。常见模式:(a) 推模式——业务系统改文档时发事件到队列,consumer 重新 embedding + upsert 向量库;(b) 拉模式——定时(如每小时)扫描数据源的 updated_at 字段,找出 diff 再批量更新;(c) 版本号字段——每个 chunk 带一个 source_id + version,更新时 delete by source_id 再插新版。三者都要处理 "embedding API 限流 / 失败重试 / 部分成功" 的边界情况。监控指标重点:embedding lag(从源数据更新到向量库可查的时间)。
4. 向量数据库适合存"用户行为日志"做行为相似度匹配吗?
看场景。短期实时行为("刚刚浏览的 5 件商品")不适合 embedding——太短,语义信号弱,且 embedding API 成本会被高频日志放大;适合用传统协同过滤 + 倒排索引。长期画像(一年的购买/搜索历史)适合 embedding,可以把序列做摘要后 embed,得到"用户兴趣向量",用于跨品类推荐。坑:embedding 会"平滑"用户画像,让小众兴趣被淹没,长尾偏好会丢——所以推荐系统里 embedding 通常是"召回"通道之一,最终还要 ranking 模型再细判。
5. 把向量数据库当作 LLM 的"长期记忆"——这个比喻准确吗?局限在哪?
比喻直观但不完全准确。它更像"外挂硬盘 + 模糊搜索",而不是大脑里的记忆。两点本质差异:(a) 记忆有"自动遗忘 + 关联重构"机制,重要的事会被反复加强,不重要的衰减;向量库默认不会忘、也不会主动关联,需要工程上加 TTL、加 importance 字段、加 reflection 任务做汇总;(b) 人类记忆是 episodic(有时间、地点、情绪上下文)+ semantic(抽象概念)双层,向量库只编码语义相似度,时间/因果关系丢失。所以"long-term memory for agents"通常要叠加 graph + summarization + retrieval 三层,纯向量库只是其中一层。
检索策略Retrieval Strategies
RAG工程
一句话解释
就像写 SQL 查询要先 EXPLAIN:单纯"embedding + top-K"在简单场景能跑,但生产里要混搭 keyword 搜索、metadata 过滤、查询改写、分块策略,像调一个多层缓存命中率一样调出"召回 → 排序 → 生成"的整条流水线。
它解决什么问题
朴素 RAG 上线后第一个发现:模型答错的原因 80% 不是 LLM 不行,而是"根本没召回到正确文档"。这就是 Retrieval 策略要解决的:怎么切文档(chunking)?怎么写查询(query rewriting)?纯向量 + 关键词 + metadata 怎么混合(hybrid search)?多次检索还是一次到位(multi-hop)?这些都是为了把"我想问的问题"和"知识库里真正相关的那块"对齐。
工作机制(直觉版)
生产级 RAG 的典型 pipeline:
用户问题 q
↓ 查询改写(query rewriting)
用 LLM 把"上周那篇关于复利的笔记呢?"改成
"复利 投资 长期收益",更利于 embedding 召回
↓ 多路召回(hybrid retrieval)
① 向量召回 top 20 ─┐
② BM25 关键词 top 20 ─┼→ 取并集(约 30-40 条)
③ metadata 过滤 ─┘
↓ 重排序(re-ranking,下一节细讲)
用更精细的模型把 30-40 条排成 top 5
↓ 拼接进 prompt → LLM 生成答案
另一个关键设计是 chunking(切块):把长文档切成 200-800 token 的小块再 embedding。切得太大召回的内容噪音多,切得太小又会丢上下文。常见策略是"按语义边界切 + 相邻 chunk 留 50-100 token 的 overlap"。
代码示例
from langchain.retrievers import EnsembleRetriever, BM25Retriever
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
# 1) 准备向量召回 + BM25 召回两条管道
vec_retriever = Chroma(embedding_function=OpenAIEmbeddings()).as_retriever(k=10)
bm25_retriever = BM25Retriever.from_documents(docs, k=10)
# 2) Hybrid:加权融合两路结果(向量 0.6 + 关键词 0.4)
hybrid = EnsembleRetriever(
retrievers=[vec_retriever, bm25_retriever],
weights=[0.6, 0.4]
)
# 3) 查询改写:先让 LLM 把用户原话改成更"可搜索"的表述
def retrieve(user_question):
rewritten = llm.invoke(f"把这个问题改写为关键词搜索:{user_question}")
return hybrid.invoke(rewritten)
常见误区
"换更大的 embedding 模型 = 召回变好"。真相是:召回不准的瓶颈 80% 在 chunking 策略和查询改写,不在 embedding 模型。先评估自己的 retrieval 命中率(比如人工标 100 个 query 的"正确文档",看是否进 top-10),找出失败 case 的根因,再决定是改切块、加 hybrid、加 reranker,还是真的需要换 embedding。盲目升级 embedding 等于"换更快的 CPU 来解决数据库慢查询"。
实践场景
📌 经典:法律/医疗问答机器人,单一向量召回常常错过包含专业术语的关键条文,必须 hybrid + metadata 过滤。
👩💼 你的场景:你的工作笔记里既有"中文随笔"也有"英文术语",单语言 embedding 会 miss 跨语言相关内容——hybrid + 多语言 embedding 模型可以补漏。
English Summary
Retrieval strategies in RAG go beyond simple vector top-K: chunking, query rewriting, hybrid (dense + sparse) retrieval, metadata filtering, and multi-hop search are all tools to align "the question asked" with "the knowledge actually relevant". Most RAG failures trace back to retrieval, not generation.
思考题
1. 为什么单纯加大 top-K(比如从 5 提到 50)反而会让最终答案变差?
三个原因:(a) context 噪音——LLM 是"被动接受 context"的,更多无关文档会稀释注意力,让正确信息被冗余包围;(b) position bias——研究表明 LLM 对 context 中间位置的内容关注度最低("lost in the middle" 现象),top-K 越大越容易把关键文档塞进盲区;(c) 成本和延迟——50 个 chunk 拼出来可能 20K token,单次成本和延迟翻几倍。正确做法:保持小 K(5-10),通过 re-ranking 提高这小 K 的精度,而不是粗放扩大召回。
2. Chunking 的最佳大小有"通用值"吗?为什么 token 数不能一刀切?
没有通用值,要看任务和语料结构。规则之拇指:QA 类(短查询、精确答案)用 200-400 token 小 chunk;总结类(需要全局视角)用 800-1500 token 大 chunk;代码类按函数/类边界切而不是按 token 数;表格、列表要保持结构完整不能从中间切。更先进的做法是"语义 chunking"——用 embedding 相似度发现自然语义边界,但实现复杂。最实用的工程方法:先用固定大小(如 512 token+50 overlap)跑通,建立 retrieval 评估集,再针对失败 case 试不同切法 A/B 对比。
3. Hybrid retrieval 里 "BM25 + 向量" 各占多大权重?跟语料有什么关系?
看语料的"关键词决定性"程度。法律、医疗、学术——专有名词决定一切,BM25 权重要高(0.5-0.7);日常对话、产品评论——同义词多、表达灵活,向量权重要高(0.7-0.8);代码 + 文档混合——函数名、API 名要精确匹配(BM25),上下文解释要语义(向量),50:50 比较常见。更稳健的方法是把权重做成可学习的——用一个评估集,把"用户问题→正确文档"打标后用 grid search 或贝叶斯优化跑出最佳权重。注意 RRF(Reciprocal Rank Fusion)等基于排名的融合方式比加权分数更鲁棒,因为它不依赖两路分数的量纲对齐。
4. 跟 Day 3 的 ReAct 联系起来——Multi-hop retrieval 和 ReAct 有什么本质区别?
Multi-hop retrieval 是"用 LLM 在检索过程中规划下一步查什么",本质上是 ReAct 在"信息收集子任务"上的特化。例如问"和 OpenAI 的创始人创办的另一家公司同期成立的对手公司估值多少?",需要先查 OpenAI 创始人、再查这些人创办的另一家公司、再查竞争对手、再查估值——每一跳的检索 query 都依赖上一跳的结果。ReAct 是更通用的框架(工具不限于检索),而 Multi-hop retrieval 把"工具"窄化为"检索 API",循环也常被预设为 2-3 跳。生产中两者经常并存:Agent 用 ReAct 决策"现在该查文档还是该算数",查文档时内部又跑一次 multi-hop。
5. 站在产品视角,"召回准确率"和"用户满意度"为什么不总是正相关?
三种背离场景:(a) 用户问"复杂哲学题",正确文档其实没用——召回 100% 准也无法让答案满意,问题在生成端;(b) 用户问"今天天气",正确文档不存在——召回率定义为 0,但用户期待的是模型直接调天气 API 或承认不知道,应该走非 RAG 路径;(c) 用户问"有没有 X 的反对意见",召回到的全是正面观点也准但片面——这是召回多样性问题,需要 MMR(Maximum Marginal Relevance)等去重策略。教训:评估 RAG 不能只看 retrieval recall@K,要看端到端的 answer correctness 和 user satisfaction,关键问题分类后分通道处理。
重排序Re-ranking
RAG优化
一句话解释
就像两阶段招聘:第一轮 HR 用关键词海选 100 人(粗排),第二轮面试官精读简历挑出 5 人(精排)。Re-ranker 就是 RAG 流水线里的"面试官"——用更慢但更准的模型,把召回的 30-50 条精筛成最相关的 top 5。
它解决什么问题
Embedding 检索快但"粗糙"——它把整段话压成单一向量,丢失了细节。Re-ranker 反其道而行:把"查询 + 候选文档"成对喂给一个更精细的模型(通常是 cross-encoder),直接输出"这条文档跟查询的相关性分数"。算力代价大,但只对召回的几十条算,总成本可控。结果是 RAG 的"答案正确率"经常因为加一层 re-ranking 提升 10-20 个点。
工作机制(直觉版)
Embedding(bi-encoder)和 re-ranker(cross-encoder)的核心区别:
# Bi-encoder(embedding):query 和 doc 各自独立 embed
emb_q = encode(query) ─┐
emb_doc = encode(doc) ─┼→ cosine_similarity → 分数
# 优点:doc 可以预先 embed 入库,查询时只 embed query;O(1) 比较
# 缺点:query 和 doc 互不知道对方存在,细粒度匹配差
# Cross-encoder(re-ranker):query 和 doc 拼起来一起喂模型
score = model(f"[CLS] {query} [SEP] {doc}")
# 优点:模型每一层都能让 query 和 doc 的 token 互相 attend,匹配更准
# 缺点:每对都要跑一次模型,N×M 复杂度,无法全库扫
所以工程上是"两阶段":bi-encoder 快速从百万级粗筛到几十条,cross-encoder 在这几十条上精细排序。
代码示例
from sentence_transformers import CrossEncoder
import cohere # 或用 Cohere 托管的 reranker API
# 方案 A:本地 cross-encoder 模型(开源)
reranker = CrossEncoder("BAAI/bge-reranker-base")
query = "如何让孩子专注做作业"
candidates = [d1, d2, ..., d30] # 从向量库召回的 30 条
scores = reranker.predict([(query, d) for d in candidates])
top5 = sorted(zip(candidates, scores), key=lambda x: -x[1])[:5]
# 方案 B:托管 API(更省事)
co = cohere.Client()
result = co.rerank(query=query, documents=candidates,
top_n=5, model="rerank-multilingual-v3.0")
top5 = [r.document["text"] for r in result.results]
# top5 拼进 prompt,再交给 LLM 生成最终答案
常见误区
"用 LLM 直接判 30 条相关性"代替专门的 reranker——能跑,但费钱且慢。专门训练的 cross-encoder reranker(如 BGE-reranker、Cohere Rerank)参数量通常只有几亿,远小于 LLM,单次推理只要几十毫秒,且专门为"打分"训练,比让 LLM 兼职打分既准又快。除非你的 reranker 错误率明显高于业务容忍度,否则不要用 LLM 替代它。
实践场景
📌 经典:搜索引擎、推荐系统的"召回 → 精排"两段架构;GitHub 代码搜索也是这个思路。
💰 你的场景:投资研究助手——召回"过去 6 个月的相关研报"30 条,re-ranker 按"和当前问题最相关"重排,避免你被旧观点或泛泛而谈的报告淹没。
English Summary
Re-ranking is the second stage of a RAG pipeline: a cross-encoder model jointly scores each (query, document) pair to refine the top candidates from a fast first-stage retriever. It trades extra compute on a small set for substantially better precision at top-K — often the highest-ROI optimization in production RAG.
思考题
1. 既然 cross-encoder 更准,为什么不直接拿来做检索,省掉两阶段?
因为复杂度爆炸。Cross-encoder 必须把 query 和每个候选 doc 拼起来跑一次模型;一个有 100 万文档的库,单次查询要做 100 万次模型推理,单次响应得几分钟,成本也无法接受。Bi-encoder 把 doc 预先 embed 入库变成"O(1) 查询时只 embed query + ANN 查询",把 100 万规模查询压到 5ms。两阶段的本质是"用便宜的方法粗筛 + 用贵的方法精排",是任何大规模搜索系统(Google、Bing、Amazon)都在用的范式——传统搜索叫 L1/L2 排序,向量检索把它换了实现但思想不变。
2. Reranker 自己也会犯错,怎么评估它真的"赚了",没有破坏召回阶段的好结果?
构建带 ground-truth 的评估集是关键。最小可行评估:人工挑 50-100 个真实 query,每个标出"理想 top-3 文档"。然后对比两条 pipeline:(a) 只用 retriever 的 top-K,看 hit rate / MRR;(b) 加上 reranker 后的 top-K。指标关注 NDCG@5 和 Recall@5。常见反直觉:reranker 在 in-domain 数据上提升 15%,在 out-of-domain(不同语种、不同领域)上可能反而下降——因为 reranker 的训练分布偏移。所以上线 reranker 前一定要在自己业务数据上 A/B 验证,不能光看官方 benchmark。
3. 让 LLM 来做 reranker 听上去很合理(既灵活又通用),什么时候这是好选择?
四种情况 LLM-as-reranker 反而是优解:(a) 业务规则复杂——"按相关性 + 新鲜度 + 用户偏好综合排序",规则用自然语言描述给 LLM 比训一个 cross-encoder 简单;(b) 流量小(每天 < 千次查询),训练/部署专用 reranker 性价比低;(c) 多语言、多领域且无现成 cross-encoder 支持;(d) 需要给出排序原因(可解释性场景)。代价是:单次成本可能高 50-100 倍,延迟从 50ms 变成 1-2s。生产实践:流量大时还是用专用 reranker,只在长尾 query 或 fallback 路径用 LLM。
4. 跟 Day 2 的 RLHF 关系——Reranker 的训练数据从哪来,有没有类似的反馈循环?
Reranker 通常用对比学习:每条训练样本是 (query, positive_doc, negative_doc) 三元组,目标让模型给正例打高分、负例打低分。数据来源三种:(a) 人工标注的 query-doc 对(成本高但质量好);(b) MS-MARCO 等公开数据集(通用但领域偏移);(c) 线上点击日志当弱监督——用户点过的视作正例,曝光未点的视作负例。这就跟 RLHF 形成了"反馈闭环"——线上用户行为成为下一版 reranker 的训练信号。但有 selection bias:用户只能点曝光过的,没曝光的好文档永远不会被发现。解决方法叫 counterfactual learning to rank,引入随机曝光 + IPS 加权来打破偏差。
5. 如果一个查询本身就模糊(如"那个东西怎么办"),reranker 还能救场吗?
救不了多少。Reranker 的输入是 (query, doc) 配对,query 本身信息量低时,无论用多精细的模型都无法"想出用户真正想问什么"。这类查询的正确处理在更上游:(a) 多轮对话——先让 LLM 反问澄清,"你说的'那个'指的是上次提的复利还是房贷?";(b) 用户画像 + 会话历史——把过去 5 轮的话题拼进 query 再 embed;(c) Query expansion——用 LLM 把模糊问题改写成 3-5 个具体版本,每个都做检索后取并集。本质是"信息论极限"——查询里没有的信息,下游再聪明也补不出来;架构上要把澄清/扩展放在 reranker 之前。