LLM长文本处理方案详解:五种主流方法及实践指南
LLM长文本处理方案详解:五种主流方法及实践指南
随着大语言模型(LLM)的进步,支持的token数量不断增加,从最初的4k、8k扩展到现在的16k、32k,这使得处理更长的文本内容成为可能。然而,随之而来的是资源限制和理解能力不足等问题。本文将介绍五种常见的长文本处理方案,并通过代码示例展示如何在实践中应用这些方案。
一.引言
随着LLM的进步,目前支持的token数目也在逐步增加,从最开始的4k、8k延伸到现在的16k、32k,从而可以支持更长的文本内容,但是随之而来的问题也不少:
机器资源不足
虽然模型支持的token数目变长了,但是我们手头显卡的资源可能是限制token长度的主要原因,因此对于一些长文本总结内容,虽然其在模型支持的token例如32k之内,但是我们的显存不足以支撑一下放入全部样本,因此GPU显存是一个限制条件。理解能力不足
在资源充足的情况下,很多开源模型对长文本的理解和总结能力还存在不足的情况,如果一次输入过多token,LLM往往抓不到重点,或者出现幻觉的情况,因此对于长文总结,如何能够尽可能把每个段落都理解到也是一个关键点。
二.处理方式
1.Stuff
该方式是最直截了当的长文处理方式,一次性将所有内容输入给LLM理解。
优点
只调用一次LLM,上下文完整便于模型理解全貌,直截了当。缺点
对GPU资源、模型理解能力有很大要求,其次处理的max_token与当前LLM匹配,对于更长的文本仍然存在限制。
2.Map Reduce
写过MR处理数据的同学应该不陌生,其类似于分布式处理的概念,先将长文本分多段采用多个mapper进行处理,再使用reducer对所有mapper的结果进行聚合,最终得到总结。
优点
理论上Mapper可以无限多,因此处理的文本总长度也很可观,支持横向扩展。同时由于是Map-Reduce结构,因此支持并发,可以一次处理多条Doc Block,因此执行效率也支持伸缩扩展。缺点
一次总结需要多次调用LLM,其次总结时单块Mapper容易有信息丢失,且总结和Block的切分也有关系,如果Block切分不佳,会造成大量上下文的缺失,影响总结效果。
3.Refine
与MR类似,先将长文本进行Block切分为多个小块进行分块合并总结,然后采用类似链式的总结过程,不断进行合并,最终生成全文的总结。
优点
相比Map Reduce该方法相对会少丢失一些信息,而且潜在有序的概念,因为是串行总结的,每一个总结都依赖上一个块的信息。缺点
需要多次调用LLM,而且由于每一个结果依赖上一个结果,因此生成阶段无法像Map Reduce那样并行,只能串行,文本过长时生成时间也会受影响。
4.Map Rerank
对长文进行Block操作,返回结果时同时返回并取相关性分数最高的分块总结作为结果。
优点
对文章进行分块总结,可以并行执行,效率高。缺点
多次调用LLM,无法进行全文总结,适合在文档中基于一些相关性指标检索最适合的分块。
5.Binary Map
对长文进行Block操作,返回结果按照二分的方式进行合并。
优点
对于block过多的场景,为了性能与效果的折中,可以选择Binary二分的方式进行总结合并,这样可以提高合并的效率。缺点
两两组合的方式与前面的MR类似,也会丢失一部分信息,但是会少丢,当然这里2也是一个超参,我们也可以使用3、4、5等等,这个需要结合具体业务场景。
Tips:该方法是博主自己想的,因此Binary Map这个mode在Langchain里还不支持,需要自己写逻辑。
三.总结测试
1.总结内容
URL:三国演义读后感
2.Langchain启动
import os
from langchain import OpenAI
from langchain.chains.summarize import load_summarize_chain
from langchain.chains import AnalyzeDocumentChain
from langchain.text_splitter import CharacterTextSplitter
os.environ["OPENAI_API_KEY"] = "your_api_key"
CHAIN_TYPE = "stuff"
long_text = "/Users/ddd/langchain/LongText.log"
with open(long_text, 'r', encoding='utf-8') as f:
state_of_the_union = f.read()
llm = OpenAI(temperature=0.95)
# 定义文本分割器 每块文本大小为500,不重叠
text_splitter = CharacterTextSplitter(
chunk_size=500,
chunk_overlap=0,
length_function=len,
)
# 生成摘要
summary_chain = load_summarize_chain(llm, chain_type=CHAIN_TYPE)
summarize_document_chain = AnalyzeDocumentChain(combine_docs_chain=summary_chain, text_splitter=text_splitter)
res = summarize_document_chain.run(state_of_the_union)
print(res)
3.自定义逻辑
需要定义自己的API-KEY,文本我们选择上面的三国演义总结,由于么有API-KEY这里程序也Run不起来,我们需要手动实现上面的Mapper或者总结逻辑,再自己构建Prompt逻辑:
初始化自己的LLM
可以选择开源的LLM,使用HuggingFace的Auto API直接加载。选择自己的长文进行切分
虽然OpenAI不能用,但是TextSplitter可以用。
chunks = text_splitter.split_text(state_of_the_union)
for chunk in chunks:
print(chunk)
- 基于不同的处理方式总结
根据上面Stuff、MR、Refine和Map Rerank的逻辑图实现自己的总结逻辑查看总结效果。不过由于我们本地机器的限制,Mapper能否并行就看我们能起几个服务了。
四.总结
长文总结是很典型常见的问题,大家有更多想法和意见也欢迎在评论区交流讨论~
