クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

ベクトルストアで近い断片を探す方法

このレッスンのあとで: ベクトルを保存し、最も近いものを見つけられる。

60分のレッスンコマンド4件AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

5000件から近い3件を探す

ベクトルストアは、断片とそのベクトルを持ち、質問に最も近いものを見つけます。検索は、速く、最もよい数件だけを返してこそ役に立つので、これが大切です。

大学の図書館に、案内や規則の断片が5000件あります。学生が質問を打ちます。プログラムは、質問をすべての断片と比べ、近い3件を返さなければなりません。

このレッスンのゴール

メモ

ベクトルを保存し、最も近いものを見つけられる。

キーワード

ことばいみれい
ベクトルストア断片とそのベクトルのリスト
クエリベクトルにした質問
スコア断片がクエリにどれだけ近いか0.82
上位k件スコアが最もよい k 件の断片k = 3
インデックスリストのほとんどを飛ばす仕組み

学生が入力するセルは、このプレビューでは空白です。

ベクトルストアは点数付きのリスト

いちばん簡単なストアは、リストです。各要素が、id とベクトルを持ちます。探すときは、質問をベクトルにし、各要素をコサインで採点し、点数を並べ替えて、先頭の k 件を残します。

これが「最近傍探索」の意味のすべてです。最もよい結果は、点数がいちばん高い要素です。

例: クエリ [1, 0] と3つの要素

要素ベクトルコサイン順位
a[1, 0]1.001
b[1, 1]0.712
c[0, 1]0.003

学生が入力するセルは、このプレビューでは空白です。

数えるベクトルは同じ語しか合わない

このラボには埋め込みのモデルがないので、次のスクリプトは自分でベクトルを作ります。決めた語のリストについて、各語が断片に何回出るかを数えます。日本語には空白がないので、語を文の中から探して数えます。

これは代用品です。本物の埋め込みは「借りる」と「貸し出す」も近づけます。数えるベクトルは、同じ語しか見えないので、できません。

ストアのスクリプトを書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const vocabulary = [\"開き\", \"閉まり\", \"土曜\", \"日曜\", \"借り\", \"本\", \"延滞\", \"延長\", \"学習室\", \"図書館\", \"平日\", \"時間\"];' 'const chunks = [' '  { id: \"hours-weekday\", text: \"つばめ図書館は平日、午前9時に開き、午後6時に閉まります。\" },' '  { id: \"hours-weekend\", text: \"土曜日は午前10時に開き、午後2時に閉まります。日曜日は休館です。\" },' '  { id: \"borrowing\", text: \"本は8冊まで3週間借りられます。インターネットで2回まで延長できます。\" },' '  { id: \"fines\", text: \"返却が遅れた本は1日20円の延滞料がかかります。上限は1000円です。\" },' '  { id: \"rooms\", text: \"学習室は6人まで使えます。受付かインターネットで予約し、1回2時間です。\" },' '];' > store.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

ストアのスクリプトを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function vectorOf(text) {' '  return vocabulary.map(function (term) { return text.split(term).length - 1; });' '}' 'function cosine(a, b) {' '  let dot = 0, sa = 0, sb = 0;' '  for (let i = 0; i < a.length; i++) { dot += a[i] * b[i]; sa += a[i] * a[i]; sb += b[i] * b[i]; }' '  return sa === 0 || sb === 0 ? 0 : dot / Math.sqrt(sa * sb);' '}' 'const store = chunks.map(function (chunk) {' '  return { id: chunk.id, vector: vectorOf(chunk.text) };' '});' >> store.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

ストアのスクリプトを書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function search(question, k) {' '  const query = vectorOf(question);' '  return store' '    .map(function (item) { return { id: item.id, score: cosine(query, item.vector) }; })' '    .sort(function (a, b) { return b.score - a.score; })' '    .slice(0, k);' '}' 'const question = \"土曜日は何時に開きますか\";' 'console.log(\"質問:\", question);' 'search(question, 3).forEach(function (hit) {' '  console.log(hit.score.toFixed(2), hit.id);' '});' >> store.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

実行して点数を読む

コマンド
docker exec -w /home/node/project agent node store.js

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

表示される内容

行意味
質問: 土曜日は何時に開きますかクエリ
0.71 hours-weekend最もよい断片。土曜が入っている
0.35 hours-weekday次の断片。開きが入っている
0.00 borrowing3番目。共通の語がない

学生が入力するセルは、このプレビューでは空白です。

インデックスがある理由

すべての要素を採点するのは、5件でも5000件でも問題ありません。5000万件では遅くなります。検索のたびに、同じ作業を全部やり直すからです。

インデックスは、近いベクトルをまとめ、検索がリストのほとんどを飛ばせるようにします。多くのインデックスは近似です。ずっと速い代わりに、本当の最近傍を、ときどき逃すことがあります。

よくある間違い

注意

先頭の結果には、いつも答えがある、と考える人が多くいます。先頭は、いちばん近い断片にすぎません。ストアに近いものがなければ、先頭は、いちばん悪くないものです。信じる前に、スコアを見ます。

このラボとソースについて: AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。