はじめに
- 生成AIを使ったRAG(Retrieval-Augmented Generation)を行うための前処理の話
- 目的は、langchainのMarkdownHeaderTextSplitterを使って、Markdownファイルをセクションごとに分割したかった
- が、投入したMarkdownが全く分割されず、ハマったので共有したい
結論
- 連続するセクションのタイトルが同じだと、一つのセクションとみなされるので、分割したい場合はちゃんと分けよう!
ハマった内容
どういうドキュメントをどのように分割したいか
- セクションごとに分割したい
# セクション1
セクション1の内容です。
## サブセクション1-1
これは
サブセクション1-1の内容です。
## サブセクション1-2
これは
サブセクション1-2の内容です。
# セクション2
セクション2の内容です。
## サブセクション2-1
これは
サブセクション2-1の内容です。
# セクション3
セクション3の内容です。
- 期待する分割結果
- 以下のように3分割したい
合計で3個のテキストに分割されました:
分割 1:
# セクション1
セクション1の内容です。
## サブセクション1-1
これは
サブセクション1-1の内容です。
## サブセクション1-2
これは
サブセクション1-2の内容です。
--------------------
分割 2:
# セクション2
セクション2の内容です。
## サブセクション2-1
これは
サブセクション2-1の内容です。
--------------------
分割 3:
# セクション3
セクション3の内容です。
--------------------
ハマった事例
# セクション
セクション1の内容です。
# セクション
セクション2の内容です。
# セクション
セクション3の内容です。
↓ 結果
合計で1個のテキストに分割されました:
分割 1:
# セクション
セクション1の内容です。
# セクション
セクション2の内容です。
# セクション
セクション3の内容です。
Tips:連続するセクションで異なっていればよい
- 同じタイトルが存在すること自体は問題ないようだ
# セクション1
セクション1の内容です。
# セクション2
セクション2の内容です。
# セクション1
セクション3の内容です。
↓ 結果
合計で3個のテキストに分割されました:
分割 1:
# セクション1
セクション1の内容です。
--------------------
分割 2:
# セクション2
セクション2の内容です。
--------------------
分割 3:
# セクション1
セクション3の内容です。
--------------------
最後に
- めっちゃ悩んで、文字コード変えたり、ファイルサイズ変えたり、日本語無くしてみたりしてもわからなかったので、危うくCharacterTextSplitterで力わざで実装しようとしかけたところで、ギリギリ気づけて命拾いしたw
参考コード
import os
from typing import List
from langchain.text_splitter import MarkdownHeaderTextSplitter
# Markdownファイルを読み込む関数
def read_markdown_file(file_path: str) -> str:
"""
指定されたファイルパスからMarkdownファイルを読み込みます。
:param file_path: Markdownファイルのパス
:return: ファイルの内容
"""
try:
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
return content
except FileNotFoundError:
print(f"エラー: ファイル '{file_path}' が見つかりません。")
return ""
except Exception as e:
print(f"ファイルを読み込む際にエラーが発生しました: {e}")
return ""
# Markdownテキストを「#'記号で分割する関数
def split_markdown_text(md_text: str) -> List[str]:
"""
Markdownテキストを「#'記号で分割します。
:param md_text: Markdown形式のテキスト
:return: 分割されたテキストのリスト
"""
headers_to_split_on = [("#", "H1")]
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on, strip_headers=False)
md_header_splits = markdown_splitter.split_text(md_text)
split_texts = [split_md.page_content for split_md in md_header_splits]
return split_texts
# メイン関数
def main():
# Markdownファイルのパスを定義
markdown_file_path = 'data/easymarkdown.md' # ここに正しいパスを設定してください
# Markdownファイルを読み込む
markdown_content = read_markdown_file(markdown_file_path)
# ファイルの内容が読み込まれた場合にのみ処理を実行
if markdown_content:
# Markdownテキストを「#'記号で分割
split_texts = split_markdown_text(markdown_content)
# 分割されたテキストの総数を表示
total_splits = len(split_texts)
print(f"合計で{total_splits}個のテキストに分割されました:\n")
# 分割されたテキストを表示
for i, text in enumerate(split_texts):
print(f"分割 {i+1}:")
print(text)
print("-" * 20) # 分割されたテキストを視覚的に分けるために区切¥り線を表示
else:
print("Markdownファイルの読み込みに失敗しました。")
if __name__ == "__main__":
main()