当前位置: 首页 > news >正文

大模型高级 RAG 检索策略之流程与模块化

我们介绍了很多关于高级 RAG(Retrieval Augmented Generation)的检索策略,每一种策略就像是机器中的零部件,我们可以通过对这些零部件进行不同的组合,来实现不同的 RAG 功能,从而满足不同的需求。

今天我们就来介绍高级 RAG 检索中一些常见的 RAG 模块,以及如何通过流程的方式来组合这些模块,实现高级 RAG 检索功能。

RAG 模块化

模块化 RAG 提出了一种高度可扩展的范例,将 RAG 系统分为模块类型、模块和操作符的三层结构。每个模块类型代表 RAG 系统中的一个核心流程,包含多个功能模块。每个功能模块又包含多个特定的操作符。整个 RAG 系统变成了多个模块和相应操作符的排列组合,形成了我们所说的 RAG 流程。在流程中,每种模块类型可以选择不同的功能模块,并且在每个功能模块中可以选择一个或多个操作符。

图片

RAG 流程

RAG 流程是指在 RAG 系统中,从输入查询到输出生成文本的整个工作流程。这个流程通常涉及多个模块和操作符的协同工作,包括但不限于检索器、生成器以及可能的预处理和后处理模块。RAG 流程的设计旨在使得 LLM(大语言模型)能够在生成文本时利用外部知识库或文档集,从而提高回答的准确性和相关性。

RAG 推理阶段的流程一般分为以下几种模式:

  • Sequential: 线性流程,包括高级和简单的 RAG 范式

  • Conditional: 基于查询的关键词或语义选择不同的 RAG 路径

  • Branching: 包括多个并行分支,分为预检索和后检索的分支结构

  • Loop: 包括迭代、递归和自适应检索等多种循环结构

下图是 Loop 模式的 RAG 流程图:

图片

后面我们主要以 Sequential 模式为例,介绍如何通过模块化和流水线的方式来实现高级 RAG 检索功能。

代码示例

LlamaIndex[1]的查询流水线(Query Pipeline)功能提供了一种模块化的方式来组合 RAG 检索策略。我们可以通过定义不同的模块,然后将这些模块按照一定的顺序组合起来,形成一个完整的查询流水线。下面我们通过一个从简单到复杂的示例来演示如何使用 LlamaIndex 的查询流水线功能实现高级 RAG 检索。

普通 RAG

首先我们定义一个普通 RAG 的流水线,这个流水线包含了 3 个模块,分别是:输入、检索和输出。其中输入模块用于接收用户输入的查询,检索模块用于从知识库中检索相关文档,输出模块用于根据检索结果生成回答。

图片

在定义查询流水线之前,我们先将我们的测试文档索引入库,这里的测试文档还是用维基百科上的复仇者联盟[2]电影剧情,示例代码如下:

import os
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core import (Settings,SimpleDirectoryReader,StorageContext,VectorStoreIndex,load_index_from_storage,
)
from llama_index.core.node_parser import SentenceSplitterdocuments = SimpleDirectoryReader("./data").load_data()
node_parser = SentenceSplitter()
llm = OpenAI(model="gpt-3.5-turbo")
embed_model = OpenAIEmbedding(model="text-embedding-3-small")
Settings.llm = llm
Settings.embed_model = embed_model
Settings.node_parser = node_parserif not os.path.exists("storage"):index = VectorStoreIndex.from_documents(documents)index.set_index_id("avengers")index.storage_context.persist("./storage")
else:store_context = StorageContext.from_defaults(persist_dir="./storage")index = load_index_from_storage(storage_context=store_context, index_id="avengers")
  • 首先我们通过SimpleDirectoryReader读取./data目录下的文档

  • 然后我们定义了一个SentenceSplitter用于将文档进行分割

  • 接着我们使用OpenAI的 LLM 和 Embedding 模型来生成文本和向量,并将他们添加到Settings

  • 最后我们将文档索引入库,并将索引保存到./storage目录下,以便后续使用

接下来我们定义一个普通的 RAG 流水线,示例代码如下:

from llama_index.core.query_pipeline import QueryPipeline, InputComponent
from llama_index.core.response_synthesizers.simple_summarize import SimpleSummarizeretriever =  index.as_retriever()
p = QueryPipeline(verbose=True)
p.add_modules({"input": InputComponent(),"retriever": retriever,"output": SimpleSummarize(),}
)p.add_link("input", "retriever")
p.add_link("input", "output", dest_key="query_str")
p.add_link("retriever", "output", dest_key="nodes")
  • 我们创建了一个普通检索器retriever,用于从知识库中检索相关文档

  • 然后创建了一个QueryPipeline对象,这是查询流水线的主体,设置 verbose 参数为 True 用于输出详细信息

  • 通过QueryPipelineadd_modules方法添加了 3 个模块:input、retriever和output

  • input模块的实现类是InputComponent,这是查询流水线常用的输入组件,retriever模块是我们定义的检索器,output模块的实现类是SimpleSummarize,这是可以将问题和检索结果进行简单总结的输出组件

  • 接着我们添加模块间的连接关系,add_link方法用于连接模块之间的关系,第一个参数是源模块,第二个参数是目标模块

  • dest_key参数用于指定目标模块的输入参数,因为输出模块有 2 个参数,分别是问题和检索结果,所以我们需要指定dest_key参数,当目标模块只有一个参数时则不需要指定

  • add_link方法中,与dest_key 参数对应的是src_key 参数,当源模块有多个参数时,我们需要指定src_key参数,反之则不需要。

