对超长文本进行总结

假如我们想要用 openai api 对一个段文本进行总结,我们通常的做法就是直接发给 api 让他总结。但是如果文本超过了 api 最大的 token 限制就会报错。

这时,我们一般会进行对文章进行分段,比如通过 tiktoken 计算并分割,然后将各段发送给 api 进行总结,最后将各段的总结再进行一个全部的总结。

如果,你用是 LangChain,他很好的帮我们处理了这个过程,使得我们编写代码变的非常简单。

废话不多说,直接上代码。

  1. from langchain.document_loaders import UnstructuredFileLoader
  2. from langchain.chains.summarize import load_summarize_chain
  3. from langchain.text_splitter import RecursiveCharacterTextSplitter
  4. from langchain import OpenAI
  5. # 导入文本
  6. loader = UnstructuredFileLoader("/content/sample_data/data/lg_test.txt")
  7. # 将文本转成 Document 对象
  8. document = loader.load()
  9. print(f'documents:{len(document)}')
  10. # 初始化文本分割器
  11. text_splitter = RecursiveCharacterTextSplitter(
  12. chunk_size = 500,
  13. chunk_overlap = 0
  14. )
  15. # 切分文本
  16. split_documents = text_splitter.split_documents(document)
  17. print(f'documents:{len(split_documents)}')
  18. # 加载 llm 模型
  19. llm = OpenAI(model_name="text-davinci-003", max_tokens=1500)
  20. # 创建总结链
  21. chain = load_summarize_chain(llm, chain_type="refine", verbose=True)
  22. # 执行总结链,(为了快速演示,只总结前5段)
  23. chain.run(split_documents[:5])

首先我们对切割前和切割后的 document 个数进行了打印,我们可以看到,切割前就是只有整篇的一个 document,切割完成后,会把上面一个 document 切成 317 个 document。

image-20230405162631460

最终输出了对前 5 个 document 的总结。

image-20230405162937249

这里有几个参数需要注意:

文本分割器的 chunk_overlap 参数

这个是指切割后的每个 document 里包含几个上一个 document 结尾的内容,主要作用是为了增加每个 document 的上下文关联。比如,chunk_overlap=0时, 第一个 document 为 aaaaaa,第二个为 bbbbbb;当 chunk_overlap=2 时,第一个 document 为 aaaaaa,第二个为 aabbbbbb。

不过,这个也不是绝对的,要看所使用的那个文本分割模型内部的具体算法。

文本分割器可以参考这个文档:https://python.langchain.com/en/latest/modules/indexes/text_splitters.html

chain 的 chain_type 参数

这个参数主要控制了将 document 传递给 llm 模型的方式,一共有 4 种方式:

stuff: 这种最简单粗暴,会把所有的 document 一次全部传给 llm 模型进行总结。如果document很多的话,势必会报超出最大 token 限制的错,所以总结文本的时候一般不会选中这个。

map_reduce: 这个方式会先将每个 document 进行总结,最后将所有 document 总结出的结果再进行一次总结。

image-20230405165752743

refine: 这种方式会先总结第一个 document,然后在将第一个 document 总结出的内容和第二个 document 一起发给 llm 模型在进行总结,以此类推。这种方式的好处就是在总结后一个 document 的时候,会带着前一个的 document 进行总结,给需要总结的 document 添加了上下文,增加了总结内容的连贯性。

image-20230405170617383

map_rerank: 这种一般不会用在总结的 chain 上,而是会用在问答的 chain 上,他其实是一种搜索答案的匹配方式。首先你要给出一个问题,他会根据问题给每个 document 计算一个这个 document 能回答这个问题的概率分数,然后找到分数最高的那个 document ,在通过把这个 document 转化为问题的 prompt 的一部分(问题+document)发送给 llm 模型,最后 llm 模型返回具体答案。