LangChain と OpenAI を使用して大きなドキュメントを要約する方法

非常に大きなドキュメントを要約する場合には、依然としていくつかの制限があります。これらの影響を軽減する方法をいくつか紹介します。

How to Summarize LargeDocuments with LangChain and OpenAI、著者 Usama Jamilより翻訳。

大規模な言語モデルにより、チャットボットの作成、言語翻訳、テキストの要約など、多くのタスクが容易になります。以前は要約を行うためにモデルを作成していましたが、常にパフォーマンスの問題が発生していました。大規模言語モデル (LLM)を使用してこれを簡単に実行できるようになりました。たとえば、最先端 (SOTA) LLM はすでにコンテキスト ウィンドウ内で書籍全体を処理できます。ただし、非常に大きなドキュメントを要約する場合には、依然としていくつかの制限があります。

大規模な文書の要約に対する LLM の制限

LLM のコンテキスト制限またはコンテキスト長は、モデルが処理できるトークンの数を指します。各モデルには独自のコンテキスト長があり、最大マークまたはマーク制限とも呼ばれます。たとえば、標準 GPT-4 モデルのコンテキスト長は 128,000 トークンです。そのタグ数を超えると情報が失われます。一部の SOTA LLM には、最大 100 万タグのコンテキスト制限があります。ただし、コンテキスト上の制約が増加するにつれて、LLM は最新性や優先性などの制限に悩まされます。これらの影響を軽減する方法を詳しく調べることもできます。

  • LLM の優位性効果は、モデルがシーケンスの先頭に提示される情報をより重視することを意味します。
  • 最新効果は、モデルが処理する最新の情報を強調する場合に発生します。

これらの効果は両方とも、モデルを入力データの特定の部分に偏らせます。モデルはシーケンスの途中で重要な情報をスキップする場合があります。

2番目の問題はコストです。コンテキスト制約の最初の問題はテキストを分割することで解決できますが、本全体をモデルに直接渡すことはできません。これには多額の費用がかかります。たとえば、100 万個のタグが付いた書籍があり、それを GPT4 モデルに直接渡した場合、総コストは約 90 ドルになります (ヒント タグと完了タグ)。価格、文脈上の制約、本の全体的な文脈を考慮して、テキストを要約する折衷的な方法を見つける必要がありました。

このチュートリアルでは、モデルの価格とコンテキスト上の制約を考慮して書籍全体を要約する方法を学びます。はじめましょう。

環境をセットアップする

このチュートリアルに従うには、次のものが必要です。

  • Pythonがインストールされています
  • IDE (VS Code は動作します)

依存関係をインストールするには、ターミナルを開いて次のコマンドを入力します。

pip install langchain openai tiktoken fpdf2 pandas

このコマンドは、必要な依存関係をすべてインストールします。

本をロードする

このプロジェクトで使用するために公開されている Charles Dickens の David Copperfield を使用します。 LangChain が提供する PyPDFLoader を使用してこの本をロードしてみましょう。

from langchain.document_loaders import PyPDFLoader

# Load the book
loader = PyPDFLoader("David-Copperfield.pdf")
pages = loader.load_and_split()

本全体がロードされますが、ここではコンテンツ部分のみに注目します。序文や序論などのページは飛ばしても構いません。

