MapReduceDocumentsChain,这种链可以突破语言模型的 token 限制 ,能够处理大量的文档。使用它的时候可以提供一组文档,还有用户的问题,这个链会使用这这些文档与用户问题并行调用语言模型,最后它会把每次调用模型的时候返回来的结果合并到一块儿,连同用户问题一起交给模型再处理一次,让模型给出最终的答案。
在我的这个项目的 files 目录里有个文本文件,名字是 nid-startup.txt ,里面主要是跟宁皓网的独立开发者训练营相关的内容,如果想让模型总结一下这段文字,或者根据这段文字问一些问题,直接调用语言模型是不行的,因为这些内容已经超过了语言模型能够处理的 token 数量。下面我们试一下用 MapReduceDocumentsChain 解决这个问题。
在这个程序文件的顶部,先导入一个 TextLoader,它来自 langchain/document_loaders/fs/text,再导入 RecursiveCharacterTexSpliter,它来自 langchain/text_splitter。
新建一个内容分割器,声明一个 splitter,新建一个 RecursiveCharacterTextSplitter,提供一个对象参数,可以设置一下块的大小,添加一个 chunkSize,值可以设置成 3000.
然后再声明一个 loader,它的值可以新建一个 TextLoader,给它提供一个文本文件的路径,当前目录 files 下面的 nid-startup.txt。下面声明一个 documents 表示一组文档,等于 await,用一下 loader 上面的 loadAndSplit,提供一个分割器,可以用一下上面定义的这个 splitter。在控制台上输出这个 documents。
在终端,执行 node index.mjs,这里输出的就是根据一个文本文件生成的一组文档。按大小切分以后生成了 3 个文档。
loadQAMapReduceChain
回到项目,在文件顶部导入 loadQAMapReduceChain,它来自 langchain/chains。在下面声明一个 chain,用一下 loadQAMapReduceChain ,它可以返回一个 MapReduceDocumentsChain,把 model 交给这个函数。
下面声明一个 response,它的值等于 await,用一下 chain 上面的 call 这个方法,提供一个对象,里面设置一下 input_documents,对应的值是 documents,然后再添加一个 question ,对应的值就是想问的问题,比如 “用中文总结一下这篇文章”。在控制台上输出 response 检查一下。
创建 OpenAI 模型的时候,我们可以设置一下它的 maxConcurrency ,比如设置成 2 ,不然可能会发生频率限制的错误。
在终端,运行一下应用,先观察一下调用模型的时候输出的 prompt。这里有一组提示,这个提示里指出下面是一个长文档里的一段文章,请根据用户问题给出相关的答案。这里先是一个文档里的文本内容,向下滚动,在提示的结尾这里会有用户的 Question,也就是用户的问题。然后让模型根据上文给出这个问题相关的内容。
下面这个提示也是一样的,让模型根据文档内容给出问题的答案,在最后一个提示里,给出了如何回答问题的一些示范,往下浏览,你会发现这里有用户的问题,下面是根据三个文档内容生成的与这个问题相关的一些内容,然后让模型根据这些内容再给出最终的答案。
最后输出的响应就是模型最终给出的答案,这里就是总结了一下篇文章。
再测试一下,问一个问题,比如 “在训练营能学到什么?” 在终端,运行一下应用,MapReduceDocumentsChain 会并行使用不同的文档向模型提问,最后再让模型汇总一下,生成最终的答案。