Claude 学習
コースガイド(分割)

Building with the Claude API 第5章 — Claudeの高度な機能

情報源は動画の公式英語字幕(トランスクリプト)。具体例・数値・デモ手順・コード例・比喩はできる限り漏らさず反映している。技術用語(extended thinking, thinking block, signature, redacted thinking, image block, document block, citations, page_location, char_location 等)は英語表記のまま用いる。


Lesson: Extended thinking(extended thinking)

ここでは Claude のより高度な機能の一つである extended thinking を見ていく。extended thinking は、Claude が最終的な応答を生成する前に、ユーザーのクエリについて推論する時間を与える機能である。多くのチャット UI では、これは応答本体とは別の「thinking プロセス」として表示され、ユーザーは任意でそれを見て、Claude がどのように問題にアプローチしているかをより深く理解できるようになっている。

一般に、extended thinking を有効にすると、Claude はより複雑なタスクをより高い精度でこなせるようになる。しかし、そこには大きなトレードオフがある。thinking フェーズの間に Claude が生成したトークンにも課金され、さらにこのフェーズ自体に一定の時間がかかる。つまり、知性の向上とともに、コストの増加とレイテンシの増加が同時にやってくる、ということである。

いつ有効にするか

extended thinking をめぐってよくある疑問は、「いつ有効にすべきか」である。答えは実はとてもシンプルで、自分のプロンプト eval に頼る、というものである。まずプロンプトを書き、それに対して eval を実行する。もし精度が望んでいる水準に達しておらず、すでにプロンプトの改善自体にかなりの労力を費やした後であれば、そのときこそ extended thinking の有効化を検討すべきタイミングである。

thinking block としくみ

extended thinking の使い方自体は非常にシンプルである。通常 Claude を使うときは、text block を含む可能性のある user message を送信し、その見返りとして text block を含む assistant message を受け取る。extended thinking を有効にすると、返ってくるレスポンスには、これまで見たことのなかった新しいブロックタイプ、すなわち thinking block が含まれるようになる。この thinking block の中には、Claude が思考している間に生成されたテキストが入っている。

この thinking block には非常に興味深い点があり、extended thinking を有効にしてコードを書き始めるとすぐに気づくはずなので、ここで紹介しておく。thinking block と text block の両方を含む assistant message の例で見ると、thinking block の中には signature(署名) と呼ばれるものが含まれている。signature は暗号学的なトークンであり、次のような役割を果たす。もしこのメッセージを、将来の会話の一部として Claude に送り返したいのであれば、Claude は thinking block 内のテキストがユーザー側で一切改変されていないことを確認したい。signature は、そのテキストが変更されていないことを保証するために使われる。Claude はそのテキストを一切変更されたくない。なぜなら、そのテキストは応答生成の際に非常に強く依拠されるものであり、もし開発者がそのテキストを自由に改変できてしまうと、Claude を安全でない方向に誘導できてしまう可能性があるからである。

これに関連して、thinking にはもう一つの側面がある。場合によっては、thinking テキストを一切含まず、暗号化されたコンテンツを保持する data というフィールドだけを持つ thinking block(type: redacted_thinking)が返ってくることがある。これは、Claude が生成した thinking テキストが、何らかの内部の安全システムによってフラグを立てられた場合に発生する。この data フィールドの中身は、実際の thinking テキストではあるが、完全に暗号化された形式になっている。これが提供される理由は、将来の会話の一部としてこの完全なメッセージを Claude に送り返す際に、Claude が以前の thinking に関する文脈を失わずに済むようにするためである。

notebook でのデモ: 001_thinking

extended thinking を本当に理解するには、実際に少しコードを書いてみる必要がある。001_thinking という新しい notebook を用意した。これまでと同様のコードの多くを引き継いでいるが、一つか二つ特別なものを追加してある(この notebook はレクチャーに添付されているので、ダウンロードしておくとよい)。

thinking を有効にするには、chat 関数を見つけて、params オブジェクトに最終的に追加される引数をいくつか渡す必要がある。具体的には、デフォルト値 falsethinking と、デフォルト値 1024thinking_budget を追加する。

thinking budget とは、Claude が応答の thinking 部分を生成する際に使ってよいトークン数のことである。最小値は 1024 であり、これより小さい thinking budget を指定することはできない。Claude が実際に 1024 トークンをすべて thinking に使うとは限らないが、これは指定できる budget の最小値である。

thinking budget についてもう一つ非常に重要な事実がある。それは、max tokens は thinking budget よりも大きくなければならない、ということである。例えば thinking budget が 1024 であれば、max tokens は少なくとも 1025 は必要になる。ただしこれでは、実際のテキスト生成に使えるトークンがたった1つしか残らない。したがって通常は、thinking budget よりも十分に大きい max tokens の値を用意することになる。今回の例では max tokens を 4,000 に増やしており、これでかなり大きなバッファが確保できる。つまり、thinking に 1,000 トークンを割り当て、残りの 3,000 トークンを実際のテキスト生成に割り当てるような応答を生成できることになる。

これら2つのキーワード引数を追加したら、params 辞書にも追加のパラメータを加える。thinking が有効であれば、params 辞書に新しいキー thinking を追加する。これはネストされた辞書で、typeenabledbudget_tokens に渡された thinking budget の値を持つ。

(注: ここで解説している budget_tokens による thinking budget 指定は、当時のモデル世代向けの手法である。現行世代モデル(Fable 5 / Opus 4.7以降 / Sonnet 5等)では budget_tokens は廃止され、thinking: {"type": "adaptive"}output_config.effort の組み合わせに置き換わっている。またこれとは別に、エージェント的ループ全体のトークン予算を管理する「Task Budgets」(output_config.task_budget、beta task-budgets-2026-03-13)という全く別スコープの機能も新設されており、混同しないよう注意が必要である。)

