为了账号安全,请及时绑定邮箱和手机立即绑定

如何利用LangChain和OpenAI快速概括大型文档,提升总结效率

大型语言模型已使许多任务变得简单多了,例如开发聊天机器人、语言翻译、文本摘要等。过去在为摘要任务编写模型时,我们总会遇到性能问题。现在,我们可以使用大型语言模型(LLM)轻松完成这些任务。例如,最先进的大型语言模型可以处理整个书籍的上下文窗口。但在处理非常大的文档时进行摘要,仍然存在一些限制。

大型文档总结中LLM的局限性

上下文限制在大型语言模型(简称LLM)中指的是模型能处理的标记数。每个模型都有自己的上下文长度,也称为最大标记数或标记限制。例如,标准GPT-4模型的上下文长度为128,000个标记。超过这个数量的标记将被忽略,导致信息丢失。一些最新的LLM的上下文限制可以达到100万个标记。然而,随着上下文限制的增加,LLM会遭受近期效应和首因效应(即近期效应和首因效应)等限制。我们还可以讨论缓解这些效应的方法。

  • Primacy effect 在大语言模型中是指模型更倾向于最早出现的信息。
  • Recency effect 是指模型强调最近处理的信息。

这两种效应会使模型对输入数据中的特定部分产生偏好,可能会忽略序列中间的重要内容。

第二个问题是成本。我们可以通过拆分文本来解决第一个问题(即上下文限制),但是我们不能直接将整本书传递给模型,这会花费很多钱。例如,比如有一本书有100万个token,直接将其传递给GPT4模型,我们的总成本大约是90美元(提示和完成的token)。我们需要找到一种折中的方法,以考虑价格、上下文限制以及书的完整内容来概括文本。

在这次教程里,你将学习如何在考虑价格和模型的限制下总结整本书。我们开始吧。

使用LangChain和OpenAI概括长文档
配置环境

要跟随本教程,您需要:

(注:原文未列出具体要求)

  • 已安装Python
  • 一个IDE(如VS Code)

安装依赖项,请打开终端窗口并输入命令:

请运行以下命令来安装所需的软件包:

pip install langchain openai tiktoken fpdf2 pandas

这条命令会安装所有必需的依赖包。

加载书

你将使用查尔斯·狄更斯的小说《大卫科波菲尔》,这本书是公开可获取的。让我们用LangChain提供的PyPDFLoader加载这本书。

    从langchain.document_loaders导入PyPDFLoader  

    # 加载PDF文件  
    loader = PyPDFLoader("David-Copperfield.pdf")  
    pages = loader.load_and_split()

它会加载整本书,但我们只对正文感兴趣。我们可以跳过前言和开场白等页面。

    # 去掉开头和结尾部分
    pages = pages[6:1308]
    # 合并页面,并将制表符替换成空格
    text = ' '.join([page.page_content.replace('\t', ' ') for page in pages])

现在我们已经有了内容,让我们打印前200个字符的内容吧。

    text[0:200]
预处理

让我们从文本中去掉像不可见字符、多余空格等等不必要的内容。

    import re  
    def 清理文本(text):  
       # 移除特定短语 'Free eBooks at Planet eBook.com' 及其周围的空白  
       cleaned_text = re.sub(r'\s*Free eBooks at Planet eBook\.com\s*', '', text, flags=re.DOTALL)  
       # 移除多余的空格  
       cleaned_text = re.sub(r' +', ' ', cleaned_text)  
       # 移除 'David Copperfield' 之前或之后的不可打印字符  
       cleaned_text = re.sub(r'(David Copperfield )?[\x00-\x1F]', '', cleaned_text)  
       # 将换行符替换为空格  
       cleaned_text = cleaned_text.replace('\n', ' ')  
       # 移除连字符周围的空白  
       cleaned_text = re.sub(r'\s*-\s*', '', cleaned_text)  
       return cleaned_text  
    result=清理文本(text)

清洗数据后,我们可以开始进行总结了。

导入OpenAI API

// 如果需要注释,可以使用“//”或“/ /”格式。API等术语保持英文,符合中文技术圈的习惯。

在使用OpenAI API之前,我们需要在这里设置并提供凭证信息。

    import os  
    # 设置OpenAI API密钥
    os.environ["OPENAI_API_KEY"] = "your-openai-key-here"

在那里输入你的API密钥,它会自动设置环境变量。

我们来看看这本书里有多少个token:

    from langchain导入OpenAI  
    llm = OpenAI()  
    Tokens = llm.get_num_tokens(clean_text)  
    print(f"这本书里有{Tokens}个token")

