AIパーソナル・ラーニング
と実践的なガイダンス
讯飞绘镜

RAGドキュメント・チャンキングを使いこなす:効率的な検索システム構築のためのチャンキング戦略ガイド

もし ラグ このアプリは期待通りの結果を出せていないので、チャンキング戦略を見直す時期なのかもしれない。より良いチャンキングは、より正確な検索を意味し、最終的に質の高い回答につながる。

しかし、チャンキングは万能の手法ではなく、一つの手法が絶対的に最適ということはありません。プロジェクトの具体的なニーズ、ドキュメントの特性、予算などに応じて、最適な戦略を検討し、選択する必要がある。


 

なぜチャンキングの質がRAGの回答の質に直接影響するのか?

この記事を読むことで、チャンキングとRAGの基本的な概念はご理解いただけたと思います。簡単におさらいすると、RAGの核となる考え方はLLMを 与えられた文脈情報に基づいて質問に答えるなぜなら、LLMは豊富な知識ベースを持っているが、知識の更新にラグがあり、個人データに直接アクセスできないからである。なぜなら、LLMは豊富な知識ベースを持っているが、知識の更新にラグがあり、個人データに直接アクセスできないからである。

RAGは、プロンプトに関連する文書の断片(すなわち、コンテキスト)を注入し、LLMがこれらの断片に基づいて回答を生成するように指示することにより、LLM自体の欠点を補う。コンテキストは、データベースへの問い合わせ、インターネット検索、PDF文書からの抽出など、さまざまな方法で得ることができる。

効率的なRAGアプリケーションを構築するには、2つの重要な課題がある:

  1. LLMのコンテクスト・ウィンドウの制限GPT-2やGPT-3のような初期のLLMはコンテキスト・ウィンドウが小さく、1回のパスで処理できるテキストの量が限られていました。現在では、より大きなコンテキスト・ウィンドウをサポートするモデルもありますが、だからといって、文書全体をLLMに詰め込むことができるわけではありません。
  2. コンテキストノイズ問題たとえLLMのコンテキストウィンドウが十分に大きくても、提供されたコンテキスト情報に質問に関係のない内容(ノイズ)が多く含まれていると、LLMの理解や判断に影響を与え、回答の質の低下や幻覚につながる可能性があります。

こうした問題に対処するためだ。ドキュメントのチャンキングこの技術が誕生した。核となるアイデアは、大きな文書を意味的に一貫性のある小さなセグメント(チャンク)に分割し、検索段階では、最も関連性の高いチャンクのみをLLMに提供されるコンテキストとして選択することである。

例えば、単純なセンテンスやパラグラフのチャンキング、複雑なセマンティック・チャンキング、エージェント・チャンキングなどである。適切なチャンキング戦略を選択することは非常に重要であり、RAGシステムの検索効率と最終的なレスポンスの品質に直接影響する。

この記事では、より堅牢なRAGアプリケーションを構築するのに役立つ、より高度で実用的なドキュメントのチャンキング戦略をいくつかご紹介します。単純な文章や段落のチャンキングは省略し、実際のRAGアプリケーションでより価値のあるテクニックに焦点を当てます。

次に、私が学び実践してきたチャンキング戦略をいくつか紹介しよう。

 

再帰的文字分割:高速で経済的な基本アプローチ

再帰的文字分割、これは最も基本的な方法だと思うかもしれない。確かに基本的ではありますが、それでも私の考えでは最もよく使われ、費用対効果の高いチャンキング手法のひとつです。理解しやすく、実装が簡単で、高速かつ安価なので、ラピッドプロトタイピングやコスト重視のプロジェクトに特に適しています。

再帰的文字分割の核となる考え方は次のとおりである。固定サイズのスライディング・ウィンドウを使用するまた、ウィンドウ間のオーバーラップも可能である。あらかじめ設定されたブロックサイズと重なり文字数で、文書の開始位置からウィンドウを連続的にスライドさせ、テキストブロックを生成する。

次の図は、再帰的文字分割がどのように機能するかを示している:

RAGs 文档分块策略:提升检索质量的实战指南-1再帰的文字分割の仕組み - Thuwarakesh氏作画
図の例では、ブロックサイズを20文字に設定し、重複する文字の数を2文字として、スライディング・ウィンドウによってテキスト・ブロックを生成する方法を示している。

再帰的文字分割の利点は、その単純さと効率性である。大規模な文書の高速処理や、年次報告書の分単位でのチャンキングが可能です。Langchainでの再帰的文字分割の実装は非常に簡単です:

from langchain.text_splitter import RecursiveCharacterTextSplitter
text = """
Hydroponics is an intelligent way to grow veggies indoors or in small spaces. In hydroponics, plants are grown without soil, using only a substrate and nutrient solution. The global population is rising fast, and there needs to be more space to produce food for everyone. Besides, transporting food for long distances involves lots of issues. You can grow leafy greens, herbs, tomatoes, and cucumbers with hydroponics.
"""
rc_splits = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
chunk_size=20, chunk_overlap=2
).split_text(text)

スライディング・ウィンドウのバリエーション

実際には、スライディング・ウィンドウのサイズやスライディング・ステップは、さまざまなニーズに合わせて変えることができる:

  • 文字ベースとトークン・ベースのスライディング・ウィンドウ上記の例は文字ベースのスライディング・ウィンドウです。文字ベースの トークン スライディング・ウィンドウを使うことで、ブロック・サイズをLLMの処理方法に合わせることができる。 再帰的文字テキスト分割器 キャラクタ・モードとトークン・モードの両方がサポートされている。
  • ダイナミック・ウィンドウ・サイズ注:再帰的文字セグメンテーションではウィンドウサイズを固定するが、特定のシナリオでは動的なウィンドウサイズの変更も考慮できる。たとえば、文の長さや段落の構造に応じてウィンドウサイズを適応的に調整し、ブロックの意味的整合性を確保する。

制限

再帰的文字分割は位置ベースのチャンキングアプローチ。これは単に、文書内で位置的に隣接するテキストは意味的にも関連していると仮定するものである。しかし、多くの場合この仮定は成り立たない。

考察:なぜロケーションベースのチャンキングはRAGのパフォーマンスを低下させるのか?セマンティック・チャンキングを実装して、より良い結果を得るには?

例えば、同じ章の中で、著者はまず複数の異なる概念について論じた後、最終的にそれらを関連付けることがある。再帰的な文字セグメンテーションだけを使用した場合、同じ意味ユニットに属するはずのコンテンツが分割されたり、意味的に関係のないコンテンツが組み合わされたりして、検索に影響を与える可能性がある。

その制限にもかかわらず、再帰的文字セグメンテーションはRAGを使い始めるのに理想的です。プロトタイピングの段階や、単純に構造化されたドキュメントでは、多くの場合満足のいく結果が得られます。再帰的文字セグメンテーションは、プロジェクトに高いコストとスピードが要求される場合にも、価値のあるオプションです。

 

セマンティック・チャンキング:テキストの意味を理解するためのチャンキング・アプローチ

セマンティック・チャンキングは、より高度なチャンキング戦略である。テキストの位置情報だけに頼るのではなく、テキストの意味論的な理解を深める。核となる考え方は、意味論が大きく変化したときに文書をセグメント化し、各チャンクが可能な限り単一のトピックを中心とするようにすることである。

下の図は、セマンティック・チャンキングがどのように機能するかを示している:

RAGs 文档分块策略:提升检索质量的实战指南-2セマンティック・チャンキングは機能する - トゥワラケシュが描く
例えば、最初の2文は水耕栽培の農業について論じ、次の2文は地球規模の問題に移り、また水耕栽培に戻る。セマンティック・チャンキングは、このような意味的なトピック・シフトを認識し、トピック・スイッチでセグメント化することができる。

再帰的な文字セグメンテーションとは異なり、セマンティック・チャンキングは通常、可変長のブロックを生成する。ブロックの境界は、文字数やトークンを固定するのではなく、意味的な完全性に基づいて決定される。

セマンティック・チャンキングに向けた主なステップ

セマンティック・チャンキングの難しさは文の意味論**を理解するようにプログラムされている。これは通常モデルの埋め込みを実装する。OpenAIのようなモデルの埋め込み テキスト埋め込み-3-大文はベクトル表現に変換することができ、ベクトルは文の意味情報を捉えることができる。意味的に似ている文は、空間的にも近いベクトルを持つ。**

セマンティック・チャンキングの典型的なプロセスは、以下の5つのステップからなる:

  • 初期ブロックの構築: 最初に文書を文または段落に分割し、隣接する文または段落を最初のブロックに結合する。
  • ブロック埋め込みを生成する埋め込みモデルを使用して、各初期ブロックの埋め込みベクトルを生成する。
  • ブロック間の距離を計算する隣接ブロック間の意味的距離を計算する。よく使われる距離測定基準には余弦距離などがある。距離が大きいほど意味的な違いが大きい。
  • スプリットポイントの決定距離のしきい値を設定する。隣接するブロック間の距離が閾値を超えると、それらを分割して新しい意味ブロックを形成する。閾値の選択は、特定の文書や実験効果に応じて調整する必要がある。
  • ビジュアライゼーション(オプション)ブロック間の距離を視覚化することで、チャンキング効果をより直感的に理解し、閾値を調整することができます。

