長い案内の中にある1つの答え
文書を分ける (チャンク化) とは、文書を、1つずつ見つけて読めるほど小さな断片に切ることです。検索は断片をまるごと返すので、断片の大きさが、手に入るものを決めます。
図書館に、開館時間、貸出のルール、学習室をまとめた案内が1枚あります。利用者が延滞料を尋ねます。答えは1文です。案内をまるごと渡すと、答えが埋もれます。
このレッスンのゴール
メモ
文書を、各断片が見つけられるように分けられる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| 断片 (チャンク) | 分けた文書の1つの部分 | |
| 断片の大きさ | 1つの断片の文字数 | 12 |
| 重なり | 続く2つの断片が共有する文字 | |
| 句点 | 文の終わりを示す、「。」の記号 | |
| 検索 | 質問に答える断片を見つけること |
学生が入力するセルは、このプレビューでは空白です。
なぜ文書を断片に切るのか
案内1枚に1つのベクトルでは、すべての話題が1つの平均に混ざります。延滞料の質問も、学習室の質問も、案内に同じくらいの近さに見えます。
小さな断片は1つのことを話すので、ベクトルがはっきり向きます。あとでプロンプトに入れるときも、ほかの数個と並べられる短さです。
断片の大きさと重なり
日本語には単語の間の空白がないので、いちばん簡単な分け方は、文字を数えることです。12文字の断片は12文字を持ちます。次の断片は、前の終わりより少し手前から始めます。この共有する文字が重なりです。
重なりは、考えが途中で切れるのを防ぎます。断片の端にある言葉が、次の断片の先頭にも入ります。
例: 10文字を、大きさ4・重なり1で分ける
| 断片 | 始まる文字 | 中身 |
|---|---|---|
| 1 | 1文字目 | あいうえ |
| 2 | 4文字目 | えおかき |
| 3 | 7文字目 | きくけこ |
学生が入力するセルは、このプレビューでは空白です。
句点で切ると、考えが保てる
文字数は、考えがどこで終わるかを知りません。句点「。」は知っています。句点で文に分ければ、各断片が1つの文になります。
次のスクリプトは両方を行います。案内を句点で文に分け、そのうち1つの文を、文字数で、重なりを付けて切ります。
分けるスクリプトを書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const sheet = \"つばめ図書館のご案内です。平日は午前9時に開き、午後6時に閉まります。土曜日は午前10時に開きます。日曜日は休館です。本は8冊まで3週間借りられます。返却が遅れると1日20円かかります。\";' 'function bySentence(text) {' ' const parts = [];' ' let current = \"\";' ' Array.from(text).forEach(function (letter) {' ' current = current + letter;' ' if (letter === \"。\") {' ' parts.push(current);' ' current = \"\";' ' }' ' });' ' if (current.length > 0) parts.push(current);' ' return parts;' '}' > chunk.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
分けるスクリプトを書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function byLetters(text, size, overlap) {' ' const letters = Array.from(text);' ' const chunks = [];' ' let start = 0;' ' while (start < letters.length) {' ' chunks.push(letters.slice(start, start + size).join(\"\"));' ' if (start + size >= letters.length) break;' ' start = start + size - overlap;' ' }' ' return chunks;' '}' 'const sentences = bySentence(sheet);' 'console.log(\"文ごとに分ける:\", sentences.length, \"個\");' 'sentences.forEach(function (one) { console.log(\"-\", one.length, \"文字:\", one); });' 'const pieces = byLetters(sentences[1], 12, 4);' 'console.log(\"12文字ずつ、重なり4:\", pieces.length, \"個\");' 'pieces.forEach(function (piece) { console.log(\"-\", piece); });' >> chunk.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
実行して断片を読む
docker exec -w /home/node/project agent node chunk.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
表示される主な行
| 行 | 意味 |
|---|---|
| 文ごとに分ける: 6 個 | 句点ごとに1つの断片 |
| - 22 文字: 平日は午前9時に開き、午後6時に閉まります。 | 2つ目の文の長さ |
| 12文字ずつ、重なり4: 3 個 | 2つ目の文を3つに切った |
| - 閉まります。 | 先頭4文字の「閉まりま」は、前の断片の終わりでもある |
学生が入力するセルは、このプレビューでは空白です。
よくある間違い
注意
大きな断片のほうが多く含むので安全だ、と考える人が多くいます。大きな断片は、複数の話題が混ざった1つのベクトルを持ち、プロンプトも埋めます。答えを1つ含む、いちばん小さな断片を選びます。