交互式 Embedding 原理实验室 — 理解向量空间、分片策略与检索范式
Embedding 是将文本映射到高维向量空间的过程。每段文本被转换为一个固定维度的数字向量(如 384 维),语义相似的文本在向量空间中距离更近。
这个过程是有损压缩——不管文本多长,最终都压缩成固定维度的向量。因此,文本内容的质量和纯度直接影响向量的表达能力。
两个向量之间的余弦相似度衡量它们方向的一致性(0=无关,1=完全相同)。试试下面的预设句子对:
或输入自定义句子(需加载浏览器模型,约 23MB):
本质上,Transformer 内部的 Q·K 注意力和 Embedding 检索中的 query·document 余弦相似度是同一个操作——在高维空间中做相似性匹配。区别在于:Attention 是模型内部的软检索(每层都在做),Embedding 检索是模型外部的硬检索(在知识库上做一次)。
向量被"拉扯"到多个语义簇的中间地带,谁都沾点边但都不精确匹配。
向量在空间中的位置"尖锐"明确,容易被精准召回。
正面和负面语义对冲,向量落在两个方向的折中位置。
同主题列表:强化信号。跨主题列表:等同于多主题混杂。
问题 → 问题
知识库存的是问题,用新问题匹配已有问题,再返回对应答案。典型相似度:0.85-0.95
问题 → 文档
知识库存的是文档/答案,用问题直接匹配文档。非对称匹配,典型相似度:0.50-0.70
文档 → 文档
用文档匹配文档,用于去重、聚类、相似推荐。对称匹配。
输入多段文本,实时看到它们在向量空间中的位置和相互间的相似度。
选择预设实验,观察不同分片策略下的 Embedding 分布和召回效果。
输入自定义 chunk,叠加到当前实验的散点图(需加载浏览器模型):
同一个 Query,在 Q2Q、Q2A、A2A 三种模式下的检索效果对比。
Bi-Encoder 是当前主流的 Embedding 模型架构。它的核心思想是:将 Query 和 Document 分别独立编码为向量,然后通过余弦相似度衡量语义相关性。两个编码器共享同一组参数(共享权重),这意味着同一个模型同时负责处理查询和文档。这种架构的优势是文档向量可以离线预计算并存入向量数据库,检索时只需编码一次 Query 然后做最近邻搜索,速度极快。
Embedding 模型通过三元组(Triplet)进行训练,每个三元组包含:一个查询(Query)、一个正例文档(Positive)和一个负例文档(Negative)。训练目标是让模型学会将 Query 的向量拉近 Positive,同时推远 Negative。例如:对于查询"怎么申请退款?",正例是退款流程文档,负例是物流查询文档。经过大量三元组训练后,模型学会了将语义相关的文本映射到向量空间中的相邻位置。
对比学习(Contrastive Learning)的损失函数驱动整个训练过程。每个 batch 中,模型计算 Query 与所有 Positive/Negative 的相似度,然后通过 InfoNCE Loss 使 Query-Positive 相似度最大化、Query-Negative 相似度最小化。左图展示了训练过程中向量空间的演变——随着训练推进,同类文本聚拢、异类文本分离;右图展示了 Loss 曲线的下降过程。
负例的选择对训练效果影响巨大。随机负例(左图)通常与 Query 毫不相关,模型很容易区分——训练信号弱,学不到细粒度的语义差异。难负例(Hard Negatives)(右图)是与 Query 表面相似但实际不相关的文档(如同主题但不同子问题),模型必须捕捉细微语义差别才能区分——训练信号强,学到的向量表示更精确。优质的训练数据应尽量使用难负例来提升模型的判别能力。
即使 Embedding 模型质量很高,检索仍然可能失败。理解失败模式是优化 RAG 系统的关键。以下是三种最常见的检索失败原因——语义稀释、语义鸿沟和否定陷阱。点击切换查看每种模式的具体表现。
在 RAG 系统中,Top-K(返回多少条结果)和相似度阈值(多低的分数可以接受)是两个关键参数。设得太高会引入噪声,设得太低会遗漏相关内容。理解相似度分数的分布特征,才能做出合理的参数选择。选择一个查询,观察其相似度分布:
Bi-Encoder 将 Query 和 Document 独立编码为向量,速度快(文档可预计算),但无法捕捉 Query 和 Document 之间的细粒度交互。Cross-Encoder 将 Query 和 Document 拼接后联合输入 Transformer,通过 Cross-Attention 捕捉每个 token 之间的交互关系,精度更高但速度慢(每对都要过一次模型)。因此实际应用采用 两阶段模式:先用 Bi-Encoder 快速召回 Top-N 候选,再用 Cross-Encoder(Reranker)对候选精排。
上方展示同一 Query 下,Bi-Encoder(余弦相似度)排序与 Cross-Encoder(相关性分数)排序的对比。注意观察排名变化——某些文档在 Bi-Encoder 中排名较低,但被 Cross-Encoder 提升到前列(因为联合编码捕捉到了更深层的语义关联)。这就是 Retrieve-then-Rerank 的核心价值:用快速粗排筛选候选,用精排模型修正排序。
HyDE(Hypothetical Document Embeddings)解决的核心问题是:用户提问和知识库文档之间存在天然的语义空间偏移——提问是"问题空间"的表达,文档是"答案空间"的表达,两者在向量空间中可能距离较远。HyDE 的做法是:先让 LLM 根据 Query 生成一个假想答案(不需要准确),然后用这个假想答案的 Embedding 去检索。因为假想答案和真实文档都属于"答案空间",它们在向量空间中更近。
关键洞察:假想答案不需要事实正确,只需要在文体和语义结构上接近真实文档即可。因为 Embedding 模型关注的是语义空间位置而非事实准确性。
上方散点图展示了 Query、假想答案和真实文档在向量空间中的位置关系。箭头从 Query 指向假想答案、再指向真实文档,直观展示了 HyDE 如何"桥接"问题空间和答案空间。柱状图对比了 Query→文档 的直接相似度与 假想答案→文档 的相似度——后者通常更高,因为假想答案已经被"转换"到了文档所在的语义空间。
稀疏检索(BM25)基于精确的词汇匹配——统计查询词在文档中出现的频率和稀有程度,适合精确关键词和专有名词。稠密检索(Embedding)基于语义匹配——即使查询和文档用词完全不同,只要语义相近就能匹配,适合口语化提问和同义改写。两种方法各有擅长场景,理解它们的差异是构建高质量检索系统的基础。
单独使用 BM25 或 Embedding 都会有盲区。混合检索通过融合两种排序来互补优缺点。RRF 是最常用的融合算法,其公式为:
RRF 只使用排名而非原始分数,因此不受 BM25 分数无界(0~20+)和余弦相似度有界(0~1)的尺度差异影响。参数 k=60 是原始论文推荐的常数,用于平滑排名差异。
上图叠加展示了 BM25 分数和 Embedding 余弦相似度的分布。注意 BM25 分数是无界的(通常 0~20+),而余弦相似度被限制在 0~1 之间。这种尺度差异意味着不能简单地将两个分数相加——BM25 的高分会"压制"Embedding 分数。这正是 RRF 使用排名而非原始分数进行融合的原因。
Embedding 模型的输入就是你的 chunk 文本——文本里的每一个字符都会变成 token 参与向量计算。JSON 括号、时间戳、页眉页脚、装饰符号……这些"噪声"都会占据有限的表示容量,稀释核心语义信号。下面通过 6 类常见噪声源,量化它们对检索相似度的真实影响。
检索系统的核心问题是:返回的结果排序够不够好?不同的评估指标从不同角度衡量排序质量。拖动下方文档改变排序,实时观察各指标的变化。
只关心第一个相关结果的位置。排在第1位=1.0,第2位=0.5,第3位=0.33…
支持多级相关度(0/1/2/3),高相关度排在前面得分更高,除以理想排序 (IDCG) 归一化到 0~1。
在每个相关文档位置计算 Precision@K 取平均。同时奖励数量多和排序靠前。
选择合适的 Embedding 模型是 RAG 系统的基础决策。模型的维度、语言支持、速度和精度各有权衡。通过下面的实验数据和对比表,帮助你做出明智的选择。
将同一模型(384维)的向量截断到不同维度,观察相似度的变化。这模拟了选择不同维度模型的效果。
实验使用 Query「」与 5 篇文档的相似度计算。
同一个意图,用不同风格表达,检索效果差异很大。关键词查询、口语化提问、书面查询——模型对哪种更友好?
根据你的场景选择合适的模型:
Bi-Encoder 把整段文本压缩成一个向量,信息损失大。Cross-Encoder 让 Query 和 Document 全交叉注意力,精度高但无法预计算。ColBERT 提出了折中方案——Late Interaction(延迟交互):分别编码 Query 和 Document 的每个 token,然后在 token 级别做匹配。
下方热力图展示 Query token 与 Document token 之间的逐对相似度。每行高亮的 cell 是该 query token 的 MaxSim(最佳匹配),所有 MaxSim 的均值即为 ColBERT 总分。
ColBERT 的 Token 级匹配能捕捉到 Bi-Encoder 遗漏的局部语义对齐。例如 Query 中的「退款」token 可以精确匹配到文档中的「退款」和「申请退款」,而 Bi-Encoder 只能依赖整个句子的平均语义。
RAG 系统的第一步是把文档切成 chunk。切法不同,检索效果天差地别。下面用同一篇文档、同一个 Query,对比四种常见分片策略的召回效果。
不同颜色代表不同分片策略。可以看到粒度越细的策略(如按句子分割)产生的点越分散,而固定长度切分的 chunk 可能跨越多个语义区域。
Chunk 被从文档中切出后,失去了文档级别的上下文信息。比如一个 chunk 说"金额将在3-5个工作日内退回",但不知道这是在说退款、工资还是退税。Contextual Retrieval 的核心思想是:在每个 chunk 前面加上一段由 LLM 生成的上下文摘要,让 chunk 自己"说清楚"自己是什么。
一个 384 维的 float32 向量占 1,536 字节。当知识库有百万文档时,仅向量就需要 ~1.5GB 内存。量化通过降低每个维度的精度来压缩向量,但会引入误差。关键问题是:精度损失多少才能接受?
下图展示不同量化精度的平均误差和排名相关性。注意 int8 的误差肉眼不可见,但从 int4 开始误差急剧上升——这就是"精度悬崖"。
高维向量的量化误差会在求和中抵消(中心极限定理)。维度越低,抵消效果越弱,量化损失越大。下图展示同一量化精度在不同维度下的误差变化。
前面所有的检索实验都默认了一件事:我们可以快速从数十万甚至数百万向量中找到最相似的那几条。但现实中,暴力遍历每一条向量(Flat Search)的计算量随数据规模线性增长,很快就不可行。近似最近邻(ANN)通过构建索引结构,用少量精度损失换取数量级的速度提升。
拖动滑杆改变知识库大小,观察暴力检索和 ANN 的延迟差异:
HNSW(Hierarchical Navigable Small World)是目前最流行的 ANN 算法。它在向量之间建立多层图结构——顶层是稀疏的"高速公路",底层是稠密的"本地道路"。检索时从顶层入口点出发,逐层向下跳跃,每层贪心地走向离目标最近的节点,直到底层找到候选集。
增大 efSearch 可以提升召回率,但也会增加延迟。下面模拟了不同 efSearch 值下的权衡曲线。拖动滑杆选择你的工作点:
不同场景适合不同的索引策略。理解它们的核心机制和权衡,才能选对方案:
在"模型训练"中我们了解了 Embedding 模型通过三元组(Query, Positive, Negative)训练。但在真实项目中,最大的挑战不是训练过程,而是获取高质量的训练数据。下面是四种最常见的数据来源,从零成本到高成本排列:
负样本的选择直接决定训练效果。下面展示了同一个 Query 在不同负样本策略下,相似度分数和模型学到的区分能力差异。注意观察正负样本之间的分数差(margin)——margin 越小,训练信号越强:
微调 Embedding 模型是一个成本不低的决策。用错了时机会浪费资源,用对了可以显著提升效果。根据以下条件判断是否需要微调:
Embedding 模型有固定的 max_length(通常 128~512 tokens)。超过这个长度的文本会被静默截断——尾部内容直接丢失,不会报错。这意味着如果关键信息在文档末尾,embedding 完全"看不到"它。
选择不同长度的文本,观察在不同截断长度下 embedding 与完整文本 embedding 的相似度。注意:本实验使用的模型 max_seq_length = 128 tokens。超过 128 tokens 的内容会被模型静默丢弃,因此 128 tokens 之后的曲线不会再变化——不是因为"几乎无损",而是因为模型根本看不到更多内容。
同一文本在不同截断长度下,对 3 个 query 的检索相似度变化。关注:当截断长度不够时,与某些 query 的相似度可能大幅下降。
"跨境订单配送要多久?"这个 query 的答案在文档末尾。当文档被截断到 128 tokens 时,跨境相关内容完全丢失。
微调能让 embedding 模型更好地理解你的领域术语和业务表述。但它有成本:需要标注数据、GPU 资源、重建所有向量。关键问题不是"能不能微调",而是 "值不值得微调"。
跟随下面的决策流程,判断你当前是否需要微调 Embedding 模型。
通用表述(如"怎么申请退款")在预训练模型上效果不错;但领域术语(如"RMA 流程"、"SLA 时效")的检索效果明显更差。微调后领域术语的检索效果显著提升。
多语言 Embedding 模型(如 multilingual-MiniLM)将不同语言映射到共享的向量空间。这意味着中文 query 可以直接检索英文文档,反之亦然——无需翻译。
相同语义的中英文 query 在向量空间中距离多近?下图展示语义等价的中英文 query 对之间的 cosine similarity。
选择查询方式,观察不同语言的 Query × Doc 检索效果。跨语言检索的精度略低于同语言,但仍保持较高水平。
中英文的 query 和 document 在向量空间中的分布。注意语义等价的中英文内容聚集在一起。
在 Playground 里跑通了检索,离生产上线还有很大距离。向量检索系统的核心工程问题不在于"能不能检索到",而在于数据变了怎么办、模型升级了怎么办、线上出问题怎么排查。
文档不是一次性导入就完事的。新增、修改、删除文档都需要更新索引。不同更新策略的复杂度和一致性保证差异很大:
当你升级 Embedding 模型时,新旧模型产生的向量处于不同的向量空间——即使是相同文本,不同模型的向量也不能直接比较。这意味着:
用旧模型编码的 query 去搜索新模型编码的文档,相似度分数没有意义。必须保证 query 和 document 用同一个模型。
升级模型后,对所有文档重新计算向量并重建索引。通过蓝绿切换实现零停机迁移。
从 384 维升级到 768 维,索引不能复用。存储、内存、检索延迟都会变化,需要重新规划容量。
在切换前用同一份测试集分别跑新旧模型,确认新模型在你的数据上确实更好,再执行迁移。
上线后最怕的是"悄悄变差"。以下指标帮你及时发现问题:
线上向量检索系统出问题时,选择你遇到的症状,跟随排查路径一步步定位根因:
生产中,知识库常有大量近似重复内容(如不同版本的文档、微调后的 FAQ)。重复 embed 相同内容既浪费算力,又让检索结果充斥冗余。缓存避免重复计算,去重清理冗余文档。
近似重复(措辞微调)vs 语义相关但不同的内容——cosine similarity 能区分它们吗?阈值设多高才不误杀有用内容?
调高阈值可以减少误判,但也会漏掉更多真正的重复。下图展示不同阈值下的去重效果。
假设 15% 的文档是重复的,使用 hash→embedding 缓存可以节省多少 embed 调用?
传统 Embedding 只处理文本。多模态模型(如 CLIP)将不同模态的数据映射到同一个向量空间,实现跨模态检索——用文字搜图片、用图片搜文字。
用文本 query 检索"图片描述"(模拟图文检索)。匹配的 query-图片对 vs 不匹配对的相似度差异有多大?
对角线是语义匹配的 query-图片对。理想情况下对角线应该最亮。
图片描述和文本 query 在向量空间中的分布。语义匹配的图文对应该聚集在一起。