LLM - 长文本总结处理方案

目录

一.引言

二.处理方式

1.Stuff

2.Map Reduce

3.Refine

4.Map Rerank

5.Binary Map

三.总结测试

1.总结内容

2.Langchain 启动

3.自定义逻辑

四.总结


一.引言

随着 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 能否并行就看我们能起几个服务了。

四.总结

长文总结是很典型常见的问题,大家有更多想法和意见也欢迎在评论区交流讨论~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIT_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值