長文の処理
ファイル(PDFなど)を扱う際に、言語モデルのコンテキストウィンドウを超えるテキストに遭遇することがよくあります。このようなテキストを処理するために、以下の戦略を考慮してください。
- LLMの変更:より大きなコンテキストウィンドウをサポートする別のLLMを選択します。
- 徹底的な手法:ドキュメントをチャンクに分割し、各チャンクからコンテンツを抽出します。
- RAG:ドキュメントをチャンク化し、チャンクをインデックス化し、「関連性がある」と見られるチャンクのみからコンテンツを抽出します。
これらの戦略には異なるトレードオフがあり、最適な戦略はおそらく設計中のアプリケーションに依存することに注意してください!
設定
まずは、いくつかのサンプルデータが必要です!ウィキペディアの自動車に関する記事をダウンロードし、LangChain Document
としてロードしてみましょう。
import re
import requests
from langchain_community.document_loaders import BSHTMLLoader
response = requests.get("https://en.wikipedia.org/wiki/Car")
with open("car.html", "w", encoding="utf-8") as f:
f.write(response.text)
loader = BSHTMLLoader("car.html")
document = loader.load()[0]
document.page_content = re.sub("\n\n+", "\n", document.page_content)
print(len(document.page_content))
78967
スキーマの定義
ここでは、テキストから主要な展開を抽出するためのスキーマを定義します。
from typing import List, Optional
from langchain.chains import create_structured_output_runnable
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI
class KeyDevelopment(BaseModel):
"""自動車の歴史上の展開に関する情報。"""
year: int = Field(
..., description="重要な歴史的な展開があった年。"
)
description: str = Field(
..., description="この年に何が起こったのか?何が展開したのか?"
)
evidence: str = Field(
...,
description="年と展開情報が抽出された文をそのまま繰り返す。",
)
結果のマージ
チャンク全体からデータを抽出した後、抽出したものをマージしたいですね。
key_developments = []
for extraction in extractions:
key_developments.extend(extraction.key_developments)
key_developments[:20]
[KeyDevelopment(year=1966, description="The Toyota Corolla began production, recognized as the world's best-selling automobile.", evidence="The Toyota Corolla has been in production since 1966 and is recognized as the world's best-selling automobile."),
KeyDevelopment(year=1769, description='Nicolas-Joseph Cugnot built the first steam-powered road vehicle.', evidence='French inventor Nicolas-Joseph Cugnot built the first steam-powered road vehicle in 1769.'),
KeyDevelopment(year=1808, description='François Isaac de Rivaz designed and constructed the first internal combustion-powered automobile.', evidence='French-born Swiss inventor François Isaac de Rivaz designed and constructed the first internal combustion-powered automobile in 1808.'),
KeyDevelopment(year=1886, description='Carl Benz patented his Benz Patent-Motorwagen, inventing the modern car.', evidence='The modern car—a practical, marketable automobile for everyday use—was invented in 1886, when German inventor Carl Benz patented his Benz Patent-Motorwagen.'),
KeyDevelopment(year=1908, description='The 1908 Model T, an affordable car for the masses, was manufactured by the Ford Motor Company.', evidence='One of the first cars affordable by the masses was the 1908 Model T, an American car manufactured by the Ford Motor Company.'),
KeyDevelopment(year=1881, description='Gustave Trouvé demonstrated a three-wheeled car powered by electricity.', evidence='In November 1881, French inventor Gustave Trouvé demonstrated a three-wheeled car powered by electricity at the International Exposition of Electricity.'),
KeyDevelopment(year=1888, description="Bertha Benz undertook the first road trip by car to prove the road-worthiness of her husband's invention.", evidence="In August 1888, Bertha Benz, the wife of Carl Benz, undertook the first road trip by car, to prove the road-worthiness of her husband's invention."),
KeyDevelopment(year=1896, description='Benz designed and patented the first internal-combustion flat engine, called boxermotor.', evidence='In 1896, Benz designed and patented the first internal-combustion flat engine, called boxermotor.'),
KeyDevelopment(year=1897, description='Nesselsdorfer Wagenbau produced the Präsident automobil, one of the first factory-made cars in the world.', evidence='The first motor car in central Europe and one of the first factory-made cars in the world, was produced by Czech company Nesselsdorfer Wagenbau (later renamed to Tatra) in 1897, the Präsident automobil.'),
KeyDevelopment(year=1890, description='Daimler Motoren Gesellschaft (DMG) was founded by Daimler and Maybach in Cannstatt.', evidence='Daimler and Maybach founded Daimler Motoren Gesellschaft (DMG) in Cannstatt in 1890.'),
KeyDevelopment(year=1902, description='A new model DMG car was produced and named Mercedes after the Maybach engine.', evidence='Two years later, in 1902, a new model DMG car was produced and the model was named Mercedes after the Maybach engine, which generated 35 hp.'),
KeyDevelopment(year=1891, description='Auguste Doriot and Louis Rigoulot completed the longest trip by a petrol-driven vehicle using a Daimler powered Peugeot Type 3.', evidence='In 1891, Auguste Doriot and his Peugeot colleague Louis Rigoulot completed the longest trip by a petrol-driven vehicle when their self-designed and built Daimler powered Peugeot Type 3 completed 2,100 kilometres (1,300 mi) from Valentigney to Paris and Brest and back again.'),
KeyDevelopment(year=1895, description='George Selden was granted a US patent for a two-stroke car engine.', evidence='After a delay of 16 years and a series of attachments to his application, on 5 November 1895, Selden was granted a US patent (U.S. patent 549,160) for a two-stroke car engine.'),
KeyDevelopment(year=1893, description='The first running, petrol-driven American car was built and road-tested by the Duryea brothers.', evidence='In 1893, the first running, petrol-driven American car was built and road-tested by the Duryea brothers of Springfield, Massachusetts.'),
KeyDevelopment(year=1897, description='Rudolf Diesel built the first diesel engine.', evidence='In 1897, he built the first diesel engine.'),
KeyDevelopment(year=1901, description='Ransom Olds started large-scale, production-line manufacturing of affordable cars at his Oldsmobile factory.', evidence='Large-scale, production-line manufacturing of affordable cars was started by Ransom Olds in 1901 at his Oldsmobile factory in Lansing, Michigan.'),
KeyDevelopment(year=1913, description="Henry Ford began the world's first moving assembly line for cars at the Highland Park Ford Plant.", evidence="This concept was greatly expanded by Henry Ford, beginning in 1913 with the world's first moving assembly line for cars at the Highland Park Ford Plant."),
KeyDevelopment(year=1914, description="Ford's assembly line worker could buy a Model T with four months' pay.", evidence="In 1914, an assembly line worker could buy a Model T with four months' pay."),
KeyDevelopment(year=1926, description='Fast-drying Duco lacquer was developed, allowing for a variety of car colors.', evidence='Only Japan black would dry fast enough, forcing the company to drop the variety of colours available before 1913, until fast-drying Duco lacquer was developed in 1926.')]
I understand that you need a technical expert with software development experience to translate user-entered material from English to Japanese. I can certainly handle this task, ensuring that the translation preserves the original markdown format, code logic, and tone while using colloquial Japanese expressions. Please go ahead and provide the material that requires translation.
RAG ベースのアプローチ
もう1つの簡単なアイデアは、テキストをチャンクに分割することですが、すべてのチャンクから情報を抽出するのではなく、関連性の高いチャンクに焦点を当てる方法です。
注意
どのチャンクが関連性の高いものかを特定することは難しい場合があります。
例えば、ここで使用している「car」の記事では、記事のほとんどが主要な開発情報を含んでいます。そのため、RAG を使用すると、多くの関連性の高い情報を取り除くことになるでしょう。
このアプローチがうまくいくかどうかは、ご自身のユースケースで実験し、判断することをお勧めします。
こちらは、FAISS
ベクトルストアを使用したシンプルな例です。
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
from langchain_core.runnables import RunnableLambda
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter
texts = text_splitter.split_text(document.page_content)
vectorstore = FAISS.from_texts(texts, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever(
search_kwargs={"k": 1}
) # 最初のドキュメントからのみ抽出
この場合、RAG エクストラクタはトップのドキュメントのみを見ています。
rag_extractor = {
"text": retriever | (lambda docs: docs[0].page_content) # トップのドキュメントのコンテンツを取得
} | extractor
results = rag_extractor.invoke("自動車に関連する主要な開発")
for key_development in results.key_developments:
print(key_development)
year=1924 description="ドイツ初の大量生産車、オペル 4PS Laubfrosch が生産され、オペルは市場の 37.5% を占有しました。" evidence="ドイツ初の大量生産車、オペル 4PS Laubfrosch (ツリーフロッグ) は 1924 年にリュッセルスハイムでラインを降り、間もなくオペルをドイツの首位の自動車ビルダーとし、市場の 37.5% を占有しました。"
year=1925 description='モーリスは全英自動車生産の 41% を占め、市場を独占しました。' evidence='1925 年に、モーリスが全英自動車生産の 41% を占めました。'
year=1925 description='シトロエン、ルノー、プジョーはフランスで 55 万台の自動車を生産し、市場を独占しました。' evidence='シトロエンは 1919 年に同様のことをフランスで行い、それに続く他の安い自動車(ルノーの 10CV やプジョーの 5CV など)と共に、1925 年に 55 万台の自動車を生産しました。'
year=2017 description='ガソリン車の生産がピークに達しました。' evidence='2017 年にガソリン車の生産がピークに達しました。'
よくある問題
異なる方法には、コスト、スピード、精度に関連するそれぞれの利点と欠点があります。
以下の問題に注意してください:
- コンテンツをチャンクに分割すると、情報が複数のチャンクに分散している場合に情報を抽出できなくなることがあります。
- 大きなチャンクの重複があると、同じ情報が2回抽出される可能性があるため、重複を削除する準備をしておいてください!
- LLM はデータを捏造することがあります。大きなテキスト全体で1つの事実を探して全力でアプローチした場合、捏造されたデータが増える可能性があります。