セルを実行し、下までスクロールしてテストする。Claude に「再帰(recursion)についての1段落のガイドを書いて」と依頼する。chat 関数の呼び出しで thinking=True を渡すように更新して実行すると、応答には2つの別々のブロックが含まれる。まず thinking block があり、その少し下に text block の開始がある。thinking block の中には確かに signature があり、それに伴って thinking テキストがある。signature の目的は、thinking テキストが一切改変・改ざんされていないことを保証することである。そして text block には、依頼した通りのガイド本文が入っている。

redacted thinking block を強制的に発生させる

最後に、アプリケーションを構築・テストする際に使えるものを紹介する。前述の通り、Claude が redacted thinking block を返してくるシナリオもありうる。アプリケーションを構築する際には、redacted thinking block が送られてきた場合でもコードが正しく動作することを確認したくなるはずである。実は、Claude に redacted thinking block を強制的に返させることができる。非常に特殊なフォーマットの文字列を含むメッセージを送信するだけでよい。

2つ目のセルの一番上に thinking_test_string という変数があり、その値は ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING に続けて特殊な数字とアルファベットの並びが入っている(正確な文字列は notebook 添付ファイルを参照)。この文字列をそのまま Claude に送信すると、必ず redacted thinking block が返ってくる。これはあくまでテスト目的で使うものであり、そのような予期しない thinking block を受け取ってもアプリケーションが正しく処理できることを確認するために使う。

一番下のセルに戻り、その thinking test string だけを含む user message を追加して送信すると、redacted thinking block を含む応答が返ってくる。redacted thinking block には datatype: redacted_thinking 以外の情報は含まれていない。これを使うことで、この種の予期しない thinking block を受け取ってもアプリケーションがクラッシュしないことを確認できる。


Lesson: Image support(画像サポート)

次に調査する Claude の高度な機能は、vision(視覚)機能である。user message を Claude に送信する際、任意で画像をメッセージの中に含めることができる。そして、その画像について考えられるほぼあらゆることを Claude に依頼できる。画像の中に何が写っているかを尋ねたり、複数の画像を比較させたり、異なる物体の数を数えさせたりと、可能性は非常に幅広い。

制限・要件

画像を扱う上でまず理解すべきなのは、いくつかの制約や要件である。

Claude に画像を送信するには、user message の中に新しい種類のブロック、すなわち image block を含める。1つの user message の中に複数の image block を添付することができ、各 image block は1枚の画像への参照を保持する。この image block の中には、生の画像データ(base64 でエンコードしたもの)を直接含めることもできるし、あるいはオンラインでホストされている画像への URL を指定することもできる。

プロンプト技法の重要性

画像を送る技術的な制限や送り方を理解したところで、ここで重要な点を伝えておきたい。エンジニアが Claude で画像を使い始めるとき、非常にシンプルなプロンプト——ここで挙げるようなごくシンプルな例に近いもの——を使い始めることがとても多い。Claude で画像を扱って良い結果を得るための最も重要な方法は、プロンプティング技法に強くフォーカスし続けることである。 画像を投げてごく単純なプロンプトを添えるだけでは、良い結果が得られないことが非常に多い。

例えば、12個のビー玉が写った画像を使った例がある。実際にテストしてみたところ、単に「この画像には何個のビー玉がありますか」というシンプルな質問をしただけでは、13個という誤った回答が返ってきた。これまでこのコースで学んできたのと同じプロンプティング技法——ガイドラインの提示、分析ステップの提示、one-shot や multi-shot の例の利用——を使うことで、画像を扱う際の Claude の精度を劇的に向上させることができる。この誤りを正した2つの方法を紹介する(実際にテストして、少なくとも自分の環境ではうまくいくことを確認済みである)。

1つ目は、Claude に画像を分析させる一連のステップを与える方法である。もちろんこれは、投入する画像の内容をある程度あらかじめ把握している場合にしか使えない。この例では、まず個々のビー玉を識別して1つずつ数え上げるよう Claude に依頼し、次に別の数え方・別の戦略で2回目の数え上げをして最初のカウントを検証するよう依頼し、最後にその2つのカウントを比較して正しい答えを判断するよう依頼する、という手順にした。このようにより洗練されたプロンプトを与えることで、正しい12個というカウントが得られた。

2つ目の技法は one-shot あるいは multi-shot プロンプティングである。user message の中で、image パートと text パートを交互に配置する。まず image パート、その下に text パート、さらにもう一つの image、そしてまた text パートというように並べる。最初のペアでは、11個のビー玉が写った画像を提示し、それに続けて「上の画像には11個のビー玉が写っています」と平易に述べる。このような例を提示することで、後で本番の画像を扱う際の Claude の精度を容易に向上させることができる。

ユースケース: 山火事リスクの衛星画像評価

いつものように、この機能を Jupyter notebook 内で実際にテストしていくが、今回は少し複雑な例を扱う。

米国の多くの地域では山火事が深刻な問題になっている。山火事がある地域を襲い、多くの家屋を焼失させることがある。これは非常によくあるリスクであるため、多くの人が自宅が焼失した場合に備えて火災保険に加入したいと考える。しかし保険会社は、家屋が明日、来年、あるいはごく近い将来に焼失しうることを十分に認識している。そのため保険会社は、家を保険に入れたい所有者に対して、家の周りの木を剪定する、あるいは完全に伐採することをしばしば要求する。

そして保険会社は、所有者が実際に木を適切に手入れしているかを確認・検証する必要がある。しかしそれを検証するには、人を派遣して各物件を検査させる必要があり、おそらく1〜2年に1回はそれを行う必要がある。これはすぐに非常に高コストになってしまう。

このプロセスを自動化する一つの方法は、高解像度で最新の衛星画像を取得し、それを Claude に送って火災リスク評価を依頼することである。具体的には、Claude に次のようなことを依頼する。

notebook でのデモ: 002_images

