「コンテキストウィンドウに入るなら、全部読んでくれる」
入ることと使われることは別です。詰めるほど中ほどに置いた文書は拾われにくくなり、これは Lost in the Middle として知られています。さらに、矛盾する新旧の文書が両方入っていれば両方を読んで混ぜます。コンテキストウィンドウそのものではなく、その半分を目安にしてください。
DBC Tech Academy / AI / 中級
社内規程や設計書をもとに、LLM に答えさせたい。そう考えたとき、多くの現場が最初に RAG (Retrieval-Augmented Generation) の構成図を描き始めます。しかし社員 30 人・規程 50 ファイル程度なら、ロングコンテキスト (Long Context) に文書を丸ごと載せるだけで足りることがあります。ここでは、どこまでが「足りる」のかを料金・待ち時間・正答率・更新頻度の 4 つで判定し、組む前に方式を決める手順を扱います。
キャッシュを効かせれば 1 回 $0.116 まで下がりますが、それでも RAG の 2 倍です。月額では $206 と $101、差は月 $105 です。この額で RAG を作って運用し続ける価値があるかどうかが、判断のすべてになります。
Start here
RAG には、分割 (チャンキング)・埋め込み (embedding)・ベクトル DB・再インデックスという、作って動かし続けるものがあります。ロングコンテキストには、そのどれもありません。だから最初に問うべきは「RAG をどう組むか」ではなく、「RAG を組まずに済むか」です。
この前提を満たさないなら、そもそもロングコンテキストは選べません。満たすなら、RAG に移る理由は 4 つの数字のどれかが閾値を割ったときだけです。数字を測らずに RAG を選ぶと、要らなかった構成を作って運用し続けることになります。
分子の合計トークンは、推定せず実物を数えます。日本語は概ね 1 文字が 1 トークン前後ですが、比率は文書の中身で変わります。
コンテキストウィンドウそのものではなく半分を前提に置くのは、上限近くまで詰めると中ほどや後ろに置いた文書が使われにくくなるからです。この現象は Lost in the Middle と呼ばれ、入力が長いほど強く出ます。入ることと、読まれることは別の話です。この理由は節 02 で扱います。
| 数字 | ロングコンテキストのままにする | RAG に移る |
|---|---|---|
| 料金 | 月額の差が、RAG の構築と運用にかける額を下回る | 月額の差が、それを上回り続ける見込み |
| 待ち時間 | キャッシュが効いた状態で、最初のトークンまでが 3 秒以内 | 3 秒を超え、利用者が待てない |
| 正答率 | 現場の 30 問で、ロングコンテキストが RAG を下回らない | 下回る。とくに矛盾する文書が混ざる場合 |
| 更新頻度 | 1 日に何度も更新され、即時の反映が要る | 更新が週 1 回より粗く、再インデックスが間に合う |
更新頻度だけ向きが逆になっている点に注意してください。文書がよく変わるほどロングコンテキストが有利です。RAG は再インデックスを回すまで古い内容を返し続けますが、ロングコンテキストは現物を読み直すだけで反映されます。
ロングコンテキストは文書量に比例して増え、RAG は文書量が増えてもほぼ一定です。ここだけを見ると RAG が勝ちますが、ベクトル DB の月額と作る手間が差を埋めます。
最初のトークンが出るまでの時間 (TTFT / Time To First Token) は、入力トークン数にほぼ比例します。キャッシュに載っている入力は数分の 1 の速さで通ります。
ロングコンテキストは検索で落とす心配がない代わりに、矛盾する文書を両方読んで混同します。RAG は上位に入らなかった文書を最初から見ません。
更新から回答に反映されるまでの時間です。ロングコンテキストは読み直せば即時、RAG は再インデックスの周期より速くはなりません。
Three paths
3 つの方式は、LLM が答えを書くところまでは同じです。違いは、渡す文書を誰が選ぶかの 1 点だけにあります。選ぶ主体が違うので、外し方も違います。
この図が示しているのは、経路の違いと、文書を選ぶ主体がどこにあるかです。段数の多さは料金や速さを表しません。RAG の各段でどんな失敗が起きるかは、RAG の精度が出ない原因の切り分けで 7 段階に分けて扱っています。
RAG の正答率は、検索が正しいチャンク (chunk) を上位に置けた割合を超えられません。ロングコンテキストにはこの制約がありません。文書の中に答えがある限り、モデルの手元には必ず届いています。
とくに強いのは、文書全体をまたぐ質問です。「この規程集で、退職に関わる条項をすべて挙げてください」のような質問は、上位 8 件を返す検索とは相性が悪く、ロングコンテキストなら素直に答えられます。
改定前の規程と改定後の規程が両方入っていると、モデルは両方を読んで混ぜます。RAG では片方しか上位に来ないため、たまたま正しく見えることがあります。
対処は、渡す前に有効な版だけにすることです。版を判定できないなら、それは方式の問題ではなく文書管理の問題で、RAG に変えても解決しません。
What to measure
どれも 1 日で測れます。測らずに決めた方式は、後から覆すのに作ったものを捨てる必要が出ます。順に、測り方を見ていきましょう。
節 01 で数えた合計トークンが、そのまま 1 回あたりの入力になります。あとは月の質問数を掛けるだけです。
利用者が体感するのは、回答が出終わるまでではなく最初のトークンが出るまでです。この値を TTFT (Time To First Token) と呼び、入力トークン数にほぼ比例します。
作った人が思いつく質問ではなく、実際に聞かれている質問を 30 問集めます。問い合わせ窓口の履歴が最良の材料です。
測るのは更新の回数ではなく、更新してから回答が変わるまでの時間です。ここが業務の許容を超えると、正しく動いていても信用されなくなります。
4 つのうち、順番に意味があるのは料金と待ち時間だけです。この 2 つは文書量と質問数から計算で先に出せるので、次の節のキャッシュを踏まえて机上で詰め、正答率と更新頻度は実物を動かしてから測ります。計算だけで RAG に決まる規模なら、正答率を測る前に判断できます。
Prompt caching
ロングコンテキストの料金と待ち時間は、プロンプトキャッシュ (prompt caching) を使うかどうかで桁が変わります。これを入れずにロングコンテキストの費用を試算すると、実際の 3 倍以上の額が出ます。比較の前提として、先に仕組みを押さえます。
キャッシュは前方一致 (prefix match) で効きます。リクエストは決まった順に組み立てられ、キャッシュの区切り (cache breakpoint) より前が 1 バイトでも変わると、その後ろは全部キャッシュから外れます。したがって、毎回同じものを前に、毎回変わるものを後ろに置きます。
システムプロンプトに現在日時や利用者名を入れると、毎回すべてが書き直しになります。料金は下がらず、書き込みの割増だけが乗って請求額が 1.25 倍に増えます。効いているかどうかは、応答の cache_read_input_tokens で確かめてください。この値が 0 のままなら、区切りより前に毎回変わる文字列が入っています。
キャッシュへの書き込みには割増があり、読み出しは 10 分の 1 になります。したがって「何回読まれるか」で損得が決まります。
| TTL | 書き込み | 読み出し | 損益が分かれる |
|---|---|---|---|
| 5 分 | 1.25 倍 | 0.1 倍 | 2 回目から |
| 1 時間 | 2 倍 | 0.1 倍 | 3 回目から |
倍率は、キャッシュを使わずに同じ入力を送ったときの単価に対するものです。TTL (Time To Live) 5 分で 2 回送れば 1.25 + 0.1 = 1.35 倍となり、キャッシュを使わずに 2 回送る 2 倍より安くなります。
読み出しは、そのたびに TTL の時計を延ばします。質問の間隔が 5 分より短く続く限り、TTL 5 分で足ります。間隔が 5 分から 1 時間の範囲で開くときだけ、TTL 1 時間が割増に見合います。
ここでいう間隔は、前の質問が始まってから次の質問が始まるまでです。回答の生成にかかった時間も、この間隔に含まれます。
RAG 側では、キャッシュはほとんど効きません。渡すチャンクが質問ごとに入れ替わるため、前方一致する部分が指示文だけになるからです。逆に言えば、キャッシュの恩恵を受けられるのは、毎回同じものを送るロングコンテキストのほうです。この非対称が、次の節で見る判断の分かれ目を大きく動かします。文書一式を先にコンテキストへ載せ、キャッシュに常駐させたまま質問だけを差し替えるこの構成は、CAG (Cache-Augmented Generation) とも呼ばれます。
Move the line
文書量・質問数・キャッシュヒット率・モデルを動かすと、3 つの方式の月額と TTFT が入れ替わります。 自社に近い値を入れて、どちら側にいるのかを確かめてみましょう。
キャッシュヒット率は、前の質問から 5 分以内に次が来る割合とほぼ同じです。利用が朝夕に固まる社内システムでは 7 割から 9 割になります。RAG 側は渡すチャンクが毎回変わるため、キャッシュを効かせていません。
この図が再現しているのは、文書量を増やすとロングコンテキストだけが線形に伸び、RAG はほぼ横ばいのまま残るという向きと、その 2 本が交わる位置が質問数とモデルで動くことです。金額の絶対値は、実際の文書のトークン数・出力の長さ・ベクトル DB の構成で変わります。自社の値は count_tokens の実測と、契約しているデータベースの請求額で置き換えてください。また、この図は正答率を計算していません。正答率は前の節のとおり、現場の 30 問で実測する数字です。
| 項目 | 値 | 根拠 |
|---|---|---|
| 入力 / 出力の単価 | $5 / $25 | Opus 5。Sonnet 5 は $2 / $10、Haiku 4.5 は $1 / $5(100 万トークンあたり) |
| 日本語のトークン換算 | 1 文字 = 1 tok | 概算。実測は count_tokens |
| 質問と指示 | 400 tok | 毎回変わる部分 |
| 回答 | 700 tok | 出力側の単価が掛かる |
| RAG が渡すチャンク | 800 tok × 8 件 | 文書量が増えても変わらない |
| ベクトル DB | $70 / 月 | 小規模のマネージド構成 |
| メタデータで絞った後に残る割合 | 10% | 50 件のうち 5 件 |
文書を増やすと、ロングコンテキストだけが伸びます。RAG は渡すチャンクの数が固定なので、文書が 10 倍になっても API の料金は変わりません。文書量が増え続ける見込みなら、いずれ必ず交差します。
質問数を下げると、ロングコンテキストが逆転します。RAG にはベクトル DB の固定費があるため、質問が少ないほど不利になります。1 日 10 問なら、多くの設定でロングコンテキストのほうが安く済みます。
モデルを替えると、判断の分かれ目が大きく動きます。入力の単価が下がると、ロングコンテキストの側だけが安くなります。コンテキストウィンドウの小さいモデルでは、そもそもロングコンテキストが成立しなくなります。
The middle option
ロングコンテキストがコンテキストウィンドウに収まらない、あるいは料金が見合わない。それでも RAG を組むほどではない。この間を埋めるのが、ファイルのメタデータで数件に絞ってから、その数件を丸ごと渡す形です。メタデータフィルタ (metadata filtering) だけで済み、分割も埋め込みもベクトル DB も持ちません。
キーの取り出しは、正規表現や語の一致で足りることがほとんどです。足りなければ、質問を LLM に渡して種別を 1 語で答えさせます。分類のための呼び出しが 1 回増え、0.2 秒ほど延びます。それでも、ベクトル DB を建てて再インデックスを回し続けるより軽い作りです。
この形を選べるのは、絞り込みのキーがファイルのメタデータで表せるときだけです。部署・文書種別・年度・製品名のように、ファイル名やディレクトリで表現できるなら成立します。表現できないなら RAG です。
確かめ方は、必要なファイルが絞り込みの中に入っていた割合です。現場の 30 問について、答えに要るファイルを人が指定し、絞り込み後に残っているかを数えます。9 割を切るなら絞りすぎで、文書セットを広げるか RAG に移ります。
文書セットを固定しておくと、キャッシュが効くようになります。絞り込みの結果が質問ごとに違うと、送る文書の並びが毎回変わってキャッシュから外れます。「人事」「経理」のようにセットを数種類に固定しておけば、セットごとにキャッシュが残ります。
Citations
RAG では「どのチャンクを渡したか」が構造として残るので、出典は自然に付いてきます。ロングコンテキストでは全部を渡しているため、出典は作り込まなければ出ません。社内規程のように根拠が要る用途では、ここが方式の差になります。
文書名と、その文書の何文字目から何文字目かが返ります。画面側でその位置を強調表示すれば、利用者は原文を自分で確かめられます。モデルに「[1] のように書いてください」と指示して番号を書かせる方法より確実です。指示は守られないことがありますが、この位置情報はモデルが生成した文とひも付いて返ります。
引用 (citations) を有効にすると、根拠の無い記述が減ります。出典を出す前提で書かせると、文書に無いことを書きにくくなるためです。
引用と構造化出力は同時に使えません。回答を JSON の形で受け取る設定にすると、引用を有効にしたリクエストはエラーになります。JSON で受けたい場合は、出典を本文中の番号として書かせる指示に切り替えてください。
文書は 1 ファイル 1 ブロックで渡します。全部を 1 つの文字列に連結して渡すと、返る文字位置が連結後の位置になり、どのファイルのどこかを画面側で復元できなくなります。
Read the symptom
ロングコンテキストで組んだ直後に持ち込まれる 3 つの症状です。どれも方式そのものの限界ではなく、作り方で直せます。原因がどこにあるかを考えてみましょう。
Myth vs. reality
どれも一見もっともらしく、実際には測れば逆の結論が出ます。
入ることと使われることは別です。詰めるほど中ほどに置いた文書は拾われにくくなり、これは Lost in the Middle として知られています。さらに、矛盾する新旧の文書が両方入っていれば両方を読んで混ぜます。コンテキストウィンドウそのものではなく、その半分を目安にしてください。
1 回あたりの入力トークンは確かに数十分の 1 です。しかしベクトル DB の月額と、分割・埋め込み・再インデックスを作って回し続ける手間が加わります。質問数が少ない小規模では、月額で逆転します。API の料金だけで比べないでください。
全部を渡していても、回答に出所は自動では付きません。文書ブロックの引用を有効にするか、番号を書かせる指示を入れて初めて残ります。根拠を示す必要がある用途では、これは方式を選んだ後に必ず発生する作り込みです。
Knowledge check
答えを当てるだけでなく、なぜそう判断できるのかを説明できれば合格です。
選択肢を1つ選んでください。
Decide before you build
count_tokens で実測する。文字数からの推定で済ませない目次