8月20日、Towards Data Scienceが「Kimi K3's 1M Token Context Window vs. RAG: Cost, Latency and Answer Quality」と題した記事を公開した。この記事では、100万トークンのコンテキストウィンドウを持つKimi K3を使い、RAGと「全文コンテキスト投入」をコスト・レイテンシ・回答品質の3軸で実測比較した実験について詳しく紹介されている。
「RAGはもう不要か?」という問いの立て方
Moonshot AIが開発したKimi K3は、100万トークンのコンテキストウィンドウを持つ推論モデルだ。著者が過去2年間にMediumとTowards Data Scienceに公開した記事32本(33本あることは後で判明)を全部まとめると、合計127,068トークン。これはウィンドウの約12%に過ぎない。
「全部突っ込めばRAGのパイプラインを丸ごと省けるのでは?」という発想は自然だ。しかし「入る」と「うまく動く」は別の話である。そこでこの実験が生まれた。
RAGが長年支持されてきた理由として、コンテキスト長の制約以外にも「安い」「速い」「ソースを追跡できる」の3点がある(Google DeepMindの論文でも言及される)。この3点をそのまま検証軸にした。
実験設計:同一コーパスを2つのパスで処理
RAGパス:32本の記事を900・150オーバーラップ(元記事ではtokenとcharacterのいずれか明示されていないが、チャンク数788からみて概ねトークン単位と推測される)で788チャンクに分割し、all-MiniLM-L6-v2で埋め込みを生成する。all-MiniLM-L6-v2はSentence Transformersが提供する軽量な埋め込みモデルで、ローカル実行が可能なためRAGパイプラインのコスト計算をシンプルに保てる。質問ごとに上位5チャンクを渡す。1リクエストあたり約1,200トークン。
long_contextパス:32本をそのままプロンプトに全部入れて質問する。1リクエストあたり約127,346トークン。
2つのパスで同じ12問を投げ、同じモデル(Kimi K3)、同じシステムプロンプトを使う。
SYSTEM_PROMPT = (
"You answer questions about a collection of articles written by one author. "
"Use only the provided article text. If the text does not contain the answer, "
"say so plainly instead of guessing. When you state a fact, name the article "
"title it comes from."
)
コスト設計の肝はプレフィックスキャッシングだ。コーパスを質問より先に置くことで、2問目以降のキャッシュヒット率を最大化する。プレフィックスキャッシングはKimi K3固有の機能ではなく、OpenAI・Anthropic・Google等の主要APIが対応しつつある業界標準的な最適化手法で、同一プレフィックスを持つリクエストをAPIサーバー側でKVキャッシュから再利用する仕組みだ。Kimi K3ではキャッシュされたトークンの単価は**$0.30/Mトークン、キャッシュミス時は$3.00/Mトークンと10倍の差**がある。質問を先に書いてしまうと毎回キャッシュミスになり、実験コストが数倍に膨らむ。
messages = [
{"role": "system", "content": config.SYSTEM_PROMPT},
{"role": "user", "content": f"{context}\n\n---\n\nQuestion: {question}"},
]
質問は3グループ、難易度で分けた理由
12問はA・B・Cの3グループに分類される。
- グループA(単一事実):答えが1つの記事の1か所にある。RAGが最も得意とするパターン。
- グループB(クロス記事):2〜3本の記事をまたいだ情報統合が必要。例:「RAGとファインチューニングをどう使い分けているか、自己矛盾がある箇所も含めて」。
- グループC(コーパス全体):全記事を見ないと答えられない。例:「GitHubリポジトリにリンクしている記事は何本か」。
グループCではRAGが負けることは明白だ。問題は「どう負けるか」——情報がないと正直に言うか、それっぽい嘘をつくかが観測ポイントになる。
実験中に起きた3つの失敗
結果より、この失敗談の方が実装上の教訓として重い。
失敗1:回答の半分が空欄で、最初は気づかなかった
最初の実行はターミナル上では完全に正常に見えた。エラーなし、abortなし、レイテンシも自然。ところがExcelでグレーディングシートを開くと、24問中12問が空欄、さらに3問が単語の途中で切れていた。
原因はmax_completion_tokensの仕様だ。Kimi K3は推論モデルであり、内部の「思考トークン」が出力トークン上限を食いつぶす。上限を800に設定していたが、難しい質問では800トークン全部を思考に使い、回答用のトークンが残らなかった。finish_reasonはlengthを返しており、他のメトリクスは一見正常に見えた。
@property
def truncated(self) -> bool:
"""The model ran out of completion budget before finishing its answer."""
return self.finish_reason == "length" or not self.answer.strip()
教訓:推論モデルではmax_completion_tokensは「回答の長さの上限」ではなく「思考バジェット」として機能する。finish_reasonをログに残さないと、この失敗は検知できない。
失敗2:同一リクエストが1回目は失敗、2回目は成功
上限を4,000トークンに上げてほぼ全問通ったが、「全記事で最も多く言及されているツールは何か」という質問(C2)だけは3,997トークン思考して空欄を返した。同じコンテキスト・同じ文面で再実行すると、今度は正常に回答が生成された。推論モデルでは同一入力でも結果が確率的に変わることを示す事例だ。
失敗3:ブラインド評価が完全ではなかった
「X」「Y」でシャッフルして採点したが、RAGパスの回答に「based on the text chunks I have」という自己言及フレーズが含まれており、どちらのパスか判別できてしまった。次回はこうした自己開示表現を採点前に除去すべきだという反省が残った。
結果:3軸の実測値
採点軸は「正確性」「完全性」「根拠の明示(グラウンデッド)」の3項目・各0〜2点、12問の合計最大72点。
スコア(回答品質):long_contextが52/72点、RAGが45/72点。差はグループB・Cで顕著で、クロス記事・コーパス全体の質問ではlong_contextが明確に上回った。グループA(単一事実)ではRAGもlong_contextも拮抗した。
コスト:RAGパスは1リクエストあたり約1,200トークンと小さいため、12問の合計コストは数セント程度。long_contextパスは1リクエストあたり約127,346トークンを投入するが、プレフィックスキャッシングが機能した2問目以降はキャッシュヒット単価($0.30/M)が適用され、12問合計でも$0.10前後に収まった。キャッシングなしであれば同じ問い合わせが$1.00超になる計算で、キャッシュ設計の有無がlong_contextの経済性を左右する。
レイテンシ:long_contextパスは初回リクエストで大量のトークンをプリフィルする都合上、1問目のTime-to-First-Tokenが数秒単位で長い。2問目以降はキャッシュヒットにより短縮されるが、RAGパスの平均レイテンシは一貫してlong_contextを下回った。レイテンシが厳しいリアルタイム用途ではRAGが有利という結論は変わらない。
「正確かどうか」と「記事テキストに基づいているかどうか」は別問題で、後者(グラウンデッド)が特に重要な観点とされている。RAGパスはチャンク単位で取得するため、文書全体の文脈が失われてクロス記事の問いで根拠が不完全になりやすい傾向が観測された。
使い分けの指針
著者が示す使い分けの基準は以下だ。
- RAGが有利な場面:コストとレイテンシが制約になる場合、ソースの追跡が必要な場合、単一事実の取り出しが中心の場合。
- long_contextが有利な場面:コーパス全体を横断した質問、複数記事の統合、RAGパイプラインの構築・保守コストを払えない小規模プロジェクト。プレフィックスキャッシングが使えるAPIであれば、コスト面のデメリットは大幅に緩和される。
コードの全実装はGitHubリポジトリで公開されている。
詳細はKimi K3's 1M Token Context Window vs. RAG: Cost, Latency and Answer Qualityを参照していただきたい。