惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
人人都是产品经理
人人都是产品经理
IT之家
IT之家
T
The Blog of Author Tim Ferriss
V
V2EX
博客园 - 聂微东
The Cloudflare Blog
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
U
Unit 42
Vercel News
Vercel News
L
LangChain Blog
博客园 - 司徒正美
H
Help Net Security
Recent Announcements
Recent Announcements
Recorded Future
Recorded Future
V
Visual Studio Blog
Jina AI
Jina AI
Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
Y
Y Combinator Blog
C
Check Point Blog
博客园 - 三生石上(FineUI控件)
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
J
Java Code Geeks
The Register - Security
The Register - Security
The GitHub Blog
The GitHub Blog
B
Blog RSS Feed
F
Fortinet All Blogs
B
Blog
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
云风的 BLOG
云风的 BLOG
爱范儿
爱范儿
MongoDB | Blog
MongoDB | Blog
F
Full Disclosure
有赞技术团队
有赞技术团队
罗磊的独立博客
博客园_首页
MyScale Blog
MyScale Blog
aimingoo的专栏
aimingoo的专栏
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
N
Netflix TechBlog - Medium
Engineering at Meta
Engineering at Meta
量子位
I
InfoQ
小众软件
小众软件
P
Proofpoint News Feed

博客园 - 若-飞

企业AI Agent落地的核心逻辑与路径 基于langchain,Function Call的成功率怎么解决? LangChain Checkpoint(检查点)是什么?—— Agent 的"存档机制" RAG 设计:Embedding 如何切分 AI 客服系统设计:RAG 知识库设计 Go 百万连接服务器设计:从网卡到业务的全链路解析 深度解析 sync.Pool:从设计哲学到生产实践 Goroutine 泄漏:原因、检测与防范 Go Channel 关闭与超时机制完全指南 Go Map 无限增长问题解决方案 LangChain 聊天记录压缩:原理、机制与实战 揭开 sklearn 文本分类的核心原理:从词袋到逻辑回归 大模型“胡说八道”怎么办?一张图读懂检测、评估与修复全方案 企业级AI知识库权限隔离设计:让AI“懂规矩”比“懂知识”更重要 RAG系统设计全解析:从架构到多模态的核心知识图谱 RAG召回率提升全攻略:7大核心方法让检索更精准 RAG召回率提升秘籍:Metadata过滤的底层原理与实践 一文搞懂 RAG 中 Retriever 和 Reranker 的区别 一文搞懂 RAG 的召回率(Recall)是什么? LangChain / LangGraph、MCP、Harness Engineer 与 Claude Code 的对应关系 Agent Harness 技术笔记:从 Trajectory 到 Function Calling Loop BLEU 是什么?——从原理到工程实践 一文讲清:Approve / Permit / Permit2 的本质区别 分库分表后跨分页查询的完整方案 ai如何处理私有数据 ai幻觉是啥,以及如何解决 别再让大模型“凭空瞎猜”了!带你认识AI最强外挂:ChromaDB 用 useQuery 管请求:TanStack React Query 入门小结 HD钱包--BIP44 TRON 四种 API 面怎么选:从节点协议到 JSON-RPC 再到 TronGrid 以太坊节点存储与共识机制全解析 BSC节点发现协议全解析:UDP发现、Bootnode引导与Gossip交易广播 以太坊节点发现背后的分布式哈希表(DHT)与 Kademlia 原理解析 Solidity中的bytes与string:深入理解这两种特殊的动态数组 智能合约自毁:当资产还在,合约死了 —— 深度解析 selfdestruct 导致的资产锁定风险 TDengine CLI (taos) 使用指南 —— Docker 本地开发实战 在 macOS 上用 DBeaver 连接 TDengine:踩坑总结与最终配置指南 Solidity Storage Slot 深度解析 Geth Snapshot Export/Import 深度解析: 不是备份工具,而是数据分析利器 基于BSC 公链的数据备份与 Snapshot 机制深度解析 Docker 共享内存完全指南:从原理到实践,避免常见的理解误区 Docker容器"僵尸状态"问题排查与自动重启方案 SSE协议深度解析:被低估的HTTP服务器推送标准 TDengine vs MySQL:时序数据处理的时代之选 Proxmox 启用 QEMU Guest Agent 实战指南 解决 Blockscout "batch too large" 错误的完整指南 一文讲清楚什么是基准测试(Benchmark) Rust中的宏(Macro):编译时的代码生成魔法 Docker优雅关闭的艺术:为什么stop_grace_period能防止数据丢失 为什么 Go 没有依赖注入和 Bean 机制?语言设计哲学对比
构建更好的RAG系统:深入理解混合搜索
若-飞 · 2026-07-06 · via 博客园 - 若-飞

在构建检索增强生成(RAG)系统时,我们经常会遇到一个核心挑战:如何高效、准确地从海量知识库中检索出最相关的信息?

