+ 作るログイン
図を読み込んでいます…
1 / 14
RAG のすべて ― 基礎から現在の形、そして難しさまで / 全15章

RAG 02:いちばん小さな RAG ― 端から端まで作る

発行
アニメモ公式
版
第1版
改訂
コマ
全14

RAG を最小の部品で端から端まで組み立てます。前もって資料を読み込み・切り・ベクトルにして保存する「準備」と、質問のたびに近い資料を探して LLM に読ませ、出典を添えて返す「本番」の2つの時間帯に分け、TypeScript の短いコードで書きます。LangChain・LlamaIndex などの枠組みとの関係、そして素朴な RAG がどこで壊れるのか(後の章の地図)まで。

いちばん小さな RAG を、端から端まで作る

第0章で RAG の流れ(質問 → 探す → 集める → 読ませる → 答える)を見て、第1章で「読ませる」側の LLM の性質を見ました。この章では、その流れ全体を、いちばん素朴な部品だけで、端から端まで組み立ててみます。

なぜ「素朴な形」から始めるのでしょうか。理由は2つあります。

1つ目は、全体像がつかめるからです。RAG の本や記事には、リランキング、ハイブリッド検索、GraphRAG…と、たくさんの手法が出てきます(名前は今は覚えなくてかまいません。後の章で1つずつ説明します)。でも、それぞれが「流れのどの段を、どう良くする話なのか」は、素朴な形を知らないと見えません。

2つ目は、実務でもこれが出発点だからです。最初から全部入りの仕組みを作るより、まず一番簡単な形を動かし、実際の質問で試して、失敗した段だけを直していくほうが、ずっと早くうまくいきます。

この章で作る RAG は、資料が数百〜数千件くらいまでなら、そのまま動きます。コードは TypeScript で書きますが、Python でもやることは同じです。

※この章は 2026年9月時点の情報をもとにしています。ライブラリや製品の名前、API の書き方は変わりやすいので、使うときは公式の資料で確かめてください。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 1 / 14
  • いちばん小さな RAG を、端から端まで作る
  • 休暇は何日?
  • 集めた資料
  • 規程 第3条
  • 質問
  • 検索
  • 有給の日数表
  • LLM
  • 答え
  • 資料庫
  • この章は RAG の流れ全体の話。どの部品も「いちばん素朴なやり方」で作る
  • 素朴な形を知っておくと、後の章の工夫が「どこを直す話か」が分かる
  • 探す → 集める → 読ませる → 答える。まずは最小の部品で、全部を一度つなげる。

RAG は2つの時間帯に分かれる:準備と本番

RAG を作るとき、最初に頭に入れておきたいのは、仕事が2つの時間帯に分かれていることです。

時間帯いつ動くかやること
準備(索引づくり)前もって。資料が増えたり変わったりしたとき資料を読み込み、切り、ベクトル(数の並び。③で説明)にして保存する
本番(質問への回答)利用者が質問するたびに質問をベクトルにし、近い資料を探し、LLM に読ませて答える

索引(インデックス)とは、本の巻末の索引のように「すぐ探せるように整えておいたもの」のことです。たとえるなら、図書館です。準備は、本を仕入れて、分類して、目録カードを作って棚に並べる仕事。本番は、利用者に「こういうことを調べたい」と聞かれて、目録から本を探して手渡す仕事です。目録づくりは閉館後にまとめてやればよく、利用者を待たせる必要はありません。

図の上のレーンが準備、下のレーンが本番です。2つをつないでいるのは、上の「保存する」から下の「近いものを探す」に伸びた矢印、つまり保存した索引だけです。

この分け方には実務上の意味があります。準備は時間がかかってもよいので、重い処理(PDF の解析や、大量の文章のベクトル化)はこちらに寄せます。本番は利用者を待たせるので、できるだけ軽くします。次のページから、上のレーンの左から順に見ていきます。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 2 / 14
  • RAG は2つの時間帯に分かれる:準備と本番
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • 準備:資料を読み込み、切り、ベクトルにして保存する(索引づくり。インデックス作成とも)
  • 本番:質問をベクトルにし、近い資料を探し、LLM に読ませて答える
  • 資料を探せる形にしておく「準備」と、質問のたびに走る「本番」。別々に動く。

