C# のみで RAG を構築する場合の留意点
- C# では Python と比べて日本語の言語処理にやチャンク(テキスト分割)に関して圧倒的にライブラリが少ないが、html ファイルのクレンジングやテキストをチャンクする際のトークンカウンターをどうするか。
- ソースのブログ記事が更新されたとき、インデックス上の当該ドキュメントを削除する判断基準となるはてなブログ記事の更新日時の管理はどうするか。
- インデックスはキー属性が付与された値でしか削除できないので、ソースデータ更新時にどうやって削除するか。
留意点①:C# によるテキストのクレンジング・チャンク
C# では Python と比べて日本語の言語処理にやチャンク(テキスト分割)に関して圧倒的にライブラリが少ないが、html ファイルのクレンジングやテキストをチャンクする際のトークンカウンターをどうするか検討したところ、以下の方法がありそうです。
- 現状提供されている SDK/ライブラリでどうにかする
- Python にあるようなリッチなライブラリは現状ない
- markdown とプレーンテキストならプレビューではあるが、 Microsoft.SemanticKernel.TextChunker が対応している
- Python にあるようなリッチなライブラリは現状ない
- Python の処理を C# に移植する
- Python の標準ライブラリは言語処理関連が充実しているが、必要な処理すべてを C# に移植するのは量的に困難
- 現状提供されているライブラリがない機能を移植する
- Python の標準ライブラリは言語処理関連が充実しているが、必要な処理すべてを C# に移植するのは量的に困難
1 をメインに機能が足りない部分は 2 も併用する。
SemanticKernel.TextChunker を使う
SemanticKernel.TextChunker の公式ドキュメントは以下を参照ください。
learn.microsoft.com
提供メソッドは以下の4種類(現状 markdown とプレーンテキストのみ対応)
① | SplitMarkDownLines(String, Int32, TextChunker.TokenCounter) | markdownテキストを行に分割します。 |
---|---|---|
② | SplitMarkdownParagraphs(List<String>, Int32, Int32, String, TextChunker.TokenCounter) | markdownテキストを段落に分割します。 |
③ | SplitPlainTextLines(String, Int32, TextChunker.TokenCounter) | プレーンテキストを行に分割します。 |
④ | SplitPlainTextParagraphs(List<String>, Int32, Int32, String, TextChunker.TokenCounter) | プレーンテキストを段落に分割します。 |
html からプレーンテキストを抽出およびクレンジングし、③, ④のメソッドでチャンクする方針とします。
SplitPlainTextParagraphs メソッドの留意点
パラメータ名 | 型 | 説明 |
---|---|---|
lines | List<String> | テキストの行。 |
maxTokensPerParagraph | Int32 | 段落ごとのトークンの最大数。 |
overlapTokens | Int32 | 段落間で重なるトークンの数。 |
chunkHeader | String | 個々のチャンクの前に追加されるテキスト。 |
tokenCounter | delegate int TokenCounter(string input) | 文字列内のトークンをカウントする関数。指定しない場合は、デフォルトのカウンターが使用される。 |
正しくトークンをカウントする必要があるので、ポイントになるのが、TokenCounter ですが、この実体はソースコードを確認すると、string をパラメータとし、int を返すデリゲートになっています。
よって、自分がデプロイした Enbedding モデルに適合した TokenCounter のデリゲートを渡すようにします。
[Experimental("SKEXP0055")] public static class TextChunker { /// <summary> /// Delegate for counting tokens in a string. /// </summary> /// <param name="input">The input string to count tokens in.</param> /// <returns>The number of tokens in the input string.</returns> public delegate int TokenCounter(string input);