同样RAG,换个Embedding召回率从62_飙升到89_
前两篇讲了RAG的核心原理和文档切分,这篇进入RAG的"心脏"——Embedding和向量数据库。
你可能觉得Embedding不就是调个API把文本转成向量嘛,选哪个都差不多。我之前也是这么想的,直到我在一个金融知识库项目里换了Embedding模型,检索准确率直接从62%涨到89%。同样的切分、同样的提示词、同样的模型,就换了个Embedding,效果天差地别。
Embedding模型决定了你的向量空间长什么样,向量数据库决定了你能不能高效地在这个空间里搜索。 这两个选对了,检索的天花板才够高。
Embedding是什么?30秒说清楚
Embedding就是把文本映射成一组数字(向量),语义相近的文本在向量空间里距离近,语义远的距离远。
<span><span leaf="">"苹果手机"</span></span><span leaf=""> → [0.12, -0.34, 0.56, ...] ← 跟下面距离近</span><span leaf=""><br></span><span><span leaf="">"iPhone"</span></span><span leaf=""> → [0.15, -0.31, 0.52, ...] ← 跟上面距离近</span><span leaf=""><br></span><span><span leaf="">"水果店"</span></span><span leaf=""> → [-0.23, 0.45, -0.12, ...] ← 跟上面距离远</span><span leaf=""><br></span>
RAG的检索就是:把用户问题转成向量,在向量空间里找距离最近的文档向量。Embedding模型的质量直接决定了"距离近"是否等于"语义相关"。
主流Embedding模型对比
英文为主的开源模型
| 模型
|
维度
|
最大长度
|
特点
|
适用场景
bge-large-en-v1.5
|
1024
|
512 tokens
|
英文最强开源
|
英文知识库
| |
e5-large-v2
|
1024
|
512 tokens
|
微软开源,多语言
|
通用英文
| |
nomic-embed-text
|
768
|
8192 tokens
|
超长上下文
|
长文档检索
|
中文为主的开源模型
| 模型
|
维度
|
最大长度
|
特点
|
适用场景
bge-m3
|
1024
|
8192 tokens
|
多语言、多功能、长上下文
| 中文首选推荐 | |
bge-large-zh-v1.5
|
1024
|
512 tokens
|
中文MTEB榜首
|
中文短文本
| |
gte-Qwen2
|
1536
|
32768 tokens
|
阿里开源,超长上下文
|
长文档中文
|
商用API模型
| 模型
|
维度
|
特点
|
价格
text-embedding-3-small
|
1536
|
性价比高
|
便宜
| |
text-embedding-3-large
|
3072
|
精度最高
|
贵
| |
Cohere embed-v3
|
1024
|
多语言好
|
中等
|
我的推荐
中文项目无脑选bge-m3。原因:
-
多语言:中英混排的文档也能处理,不用分语言建库
-
长上下文:8192 tokens,比bge-large-zh的512长了16倍
-
多功能:同时支持稠密检索、稀疏检索、多向量检索
-
免费开源:本地部署,数据不出境
<span><span leaf="">from</span></span><span leaf=""> langchain_community.embeddings </span><span><span leaf="">import</span></span><span leaf=""> HuggingFaceBgeEmbeddings</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">embedding = HuggingFaceBgeEmbeddings(</span><span leaf=""><br></span><span leaf=""> model_name=</span><span><span leaf="">"BAAI/bge-m3"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf=""> model_kwargs={</span><span><span leaf="">"device"</span></span><span leaf="">: </span><span><span leaf="">"cuda"</span></span><span leaf="">}, </span><span><span leaf=""># 有GPU用GPU,没有用cpu</span></span><span leaf=""><br></span><span leaf=""> encode_kwargs={</span><span><span leaf="">"normalize_embeddings"</span></span><span leaf="">: </span><span><span leaf="">True</span></span><span leaf="">}, </span><span><span leaf=""># 归一化,余弦相似度</span></span><span leaf=""><br></span><span leaf="">)</span><span leaf=""><br></span>
英文项目或追求极致方便:用OpenAI的text-embedding-3-small,调API就行。
<span><span leaf="">from</span></span><span leaf=""> langchain_openai </span><span><span leaf="">import</span></span><span leaf=""> OpenAIEmbeddings</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">embedding = OpenAIEmbeddings(model=</span><span><span leaf="">"text-embedding-3-small"</span></span><span leaf="">)</span><span leaf=""><br></span>
向量数据库选型:6个主流方案对比
| 数据库
|
类型
|
特点
|
适用场景
|
上手难度
| Chroma |
嵌入式
|
轻量、开箱即用、纯Python
|
开发测试、小规模
|
最低
| | FAISS |
内存库
|
Meta开源、速度极快、纯内存
|
大规模数据、不需要持久化
|
低
| | Milvus |
分布式
|
企业级、高性能、云原生
|
生产环境、大规模
|
中高
| | Qdrant |
独立服务
|
Rust实现、过滤能力强、轻量
|
需要元数据过滤
|
中
| | Weaviate |
独立服务
|
内置多模态、GraphQL API
|
多模态检索
|
中
| | pgvector |
PostgreSQL扩展
|
跟PG一体、运维简单
|
已有PG基础设施
|
低
|
我的选择建议
开发阶段:Chroma或FAISS
<span><span leaf=""># Chroma:最简单</span></span><span leaf=""><br></span><span><span leaf="">from</span></span><span leaf=""> langchain_community.vectorstores </span><span><span leaf="">import</span></span><span leaf=""> Chroma</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">vectorstore = Chroma.from_documents(</span><span leaf=""><br></span><span leaf=""> documents=chunks,</span><span leaf=""><br></span><span leaf=""> embedding=embedding,</span><span leaf=""><br></span><span leaf=""> persist_directory=</span><span><span leaf="">"./chroma_db"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">)</span><span leaf=""><br></span>
<span><span leaf=""># FAISS:最快</span></span><span leaf=""><br></span><span><span leaf="">from</span></span><span leaf=""> langchain_community.vectorstores </span><span><span leaf="">import</span></span><span leaf=""> FAISS</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">vectorstore = FAISS.from_documents(chunks, embedding)</span><span leaf=""><br></span><span leaf="">vectorstore.save_local(</span><span><span leaf="">"./faiss_db"</span></span><span leaf="">)</span><span leaf=""><br></span>
生产环境:Milvus或Qdrant
<span><span leaf=""># Milvus</span></span><span leaf=""><br></span><span><span leaf="">from</span></span><span leaf=""> langchain_community.vectorstores </span><span><span leaf="">import</span></span><span leaf=""> Milvus</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">vectorstore = Milvus.from_documents(</span><span leaf=""><br></span><span leaf=""> documents=chunks,</span><span leaf=""><br></span><span leaf=""> embedding=embedding,</span><span leaf=""><br></span><span leaf=""> connection_args={</span><span><span leaf="">"host"</span></span><span leaf="">: </span><span><span leaf="">"localhost"</span></span><span leaf="">, </span><span><span leaf="">"port"</span></span><span leaf="">: </span><span><span leaf="">"19530"</span></span><span leaf="">},</span><span leaf=""><br></span><span leaf=""> collection_name=</span><span><span leaf="">"knowledge_base"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">)</span><span leaf=""><br></span>
已有PostgreSQL:pgvector,不用额外部署新服务
Java类比:向量数据库选型就像你选缓存方案——开发阶段用HashMap或Caffeine(Chroma/FAISS),生产环境上Redis集群(Milvus/Qdrant),如果已经有了Redis就不折腾别的(pgvector)。别一上来就上Milvus,就像你不会在本地开发用Redis集群一样。
<span><span leaf="">from</span></span><span leaf=""> langchain_community.vectorstores </span><span><span leaf="">import</span></span><span leaf=""> PGVector</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">vectorstore = PGVector.from_documents(</span><span leaf=""><br></span><span leaf=""> documents=chunks,</span><span leaf=""><br></span><span leaf=""> embedding=embedding,</span><span leaf=""><br></span><span leaf=""> connection_string=</span><span><span leaf="">"postgresql://user:pass@localhost:5432/vectordb"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">)</span><span leaf=""><br></span>
向量检索的三种方式
1. 余弦相似度(最常用)
衡量两个向量方向的一致性,值域[-1, 1],1表示完全相同:
<span leaf="">results = vectorstore.similarity_search(</span><span leaf=""><br></span><span leaf=""> query=</span><span><span leaf="">"年假怎么申请"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf=""> k=</span><span><span leaf="">5</span></span><span leaf="">, </span><span><span leaf=""># 返回最相似的5个文档</span></span><span leaf=""><br></span><span leaf="">)</span><span leaf=""><br></span>
2. MMR(最大边际相关性)
兼顾相关性和多样性——避免返回5个内容几乎一样的chunk:
<span leaf="">results = vectorstore.max_marginal_relevance_search(</span><span leaf=""><br></span><span leaf=""> query=</span><span><span leaf="">"年假怎么申请"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf=""> k=</span><span><span leaf="">5</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf=""> fetch_k=</span><span><span leaf="">20</span></span><span leaf="">, </span><span><span leaf=""># 先取20个候选</span></span><span leaf=""><br></span><span leaf=""> lambda_mult=</span><span><span leaf="">0.5</span></span><span leaf="">, </span><span><span leaf=""># 0=最大多样性,1=最大相关性</span></span><span leaf=""><br></span><span leaf="">)</span><span leaf=""><br></span>
当你的检索结果重复度很高时,MMR特别管用。
3. 相似度+分数阈值
只返回相似度高于某个阈值的结果,过滤掉不太相关的:
<span leaf="">results = vectorstore.similarity_search_with_relevance_scores(</span><span leaf=""><br></span><span leaf=""> query=</span><span><span leaf="">"年假怎么申请"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf=""> k=</span><span><span leaf="">10</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf=""> score_threshold=</span><span><span leaf="">0.7</span></span><span leaf="">, </span><span><span leaf=""># 只返回分数>0.7的</span></span><span leaf=""><br></span><span leaf="">)</span><span leaf=""><br></span>
向量库的增量更新
知识库不是一成不变的,文档会更新、新增、删除。
新增文档
<span><span leaf=""># 加载新文档</span></span><span leaf=""><br></span><span leaf="">new_docs = loader.load()</span><span leaf=""><br></span><span leaf="">new_chunks = splitter.split_documents(new_docs)</span><span leaf=""><br></span><span leaf=""><br></span><span><span leaf=""># 追加到现有向量库</span></span><span leaf=""><br></span><span leaf="">vectorstore.add_documents(new_chunks)</span><span leaf=""><br></span>
删除文档
<span><span leaf=""># Chroma</span></span><span leaf=""><br></span><span leaf="">vectorstore._collection.delete(</span><span leaf=""><br></span><span leaf=""> where={</span><span><span leaf="">"source"</span></span><span leaf="">: </span><span><span leaf="">"old_policy.pdf"</span></span><span leaf="">} </span><span><span leaf=""># 按元数据删除</span></span><span leaf=""><br></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span><span leaf=""># Milvus</span></span><span leaf=""><br></span><span leaf="">vectorstore.delete(expr=</span><span><span leaf="">'source == "old_policy.pdf"'</span></span><span leaf="">)</span><span leaf=""><br></span>
生产环境的增量更新策略
不要每次更新都重建整个向量库,太慢了。推荐方案:
-
给每个文档分配唯一ID(如文件名的哈希值)
-
更新时:删旧版本的chunk → 加新版本的chunk
-
用定时任务扫描文档目录,自动检测变更
-
大规模更新时用批量写入(batch insert),别一条条加
我踩过的向量库坑
1. Embedding维度不一致
你换了Embedding模型,向量维度变了,旧的向量库就不能用了。建议在项目初期就确定好Embedding模型,后续不要换。如果必须换,就得重建整个向量库。
2. 没有做归一化
余弦相似度要求向量是归一化的。有些Embedding模型输出的向量没归一化,直接算余弦相似度结果不对。解决:在encode_kwargs里加"normalize_embeddings": True。
3. 中文Embedding用错了模型
用英文为主的Embedding(如text-embedding-ada-002)处理中文文档,检索效果惨不忍睹。中文项目一定要用bge-m3或bge-large-zh这类中文优化的模型。
4. FAISS持久化路径问题
FAISS保存和加载时路径要一致,而且它会生成多个文件(.faiss + .pkl),移动时别漏了。
本篇要点
| 要点
|
说明
Embedding本质
|
把文本映射成向量,语义近的距离近
| |
中文首选
|
bge-m3:多语言+长上下文+多功能+免费
| |
商用API
|
text-embedding-3-small:方便但要花钱
| |
向量库选型
|
开发用Chroma,生产用Milvus/Qdrant
| |
已有PG
|
pgvector,不额外部署
| |
检索方式
|
余弦相似度最常用,MMR去重,阈值过滤
| |
增量更新
|
文档哈希做差量检测,别全量重建
| |
维度一致
|
换Embedding模型必须重建向量库
|
下篇预告
下一篇讲RAG检索策略的进阶——混合检索(BM25+向量融合)和Rerank重排序。这是从"能用"到"好用"最关键的一步,也是目前生产环境RAG的标准配置。我会在代码里实测:纯向量 vs 混合检索 vs 混合+Rerank,三种方案的准确率对比。
你用的Embedding模型和向量库是什么?有没有踩过什么坑?评论区分享下。
觉得有用就点个在看,下一篇讲混合检索+Rerank——这是从"能用"到"好用"最关键的一步。
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/ai002/post/20260822/%E5%90%8C%E6%A0%B7RAG%E6%8D%A2%E4%B8%AAEmbedding%E5%8F%AC%E5%9B%9E%E7%8E%87%E4%BB%8E62_%E9%A3%99%E5%8D%87%E5%88%B089_/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com