002_images という新しい notebook を使う。あらかじめ用意しておいたスターター用のプロンプトがある。このプロンプトは非常に詳細で、画像の中で分析してほしいさまざまなポイントやアイデアを Claude に順を追って示している。単に「この物件の衛星画像に基づいて火災スコアをつけてください」というごくシンプルなプロンプトを書くこともできたが、それではまず良い結果は得られなかっただろう。そこで、これまで学んできたプロンプトエンジニアリング技法を適用し、Claude がたどるべき一連の分析ステップを用意した。

  1. まず衛星写真の中から実際の主要な住居を見つける。
  2. 木の密度を確認する。
  3. 消防サービスが実際に物件にアクセスできる可能性を確認する。
  4. 屋根に張り出している木や枝がどれだけあるかを確認する(これは非常によくある火災リスクである)。
  5. これらすべての特性に基づいて火災リスクの評点をつける。評点が 1、2、3、4 のいずれになるかを判断するための基準もいくつか与える。
  6. 最後に、それぞれについて最終スコア付きの1文サマリーを書く。

このレクチャーには images.zip というアーカイブが添付されている。これを展開し、images ディレクトリを notebook と同じフォルダに配置する。このフォルダには、木の本数がそれぞれ異なるいくつかの家の衛星画像が入っている。例えば画像1の家にはかなりの量の木の張り出しがあり、画像2は木の量がかなり少ないが、それでも物件のすぐ近くに少し木が寄っている、といった具合である。目標は、これらの画像を Claude に送って、それぞれについて火災スコアの評価を得ることである。

notebook の中では、まず画像ファイルを開いて内容を base64 に変換する。images ディレクトリの中から特に画像7(prop7.png)を選ぶ。これは家が木に完全に囲まれている画像で、火災のリスクが明らかに大きい。base64.standard_b64encodef.read() を渡し、utf-8 にデコードして画像データを取得する。

空の messages リストを用意し、user message を1つ追加する。このメッセージには2つの別々のブロックを持たせる。まず image block で、typeimage、ネストした source 辞書に type: base64media_type: image/png、そして base64 エンコードした画像バイト列を data として持たせる。その後ろに、実際に Claude へ送りたい指示を含む text block(type: texttext に先ほどのプロンプト変数)を追加する。

最後に chat を呼び出し、このメッセージリストを渡す。実行して一番下までスクロールすると、火災リスクの評点が表示される。この例では火災リスクは高、スコアでいうと 3 という結果になった。物件周辺の木々を Claude がかなり妥当に評価し、リスクがありそうだと判断できたと言える。

先へ進む前に、画像についてもう一つ念を押しておきたい。Claude に画像を投入して良い結果を得られるかどうかは、すべてプロンプティング技法にかかっている。 平文テキストを扱う際に検討した多くの手法は、画像の世界でも同じように当てはまる。ここで示したようなシンプルなプロンプトに頼ってしまうと、期待するほどうまくいかない可能性が高いので、常によく練られ、しっかり評価されたプロンプトを用意することを強く勧める。


Lesson: PDF support(PDFサポート)

画像に加えて、Claude は PDF ファイルから直接コンテンツを読み取ることもできる。

このビデオには earth.pdf というドキュメントが添付されている。開いてみると、Wikipedia の「地球」の記事から数ページを抜粋したものであることがわかる。このPDFファイルをダウンロードし、notebook と同じディレクトリに配置しておく。

PDF ファイルを読み込むには、画像を読み込んで Claude に投入する際とほぼ同じコードを使う。現在画像を開いている箇所を見つけ、earth.pdf に変更する。変数名を image_bytes から file_bytes に変更する(もはや画像を読んでいるわけではないため)。下の変数も合わせて更新する。typeimage から document に変更し、media_typeimage/png から application/pdf に変更する。そして、これまでの大きなプロンプトを差し替えて、Claude に「このドキュメントを1文で要約してください」と尋ねる。

実行すると、サマリーが返ってくる。PDF ファイルの内容を正しく読み取れたことがわかる。Claude は PDF からテキストを読み取れるだけでなく、画像やチャート、テーブルなども読み取ることができる。つまり Claude は、PDF ドキュメントからほぼあらゆる種類の情報を抽出できる、ワンストップの手段だと考えてよい。


Lesson: Citations(citations)

先ほど扱った PDF ファイルの一番下のページまでスクロールすると、地球の大気と海洋が火山活動とガス放出(volcanic activity and outgassing)によって形成された、という記述がある。

ここで簡単な演習として、Claude に「地球の大気と海洋はどのように形成されたか」というシンプルな質問をしてみる。おそらく「火山活動とガス放出によって」というような答えが返ってくると予想される。この一節をコピーしてプロンプトに入れ、Claude に尋ねる("How were Earth's atmosphere and oceans formed?")。実行すると、少なくともこの例では、最初の一文で適切な答えが得られる。火山活動とガス放出によって形成された、とまさに期待通りの回答である。

ここでユーザーの視点に立って考えてほしい。ユーザーがこの生成テキストを見たとき、それが単に Claude が記憶から直接話しているだけだと思ってしまうかもしれない。実際には何らかの情報源を引用しているということを、ユーザーは理解できないかもしれない。この場合の情報源は完璧なものではなく Wikipedia だが、少なくとも何らかの根拠にはなっている。ここで、この情報をどう取得したのかをユーザーに知らせる何らかの方法があれば、非常に望ましい。

そのためにあるのが citations 機能である。citations を使うと、Claude はある外部の情報源を直接参照し、その回答をある別のドキュメントやテキストを見て得たのだと示すことができる。

citations の有効化と page_location

プロンプトの中に戻り、メッセージに入れている最初のブロックに小さな変更を加える。source フィールドのすぐ後ろに、titleearth.pdf(開いているPDFファイルの名前)、そして citations フィールドとして enabled: true を持つ辞書を追加する。