準備①:資料を読み込んで、文字にする

最初の段は、資料を読み込んで、ただの文字に直すことです。

社内の資料は、PDF、Word、Excel、PowerPoint、Web ページ(HTML)、社内 Wiki など、いろいろな形で置かれています。後で使う検索の仕組みも LLM も、読めるのは基本的に文字だけなので、まず中身の文字を取り出します。

このとき、文字と一緒に出典(どのファイルの何ページか)も覚えておきます。後で答えに「就業規則.pdf 3ページ」と添えるための情報です。この段で捨ててしまうと、後から取り戻せません。

素朴な RAG では、形式ごとのライブラリで文字を取り出すだけにします。

形式素朴な取り出し方
テキスト・Markdownそのまま読む
HTMLタグを取り除いて本文だけにする
PDFPDF から文字を抜き出すライブラリを使う
Word など形式に対応したライブラリで本文を抜き出す

実は、ここが一番地味で、一番よく壊れる段です。PDF の表が崩れる、2段組みの文章が混ざる、スキャンした PDF からは文字が1つも取れない…。こうした問題と対処は、次の第3章でまとめて扱います。この章では「とりあえず文字になった」ところから進みます。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 3 / 14
  • 準備①:資料を読み込んで、文字にする
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • 休暇規程
  • PDF
  • HTML
  • Word
  • 第3条 有給休暇は、入社6か月後に10日を…
  • 出典: 就業規則.pdf 3ページ
  • PDF も Word も Web ページも、まずは「ただの文字」に直す。ここが崩れると全部崩れる。

準備②:長い文書を、小さな塊(チャンク)に切る

次に、取り出した長い文章を、チャンクと呼ぶ小さな塊に切ります。

なぜ切るのでしょうか。1万字の就業規則を丸ごと1件として扱うと、「休暇は何日?」という質問に対して、就業規則全体が「近い」か「遠い」かしか判断できません。しかも、見つかった後で1万字を丸ごと LLM に渡すことになります。第1章で見たとおり、読ませる量が多いほど高く・遅く・見落としやすくなります。

小さく切っておけば、質問に効く部分だけを拾って渡せます。

素朴な切り方は「決まった長さで切る」です。長さはトークン(第1章で見た、LLM が文章を読むときの単位。「LLM にとっての1語」のようなもの)で数えることが多く、たとえば800トークンずつ切り、切れ目で文が途切れても前後のつながりが残るように、隣のチャンクと100トークンくらい重ねておきます。

決めること素朴な出発点気にすること
大きさ数百〜千トークンくらい小さすぎると文脈が消え、大きすぎると焦点がぼける
重なり大きさの1〜2割くらい重ねすぎると同じ文が何度も拾われる

この数字は「まず試す値」であって、正解ではありません。見出しで切る、意味の切れ目で切る、といった工夫は第3章で詳しく見ます。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 4 / 14
  • 準備②:長い文書を、小さな塊(チャンク)に切る
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • 長い文書(就業規則・1万字)
  • チャンク1
  • チャンク2
  • チャンク3
  • チャンク4
  • 例:800トークンずつ、前後を100トークン重ねて切る(数字は出発点。第3章)
  • 検索で拾う単位を作る。細かすぎず大きすぎず。切り方の工夫は第3章で。

準備③:チャンクを「意味の座標」に変える

切ったチャンクを、1つずつ埋め込みモデル(文章を数の並びに変える専用の AI)に渡して、ベクトル(数の並び)に変えます。これを埋め込み(エンベディング)と呼びます。

