次优的嵌入模型、低效的分块以及缺乏元数据过滤可能会影响LLM响应的相关性。以下是应对方法。
译自 Fixing Relevancy in Retrieval Augmentation。作者Chris Latimer是DataStax的产品管理副总裁,领导公司在事件流和云消息传递方面的产品策略。 在加入DataStax之前,克里斯在谷歌、NetJets和Apigee等公司担任软件工程师、架构师和产品经理,在技术领域工作了20多年。
构建采用检索增强生成(RAG)的生成式AI应用程序可能面临各种挑战。让我们来看看依靠向量数据库检索相关上下文,然后将其融入提示送入大语言模型(LLM),以提供更相关结果的RAG实现的故障排除。
我们将这个过程分成两个主要部分。第一个是嵌入流水线,它用嵌入填充向量数据库:
在这里,我们将考察三个可能导致糟糕结果的主要领域:次优的嵌入模型、低效的分块策略以及缺乏元数据过滤。
第二个领域是与LLM的实际交互,这里用简化的形式表示:
我们将检查一些常见的问题,这些问题可能导致糟糕的结果,包括不精确的提示和不充分的生成方法。
您选择的嵌入模型将对RAG应用程序的整体相关性和可用性产生重大影响。因此,这需要对每个模型的功能以及这些功能与应用程序要求的匹配进行细致的理解。
如果您对RAG和嵌入整体比较陌生,您应该知道的最好资源之一是MTEB(大规模文本嵌入基准)嵌入排行榜。本文重点关注检索用例,但嵌入当然可以用于许多其他应用,包括分类、聚类和总结。该排行榜可以帮助您确定对特定用例表现最佳的模型。
RAG性能差的一个最常见原因是开发人员刚接触这个领域,进行谷歌搜索以找到嵌入生成的示例。他们经常发现使用Word2Vec、sBERT和RoBERTa等嵌入模型的样本代码,而这些模型对于检索用例来说是糟糕的选择。如果您由于相关性结果差而找到这篇文章,并且您使用了类似sBERT的模型生成嵌入,那么我们可能已经找到了相关性问题的原因。
如果是这样,您下一个自然的问题可能是哪些嵌入模型可以用来改进相似性搜索结果。在不知道您的具体用例的情况下,我们推荐的三个是:
来自OpenAI的Ada v2可能是大多数RAG应用程序的最常见起点,简单是因为许多开发人员一开始就使用OpenAI的API。Ada v2在检索用例中表现突出,它是为处理不同类型的内容(包括文本和代码)而构建的。它支持长达8192个标记的最大输入序列长度,也允许您为比替代模型更长的文本创建嵌入。这既是优势也是劣势。拥有大序列长度简化了为更多文本内容创建嵌入的过程,它允许嵌入模型在更大的文本体中识别单词和句子之间的关系。
然而,这也会导致在比较两个长文档的相似性时结果变得模糊,而您正在寻找的是相关上下文以促进生成过程。
Ada v2有两个主要缺点。第一个是它不能在本地运行。您必须使用OpenAI的API来创建嵌入。这不仅可能在您希望为许多内容创建嵌入的情况下引入瓶颈,而且还增加了每1000个标记0.0001美元的成本。第二个是OpenAI模型创建的嵌入每个都是1536维的。如果您使用云向量数据库,这可以大大增加向量存储成本。
何时选择:您需要一个只需要API调用的简单解决方案,您可能需要为大型文档建立向量,成本不是问题。
Jina v2是一个新的开源嵌入模型,它为您提供与Ada v2相同的8000输入序列支持,实际上在检索用例中得分略高。
Jina v2提供了对Ada v2问题的解决方案。它是Apache许可证2.0下的开源,可以在本地运行,当然,如果您不想运行自己的代码来做到这一点,这也是一个劣势。它还产生一个具有Ada v2一半维数的嵌入向量。因此,不仅在基准用例的检索性能方面略胜一筹,而且还以较低的存储和计算需求从向量数据库角度获得了这些改进的结果。
何时选择:您希望使用开源解决方案,可能需要为大型文档建立向量,并且适应在本地运行嵌入管道。您想要降低矢量数据库成本,使用较低维度的嵌入。
bge-large-en-v1.5在MIT许可下开源,目前在检索用例的MTEB排行榜上排名第一的嵌入模型。带有更小的输入序列,它将需要您更多地考虑分块策略,但最终为检索用例提供了最佳的全面性能。
何时选择:您希望使用开源解决方案,并愿意花更多时间研究分块策略,以适应输入大小限制。您适应在本地运行嵌入管道。您想要检索用例中表现最佳的嵌入模型。
虽然超出本文的范围,但您可能需要更深入地研究MTEB排行榜中的15个基准,以确定最接近您特定情况的基准。虽然各种嵌入模型在不同基准中的表现确实存在模式,但通常每个基准中都有特定的模型脱颖而出。如果您需要进一步优化嵌入选择,这是一个可能的进一步调查区域。
输入文本的分割或“分块”是关键因素,它会显著影响生成输出的相关性和准确性。各种分块策略提供了独特的优势,适用于特定类型的任务。在这里,我们深入研究这些方法,并提供应用建议,结合一些关键注意事项:
作为一种通用方法,在尝试将大型语料库分块并向量化之前,您应该考虑对数据进行一些特殊实验。手动检查在给定查询下您希望检索的文档,确定表示您希望为LLM提供的理想上下文的块,然后尝试不同的分块策略,看哪种策略为LLM提供您认为最相关的块。
LLM的可用上下文窗口是选择分块策略的一个重要因素。如果上下文窗口很小,您需要在馈送模型的数据块中进行更选择性的选择,以确保包含最相关的信息。相反,更大的上下文窗口允许更大的灵活性,即使并非所有内容都严格必要,也可以包含可能增强模型输出的额外上下文。
通过实验这些分块策略并考虑这些因素,您可以评估它们对生成输出相关性的影响。关键是将所选策略与RAG应用程序的具体要求相匹配,保持输入的语义完整性,并对上下文进行全面理解。这将使您能够找到最佳性能的正确分块流程。
随着搜索索引中的嵌入数量的增长,近似最近邻居(ANN)在查找相关上下文以包含在提示中的用处变得不大。假设您在知识库中为200篇文章建立了索引嵌入。如果您可以以1%的准确率识别最近的邻居,那么找到非常相关的结果的可能性很高,因为1%代表200篇文章中的前两篇文章,您将获得这两篇文章之一。
现在考虑一个包含维基百科上每一篇文章的搜索索引。这大约是670万篇文章。如果您的最近邻居位于最相似文章的前1%,这意味着您将获得约67,000篇最相似文章之一。对于像维基百科这样的语料库,这意味着您最终仍可能偏离目标。
元数据过滤提供了一种方法,可以先过滤文档,然后再应用最近邻算法来缩小内容块的范围。在处理大量可能匹配的情况下,这种初始预过滤可以帮助您在检索最近的邻居之前缩小可能的选项。
即使是最好的嵌入和分块策略也无法取代高质量的提示工程的需要。这涉及使提示更明确、更具体和更符合预期输出。应该测试各种提示格式、长度和词汇选择以微调RAG过程。
具体来说,在为RAG应用程序构建提示时,您应该考虑几件事。这些包括:
告诉LLM其角色: 与ChatGPT等LLM代理交互时,它们默认会充当有帮助的聊天机器人。但是,您可以通过指示LLM以特定方式行事来改变将生成的响应的性质。示例可以是“你是一个律师,正在评估任何一方是否违反了协议”或“你是互联网服务提供商的客户服务代理;您的工作是帮助人们解决互联网问题”或任何与您的特定情况相关的内容。
明确告诉LLM使用提供的上下文: 明确告诉LLM您正在提供上下文,并且您希望生成的响应反映该上下文。您可以通过说“您的响应应考虑以下上下文”然后添加上下文来实现这一点。
使用示例: 在上述要求LLM充当评估合同的律师的场景中,您可能希望在提示中包含几个示例。例如,您可以提供一个合同示例,说明在合同签署后30天内应付款,但买方在合同签署后40天才发送付款,因此违反了协议。您可以提供有关补救权利和可能的合同违约解决方法的额外示例。
指定输出格式: 如果您的用例需要特定输出,您可以指定生成输出应遵循的格式。您可以将这种技术与上述提示相结合,以提供示例,使LLM明确知道您希望它如何响应以及您希望生成的响应中需要包含的关键信息点。
使用思路链: 对于需要推理才能确定适当响应的用例,您可以考虑使用一种称为思路链的技术来帮助解释您希望LLM遵循的步骤以得出生成的响应。例如,在法律合同的例子中,您可能希望引导LLM遵循人员确定合同条款是否已违反的逻辑步骤。例如,在处理法律合同时,您可能会告诉LLM首先查找指定付款条款的条款,然后确定买方提交付款的时间,然后计算收到付款与签订合同日期之间的天数。然后,如果付款时间超过了约定的时间范围,买方就违反了协议。
利用这些技术改进提示工程可以显著提高您能够在RAG应用程序中生成的结果质量。但是,有时您需要使用涉及与LLM多次交互的技术才能获得可接受的响应。
前向主动检索(Forward-looking active retrieval,FLARE)是一种多查询RAG技术的例子,它涉及在提示中以定制指示迭代调用LLM,要求LLM提供有关关键短语的额外问题,这些关键短语将有助于它生成更好的答案。一旦LLM具有无间隙的上下文,它就会以最终响应结束。该过程在LLM和AI代理(图中的AI聊天机器人)之间添加了一个循环,以促进这些迭代:
您可以在LangChain Cookbook的FLARE示例中看到FLARE的工作方式。
通过生成类似用户查询的查询并为原始查询和生成的类似查询检索相关上下文,我们能够增加选择最有用上下文来生成准确结果的可能性。该过程称为“RAG融合”,如下所示:
这里的关键步骤是利用排名函数进一步优化ANN结果,以确定要使用的生成响应的最相关上下文。