このリクエストを再度送信すると、レスポンスがそれまでよりもずっと複雑になる。content フィールドはいくつかの text block からなるリストになり、それらの text block の一部には typepage_location であるオブジェクトを含む citations リストが付いている(注: 実際のAPIレスポンスでは接頭辞なしの page_location が正式な値であり、citation_ という接頭辞の付いた名前は存在しない)。

page_location とは、Claude がある事実や情報をどこから得たのかを正確に伝える仕組みである。返ってくる構造体には cited_textdocument_indexdocument_titlestart_page_numberend_page_number が含まれる。

citations の意図: UI での提示

citations を提供する本来の狙いは、Claude の回答をもとにこうしたユーザーインターフェースを構築できるようにすることである。実際に、Claude から返ってきた応答をそのまま Claude に再度渡し、その応答全体をきれいにフォーマットされたドキュメントとしてレンダリングし、すべての citation を表すポップアップを付けてほしいと依頼した。マウスを「1」「2」「3」のマーカーの上に乗せると、きちんとフォーマットされたポップアップが現れる。このポップアップには、その citation オブジェクト(typepage_location のもの)の情報がすべて含まれている。これは、Claude の回答のこの特定の一文が、ある外部ドキュメントの情報に基づいていることをユーザーに知らせるためのものである。この例では、この一文は earth.pdf の4〜5ページの特定のテキスト(「地球の大気は...」云々)に由来している、というように示される。

この citations 機能によって、Claude が提示している情報が実際に何らかの外部ソースに由来していることをユーザーが確信できるようなインターフェースを構築できる。ユーザーはそのソースを参照しに行き、Claude がそのドキュメント内の情報を正しく解釈しているかどうかを確認できるようになる。

PDF 以外: プレーンテキストでの citations と char_location

citations 機能は PDF ドキュメントに限定されるものではなく、プレーンテキストでも利用できる。簡単な例として、上のセルで PDF ドキュメントからテキストを手動でコピー&ペーストし、article_text という変数に代入しておいた。

リクエストを組み立てている箇所に戻り、ブロックに大きな変更を加える。typedocument のままにし、source も残しつつ、typetext に変更し、media_typetext/plain に変更し、dataarticle_text を指定する。title は、もはや直接 PDF ファイルではないので earth article のようなものに変更する。citationsenabled: true はそのまま残す。

この状態で再度実行してレスポンスを確認すると、page_location の代わりに、今度は char_location が返ってくる。これは、Claude が引用している位置を、あの大きなテキストブロックの中の位置として示すものである。これを使えば、先ほどブラウザの中で見せたのとよく似たインターフェースを構築できる。

つまり、プレーンテキストからでも PDF ドキュメントからでも citations を引用できる。ユーザーが Claude の回答の組み立て方を何らかの形で調べられるようにすること、そして Claude が PDF であれプレーンテキストであれ、ソースドキュメントから情報を引き出していることを保証することが重要な場面では、citations 機能を積極的に活用することを強く勧める。


章末まとめ: 高度な機能(前半)の要点

情報源は動画の公式英語字幕(トランスクリプト)。具体例・数値・デモ手順・コード例・比喩はできる限り漏らさず反映している。技術用語(prompt caching, cache_control, Files API 等)は英語表記のまま用いる。


Lesson: Prompt caching(プロンプトキャッシュの導入)

次に焦点を当てる機能は prompt caching である。prompt caching は、Claude の応答を高速化し、テキスト生成のコストを下げるために使われる。prompt caching がどう動くのかを理解するために、まず prompt caching を一切有効にしていない、ごく普通のリクエストの内部で何が起きているのかを順を追って見ていく。

prompt caching なしの通常リクエストで内部的に起きていること

通常のリクエストの全体的な流れについてはこれまでも少し触れてきたが、今回は Claude の内部で実際に何が起きているのかについて、もう少し詳しく説明を加える。

すべては、こちらが何らかのメッセージを Claude に送信するところから始まる。Claude はそのメッセージを受け取ると、実際に出力テキストを生成し始める前に、入力メッセージに対して膨大な量の作業を行う。つまり、Claude は内部的に、入力テキストだけを対象にした膨大な数の内部データ構造を作り、膨大な数の計算を行う。そのあとで、その事前の作業をすべて使って出力テキストを生成し、アシスタントメッセージという形で応答を返してくる。

そして、応答をこちらに送り返したあと、Claude は出力テキストと、入力メッセージに対して行ったあらゆる計算の結果を、すべてゴミ箱に捨ててしまう。これまでの作業がすべて、まるで煙のように消え去ってしまうわけである。このクリーンアップが終わると、Claude は「次のリクエストを処理する準備ができた」と宣言する。

ここで、この最初のリクエストのあとに、続けてフォローアップのリクエストを送るとしよう。この会話を続けるとして、メッセージのリストを添えて送信する。1通目は先ほど送ったのとまったく同じメッセージ、2通目はそれに対して返ってきたアシスタントメッセージの応答、そして3通目に会話を先に進めるための新しいユーザーメッセージを追加する。これらすべてのメッセージをまとめて Claude に送る。

内部的には、Claude は最初のメッセージを見たときに、少しばかりフラストレーションを感じているかもしれない。もちろん、これは実際にそうなっているわけではないが、裏側で起きていることをイメージするための比喩として捉えてほしい。Claude はその最初のメッセージを見て、「このメッセージはついさっき見た。処理するのにあれだけの作業をしたのに、その計算結果を全部捨ててしまった。ついさっき捨てたばかりのあの作業を、再利用できたらよかったのに」と思うかもしれない。もし Claude が、ついさっき捨ててしまった作業を保存しておけたなら、その作業を繰り返す必要がないぶん、もっと素早く応答を返せたはずである。

解決策としての prompt caching

