Amazon Bedrock Knowledge bases のセマンティックチャンクを試してみる

Amazon Bedrock Knowledge bases のセマンティックチャンクを試してみる

Amazon Bedrock Knowledge bases のセマンティックチャンキングを試してみました。文章を文ごとに区切り、エンべディングモデルでベクトル化、隣接する文同士の類似度を計算するのがポイントです。
Clock Icon2024.09.08

Amazon Bedrock Knowledge bases のセマンティックチャンクを試してみる

こんにちは! AWS 事業本部コンサルティング部のたかくに(@takakuni_)です。

Amazon Bedrock Knowledge bases にはチャンク化戦略に大きく分けて次の戦略をサポートしています。

  • デフォルトチャンキング
  • 固定サイズのチャンキング
  • 階層チャンキング
  • セマンティックチャンキング
  • チャンキングなし

今回は「セマンティックチャンキング」のお話です。

セマンティックチャンクは、テキストを意味のあるまとまり(チャンク)に分割するチャンク化戦略です。テキストを意味のあるまとまりで分割することで、ベクトル検索性能、回答の精度向上が見込めます。

セマンティックチャンキングを使わない場合

まずは、セマンティックチャンキングを使わない場合をおさらいします。

たとえばチャンク化戦略に固定サイズを選択し、以下のようなチャンクに区切られたと想定します。

Untitled(64).png

就業規則の適用範囲」について質問したとします。赤線で囲った上部と中間のチャンクが該当する部分です。

Untitled(57).png

返すチャンクの数にもよりますが 1 つだと仮定した場合、おそらく緑の文章が返されるでしょう。

緑が返されると言うことは、 水色の文章に該当する「し、別に定める場合はこの限りではない。」の部分が抜けているため、回答精度が下がる可能性があります。

Untitled(61).png

緑色のチャンクで発生している文章の抜け や、水色のチャンクの前半部分(ノイズ) はできる限り減らしたいですよね。[1]

そこで有効なのが、文章を意味のあるまとまりにチャンク化するセマンティックチャンキングです。

セマンティックチャンキングの構造

Amazon Bedrock Knowledge bases が行う、セマンティックチャンキングは文章を文ごとに区切り、エンべディングモデルを利用して区切られた文ごとにベクトル化を行います。

隣接する文同士の類似度を計算し、非類似度が指定したパーセンタイルよりも低い場合に、文の区切れとみなしチャンク化する手法です。図にするとこのような形です。

Untitled(5) (1).png

類似度の計算にエンべディングモデルを利用するため、別途コストが発生すると記載がありました。

There are additional costs to using semantic chunking due to its use of a foundation model. The cost depends on the amount of data you have. See Amazon Bedrock pricing for more information on the cost of foundation models.

また、 3 つのパラメーターが設定可能です。

  • Maximum tokens
    • 1 つのチャンクに含めるトークンの最大数
    • 20 から 8192 の間で指定(マネジメントコンソールで確認した情報)
  • Buffer size
    • 対象の文章に合わせて結合する周囲の文章の数
    • 0 から 1 で指定(マネジメントコンソールで確認した情報)
    • バッファサイズが 1 の場合、3 つの文(現在の文、前の文、次の文)が結合される
    • バッファサイズを大きくすると、より多くのコンテキストを取り込むことができるが、ノイズが発生する可能性がある
    • バッファサイズを小さくすると、重要なコンテキストを見逃す可能性があるが、より正確なチャンキングが保証される
  • Breakpoint percentile threshold
    • 文章間の距離/非類似度のしきい値(パーセンタイル)
    • 50 から 99 で指定(マネジメントコンソールで確認した情報)
    • 90 とした場合、残り 10 パーセントの非類似している文章のペアを文の区切りとみなす
    • 閾値を高くすると、チャンク化には文章がより区別しやすい必要がある
    • しきい値が高いほど、チャンクの数は少なくなり、平均チャンクサイズも大きくなる

