第3章 LLM活用の基本(Understand the Basics)
3.1 概要
Section titled “3.1 概要”第2章ではLLMという部品の内部的な性質を見た。本章では、その部品をどう使うかという選択肢を扱う。ここで扱う6つのトピックは、いずれもエージェントの設計判断に直結する。
- 応答をストリーミングするか否かは、UXとエラーハンドリングの両方に影響する
- 推論モデルを使うか否かは、精度・レイテンシ・コストのトレードオフを決める
- ファインチューニングするか否かは、開発プロセス全体の重さを変える
- 埋め込みとRAGは、エージェントのメモリ(第8章)と知識アクセスの土台になる
重要なのは、これらがすべて**「どちらが優れているか」ではなく「どの状況でどちらを選ぶか」**の問題であるという点である。本章は各トピックについて判断基準を示すことを目的とする。
3.2 ストリーミング応答と非ストリーミング応答
Section titled “3.2 ストリーミング応答と非ストリーミング応答”3.2.1 何が違うのか
Section titled “3.2.1 何が違うのか”非ストリーミング(unstreamed / blocking) では、モデルが全出力を生成し終えてから、完成したレスポンスが一度に返る。ストリーミング(streamed) では、生成されたトークンが順次サーバー送信イベント(SSE、Server-Sent Events)として届く。
第2章で見たとおり、LLMは自己回帰的に1トークンずつ生成する。したがって「全部できてから返す」のは、単に途中経過を見せないという選択にすぎない。実際の生成速度は変わらない。
3.2.2 使い分けの基準
Section titled “3.2.2 使い分けの基準”| 状況 | 推奨 | 理由 |
|---|---|---|
| ユーザーが応答を読む対話型UI | ストリーミング | 体感待ち時間が劇的に短くなる |
| 長文生成(レポート、記事) | ストリーミング | 非ストリーミングだとタイムアウトのリスクがある |
| エージェントの内部ステップ(ツール選択など) | 非ストリーミング | 完全な出力が揃わないとパースできない |
| 構造化出力(JSON)を機械処理する | 非ストリーミング | 途中のJSONは不完全でパースできない |
| バッチ処理・評価実行 | 非ストリーミング | 誰も見ていないので逐次性に意味がない |
エージェントにおける実務上の重要な指針は、「ユーザーに見せる最終応答はストリーミング、内部の中間ステップは非ストリーミング」という使い分けである。エージェントループの各ステップでツール呼び出しの引数を生成させる場面では、JSONが完成するまで何もできないため、ストリーミングの利点がない。
ただし例外として、進捗の可視化のためにストリーミングを使う設計はありうる。「いま検索ツールを実行しています」といった中間状態をユーザーに見せることで、長時間動くエージェントの体感品質は大きく改善する。この場合、ストリーミングするのはモデルの生出力ではなく、エージェント側が生成する進捗イベントである。
3.2.3 実装例
Section titled “3.2.3 実装例”import anthropic
client = anthropic.Anthropic()
# ストリーミング: 最終応答をユーザーに逐次表示するwith client.messages.stream( model="claude-sonnet-5", max_tokens=2048, messages=[{"role": "user", "content": "AIエージェントの設計原則を説明して"}],) as stream: for text in stream.text_stream: print(text, end="", flush=True)
# ストリーム完了後、完全なメッセージオブジェクトを取得できる final = stream.get_final_message() print(f"\n\n[使用トークン: 出力 {final.usage.output_tokens}]")import Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic()
// ストリーミング: 最終応答をユーザーに逐次表示する// Python 版は with 文でストリームを閉じるが、JavaScript に相当構文は無い。// text_stream の代わりに 'text' イベントを購読するconst stream = client.messages.stream({ model: 'claude-sonnet-5', max_tokens: 2048, messages: [ { role: 'user', content: 'AIエージェントの設計原則を説明して' }, ],})stream.on('text', (text) => process.stdout.write(text))
// ストリーム完了後、完全なメッセージオブジェクトを取得できるconst final = await stream.finalMessage()console.log(`\n\n[使用トークン: 出力 ${final.usage.output_tokens}]`)# 非ストリーミング: ツール呼び出しの判断など、内部ステップ向けresponse = client.messages.create( model="claude-sonnet-5", max_tokens=1024, temperature=0, tools=[...], # 第7章 messages=conversation,)# 完全なレスポンスが揃っているので、安全に分岐できるif response.stop_reason == "tool_use": ...// 非ストリーミング: ツール呼び出しの判断など、内部ステップ向けconst response = await client.messages.create({ model: 'claude-sonnet-5', max_tokens: 1024, temperature: 0, tools: [], // 第7章 messages: conversation,})// 完全なレスポンスが揃っているので、安全に分岐できるif (response.stop_reason === 'tool_use') { // ...}3.2.4 ストリーミング特有の落とし穴
Section titled “3.2.4 ストリーミング特有の落とし穴”長時間の非ストリーミングリクエストはタイムアウトしうる。 大きな max_tokens を指定した非ストリーミングリクエストは、ネットワーク経路上のプロキシやロードバランサのアイドルタイムアウトに引っかかることがある。長い出力を扱う場合は、たとえ逐次表示しなくてもストリーミングで受け取り、内部で結合するのが安全である。
エラーがストリームの途中で来る。 非ストリーミングならHTTPステータスコードで一括判定できるが、ストリーミングでは接続が確立した後に error イベントが流れてくる場合がある。ストリームの途中で失敗したときに、すでにユーザーに表示した部分をどう扱うか(そのまま残すか、エラー表示に切り替えるか)を設計しておく必要がある。
トークン使用量は最後にしかわからない。 使用量はストリーム終盤の message_delta に含まれる。コスト計測はストリーム完了後に行う。
3.3 推論モデルと標準モデル
Section titled “3.3 推論モデルと標準モデル”3.3.1 推論モデルとは
Section titled “3.3.1 推論モデルとは”推論モデル(Reasoning Model) は、最終回答を出す前に内部で思考過程(thinking / reasoning)を生成するモデルである。この思考過程は追加の出力トークンとして消費されるが、多段の論理を要する問題での正答率を大きく引き上げる。
第2章で見た自己回帰生成の性質を思い出すと、この仕組みの意味がわかる。モデルは1トークンずつ予測しており、途中で「立ち止まって考える」ことができない。思考過程を明示的に生成させることは、モデルに計算のための作業領域を与えることに等しい。
近年のモデルでは、思考の有無と深さをモデル自身が判断する adaptive thinking(適応的思考) が既定の動作になっている。Claude Opus 5 / Sonnet 5 / Fable 5 などがこれにあたり、リクエストごとに「考える必要があるか」をモデルが評価する。
3.3.2 effort による制御
Section titled “3.3.2 effort による制御”adaptive thinking では、思考の深さと頻度を effort パラメータで調整する。effort は応答全体に投入する労力を表すシグナルであり、トークン予算の直接指定ではない。
| effort | 挙動 | 備考 |
|---|---|---|
low |
最も効率重視。トークン消費を大きく削減する代わりに能力が一部低下する | 簡単な問題では思考を省略しうるが、難問では低 effort でも思考する |
medium |
バランス型。適度なトークン節約 | |
high |
既定値。 パラメータを省略した場合と同一の挙動 | |
xhigh |
長時間タスク向けの拡張。high より明確にトークン消費が増える |
Opus 5 では思考を無効化できない |
max |
能力の絶対最大。トークン消費に制約をかけない | Opus 5 では思考を無効化できない |
重要: effort の既定値は high である。 つまり明示的に下げない限り、すべての呼び出しが high で実行される。エージェントは1タスクで何十回もLLMを呼ぶため、「単純なステップでは意識的に low / medium に落とす」ことがコスト管理の要点になる。「必要なところを上げる」のではなく「不要なところを下げる」という発想が正しい。
また、effort はトップレベル引数ではなく output_config の中にネストする。
import anthropic
client = anthropic.Anthropic()
response = client.messages.create( model="claude-opus-5", max_tokens=16000, thinking={"type": "adaptive", "display": "summarized"}, output_config={"effort": "high"}, # ← output_config の中に入れる messages=[{"role": "user", "content": "この障害の根本原因を特定して"}],)
for block in response.content: if block.type == "thinking": print(f"[思考過程]\n{block.thinking}\n") elif block.type == "text": print(f"[回答]\n{block.text}")import Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic()
const response = await client.messages.create({ model: 'claude-opus-5', max_tokens: 16000, thinking: { type: 'adaptive', display: 'summarized' }, output_config: { effort: 'high' }, // ← output_config の中に入れる messages: [{ role: 'user', content: 'この障害の根本原因を特定して' }],})
for (const block of response.content) { if (block.type === 'thinking') { console.log(`[思考過程]\n${block.thinking}\n`) } else if (block.type === 'text') { console.log(`[回答]\n${block.text}`) }}# 単純なステップでは effort を落としてコストとレイテンシを抑えるrouting = client.messages.create( model="claude-opus-5", max_tokens=256, output_config={"effort": "low"}, # 分類なので浅くてよい messages=[{"role": "user", "content": "この問い合わせを分類して: ..."}],)// 単純なステップでは effort を落としてコストとレイテンシを抑えるconst routing = await client.messages.create({ model: 'claude-opus-5', max_tokens: 256, output_config: { effort: 'low' }, // 分類なので浅くてよい messages: [{ role: 'user', content: 'この問い合わせを分類して: ...' }],})注意点
- 思考トークンは出力トークンとして課金される。effort を上げるとコストとレイテンシが増える
- 最新モデルでは
displayの既定値が"omitted"(思考内容を返さない)になっており、思考過程を見たい場合は"summarized"を指定するbudget_tokensを指定する旧来の extended thinking は Claude 4.7 以降では非対応であり、adaptive thinking への移行が必要であるxhigh/maxを指定した状態でthinking: {"type": "disabled"}を送ると 400 エラーになる(Opus 5)
3.3.3 エージェントでの使い分け
Section titled “3.3.3 エージェントでの使い分け”推論モデルは万能薬ではない。単純なタスクに使うと、遅く高価になるだけで精度は上がらない。
既定が high であることを踏まえると、設計の作業は「どこを 下げる か」を決めることになる。
| エージェント内の場面 | 推奨 effort | 理由 |
|---|---|---|
| デバッグ・根本原因分析 | xhigh 〜 max |
仮説検証の連鎖が必要。上げる価値がある数少ない場面 |
| タスクの分解・計画立案 | high(既定のまま) |
誤ると全体が破綻する。最も投資価値が高い |
| 複数ツール結果の統合・矛盾解決 | high 〜 medium |
複数情報源の突き合わせは多段の論理を要する |
| ツール選択(選択肢が明確) | low 〜 medium |
パターンマッチに近く、思考の効果が薄い |
| 分類・ルーティング | low |
単純な判断。速度が重要 |
| 結果の整形・要約 | low |
難易度が低く、呼び出し回数が多い |
| 定型的な応答生成 | low |
同上 |
呼び出し回数の多いステップほど下げる効果が大きい。1タスクにつき1回しか走らない計画立案を high のままにしても総額への影響は小さいが、8回走るツール選択と8回走る要約を low に落とすと、全体のコストは大きく変わる。
エージェント設計の実践的なパターンとして、「計画フェーズは既定の高い effort のまま使い、実行フェーズは明示的に落とす」という役割分担が有効である。これは第9章の Planner-Executor アーキテクチャの根拠のひとつでもある。
3.3.4 推論モデルとツール呼び出しの相互作用
Section titled “3.3.4 推論モデルとツール呼び出しの相互作用”推論モデルは、ツール呼び出しと組み合わせたときに特に効果を発揮する。ツールの実行結果を受け取った後で「この結果は妥当か」「次に何をすべきか」を考えるステップは、まさに多段推論が必要な場面だからである。
一方で注意点もある。思考ブロックを含む会話履歴を次のターンに渡す際、思考ブロックをそのまま保持する必要がある(プロバイダによっては署名付きで整合性が検証される)。エージェントループで履歴を自前で組み立てる場合、思考ブロックを削ってしまうとエラーになったり、モデルの推論の連続性が失われたりする。SDKの提供する会話履歴管理を使うか、レスポンスの content 配列をそのまま保持する実装にすべきである。
3.4 ファインチューニングとプロンプトエンジニアリング
Section titled “3.4 ファインチューニングとプロンプトエンジニアリング”3.4.1 二つのアプローチ
Section titled “3.4.1 二つのアプローチ”プロンプトエンジニアリング(Prompt Engineering) は、モデルの重みを変えずに入力を工夫して望む挙動を引き出す手法である。ファインチューニング(Fine-tuning) は、追加の学習データでモデルの重み自体を更新する手法である。
現在利用可能な主なファインチューニング手法は3つある。
| 手法 | 概要 | 適した状況 |
|---|---|---|
| SFT(Supervised Fine-Tuning、教師あり) | 「入力→望ましい出力」のペアで学習 | 望ましい出力例が大量にある。定型的なフォーマットや文体を固定したい |
| DPO(Direct Preference Optimization、直接選好最適化) | 「Aの方がBより良い」という選好比較で学習 | 良し悪しの判断はできるが、理想の出力を書き下すのが難しい |
| RFT(Reinforcement Fine-Tuning、強化学習) | 報酬関数を定義し、強化学習で最適化 | 正解を自動採点できる。複雑な推論タスク |
3.4.2 判断のフローチャート
Section titled “3.4.2 判断のフローチャート”大原則: まずプロンプトエンジニアリングを尽くす。 ファインチューニングは、プロンプトで到達できない領域に踏み込むための最後の手段である。
3.4.3 それぞれの向き不向き
Section titled “3.4.3 それぞれの向き不向き”プロンプトエンジニアリングが向く場面は、反復が速いこと(数分で試せる)、コストがほぼゼロであること、モデルを差し替えても移植しやすいことから、圧倒的に広い。エージェント開発においては、挙動の調整の9割以上がプロンプト側で解決する。
ファインチューニングが向く場面は限定的だが明確である。
- 出力フォーマットを厳密に固定したい: 毎回同じ構造の出力が必要で、プロンプトで指示しても揺れる場合
- プロンプトを短縮したい: 長大な指示をモデルに内在化させることで、毎回の入力トークンを削減できる。呼び出し回数が極めて多いエージェントでは、これがコスト面で効く
- 特定ドメインの文体・専門用語に適応させたい: 医療、法務、社内固有の表現体系など
- 小型モデルで大型モデル並みの性能を出したい: 特定タスクに絞ってファインチューニングした小型モデルが、汎用の大型モデルを上回ることがある。レイテンシとコストの両面で有利
ファインチューニングが解決しない問題も明確にしておきたい。
- 知識の追加: 「社内の最新情報を覚えさせたい」という目的には向かない。情報が更新されるたびに再学習が必要になり、かつ学習した知識は不正確に想起されやすい。これはRAG(3.6節)の役割である
- 推論能力の向上: 汎用的な思考力そのものは上がらない
- ハルシネーションの根絶: 減らせる場合はあるが、なくなるわけではない
3.4.4 エージェント開発における現実的な位置づけ
Section titled “3.4.4 エージェント開発における現実的な位置づけ”エージェント開発の初期から中期において、ファインチューニングを検討する必要はほぼない。理由は、エージェントの性能を決めているのがモデルの挙動よりもシステム設計だからである。ツールの説明文が曖昧、コンテキストが溢れている、エラーハンドリングがない — こうした問題はファインチューニングでは解決しない。
ファインチューニングが選択肢に入るのは、システム設計が固まり、評価基盤(第11章)が整備され、「プロンプトではこれ以上上がらない」ことがデータで示された後である。
3.5 埋め込みとベクトル検索
Section titled “3.5 埋め込みとベクトル検索”3.5.1 埋め込みとは
Section titled “3.5.1 埋め込みとは”埋め込み(Embedding) とは、テキストを固定長の数値ベクトルに変換したものである。意味的に近いテキストはベクトル空間上でも近い位置に配置されるように学習されている。
これにより、キーワードが一致しなくても意味が近ければ検索できるようになる。「有給休暇の申請方法」というクエリで「年次休暇の取得手続きについて」という文書がヒットする、といった具合である。
3.5.2 類似度の測り方
Section titled “3.5.2 類似度の測り方”最も一般的なのはコサイン類似度(cosine similarity) で、2つのベクトルのなす角度に基づいて -1 〜 1 の値を返す。1に近いほど意味的に近い。多くの埋め込みモデルは正規化済みベクトルを返すため、内積(dot product)を使っても等価になる。
import numpy as np
def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float: return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))// Python 版は numpy を使うが、TypeScript では素の配列で書くfunction cosineSimilarity(a: number[], b: number[]): number { // numpy は次元数が違えば例外を投げる。同じ前提を明示的に確認する if (a.length !== b.length) { throw new Error('ベクトルの次元数が一致していません') } const dot = a.reduce((sum, x, i) => sum + x * (b[i] ?? 0), 0) const normA = Math.sqrt(a.reduce((sum, x) => sum + x * x, 0)) const normB = Math.sqrt(b.reduce((sum, x) => sum + x * x, 0)) return dot / (normA * normB)}実運用では全件との類似度を総当たりで計算するのは非効率なため、ANN(Approximate Nearest Neighbor、近似最近傍探索) を用いたベクトルDBを使う。HNSWやIVFといったインデックス方式により、精度をわずかに犠牲にして検索速度を桁違いに上げる。
3.5.3 埋め込みモデルの選定
Section titled “3.5.3 埋め込みモデルの選定”2026年時点の主な選択肢を挙げる。
| モデル | 提供元 | 次元数 | 最大入力 | 価格 / 1M tokens |
|---|---|---|---|---|
| voyage-3-large | Voyage AI | 1,024 | 32,000 | $0.18 |
| embed-v4 | Cohere | 256/512/1,024/1,536(既定 1,536) | 128,000 | $0.10 |
| jina-embeddings-v3 | Jina AI | 1,024 | 8,192 | $0.02 |
| text-embedding-3-large | OpenAI | 3,072 | 8,191 | $0.13 |
| text-embedding-3-small | OpenAI | 1,536 | 8,191 | $0.02 |
| GTE-large-en-v1.5 | Alibaba | 1,024 | 8,192 | 無料(オープン) |
| nomic-embed-text-v1.5 | Nomic AI | 768 | 8,192 | 無料(オープン) |
(出典: Text Embedding Models 2026 比較、2026年7月29日参照。価格・性能は変動するため導入時に再確認すること)
選定にあたって見るべき観点は次のとおりである。
① 次元数: 大きいほど表現力が高いが、ストレージと検索コストが増える。1,024次元前後が実務的なバランス点になっている。OpenAIの text-embedding-3-* や Cohere の embed-v4 は次元数を縮約するオプション(Matryoshka表現)を持ち、精度をあまり落とさずにコストを下げられる。
② 最大入力長: チャンク分割の粒度を決める制約になる。512トークン程度しか入らない旧世代のモデル(BGE、E5 など。上表には未掲載)では細かく刻む必要があり、文脈が失われやすい。逆に embed-v4(128,000トークン)や voyage-3-large(32,000トークン)のように長文をそのまま扱えるモデルなら、章や節をまるごと1チャンクにする設計も選べる。
③ 多言語性能: MTEBなどのベンチマークスコアは英語中心のことが多い。日本語での性能は別途確認が必要である。 日本語文書を扱うなら、多言語対応を明示しているモデル(voyage、Cohere embed、多言語版のオープンモデルなど)を候補にし、自前のデータで比較評価すべきである。
④ 一貫性: 検索対象の文書とクエリは必ず同じ埋め込みモデルでベクトル化する。モデルを変更したら、全文書の再インデックスが必要になる。これは運用上の大きなコストになるため、初期選定は慎重に行う。
from openai import OpenAI
client = OpenAI()
def embed(texts: list[str]) -> list[list[float]]: response = client.embeddings.create( model="text-embedding-3-small", input=texts, dimensions=512, # 次元縮約でストレージと検索コストを削減 ) return [d.embedding for d in response.data]
vectors = embed(["有給休暇の申請方法", "経費精算の締め日"])print(f"次元数: {len(vectors[0])}")import OpenAI from 'openai'
const client = new OpenAI()
async function embed(texts: string[]): Promise<number[][]> { const response = await client.embeddings.create({ model: 'text-embedding-3-small', input: texts, dimensions: 512, // 次元縮約でストレージと検索コストを削減 }) return response.data.map((d) => d.embedding)}
const vectors = await embed(['有給休暇の申請方法', '経費精算の締め日'])console.log(`次元数: ${vectors[0]?.length}`)3.5.4 埋め込みの限界
Section titled “3.5.4 埋め込みの限界”埋め込みによる意味検索は強力だが、苦手な領域がある。
- 固有名詞・型番・IDの厳密一致: 「型番 XR-4471B」のような検索は、意味的類似度ではなくキーワード一致の方が強い
- 否定表現: 「Aを含まない文書」といった条件は、埋め込みでは表現しにくい
- 数値範囲・日付範囲: 「2026年4月以降の議事録」のような条件はメタデータフィルタで処理すべきである
これらの弱点を補うため、実務ではハイブリッド検索が標準的な構成になっている。ベクトル検索とBM25等のキーワード検索を組み合わせ、スコアを統合する方式である。
3.6 RAGの基礎
Section titled “3.6 RAGの基礎”3.6.1 RAGとは
Section titled “3.6.1 RAGとは”RAG(Retrieval-Augmented Generation、検索拡張生成) は、LLMに回答させる前に外部の知識源から関連情報を検索し、それをコンテキストに含めて回答させる手法である。
RAGが解決する問題は3つある。第一に、モデルの学習データに含まれない知識(社内文書、最新情報)を扱えるようにすること。第二に、出典を提示できるようにすること。第三に、ハルシネーション(もっともらしい嘘)を減らすことである。
3.6.2 基本的なパイプライン
Section titled “3.6.2 基本的なパイプライン”各工程で押さえるべき要点を述べる。
チャンク分割(Chunking): 文書を検索単位に切り分ける工程。ここが品質を最も左右する。小さすぎると文脈が失われ、大きすぎるとノイズが混ざる。実務では 300〜800トークン程度を基準に、段落や見出しといった意味的な境界で切るのが定石である。前後のチャンクを少し重複させる(オーバーラップ)ことで、境界をまたぐ情報の欠落を防ぐ。
メタデータの付与: チャンクに文書名、章タイトル、更新日、アクセス権限などを付けておくと、検索時のフィルタリングと出典提示に使える。これは軽視されがちだが、実運用では極めて重要である。
リランキング(Reranking): ベクトル検索で上位30件程度を粗く取り、専用のリランカーモデルで精密に並べ替えて上位5件に絞る。この二段構えは、精度向上のコストパフォーマンスが高い。
プロンプトへの挿入: 取得した文脈をどう提示するかも設計対象である。出典番号を付けて「回答には必ず [1] のように出典を示すこと」と指示すると、検証可能性が上がる。
3.6.3 「コンテキストが100万トークンならRAGは不要か」
Section titled “3.6.3 「コンテキストが100万トークンならRAGは不要か」”コンテキストウィンドウが100万トークンに達した現在、「文書を全部入れればRAGは要らない」という議論がある。これは部分的には正しいが、一般化はできない。
判断の材料を整理する。
| 観点 | 全文投入(Long Context) | RAG |
|---|---|---|
| 知識量の上限 | コンテキストウィンドウまで | 実質無制限 |
| コスト | 毎回全量に課金される | 検索した数千トークンのみ |
| レイテンシ | 入力が長いほど遅い | 検索のオーバーヘッドはあるが入力は短い |
| 更新の反映 | 即座(毎回読み込むため) | 再インデックスが必要 |
| 出典の提示 | 難しい | 容易(チャンク単位で追跡できる) |
| アクセス制御 | 難しい | 容易(メタデータでフィルタ) |
| 精度 | 情報が少量なら高い | 検索精度に依存する |
実務的な指針は次のようになる。
- 扱う文書が数万トークン以下で固定なら、全文投入が最も簡単で精度も高い。プロンプトキャッシュ(第2章)と組み合わせればコストも抑えられる
- 文書が大量、または頻繁に更新されるなら、RAGが必要
- 出典提示やアクセス制御が要件なら、コンテキスト長にかかわらずRAGが必要
- 両方を組み合わせる構成も有効である。RAGで関連文書を絞り込んだうえで、絞り込んだ文書は丸ごと(チャンクではなく全文で)投入する、といった設計は精度が高い
3.6.4 エージェントにおけるRAG — 「検索」から「探索」へ
Section titled “3.6.4 エージェントにおけるRAG — 「検索」から「探索」へ”エージェント時代のRAGには、従来型との重要な違いがある。
従来のRAGは単発の検索である。質問を1回ベクトル化し、1回検索し、1回回答する。これに対しエージェント型の検索(agentic search / agentic RAG)では、検索そのものをツールとしてエージェントに与える。
エージェント型の利点は次の点にある。曖昧な質問に対して自らクエリを組み立て直せること、複数の観点から段階的に検索を重ねられること、検索結果が不十分だと判断したら別の情報源に切り替えられること、そして複数のサブ質問に分解して並列に調べられることである。
その代償として、レイテンシとコストは増える。単純な事実検索には従来型のRAGで十分であり、複雑な調査タスクにエージェント型を使う、という使い分けが妥当である。
RAGの詳細、特に長期記憶としての活用は第8章「エージェントメモリ」で、検索ツールの設計は第7章で扱う。
3.7 主要モデルの料金(2026年7月時点)
Section titled “3.7 主要モデルの料金(2026年7月時点)”第2章で料金体系の構造を扱ったので、ここでは設計に織り込む視点を補足する。
3.7.1 価格帯の整理
Section titled “3.7.1 価格帯の整理”具体的な単価は第2章2.2.2節の表を参照してほしい。 ここで繰り返さないのは、価格が頻繁に改定されるため、本書内で二重に持つと片方が古くなるからである。
用途と価格帯の対応だけ整理しておく。
| 価格帯 | 該当するモデル | エージェントでの用途 |
|---|---|---|
| フロンティア | Claude Fable 5 / Opus 5、GPT-5.6 Sol | 長時間動く複雑なエージェント、計画立案 |
| バランス | Claude Sonnet 5、GPT-5.6 Terra、Gemini 3.6 Flash | 汎用エージェントの主力 |
| 軽量 | Claude Haiku 4.5、GPT-5.6 Luna、Gemini 3.5 Flash-Lite | 分類・要約・高頻度の呼び出し |
第2章2.6節で述べた役割ごとのモデル使い分けは、この3層に対応している。
3.7.2 コストを設計に織り込む
Section titled “3.7.2 コストを設計に織り込む”エージェント開発では、プロトタイプの段階でコストモデルを作っておくことを推奨する。動くものができてから「本番のトラフィックだと月額いくらか」を計算して、設計をやり直すのは手戻りが大きい。
最低限、次の数値を把握しておきたい。
- 1タスクあたりの平均トークン数(入力・出力別、キャッシュヒット分を区別して)
- 1タスクあたりの平均ステップ数
- 想定される月間タスク数
# 簡易コスト推定PRICING = { # USD per 1M tokens (2026-07-29 時点) "claude-sonnet-5": {"input": 3.00, "output": 15.00, "cache_read": 0.30}, "claude-haiku-4-5": {"input": 1.00, "output": 5.00, "cache_read": 0.10},}
def estimate_monthly_cost( model: str, tasks_per_month: int, input_tokens_per_task: int, cached_tokens_per_task: int, output_tokens_per_task: int,) -> float: p = PRICING[model] per_task = ( input_tokens_per_task / 1_000_000 * p["input"] + cached_tokens_per_task / 1_000_000 * p["cache_read"] + output_tokens_per_task / 1_000_000 * p["output"] ) return per_task * tasks_per_month
cost = estimate_monthly_cost( "claude-sonnet-5", tasks_per_month=50_000, input_tokens_per_task=25_000, # キャッシュミス分 cached_tokens_per_task=120_000, # キャッシュヒット分 output_tokens_per_task=6_000,)print(f"推定月額: ${cost:,.2f}")// 簡易コスト推定const PRICING: Record< string, { input: number; output: number; cacheRead: number }> = { // USD per 1M tokens (2026-07-29 時点) 'claude-sonnet-5': { input: 3.0, output: 15.0, cacheRead: 0.3 }, 'claude-haiku-4-5': { input: 1.0, output: 5.0, cacheRead: 0.1 },}
// Python 版はキーワード引数で呼び分けるが、TypeScript に相当構文は無い。// トークン数の引数を取り違えないよう、オブジェクトで受け取るinterface CostParams { model: string tasksPerMonth: number inputTokensPerTask: number cachedTokensPerTask: number outputTokensPerTask: number}
function estimateMonthlyCost(params: CostParams): number { const p = PRICING[params.model] // Python の dict は未登録のキーで KeyError になる。同じ振る舞いを明示的に書く if (p === undefined) { throw new Error(`単価が未登録のモデル: ${params.model}`) } const perTask = (params.inputTokensPerTask / 1_000_000) * p.input + (params.cachedTokensPerTask / 1_000_000) * p.cacheRead + (params.outputTokensPerTask / 1_000_000) * p.output return perTask * params.tasksPerMonth}
const cost = estimateMonthlyCost({ model: 'claude-sonnet-5', tasksPerMonth: 50_000, inputTokensPerTask: 25_000, // キャッシュミス分 cachedTokensPerTask: 120_000, // キャッシュヒット分 outputTokensPerTask: 6_000,})console.log( `推定月額: $${cost.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, })}`)3.7.3 見落としやすいコスト要因
Section titled “3.7.3 見落としやすいコスト要因”思考トークン: 推論モデルの思考は出力トークンとして課金される。effort を上げるとコストが跳ね上がる可能性がある。
失敗したステップ: エージェントがツール呼び出しに失敗して再試行した分も、当然課金される。成功率が低いエージェントは、精度だけでなくコストの面でも問題を抱えている。
評価の実行: 第11章で扱う評価は、それ自体がLLM呼び出しを大量に発生させる。LLM-as-a-Judge方式の評価では、評価コストが本番の推論コストを上回ることさえある。バッチAPI(50%割引)の活用を検討すべきである。
埋め込みの再生成: RAGの文書を再インデックスするたびに埋め込みコストが発生する。埋め込みモデルは推論モデルより桁違いに安いが、文書量が多い場合は無視できない。
3.8 まとめ
Section titled “3.8 まとめ”- ストリーミングはユーザーに見せる最終応答に、非ストリーミングは機械処理する内部ステップに使う。ストリーミングではエラーが途中で来ることを前提に設計する
- 推論モデルは計画立案や矛盾解決といった多段の論理を要する場面で価値を発揮する。単純なタスクに使っても遅く高価になるだけである。
effortの既定値はhighであり、output_configにネストして指定する。単純なステップを意識的に下げるのがコスト管理の要点で、思考トークンは出力として課金される - ファインチューニングは最後の手段である。まずプロンプトを尽くし、知識不足ならRAGを検討する。ファインチューニングは知識の追加には向かない
- 埋め込みは意味的な検索を可能にするが、固有名詞の厳密一致や否定条件は苦手である。ハイブリッド検索とメタデータフィルタで補う。文書とクエリは必ず同じモデルでベクトル化する
- RAGはコンテキストが長くなっても不要にはならない。コスト、更新の反映、出典提示、アクセス制御という4つの理由から依然として必要である
- エージェント時代のRAGは単発検索から、エージェント自身が検索を繰り返す探索へと移行しつつある
- コストモデルはプロトタイプ段階で作る。思考トークン、失敗した再試行、評価の実行が見落としやすいコスト要因である
問1 次の3つの場面それぞれについて、ストリーミングと非ストリーミングのどちらを使うべきか、理由とともに述べよ。 (a) エージェントがユーザーの質問に対し、最終的な調査レポート(約3,000トークン)を返す (b) エージェントが「次にどのツールを呼ぶか」をJSON形式で判断する (c) 1万件の問い合わせログを夜間バッチでカテゴリ分類する
問2
あるエージェントで effort をまったく指定せずに実装したところ、レスポンスが遅くコストも想定を大きく超えた。ステップの内訳は「計画立案1回、ツール選択8回、結果要約8回、最終応答1回」である。
(a) effort を指定していないにもかかわらずコストが膨らんだのはなぜか
(b) ステップごとに effort をどう設定し直すべきか提案し、呼び出し回数を踏まえて期待される効果の大きい順に並べよ
問3 社内の技術文書(合計約40万トークン、月に数回更新)を参照して質問に答えるエージェントを作る。回答には必ず出典を示す必要があり、文書には部署ごとの閲覧制限がある。 (a) 全文をコンテキストに投入する方式と、RAG方式のどちらを選ぶか。理由を3つ挙げて説明せよ (b) 選んだ方式で、月間1万クエリを処理する場合の概算コストを Claude Sonnet 5 の標準レートで見積もれ(仮定は明示すること)
問4 RAGを導入したが、「型番 XR-4471B の仕様を教えて」という質問で正しい文書が検索されないという問題が起きている。原因として考えられることを述べ、対処法を2つ提案せよ。
問5 「社内規程をモデルに覚えさせたいのでファインチューニングしたい」という要望を受けた。この要望に対してどう応答すべきか。ファインチューニングが適切でない理由と、代わりに提案すべき方式を述べよ。
参考文献・出典
Section titled “参考文献・出典”| 出典 | 内容 | 参照日 |
|---|---|---|
| Anthropic — Streaming Messages | SSEによるストリーミングのイベント構造と実装 | 2026-07-29 |
| Anthropic — Adaptive Thinking | adaptive thinking の仕組み | 2026-07-29 |
| Anthropic — Effort | effort の既定値(high)、output_config へのネスト、各レベルの制約 |
2026-07-29 |
| Cohere — Embed | embed-v4 の次元数・最大入力長 | 2026-07-29 |
| Anthropic — Extended Thinking (Legacy) | 旧来の budget_tokens 方式と移行方法 | 2026-07-29 |
| Anthropic — Pricing | Claudeモデルの料金 | 2026-07-29 |
| OpenAI — Fine-tuning | SFT / DPO / RFT の概要と使い分け | 2026-07-29 |
| OpenAI — API Pricing | GPT-5.6系の料金 | 2026-07-29 |
| Google — Gemini API Pricing | Gemini系の料金 | 2026-07-29 |
| Text Embedding Models 2026: Dimensions, Price, MTEB Specs | 埋め込みモデルの比較 | 2026-07-29 |
| roadmap.sh — AI Agents Roadmap | 章構成の基準 | 2026-07-29 |
次章予告: 第4章からいよいよエージェント本体に入る。「AIエージェントとは何か」「ツールとは何か」という定義を、単なる用語解説ではなく、設計判断に使える形で整理する。
Built with Astro ・ Deployed on Cloudflare Pages
© 2026 watakumi — made with 💜 & ☕ ・watakumi.page