この問題が見えてきたところで、解決策を考えてみる。一つの案として、Claude への最初のリクエストを送ったときに、ユーザーメッセージに対して行われたあの初期の作業結果を、ゴミ箱に捨てるのではなく、何らかの一時的なデータストアにキャッシュしておく、というやり方が考えられる。

そうしておけば、その後フォローアップのリクエストを送り、そこにまったく同一の入力ユーザーメッセージが含まれていた場合、Claude はキャッシュを覗きに行き、「このメッセージはついさっき見た。そのときの分析結果はすでに保存してある」と気づける。そうすれば、メッセージを再分析するのではなく、以前に行った作業をそのまま再利用できる。これによって、出力テキストの生成が劇的に速くなることが期待できる。すでに済んでいる作業を再利用しているためである。

この「あるリクエストからの作業結果を保存しておき、あとで使う」という考え方こそが、まさに prompt caching の本質である。次のレッスンでは、prompt caching の実装の詳細に踏み込み、Claude によってどのように実装されているのかを理解していく。


Lesson: Rules of prompt caching(プロンプトキャッシュのルール)

理論を理解したところで、Claude における実際の prompt caching の動き方を見ていく。prompt caching の核となる考え方は、前のレッスンで議論した内容とまったく同じである。まず Claude に初回のリクエストを送る。Claude はその最初のメッセージに対して何らかの処理を行い、その作業結果を一時的なキャッシュに保存する。そして、将来のある時点でフォローアップのリクエストを送り、そこにまったく同一のメッセージが含まれていた場合、Claude はそのメッセージを一から処理し直すのではなく、キャッシュを覗きに行き、すでに保存済みの作業を見つけ出してロードする。

はっきりさせておきたいのは、キャッシュに保存された作業は永遠に保持されるわけではないということである。キャッシュのデフォルトの保持期間は5分間である。(1時間のTTLも cache_control で明示的に指定すれば利用できるが、これはオプションのオプトイン機能で、通常の入力トークン価格の2倍のコストがかかる。)prompt caching が最も役立つのは、同じ内容を繰り返し繰り返し Claude に送り続けるようなケースである。これはまさに2段階のプロセスであり、まず初回のリクエストでキャッシュにデータを書き込み、その後のフォローアップのリクエストだけが、事前に済ませておいたその作業を活用できる、という構造になっているからである。

cache_control フィールドで手動で有効化する

このキャッシュの仕組みは、デフォルトでは有効になっていない。キャッシュを有効にするには、いずれかのメッセージ内のブロックに手動で cache breakpoint を追加する必要がある。具体的には、ちょっとした cache_control フィールドを追加するだけでよい。ただし、この cache_control が実際に何をするかについては、多くのルールが存在する。

そのルールの説明に入る前に、少し役立つ Tips を紹介する。このコースを通じて、テキストブロックを書くための省略記法を頻繁に使ってきた。ユーザーメッセージに少しのテキストしか含まれていない場合、content フィールドに文字列を直接代入するというやり方である。これとは別に、テキストブロックを書くもう一つの方法もある。それは、content フィールドにリストを代入し、その中に typetexttext フィールドに実際のテキストを含む辞書を入れる、という書き方である。

これまでの授業では、この長い書き方はほとんど使ってこなかった。しかし、cache_control を使いたい、つまり prompt caching 機能を有効にしたい場合には、テキストフィールドをこの長い形式で書く必要がある。つまり、cache_control をどこかに書き込む必要があり、この長い形式であれば、それを置く場所が用意されている。短い形式を使ってしまうと、cache_control を置く場所がない。

breakpoint より前のコンテンツはすべてキャッシュされる

ブロックに breakpoint を追加すると、リクエスト全体の中で、その breakpoint を含めてそれより前にあるすべてのコンテンツがキャッシュされる。つまり、最初のブロックに breakpoint があるリクエストを送ると、Claude はそのテキストを処理するのに何らかの作業を行い、その作業結果が生まれる。このテキストブロックには breakpoint があるので、この作業結果はキャッシュに保存される。一方、breakpoint より後にある作業はキャッシュされない。

その後フォローアップのリクエストを送ると、Claude はキャッシュを確認し、この最初のブロックの処理についてすでに作業が済んでいることを見つけ出す。そこでその作業結果を取り出して再利用し、少しだけ手間を省くことができる。

ここで注意すべき点は、フォローアップのリクエストは、その breakpoint までの内容がすべて完全に同一でなければならないということである。例えば、breakpoint のある最初のテキストブロックに "please" という単語を1つ追加しただけでも、内容はもはや同一ではなくなり、その作業結果はキャッシュから使われることはない。代わりに、Claude はこのブロック全体と、それより前のすべての内容を再処理することになる。

複数メッセージ・複数ブロックにまたがる breakpoint

cache breakpoint は、複数の異なるメッセージや複数の異なるブロックにまたがることができる。例えば、ユーザーメッセージ、アシスタントメッセージ、そして別のユーザーメッセージという順番で送り、その一番最後のメッセージの中のブロックに breakpoint がある場合、このブロックまでを含めてすべてがキャッシュされる。つまり、この3つのメッセージすべてを処理するために行われた作業が、キャッシュに保存されると考えられる。そして後でフォローアップのリクエストを送るとき、その breakpoint までのすべてが同一であれば、その作業はキャッシュから取り出され、再び少しの手間を省くことができる。

テキストブロック以外にも breakpoint を置ける

cache breakpoint はテキストブロックだけに限定されているわけではない。画像ブロックや tool use、tool result といった、ほとんど他の種類のブロックにも追加できる。さらに、tool schema や system prompt に対しても追加できる。tool schema と system prompt に対して caching を有効にすることは非常によくある。というのも、多くのアプリケーション(すべてではないが)では、system prompt や tool のリストは変化しないことが多いためである。したがって、これらは cache breakpoint を置くのに絶好の場所になる。