こだわりがなければ、デフォルトの推奨値が記載されていますね。

The recommended default values are:

  • 300 max tokens per chunk
  • 0 buffer
  • 95% breakpoint percentile threshold

For more information on the accepted values for max tokens per chunk, buffer size, and breakpoint percentile threshold, see SemanticChunkingConfiguration.

https://docs.aws.amazon.com/bedrock/latest/userguide/kb-chunking-parsing.html#kb-semantic-chunking

また、 Breakpoint percentile threshold によって分割されたチャンクのトークンサイズが、 Maximum tokens を上回った場合は、 Maximum tokens でさらに分割されるようです。

With semantic chunking, each sentence is compared to the next to determine how similar they are. You specify a threshold in the form of a percentile, where adjacent sentences that are less similar than that percentage of sentence pairs are divided into separate chunks. For example, if you set the threshold to 90, then the 10 percent of sentence pairs that are least similar are split. So if you have 101 sentences, 100 sentence pairs are compared, and the 10 with the least similarity are split, creating 11 chunks. These chunks are further split if they exceed the max token size.

https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent_SemanticChunkingConfiguration.html

やってみる

今回はセマンティックチャンキングを使ってみます。 AWS インフラの準備で利用した Terraform はこちら。

https://github.com/takakuni-classmethod/genai-blog/tree/main/knowledge_bases_semantic_chunking

なお、 AWS Provider v5.66.0 で aws_bedrockagent_data_source がセマンティックチャンキングをサポートしたのがポイントです。