ベクトルは、文章の意味を表す座標のようなものです。地図の上で、近い場所は緯度と経度の数字も近くなります。埋め込みも同じで、意味の近い文章は、近い数の並びになるように作られています。「有給休暇は何日?」と「年次休暇の日数」は、使っている言葉が違っても、近い座標になります。

地図は2つの数(緯度・経度)ですが、埋め込みのベクトルは、モデルによって数百から数千個の数でできています。この数の個数を次元と呼びます(地図なら2次元)。それだけ細かく「意味の違い」を表せるということです。

実装としては、埋め込みモデルを提供している会社の API(プログラムから呼び出す窓口。第1章)に、チャンクの文字を送ると、ベクトルが返ってくるだけです。自分のサーバーで動かせる公開モデルもあります。

1つ大事な決まりがあります。準備で使った埋め込みモデルと、本番で質問をベクトルにするモデルは、同じものにすることです。モデルが違うと、座標の決め方そのものが違うので、近いかどうかを比べられません。モデルを変えたら、準備をやり直します。埋め込みの仕組みと選び方は第4章で見ます。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 5 / 14
  • 準備③:チャンクを「意味の座標」に変える
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • 「有給は入社6か月で10日…」
  • [0.12, -0.53, 0.88, 0.07, … ]
  • 意味の近い文章は、近い数の並びになる。地図の座標のようなもの(第4章)
  • 埋め込みモデルが、文章を数百〜数千個の数の並び(ベクトル)に変える。

準備④:本文・ベクトル・出典を一緒に保存する

最後に、チャンクごとに次のものをまとめて保存します。

保存するもの何に使うか
IDどのチャンクかを指す名札。更新や削除、出典の表示に使う
本文見つかった後、LLM に読ませる
ベクトル質問と「近いか」を比べる
出典ファイル名・ページ・URL。答えに添えて見せる

よくある勘違いは、「ベクトルにしたら、本文は要らない」というものです。ベクトルは座標であって、そこから元の文章を読み戻すことはできません。探すのはベクトルで、読ませるのは本文です。

保存先は、最初は何でもかまいません。数千件くらいなら、JSON ファイルに書き出して、起動時にメモリに読み込むだけで十分です。件数が増えたり、複数のサーバーから使ったりするようになったら、ベクトル DB(ベクトルを保存して近いものを速く探せるデータベース)を使います。

ID の付け方は、後で効いてきます。「就業規則の3番目のチャンク」のように、元の資料と順番から決まる ID にしておくと、資料が改訂されたときにどのチャンクを差し替えればよいかが分かります(第3章)。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 6 / 14
  • 準備④:本文・ベクトル・出典を一緒に保存する
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • ID
  • 本文 / ベクトル / 出典
  • kyuka-03
  • 有給は入社6か月で10日… / [0.12, …] / 就業規則.pdf p.3
  • kyuka-04
  • 勤続年数に応じて最大20日… / [0.09, …] / 就業規則.pdf p.3
  • keihi-11
  • 交通費の精算は翌月10日まで… / [-0.41, …] / 経費の手引き p.2
  • ベクトルだけでは答えられない。本文と出典も並べて、あとで取り出せるようにする。

本番①②:質問もベクトルにして、近いチャンクを探す

ここから下のレーン、利用者が質問するたびに動く「本番」です。

まず、質問の文を、準備と同じ埋め込みモデルでベクトルにします。次に、保存しておいた全部のチャンクのベクトルと比べて、近い順に並べ、上位 k 個を取ります。図では、上位3つが休暇の資料、4番目の経費の資料は遠いので取りません。

「近さ」の測り方として一番よく使われるのが、コサイン類似度です。ベクトルを、地図の基準点から座標へ向かう矢印だと考えてください。2本の矢印が同じ向きを向いているほど1に近く、関係ないほど0に近くなります(詳しくは第4章)。図の左の数字(0.91 など)が、そのイメージです。

決めること素朴な出発点
何個取るか(k)3〜5個くらいから試す
近さの測り方コサイン類似度
探し方全部のチャンクと1件ずつ比べる

