在之前的一篇文章——推荐几个可以免费使用的ChatGPT工具 的最后,简单分析了下ChatGPT检索类应用的原理,当时写了自己认为可以优化的地方。
结果昨天看到了Andrej Karpathy大神发的一条推特,主要针对之前那篇文章没有提到的第三点——召回相关性最高的句子集合——提出了一种改进方法。截图如下:
Andrej Karpathy’s twitter
关于大神的履历这篇文章不做介绍,详细内容可以查看karpathy.ai。
这篇文章就来详细讲一下ChatGPT检索类应用的原理以及可以改进的方法。
整体流程
ChatGPT检索类应用的表现形式多种多样,但基本原理都如下如图所示:
从图片中可以看出,最主要的步骤就是图中箭头上的文字:
- 各种类型的文档解析
- 文本内容向量化(包括文档与用户输入两部分)
- 相关内容召回
- 利用用户输入的问题和召回的相关内容为大语言模型构造Prompt,获取输出
检索类应用最常见的就是搜索引擎,不过在传统的搜索引擎中,由于检索空间巨大,一般是没有向量化这一步的。但是在基于ChatGPT的检索空间一般来说都很小,另外采用向量化的方法,可以召回语义上更相似内容。
下面就简要描述上述4个方面的难点与改进方法。
各种类型的文档解析
这里的难点主要在于以下三个方面:
- 不同类型文档中的特殊格式需特殊处理,例如PDF类型文档解析中的分栏、跨段、跨页内容合并、无边框表格等等
- 文档中除了包含纯文本,还可能包含图片、表格等内容
- 不同场景下的文档结构不一样,比如论文解读场景下,论文的结构包含作者、摘要、方法、结论等
针对上述三个难点,改进的方法主要如下:
- 针对不同类型文档开发不同的解析方式,降低解析错误对检索结果的影响
- 针对不同的内容类型(文本、表格、图片),采用统一的表示方法
- 针对不同场景,开发特定的文档表示结构
文本内容向量化
文本内容向量化包含了两点:
- 文本内容分割/截断
- 文本内容向量化
其中,文本内容分割目前大部分工具采取的是固定长度的分割方式。这里其实可以采用句子的方式对原始文本内容进行分割。
文本内容向量化,应选取在待处理文档内容的向量化效果较好的模型,若有可能,可以在预训练模型上使用自己的数据进行微调。
常见的句子向量化模型可以参考huggingface的sentence transformer页面。
相关内容召回
这一步,主要处理的是向量化后的句子之间的距离度量,最直接的方式就是cosine距离或者欧式距离。其中cosine距离消除了向量本身长度的影响。
另外,Andrej Karpathy提出了一种使用SVM模型进行召回排序的方法,具体做法如下:
目的:
从文档中召回与用户提问最相关的文档内容
输入:
x : 用户提问对应的embedding
X=[x_1, x_2, ..., x_n] : 向量化后的文档内容
步骤:
1 将x视为正例,X视为负例,训练一个SVM分类器C
2 使用训练好的分类器C,对X中的内容进行打分,得到打分结果S
3 将S从大到小排序,前k个下标对应的内容即为应该召回的内容
当然,上述方法显然存在几个问题:
- 每当用户输入一个问题,就需要生成一个分类器,影响回答的实时性
- 训练分类器时,正样本仅有一个,正负样本差别过大,可能影响分类效果
但Andrej Karpathy在推特中说,第一个问题确实存在,但在1万条1536维的数据集上一般1秒左右可以训练好一个SVM分类器。针对第二个问题,他解释说采用了这种方法召回的结果要比原始的KNN的方法要好很多。
就在Andrej Karpathy提出这个想法没多久之后,LangChain(一个大语言模型集成工具)就将SVM集成为了SVM Retriever。
prompt构造
这一步做的主要工作就是将用户提问和召回的相关文档组装后,投喂给大语言模型。
这里可以根据不同的场景设定不同的提示词和组装方法,具体可以参考之前的一篇文档——如何更好地使用ChatGPT类大语言模型?这儿汇总了一份prompt指引。
以上就是目前ChatGPT检索类应用的原理,可能再过一段时间,某些步骤又有了新的解决方法,到时再来更新。
更多内容,欢迎关注【算法工程笔记】公众号。