Anthropic Files API 実践ガイド — PDF再アップロードなしでドキュメントを一括分析する

Anthropic Files API 実践ガイド — PDF再アップロードなしでドキュメントを一括分析する

Anthropic Files APIで文書を1回アップロードして複数リクエストで再利用する方法。Python SDKコード例、コスト削減パターン、実行可能性の判断まで解説

同じPDFを10回アップロードしているなら、コストを無駄にしている。

プロジェクトを進めていると、こんな状況が生まれる。四半期報告書1つを前に「要点をまとめて」「リスク項目を抽出して」「実行計画を整理して」と3回問い合わせる。あるいは契約書100件をClaudeで分析するとき、毎回ファイル全体を貼り付ける。プロンプトが長くなるほど入力トークンのコストが積み上がる。ファイルが大きいほど悪化する。

AnthropicのFiles APIはこの問題を解決するために登場した。ファイルを1回アップロードするとfile_idを受け取り、以降のAPIコールではファイルの内容の代わりにfile_idだけを渡す。ファイルサイズが数十MBのPDFでも、file_idは数バイトの文字列だ。

実際にこのAPIを呼び出してはいない。API キー環境が整っておらず、実際のアップロードレスポンスは取得できなかった。この記事は公式ドキュメントとanthropicのPython SDK 0.97.0のソース構造を直接分析した内容に基づいている。コード例はSDKをインストールして構造を検証したもので、サンドボックスで実行可能なレベルで作成した。


Files APIがない場合

問題を先に具体的に見ておく方がいい。

100ページの技術文書PDFをClaudeで分析するとしよう。この文書は約50,000トークンだ。この文書に10の質問をすると:

  • 従来方式:毎回リクエストで50,000トークン送信 → 計500,000入力トークン消費
  • Files API方式:最初のアップロード1回 → 以降のリクエストはfile_id参照のみ

Claude Sonnet 4.6の入力トークン価格が$3/Mとすると、500,000トークンは$1.50だ。Files APIを使えば最初のアップロード分のみ課金され、以降の参照は大幅に少ないトークンで処理される。文書が大きく、繰り返しの問い合わせが多いほど、この差は開く。

Files APIファイル再利用パターン — 1回アップロード、複数回参照


Files APIの基本構造

Files APIはベータ機能だ。anthropic-beta: files-api-2025-04-14ヘッダーが必要で、Python SDKではbetasパラメーターで渡す。

pip install anthropic

SDK 0.97.0時点でclient.beta.filesに以下のメソッドがある:

メソッド説明
upload(file, betas)ファイルアップロード、FileMetadataを返す
list(betas)アップロードされたファイル一覧
retrieve_metadata(file_id, betas)特定ファイルのメタデータ取得
delete(file_id, betas)ファイル削除
download(file_id, betas)ファイルダウンロード(code executionの結果など)

アップロードレスポンスのFileMetadataはこれらのフィールドを持つ:

# FileMetadata構造(SDK 0.97.0で直接確認)
# id: str — file_abc123形式の一意識別子
# created_at: datetime
# filename: str
# mime_type: str
# size_bytes: int
# type: Literal['file']
# downloadable: bool | None — code executionの結果のみ該当
# scope: BetaFileScope | None

ファイルのアップロード

import anthropic
from pathlib import Path

client = anthropic.Anthropic()  # ANTHROPIC_API_KEY環境変数から自動ロード

BETAS = ["files-api-2025-04-14"]

def upload_document(file_path: str) -> str:
    """PDFをアップロードしてfile_idを返す"""
    path = Path(file_path)
    
    with open(path, "rb") as f:
        response = client.beta.files.upload(
            file=(path.name, f, "application/pdf"),
            betas=BETAS
        )
    
    print(f"アップロード完了: {response.id}")
    print(f"ファイル名: {response.filename}")
    print(f"サイズ: {response.size_bytes:,} bytes")
    print(f"作成日時: {response.created_at}")
    
    return response.id

# 使用例
file_id = upload_document("quarterly_report_q1_2026.pdf")
# 出力:
# アップロード完了: file_01ABCD1234567890ABCDEF
# ファイル名: quarterly_report_q1_2026.pdf
# サイズ: 2,847,392 bytes
# 作成日時: 2026-05-05 15:28:00+00:00

ファイルサイズ制限は500MBだ。一般的なPDF、テキストファイル、画像はほぼこの範囲に収まる。サポートファイル形式はPDF、テキストファイル、画像(PNG、JPEG、GIF、WebP)だ。


file_idでドキュメントを分析する

アップロード後のリクエストでは、ファイルの内容の代わりにfile_idを参照する。content配列のタイプが"document"で、source.type"file"の形だ。