次のコードは、セマンティック・チャンキングの実装方法を示している:

# Step 1 : Create initial chunks by combining concecutive sentences.
# ------------------------------------------------------------------
#Split the text into individual sentences.
sentences = re.split(r"(?<=[.?!])\s+", text)
initial_chunks = [
{"chunk": str(sentence), "index": i} for i, sentence in enumerate(sentences)
]
# Function to combine chunks with overlapping sentences
def combine_chunks(chunks):
for i in range(len(chunks)):
combined_chunk = ""
if i > 0:
combined_chunk += chunks[i - 1]["chunk"]
combined_chunk += chunks[i]["chunk"]
if i < len(chunks) - 1:
combined_chunk += chunks[i + 1]["chunk"]
chunks[i]["combined_chunk"] = combined_chunk
return chunks
# Combine chunks
combined_chunks = combine_chunks(initial_chunks)
# Step 2 : Create embeddings for the initial chunks.
# ------------------------------------------------------------------
# Embed the combined chunks
chunk_embeddings = embeddings.embed_documents(
[chunk["combined_chunk"] for chunk in combined_chunks]
# If you haven't created combined_chunk, use the following.
# [chunk["chunk"] for chunk in combined_chunks]
)
# Add embeddings to chunks
for i, chunk in enumerate(combined_chunks):
chunk["embedding"] = chunk_embeddings[i]
# Step 3 : Calculate distance between the chunks
# ------------------------------------------------------------------
def calculate_cosine_distances(chunks):
distances = []
for i in range(len(chunks) - 1):
current_embedding = chunks[i]["embedding"]
next_embedding = chunks[i + 1]["embedding"]
similarity = cosine_similarity([current_embedding], [next_embedding])[0][0]
distance = 1 - similarity
distances.append(distance)
chunks[i]["distance_to_next"] = distance
return distances
# Calculate cosine distances
distances = calculate_cosine_distances(combined_chunks)
# Step 4 : Find chunks with significant different to it's previous ones.
# ----------------------------------------------------------------------
import numpy as np
threshold_percentile = 90
threshold_value = np.percentile(cosine_distances, threshold_percentile)
crossing_points = [
i for i, distance in enumerate(distances) if distance > threshold_value
]
len(crossing_points)
# Step 5 (Optional) : Create a plot of chunk distances to get a better view
# -------------------------------------------------------------------------
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
def visualize_cosine_distances_with_thresholds_multicolored(
cosine_distances, threshold_percentile=90
):
# Calculate the threshold value based on the percentile
threshold_value = np.percentile(cosine_distances, threshold_percentile)
# Identify the points where the cosine distance crosses the threshold
crossing_points = [0]  # Start with the first segment beginning at index 0
crossing_points += [
i
for i, distance in enumerate(cosine_distances)
if distance > threshold_value
]
crossing_points.append(
len(cosine_distances)
)  # Ensure the last segment goes to the end
# Set up the plot
plt.figure(figsize=(14, 6))
sns.set(style="white")  # Change to white to turn off gridlines
# Plot the cosine distances
sns.lineplot(
x=range(len(cosine_distances)),
y=cosine_distances,
color="blue",
label="Cosine Distance",
)
# Plot the threshold line
plt.axhline(
y=threshold_value,
color="red",
linestyle="--",
label=f"{threshold_percentile}th Percentile Threshold",
)
# Highlight segments between threshold crossings with different colors
colors = sns.color_palette(
"hsv", len(crossing_points) - 1
)  # Use a color palette for segments
for i in range(len(crossing_points) - 1):
plt.axvspan(
crossing_points[i], crossing_points[i + 1], color=colors[i], alpha=0.3
)
# Add labels and title
plt.title(
"Cosine Distances Between Segments with Multicolored Threshold Highlighting"
)
plt.xlabel("Segment Index")
plt.ylabel("Cosine Distance")
plt.legend()
# Adjust the x-axis limits to remove extra space
plt.xlim(0, len(cosine_distances) - 1)
# Display the plot
plt.show()
return crossing_points
# Example usage with cosine_distances and threshold_percentile
crossing_poings = visualize_cosine_distances_with_thresholds_multicolored(
distances, threshold_percentile=bp_threashold
)

距離を視覚化するセボーン・チャート:

RAGs 文档分块策略:提升检索质量的实战指南-3セマンティック・チャンキングの説明に使用 シーボーン・ダイアグラム - Thuwarakesh氏作図
図では、ブロック間の距離が閾値0.12を超えると、前のブロックは1つの大きな意味ブロックに統合される。最終的に長さの異なる6つの意味ブロックが生成された。

セマンティック・チャンキングの利点と適用シナリオ

セマンティック・チャンキングの利点は、次のことができることだ。文書の意味構造をより良く捉え、意味的に関連するテキスト断片を集約することで、RAGシステムの検索品質を向上させる。以下のようなタイプの文書の処理に適している:

  • 複雑な構造と多様なトピックを持つ文書例えば、複数のサブトピックを含む長いレポート、技術文書、書籍など。
  • セマンティック・ジャンプの高い文書セマンティック・チャンキングを使えば、このようなスタイルにも対応できる。

再帰的文字セグメンテーションに比べ、意味的チャンキングは計算はより高価**で遅い。これは主に、埋め込みベクトル計算と距離メトリックが必要なためである。したがって、リソースが限られたシナリオでは、トレードオフを考慮する必要がある。

 

エージェント・チャンキング:人間の理解を模倣したチャンキング戦略

エージェント・チャンキングはインテリジェント・チャンキングへのさらなるステップである。それは人間が文書を読んで理解する方法を参考に、LLMはチャンキングを支援する「知的エージェント」として使用される。

人間の読書習慣は完全に直線的なものではないエージェンティック・チャンキングは、この人間の理解プロセスをシミュレートしようとするものである。私たちは読書をするとき、トピックからトピックへ、概念から概念へと飛び回り、頭の中で文書の論理構造を構築する。エージェント・チャンキングは、この人間の理解プロセスを模倣しようとするものである。

前の2つの方法とは異なり、エージェンティック・チャンキングはは、意味的に類似したコンテンツが文書内で連続して出現することを想定していない**。散在しているが意味的に関連する文書の断片を集約して、人間の知覚により適合する意味的な塊を形成することができる。

エージェントによるチャンキングワークフロー

エージェント・チャンキングの核となる考え方はLLMに人間のようにドキュメントを「読ませ」、ドキュメントの核となる概念やテーマを特定し、それに基づいてチャンキングする。典型的なAgenticのチャンキング・プロセスには以下が含まれます:

  • プロポジショニング文書の各文をより独立した命題に変換する。例えば、未知の代名詞を目的語に置き換えて、各文により完全な意味づけをする。
  • ビルディング・ブロック・コンテナ意味的に関連する命題のために、1つ以上の Chunk コンテナを作成します。各チャンクコンテナには、そのコンテナの主題を説明するタイトルと要約を付けることができます。
  • エージェント主導の命題割り当てLLMをエージェントとして使い、命題を一つずつ「読み」、その命題がどのブロックコンテナに属するべきかを決定する。
    • エージェントが、その命題が既存のブロックコンテナの1つのトピックに関連するとみなした場合、そのコンテナに追加される。
    • エージェントは、その提案が新しいトピックを提案していると考える場合、その提案を保持するために新しいブロックコンテナを作成する。
  • ブロックコンテナ再処理例えば、コンテナ内の命題に基づいて、より洗練されたブロックの要約やタイトルを生成する。

次のコードは、エージェント・チャンキングの実装を示している:

from langchain import hub
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
# Step 1: Convert paragraphs to propositions.
# --------------------------------------------
# Load the propositioning prompt from langchain hub
obj = hub.pull("wfh/proposal-indexing")
# Pick the LLM
llm = ChatOpenAI(model="gpt-4o")
# A Pydantic model to extract sentences from the passage
class Sentences(BaseModel):
sentences: List[str]
extraction_llm = llm.with_structured_output(Sentences)
# Create the sentence extraction chain
extraction_chain = obj | extraction_llm
# NOTE: text is your actual document
paragraphs = text.split("\n\n")
propositions = []
for i, p in enumerate(paragraphs):
propositions = extraction_chain.invoke(p
propositions.extend(propositions)
# Step 2: Create a placeholder to store chunks
chunks = {}
# Step 3: Deine helper classes and functions for agentic chunking.
class ChunkMeta(BaseModel):
title: str = Field(description="The title of the chunk.")
summary: str = Field(description="The summary of the chunk.")
def create_new_chunk(chunk_id, proposition):
summary_llm = llm.with_structured_output(ChunkMeta)
summary_prompt_template = ChatPromptTemplate.from_messages(
[
(
"system",
"Generate a new summary and a title based on the propositions.",
),
(
"user",
"propositions:{propositions}",
),
]
)
summary_chain = summary_prompt_template | summary_llm
chunk_meta = summary_chain.invoke(
{
"propositions": [proposition],
}
)
chunks[chunk_id] = {
"summary": chunk_meta.summary,
"title": chunk_meta.title,
"propositions": [proposition],
}
def add_proposition(chunk_id, proposition):
summary_llm = llm.with_structured_output(ChunkMeta)
summary_prompt_template = ChatPromptTemplate.from_messages(
[
(
"system",
"If the current_summary and title is still valid for the propositions return them."
"If not generate a new summary and a title based on the propositions.",
),
(
"user",
"current_summary:{current_summary}\n\ncurrent_title:{current_title}\n\npropositions:{propositions}",
),
]
)
summary_chain = summary_prompt_template | summary_llm
chunk = chunks[chunk_id]
current_summary = chunk["summary"]
current_title = chunk["title"]
current_propositions = chunk["propositions"]
all_propositions = current_propositions + [proposition]
chunk_meta = summary_chain.invoke(
{
"current_summary": current_summary,
"current_title": current_title,
"propositions": all_propositions,
}
)
chunk["summary"] = chunk_meta.summary
chunk["title"] = chunk_meta.title
chunk["propositions"] = all_propositions
# Step 5: The main functino that creates chunks from propositions.
def find_chunk_and_push_proposition(proposition):
class ChunkID(BaseModel):
chunk_id: int = Field(description="The chunk id.")
allocation_llm = llm.with_structured_output(ChunkID)
allocation_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You have the chunk ids and the summaries"
"Find the chunk that best matches the proposition."
"If no chunk matches, return a new chunk id."
"Return only the chunk id.",
),
(
"user",
"proposition:{proposition}" "chunks_summaries:{chunks_summaries}",
),
]
)
allocation_chain = allocation_prompt | allocation_llm
chunks_summaries = {
chunk_id: chunk["summary"] for chunk_id, chunk in chunks.items()
}
best_chunk_id = allocation_chain.invoke(
{"proposition": proposition, "chunks_summaries": chunks_summaries}
).chunk_id
if best_chunk_id not in chunks:
best_chunk_id = create_new_chunk(best_chunk_id, proposition)
return
add_proposition(best_chunk_id, proposition)

命題化の例

原始文本
===================
A crow sits near the pond. It's a white one.
命题化文本
==================
A crow sits near the pond. This crow is a white one.

エージェント・チャンキングの利点と課題

エージェント・チャンク最大の利点は、その柔軟性とインテリジェンス**である。文書の深い意味構造をよりよく理解し、人間の認知により近い意味チャンクを生成することができ、特に以下のような種類の文書を扱うのが得意です。

  • 非線形構造ドキュメンテーション例えば、思考が飛び飛びで、背景知識や暗示的な情報を多く含む文書。
  • 段落やセクションをまたいで情報を統合する必要がある文書エージェンティック・チャンキングは、文書内の異なる場所に散在する意味的に関連する断片を集約することができる。

しかし、エージェント・チャンキングには課題もある:

  • コスト高エージェンティック・チャンキングでは、LLMを頻繁に呼び出す必要があり、計算量と時間がかかる。
  • プロジェクトの依存関係を促すエージェントによるチャンキングの効果は、プロンプトのデザインに大きく依存します。LLMを効果的にチャンクに導くためには、プロンプトを注意深くデザインする必要があります。
  • 結果の不確実性LLMの出力には不確実性があり、チャンキングの結果が不安定になる可能性があります。

エージェント・チャンキング・アプリケーションのシナリオ

エージェンティックのチャンキングは、よりコストがかかるが、RAGの有効性が重要なシナリオにおいては、検討する価値のあるオプションである。例

  • 専門分野の知識ベース例えば、法律、医療、金融などの知識ベースでは、検索精度と想起率が極めて高いことが要求されます。
  • 複雑な質疑応答システム推論や情報の統合を必要とする複雑な質問に対応する必要がある質問応答システム。

深読み:エージェンティック・チャンキング:AIエージェント駆動型意味論的テキストチャンキング

 

さまざまな文書形式に対応するチャンキング戦略

前回は主にプレーン・テキストのチャンキングについて説明した。しかし、実用的なアプリケーションでは、Markdown、HTML、PDF、コードなど、様々な異なる文書形式に遭遇することが多い。異なるフォーマットの場合、文書の構造情報を最大限に活用するために、より洗練されたチャンキング戦略が必要となる。

MarkdownとHTMLドキュメントのチャンキング