k を大きくすると、答えの載ったチャンクを取りこぼしにくくなりますが、LLM に渡す量が増えて、高く・遅く・見落としやすくなります(第1章)。小さくすると逆です。

「全部と1件ずつ比べる」のは素朴ですが、数千件なら一瞬で終わります。数百万件になると遅すぎるので、近似最近傍探索(全部と比べる代わりに、少しの誤差を許して「だいたい一番近いもの」を素早く見つける方法)を使います(第5章)。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 7 / 14
  • 本番①②:質問もベクトルにして、近いチャンクを探す
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • 左の数字=質問との近さ(1に近いほど近い)
  • 0.91
  • kyuka-04 勤続年数に応じて最大20日…
  • 休暇は何日もらえる?
  • 0.88
  • kyuka-03 有給は入社6か月で10日…
  • 0.64
  • kyuka-07 慶弔休暇は…
  • 0.21
  • keihi-11 交通費の精算は…(取らない)
  • 質問と同じ埋め込みモデルで座標にし、近い順に上位 k 個(例:4個)を取る。

本番③:資料と質問を並べて、頼み文を組む

探したチャンクを、質問と一緒に並べて、LLM への頼み文(プロンプト)を組み立てます。素朴な形は、図のようなものです。

次の資料だけを根拠に答えてください。
資料に無いことは「資料には書かれていません」と答えてください。
答えの文ごとに、使った資料の番号を [1] のように付けてください。

[1] 勤続年数に応じて最大20日…
[2] 有給は入社6か月で10日…
[3] 慶弔休暇は…

質問:休暇は何日もらえる?

短い文ですが、第1章で見た LLM の弱点への対策が詰まっています。

一文対策している弱点
資料だけを根拠に覚えている不確かな知識で答えてしまう
無ければ無いと答えて知らなくても、それらしく作ってしまう(ハルシネーション)
番号を付けて根拠が見えず、人が確かめられない

資料に番号を振っておくのがコツです。LLM が「[2]」と書けば、それがどのチャンクか、プログラムの側で分かります。

資料を並べる順番(大事なものを先頭に置く、など)や、指示の書き方の工夫は、第8章で詳しく見ます。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 8 / 14
  • 本番③:資料と質問を並べて、頼み文を組む
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • 次の資料だけを根拠に答えてください。資料に無いことは「資料には書かれていません」と答えてください。
  • [1] 勤続年数に応じて最大20日… [2] 有給は入社6か月で10日… [3] 慶弔休暇は…
  • 質問:休暇は何日もらえる? 答えの文ごとに、使った資料の番号を [1] のように付けてください。
  • 「この資料だけを根拠に。無ければ無いと。番号で出典を」。頼み方の工夫は第8章。

本番④⑤:LLM に答えさせ、出典を添えて返す

組み立てた頼み文を LLM に送ると、答えが返ってきます。図の例では「入社6か月で10日です [2]。勤続年数に応じて、最大20日まで増えます [1]。」となりました。

最後に、答えの中の [1] や [2] を、元の出典に戻して画面に出します。準備の段で保存しておいた出典(就業規則.pdf 3ページ)が、ここで生きてきます。利用者は、気になった答えについて、元の資料を開いて確かめられます。

ここで1つ注意があります。LLM が付けた番号が、本当にその資料の内容に基づいているかは、保証されていません。LLM は、資料 [1] の内容を書いたのに [2] と書いてしまうこともありますし、資料に無いことを書いて、それらしい番号を付けてしまうこともあります。

確かめ方やり方の例
形の確認存在しない番号([7] など)が付いていないか、プログラムで確かめる
中身の確認答えの各文が、付いた資料で裏付けられるかを別に確かめる(第12章)