まとめると、breakpoint は tool schema・system prompt・メッセージブロックに適用できる。これらは3つの別々のキャッシュシステムというわけではない。tools・system prompt・messages を追加すると、裏側ではこれらがまとめて結合され、Claude に投入される。そしてその結合順序は「tools → system prompt → messages」の順である。したがって、最後の tool に cache breakpoint を置くと、その最後の tool までを含めたすべてがキャッシュされる。しかし system prompt とメッセージのリストはキャッシュされない。そのため、その後にアシスタントメッセージを変更してフォローアップのリクエストを送っても、tools のリストは事前にキャッシュされているので、そのぶんの作業は節約できる。

最大4つまでの複数 breakpoint

最後に、複数の異なる cache breakpoint を追加できる点にも触れておく。最大4つまで設定可能である。例えば、渡す tool schema の最後のものに1つ cache breakpoint を置き、さらにその下のあるアシスタントメッセージにも breakpoint を置く、といった具合である。この状態でフォローアップのリクエストを送り、下の方にあるユーザーメッセージを変更しても問題ない。tools のリストと system prompt、そしてそのアシスタントメッセージまでの再処理を省くことができる。同様に、最初のユーザーメッセージを変更した場合は、それより下の部分のキャッシュは無効になるが、tools リストのキャッシュされた作業は引き続き有効である。したがって、tools のリスト全体、system prompt、そしていくつかのメッセージにまで、複数の breakpoint を適切に追加することがよくある。breakpoint をどこに配置するかは、結局のところ個々のアプリケーション次第である。

キャッシュ対象コンテンツの最小トークン数(1,024トークン)

最後にもう一点、キャッシュされるコンテンツには最小サイズがあるという点を共有しておく。ある程度のコンテンツをキャッシュするためには、最低でも1,024トークンをキャッシュする必要がある。右上の例では、"hi" というテキストだけを含むメッセージに cache breakpoint がついているが、これは明らかに1,024トークンには遠く及ばない。したがってこのコンテンツはキャッシュに書き込まれない。しかし、そのテキストブロックを500回複製したとすれば、おそらく1,024トークンを超えるはずなので、このブロックのリスト全体がキャッシュされることになる。


Lesson: Prompt caching in action(プロンプトキャッシュを実践する)

ここからは実際に手を動かして prompt caching を試していく。003 caching という新しい notebook が用意されている(このレクチャーに添付されている)。この中には「6Kトークンのプロンプト」というセクションがあり、これは system prompt として使うためのものである。加えて tool schema のセクションもあり、いくつかの tool schema が定義されている。これらの tool schema をすべて合わせると、合計で約1.7Kトークンになる。

まず、chat 関数(helper functions セルの中にある)を更新する作業から始める。この chat 関数が、tool schema と system prompt に対して、デフォルトで常に prompt caching を有効にするようにする。

chat 関数の実装

helper function のセルの中にある chat 関数までスクロールしていくと、2つの TODO 項目が入れてある。

  1. tools のリストが渡された場合、常に tools のリストをキャッシュする
  2. system prompt が渡された場合、それも同様にキャッシュする

1つのリクエストの中に複数の cache breakpoint を設定できることを思い出してほしい。system prompt と tools のリストの両方を渡す場合は、2つの異なる cache breakpoint を設定することになる。

まず tools のリストをキャッシュする処理から取りかかる。渡された tool schema のうち、一番最後の tool schema を変更し、そこに cache_control フィールドを追加する必要がある。単純には tools[-1] に対して cache_controltype: ephemeral として設定する、というやり方も考えられる。これでも確かに動作するが、あまり良いコーディング手法とは言えない。というのも、この方法だと元の tool schema そのものを直接書き換えてしまうことになる。アプリケーションの中で、後になって tool schema を渡す順序を変えることになった場合、tool schema の中に複数の cache breakpoint が意図せず残ってしまう可能性がある。

そこで、もう少し良いやり方として、まず tools リストのコピーを作成し、そのコピーの中の最後の tool schema を複製したうえで cache_control フィールドを追加する、という手順を踏む。具体的には次のようにする。

ここで行っているコピーのロジックは厳密には必須ではないが、将来 tools のリストを変更することになった場合に備えた、良い実践である。

続いて2つ目の TODO に取りかかる。system prompt が渡された場合には、必ず cache breakpoint を設定するようにする。コメントを外し、system をリストに置き換える。その中にテキストブロックを1つ入れる。つまり type: texttext: system(渡された system prompt のテキスト)、そして最後に cache_controltype: ephemeral を持つ辞書である。これで完了である。

notebook の一番下でテストする

セルを実行したら、notebook の一番下までスクロールして、いま設定した caching を実際にテストしてみる。一番下にはすでに tools のリスト(1つ上のセルで定義された tool schema)が定義済みで、さらに先ほどの大きな system prompt(code_prompt)も用意されている。

ケース1: tools も system prompt も渡さない場合

まず、何も渡さない状態、つまり tools のリストも system prompt も渡さない状態で試す。"1+1 とは何か" というメッセージを処理して応答を生成するのに使われるトークン数を確認する。実行すると、応答の中に usage フィールドがあり、入力14トークン、出力11トークンが使われたことがわかる。

ケース2: tools のリストを追加

次に tools のリストを追加してみる。追加して実行すると、usage フィールドがまったく違う内容になる。今度は usage の中に cache_creation_input_tokens が1,700 という値が現れる。これは、Claude が tool schema をキャッシュしたいという意図を認識し、合計約1,700トークンをキャッシュに書き込んだことを意味する。

続けて、何も変更せずにすぐにもう一度フォローアップのリクエストを送ると、今度は一定のトークン数をキャッシュから読み取ることになる。cache_read_input_tokens が1,700 となり、これは先ほど tool schema をキャッシュに正しく保存し、その後それを取り出せたことを示している。

