利用混合搜索与重排序改进RAG检索效果(含代码示例)
RAG 在实际应用中,检索环节到底存在哪些“坑”?一个典型的场景是:精确匹配特定标识符(ID)。很多业务数据都带有唯一 ID,比如包含数字和字母的复杂组合,长度轻轻松松超过 10 个字符。这时候,如果只依赖基于向量的语义搜索(比如用 PGVector 存嵌入向量做相似性检索),结果往往差强人意。 语
RAG 在实际应用中,检索环节到底存在哪些“坑”?一个典型的场景是:精确匹配特定标识符(ID)。很多业务数据都带有唯一 ID,比如包含数字和字母的复杂组合,长度轻轻松松超过 10 个字符。这时候,如果只依赖基于向量的语义搜索(比如用 PGVector 存嵌入向量做相似性检索),结果往往差强人意。
语义搜索靠的是向量之间的软相似性来排序——计算余弦相似度,返回前 k 个最接近的文本块。处理语义相近的文本时确实好用,但碰上 ID 这种需要严格一致的活儿,就不灵了。举个具体例子:查询“1234567890XYZ”时,语义搜索可能把“1234567890ABC”排在前面,因为它俩在向量空间里距离不远;真正要的那个反而因为嵌入时的细微差异被挤到后面,甚至直接出局。这个问题在医疗记录查询(根据患者 ID 查病历)、金融交易追溯(按交易 ID 拿详情)等场景里,后果相当严重——检索结果错了,后续生成就全偏了。
怎么破?混合搜索是一条切实可行的路——把多种搜索技术组合起来,取长补短。具体分几步走:
基于 PGVector 的语义搜索
PGVector 是 PostgreSQL 里专门存向量和做相似性查询的扩展。第一步用它做语义搜索,能快速找到和查询语义相近的文本块。可以选一个合适的嵌入模型(比如 JinaAI 的“jina-embeddings-v2-base-en”),把文档和查询都转成向量,然后在数据库里高效检索。比如在新闻文章库里搜“科技行业最新动态”,PGVector 能迅速返回语义上相关的片段。但正如前面说的,它对精确 ID 匹配力不从心,所以需要其他搜索来补位。
PostgreSQL 全文搜索
这一步专门对付精确匹配和部分匹配。PostgreSQL 自带的全文搜索功能很强,正好弥补语义搜索的短板。
- 精确匹配:用
to_tsvector和plainto_tsquery函数,确保查询的 ID 在文本块里一个字符都不差地出现。比如查“1234567890XYZ”,to_tsvector('english', content) @@ plainto_tsquery('english', '1234567890XYZ')这条语句能在 documents 表的 content 字段里找到完全匹配的记录。 - 部分匹配:如果精确匹配没结果,就用
ILIKE操作符做模糊匹配,例如content ILIKE '%1234567890XYZ%'。这样能处理 ID 带拼写错误或格式变体的情况,尽量扩大召回范围。
合并结果
语义搜索和全文搜索的结果可能有重叠,需要去重。具体实现上,在 Python 里可以用集合或字典来合并,按文档 ID 或内容去重。合并后的集合既包含语义相关的,也包含文本精确匹配的,给后续重排序提供更全面的素材。
使用 Flash Re-Ranker 重排序
混合搜索拿到的结果,顺序不一定最优——最相关的可能排在后面。Flash Re-Ranker 就是干这个的:它用更复杂的算法,综合考虑语义、词汇匹配度、上下文等因素,对合并后的结果重新排序,把最相关的文本块推上前列。比如在产品描述库里搜特定产品 ID,它能把精确命中并且语义最匹配的描述排在最前面。
基于 LangChain 的实现
LangChain 这个框架很适合整合检索和文本处理流程。下面是一套完整的实现示例:
(一)基于 PGVector 的语义搜索实现
from langchain.vectorstores import PGVector
from jinaai import Embedding
# 初始化PGVector
vector_store = PGVector(
connection_string="postgresql://myuser:mypassword@localhost/mydb",
embedding_function=Embedding(model="jina-embeddings-v2-base-en")
)
# 执行语义搜索
query = "1234567890XYZ"
semantic_results = vector_store.similarity_search(query, k=10)
print(semantic_results)
代码中先用 PGVector 类创建向量存储对象,指定连接字符串和嵌入函数,然后用 similarity_search 方法做语义搜索,k 控制返回的结果数量。
(二)PostgreSQL 全文搜索实现
import psycopg2
# 定义自定义停用词
STOP_WORDS = {
"a", "an", "and", "are", "as", "at", "be", "but", "by", "for", "if",
"in", "into", "is", "it", "no", "not", "of", "on", "or", "such", "that",
"the", "their", "then", "there", "these", "they", "this", "to", "was",
"will", "with", "me", "my", "you", "your", "we", "our", "us", "he",
"him", "his", "she", "her", "hers", "it", "its", "them", "so", "too"
}
def filter_stop_words(query):
"""从输入查询中去除停用词。"""
words = query.split()
filtered_words = [word for word in words if word.lower() not in STOP_WORDS]
return " ".join(filtered_words) if filtered_words else query
def perform_full_text_search(query):
conn = psycopg2.connect("dbname=mydb user=myuser password=mypassword host=localhost")
cursor = conn.cursor()
filtered_query = filter_stop_words(query)
print(f"原始查询: {query}")
print(f"过滤后的查询(不含停用词): {filtered_query}")
# 精确匹配(过滤停用词后)
cursor.execute(
"SELECT * FROM documents WHERE to_tsvector('english', content) @@ plainto_tsquery('english', %s);",
(filtered_query,)
)
exact_results = cursor.fetchall()
# 部分匹配(ILIKE,不过滤停用词)
cursor.execute("SELECT * FROM documents WHERE content ILIKE %s;", (f"%{query}%",))
partial_results = cursor.fetchall()
cursor.close()
conn.close()
return exact_results + partial_results
query = "I want to see details of 1234567890XYZ"
retrieved_chunks = perform_full_text_search(query)
print("结果:", retrieved_chunks)
这段代码先定义停用词集合,写了一个过滤函数 filter_stop_words,然后 perform_full_text_search 函数里分别做精确匹配(过滤停用词后)和部分匹配(ILIKE),最后合并返回。
(三)合并和重排序结果
from flashrank import FlashRanker
def re_rank_results(semantic_results, text_results):
ranker = FlashRanker()
semantic_texts = [{"text": doc.page_content} for doc in semantic_results]
text_texts = [{"text": row[1]} for row in text_results] # 假设文本在第二列
combined_results = semantic_texts + text_texts
reranked_results = ranker.rank(combined_results)
return reranked_results
final_results = re_rank_results(semantic_results, retrieved_chunks)
print(final_results)
re_rank_results 函数提取语义和文本搜索的结果,合并后调用 Flash Re-Ranker 的 rank 方法完成重排序。
重要考虑因素
整个流程里有几个细节值得注意:
自定义停用词
全文搜索里停用词处理很关键。停用词是那些出现频率高但对检索没帮助的词(a、the、and 等)。自定义停用词列表可以根据场景灵活调整:科技文献里某些常用词可能很有意义,就需要移除;代码注释里则可能要把特殊符号加进去。合理的停用词配置能明显提升检索准确率。
PostgreSQL 配置
PostgreSQL 内置了多种语言的停用词列表,还支持创建自定义词典来实现更精细的处理。根据文本语言和应用场景选择合适的内置列表,或者建自定义词典来标记特殊词汇或做词形转换,能进一步优化全文搜索性能。
性能优化
去除停用词不仅能提高准确率,还能加快搜索速度——尤其是在处理大规模数据集时。去掉那些低频词汇后,数据库要处理的词数减少,索引也可以更小更高效。实际应用中需要根据数据集规模和特性,在停用词处理复杂度和性能提升之间做好平衡。
回到检索精度这个核心问题:通过 PGVector 语义搜索 + PostgreSQL 全文搜索 + Flash Re-Ranker 重排序的混合方案,能有效解决特定 ID 匹配不准确的老大难问题,让 RAG 系统在真实业务场景中跑得更稳、更准。
你是一名 AI 行业编辑,请围绕下面这条热点输出一份资讯解读:
热点:利用混合搜索与重排序改进RAG检索效果(含代码示例)要求:
1. 先用一句话解释这条热点在讲什么
2. 再总结它为什么重要
3. 说明会影响哪些 AI 产品或内容方向
4. 最后给出 3 个适合资讯站使用的标题
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
相关热点Dzine是一款强调构图控制与风格管理的AI图像设计工具,提供样式库、图层操作、定位和素描工具,支持文生图与图生图,具备生成填充编辑、一键修复增强及最高6144像素超高清导出功能,降低设计门槛,兼顾新手与专业用户。
3D虚拟空间的搭建,过去往往依赖专业建模软件和大量手动操作,技术门槛相当高。但现在,一款名为Arrival的云端SaaS解决方案正凭借AI与拖放功能,将这件事变得像搭积木一样轻松便捷。 什么是Arrival? Arrival本质上是一套专业的软件工具,核心目标就是帮助用户快速构建一个3D虚拟空间。它
ZENAI通过AI自动完成用户访谈,省去人工招募与主持流程,并自动总结用户场景、痛点及人物画像。产品经理、设计师、研究员可借此快速验证假设、提炼场景、获取市场洞察,加速产品市场契合度(PMF)达成,提供基础与专业两种套餐。
MeshcapadeMe基于SMPL人体模型技术,提供API接口支持图像、视频、测量及3D扫描输入,自动生成统一格式的逼真数字分身,无需专业建模技能即可将各类素材转化为可动画、跨平台使用的数字人类,适用于虚拟现实、游戏与影视等领域。
- 日榜
- 周榜
- 月榜
热点快看