素朴な RAG では、形の確認だけでもしておくとよいでしょう。答えを画面に流しながら表示する(ストリーミング)場合も、出典の一覧は最後にまとめて付ける、という作りが扱いやすいです。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 9 / 14
  • 本番④⑤:LLM に答えさせ、出典を添えて返す
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • 入社6か月で10日です [2]。
  • [1]
  • 就業規則.pdf 3ページ
  • 勤続年数に応じて、最大20日まで増えます [1]。
  • [2]
  • 就業規則.pdf 3ページ
  • LLM が付けた番号が本当にその資料の内容かは、別に確かめる価値がある(第8・12章)
  • 答えに付いた番号を、元の資料名とページに戻して見せる。人が確かめられる形にする。

コードで書くと(準備)

ここまでの準備の流れを、TypeScript で書くと次のようになります。枠組み(ライブラリ)を使わない、素朴な書き方です。

ts
type Chunk = { id: string; text: string; source: string };
type Indexed = Chunk & { vector: number[] };

// 長い文章を size 文字ずつ、overlap 文字重ねて切る(トークンの代わりに文字数で近似)
function split(doc: { name: string; text: string }, size = 800, overlap = 100): Chunk[] {
  const out: Chunk[] = [];
  for (let start = 0, n = 0; start < doc.text.length; start += size - overlap, n++) {
    out.push({ id: `${doc.name}#${n}`, text: doc.text.slice(start, start + size), source: doc.name });
  }
  return out;
}

const docs = await loadFiles("./docs");             // PDF・HTML → { name, text }
const chunks = docs.flatMap((d) => split(d));
const vectors = await embed(chunks.map((c) => c.text)); // 埋め込み API を呼ぶ
const index: Indexed[] = chunks.map((c, i) => ({ ...c, vector: vectors[i] }));
await writeFile("index.json", JSON.stringify(index));

上から順に、次のことをしています。

コードしていること
type Chunk / Indexedチャンク(ID・本文・出典)と、それにベクトルを足したものの形を決める
split文章を800文字ずつ、100文字ずつ重ねながら切り、「ファイル名#番号」の ID を付ける(簡単にするため、ここではトークンではなく文字数で数えている)
loadFilesフォルダの資料を読み込み、文字にする(形式ごとのライブラリを呼ぶ自作の関数)
embedチャンクの文字をまとめて埋め込み API に送り、ベクトルを受け取る
index / writeFile本文・出典・ベクトルを組にして、JSON ファイルに保存する

埋め込み API には一度に送れる件数の上限があるので、実際には数十〜数百件ずつに分けて呼びます。切る長さは、実際には文字数よりトークン数で数えるほうが正確です(第1章)。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 10 / 14
  • コードで書くと(準備)
  • // 準備:資料を読み込み、切って、ベクトルにして保存する
  • const docs = await loadFiles("./docs"); // PDF・HTML → 文字と出典
  • const chunks = docs.flatMap((d) => split(d, 800, 100)); // 800文字ずつ、100重ねる(例)
  • const vectors = await embed(chunks.map((c) => c.text)); // 埋め込みAPIを呼ぶ
  • const index = chunks.map((c, i) => ({ ...c, vector: vectors[i] }));
  • await save("index.json", index); // 小さければファイルで十分
  • loadFiles・split・embed は自分で書くか、ライブラリの部品を使う。
  • embed は使う会社の埋め込み API を呼ぶだけの小さな関数。
  • 読み込む・切る・ベクトルにする・保存する。枠組みを使わなければ、この程度の量。

コードで書くと(本番)

本番の流れです。準備で作った index を読み込んでおき、質問のたびに次を実行します。

ts
// 2つのベクトルの向きの近さ(コサイン類似度)
function cosine(a: number[], b: number[]): number {
  let dot = 0, na = 0, nb = 0;
  for (let i = 0; i < a.length; i++) { dot += a[i] * b[i]; na += a[i] ** 2; nb += b[i] ** 2; }
  return dot / (Math.sqrt(na) * Math.sqrt(nb));
}