这本书有超过466,000个词汇单元,如果我们直接全部输入给语言模型,成本会很高。因此,为了降低成本,我们将使用K-means聚类算法来提取书中的重要片段。

注意:使用K-means聚类算法的决定是受到数据达人Greg Kamradt的教程(https://www.youtube.com/watch?v=qaPMdcCqtWk&t=870s&ab_channel=GregKamradt%28DataIndy%29)的启发。

为了得到书中的重点,我们先把它分成几部分吧。

将内容分成单独的文档

我们将使用LangChain的SemanticChunker工具将书拆分成多个文档。

    从 langchain_experimental.text_splitter 导入 SemanticChunker  
    从 langchain_openai.embeddings 导入 OpenAIEmbeddings  
    text_splitter = SemanticChunker(  
        OpenAIEmbeddings(), breakpoint_threshold_type="interquartile"  
    )  
    docs = text_splitter.create_documents([clean_text])

SemanticChunker接收两个参数,分别是嵌入模型和breakpoint_threshold_type。嵌入模型生成的嵌入用于根据语义将文本分割成不同的段落。breakpoint_threshold_type决定了文本在哪些点上应该被分割成不同的段落,依据语义相似度。

注意:通过处理这些较小的、语义上相似的块,我们旨在减少在我们的大型语言模型(LLM)中的近期效应和初始效应。这一策略使我们的模型能够更好地处理每个小的上下文,从而实现更加平衡的解释和响应生成。

获取每个文档的嵌入

现在,我们来获取每个生成文档的嵌入表示吧。你会用OpenAI的默认方法来获取这些嵌入。

import numpy as np  
import openai  
def get_embeddings(text):  
   response = openai.embeddings.create(  
       model="text-embedding-3-small",  
       input=text  
   )  
   return response.data  
# 获取文档内容的嵌入表示
embeddings=get_embeddings([doc.page_content for doc in docs])  

get_embeddings 方法可以得到所有文档的嵌入表示。

请注意:text-embedding-3-small 方法是由 OpenAI 特别发布,被认为更便宜且更快。

整理数据

接下来,我们将文档内容列表及其嵌入转换成pandas的DataFrame,以便更方便地进行数据处理和分析。

    import pandas as pd  
    content_list = [doc.page_content for doc in docs]  # Extract page content from each document
    df = pd.DataFrame(content_list, columns=['page_content'])  # Create a DataFrame with the content list
    vectors = [embedding.embedding for embedding in embeddings]  # Extract embeddings from each embedding object
    array = np.array(vectors)  # Convert the list of vectors to a numpy array
    embeddings_series = pd.Series(list(array))  # Convert the array to a pandas Series
    df['embeddings'] = embeddings_series  # Add the embeddings to the DataFrame
使用Faiss来做高效的聚簇

现在,我们将文档向量转换为与Faiss兼容的格式,之后使用K-means将其聚成50个簇,并为文档之间的相似度搜索创建一个Faiss索引。

    **<code>import numpy as np \  
    import faiss \  
    <em>//如果不是 float32 类型,转换为 float32</em> \  
    array = array.astype('float32')  \  
    num_clusters = 50 \  
    <em>//向量维度</em> \  
    dimension = array.shape[1]  \  
    <em>//使用 Faiss 训练 K-means</em> \  
    kmeans = faiss.Kmeans(dimension, num_clusters, niter=20, verbose=True) \  
    kmeans.train(array) \  
    <em>//直接访问聚类的中心</em> \  
    centroids = kmeans.centroids  \  
    <em>//为原始数据集创建索引</em> \  
    index = faiss.IndexFlatL2(dimension) \  
    <em>//将原始数据集添加进索引</em> \  
    index.add(array)</code></strong>

这些文档会被分成50个组,通过这种K-means算法。

注意:选择K-means聚类的原因在于,每个聚类将具有相似的内容和上下文,因为该聚类内的所有文档都具有相关的嵌入,我们将选择离中心最近的那个。

选择要导入的文档

我们就挑选最重要的文档。为此,我们只会选择最接近簇中心的向量,从每个簇中进行挑选。

D, I = index.search(centroids, 1)  # 寻找最接近的中心点

这段代码使用了索引上的搜索方法,找到每个质心最近的那个文档。它返回两个数组:D,包含每个质心到其最近文档的距离;I,包含这些最近文档的索引号。搜索方法中的第二个参数1指定了只为每个质心找到最近的那个文档。

现在我们需要对选定的文档编号进行排序,因为这些文档是按照书里的顺序排列的。

    将 sorted_array 设置为 np.sort(I, axis=0) 的结果。  
    将 sorted_array 平铺。  
    从 sorted_array 中提取 docs 的文档。
获取每个文档的概要,

下一步是使用GPT-4模型为每个文档生成摘要以节省成本。在使用GPT-4之前,我们先来定义一下这个模型。

    model = ChatOpenAI(temperature=0, model="gpt-4")  # 这里设置了聊天模型为gpt-4,温度为0

先定义好提示,做个提示模板出来,然后通过LangChain传给模型。

from langchain_core.output_parsers import StrOutputParser  
from langchain_openai import ChatOpenAI  
from langchain_core.prompts import ChatPromptTemplate  
提示 = ChatPromptTemplate.from_template("""  
你将一次接一次地收到一本书的不同段落,并对它们进行总结。请对以下文本进行总结。你的结果必须详细,并至少包含两段落。在总结时,直接进入文本的叙述或描述,不需要使用类似 '在这一段中' 的引言。直接描述主要事件、角色和主题,将文本中的精髓和重要细节以流畅的方式呈现出来。目标是提供一个统一的内容视图,使内容像自然过渡到总结中一样流畅地继续下去。  

段落:  

```{text}```  
摘要:  
"""  
)

这个提示模板将帮助模型更有效地总结文件。

接下来的步骤是使用LCEL(LangChain表达语言)来定义一个这样的LangChain。

chain = ( 提示 | 模型 | StrOutputParser() )

汇总链使用StrOutputParser用以解析结果。此外,还有其他解析器可以进一步了解。

你可以最后应用定义的链到每个文档上,从而得到摘要。

    from tqdm import tqdm  
    final_summary = ""  

    for doc in tqdm(extracted_docs, desc="Processing documents"):  
       # 获取新的摘要。  
       new_summary = chain2.invoke({"text": doc.page_content})  
       # 更新摘要列表:移除最早的一个摘要并添加新的摘要到最后:  
       final_summary+=new_summary

上述代码对每个文档依次应用链式操作,并将每个摘要添加到final_summary

将摘要保存为PDF。

下一步是将摘要保存为PDF文件并整理好。

    从fpdf导入FPDF  

    class PDF(FPDF):  
       def header(self):  
           # 选择Arial粗体15  
           self.set_font('Arial', 'B', 15)  
           # 向右移动  
           self.cell(80)  
           # 带边框的标题  
           self.cell(30, 10, '摘要', 1, 0, 'C')  
           # 换行  
           self.ln(20)  

       def footer(self):  
           # 距底部1.5厘米处  
           self.set_y(-15)  
           # 选择Arial斜体8  
           self.set_font('Arial', 'I', 8)  
           # 页面编号  
           self.cell(0, 10, '第%s页' % self.page_no(), 0, 0, 'C')  

    # 创建PDF对象并添加一页  
    pdf = PDF()  
    pdf.add_page()  
    pdf.set_font("Arial", size=12)  

    # 确保'last_summary'文本被正确地处理成UTF-8格式  
    # 请将'last_summary'替换为你的实际文本变量  
    # 请确认你的文本已经转换为utf-8编码的字符串  
    last_summary_utf8 = last_summary.encode('latin-1', 'replace').decode('latin-1')  
    pdf.multi_cell(0, 10, last_summary_utf8)  

    # 将PDF保存为文件's_output1.pdf'  
    pdf_output_path = "s_output1.pdf"  
    pdf.output(pdf_output_path)

那么这里就有了这本书的PDF全文。

结论部分

在这次教程里,我们探讨了如何使用大型语言模型(LLMs)来总结像整本书这样的大量文本的复杂情况,并解决了上下文限制和成本方面的挑战。我们学习了预处理文本并实施一种结合语义分块和K-means聚类策略的步骤,以有效地管理模型的上下文限制。通过高效地使用聚类方法,我们有效地提取了关键段落,减少了直接处理大量文本的负担。这种方法不仅通过减少处理令牌的数量显著降低了成本,还减轻了大型语言模型的近期效应和首要效应,确保了对所有文本段落的均衡考虑。

人们对于通过大型语言模型(LLM)的API开发AI应用程序表现出极大的热情,其中向量数据库起到了关键作用,通过提供上下文嵌入的高效存储和检索。MyScaleDB 是一个专为AI应用程序设计的向量数据库,充分考虑了成本、准确性和速度。它友好的SQL界面允许开发人员无需学习新技能就能开始开发AI应用程序。

如果你想与我们更深入地讨论,欢迎大家来分享你的想法和反馈。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消