ENHANCEMENTS:
resource/aws_bedrockagent_data_source: Add vector_ingestion_configuration.chunking_configuration.semantic_chunking_configuration, vector_ingestion_configuration.chunking_configuration.hierarchical_chunking_configuration, and vector_ingestion_configuration.parsing_configuration configuration blocks (#39138)

https://github.com/hashicorp/terraform-provider-aws/releases/tag/v5.66.0

main.tf
resource "aws_bedrockagent_data_source" "this" {
  name                 = "${local.prefix}-knowledge-base-datasource"
  knowledge_base_id    = aws_bedrockagent_knowledge_base.this.id
  data_deletion_policy = "DELETE" // "RETAIN"
  data_source_configuration {
    type = "S3"
    s3_configuration {
      bucket_arn = module.datasource.bucket.arn
    }
  }

+  vector_ingestion_configuration {
+    chunking_configuration {
+      chunking_strategy = "SEMANTIC"
+      semantic_chunking_configuration {
+        breakpoint_percentile_threshold = 95
+        buffer_size                     = 0
+        max_token                       = 300
+      }
+    }
+  }
}

無事、 Terraform でデプロイできてそうです。

2024-09-07 at 15.48.43-Amazon Bedrock.png

同期

それではデータソースの同期を行います。 S3 バケット内には Bedrock のユーザーガイドがアップロードされている状態です。

対象のデータソースを選択し同期をクリックします。

2024-09-07 at 15.53.46-Amazon Bedrock.png

おっと、エラーになりましたね。どうやら、ファイルサイズにも制限もありそうです。この、 1,000,000(100 万)と言う数字はおそらくトークンかと思います。

2024-09-07 at 15.56.10-Amazon Bedrock.png

Encountered error: File body text exceeds size limit of 1000000 for semantic chunking. [Files: bedrock/bedrock-ug.pdf]. Call to Customer Source did not succeed.

ファイルの分割をしてあげれば解決ですが、ファイル分割は趣旨と異なるため別の文章を用意します。

楠山正雄著の桃太郎第 1 章をデータソースとします。

桃太郎第1章.txt
むかし、むかし、あるところに、おじいさんとおばあさんがありました。まいにち、おじいさんは山へしば刈りに、おばあさんは川へ洗濯に行きました。

ある日、おばあさんが、川のそばで、せっせと洗濯をしていますと、川上から、大きな桃が一つ、「ドンブラコッコ、スッコッコ。ドンブラコッコ、スッコッコ。」と流れて来ました。

「おやおや、これはみごとな桃だこと。おじいさんへのおみやげに、どれどれ、うちへ持って帰りましょう。」

おばあさんは、そう言いながら、腰をかがめて桃を取ろうとしましたが、遠くって手がとどきません。

おばあさんはそこで、「あっちの水は、かあらいぞ。こっちの水は、ああまいぞ。かあらい水は、よけて来い。ああまい水に、よって来い。と歌いながら、手をたたきました。

すると桃はまた、「ドンブラコッコ、スッコッコ。ドンブラコッコ、スッコッコ。」といいながら、おばあさんの前へ流れて来ました。

おばあさんはにこにこしながら、「早くおじいさんと二人で分けて食べましょう。」と言って、桃をひろい上げて、洗濯物といっしょにたらいの中に入れて、えっちら、おっちら、かかえておうちへ帰りました。

夕方になってやっと、おじいさんは山からしばを背負って帰って来ました。

「おばあさん、今帰ったよ。」

「おや、おじいさん、おかいんなさい。待っていましたよ。さあ、早くお上がんなさい。いいものを上げますから。」

「それはありがたいな。何だね、そのいいものというのは。」

こういいながら、おじいさんはわらじをぬいで、上に上がりました。その間に、おばあさんは戸棚の中からさっきの桃を重そうにかかえて来て、「ほら、ごらんなさいこの桃を。」と言いました。

「ほほう、これはこれは。どこからこんなみごとな桃を買って来た。」

「いいえ、買って来たのではありません。今日川で拾って来たのですよ。」

「え、なに、川で拾って来た。それはいよいよめずらしい。」

こうおじいさんは言いながら、桃を両手にのせて、ためつ、すがめつ、ながめていますと、だしぬけに、桃はぽんと中から二つに割れて、

「おぎゃあ、おぎゃあ。」

と勇ましいうぶ声を上げながら、かわいらしい赤さんが元気よくとび出しました。

「おやおや、まあ。」

おじいさんも、おばあさんも、びっくりして、二人いっしょに声を立てました。

「まあまあ、わたしたちが、へいぜい、どうかして子供が一人ひとりほしい、ほしいと言っていたものだから、きっと神さまがこの子をさずけて下さったにちがいない。」

おじいさんも、おばあさんも、うれしがって、こう言いました。

そこであわてておじいさんがお湯をわかすやら、おばあさんがむつきをそろえるやら、大さわぎをして、赤さんを抱き上あげて、うぶ湯をつかわせました。するといきなり、

「うん。」

と言いいながら、さんは抱いているおばあさんの手をはねのけました。

「おやおや、何という元気のいい子だろう。」

おじいさんとおばあさんは、こう言って顔を見合わせながら、「あッは、あッは。」とおもしろそうに笑いました。

そして桃の中から生まれた子だというので、この子に桃太郎という名をつけました。

引用:楠山正雄 桃太郎

データソースに再度同期をかけると、エラーが発生せずに同期が完了しましたね。

2024-09-07 at 16.28.45-Amazon Bedrock.png

質問をしてみると。正しく回答が返ってきていますね。

2024-09-07 at 16.42.47-Amazon Bedrock.png

なお、チャンクは以下のブロックで分けられていました。

チャンク1
むかし、むかし、あるところに、おじいさんとおばあさんがありました。まいにち、おじいさんは山へしば刈りに、おばあさんは川へ洗濯に行きました。

ある日、おばあさんが、川のそばで、せっせと洗濯をしていますと、川上から、大きな桃が一つ、「ドンブラコッコ、スッコッコ。ドンブラコッコ、スッコッコ。」と流れて来ました。

「おやおや、これはみごとな桃だこと。おじいさんへのおみやげに、どれどれ、うちへ持って帰りましょう。」

おばあさんは、そう言いながら、腰をかがめて桃を取ろうとしましたが、遠くって手がとどきません。

おばあさんはそこで、「あっちの水は、かあらいぞ。こっちの水は、ああまいぞ。かあらい水は、よけて来い。ああまい水に、よって来い。と歌いながら、手をたたきました。
チャンク2
すると桃はまた、「ドンブラコッコ、スッコッコ。ドンブラコッコ、スッコッコ。」といいながら、おばあさんの前へ流れて来ました。

おばあさんはにこにこしながら、「早くおじいさんと二人で分けて食べましょう。」と言って、桃をひろい上げて、洗濯物といっしょにたらいの中に入れて、えっちら、おっちら、かかえておうちへ帰りました。

夕方になってやっと、おじいさんは山からしばを背負って帰って来ました。

「おばあさん、今帰ったよ。」

「おや、おじいさん、おかいんなさい。待っていましたよ。
チャンク3
さあ、早くお上がんなさい。いいものを上げますから。」

「それはありがたいな。何だね、そのいいものというのは。」

こういいながら、おじいさんはわらじをぬいで、上に上がりました。その間に、おばあさんは戸棚の中からさっきの桃を重そうにかかえて来て、「ほら、ごらんなさいこの桃を。」と言いました。

「ほほう、これはこれは。どこからこんなみごとな桃を買って来た。」

「いいえ、買って来たのではありません。今日川で拾って来たのですよ。」

「え、なに、川で拾って来た。それはいよいよめずらしい。」

こうおじいさんは言いながら、桃を両手にのせて、ためつ、すがめつ、ながめていますと、だしぬけに、桃はぽんと中から二つに割れて、

「おぎゃあ、おぎゃあ。」

と勇ましいうぶ声を上げながら、かわいらしい赤さんが元気よくとび出しました。

「おやおや、まあ。」

おじいさんも、おばあさんも、びっくりして、二人いっしょに声を立てました。

「まあまあ、わたしたちが、へいぜい、どうかして子供が一人ひとりほしい、ほしいと言っていたものだから、きっと神さまがこの子をさずけて下さったにちがいない。」

おじいさんも、おばあさんも、うれしがって、こう言いました。

そこであわてておじいさんがお湯をわかすやら、おばあさんがむつきをそろえるやら、大さわぎをして、赤さんを抱き上あげて、うぶ湯をつかわせました。するといきなり、

「うん。」

と言いいながら、さんは抱いているおばあさんの手をはねのけました。

「おやおや、何という元気のいい子だろう。」

おじいさんとおばあさんは、こう言って顔を見合わせながら、「あッは、あッは。」とおもしろそうに笑いました。

そして桃の中から生まれた子だというので、この子に桃太郎という名をつけました。

引用:[楠山正雄 桃太郎](https://www.aozora.gr.jp/cards/000329/files/18376_12100.html)

文はどう認識されるか?

セマンティックチャンキングは、文章を文ごとに区切り、ベクトル化、隣接する文の類似度をもとにチャンキングを行う手法です。

文章を文ごとに区切るロジックがどのように行われているのか、個人的に気になったので検証してみます。

Bedrock のモデル実行ログを見るに、先ほどの資料では次の絵のように文が認識されてエンべディングが行われていました。

Untitled(6).png

絵から次の規則性があることがわかります。

  • 句点(。)をもとに文章と認識している
  • 句点の次に閉じ括弧(」)が含まれる場合は閉じカッコも含めて文としている

句点がない文章はどうなるのでしょうか。と言うわけで次の文章で試してみます。

桃太郎第1章_句点なし.txt
むかし、むかし、あるところに、おじいさんとおばあさんがありましたまいにち、おじいさんは山へしば刈りに、おばあさんは川へ洗濯に行きました

ある日、おばあさんが、川のそばで、せっせと洗濯をしていますと、川上から、大きな桃が一つ、「ドンブラコッコ、スッコッコドンブラコッコ、スッコッコ」と流れて来ました

「おやおや、これはみごとな桃だことおじいさんへのおみやげに、どれどれ、うちへ持って帰りましょう」

おばあさんは、そう言いながら、腰をかがめて桃を取ろうとしましたが、遠くって手がとどきません

おばあさんはそこで、「あっちの水は、かあらいぞこっちの水は、ああまいぞかあらい水は、よけて来いああまい水に、よって来いと歌いながら、手をたたきました

すると桃はまた、「ドンブラコッコ、スッコッコドンブラコッコ、スッコッコ」といいながら、おばあさんの前へ流れて来ました

おばあさんはにこにこしながら、「早くおじいさんと二人で分けて食べましょう」と言って、桃をひろい上げて、洗濯物といっしょにたらいの中に入れて、えっちら、おっちら、かかえておうちへ帰りました

夕方になってやっと、おじいさんは山からしばを背負って帰って来ました

「おばあさん、今帰ったよ」

「おや、おじいさん、おかいんなさい待っていましたよさあ、早くお上がんなさいいいものを上げますから」

「それはありがたいな何だね、そのいいものというのは」

こういいながら、おじいさんはわらじをぬいで、上に上がりましたその間に、おばあさんは戸棚の中からさっきの桃を重そうにかかえて来て、「ほら、ごらんなさいこの桃を」と言いました

「ほほう、これはこれはどこからこんなみごとな桃を買って来た」

「いいえ、買って来たのではありません今日川で拾って来たのですよ」

「え、なに、川で拾って来たそれはいよいよめずらしい」

こうおじいさんは言いながら、桃を両手にのせて、ためつ、すがめつ、ながめていますと、だしぬけに、桃はぽんと中から二つに割れて、

「おぎゃあ、おぎゃあ」

と勇ましいうぶ声を上げながら、かわいらしい赤さんが元気よくとび出しました

「おやおや、まあ」

おじいさんも、おばあさんも、びっくりして、二人いっしょに声を立てました

「まあまあ、わたしたちが、へいぜい、どうかして子供が一人ひとりほしい、ほしいと言っていたものだから、きっと神さまがこの子をさずけて下さったにちがいない」

おじいさんも、おばあさんも、うれしがって、こう言いました

そこであわてておじいさんがお湯をわかすやら、おばあさんがむつきをそろえるやら、大さわぎをして、赤さんを抱き上あげて、うぶ湯をつかわせましたするといきなり、

「うん」

と言いいながら、さんは抱いているおばあさんの手をはねのけました

「おやおや、何という元気のいい子だろう」

おじいさんとおばあさんは、こう言って顔を見合わせながら、「あッは、あッは」とおもしろそうに笑いました

そして桃の中から生まれた子だというので、この子に桃太郎という名をつけました

引用:[楠山正雄 桃太郎](https://www.aozora.gr.jp/cards/000329/files/18376_12100.html)

実行ログの結果。句点(。)がない場合は 1 つのチャンクにまとめらていました。

{
	"schemaType": "ModelInvocationLog",
	"schemaVersion": "1.0",
	"timestamp": "2024-09-08T08:52:32Z",
	"accountId": "123456789012",
	"identity": {
		"arn": "arn:aws:sts::123456789012:assumed-role/smntc-chnkng-kb-role/PMMIDRHPFE-TextSplitterTask-61f77d4a-a31e-42c9-8ed2-9cfea85ff09"
	},
	"region": "us-west-2",
	"requestId": "9f1b3b9c-3604-4993-922d-5887875632fb",
	"operation": "InvokeModel",
	"modelId": "arn:aws:bedrock:us-west-2::foundation-model/amazon.titan-embed-text-v2:0",
	"input": {
		"inputContentType": "application/json",
		"inputBodyJson": {
			"inputText": "むかし、むかし、あるところに、おじいさんとおばあさんがありましたまいにち、おじいさんは山へしば刈りに、おばあさんは川へ洗濯に行きました\n\nある日、おばあさんが、川のそばで、せっせと洗濯をしていますと、川上から、大きな桃が一つ、「ドンブラコッコ、スッコッコドンブラコッコ、スッコッコ」と流れて来ました\n\n「おやおや、これはみごとな桃だことおじいさんへのおみやげに、どれどれ、うちへ持って帰りましょう」\n\nおばあさんは、そう言いながら、腰をかがめて桃を取ろうとしましたが、遠くって手がとどきません\n\nおばあさんはそこで、「あっちの水は、かあらいぞこっちの水は、ああまいぞかあらい水は、よけて来いああまい水に、よって来いと歌いながら、手をたたきました\n\nすると桃はまた、「ドンブラコッコ、スッコッコドンブラコッコ、スッコッコ」といいながら、おばあさんの前へ流れて来ました\n\nおばあさんはにこにこしながら、「早くおじいさんと二人で分けて食べましょう」と言って、桃をひろい上げて、洗濯物といっしょにたらいの中に入れて、えっちら、おっちら、かかえておうちへ帰りました\n\n夕方になってやっと、おじいさんは山からしばを背負って帰って来ました\n\n「おばあさん、今帰ったよ」\n\n「おや、おじいさん、おかいんなさい待っていましたよさあ、早くお上がんなさいいいものを上げますから」\n\n「それはありがたいな何だね、そのいいものというのは」\n\nこういいながら、おじいさんはわらじをぬいで、上に上がりましたその間に、おばあさんは戸棚の中からさっきの桃を重そうにかかえて来て、「ほら、ごらんなさいこの桃を」と言いました\n\n「ほほう、これはこれはどこからこんなみごとな桃を買って来た」\n\n「いいえ、買って来たのではありません今日川で拾って来たのですよ」\n\n「え、なに、川で拾って来たそれはいよいよめずらしい」\n\nこうおじいさんは言いながら、桃を両手にのせて、ためつ、すがめつ、ながめていますと、だしぬけに、桃はぽんと中から二つに割れて、\n\n「おぎゃあ、おぎゃあ」\n\nと勇ましいうぶ声を上げながら、かわいらしい赤さんが元気よくとび出しました\n\n「おやおや、まあ」\n\nおじいさんも、おばあさんも、びっくりして、二人いっしょに声を立てました\n\n「まあまあ、わたしたちが、へいぜい、どうかして子供が一人ひとりほしい、ほしいと言っていたものだから、きっと神さまがこの子をさずけて下さったにちがいない」\n\nおじいさんも、おばあさんも、うれしがって、こう言いました\n\nそこであわてておじいさんがお湯をわかすやら、おばあさんがむつきをそろえるやら、大さわぎをして、赤さんを抱き上あげて、うぶ湯をつかわせましたするといきなり、\n\n「うん」\n\nと言いいながら、さんは抱いているおばあさんの手をはねのけました\n\n「おやおや、何という元気のいい子だろう」\n\nおじいさんとおばあさんは、こう言って顔を見合わせながら、「あッは、あッは」とおもしろそうに笑いました\n\nそして桃の中から生まれた子だというので、この子に桃太郎という名をつけました\n\n引用:[楠山正雄 桃太郎](https://www.aozora.gr.jp/cards/000329/files/18376_12100.html)",
			"dimensions": 1024
		},
		"inputTokenCount": 1256
	},
	"output": {
		"outputContentType": "application/json",
		"outputBodyJson": {
			"embedding": [-0.009575531, -0.0033763358],
			"inputTextTokenCount": 1256
		}
	}
}

まとめ

以上、「Amazon Bedrock Knowledge bases のセマンティックチャンクを試してみる」でした。

日本語の場合は文を句点で認識するなど、言語ごとに文の区切りが最適化されている点がとても素敵ですね。

このブログがどなたかの参考になれば幸いです。

AWS 事業本部コンサルティング部のたかくに(@takakuni_)でした!

参考

脚注
  1. もう少し補足すると、水色のチャンクに含まれる採用の事項は「し、別に定める場合はこの限りではない。」に引っ張られたくないですよね。 ↩︎

この記事をシェアする

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.