MarkdownやHTML文書には、見出し、段落、リスト、コードブロックなどの構造化されたタグ情報があります。私たちはより正確なチャンキングを行うために、チャンキングの基準としてこれらのラベルを使用してください。**

  • タイトル別ブロック各見出しとその下にあるコンテンツを独立したブロックとして扱います。これは、明確なセクションを持つ明確な構造の文書に適しています。
  • チャンク各段落をチャンクとして扱う。段落は通常、意味的に完全な単位であり、基本的なチャンキング単位として適している。
  • チャンキング見出しと段落を組み合わせてチャンキングする。例えば、文書はまず第一レベルの見出しで分割され、各第一レベルの見出しの下のコンテンツでは、段落で分割される。

例:HTMLタグベースのチャンキング(Python)

from bs4 import BeautifulSoup
html_text = """
<h1>Section 1</h1>
<p>This is the first paragraph of section 1.</p>
<p>This is the second paragraph of section 1.</p>
<h2>Subsection 1.1</h2>
<ul>
<li>List item 1</li>
<li>List item 2</li>
</ul>
"""
soup = BeautifulSoup(html_text, 'html.parser')
chunks = []
# 按 h1 标题分块
for h1_tag in soup.find_all('h1'):
chunk_text = h1_tag.text + "\n"
next_sibling = h1_tag.find_next_sibling()
while next_sibling and next_sibling.name not in ['h1', 'h2']: #  假设按 h1 和 h2 分级
chunk_text += str(next_sibling) + "\n" #  保留 HTML 标签,或 next_sibling.text  只保留文本
next_sibling = next_sibling.find_next_sibling()
chunks.append(chunk_text)
#  可以类似地处理 h2, p, ul, ol 等标签
print(chunks)

PDFドキュメントのチャンキング

PDFは本質的に、テキストコンテンツと組版情報が混在する組版フォーマットであるため、PDF文書のチャンキングは比較的複雑です。PDFを文字や行で直接分割すると、セマンティックな整合性が失われる可能性があります。

通常、PDFのチャンキングにおける重要なステップは以下の通りです:

  • PDFテキスト抽出PDF解析ライブラリ(例:PyPDF2、pdfminer、またはもっと専門的な)を使う 不定形.io)でPDFファイルからテキストコンテンツを抽出します。
  • テキストのクリーニングと前処理ノイズ文字の除去、改行の処理、OCRエラーの修正など。
  • 構造化情報抽出: PDFから、タイトル、ヘッダー、フッター、表、リストなどの構造化された情報を抽出しようとします。いくつかの高度なPDF解析ライブラリ(例:unstructured.io)は、構造化された情報の抽出を支援することができます。
  • チャンキング戦略のオプション抽出されたテキストの内容と構造情報に基づいて、適切なチャンキング戦略(意味的チャンキング、再帰的文字分割など)を選択します。

注意を引く非構造化.io は、(PDFを含む)さまざまな文書形式を扱うことができる強力なツールで、文書から構造化された情報を抽出し、PDFチャンキングのプロセスを簡素化します。

コード・ドキュメントのチャンキング

コード・ドキュメント(Python、Java、C++のコード・ファイルなど)のチャンキングでは、コードの構文構造と論理単位を考慮する必要がある。単に行や文字でコードを分割するだけでは、コードの完全性や実行可能性が損なわれる可能性が高い。

コード・ドキュメントをチャンキングするための一般的な戦略には、次のようなものがある:

  • 機能/クラスによるチャンキング各関数やクラスは独立したブロックとして扱う。関数やクラスは通常、コードの論理的な単位です。
  • コードブロックによるチャンキングコード内のロジックのブロック(ループ、条件文、try-exceptブロックなど)を識別し、各ブロックをチャンクとして扱う。
  • コード・コメント・チャンキングとの組み合わせコード・コメントは通常、コードの機能とロジックの説明である。コード・コメントとそれに関連するコード・ブロックは、全体としてチャンク化することができます。

アーティファクトコードの構造解析とチャンキングは、tree-sitterのような構文解析ツールの使用によって支援されます。tree-sitterは、さまざまなプログラミング言語のコードを解析し、抽象構文木(AST)を生成します。

 

適切なチャンクサイズとオーバーラップの選択

チャンクサイズとチャンクスオーバーラップは、RAGシステムのパフォーマンスに直接影響するチャンキングポリシーの2つの重要なパラメータである。

  • チャンクサイズ各チャンクに含まれるテキストの量。チャンクサイズが小さすぎると意味情報が不完全になり、大きすぎるとノイズが入り検索精度が低下する。
  • オーバーラップサイズ隣接するブロック間で重なるテキストの量。オーバーラップの目的は、文脈の連続性を確保し、ブロック境界での情報の損失を避けることである。