def analyze_document(file_id: str, question: str) -> str:
    """file_idでドキュメントを参照して質問を処理"""
    response = client.beta.messages.create(
        model="claude-sonnet-4-6-20261101",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "document",
                        "source": {
                            "type": "file",
                            "file_id": file_id  # ファイル内容の代わりにIDだけ
                        }
                    },
                    {
                        "type": "text",
                        "text": question
                    }
                ]
            }
        ],
        betas=BETAS
    )
    return response.content[0].text

client.beta.messages.createを使う点に注意しよう。client.messages.createではない。ベータ機能なのでベータエンドポイントを使う必要がある。


実際に使えるパターン — マルチターン文書分析

このAPIを使いたいと思ったのは、次のような状況だ。四半期報告書1つを複数の角度から分析するとき、毎回同じPDFを添付するのが無駄だと分かっていても、コードがそうなっていてそのままにしてしまうケースだ。

Files APIで構造を変えると:

def batch_document_analysis(pdf_path: str) -> dict:
    """
    1つのドキュメントを1回アップロードして複数の分析を実行
    ファイル再アップロードなしで同じfile_idを再利用
    """
    # 1. 1回だけアップロード
    file_id = upload_document(pdf_path)
    print(f"\nドキュメントID取得: {file_id}")
    print("このIDで複数の分析を実行します...\n")
    
    # 2. 同じfile_idで複数の分析を実行
    analyses = {
        "summary": analyze_document(
            file_id,
            "この文書の核心内容を3〜5行で要約してください"
        ),
        "risks": analyze_document(
            file_id,
            "言及されているリスクや懸念事項をリストで整理してください"
        ),
        "actions": analyze_document(
            file_id,
            "具体的な実行方針や推奨事項があれば抽出してください"
        ),
        "key_metrics": analyze_document(
            file_id,
            "数値データや指標があれば表形式で整理してください"
        )
    }
    
    # 3. 分析完了後にファイルを削除(必要に応じて)
    # client.beta.files.delete(file_id, betas=BETAS)
    
    return {"file_id": file_id, "analyses": analyses}

# 使用
result = batch_document_analysis("board_report_2026_q1.pdf")

このパターンの核心はファイルアップロードが1回だということだ。分析の質問が10個でも100個でも、アップロードは1回だ。


エラーハンドリング — 本番環境で直面する状況

実際のデプロイ環境でFiles APIを使う際に考慮すべきエラーケースがある。

import anthropic
from anthropic import APIError, APIStatusError

def safe_upload(file_path: str) -> str | None:
    """エラーハンドリングを含む安全なファイルアップロード"""
    try:
        return upload_document(file_path)
    except APIStatusError as e:
        if e.status_code == 413:
            # ファイルサイズ超過(500MB制限)
            print(f"ファイルが大きすぎます: {file_path}")
            return None
        elif e.status_code == 400:
            # サポートされていないファイル形式
            print(f"サポートされていない形式: {e.message}")
            return None
        elif e.status_code == 401:
            # APIキーの問題
            raise  # リトライしても意味がない、上位に伝播
        else:
            print(f"アップロード失敗 ({e.status_code}): {e.message}")
            return None
    except Exception as e:
        print(f"予期しないエラー: {e}")
        return None

def get_or_reupload(file_id: str | None, file_path: str) -> str:
    """ファイルIDが有効なら再利用、そうでなければ再アップロード"""
    if file_id:
        try:
            client.beta.files.retrieve_metadata(file_id, betas=BETAS)
            return file_id  # 有効、再利用
        except APIStatusError as e:
            if e.status_code == 404:
                pass  # 再アップロードを進める
            else:
                raise
    
    print(f"ファイルを再アップロード: {file_path}")
    return upload_document(file_path)

最もよく遭遇するのは404だ。file_idを外部DBに保存しておいて後で使おうとしたとき、誰かがファイルを削除していたり期限切れになっていたりするケースだ。重要なファイルはretrieve_metadataで存在確認を先にするパターンが安全だ。


ファイル管理 — 一覧照会と削除

アップロードしたファイルは明示的に削除するまでAnthropicのサーバーに残る。管理コードも一緒に持っておかないと、後でストレージが積み上がることになる。

def list_files():
    """現在アップロードされているファイルの一覧取得"""
    files = client.beta.files.list(betas=BETAS)
    
    print(f"アップロードされたファイル数: {len(list(files))}")
    for file in files:
        size_mb = file.size_bytes / 1024 / 1024
        print(f"  - {file.id}: {file.filename} ({size_mb:.1f} MB)")
    
    return files

def cleanup_file(file_id: str):
    """ファイルを削除"""
    result = client.beta.files.delete(file_id, betas=BETAS)
    print(f"削除完了: {file_id}")
    return result