async function ask(question: string, index: Indexed[]) {
  const [qv] = await embed([question]);
  const hits = index
    .map((c) => ({ ...c, score: cosine(qv, c.vector) }))
    .sort((a, b) => b.score - a.score)
    .slice(0, 4);
  const context = hits.map((h, i) => `[${i + 1}] ${h.text}`).join("\n\n");
  const answer = await llm(
    `次の資料だけを根拠に答えてください。資料に無いことは「資料には書かれていません」と答えてください。\n` +
    `答えの文ごとに、使った資料の番号を [1] のように付けてください。\n\n${context}\n\n質問:${question}`,
  );
  return { answer, sources: hits.map((h, i) => ({ no: i + 1, source: h.source, id: h.id })) };
}
コードしていること
cosine2つのベクトルの同じ位置の数を掛けて足し、それぞれの長さで割る。向きがそろうほど1に近い
embed([question])質問を、準備と同じモデルでベクトルにする
map → sort → slice全チャンクに近さ(score)を付け、大きい順に並べ、上位4個を取る
context取ったチャンクに [1]〜[4] の番号を付けて、1つの文字列につなぐ
llm(…)頼み文を LLM の API に送り、答えを受け取る
return答えと、番号ごとの出典を返す

温度(答えのぶれ)は低めにしておくとよいでしょう(第1章)。

これで、いちばん小さな RAG が完成です。準備と本番を合わせても、補助の関数を除けば数十行です。第0章で「作るのは簡単」と言ったのは、このことです。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 11 / 14
  • コードで書くと(本番)
  • const [qv] = await embed([question]);
  • const hits = index
  • .map((c) => ({ ...c, score: cosine(qv, c.vector) })) // 向きの近さ
  • .sort((a, b) => b.score - a.score)
  • .slice(0, 4); // 上位4個
  • const context = hits.map((h, i) => `[${i + 1}] ${h.text}`).join("\n\n");
  • const answer = await llm(`次の資料だけを根拠に…\n${context}\n\n質問:${question}`);
  • return { answer, sources: hits.map((h) => h.source) };
  • 全部を1件ずつ比べる素朴な探し方。数千件なら十分速い(多いときは第5章)。
  • 質問をベクトルにし、近い順に並べて上位を取り、頼み文に並べて LLM に渡す。

枠組みを使うか、自分で書くか

RAG を作るための枠組み(フレームワーク)も、たくさんあります。代表的なのは次の2つです。

枠組み特徴
LangChainLLM を使ったアプリの部品(読み込み、分割、埋め込み、検索、LLM 呼び出し)をつなぐ汎用の枠組み。Python と TypeScript 版がある
LlamaIndex資料の取り込みと索引づくりに力を入れた枠組み。いろいろな形式の読み込み部品がそろっている

保存先(ベクトル DB)の選択肢も多くあります。PostgreSQL にベクトルを扱う機能を足す pgvector、手元ですぐ試せる Chroma、ベクトル検索専用の Qdrant、サーバーの管理を提供会社に任せられるマネージド型のサービスなどです。

どれを使うかより大事なのは、中で何が起きているかを知っていることです。枠組みを使うと、数行で RAG が動きます。でも、うまく答えられないとき、「どのチャンクが拾われたのか」「LLM に何が渡ったのか」が見えないと、直しようがありません。

おすすめの進め方は、次のとおりです。

段階やり方
最初この章のように自分で書くか、枠組みを使っても「拾ったチャンク」と「渡した頼み文」を必ず記録して見られるようにする
部品が増えてきたら読み込みの部品など、自分で書くと大変なところから枠組みやライブラリに頼る
件数が増えたらファイル保存からベクトル DB に移す(第5章)
  • RAG のすべて 02 ― いちばん小さな RAG
  • 12 / 14
  • 枠組みを使うか、自分で書くか
  • 自分で書く
  • LangChain
  • LlamaIndex
  • 中身が全部見える
  • 部品をつなぐ汎用の枠組み
  • 資料の取り込みと索引が得意
  • 保存先(ベクトル DB)の例
  • ファイル・メモリ
  • pgvector
  • Chroma
  • Qdrant
  • マネージド型
  • どれを選んでも、中でやっていることはこの章の流れと同じ
  • 最初は自分で書いて中身を知り、部品が増えてきたら枠組みやベクトル DB を検討する。