適切なチャンクサイズとオーバーラップを選ぶには?

適切なチャンクサイズとオーバーラップの選択に絶対的な最適解はなく、通常は文書の特徴歌で応える実験効果を決定します。以下は経験則と提案である:

  • 発見的方法::
    • 文/パラグラフの長さに基づく文書の平均的な文の長さや段落の長さは、チャンクサイズの参考として分析することができます。例えば、段落の長さの平均が150Tokenであれば、チャンクサイズを150-200Tokenに設定してみるとよいでしょう。
    • LLMのコンテキストウィンドウを考えるブロックのサイズは、LLMのコンテキスト・ウィンドウの制限を超えないように、あまり大きくすべきではない。同時に、ブロックに十分な意味情報が含まれるように、小さすぎてもいけない。
  • 実験と評価:
    • 反復チューニングチャンクサイズとオーバーラップのパラメータ(チャンクサイズ500Token、オーバーラップ50Tokenなど)を初期設定し、RAGシステムを構築して評価する。その後、徐々にパラメータを調整し、検索効果やQ&A効果の変化を観察し、最適なパラメータの組み合わせを選択する。
    • 指標の評価Recall@k、Precision@k、NDCG (Normalised Discounted Cumulative Gain)などの検索に適した評価指標を使用して、RAGシステムのパフォーマンスを定量化します。これらのメトリクスは、異なるチャンキング戦略の有効性を客観的に評価するのに役立ちます。

ラングチェーンにおける評価ツール

Langchainは、RAGシステムの評価やパラメータチューニングを支援する評価ツールを多数提供しています。例えば、DatasetEvaluatorやRetrievalQAChainなどのツールは、異なるチャンキング戦略、検索モデル、LLMモデルの組み合わせの効果を自動評価するのに役立ちます。

 

チャンキング戦略の有効性の評価

適切なチャンキング戦略を選択した後、その効果をどのように評価するのか? 「より良いチャンキングはより良い検索を意味する」しかし「より良い」をどのように定量化するのか? チャンキング戦略の良し悪しを評価するための指標が必要なのだ。

以下は、チャンキング戦略がRAGシステムのパフォーマンスに与える影響を評価するのに役立つ、一般的な評価指標です:

  • 指標の検索:
    • リコール(リコール@k)これは、Top-k検索結果のうち、関連文書(またはチャンク)が占める割合のことである。リコールが高いほど、チャンキング戦略によってより多くの関連情報が検索されたことになる。
    • 精度(Precision@k)これは、Top-k検索結果のうち、真に関連性のある文書(またはチャンク)の割合を示す。精度が高ければ高いほど、検索結果の質が高いことを意味する。
    • NDCG (正規化割引累積利益)NDCGが高いほど、検索ランキングの質が高いことを示す。
  • Q&A指標:
    • 回答の妥当性LLMによって生成された回答が質問に対してどの程度関連性があるかを評価します。回答の関連性が高ければ高いほど、RAGシステムは検索された情報に基づいて意味のある回答を生成することに優れています。
      • 回答の正確さ/誠実さLLMによって生成された回答が、「錯覚」や不正確な情報を避け、検索された文脈情報に忠実であるかどうかを評価する。解答精度が高いほど、チャンキング戦略が信頼できる文脈を提供し、LLMがより信頼できる解答を生成するよう導く能力が高いことを示す。
      • 解答の流暢さと一貫性主にLLM自身の能力に影響されますが、優れたチャンキング戦略は、間接的に解答の流暢さと一貫性を向上させることもできます。例えば、セマンティック・チャンキングは、より首尾一貫した文脈を提供し、LLMがより自然な言葉を発するのに役立ちます。

評価ツールと方法論

  • 手動評価最も直接的で信頼性の高い方法です。人間の評価者が、あらかじめ定義された評価基準に基づいて、RAGシステムの検索結果とQ&A回答を評価します。手動評価の欠点は、コストと時間がかかること、そして非常に主観的であることです。
  • 自動評価:: 自動化された評価指標やツールの使用:
    • 指標の検索例えば、標準的な情報検索評価ツール(例えば、以下のようなもの)を使用して、想起、精度、NDCGなどを測定することができる。 rank_bm25sentence-transformers など)を自動計算する。
    • Q&A指標一部の NLP 評価メトリクス(BLEU、ROUGE、METEOR、BERTScore など)は、回答の質の評価を支援するために使用することができます。しかし、自動化されたQ&A評価メトリクスにはまだ限界があり、手動による評価を完全に置き換えることはできないことに留意する必要があります。
    • ラングチェーン・アセスメント・ツールラングチェーンには、以下のような評価ツールが統合されています。 DatasetEvaluator 歌で応える RetrievalQAChainこれにより、RAGシステムの自動評価プロセスが簡素化される。