ここで、ユーザーメッセージを何らかの形で変更してみる。例えば末尾の疑問符を削除して再実行しても、引き続きキャッシュから読み取られる。これは、キャッシュの順序が「tools のリスト → system prompt → 各メッセージ」の順であることを思い出せば納得できる。

しかし、tools を何らかの形で変更すると、キャッシュは無効になる。tools のリストの中の、最初の tool の description を変更してみる。"ads" という単語から "s" を削除して "add a specified duration" のようにする。このセルを再実行すると、tool schema を変更したことになるため、すべての tools に適用していた cache breakpoint はもはや適用されなくなる。一番下のセルを再度実行すると、usage の値が更新され、再び cache write が発生する。もはや読み取りではなく、書き込みに戻っている。これは、Claude から見て送信された tools のリストが完全に別物として扱われるためである。

ケース3: system prompt を追加

続いて system prompt を追加してみる。chat 関数に system=code_prompt を追加する。ここでも caching の順序(tools → system prompt → messages)を思い出してほしい。tools のリストはそのまま変更していないが、system prompt を変更しているので、部分的な cache read と cache write が同時に発生することが予想される。cache read が発生するのは同じ tools のリストを使い続けているためであり、cache write が発生するのは、新しい system prompt を送ることで新しい cache breakpoint を書き込むことになるためである。

実際に実行すると、想定どおり cache read が1,700、cache write が6.3K という結果になる。

続けて、tools のときと同様に system prompt を何らかの形で変更してみる。末尾の "builder" という単語を削除して、そのセルを再実行する。すると、Claude からすればこれもまた完全に別の system prompt として扱われるため、再度リクエストを送ると、system prompt について以前保持していたキャッシュデータはすべて失われる。もう一度実行すると、再び cache read が約1.7K となり、そして今度はこの新しい system prompt について新規に書き込みが発生するため、もう一つの6.3Kのキャッシュ書き込みが起きる。

以上が prompt caching である。同じ内容——メッセージのリストであれ、tool schema であれ、system prompt であれ——を繰り返し Claude に送るようなケースでは、prompt caching を非常によく利用することになる。


Lesson: Code execution and the Files API(コード実行と Files API)

このレッスンでは、Anthropic API が提供する2つの機能を見ていく。この2つの機能は一見すると少し異なる、少し別々のもののように思えるかもしれないが、実際には非常に興味深い形で組み合わせて使うことができる。

Files API とは何か

まず Files API について理解するところから始める。このコースの前半で、画像を Claude に渡し、その画像を解釈してもらう方法について議論した。その際、image block を使うことで、base64 でエンコードされた実際の生の画像データを含めることができることを紹介した。PDF ドキュメントのアップロードでも、非常によく似たプロセスを見てきた。

Files API は、この仕組み全体に少しひねりを加えたものである。Files API を使うと、PDF や画像、テキストファイルなど、特定のドキュメントを事前にアップロードするための個別のリクエストを、あらかじめ行っておくことができる。つまり、ファイルをアップロードするための初回リクエストを Claude に対して送る。すると、file metadata object と呼ばれるものが返ってくる。この file metadata object にはいくつかの情報が含まれているが、我々にとって最も興味深く重要なプロパティが file ID である。この ID を使うことで、将来のある時点でアップロード済みのそのファイルを参照できるようになる。

そして将来のある時点で、ユーザーが「この画像の中に何が見えるか」といったメッセージを送ってきたとする。この場合、image block の中に画像そのものの生データを含める代わりに、単に file ID を含めるだけでよい。この file ID を入れることで、Claude は事前にアップロードしておいたその画像を見つけ出し、可能な限り画像を解釈しようとする。つまり、Files API を使うことで、ファイルを事前にアップロードしておき、後になってそのファイルに関するデータをリクエストに含める、という別のやり方で画像や PDF を Claude に提供できる。

Code execution とは何か

Files API の基本、つまりファイルを送信し、あとで再びそのファイルを参照できるという考え方を理解したところで、このレッスンのもう一つの焦点である code execution に話を移す。

code execution は server-based tool(サーバーベースのツール)である。したがって、このツールについて実装を自前で用意する必要はない。用意する必要があるのは、あらかじめ定義済みの tool schema を渡すことだけである。Claude への初回リクエストの中に、このあらかじめ定義された tool schema を、送信したいユーザーメッセージと一緒に含める。すると、裏側で Claude は、隔離された Docker コンテナの中で何らかの Python コードを実行するかどうかを、オプションとして自ら判断できるようになる。

Claude はこのコンテナの中で、複数回にわたってコードを実行できる。これらのコード実行から得られた出力(print されたもの)は Claude に送り返され、Claude はその結果を解釈して最終的な応答を書くことができる。

これらの Docker コンテナにはネットワークアクセスが一切ない。 つまり、Claude がネットワークリクエストを行ったり、何らかの外部 API にアクセスしようとしたりするコードを書いても、それは実行できない。代わりに、情報を Docker コンテナの中に入れたり外に出したりするには、先ほど説明した Files API と、この code execution tool を組み合わせて利用する。

Files API と code execution の組み合わせ方

具体的な流れを説明する。maybemydata.csv という CSV ファイルがあり、そこに Claude に分析してほしい大量の表形式データが含まれているとする。Claude にコードを書かせて、それを自分で手動実行するという複雑なセットアップを経由する代わりに、Files API と code execution tool を組み合わせて使うことで、Claude に自動的にそのファイルを分析させ、結果を出力させることができる。