# Cut out the open and closing parts
pages = pages[6:1308]
# Combine the pages, and replace the tabs with spaces
text = ' '.join([page.page_content.replace('\t', ' ') for page in pages]

これでコンテンツが完成しました。最初の 200 文字を出力してみましょう。

前処理

印刷できない文字や余分なスペースなど、テキストから不要な内容を削除しましょう。

import re
def clean_text(text):
   # Remove the specific phrase 'Free eBooks at Planet eBook.com' and surrounding whitespace
   cleaned_text = re.sub(r'\s*Free eBooks at Planet eBook\.com\s*', '', text, flags=re.DOTALL)
   # Remove extra spaces
   cleaned_text = re.sub(r' +', ' ', cleaned_text)
   # Remove non-printable characters, optionally preceded by 'David Copperfield'
   cleaned_text = re.sub(r'(David Copperfield )?[\x00-\x1F]', '', cleaned_text)
   # Replace newline characters with spaces
   cleaned_text = cleaned_text.replace('\n', ' ')
   # Remove spaces around hyphens
   cleaned_text = re.sub(r'\s*-\s*', '', cleaned_text)
   return cleaned_text
clean_text=clean_text(text)

データをクリーンアップした後、要約問題に取り組むことができます。

OpenAI APIをロードする

OpenAI API を使用する前に、ここで構成して認証情報を提供する必要があります。

import os
os.environ["OPENAI_API_KEY"] = "your-openai-key-here"

ここに API キーを入力すると、環境変数が設定されます。

この本にタグがいくつあるか見てみましょう:

from langchain import OpenAI
llm = OpenAI()
Tokens = llm.get_num_tokens(clean_text)
print (f"We have {Tokens} tokens in the book")

この本には 466,000 を超えるマーカーが含まれており、それらをすべて LLM に直接渡すと、多額の料金が請求されることになります。したがって、コストを削減するために、K 平均法クラスタリングを実装して書籍から重要な部分を抽出します。

: K-means クラスタリングを使用するという決定は、データ専門家 Greg Kamradt によるチュートリアルに触発されました。

本の重要な部分を理解するために、まず本をいくつかの部分に分割しましょう。

コンテンツをドキュメントに分割する

LangChain の SemanticChunker ユーティリティを使用して、本のコンテンツをドキュメントに分割します。

from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings
text_splitter = SemanticChunker(
   OpenAIEmbeddings(), breakpoint_threshold_type="interquartile"
)
docs = text_splitter.create_documents([clean_text])

SemanticChunker は 2 つのパラメータを受け取ります。1 つ目は埋め込みモデルです。このモデルによって生成された埋め込みは、セマンティクスに基づいてテキストを分割するために使用されます。 2 番目は、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メソッドはすべてのドキュメントの埋め込みを提供できます。

OpenAI は、より安価で高速であると考えられる te​​xt-embedding-3-small メソッドを特別にリリースしました。

データの再配置

次に、データの処理と分析を容易にするために、ドキュメント コンテンツ リストとその埋め込みを pandas DataFrame に変換します

import pandas as pd
content_list = [doc.page_content for doc in docs]
df = pd.DataFrame(content_list, columns=['page_content'])
vectors = [embedding.embedding for embedding in embeddings]
array = np.array(vectors)
embeddings_series = pd.Series(list(array))
df['embeddings'] = embeddings_series

Faiss を使用した効率的なクラスタリング

次に、文書ベクトルをFaiss互換形式に変換し、K 平均法を使用してそれらを 50 のグループにクラスター化し、文書間の効率的な類似性検索のための Faiss インデックスを作成します。

import numpy as np
import faiss
# Convert to float32 if not already
array = array.astype('float32') 
num_clusters = 50
# Vectors dimensionality
dimension = array.shape[1] 
# Train KMeans with Faiss
kmeans = faiss.Kmeans(dimension, num_clusters, niter=20, verbose=True)
kmeans.train(array)
# Directly access the centroids
centroids = kmeans.centroids 
# Create a new index for the original dataset
index = faiss.IndexFlatL2(dimension)
# Add original dataset to the index
index.add(array) 

この K 平均クラスタリングは、文書を 50 のグループにグループ化します。

: K 平均法クラスタリングを選択する理由は、クラスター内のすべてのドキュメントに関連するエンベディングがあり、コアに最も近いドキュメントを選択するため、各クラスターが同様のコンテンツまたは同様のコンテキストを持つためです。

インポートドキュメントを選択

次に、各クラスターから最も重要なドキュメントのみを選択します。これを行うには、重心に最初に最も近いベクトルのみを選択します。

D, I = index.search(centroids, 1)

このコードは、インデックスの検索メソッドを使用して、重心のリスト内の各重心に最も近いドキュメントを検索します。 2 つの配列を返します。

  • D: 最も近いドキュメントからそれぞれの重心までの距離が含まれます。
  • I には、これらの最近の文書の索引が含まれています。検索メソッドの 2 番目のパラメーター 1 は、重心ごとに最も近いドキュメントが 1 つだけ見つかることを指定します。

次に、ドキュメントが本の順序になっているので、選択したドキュメントのインデックスを並べ替える必要があります。

sorted_array = np.sort(I, axis=0)
sorted_array=sorted_array.flatten()
extracted_docs = [docs[i] for i in sorted_array]

各ドキュメントの概要を取得する

次のステップは、GPT-4 モデルを使用して各ドキュメントの概要を取得し、費用を節約することです。 GPT-4 を使用するには、モデルを定義します。

model = ChatOpenAI(temperature=0,model="gpt-4")

ヒントを定義し、LangChain を使用してヒント テンプレートを作成し、モデルに渡します。

from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template("""
You will be given different passages from a book one by one. Provide a summary of the following text. Your result must be detailed and atleast 2 paragraphs. When summarizing, directly dive into the narrative or descriptions from the text without using introductory phrases like 'In this passage'. Directly address the main events, characters, and themes, encapsulating the essence and significant details from the text in a flowing narrative. The goal is to present a unified view of the content, continuing the story seamlessly as if the passage naturally progresses into the summary.
Passage:
```{text}```
SUMMARY:
"""
)

このプロンプト テンプレートは、モデルがドキュメントをより効果的かつ効率的に要約するのに役立ちます。

次のステップは、LangChain Expression Language (LCEL) を使用して LangChain チェーンを定義することです。

chain= (
    prompt
   | model
   |StrOutputParser() )

要約チェーンはStrOutputParserを使用して出力を解析します。探索できる出力パーサーは他にもあります。

最後に、定義したチェーンを各ドキュメントに適用して概要を取得できます。

from tqdm import tqdm
final_summary = ""

for doc in tqdm(extracted_docs, desc="Processing documents"):
   # Get the new summary.
   new_summary = chain2.invoke({"text": doc.page_content})
   # Update the list of the last two summaries: remove the first one and add the new one at the end.
   final_summary+=new_summary

上記のコードは、チェーンを各ドキュメントに 1 つずつ適用し、各サマリーを Final_summary に接続します。

要約を PDF として保存

次のステップでは、概要をフォーマットして PDF として保存します。

from fpdf import FPDF

class PDF(FPDF):
   def header(self):
       # Select Arial bold 15
       self.set_font('Arial', 'B', 15)
       # Move to the right
       self.cell(80)
       # Framed title
       self.cell(30, 10, 'Summary', 1, 0, 'C')
       # Line break
       self.ln(20)

   def footer(self):
       # Go to 1.5 cm from bottom
       self.set_y(-15)
       # Select Arial italic 8
       self.set_font('Arial', 'I', 8)
       # Page number
       self.cell(0, 10, 'Page %s' % self.page_no(), 0, 0, 'C')

# Instantiate PDF object and add a page
pdf = PDF()
pdf.add_page()
pdf.set_font("Arial", size=12)

# Ensure the 'last_summary' text is treated as UTF-8
# Replace 'last_summary' with your actual text variable if different
# Make sure your text is a utf-8 encoded string
last_summary_utf8 = last_summary.encode('latin-1', 'replace').decode('latin-1')
pdf.multi_cell(0, 10, last_summary_utf8)

# Save the PDF to a file
pdf_output_path = "s_output1.pdf"
pdf.output(pdf_output_path)

ここでは、この本の完全な概要を PDF 形式で示します。

結論は

このチュートリアルでは、コンテキストの制約とコストに関連する課題に対処しながら、書籍全体などの大きなテキストを要約するために LLM を使用する複雑さを検討します。私たちはテキストの前処理の手順を学び、セマンティック チャンキングと K 平均法クラスタリングを組み合わせた戦略を実装して、モデルのコンテキスト上の制約を効果的に管理しました。

効率的なクラスタリングを使用することで、重要な段落を効果的に抽出し、大量のテキストを直接処理するオーバーヘッドを削減します。このアプローチは、処理されるトークンの数を最小限に抑えてコストを大幅に削減するだけでなく、LLM に固有の最新性と優先性の影響を軽減し、すべてのテキストパッセージのバランスの取れた考慮を保証します。

LLM の API を介した AI アプリケーションの開発は大きな注目を集めており、ベクトル データベースはコンテキスト埋め込みの効率的な保存と取得を提供することで重要な役割を果たしています。

MyScaleDB は、コスト、精度、速度などのすべての要素を考慮して、AI アプリケーション専用に設計されたベクトル データベースです。 SQL フレンドリーなインターフェイスにより、開発者は新しい知識を学ぶことなく AI アプリケーションの開発を開始できます。

この記事はYunyunzhongsheng ( https://yylives.cc/ ) で最初に公開されたもので、どなたでもご覧いただけます。

私はオープンソース紅蒙を諦めることにしました 、オープンソース紅蒙の父である王成露氏:オープンソース紅蒙は 中国の基本ソフトウェア分野における唯一の建築革新産業ソフトウェアイベントです - OGG 1.0がリリースされ、ファーウェイがすべてのソースコードを提供します。 Google Readerが「コードクソ山」に殺される Ubuntu 24.04 LTSが正式リリース Fedora Linux 40の正式リリースを前に、 Microsoft開発者ら:Windows 11のパフォーマンスは「ばかばかしいほど悪い」、 馬化騰氏と周宏毅氏が握手し「恨みを晴らす」 有名ゲーム会社が新たな規定を発行:従業員の結婚祝いは10万元を超えてはならない 拼多多は不正競争で有罪判決 賠償金500万元
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/u/6919515/blog/11054174