查询流水线添加模块和连接关系的方式除了add_modulesadd_link方法外,还可以通过add_chain方法添加,示例代码如下:

p = QueryPipeline(verbose=True)
p.add_chain([InputComponent(), retriever])

这种方式可以一次性添加模块与连接关系,但这种方式只能添加单参数的模块,如果模块有多个参数则需要使用add_modulesadd_link方法。

接下来我们再来运行查询流水线,示例代码如下:

question = "Which two members of the Avengers created Ultron?"
output = p.run(input=question)
print(str(output))# 结果显示
> Running module input with input:
input: Which two members of the Avengers created Ultron?> Running module retriever with input:
input: Which two members of the Avengers created Ultron?> Running module output with input:
query_str: Which two members of the Avengers created Ultron?
nodes: [NodeWithScore(node=TextNode(id_='53d32f3a-a2d5-47b1-aa8f-a9679e83e0b0', embedding=None, metadata={'file_path': '/data/Avengers:Age-of-Ul...Bruce Banner and Tony Stark.
  • 使用查询流水线的run方法运行查询流水线,传入问题作为输入参数

  • 在显示结果中可以看到查询流水线的调试信息,查询流水线首先运行了input模块,然后运行了retriever模块,最后运行了output模块,调试信息还打印了每个模块的输入参数,最后输出了问题的答案

增加 reranker 模块

接下来我们在普通 RAG 的基础上增加一个 reranker 模块,用于对检索结果进行重新排序。

图片

+from llama_index.postprocessor.cohere_rerank import CohereRerank+reranker = CohereRerank()
p = QueryPipeline(verbose=True)
p.add_modules({"input": InputComponent(),"retriever": retriever,
+        "reranker": reranker,"output": SimpleSummarize(),}
)p.add_link("input", "retriever")
+p.add_link("input", "reranker", dest_key="query_str")
+p.add_link("retriever", "reranker", dest_key="nodes")
p.add_link("input", "output", dest_key="query_str")
-p.add_link("retriever", "output", dest_key="nodes")
+p.add_link("reranker", "output", dest_key="nodes")
  • 这里我们使用了Cohere[3]公司的 rerank 功能,在 LlamaIndex 中提供了CohereRerank类用于实现 Cohere 的 rerank 功能

  • 要使用CohererRerank类,需要先在 Cohere 官网上注册账号并获取 API KEY,并在环境变量中设置COHERE_API_KEY的值:export COHERE_API_KEY=your-cohere-api-key

  • 然后我们在查询流水线中添加一个reranker模块,并将其添加到retriever模块和output模块之间,用于对检索结果进行重新排序

  • 我们去除原来从retriever模块到output模块的连接关系,增加了retriever模块到reranker模块和reranker模块到output模块的连接关系

  • reranker模块同样需要 2 个参数,分别是问题和检索结果,这样reranker模块才可以根据问题对检索结果进行重新排序,所以我们需要指定dest_key参数

查询流水线的运行方法除了run方法外,还有run_with_intermeation方法,这个方法可以获取流水线的中间结果,我们将retrieverrerank模块的中间结果打印出来进行对比,示例代码如下:

output, intermediates = p.run_with_intermediates(input=question)
retriever_output = intermediates["retriever"].outputs["output"]
print(f"retriever output:")
for node in retriever_output:print(f"node id: {node.node_id}, node score: {node.score}")
reranker_output = intermediates["reranker"].outputs["nodes"]
print(f"\nreranker output:")
for node in reranker_output:print(f"node id: {node.node_id}, node score: {node.score}")# 显示结果
retriever output:
node id: 53d32f3a-a2d5-47b1-aa8f-a9679e83e0b0, node score: 0.6608391314791646
node id: dea3844b-789f-46de-a415-df1ef14dda18, node score: 0.5313643379538727reranker output:
node id: 53d32f3a-a2d5-47b1-aa8f-a9679e83e0b0, node score: 0.9588471
node id: dea3844b-789f-46de-a415-df1ef14dda18, node score: 0.5837967
  • 执行run_with_intermediates方法后返回结果是一个元组,包含了输出结果和中间结果

  • 要获取某个模块的中间结果,可以通过intermediates变量加上模块 key 进行获取,比如intermediates["retriever"]是获取检索模块的中间结果

  • 每个中间结果都有 2 个参数,分别是inputsoutputsinputs表示模块的输入参数,outputs表示模块的输出参数

  • inputsoutputs参数类型是字典,比如reranker模块的outputs参数中包含了nodes属性,我们可以这样来获取nodes属性的值:intermediates["reranker"].outputs["nodes"]

增加 query rewrite 模块

之前我们在查询流水线中加入了 reranker 模块,相当是对检索结果的后处理操作,现在我们再加入一个 query rewrite 模块,用于对查询问题进行预处理操作。

图片

+query_rewriter = HydeComponent()
p = QueryPipeline(verbose=True)
p.add_modules({"input": InputComponent(),
+        "query_rewriter": query_rewriter,"retriever": retriever,"reranker": reranker,"output": SimpleSummarize(),}
)-p.add_link("input", "retriever")
+p.add_link("input", "query_rewriter")
+p.add_link("query_rewriter", "retriever")
p.add_link("input", "reranker", dest_key="query_str")
p.add_link("retriever", "reranker", dest_key="nodes")
p.add_link("input", "output", dest_key="query_str")
p.add_link("reranker", "output", dest_key="nodes")
  • 这里我们定义了一个HydeComponent类用于实现查询重写的功能,使用的是 HyDE(假设性文档向量)查询重写策略,它会根据查询问题生成一个假设性回答,然后使用这个假设性回答去检索文档,从而提高检索的准确性

  • HydeComponent是一个自定义的查询流水线组件,后面我们再详细介绍它的实现

  • 我们在原有的查询流水线上增加了一个query_rewriter模块,放在input模块和retriever模块之间,用于对查询问题进行预处理

  • 我们去除原来从input模块到retriever模块的连接关系,增加了input模块到query_rewriter模块和query_rewriter模块到retriever模块的连接关系

  • query_rewriter模块只有一个参数,所以不需要指定dest_key参数

LlamaIndex 的查询流水线提供了自定义组件的功能,我们可以通过继承CustomQueryComponent类来实现自定义组件,下面我们来实现HydeComponent类,示例代码如下:

from llama_index.core.query_pipeline import CustomQueryComponent
from typing import Dict, Any
from llama_index.core.indices.query.query_transform import HyDEQueryTransformclass HydeComponent(CustomQueryComponent):"""HyDE query rewrite component."""def _validate_component_inputs(self, input: Dict[str, Any]) -> Dict[str, Any]:"""Validate component inputs during run_component."""assert "input" in input, "input is required"return input@propertydef _input_keys(self) -> set:"""Input keys dict."""return {"input"}@propertydef _output_keys(self) -> set:return {"output"}def _run_component(self, **kwargs) -> Dict[str, Any]:"""Run the component."""hyde = HyDEQueryTransform(include_original=True)query_bundle = hyde(kwargs["input"])return {"output": query_bundle.embedding_strs[0]}
  • HydeComponent类中的_validate_component_inputs方法用于验证组件的输入参数,必须实现这个方法,否则会抛出异常

  • _input_keys_output_keys属性分别用于定义组件的输入和输出 key 值

  • _run_component方法用于实现组件的具体功能,这里我们使用HyDEQueryTransform类实现了 HyDE 查询重写功能,将查询问题转换为假设性回答,并返回这个假设性回答

替换 output 模块

在之前的查询流水线中,我们使用的是简单的总结输出组件,现在我们将其替换为树形总结组件,用来提高最终的输出结果。

树形总结组件以自底向上的方式递归地合并文本块并对其进行总结(即从叶子到根构建一棵树)。 具体地说,在每个递归步骤中:

  1. 我们重新打包文本块,使得每个块填充大语言模型的上下文窗口

  2. 如果只有一个块,我们给出最终响应

  3. 否则,我们总结每个块,并递归地总结这些摘要

图片

from llama_index.core.response_synthesizers.tree_summarize import TreeSummarizep = QueryPipeline(verbose=True)
p.add_modules({"input": InputComponent(),"query_rewriter": query_rewriter,"retriever": retriever,"reranker": reranker,
-        "output": SimpleSummarize(),
+        "output": TreeSummarize(),}
)
  • 替换output模块的组件比较简单,只需要将原来的SimpleSummarize替换为TreeSummarize即可

  • TreeSummarize组件的结构和SimpleSummarize组件类似,因此这里我们不需要修改其他模块的连接关系

查询流水线实际上是一个 DAG(有向无环图),每个模块是图中的一个节点,模块之间的连接关系是图中的边,我们可以通过代码来展示这个图形结构,示例代码如下:

from pyvis.network import Networknet = Network(notebook=True, cdn_resources="in_line", directed=True)
net.from_nx(p.clean_dag)
net.write_html("output/pipeline_dag.html")
  • 我们使用pyvis库来绘制查询流水线的图形结构

  • Network类用于创建一个网络对象,notebook=True表示在 Jupyter Notebook 中显示,cdn_resources="in_line"表示使用内联资源,directed=True表示有向图

  • from_nx方法用于将查询流水线的 DAG 结构转换为网络对象

  • write_html方法用于将网络对象保存为 HTML 文件,这样我们就可以在浏览器中查看查询流水线的图形结构

保存后的查询流水线图形结构如下:

图片

使用句子窗口检索

在之前的查询流水线中,retriever模块使用的是普通的检索策略,现在我们将其替换为句子窗口检索策略,用于提高检索的准确性。

句子窗口检索的原理:首先在文档切分时,将文档以句子为单位进行切分,同时进行 Embedding 并保存数据库。然后在检索时,通过问题检索到相关的句子,但并不只是将检索到的句子作为检索结果,而是将该句子前面和后面的句子一起作为检索结果,包含的句子数量可以通过参数来进行设置,最后将检索结果再一起提交给 LLM 来生成答案。

图片

+from llama_index.core.node_parser import SentenceWindowNodeParser-node_parser = SentenceSplitter()
+node_parser = SentenceWindowNodeParser.from_defaults(
+    window_size=3,
+    window_metadata_key="window",
+    original_text_metadata_key="original_text",
+)+meta_replacer = MetadataReplacementPostProcessor(target_metadata_key="window")
p = QueryPipeline(verbose=True)
p.add_modules({"input": InputComponent(),"query_rewriter": query_rewriter,"retriever": retriever,
+        "meta_replacer": meta_replacer,"reranker": reranker,"output": TreeSummarize(),}
)
p.add_link("input", "query_rewriter")
p.add_link("query_rewriter", "retriever")
+p.add_link("retriever", "meta_replacer")
p.add_link("input", "reranker", dest_key="query_str")
-p.add_link("retriever", "reranker", dest_key="nodes")
+p.add_link("meta_replacer", "reranker", dest_key="nodes")
p.add_link("input", "output", dest_key="query_str")
p.add_link("reranker", "output", dest_key="nodes")
  • 句子窗口检索首先需要调整文档的入库策略,以前是用SentenceSplitter来切分文档,现在我们使用SentenceWindowNodeParser来切分文档,窗口大小为 3,原始文本的 key 为original_text,窗口文本的 key 为window

  • 句子窗口检索的原理是在检索出结果后,将检索到的节点文本替换成窗口文本,所以这里需要增加一个meta_replacer模块,用来替换检索结果中的节点文本

  • meta_replacer模块的实现类是MetadataReplacementPostProcessor,输入参数是检索结果nodes,输出结果是替换了节点文本的检索结果nodes

  • 我们将meta_replacer模块放在retriever模块和reranker模块之间,先对检索结果进行元数据替换处理,然后再进行 rerank 操作,因此这里修改了这 3 个模块的连接关系

我们可以打印出retriever模块和meta_replacer模块的中间结果,来对比检索结果的变化,示例代码如下:

output, intermediates = p.run_with_intermediates(input=question)
retriever_output = intermediates["retriever"].outputs["output"]
print(f"retriever output:")
for node in retriever_output:print(f"node: {node.text}\n")
meta_replacer_output = intermediates["meta_replacer"].outputs["nodes"]
print(f"meta_replacer output:")
for node in meta_replacer_output:print(f"node: {node.text}\n")# 显示结果
retriever output:
node: In the Eastern European country of Sokovia, the Avengers—Tony Stark, Thor, Bruce Banner, Steve Rogers, Natasha Romanoff, and Clint Barton—raid a Hydra facility commanded by Baron Wolfgang von Strucker, who has experimented on humans using the scepter previously wielded by Loki.node: They meet two of Strucker's test subjects—twins Pietro (who has superhuman speed) and Wanda Maximoff (who has telepathic and telekinetic abilities)—and apprehend Strucker, while Stark retrieves Loki's scepter.meta_replacer output:
node: and attacks the Avengers at their headquarters.  Escaping with the scepter, Ultron uses the resources in Strucker's Sokovia base to upgrade his rudimentary body and build an army of robot drones.  Having killed Strucker, he recruits the Maximoffs, who hold Stark responsible for their parents' deaths by his company's weapons, and goes to the base of arms dealer Ulysses Klaue in Johannesburg to get vibranium.  The Avengers attack Ultron and the Maximoffs, but Wanda subdues them with haunting visions, causing Banner to turn into the Hulk and rampage until Stark stops him with his anti-Hulk armor. [a]
A worldwide backlash over the resulting destruction, and the fears Wanda's hallucinations incited, send the team into hiding at Barton's farmhouse.  Thor departs to consult with Dr.  Erik Selvig on the apocalyptic future he saw in his hallucination, while Nick Fury arrives and encourages the team to form a plan to stop Ultron.node: In the Eastern European country of Sokovia, the Avengers—Tony Stark, Thor, Bruce Banner, Steve Rogers, Natasha Romanoff, and Clint Barton—raid a Hydra facility commanded by Baron Wolfgang von Strucker, who has experimented on humans using the scepter previously wielded by Loki.  They meet two of Strucker's test subjects—twins Pietro (who has superhuman speed) and Wanda Maximoff (who has telepathic and telekinetic abilities)—and apprehend Strucker, while Stark retrieves Loki's scepter.
Stark and Banner discover an artificial intelligence within the scepter's gem, and secretly decide to use it to complete Stark's "Ultron" global defense program.  The unexpectedly sentient Ultron, believing he must eradicate humanity to save Earth, eliminates Stark's A.I.

从结果中我们可以看出,原来的retreiver模块输出的只是简单的一句话,而meta_replacer模块输出的是多个句子,包含了检索节点的前后节点的文本,这样可以让 LLM 生成更准确的答案。

增加评估模块

最后我们再为查询流水线增加一个评估模块,用于评估查询流水线,这里我们使用Ragas[6]来实现评估模块。

Ragas 是一个评估 RAG 应用的框架,拥有很多且详细的评估指标。

图片

+evaluator = RagasComponent()
p = QueryPipeline(verbose=True)
p.add_modules({"input": InputComponent(),"query_rewriter": query_rewriter,"retriever": retriever,"meta_replacer": meta_replacer,"reranker": reranker,"output": TreeSummarize(),
+        "evaluator": evaluator,}
)
-p.add_link("input", "query_rewriter")
+p.add_link("input", "query_rewriter", src_key="input")
p.add_link("query_rewriter", "retriever")
p.add_link("retriever", "meta_replacer")
-p.add_link("input", "reranker", dest_key="query_str")
+p.add_link("input", "reranker", src_key="input", dest_key="query_str")
p.add_link("meta_replacer", "reranker", dest_key="nodes")
-p.add_link("input", "output", dest_key="query_str")
+p.add_link("input", "output", src_key="input", dest_key="query_str")
p.add_link("reranker", "output", dest_key="nodes")
+p.add_link("input", "evaluator", src_key="input", dest_key="question")
+p.add_link("input", "evaluator", src_key="ground_truth", dest_key="ground_truth")
+p.add_link("reranker", "evaluator", dest_key="nodes")
+p.add_link("output", "evaluator", dest_key="answer")
  • RagasComponent也是一个自定义的查询流水线组件,后面我们再详细介绍它的实现

  • 在查询流水线中增加了一个evaluator模块,用于评估查询流水线

  • 我们将evaluator模块放到output模块之后,用于评估输出结果

  • evaluator模块有 4 个输入参数,分别是问题、真实答案、检索结果和生成答案,其中问题和真实答案通过input模块传入,检索结果通过reranker模块传入,生成答案通过output模块传入

  • 因为input模块现在有 2 个参数,分别是问题input和真实答案ground_truth,所以我们在添加input模块的相关连接关系时,需要指定src_key参数

我们再来看下RagasComponent的实现,示例代码如下:

from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall
from ragas import evaluate
from datasets import Dataset
from llama_index.core.query_pipeline import CustomQueryComponent
from typing import Dict, Anymetrics = [faithfulness, answer_relevancy, context_precision, context_recall]class RagasComponent(CustomQueryComponent):"""Ragas evalution component."""def _validate_component_inputs(self, input: Dict[str, Any]) -> Dict[str, Any]:"""Validate component inputs during run_component."""return input@propertydef _input_keys(self) -> set:"""Input keys dict."""return {"question", "nodes", "answer", "ground_truth", }@propertydef _output_keys(self) -> set:return {"answer", "source_nodes", "evaluation"}def _run_component(self, **kwargs) -> Dict[str, Any]:"""Run the component."""question, ground_truth, nodes, answer = kwargs.values()data = {"question": [question],"contexts": [[n.get_content() for n in nodes]],"answer": [str(answer)],"ground_truth": [ground_truth],}dataset = Dataset.from_dict(data)evalution = evaluate(dataset, metrics)return {"answer": str(answer), "source_nodes": nodes, "evaluation": evalution}
  • 和之前的自定义组件一样,RagasComponent类需要实现_validate_component_inputs_input_keys_output_keys_run_component方法

  • 组件的输入参数是问题、真实答案、检索结果和生成答案,输出参数是生成答案、检索结果和评估结果

  • _run_component方法中,我们将输入参数重新封装成一个可供 Ragas 评估的Dataset对象

  • 评估指标我们使用的分别是:faithfulness(评估QuestionContext的一致性),answer_relevancy(评估AnswerQuestion的一致性),context_precision(评估Ground TruthContext中是否排名靠前),context_recall(评估Ground TruthContext的一致性)

  • 我们再调用evaluate方法对Dataset对象进行评估,得到评估结果

  • 最后将生成答案、检索结果和评估结果一起返回

最后我们来运行下查询流水线,示例代码如下:

question = "Which two members of the Avengers created Ultron?"
ground_truth = "Tony Stark (Iron Man) and Bruce Banner (The Hulk)."
output = p.run(input=question, ground_truth=ground_truth)
print(f"answer: {output['answer']}")
print(f"evaluation: {output['evaluation']}")# 显示结果
answer: Tony Stark and Bruce Banner
evaluation: {'faithfulness': 1.0000, 'answer_relevancy': 0.8793, 'context_precision': 1.0000, 'context_recall': 1.0000}
  • 运行查询流水线时,我们需要传入问题和真实答案作为输入参数

  • 在输出结果中,我们可以看到生成的答案,以及评估结果 4 个评估指标的值

总结

通过上面的示例,我们可以看到如何通过模块化和流程的方式来实现高级 RAG 检索功能,我们可以根据具体的需求,自定义不同的模块,然后将这些模块按照一定的顺序组合起来,形成一个完整的查询流水线。在 RAG 应用中,我们还可以定义多个查询流水线,用于不同的场景,比如问答、对话、推荐等,这样可以更好地满足不同的需求。

关注我,一起学习各种人工智能和 AIGC 新技术,欢迎交流,如果你有什么想问想说的,欢迎在评论区留言。

引用参考

  • Modular RAG and RAG Flow: Part Ⅰ[8]

  • Modular RAG and RAG Flow: Part II[9]

  • An Introduction to LlamaIndex Query Pipelines[10]

参考:

[1] LlamaIndex: https://www.llamaindex.ai/

[2]复仇者联盟: https://en.wikipedia.org/wiki/Avenger

[3]Cohere: https://cohere.com/

[6] Ragas: https://docs.ragas.io/

[8]Modular RAG and RAG Flow: Part Ⅰ: https://medium.com/@yufan1602/modular-rag-and-rag-flow-part-%E2%85%B0-e69b32dc13a3

[9]Modular RAG and RAG Flow: Part II: https://medium.com/@yufan1602/modular-rag-and-rag-flow-part-ii-77b62bf8a5d3

[10]An Introduction to LlamaIndex Query Pipelines: https://docs.llamaindex.ai/en/stable/examples/pipeline/query_pipeline/

相关文章:

大模型高级 RAG 检索策略之流程与模块化

我们介绍了很多关于高级 RAG(Retrieval Augmented Generation)的检索策略,每一种策略就像是机器中的零部件,我们可以通过对这些零部件进行不同的组合,来实现不同的 RAG 功能,从而满足不同的需求。 今天我们…...

TCPListen客户端和TCPListen服务器

创建项目 TCPListen服务器 public Form1() {InitializeComponent();//TcpListener 搭建tcp服务器的类,基于socket套接字通信的//1创建服务器对象TcpListener server new TcpListener(IPAddress.Parse("192.168.107.83"), 3000);//2 开启服务器 设置最大…...

DDei在线设计器-属性编辑器

DDei-Core-属性编辑器 DDei-Core-属性编辑器插件包含了文本、大文本、数值、下拉、单选、勾选以及颜色等属性编辑。 图形和属性共同构成一个完整的定义,属性编辑器就是编辑属性值的控件。当选中图形实例时,属性面板就会展现当前实例的所有属性以及属性编…...

八字综合测算网整站源码程序/黄历/灵签/排盘/算命/生肖星座/日历网/周公解梦

八字综合测算网整站源码程序/黄历/灵签/排盘/算命/生肖星座/日历网/周公解梦 演示地址: https://s24.gvyun.com/ 手机端地址: https://ms24.gvyun.com/ 网站功能分类: 八字:八字测算;日干论命;称骨论命…...

C# WPF入门学习主线篇(十一)—— 布局管理

C# WPF入门学习主线篇(十一)—— 布局管理 欢迎来到C# WPF入门学习系列的第十一篇。在前面的文章中,我们已经探讨了WPF中的许多控件及其属性和事件。今天,我们将开启一个新的篇章——布局管理。布局管理是WPF中一个至关重要的概念…...

LabVIEW轴承试验机测控系统

开发了一种基于LabVIEW软件开发的大功率风电机组增速箱轴承试验机测控系统。系统主要用于模拟实际工况,进行轴承可靠性分析,以优化风电机组的性能和可靠性。通过高度自动化的测控系统,实现了对试验机的精确控制,包括速度、振动、温…...

0605 实际集成运算放大器的主要参数和对应用电路的影响

6.5.1 实际集成运放的主要参数 6.5.2 集成运放应用中的实际问题 6.5.2 集成运放应用中的实际问题...

艾宾浩斯winform单词系统+mysql

为用户提供集词典、题库、记忆单词功能于一体的应用,为用户提供目的性强、科学高效、多样化的记忆单词方法,使用户学习英语和记忆单词的效率得到提高 单词记忆模块 管理模块 查询单词 阅读英文 查看词汇 记忆单词 收藏单词 字段管理设置 统计 艾宾浩斯wi…...

rv1126-rv1109-串口显示路径不变化

串口只有#, 后来看了教程改成如下 但是没有变化,那个路径都只显示rootLonbon# 于是最后改成了这样 因为:...

基于C#开发web网页管理系统模板流程-主界面密码维护功能完善

点击返回目录-> 基于C#开发web网页管理系统模板流程-总集篇-CSDN博客 前言 紧接上篇->基于C#开发web网页管理系统模板流程-主界面统计功能完善-CSDN博客 一个合格的管理系统,至少一定存在一个功能——用户能够自己修改密码,理论上来说密码只能有用…...

[NOVATEK] NT96580行车记录仪功能学习笔记(持续更新~

sdk文件结构(我个人理解) 1、DX文件夹里面是IO口以及项目使用到的相关外设配置 2、GX是外设功能实现函数所在文件夹 3、Startup文件夹是整个项目的入口,里面有个startup.c文件是main函数所在 4、UIAPP是手机APP功能设置的文件夹,增删改功能主要是在UIAPP和UIWnd文件夹里…...

力扣752. 打开转盘锁

Problem: 752. 打开转盘锁 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 1.用一个集合 deads 存储所有的“死锁”状态,一个集合 visited 存储所有已经访问过的状态,以避免重复访问,一个队列 q 进行广度优先搜索(BF…...

揭秘:义乌理阳的跨境选品师项目

在全球经济一体化的今天,跨境电商已成为各国贸易的重要组成部分,而选品师作为其中的关键角色,扮演着挑选优质商品的重要角色。在中国义乌,一家名为理阳信息咨询服务有限公司备受关注,因其据称拥有跨境选品师项目而备受…...

电视剧推荐

1、《春色寄情人》 2、《唐朝诡事录》 3、《南来北往》 4、《与凤行》 5、《利剑玫瑰》 6、《承欢记》...

ISO 19115-3:2023 关于元数据最小实例的允许命名空间的详细说明

理解说明内容 标识符(Identifier) URL: https://standards.isotc211.org/19115/-1/1/req/metadata-minimal-xml/allowed-namespaces解释: 这个 URL 标识了元数据最小实例中允许的命名空间的具体标准和规范。包含于(Included in) 要求类 4:元数据信息最小交换 (ISO 19115-…...

最新下载:CorelDraw 2023【软件附加安装教程】

简介: CorelDRAW Graphics Suite 订阅版拥有配备齐全的专业设计工具包,可以通过非常高的效率提供令人惊艳的矢量插图、布局、照片编辑和排版项目。价格实惠的订阅就能获得令人难以置信的持续价值,即时、有保障地获得独家的新功能和内容、一流…...

QT系列教程(8) QT 布局学习

简介 Qt 中的布局有三种方式,水平布局,垂直布局,栅格布局。 通过ui设置布局 我们先创建一个窗口应用程序,程序名叫layout,基类选择QMainWindow。但我们不使用这个mainwindow,我们创建一个Qt应用程序类Log…...

SpringCloud Gateway中Route Predicate Factories详细说明

官网地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicates-factories Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。 Spring Cloud Gateway …...

计算机视觉全系列实战教程:(八)图像变换-点运算、灰度变换、直方图变换

图像变换:点运算、灰度变换、直方图变换 1.点运算(1)What(2)Why 2.灰度变换(1)What(2)Why(作用)(3)Which(有哪些灰度变换) 3.直方图修正(1)直方图均衡化 1.点运算 (1)What 通过点运算,输出图像的每个像素的灰度值仅仅取决于输入图像中相对应…...

4.MongoDB sharding Cluster 分片集群

MongoDB分片集群的介绍: 是MongoDB提供的一种可水平扩展的数据存储解决方案。 当单个MongoDB服务器无法满足数据存储需求或吞吐量要求时,可以使用分片集群来分散数据量和查询负载。分片集群的结构组成: 1.分片(shards)…...

PDF转图片工具

背景: 今天有个朋友找我:“我有个文件需要更改,但是文档是PDF的,需要你帮我改下内容,你是搞软件的,这个对你应该是轻车熟路了吧,帮我弄弄吧”,听到这话我本想反驳,我是开…...

Day 19:419. 甲板上的战舰

Leetcode 419. 甲板上的战舰 给你一个大小为 m x n 的矩阵 board 表示甲板,其中,每个单元格可以是一艘战舰 ‘X’ 或者是一个空位 ‘.’ ,返回在甲板 board 上放置的 战舰 的数量。 战舰 只能水平或者垂直放置在 board 上。换句话说&#xff…...

Web前端专科实习:技能提升、实践挑战与职业展望

Web前端专科实习:技能提升、实践挑战与职业展望 在数字化时代,Web前端技术作为连接用户与互联网世界的桥梁,其重要性日益凸显。作为一名Web前端专科实习生,我有幸在这个充满机遇和挑战的领域进行实践学习。接下来,我将…...

简单脉冲动画效果实现

简单脉冲动画效果实现 效果展示 CSS 知识点 CSS 变量的灵活使用CSS 动画使用 页面整体结构实现 <div class"pulse"><span style"--i: 1"></span><span style"--i: 2"></span><span style"--i: 3"…...

apache poi 插入“下一页分节符”并设置下一节纸张横向的一种方法

一、需求描述 我们知道&#xff0c;有时在word中需要同时存在不同的节&#xff0c;部分页面需要竖向、部分页面需要横向。本文就是用java调用apache poi来实现用代码生成上述效果。下图是本文实现的效果&#xff0c;供各位看官查阅&#xff0c;本文以一篇课文为例&#xff0c;…...

【React】useCallback和useMemo使用指南

useCallback和useMemo是React中两个用于优化性能的Hooks。以下是它们的使用指南,分点表示并归纳了关键信息: useCallback useCallback返回一个记忆化的回调函数,该回调函数只在它的依赖项发生改变时才会更新。这对于在组件渲染之间保持稳定的引用特别有用,可以防止不必要…...

XMind软件下载-详细安装教程视频

​简介 XMind是一款实用的思维导图软件&#xff0c;简单易用、美观、功能强大&#xff0c;拥有高效的可视化思维模式&#xff0c;具备可扩展、跨平台、稳定性和性能&#xff0c;真正帮助用户提高生产率&#xff0c;促进有效沟通及协作。中文官方网站&#xff1a;http://www.x…...

一个小的画布Canvas页面,记录点的轨迹

Hello大家好&#xff0c;好久没有更新了&#xff0c;最近在忙一些其他的事&#xff0c;今天说一下画布canvas&#xff0c;下面是我的代码&#xff0c;实现了一个点从画布的&#xff08;0,0&#xff09;到&#xff08;canvas.width&#xff0c;canvas.height&#xff09;的一个实…...

docker-compose教程

1. docker-compose是什么&#xff1f; 1. 1 简介 compose、machine 和 swarm 是docker 原生提供的三大编排工具。 简称docker三剑客。Compose 项目是 Docker 官方的开源项目&#xff0c;定义和运行多个 Docker 容器的应用&#xff08;Defining and running multi-container Do…...

结果出乎意料!MySQL和MariaDB谁快?MySQL 8.0比MySQL 5.6快吗?

MySQL和MariaDB哪个更快&#xff1f;MySQL 8.0的版本和早期MySQL 5.6的版本哪个更快&#xff1f;这儿有个第三方的测试报告回答了这两个大家关心的问题&#xff0c;姚远来和大家一起解读一下。https://smalldatum.blogspot.com/2024/04/sysbench-on-small-server-mariadb-and.h…...

建设银行卡在哪里/小红书搜索优化

如今&#xff0c;任何企业对共享企业工具的第一明显需求是&#xff0c;它可以在任何地方、任何设备上被浏览器访问&#xff0c;而且部署的灵活性符合组织政策&#xff0c;无论是安全的公共云还是公司数据中心。 看板工具本身应该具有很高的可配置性&#xff0c;可以将项目和流…...

重庆企业网站推广代理/广州头条新闻最新

Http响应结构有三部分组成&#xff1a; Http头部&#xff08;Http Header&#xff09;&#xff1a;它们包含了更多关于响应的信息。比如&#xff1a;头部可以指定认为响应过期的过期日期&#xff0c;或者是指定用来给用户安全的传输实体内容的编码格式。如何在Serlet中检索HTTP…...

安陆网站建设/刷神马seo排名首页排名

项目需求根据json导入数据到本地数据库中 项目分析及项目进程项目分析需要把json转换成项目中对应的实体&#xff0c;然后进行一一赋值&#xff0c;这里只提供思路当然&#xff0c;也可以选择直接json串进行解析&#xff0c;但是不让实体直观&#xff0c;时刻具备面向对象的思维…...

新疆维吾尔建设厅网站官网/好用吗

OID(对象标识符)是指数据库表中的一列&#xff0c;其中存储着每行数据的唯一标识符。这种标识符通常被用来引用表中的某一行数据&#xff0c;而不需要使用其他的列值。为了在数据库表中使用OID&#xff0c;需要在创建表的时候明确指定一列作为OID列。 例如&#xff0c;假设我们…...

有设计师做的装修效果图的网站/今日热搜头条

一键设置DNS官方版是一款非常受欢迎的DNS设置工具&#xff0c;一键设置DNS官方版体积小巧&#xff0c;功能强大&#xff0c;能够根据用户提前设定好的规则&#xff0c;动态的为电脑设置、更改DNS服务器地址等操作&#xff0c;使用起来简单便捷。软件介绍一键设置DNS官方版是一款…...

劳务公司网站怎么做/sem工具是什么

1.多表查询 select * from user u,card c where u.userIdc.userId2.嵌套查询 简单嵌套查询 select * from user where city (select city from user where userId101 )带in的嵌套查询 select * from user where city in (select city from user where userId !101)带any的…...