在大型语言模型(LLM)的应用中,有几个场景需要以结构化的方式呈现数据,其中信息提取和查询分析是两个典型的例子。我们最近通过更新的文档和一个专门的代码仓库强调了信息提取的重要性。对于查询分析,我们同样更新了相关文档。在这些场景中,数据字段可能包括字符串、布尔值、整数等多种类型。而在这些类型中,处理高基数的分类值(即枚举类型)是最具挑战性的。
图片
所谓的“高基数分类值”,指的是那些必须从有限的选项中选择的值,这些值不能随意指定,而必须来自一个预定义的集合。当这个集合中的有效值数量非常庞大时,我们称之为“高基数”。处理这类值之所以困难,是因为LLM本身并不知道这些可能的值是什么。因此,我们需要向LLM提供关于这些可能值的信息。如果忽略了这一点,LLM可能会自行编造值。对于只有少数几个可能值的情况,我们可以通过在提示中明确列出这些值来解决。但是,当可能的值非常多时,问题就变得复杂了。
随着可能值数量的增加,LLM正确选择值的难度也随之增加。一方面,如果可能的值太多,它们可能无法适应LLM的上下文窗口。另一方面,即使所有可能的值都能适应上下文,将它们全部包含在内会导致处理速度变慢、成本增加,以及LLM在处理大量上下文时的推理能力下降。
我们最近对查询分析进行了深入研究,并在修订相关文档时特别增加了一个关于如何处理高基数分类值的页面。在这篇博客中,我们将深入探讨几种实验性方法,并提供它们的性能基准测试结果。
结果的概览可以在LangSmithhttps://smith.langchain.com/public/8c0a4c25-426d-4582-96fc-d7def170be76/d?ref=blog.langchain.dev中查看。接下来,我们将详细介绍:
图片
数据集概览
详细的数据集可以在这里查看https://smith.langchain.com/public/8c0a4c25-426d-4582-96fc-d7def170be76/d?ref=blog.langchain.dev。
为了模拟这一问题,我们假设了一个场景:我们要查找某位作者关于外星人的书籍。在这个场景中,作者字段是一个高基数分类变量——可能的值有很多,但它们应该是特定的有效作者名字。为了测试这一点,我们创建了一个包含作者姓名和常用别名的数据集。例如,“Harry Chase”可能是“Harrison Chase”的别名。我们希望智能系统能够处理这类别名。有了这个姓名和别名列表后,我们又生成了10,000个随机姓名。需要注意的是,10,000的基数并不算高——对于企业级系统来说,可能要面对的是数百万级别的基数。
利用这个数据集,我们提出了这样的问题:“Harry Chase关于外星人的书有哪些?”我们的查询分析系统应该能够将这个问题解析为结构化格式,包含两个字段:主题和作者。在这个例子中,预期的输出应该是{“topic”: “aliens”,“author”: “Harrison Chase”}。我们期望系统能够识别出没有名为Harry Chase的作者,但Harrison Chase可能是用户想要表达的意思。
通过这种设置,我们可以针对我们创建的别名数据集进行测试,检查它们是否能够正确映射到真实姓名。同时,我们还会记录查询的延迟和成本。这种查询分析系统通常用于搜索,因此我们非常关心这两个指标。出于这个原因,我们也限制了所有方法只能进行一次LLM调用。我们可能会在未来的文章中对使用多次LLM调用的方法进行基准测试。
接下来,我们将介绍几种不同的方法及其性能表现。
图片
完整的结果可以在LangSmith中查看,复现这些结果的代码可以在这里找到。
基线测试
首先,我们对LLM进行了基线测试,即在不提供任何有效姓名信息的情况下,直接要求LLM进行查询分析。结果不出所料,没有一个问题得到了正确回答。这是因为我们故意构建了一个需要通过别名查询作者的数据集。
上下文填充法
在这种方法中,我们将所有10,000个合法的作者姓名都放入了提示中,并要求LLM在进行查询分析时记住这些是合法的作者姓名。一些模型(如GPT-3.5)由于上下文窗口的限制,根本无法执行这个任务。对于其他具有更长上下文窗口的模型,它们在准确选择正确姓名方面也遇到了困难。GPT-4只在26%的案例中选择了正确的姓名。它最常见的错误是提取了姓名但没有进行校正。这种方法不仅速度慢,成本也高,平均需要5秒钟才能完成,总成本为8.44美元。
LLM前过滤法
我们接下来测试的方法是在将可能的值列表传递给LLM之前进行过滤。这样做的好处是只传递可能姓名的子集给LLM,这样LLM需要考虑的姓名就少得多,希望能够让它更快、更便宜、更准确地完成查询分析。但这也增加了一个新的潜在失败模式——如果初步过滤出错怎么办?
基于嵌入的过滤法
我们最初使用的过滤方法是嵌入法,并选择了与查询最相似的10个姓名。需要注意的是,我们是将整个查询与姓名进行比较,这并不是一个理想的比较方式!
我们发现,使用这种方法,GPT-3.5能够正确处理57%的案例。这种方法比以前的方法快得多,也便宜得多,平均只需要0.76秒就能完成,总成本仅为0.002美元。
基于NGram相似性的过滤法
我们使用的第二种过滤方法是对所有有效姓名的3-gram字符序列进行TF-IDF向量化,并使用向量化的有效姓名与向量化的用户输入之间的余弦相似度来选择最相关的10个有效姓名添加到模型提示中。同样需要注意的是,我们是将整个查询与姓名进行比较,这并不是一个理想的比较方式!
我们发现,使用这种方法,GPT-3.5能够正确处理65%的案例。这种方法同样比以前的方法快得多,也便宜得多,平均只需要0.57秒就能完成,总成本仅为0.002美元。
LLM后选择法
我们最后测试的方法是在LLM完成初步查询分析后,尝试纠正任何错误。我们首先对用户输入进行了查询分析,没有在提示中提供任何关于有效作者姓名的信息。这与我们最初进行的基线测试相同。然后,我们进行了一个后续步骤,取作者字段中的姓名,找到最相似的有效姓名。
基于嵌入相似性的选择法
首先,我们使用嵌入法进行了相似性检查。
我们发现,使用这种方法,GPT-3.5能够正确处理83%的案例。这种方法比以前的方法快得多,也便宜得多,平均只需要0.66秒就能完成,总成本仅为0.001美元。
基于NGram相似性的选择法
最后,我们尝试使用3-gram向量化器进行相似性检查。
我们发现,使用这种方法,GPT-3.5能够正确处理74%的案例。这种方法同样比以前的方法快得多,也便宜得多,平均只需要0.48秒就能完成,总成本仅为0.001美元。
结论
我们对处理高基数分类值的查询分析方法进行了多种基准测试。我们限制了自己只能进行一次LLM调用,这是为了模拟现实世界中的延迟限制。我们发现,使用LLM后基于嵌入相似性的选择方法表现最佳。
还有其他方法值得进一步测试。特别是,在LLM调用之前或之后寻找最相似的分类值有许多不同的方法。此外,本数据集中的类别基数并不像许多企业系统所面临的那样高。这个数据集大约有10,000个值,而许多现实世界中的系统可能需要处理的是数百万级别的基数。因此,对更高基数的数据进行基准测试将是非常有价值的。