どこで壊れるか:この本の残りの地図

いちばん小さな RAG は、デモではよく動きます。でも、本物の資料と本物の質問で試すと、あちこちで壊れます。図の赤い箱は、どれも壊れうる段です。

壊れ方起きる段直し方を見る章
PDF の表や段組みが崩れて、正しい文字にならない読み込む・切る第3章
切れ目が悪く、答えが2つのチャンクに割れる切る第3章
質問と資料の言葉が違うと見つからない/型番のような語に弱いベクトルにする・探す第4・6章
近いが答えの無いチャンクが上位に来る探す第5・7章
質問があいまい・複数の問いが混ざっている質問第9章
正しい資料を渡したのに、無視したり付け足したりする頼み文・生成第8章
1回探すだけでは答えが集まらない全体第10・11章
直したつもりが、本当に良くなったのか分からない全体第12章

最後の行が特に大事です。素朴な RAG を作ったら、実際にありそうな質問と、その正しい答えを数十個用意して、試してみてください。どの質問で、どの段が失敗したのかを1つずつ見ていくと、次に何を直せばよいかが分かります。測り方は第12章で詳しく扱います。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 13 / 14
  • どこで壊れるか:この本の残りの地図
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • 表が崩れる(3章)
  • 言い換えに弱い(4・6章)
  • 順位が甘い(5・7章)
  • 質問があいまい(9章)
  • 資料を無視する(8章)
  • 効果を測れない(12章)
  • まずは一度つなげて動かし、どこで失敗しているかを見るのが近道
  • 素朴な RAG は、どの段でも壊れうる。後の章は、それぞれの段の直し方。

まとめ:準備4段と本番5段

この章で見たことをまとめます。

段やること素朴なやり方深める章
読み込む資料を文字と出典にする形式ごとのライブラリ第3章
切るチャンクにする決まった長さ+重なり第3章
ベクトルにする意味の座標にする埋め込み API第4章
保存するID・本文・ベクトル・出典JSON ファイル第5章
探す質問に近いチャンク上位 k 個全部とコサイン類似度第5〜7章
頼み文資料と質問を並べる「資料だけを根拠に」第8章
生成・出典答えと出典を返す番号を出典に戻す第8・12章

RAG は「準備」と「本番」の2つの時間帯に分かれ、つなぐのは保存した索引だけです。準備で使った埋め込みモデルと、本番のモデルは同じにします。

まず動くものを作り、実際の質問で試し、壊れた段を直す。次の第3章では、最初の段である「資料を読み込んで、切る」を詳しく見ます。地味ですが、ここの質が RAG 全体の上限を決めます。

  • RAG のすべて 02 ― いちばん小さな RAG
  • 14 / 14
  • まとめ:準備4段と本番5段
  • 準備(前もって。資料が変わったらやり直す)
  • 読み込む
  • 切る
  • ベクトルにする
  • 保存する
  • 本番(質問のたびに)
  • 質問
  • ベクトルにする
  • 近いものを探す
  • プロンプト組立
  • 生成する
  • 出典を添える
  • 準備
  • 読み込む → 切る → ベクトルにする → 保存する(資料が変わったら)
  • 本番
  • 質問をベクトルに → 近いものを探す → 頼み文 → 生成 → 出典
  • 要の部品
  • 埋め込みモデル・保存先・LLM の3つ。どれも差し替えられる
  • 動くものを先に作る。そうすれば、どこを直せば良くなるのかを確かめながら進める。

0 件のコメント

読み込み中…

権利侵害・不適切な内容の連絡: [email protected]