链载Ai

标题: 通过源码对 RAGFlow 检索召回机制的分析 [打印本页]

作者: 链载Ai    时间: 昨天 21:10
标题: 通过源码对 RAGFlow 检索召回机制的分析

1. 引言

RAGFlow 是一个基于深度文档理解的开源 RAG(检索增强生成)引擎。接上文:关于 RAGFlow 项目中 RAG 技术的实现分析。本文将基于对 RAGFlow 源代码的分析,详细解析 RAGFlow 在检索召回(Retrieval)环节的实现机制。

2. RAGFlow 整体架构

根据 GitHub 仓库首页的介绍,RAGFlow 是一个"基于深度文档理解的开源 RAG 引擎",它提供了一个流线型的 RAG 工作流,结合大型语言模型(LLM)提供真实的问答能力,并通过各种复杂格式数据的引用支持回答。

RAGFlow 的核心特点包括:

3. 检索找回机制的源码分析

通过分析 RAGFlow 的源代码rag/nlp/search.pyrag/nlp/query.py等核心文件,来详细了解其检索召回机制的实现。

3.1 检索流程概述

RAGFlow 的检索流程主要包括以下几个步骤:

  1. 1. 查询处理与向量化
  2. 2. 混合检索(向量检索+全文检索)
  3. 3. 重排序与结果融合
  4. 4. 引用插入与来源追踪

3.2 查询处理与向量化

rag/nlp/query.py中,FulltextQueryer类负责处理用户查询,将其转换为可用于检索的形式:

defquestion(self, txt, tbl="qa", min_match:float=0.6):
txt = FulltextQueryer.add_space_between_eng_zh(txt)
txt = re.sub(
r"[ :|\\r\\n\\t,,。??/`!!&^%%()\\[\\]{}<>]+"," ",
rag_tokenizer.tradi2simp(rag_tokenizer.strQ2B(txt.lower())),
).strip()
otxt = txt
txt = FulltextQueryer.rmWWW(txt)
ifnotself.isChinese(txt):
txt = FulltextQueryer.rmWWW(txt)
tks = rag_tokenizer.tokenize(txt).split()
keywords = [tfortintksift]
tks_w =self.tw.weights(tks, preprocess=False)
# ...处理权重和同义词
returnMatchTextExpr(self.query_fields, query,100, {"minimum_should_match": min_match}), keywords

这段代码展示了 RAGFlow 如何处理用户查询:

  1. 1. 对查询文本进行预处理(添加英中间的空格、繁体转简体、全角转半角等)
  2. 2. 移除无关词(如疑问词)
  3. 3. 分词并提取关键词
  4. 4. 计算词权重
  5. 5. 添加同义词扩展
  6. 6. 构建匹配表达式

rag/nlp/search.py中,Dealer类的get_vector方法负责将查询文本转换为向量:

defget_vector(self, txt, emb_mdl, topk=10, similarity=0.1):
qv, _ = emb_mdl.encode_queries(txt)
shape = np.array(qv).shape
iflen(shape) >1:
raiseException(
f"Dealer.get_vector returned array's shape{shape}doesn't match expectation(exact one dimension).")
embedding_data = [get_float(v)forvinqv]
vector_column_name =f"q_{len(embedding_data)}_vec"
returnMatchDenseExpr(vector_column_name, embedding_data,'float','cosine', topk, {"similarity": similarity})

这段代码展示了如何使用嵌入模型将查询文本转换为向量,并创建用于向量匹配的表达式。

3.3 混合检索机制

RAGFlow 采用了混合检索策略,结合了向量检索和全文检索。在rag/nlp/search.pysearch方法中可以看到这一实现:

defsearch(self, req, idx_names:str|list[str], kb_ids:list[str], emb_mdl=None, highlight=False, rank_feature:dict|None=None):
# ...前置处理

ifnotqst:
# 处理无查询情况
# ...
else:
highlightFields = ["content_ltks","title_tks"]ifhighlightelse[]
matchText, keywords =self.qryr.question(qst, min_match=0.3)

ifemb_mdlisNone:
# 仅使用全文检索
matchExprs = [matchText]
res =self.dataStore.search(src, highlightFields, filters, matchExprs, orderBy, offset, limit, idx_names, kb_ids, rank_feature=rank_feature)
# ...
else:
# 混合检索:结合向量检索和全文检索
matchDense =self.get_vector(qst, emb_mdl, topk, req.get("similarity",0.1))
q_vec = matchDense.embedding_data
src.append(f"q_{len(q_vec)}_vec")
fusionExpr = FusionExpr("weighted_sum", topk, {"weights":"0.05, 0.95"})
matchExprs = [matchText, matchDense, fusionExpr]
res =self.dataStore.search(src, highlightFields, filters, matchExprs, orderBy, offset, limit, idx_names, kb_ids, rank_feature=rank_feature)
# ...

这段代码揭示了 RAGFlow 的混合检索策略:

  1. 1. 创建全文检索表达式matchText
  2. 2. 如果提供了嵌入模型,则创建向量检索表达式matchDense
  3. 3. 使用FusionExpr融合两种检索结果,权重分别为 0.05 和 0.95,表明向量检索在混合检索中占主导地位
  4. 4. 如果初次检索结果为空,会尝试降低匹配阈值进行二次检索

3.4 重排序机制

RAGFlow 的重排序机制是其检索找回流程中的关键环节,主要通过rerank函数实现。在rag/nlp/search.py中,rerank函数负责对初步检索结果进行多维度重排序:

defrerank(self, sres, query, tkweight=0.3,
vtweight=0.7, rank_feature:dict|None=None):
"""
对检索结果进行重排序

参数:
- sres: 搜索结果
- query: 查询文本
- tkweight: 词元相似度权重
- vtweight: 向量相似度权重
- rank_feature: 排序特征

返回:
- 重排序后的结果
"""
_, keywords =self.qryr.question(query)
vector_size =len(sres.query_vector)
vector_column =f"q_{vector_size}_vec"
zero_vector = [0.0] * vector_size
ins_embd = []

# 提取文档向量
forchunk_idinsres.ids:
vector = sres.field[chunk_id].get(vector_column, zero_vector)
ifisinstance(vector,str):
vector = [get_float(v)forvinvector.split("\t")]
ins_embd.append(vector)

ifnotins_embd:
return[], [], []

# 处理重要关键词
foriinsres.ids:
ifisinstance(sres.field[i].get("important_kwd", []),str):
sres.field[i]["important_kwd"] = [sres.field[i]["important_kwd"]]

# 提取文本特征
ins_tw = []
foriinsres.ids:
content_ltks =list(OrderedDict.fromkeys(sres.field[i]["field"].split()))
title_tks = [tfortinsres.field[i].get("title_tks","").split()ift]
question_tks = [tfortinsres.field[i].get("question_tks","").split()ift]
important_kwd = sres.field[i].get("important_kwd", [])

# 计算加权分数
tks = content_ltks + title_tks *2+ important_kwd *5+ question_tks *6
ins_tw.append(tks)

# 计算排序特征分数
rank_fea =self._rank_feature_scores(rank_feature, sres)

# 计算混合相似度
sim, tksim, vtsim =self.qryr.hybrid_similarity(
sres.query_vector,
ins_embd,
keywords,
ins_tw, tkweight, vtweight)

# 返回综合排序分数
returnsim + rank_fea, tksim, vtsim

这个函数展示了 RAGFlow 的重排序机制如何工作:

  1. 1.多维特征提取






欢迎光临 链载Ai (https://www.lianzai.com/) Powered by Discuz! X3.5