在构建高效的检索增强型生成(RAG)应用中,检索适当的块、节点或上下文是至关重要的。然而,基于向量或嵌入的搜索可能并不适用于所有类型的用户查询。
为了解决这个问题,混合搜索结合了基于关键词的方法(BM25)和向量(嵌入)搜索技术。混合搜索有一个特定的参数Alpha
,用于平衡关键词(BM25)和向量搜索在检索RAG应用正确上下文时的权重。(alpha=0.0 - 关键词搜索(BM25),alpha=1.0 - 向量搜索)
但这里有趣的是:微调Alpha不仅仅是一项任务;它是一种艺术形式。实现理想的平衡对于发挥混合搜索的全部潜力至关重要。这涉及到为您的RAG系统中的各种用户查询调整不同的Alpha值。
我们将探讨在Weaviate向量数据库中使用LlamaIndex的检索评估
模块,在有无重排器的帮助下,通过命中率和MRR指标来调整Alpha。
在深入实现之前,我们首先来理解本文将使用的不同查询类型和指标。
不同的用户查询类型:
RAG应用中的用户查询根据个人意图而变化。对于这些多样化的查询类型,微调Alpha
参数至关重要。这个过程涉及将每个用户查询路由到特定的Alpha
值,以实现有效的检索和响应合成。微软已经识别出各种用户查询类别,我们选择了一些来调整我们的混合搜索。以下是我们考虑的不同用户查询类型:
-
网页搜索查询: 类似于通常输入搜索引擎的简短查询。
-
概念寻求查询: 需要详细、多句子回答的抽象问题。
-
事实寻求查询: 具有单一、明确答案的查询。
-
关键词查询: 仅由关键标识符词组成的简洁查询。
-
带有拼写错误的查询: 包含错别字、置换和常见拼写错误的查询。
-
精确子字符串搜索: 与原始上下文中的子字符串完全匹配的查询。
让我们看看每种不同用户查询类型的示例:
-
网页搜索查询
Transfer capabilities of LLaMA language model to non-English languages
(LLaMA语言模型的转移能力到非英语语言) -
概念寻求查询
What is the dual-encoder architecture used in recent works on dense retrievers?
(什么是最近在密集检索器上使用的双编码器架构?) -
事实寻求查询
What is the total number of propositions the English Wikipedia dump is segmented into in FACTOID WIKI?
(在FACTOID WIKI中,英语维基百科转储被分割成多少个命题?) -
关键词查询
GTR retriever recall rate
(GTR检索器召回率) -
带有拼写错误的查询
What is the advntage of prposition retrieval over sentnce or passage retrieval?
(prposition检索相对于句子或段落检索的优势是什么?) -
精确子字符串搜索
first kwords for the GTR retriever. Finer-grained
(GTR检索器的首词。更细粒度)
检索评估指标:
我们将使用命中率和平均倒数排名(MRR)指标进行检索评估。让我们深入了解这些指标。
命中率:命中率衡量的是正确块/上下文出现在前k个结果块/上下文中的查询比例。简单来说,它评估了我们的系统在其前k个块中正确识别块的频率。
平均倒数排名(MRR):MRR通过考虑每个查询中排名最高的相关块/上下文的位置来评估系统的准确性。它计算所有查询中这些位置的倒数的平均值。例如,如果第一个相关块/上下文位于列表的顶部,其倒数排名为1。如果是第二项,则倒数排名变为1/2,并相应地继续这种模式。
这篇博客文章的其余部分分为两个主要部分:
-
实施不同查询类型的混合搜索中的
Alpha
调整。 -
分析两个不同文档数据集的结果显示:
-
索引单个文档: LLM编译器论文。
-
索引三个文档: LLM编译器、Llama Beyond English和Dense X检索论文。
您也可以从这一点开始继续在Google Colab笔记本中进行。
实施
我们将采取系统化的方法来实施实验工作流程,其中包括以下步骤:
- 下载数据
!wget --user-agent "Mozilla" "https://arxiv.org/pdf/2312.04511.pdf" -O "llm_compiler.pdf"``!wget --user-agent "Mozilla" "https://arxiv.org/pdf/2401.01055.pdf" -O "llama_beyond_english.pdf"``!wget --user-agent "Mozilla" "https://arxiv.org/pdf/2312.06648.pdf" -O "dense_x_retrieval.pdf"
- 加载数据
# 加载文档,我们将跳过论文中的参考文献和附录。``documents1 = load_documents("llm_compiler.pdf", 12)``documents2 = load_documents("dense_x_retrieval.pdf", 9)``documents3 = load_documents("llama_beyond_english.pdf", 7)`` ``# 创建节点``nodes1 = create_nodes(documents1)``nodes2 = create_nodes(documents2)``nodes3 = create_nodes(documents3)
- 设置Weaviate客户端
url ='cluster URL'# 集群URL``api_key ='your api key'# 你的API密钥`` ``client = get_weaviate_client(api_key, url)
- 创建索引并插入节点。
index = connect_index(client)`` ``insert_nodes_index(index, nodes1)
- 定义LLM
# 定义用于查询生成的LLM``llm = OpenAI(model='gpt-4', temperature=0.1)
- 创建合成查询
我们将按前面讨论的方式创建查询,检查笔记本中每种查询类型的提示,并展示每种类型查询的代码片段以供参考。
queries = generate_question_context_pairs(` `nodes,` `llm=llm,` `num_questions_per_chunk=2,` `qa_generate_prompt_tmpl=qa_template``)
- 定义重排器
reranker = CohereRerank(api_key=os.environ['COHERE_API_KEY'], top_n=4)
- 定义CustomRetriever
我们将定义CustomRetriever
类来执行有无重排器的检索操作。
classCustomRetriever(BaseRetriever):` `"""Custom retriever that performs hybrid search with and without reranker"""`` ``def__init__(` `self,` `vector_retriever: VectorIndexRetriever,` `reranker: CohereRerank` `) ->None:` `"""Init params."""`` ` `self._vector_retriever = vector_retriever` `self._reranker = reranker`` ``def_retrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:``"""Retrieve nodes given query."""` `retrieved_nodes = self._vector_retriever.retrieve(query_bundle)`` ` `if self._reranker != None:` `retrieved_nodes = self._reranker.postprocess_nodes(retrieved_nodes, query_bundle)` `else:` `retrieved_nodes = retrieved_nodes[:4]`` ` `return retrieved_nodes`` ``async def _aretrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:` `"""Asynchronously retrieve nodes given query."""`` ` `return self._retrieve(query_bundle)`` ``async def aretrieve(self, str_or_query_bundle: QueryType) -> List[NodeWithScore]:` `if isinstance(str_or_query_bundle, str):` `str_or_query_bundle = QueryBundle(str_or_query_bundle)` `return await self._aretrieve(str_or_query_bundle)
9. **定义检索评估和指标计算的函数** 我们将研究不同`alpha`值下有无重排器的检索器性能。
```python ``alpha_values = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]`` ``async def evaluate_retriever(alpha, dataset, reranker=None):` `retriever = VectorIndexRetriever(index,` `vector_store_query_mode="hybrid",` `similarity_top_k=10,` `alpha=alpha)` `custom_retriever = CustomRetriever(retriever,` `reranker)`` ` `retriever_evaluator = RetrieverEvaluator.from_metric_names(["mrr", "hit_rate"], retriever=custom_retriever)` `eval_results = await retriever_evaluator.aevaluate_dataset(dataset)` `return eval_results`` ``def calculate_metrics(eval_results):` `metric_dicts = []` `for eval_result in eval_results:` `metric_dict = eval_result.metric_vals_dict` `metric_dicts.append(metric_dict)`` ` `full_df = pd.DataFrame(metric_dicts)`` ` `hit_rate = full_df["hit_rate"].mean()` `mrr = full_df["mrr"].mean()` `return hit_rate, mrr
10. 检索评估
在这里,我们对不同查询类型(数据集)和Alpha值进行检索评估,以了解哪个Alpha值适合哪种查询类型。您需要相应地插入重排器,以计算有无重排器的检索评估。
asyncdefmain():` `results_df = pd.DataFrame(columns=['Dataset', 'Alpha', 'Hit Rate', 'MRR'])`` ``for dataset in datasets_single_document.keys():` `for alpha in alpha_values:` `eval_results =await evaluate_retriever(alpha, datasets_single_document[dataset])` `hit_rate, mrr = calculate_metrics(eval_results)` `new_row = pd.DataFrame({'Dataset': [dataset], 'Alpha': [alpha], 'Hit Rate': [hit_rate], 'MRR': [mrr]})` `results_df = pd.concat([results_df, new_row], ignore_index=True)`` ` `num_rows =len(datasets_single_document) //2+len(datasets_single_document) %2` `num_cols =2`` ` `fig, axes = plt.subplots(num_rows, num_cols, figsize=(12, num_rows *4), squeeze=False)`` ``for i, dataset inenumerate(datasets_single_document):` `ax = axes[i // num_cols, i % num_cols]` `dataset_df = results_df[results_df['Dataset'] == dataset]` `ax.plot(dataset_df['Alpha'], dataset_df['Hit Rate'], marker='o', label='Hit Rate')` `ax.plot(dataset_df['Alpha'], dataset_df['MRR'], marker='o', linestyle='--', label='MRR')` `ax.set_xlabel('Alpha')` `ax.set_ylabel('Metric Value')` `ax.set_title(f'{dataset}')` `ax.legend()` `ax.grid(True)`` ``iflen(datasets_single_document) % num_cols !=0:` `fig.delaxes(axes[-1, -1])`` ` `plt.tight_layout()` `plt.show()`` ``asyncio.run(main())
结果分析
完成实施阶段后,我们现在将注意力转向分析结果。我们进行了两组实验:一组针对单个文档,另一组针对多个文档。这些实验在alpha值、用户查询类型以及是否包含重排器方面有所不同。附带的图表显示了结果,重点关注命中率和MRR(平均倒数排名)作为检索评估指标。
请注意,以下观察结果特定于我们研究中使用的数据集。我们鼓励您使用自己的文档进行实验,并得出相关的观察和结论。
无重排器:
有重排器:
无重排器:
有重排器:
观察结果
-
使用重排器可以在单文档和多文档索引中提高命中率和MRR。一再证明,在您的RAG应用中使用重排器是非常有用的。
-
尽管大多数时候混合搜索胜过关键词/向量搜索,但应根据RAG应用中的用户查询仔细评估不同查询类型的搜索。
-
当您索引单个文档和多个文档时,行为是不同的,这表明随着向索引中添加文档,调整alpha总是更好的。
让我们更深入地分析不同类型的查询:
-
网页搜索查询:
-
无论有无重排器,无论单文档还是多文档索引,使用混合搜索(alpha=0.2/0.6)的MRR都更高。
-
无论有无重排器,在单文档和多文档索引中,使用alpha=1.0的命中率都更高。
-
概念寻求查询:
-
在多文档索引中,使用不同alpha值的混合搜索的MRR和命中率更高。
-
在单文档索引中,MRR和命中率在Alpha=0.0时更高,表明关键词搜索效果更好。需要注意的是,有无重排的MRR行为不同。
-
事实寻求查询:
-
在多文档索引中,无论有无重排器,使用混合搜索的MRR和命中率都更高。
-
在单文档索引中,使用重排器的混合搜索和无重排器的关键词搜索(alpha=0.0)的MRR和命中率更高。
-
关键词查询:
-
在多文档索引中,无论有无重排器,使用混合搜索的MRR和命中率都更高。
-
在单文档索引中,使用重排器的混合搜索和无重排器的关键词搜索的MRR和命中率更高(尽管alpha=0.2时MRR略高)。
-
带有拼写错误的查询:
-
无论有无重排器,在单文档和多文档索引中,使用混合搜索的MRR和命中率都更高。(尽管在某些情况下,使用alpha=1.0的混合搜索胜出)。
-
这也表明,向量搜索在处理拼写错误的查询时表现更好,因为关键词搜索在这种情况下会失去效果。
-
精确子字符串搜索:
-
在单文档索引中,无论有无重排器,使用关键词搜索的MRR和命中率更高,在多文档索引中,如果没有重排器,使用关键词搜索的MRR和命中率更高。
-
在多文档索引中,使用重排器的混合搜索(alpha=0.4)的MRR和命中率更高。
我们研究了混合搜索系统中Alpha的调整,针对一系列查询类型。看到索引单个文档或多个文档时结果的变化很有趣。
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。