査定プロセスへの提言

  1. 評価データセットの構築:: 質問とそれに対応する標準的な解答を含む評価データセットを準備する。データセットは、RAGシステムの典型的なアプリケーションシナリオと質問タイプを可能な限り網羅すること。
  2. 評価指標の選択: : 評価の目的に応じて、適切な検索指標と質疑応答指標を選択する。手動評価と自動評価の同時使用も可能。
  3. RAGシステムの実行チャンキング戦略、検索モデル、LLMモデルの様々な組み合わせを使用して、評価データセット上でRAGシステムを実行し、評価結果を記録する。
  4. 分析と比較異なる戦略の評価指標を比較し、その強みと弱みを分析し、最適な戦略の組み合わせを選択する。
  5. 反復最適化評価結果に基づいて、チャンキング戦略、検索モデル、LLMモデルのパラメータを継続的に調整し、RAGシステムの性能を向上させるために最適化を繰り返す。

 

まとめ:自分に最適なチャンキング戦略を選ぶ

本稿では、基本的な再帰的文字セグメンテーションから、よりスマートなセマンティック・チャンキングやエージェント・チャンキング、様々な文書フォーマットに対する洗練されたチャンキング戦略、さらにはチャンクサイズやオーバーラップパラメータの選択・評価方法まで、RAGアプリケーションにおいて重要な文書チャンキング技術について詳しく説明する。

コア・ポイントの見直し

  • チャンクの質量がRAGの質量を決める優れたチャンキング戦略は、高性能なRAGシステム構築の礎となる。
  • 万能のチャンキング戦略はない異なるチャンキング戦略にはそれぞれ長所と短所があり、異なるシナリオに適しています。プロジェクトの具体的な要件、ドキュメントの特性、リソースの制約に基づいて、最も適切な戦略を選択する必要があります。
  • 再帰的文字分割プロトタイピングやコスト重視のプロジェクトに最適です。
  • セマンティックチャンキングテキストのセマンティクスを理解し、セマンティクス的に一貫性のあるチャンクを生成することは、検索の質を向上させるが、計算コストがかかる。
  • エージェント・チャンキング人間の理解をシミュレートし、より賢く、より柔軟で、複雑な文書を扱うことができるが、コストが高く、プロンプトエンジニアリングは複雑である。
  • 異なるフォーマットのためのチャンキングMarkdown、HTML、PDF、コードなどの異なるフォーマットでは、ドキュメントの構造情報を活用するために、きめ細かいチャンキング戦略が必要です。
  • チャンクサイズとオーバーラップ文書の特性や実験結果に応じて調整する必要があり、絶対的な最適値はない。
  • 査定が鍵チャンキング戦略の有効性を評価指標と手動評価によって定量化し、最適化を繰り返す。

どう選ぶ?私のアドバイス

  • ラピッドプロトタイピング:: 優先試行再帰的文字分割RAGは、RAGのプロトタイプを作り、システムの実現可能性を検証するための迅速な方法である。
  • より高い品質の追求RAGの品質に対する要求が高く、計算リソースが許すのであれば、次のような方法もあります。セマンティックチャンキング.
  • 複雑な文書の取り扱い:: 複雑な構造とセマンティック・ジャンプを持つ文書向け。エージェント・チャンキングそれが望ましい選択肢かもしれないが、コストと効果を慎重に天秤にかける必要がある。
  • フォーマット固有Markdown、HTML、PDF、コードなど、特定のフォーマットのドキュメントを扱う場合は、必ずターゲット・チャンキング戦略文書の構造的な情報は十分に活用されている。
  • 継続的な反復最適化チャンキング戦略の選択は、一朝一夕にできるものではない。実際のプロジェクトでは、常に実験、評価、反復最適化あなたに最適なチャンキング・ソリューションを見つけるために。

この記事が、RAGチャンキング技術をより深く理解し、より強力なRAGアプリケーションを構築するために、実際のプロジェクトで適切なチャンキング戦略を選択・適用する一助となれば幸いです!

無断転載を禁じます:チーフAIシェアリングサークル " RAGドキュメント・チャンキングを使いこなす:効率的な検索システム構築のためのチャンキング戦略ガイド
ja日本語