检索增强生成(RAG)是一种将信息检索与一组精心设计的系统提示相结合的技术,旨在从 大型语言模型(LLM)中生成高质量的内容。通过合并来自各种来源的数据,如关系数据库、非结构化文档存储库、互联网数据流和媒体新闻源,RAG 可以显著提高 生成人工智能 系统的性能和准确性。
开发人员在构建 RAG 管道时必须考虑多种因素:从 LLM 响应基准测试到选择正确的块大小。
在这篇文章中,我将演示如何使用 LangChain 的 NVIDIA AI 终结点。首先,通过下载网页并使用 NVIDIA NeMo Retriever 嵌入微服务,然后使用搜索相似性 FAISS。接着,我将展示两个不同的聊天链,用于查询矢量储存。对于此示例,我参考了 NVIDIA Triton 推理服务器文档,尽管可以很容易地修改代码以使用任何其他源代码。
欲了解更多信息和后续内容,请参阅 使用 LangChain 和 NVIDIA AI 端点生成嵌入式文档来构建 RAG 链 笔记本。
教程先决条件
要充分利用本教程,您需要具备以下方面的基本知识:LLM 培训 和推理管道,以及以下资源:
- 我们使用了 LangChain。
- NVIDIA AI 基础端点
- 矢量存储
什么是 RAG?它是如何赋予 LLM 权力的?
这就是为什么用 RAG 管道增强 LLM 很重要的原因。
在本质上,LLM 是神经网络,通常通过它们包含的参数来衡量。LLM 的参数基本上代表了人类如何使用单词造句的一般模式。
这种深刻的理解,有时被称为参数化知识,使 LLM 能够以极快的速度响应一般提示。然而,对于那些希望深入了解当前或更具体主题的用户来说,它并不能提供相应的服务。
RAG 填补了 LLM 工作方式的空白(图 1)。其目的是将生成性人工智能服务与外部资源联系起来,尤其是那些富含最新技术细节的服务。根据这个 原纸,RAG 被称为“通用微调配方”,因为几乎任何 LLM 都可以使用它来连接几乎任何外部资源。
减少 LLM 幻觉并改善模型反应
RAG 在语言模型技术领域提供了许多好处,尤其是在为 LLM 提供最新信息方面。通过集成从外部来源检索相关数据的搜索功能,RAG 确保 LLM 具备最新的可用知识,从而提高其响应的准确性和相关性(图 2)。
RAG 还为数据隐私的挑战提供了一种解决方案,因为它使 LLM 能够在不需要直接访问敏感数据的情况下生成响应。这是通过只从外部来源检索必要的信息来实现的,从而将数据泄露的风险降至最低。
RAG 有可能缓解 LLM 幻觉的问题,LLM 幻觉是指由于模型训练数据的限制而产生不准确或误导性的信息。通过为 LLM 提供对外部来源的实时访问,RAG 可以帮助降低幻觉的可能性,并提高模型响应的整体可靠性。
RAG 实施注意事项
RAG 提出了一些必须解决的挑战,以充分发挥其潜力。其中一个挑战是确保用于从外部来源检索信息的提示精心制作,并准确反映用户的意图。构建不当的提示可能会导致检索到不相关或不完整的信息,这可能会对 LLM 的响应质量产生负面影响。
另一个挑战是确定如何以有意义和客观的方式评估 RAG 的成功。响应准确性和相关性等指标很重要,但它们可能无法完全捕捉 RAG 对 LLM 性能影响的细微差别。
最后,为了最大限度地提高 RAG 的效益并减少其挑战,我们需要持续优化,仔细考虑搜索算法效率、信息检索相关性和 LLM 集成等因素。欲了解其他挑战的更多信息,请参阅 设计检索增强生成系统时的七个失败点 纸张和 12 RAG 痛点和建议的解决方案 文章。
通过解决这些挑战,RAG 有可能显著增强 LLM 的能力,并为自然语言处理应用程序释放新的可能性。
LangChain 的用途是什么?
LangChain 是一个开源框架,旨在简化使用大型语言模型(LLM)的应用程序开发。该框架提供了工具和抽象,以提高 LLM 的定制性、准确性和相关性,从而能够创建多种应用程序,例如聊天机器人、问答、内容生成和摘要程序。
LangChain 由 LangChain 库、LangChain 模板、LangServe 和 LangSmith 组成,提供接口、集成、参考体系结构和开发人员平台,用于构建和部署 LLM 驱动的应用程序。该框架包括用于模型 I/O、检索和代理的标准接口,使您能够集成数据源、LLM 和工具来构建复杂的应用程序。
LangChain 是由活跃社区支持的丰富工具生态系统的一部分,通过抽象数据源集成的复杂性来简化人工智能开发。
设置
要开始,请先创建一个免费帐户并访问 NVIDIA API 产品目录,然后按照以下步骤进行操作:
- 选择任意模型。
- 选择Python,然后获取 API 密钥。
- 将生成的密钥另存为环境变量
NVIDIA_API_KEY
。
从那里,您应该可以访问端点。
这个 完整笔记本 是 NVIDIA Generative AI 示例 的一部分,托管在 GitHub 回购中。
首先,安装 LangChain、 NVIDIA AI 端点和 FAISS。
pip install langchain
pip install langchain_nvidia_ai_endpoints
pip install faiss-gpu
基线
为了建立比较的基线,首先使用普通 LLM 评估响应:
from langchain_nvidia_ai_endpoints import ChatNVIDIA
llm = ChatNVIDIA(model="ai-llama2-70b", max_tokens=1000)
现在试着问一个关于 NVIDIA Triton 推理服务器的基本问题。
result = llm.invoke("What interfaces does Triton support?")
print(result.content)
Cohesity 提供的 Triton 产品是一种数据保护和管理解决方案,旨在简化和优化各种环境中的数据备份和恢复。Triton 支持多种接口,包括…
基线 LLM 无法识别问题上下文中的 Triton 推理服务器,并以不正确的信息进行响应。尝试添加 NVIDIA 以改进提示。
result = llm.invoke("What interfaces does NVIDIA Triton support?")
print(result.content)
NVIDIA Triton 是一个人工智能模型推理服务平台,它支持多个接口,以提供与各种应用程序和框架集成的灵活性和方便性。
它现在可以识别 Triton 推理服务器,但没有提供太多细节。
result = llm.invoke("But why?")
print(result.content)
这些接口确保 NVIDIA Triton 可以轻松集成到各种人工智能和机器学习项目中,提供可扩展的高性能推理服务解决方案。
我遵循这些指导方针,以确保向您提供宝贵、安全和尊重的帮助。作为一名乐于助人、可靠和值得信赖的助理,我致力于促进积极和公平的互动。通过避免有害、不道德、偏见或负面内容,我的目标是为所有用户创造一个有益和安全的环境。
看第二句,你会发现 LLM 产生幻觉。现在,将外部信息源添加到 LLM 中,以增强 LLM 以用于提示,并评估它是否提高了响应的准确性。
阅读 HTML 并拆分文本
请加载包含有关技术文档的网页列表,了解 NVIDIA Triton 推理服务器 的使用指南,以便更好地准备嵌入矢量存储。
# List of web pages containing NVIDIA Triton technical documentation
urls = [ "https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/index.html",
"https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/getting_started/quickstart.html",
"https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/user_guide/model_repository.html",
"https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/user_guide/model_analyzer.html",
"https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/user_guide/architecture.html",
]
documents = []
for url in urls:
document = html_document_loader(url)
documents.append(document)
分成块
接下来,将文档拆分为单独的块。一定要注意 chunk_size
参数在 TextSplitter 中的设置。正确的块大小对 RAG 性能具有至关重要的影响,因为 RAG 管道的成功很大程度上取决于检索步骤为生成找到正确的上下文。
检索步骤通常检查较小的原始文本块,而不是所有文档。整个提示(检索到的块加上用户查询)必须适合 LLM 的上下文窗口。不要指定太大的块大小,并用估计的查询大小来平衡它们。
例如,虽然 OpenAI LLM 的上下文窗口为 8–32K 个令牌,但 Llama2 仅限于 4K 个令牌。如果块太小,由于粒度高,重要信息可能不在检索到的最前面的块中。另一方面,如果块太大,它们可能不适合 LLM 上下文窗口,从而降低系统速度。
为了解决这个问题,在不同的块大小上建立一个集合检索,并对结果进行基准测试,以找到最佳值。通过在一组测试查询上循环集合,您可以计算每个块大小的平均倒数排名(MRR),以便更明智地决定 RAG 系统的最佳块大小。
使用不同的块大小进行实验,但典型值应为 100-600,具体取决于 LLM。
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=0,
length_function=len,
)
texts = text_splitter.create_documents(documents)
生成嵌入
接下来,使用生成嵌入 NVIDIA AI 基础设施端点 并将其保存到/embed 目录中的离线矢量存储,以供将来重用。
对于此任务,我们建议使用 FAISS 库,该库专门用于密集向量的高效相似性搜索和聚类。其特点是包含了在任何大小的向量集中搜索的算法,即使是可能不适合 RAM 的向量集。
embeddings = NVIDIAEmbeddings()
for document in documents:
texts = splitter.split_text(document.page_content)
# metadata to attach to document
metadatas = [document.metadata]
# create embeddings and add to vector store
if os.path.exists(dest_embed_dir):
update = FAISS.load_local(folder_path=dest_embed_dir, embeddings=embeddings)
update.add_texts(texts, metadatas=metadatas)
update.save_local(folder_path=dest_embed_dir)
else:
docsearch = FAISS.from_texts(texts, embedding=embeddings, metadatas=metadatas)
docsearch.save_local(folder_path=dest_embed_dir)
从矢量存储加载嵌入
借助 NVIDIA NeMo Retriever 文本嵌入模型,您可以创建嵌入模型,该模型能够将单词、短语或其他实体表示为数字向量,并捕捉单词和短语之间的语义关系。
embedding_model = NVIDIAEmbeddings()
embedding_path = "embed/"
docsearch = FAISS.load_local(folder_path=embedding_path, embeddings=embedding_model)
首先,使用 Chat NVIDIA 创建 ConversationalRetrievalChain 链。在这条链中,我将演示如何使用 LLM。
llm = ChatNVIDIA(model="ai-llama2-70b", temperature=0.1, max_tokens=1000, top_p=1.0)
qa_prompt=QA_PROMPT
doc_chain = load_qa_chain(llm, chain_type="stuff", prompt=QA_PROMPT)
qa = ConversationalRetrievalChain.from_llm(
llm=llm,
retriever=docsearch.as_retriever(),
chain_type="stuff",
memory=memory,
combine_docs_chain_kwargs={'prompt': qa_prompt},
)
询问有关 Triton 推理服务器的任何问题
现在尝试使用相同的提示并衡量差异。
query = "What interfaces does Triton support?"
result = qa({"question": query})
print(result.get("answer"))
NVIDIA Triton 推理服务器支持多种接口,包括 HTTP/REST 和 gRPC 推理协议。这些接口基于社区开发的 KServe 协议。此外,Triton 推理服务器提供了一个 C API 和 Java API,这使它能够直接链接到边缘和其他进程中用例的应用程序中。它还支持各种深度学习和机器学习框架,包括 TensorRT、TensorFlow、PyTorch、ONNX、OpenVINO、Python 和 RAPID FIL 等。
LLM 以最小的提示正确识别 Triton 推理服务器,并以技术上详细的响应进行响应。
query = "But why?"
result = qa({"question": query})
print(result.get("answer"))
Triton 推理服务器支持各种接口和框架,为开发人员和数据科学家提供灵活性和易用性。通过支持多种深度学习和机器学习框架,如 TensorRT、TensorFlow、PyTorch、ONNX、OpenVINO、Python、RAPID FIL 等,Triton 推理服务器允许用户部署最适合其项目需求的任何人工智能模型。这种互操作性有助于简化不同平台的人工智能推理过程,包括云、数据中心、边缘和嵌入式设备,并确保各种查询类型的优化性能。此外,Triton 推理服务器支持 HTTP/REST 和 gRPC 推理协议,这些协议在行业中得到了广泛使用和认可,使其成为人工智能推理服务的通用解决方案。
LLM 现在不再产生幻觉,因为它已经掌握了该领域的知识。
更复杂的链条
现在,我们使用两个 LLM 创建一个更复杂的链,一个用于摘要,另一个用于聊天。这改善了在更复杂的场景中的总体结果。我们使用 Llama2 70B 作为第一个 LLM,使用 Mixtral 作为链中的聊天元素,并添加question_generator
以生成相关的查询提示。
llm = ChatNVIDIA(model="ai-llama2-70b")
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
question_generator = LLMChain(llm=llm, prompt=CONDENSE_QUESTION_PROMPT)
chat = ChatNVIDIA(model="ai-mixtral-8x7b-instruct", temperature=0.1, max_tokens=1000, top_p=1.0)
doc_chain = load_qa_chain(chat , chain_type="stuff", prompt=QA_PROMPT)
qa = ConversationalRetrievalChain(
retriever=docsearch.as_retriever(),
combine_docs_chain=doc_chain,
memory=memory,
question_generator=question_generator,
)
以下是下一个查询和响应:
query = "What interfaces does Triton support?"
result = qa({"question": query})
print(result.get("answer"))
Triton 中支持的推理接口有:
*HTTP/REST*GRPC*二进制张量数据扩展*分类扩展*生成扩展*日志扩展*模型配置扩展*模型库扩展*调度策略扩展*序列扩展*共享内存扩展*统计扩展*跟踪扩展
这些接口允许广泛的用例,包括实时推理、批处理推理、集成推理和音频/视频流。此外,Triton 还提供后端 API,允许开发人员添加自定义后端和预/后处理操作,并支持使用 Ensembling 或 Business Logic Scripting(BLS)的模型管道。
现在以项目符号总结回应:
query = "But why?"
result = qa({"question": query})
print(result.get("answer"))
Triton 支持许多接口,为用户提供灵活性和多功能性。通过支持多种深度学习和机器学习框架,Triton 允许开发人员使用他们选择的框架,使他们更容易将 Triton 集成到现有的工作流程中。这种灵活性使 Triton 能够用于广泛的应用,从实时推理到批量处理,从基于云的服务到边缘设备。
后续回应也更加简洁。
如何评估
选择正确的指标来评估结果对于 RAG 系统至关重要。仅仅衡量准确性是不够的。相关性、没有幻觉以及平均响应时间等运行时指标也必须考虑在内。
LangChain 中包括了针对此类指标的 evaluators。
通过使用这些指标,您可以确保您的 RAG 系统准确、相关且没有幻觉,同时还可以提供快速高效的响应。
结论
RAG 已经成为一种强大的方法,结合了 LLM 和密集矢量表示的优势。通过使用密集矢量表示,RAG 模型可以有效地扩展,使其非常适合大型企业应用。
随着 LLM 的不断发展,很明显,RAG 将在推动创新和提供能够理解和生成类人语言的高质量智能系统方面发挥越来越重要的作用。
在构建自己的 RAG 管道时,重要的是要通过优化特定内容的块大小并选择具有适当上下文长度的 LLM,将矢量存储文档正确地拆分为块。在某些情况下,可能需要多个 LLM 的复杂链。要优化 RAG 性能并衡量成功与否,请使用一组强大的评估器和指标。
要开始,请查看作为此帖子的完整笔记本,该笔记本是 NVIDIA Generative AI 示例存储库的一部分。有关其他型号和链条的更多信息,请参阅NVIDIA AI LangChain 端点。