個人的なメモ

Tomohiro Suzuki @hiro128_777 のブログです。Microsoft MVP for Developer Technologies 2017- 本ブログと所属組織の公式見解は関係ございません。

C# だけで Azure OpenAI の RAG を試してみたい (2)C# によるテキストのクレンジング・チャンクの方針

 
前の記事
hiro128.hatenablog.jp
 

C# のみで RAG を構築する場合の留意点

  1. C# では Python と比べて日本語の言語処理にやチャンク(テキスト分割)に関して圧倒的にライブラリが少ないが、html ファイルのクレンジングやテキストをチャンクする際のトークンカウンターをどうするか。
  2. ソースのブログ記事が更新されたとき、インデックス上の当該ドキュメントを削除する判断基準となるはてなブログ記事の更新日時の管理はどうするか。
  3. インデックスはキー属性が付与された値でしか削除できないので、ソースデータ更新時にどうやって削除するか。

 

留意点①:C# によるテキストのクレンジング・チャンク

C# では Python と比べて日本語の言語処理にやチャンク(テキスト分割)に関して圧倒的にライブラリが少ないが、html ファイルのクレンジングやテキストをチャンクする際のトークンカウンターをどうするか検討したところ、以下の方法がありそうです。

  1. 現状提供されている SDK/ライブラリでどうにかする
    • Python にあるようなリッチなライブラリは現状ない
      • markdown とプレーンテキストならプレビューではあるが、 Microsoft.SemanticKernel.TextChunker が対応している
  2. 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);

 
次の記事
hiro128.hatenablog.jp