その手順は次のとおりである。

  1. まず Files API を使って CSV ファイル(何らかのデータが入ったもの)をアップロードする。すると file ID が返ってくる。
  2. その file ID を、Claude へのフォローアップのリクエストに含める。具体的には container upload block と呼ばれるものを追加する。container upload block とは、事前にアップロードしておいたファイルを、何らかの形でコンテナの中に注入・配置したい、ということを意味するブロックである。type: container_upload と、アップロード時に返ってきた file ID を持つプロパティを指定した、この特別な形式のブロックを追加する。
  3. 別のテキストブロックの中で、Claude に何らかの分析を依頼する。「このファイルの中のデータを分析して」といった単純な依頼でよい。

すると裏側で、Claude は code execution tool を使うようになる。Claude はアップロード済みのファイルに Docker コンテナの中からアクセスできるので、そのファイルを分析するコードを書き、結果を処理し、ファイル内のすべてのデータについて完全なレポートを作成できる。

notebook でのデモ: 005 code execution

この全体の流れを実際に見ていく。005 code execution という notebook と、streaming.csv という別の CSV ファイルが用意されている。この中には、ある動画配信サービスの架空のデータが大量に入っている。特定のユーザーに関する情報(どのサブスクリプション tier に含まれているか、つまりどのレベルのアクセス権を持っているか)と、そのユーザーに関する数多くの統計情報(総視聴時間、トップジャンルなど)が含まれている。そして一番最後の列は churned(解約したかどうか)というカラムで、0 はサブスクリプションを解約していない、1 は解約したことを示す。

このファイル内のデータを分析して、これらの異なる特徴量と、ユーザーがサブスクリプションを解約したかどうかとの間に何らかの相関があるかどうかを調べるコードを、自分で大量に書くこともできる。しかし、それをすべて自分で行う代わりに、このタスクを丸ごと Claude に任せることにする。まず streaming.csv ファイルをアップロードし、Claude にその code execution tool を使ってファイル内のすべてのデータを分析するよう依頼する。

helper function セル

notebook に戻り、helper function セルを確認する。少しスクロールすると、いくつかの関数が追加されている。

これらの関数はこのあとすぐに使う。このセルを畳んで、忘れずに実行しておく。

ファイルのアップロード

次のセルで streaming.csv ファイルをアップロードする。このセルをすぐに実行すると、file metadata object が返ってくる。この中に ID があり、これが Claude に対してこのファイルを識別するための一意な ID である。今後の会話の中でこのファイルを含めたい場合には、この特定の ID を参照することになる。

分析の依頼

次のセルには、Claude に「顧客がなぜサブスクリプションを解約しているのかについて詳細な分析を行い、結果を要約するプロットを1枚出力してほしい」と依頼する短いプロンプトが用意されている。その後に、実際にアップロード済みのファイルをリクエストに含めるための Container Upload block が続く。

このセルを実行する。code execution を使う場合、応答が返ってくるまでに少し時間がかかることがある点に注意してほしい。返ってくる応答には非常に大量のテキストが含まれる。このメッセージの中には、Claude が書いたすべてのコード、そこから得られたすべての print 文と出力、そして最終的な分析結果が含まれている。Claude はコンテナの中でコードを複数回実行することがあるため、複数のコードブロックと複数の実行結果がメッセージの中に見られることもある。

応答メッセージの構造

応答の内容をわかりやすく整形したものを見てみる。content リストの中に、さまざまな種類のブロックが含まれている。

この例では、そのあとさらに Claude がコードを追加で実行している。さらなる分析結果を得て、さらに分析を行い、という具合である。つまりこのケースでは、Claude は徹底的な分析を行うために、何度も連続してコードを実行している。

このすべてのコンテンツをユーザーに見せるかどうかは、完全にアプリケーション次第である。見せたい場合は、きれいなレポートを組み立てることもできる。先ほど見ていたすべての情報を使って、Claude にきれいに整形させることもできる。最初のテキストブロックからのそのままの応答内容が見え、続いて code execution tool、Claude が実行したコードとその出力が続き、これが何度か繰り返される、という形でレポートを作成できる。

生成されたプロット画像をダウンロードする

最後に、code execution の最も興味深い側面の一つを紹介する。先ほど送ったプロンプトの中で、Claude に「詳細なプロットを1枚、調査結果の要約として含めてほしい」と依頼したことを思い出してほしい。Claude は裏側で、画像ファイルの形でプロットを生成しており、それは Docker コンテナの中に保存されている。この、コンテナの中で生成されたプロットをダウンロードするために、Files API を使うことができる。

その手順は次のとおりである。

  1. 先ほど整形して見ていたメッセージをよく確認する
  2. スクロールしていくと、ネストされた content プロパティを持つテキストブロックが見つかる。その中に type: code_execution_output というものが見つかることがある(見当たらない場合は "code execution output" で検索する)
  3. その直下に file ID がある。この file ID を使ってファイルをダウンロードできる
  4. その file ID をコピーし、notebook の一番下に新しいセルを追加する
  5. このレッスンの冒頭で見た定義済み関数の一つである download_file を呼び出し、先ほど応答の中で見つけた file ID を渡す
  6. これを実行すると、正常に完了する

これで、notebook と同じディレクトリの中に、PNG か JPEG のファイルが見つかるはずである。ファイル名はランダムというわけではなく、Claude が決めた名前になる。そのファイルを開くと、Claude が CSV ファイルから抽出した情報がたくさん見える。視聴時間別の解約率、月額料金帯別の解約率など、Claude はこのファイルの内容を理解するために非常に徹底した分析を行っている。

このデモからわかるように、Files API と code execution tool を組み合わせることで、かなり複雑なタスクを Claude に委任できるようになる。もちろんデータ分析だけに限られるわけではなく、code execution と Files API の組み合わせは、非常に幅広い種類のタスクの実行に使うことができる。これをアプリケーションにどう統合するかは、最終的には利用者次第である。


章末まとめ: Prompt Caching + Code Execution の要点

Prompt caching

Code execution と Files API


Claude 学習サイト — 完全ローカル静的サイト(build.py で生成)。進捗はこのブラウザの localStorage に保存されます。