背景介绍
检索增强生成(RAG)是一种提示工程,它通过将外部数据整合到提示中来增强大型语言模型(LLM)。这可以提高模型的知识性、相关性和专业性。然而,传统的 RAG 系统有其局限性。它们往往缺乏灵活性,严重依赖矢量数据库的检索结果,这可能导致不加批判地纳入数据。随着这些数据库规模的扩大,标准 RAG 难以有效地对输入请求进行分类和过滤,从而使检索过程变成了一项耗时耗力的任务,无异于大海捞针。在本文中,我们将提供一个使用 LlamaIndex 的 RAG 的详细示例,以及 OpenVINO™ 所带来的性能优势。
Agentic-RAG 系统利用人工智能代理将各种 RAG 检索器整合为专用工具,从而解决了标准 RAG 的局限性。这些代理可以智能地决定是否使用 RAG 的上下文搜索,并根据用户的查询选择合适的检索器。例如,历史问题可以优先使用历史 RAG 检索器,而数学问题则可以完全绕过 RAG,直接使用与计算相关的工具,立即从 LLM 中获得答案。此外,Agentic-RAG 还可以将 RAG 与其他工具结合起来,共同处理复杂的任务。在附图中,人工智能代理委托任务,依次调用不同的工具或 RAG 组件来生成最终解决方案。
接下来,我们将探讨如何使用 OpenVINO™ 和 LlamaIndex 构建一个 Agentic-RAG 系统。
完整示例: 使用 OpenVINO™ 和 LlamaIndex 创建 RAG 系统
模型转换和量化
RAG 系统需要 LLM 和嵌入模型这两个基本组件。可以使用 Optimum-Intel CLI 将这些模型转换为 OpenVINO™ IR 格式并进行量化。
安装:
要安装模型转换和量化所需的工具,请使用以下 pip 命令:
pip install optimum[openvino]
该命令安装支持 OpenVINO™ 的最佳软件包,实现模型转换和优化。
LLM 转换:
OpenVINO™ LLM 模型可通过text-generation-with-pastOptimum Intel 中的任务导出。由于 LLM 在此流程中充当代理,因此建议选择推理能力较强的模型,如 Llama3-8B 或 Phi3-Medium。
optimum-cli export openvino --model {llm_model_id} --task text-generation-with-past --trust-remote-code --weight-format int4 {llm_model_path}
嵌入模型转换:
同样,OpenVINO™ 嵌入模型也可通过特征提取任务导出。BGE 或 Jina 等流行模型均可兼容。在本例中,我们使用了 BAAI/bge-small-en-v1.5,以兼顾性能和准确性。
optimum-cli export openvino --model {embedding_model_id} --task feature-extraction {embedding_model_path}
模型任务初始化
一旦将基于 OpenVINO™ 的 LLM、Embedding 和 Reranker 任务集成到 LlamaIndex 框架中,开发人员就可以使用导出的模型毫不费力地初始化这些任务。
安装
pip install llama-index llama-index-llms-openvino llama-index-embeddings-openvino
LLM 初始化:
在 LlamaIndex 中,使用 OpenVINOLLM 类创建了基于 OpenVINO™ 的 LLM 任务。
from llama_index.llms.openvino import OpenVINOLLM
llm = OpenVINOLLM(
model_id_or_path=str(llm_model_path),
max_new_tokens=1000,
model_kwargs={"ov_config": ov_config},
device_map=llm_device.value,
)
嵌入初始化:
文本嵌入模型将输入文本转换为使用 OpenVINOEmbedding 创建的特征向量。
from llama_index.embeddings.huggingface_openvino import OpenVINOEmbedding
embedding = OpenVINOEmbedding(model_id_or_path=embedding_model_path, device=embedding_device.value)
创建 RAG 工具
接下来,我们使用 LLM 和 Embedding 组件开发一个 RAG 工具。在本示例中,Meta-Llama-3-8B-Instruct 用作 LLM,bge-small-en-v1.5 用作嵌入模型。初始设置包括在 LlamaIndex 中使用标准的 RAG 检索器,使用默认的向量相似性搜索方法进行上下文过滤。
from llama_index.readers.file import PyMuPDFReader
from llama_index.core import VectorStoreIndex, Settings
from llama_index.core.tools import FunctionTool
Settings.embed_model = embedding
Settings.llm = llm
loader = PyMuPDFReader()
documents = loader.load(file_path=text_example_en_path)
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine(similarity_top_k=2)
一旦创建了 RAG Retriever,就可以使用 LlamaIndex 接口将其封装为一个代理。必须对工具进行描述,这样 LLM 才能根据任务确定要调用的工具。
from llama_index.core.tools import QueryEngineTool
budget_tool = QueryEngineTool.from_defaults(
query_engine,
name="Xeon6",
description="A RAG engine with basic facts about Intel Xeon 6 processors with E-cores",
)
为了展示 Agentic-RAG 处理复杂任务的能力,我们还开发了两种不同的数学工具,供LLM选择。
def multiply(a: float, b: float) -> float:
return a * b
multiply_tool = FunctionTool.from_defaults(fn=multiply)
def add(a: float, b: float) -> float:
return a + b
add_tool = FunctionTool.from_defaults(fn=add)
构建代理管道
由于 Llama3 目前不支持函数调用,因此我们使用 ReAct 方法创建一个代理。通过 ReActAgent.from_tools 接口,只需一行代码就能构建一个代理管道。绑定工具和 LLM 组件,建立一个基本的 ReAct 代理。
agent = ReActAgent.from_tools([multiply_tool, add_tool, budget_tool], llm=llm, verbose=True)
最后,让我们来测试一下这个示例。当被问及 “配备 4 个插槽的英特尔至强 6 处理器服务器的最大内核数是多少?”时,代理会按如下步骤进行: 它查询 “至强 6 ”RAG 系统中单个 CPU 插槽的最大线程数,然后使用数学工具将结果乘以 4,得出最终答案。
response = agent.chat("What's the maximum number of cores in an Intel Xeon 6 processor server with 4 sockets? Go step by step, using a tool to do any math.")
结果:
行动: Xeon6
- 输入:"单个插槽中的最大内核数
- 观察结果:单插槽最大内核数: 144
操作: 倍增
- 输入 {'a': 144, 'b': 4}
- 观察结果:576
答案: 576 配备 4 个插槽的英特尔至强 6 处理器服务器的最大内核数为 576。
与标准 RAG 相比,Agentic-RAG 管道通过推理和调用外部工具,支持更复杂的任务,如数据分析。不过,考虑到生成响应所需的多轮操作,Agentic-RAG 系统的性能应该得到优化。
总结
通过整合代理和 RAG,我们增强了 LLM 直接处理复杂任务的能力,与传统 RAG 方法相比,这种方法更适合行业应用。随着多代理方法的采用,基于代理的 RAG 系统很可能会取代标准 RAG 系统,为 LLM 应用提供一个适应性更强、更精确的框架。