传统的向量搜索(语义搜索)虽然强大,但并非万能。今天,我想和大家深入探讨一种更强大的检索策略——混合搜索(Hybrid Search),它正在成为构建生产级RAG系统的关键组件。


为什么单一检索策略不够?

向量搜索的局限

向量搜索通过将文本转换为高维向量,能够捕捉语义相似性。但它在以下场景中表现不佳:

  • 精确关键词匹配:如产品型号“iPhone 15 Pro Max”

  • 罕见专有名词:如人名“埃隆·里夫·马斯克”

  • 特定短语:如法律条文中的精确表述

关键词搜索的局限

传统的BM25等关键词搜索擅长精确匹配,但:

  • 无法理解同义词(如“汽车”和“轿车”)

  • 无法捕捉上下文语义

  • 对拼写错误敏感


混合搜索:两全其美

混合搜索将语义搜索关键词搜索结合起来,通过智能融合机制,提供更全面、准确的检索结果。

核心架构

用户查询
    │
    ├───► 语义检索(向量搜索) ───┐
    │                              │
    └───► 关键词检索(BM25) ─────┼───► 结果融合 ──► 重排序 ──► 最终结果
                                   │
                                   └───► 融合算法(RRF/加权平均)

关键技术组件

1. 语义检索(向量检索)

使用嵌入模型(如OpenAI的text-embedding-3-small)将文本转换为向量,通过余弦相似度查找最相似的文档。

from sentence_transformers import SentenceTransformer
import numpy as np

model = SentenceTransformer('all-MiniLM-L6-v2')
query_vector = model.encode("什么是混合搜索?")
doc_vectors = model.encode(documents)
similarities = np.dot(query_vector, doc_vectors.T)

2. 关键词检索(BM25)

基于词频-逆文档频率(TF-IDF)的改进算法,考虑文档长度因素。

from rank_bm25 import BM25Okapi

tokenized_docs = [doc.split() for doc in documents]
bm25 = BM25Okapi(tokenized_docs)
scores = bm25.get_scores(query.split())

3. 结果融合策略

方法一:加权平均(Weighted Average)

# 归一化后加权求和
semantic_score = semantic_scores / max(semantic_scores)
keyword_score = keyword_scores / max(keyword_scores)

alpha = 0.7  # 语义权重
hybrid_score = alpha * semantic_score + (1 - alpha) * keyword_score

方法二:RRF(Reciprocal Rank Fusion)

def reciprocal_rank_fusion(ranked_lists, k=60):
    scores = {}
    for ranked_list in ranked_lists:
        for rank, doc_id in enumerate(ranked_list, 1):
            scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

方法三:学习排序(Learning to Rank)
使用机器学习模型学习最佳融合权重,适应特定领域数据。


实战演示:使用LlamaIndex实现混合搜索

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.vector_stores.elasticsearch import ElasticsearchVectorStore
from llama_index.core.retrievers import BM25Retriever
from llama_index.core.retrievers import RouterRetriever

# 1. 创建向量存储
vector_store = ElasticsearchVectorStore(
    index_name="hybrid_demo",
    es_url="http://localhost:9200"
)

# 2. 创建文档索引
documents = SimpleDirectoryReader("data").load_data()
vector_index = VectorStoreIndex.from_documents(
    documents, 
    vector_store=vector_store
)

# 3. 配置混合检索器
vector_retriever = vector_index.as_retriever(similarity_top_k=10)
bm25_retriever = BM25Retriever.from_documents(documents)

# 4. 融合检索结果
from llama_index.core.retrievers import FusionRetriever

hybrid_retriever = FusionRetriever(
    retrievers=[vector_retriever, bm25_retriever],
    mode="reciprocal_rerank"  # 使用RRF融合
)

# 5. 执行混合检索
results = hybrid_retriever.retrieve("什么是混合搜索?")

高级优化技巧

1. 分块策略优化

from llama_index.core.text_splitter import SentenceSplitter

# 使用语义感知的分块
splitter = SentenceSplitter(
    chunk_size=512,
    chunk_overlap=50,
    separator="。",  # 以句子为边界
)

2. 元数据过滤增强

# 在检索时添加元数据过滤
retriever = index.as_retriever(
    similarity_top_k=10,
    filters=MetadataFilters(
        filters=[
            ExactMatchFilter(key="category", value="技术文档"),
            RangeFilter(key="date", min_value="2024-01-01")
        ]
    )
)

3. 重排序(Re-ranking)

from llama_index.core.postprocessor import SentenceTransformerRerank

reranker = SentenceTransformerRerank(
    model="cross-encoder/ms-marco-MiniLM-L-6-v2",
    top_n=5
)

# 对混合搜索结果重排序
final_results = reranker.postprocess_nodes(results, query_str)