文書を分けるとき、文字数で切ると話題の途中で切れることがあります。前半が宿泊費、後半が社用車という塊ができます。
実際に測ったところ、同じ平均51文字でも、文字数で切ると3話題中1つ、近さで切ると3つすべてが1つの塊に収まりました。
話題が3つ入った本文を5通りに分けました。塊の大きさが同じでも、切る位置の決め方で結果が3倍違います。
セマンティックチャンクがどう効くのかを、実際に分けて測りました。用意したのは宿泊費・社用車・健康診断という3つの話題が並んだ本文9文です。
分割も判定も本当に実行しています。ただし文の近さは共通する2文字の割合で測っており、埋め込みによる判定ではありません。
// 隣り合う文の近さ。共通する2文字の割合で測る
const sim = (a, b) => {
const A = new Set(bigrams(a)), B = new Set(bigrams(b));
let n = 0; for (const w of A) if (B.has(w)) n++;
return n / Math.max(A.size, B.size);
};
// 近さがしきい値を下回ったところで切る
const bySim = (th) => {
const out = []; let cur = SENTS[0];
for (let i = 1; i < SENTS.length; i++) {
if (sim(SENTS[i - 1], SENTS[i]) < th) { out.push(cur); cur = SENTS[i]; }
else cur += SENTS[i];
}
out.push(cur);
return out;
};
隣り合う文の近さ 1文目 → 2文目: 0.31 2文目 → 3文目: 0.29 3文目 → 4文目: 0.00 ← 話題の切れ目 4文目 → 5文目: 0.16 5文目 → 6文目: 0.18 6文目 → 7文目: 0.00 ← 話題の切れ目 7文目 → 8文目: 0.29 8文目 → 9文目: 0.33 分け方 かたまり数 平均文字数 話題が1つに収まった数 40文字ごと 4個 38文字 0 / 3 60文字ごと 3個 51文字 1 / 3 80文字ごと 2個 77文字 0 / 3 近さ0.15で切る 3個 51文字 3 / 3 近さ0.30で切る 7個 22文字 0 / 3
4行目と5行目を見比べてください。どちらも3個・平均51文字なのに、1/3と3/3で違います。
上の一覧が仕組みを示しています。同じ話題の中では0.16から0.33ですが、話題が切り替わるところは2箇所とも0.00です。
宿泊費の文と社用車の文には、共通する2文字がありません。切れ目が数字としてはっきり見えるので、しきい値を置けます。
60文字ごとに切った場合も3個できます。ところが境目が話題の途中に来るので、1つの塊に2つの話題が混ざります。
収まったのは3つ中1つだけでした。塊の数も平均文字数も同じなので、これらの数字を見ているだけでは差に気づけません。
最後の行が失敗例です。しきい値を0.30にすると、7個に割れて0/3になりました。
同じ話題の中の0.16や0.18も切れ目と判定されるためです。切れ目の値と、同じ話題の値の間に置くのが条件になります。
塊の数も大きさも同じ。違うのは境目の位置だけ。
Node parsers are a simple abstraction that take a list of documents, and chunk them into Node objects, such that each node is a specific chunk of the parent document.原文LlamaIndex Developer Documentation「Node Parser Usage Pattern」 この内容の有効期限2027-02-18
隣り合う文の近さを見て、離れたところで切ります。切る位置を文字数ではなく内容で決める方法です。
セマンティックチャンクは、隣り合う文がどれだけ近いかを測り、離れたところで切る方法です。切る位置を内容で決めます。
2番目が方法の中心です。前の節では共通する2文字の割合で代用しましたが、実際には文を数値に変えて近さを測ります。
この処理は、文書を扱う枠組みに部品として用意されています。LlamaIndexでは文書の一覧を受け取り、それぞれが元の文書の一部となる単位に分ける仕組みだと説明されています。
同じ文書では、この部品は単体でも使えるとされています。文書を取り込む流れの中に組み込むこともできます。
文字数で切る方法との違いは、計算の量にも出ます。文の数だけ数値に変える処理が必要です。
文書が1万件なら、その文の数だけ処理が走ります。文書を入れ直すたびに掛かるので、取り込みの時間に効いてきます。
測ってみて実際的だったのは、しきい値を決める前に、隣り合う文の近さを全部並べて見ることでした。前の節の一覧のように、切れ目が0.00で同じ話題が0.16以上なら、その間に置けばよいと一目で分かります。
Node parsers can be used on their own:原文LlamaIndex Developer Documentation「Node Parser Usage Pattern」 この内容の有効期限2027-02-18
しきい値を文書ごとに合わせないと崩れます。1つの値をすべての文書に当てる形では、割れすぎるものが出ます。
セマンティックチャンクの難しさは、しきい値が文書によって変わることにあります。前の節の0.15は、あの本文での値です。
同じ話題を続ける文書では、隣り合う文の近さが全体的に高くなります。逆に1文ごとに話題が変わる箇条書きでは、全体的に低くなります。
0.15という値を後者に当てると、すべての文が別々の塊になります。前の節の0.30の行と同じ状態です。
もうひとつの性質が、塊の大きさが均等にならないことです。話題の長さがそのまま塊の長さになります。
長い話題は1つの大きな塊になり、渡す量が増えます。上限を別に設けて、超えたら分けるという組み合わせが要ります。渡す量の話はチャンク戦略の記事で扱っています。
確かめるのは話題が1つの塊に収まっているかです。前の節では、話題ごとの文が1つの塊に入り、他の話題が混ざっていないかを数えました。
この判定はコードで書けます。塊の数や平均文字数だけを見ていると、1/3と3/3の差に気づけません。
しきい値は文書ごとに違う。1つの値を全部に当てない。
Node parsers can be included in any set of transformations with an ingestion pipeline.原文LlamaIndex Developer Documentation「Node Parser Usage Pattern」 この内容の有効期限2027-02-18
同じ課題を持つ会社にとって、動いている設定は「作る時間」を買えるということです。ServiceDockは自作のワークフローやテンプレートを出品できるマーケットプレイスです。手数料や出品の流れは出品者向けページにまとまっています。
出品の仕組みを見る