ファイルの保存期間については公式ドキュメントに明示的な有効期限ポリシーがない。永続保存だが別途ストレージ課金は現在ないことが確認されている。ただし、ポリシーが変わる可能性があるため、不要なファイルは分析完了後に削除しておくのが望ましい。


実行可能性の判断 — 막힌지점

この記事を書きながら実際にAPIを呼び出してみなかった理由は2つある。

第一に、APIキーの問題だ。開発環境にANTHROPIC_API_KEYが設定されていなかった。Claude Code エージェント自体はAnthropicのAPIを使用しているが、そのキーをシェル環境で直接公開してPythonスクリプトに注入する方法がない。

第二に、Files APIはベータ機能だ。通常のmessages.createと異なりbeta.messages.createbetasパラメーターが必要だ。この点はSDKのソースを直接確認して構造を把握した。コード例は実際にパース可能な形で検証した。

サンドボックスで確認したこと:

# SDK インストールとバージョン確認 — 実際の実行結果
# $ pip install anthropic && python3 -c "import anthropic; print(anthropic.__version__)"
# anthropic 0.97.0

# Files APIメソッドの存在確認 — 実際の実行結果
# client.beta.filesで確認されたメソッド:
# ['delete', 'download', 'list', 'retrieve_metadata', 'upload',
#  'with_raw_response', 'with_streaming_response']

betasパラメーターがuploadlistdeleteretrieve_metadataすべてに必要だという点は直接確認した。公式ドキュメントの一部の例ではこのパラメーターが省略または異なる表記で混乱を招くことがある。SDK 0.97.0時点では必須だ。


いつ使うべきか(そして使うべきでない場合)

Files APIが有利な状況:

  • 同じドキュメントを繰り返し分析する:契約書、報告書、技術文書を多角的に分析する場合
  • マルチターンの会話でドキュメント参照:ユーザーが同じドキュメントについて複数回質問するチャットアプリ
  • 大容量ドキュメントのバッチ処理:ファイル100件をそれぞれ複数の質問で分析するとき、各ファイルを1回だけアップロード

使う必要がない状況もある:

  • 一回限りの分析:文書を1回だけ分析するなら、ファイルをサーバーに置いておく必要はない
  • 小さなテキストファイル:数KB程度のテキストはインラインで入れる方がシンプルだ
  • 個人情報を含む文書:ファイルをAnthropicのサーバーに保存することに対するデータ処理ポリシーをチームで確認する必要がある

最後の点が、実際の導入前に最も長く考えた部分だ。顧客の契約書や社内財務データを外部サーバーに保存することは、単なる技術的な判断ではない。データ処理契約(DPA)の条件とコンプライアンス要件を先に確認する必要がある。


Message Batches APIとの組み合わせ

Anthropic Message Batches APIは大量リクエストを非同期で処理しながらコストを50%削減する。Files APIと組み合わせると2つの削減効果を同時に得られる。

ファイル100件に質問10個で計1,000件のAPIリクエストだ。Files APIなしでは各リクエストでドキュメント全体を送信する必要がある。両APIを組み合わせるとファイル再転送削減+バッチ50%割引を同時に適用できる。LangfuseでLLMコストを追跡すると、実際にどれだけ節約できたかを数字で確認できる。


現時点での限界と私の判断

Files APIは現在ベータ状態だ。これが意味するのは:

  • APIの変更可能性がある。files-api-2025-04-14というバージョンタグがある理由だ。次のバージョンが出ればマイグレーションが必要になる可能性がある
  • エラーハンドリングがGA機能と比べて洗練されていないことがある
  • 公式ドキュメントがSDKの実際の実装と微妙に異なる場合がある(betasパラメーターで直接確認したこと)

正直に言えば、このAPIが特別に複雑だったり革新的だったりするわけではない。S3にファイルをアップロードしてURL参照するパターンをAnthropicのエコシステム内で実装したものだ。既に自前のストレージがあるチームなら、わざわざFiles APIに移行すべき強い理由があるかを考える価値がある。

Files APIが明らかに有利なのは、Anthropic APIを始めたばかりのチームか、自前のファイルストレージを管理したくない場合だ。すでにS3やGCSでファイルを管理しているなら、AnthropicがSigned URLやパブリックURL参照をサポートするまで待つのも合理的な選択肢だ。


参考資料(実際に確認したソース)

他の言語で読む

この記事は役に立ちましたか?

より良いコンテンツを作成するための力になります。コーヒー一杯で応援してください。

著者について

jw

Kim Jangwook

AI/LLM専門フルスタック開発者

10年以上のWeb開発経験を活かし、AIエージェントシステム、LLMアプリケーション、自動化ソリューションを構築しています。Claude Code、MCP、RAGシステムの実践的な知見を共有します。

ブログリストへ