検索結果コンテンツブロックは、適切なソース帰属を持つ自然な引用を可能にし、ウェブ検索品質の引用をカスタムアプリケーションにもたらします。この機能は、Claudeにソースを正確に引用させる必要があるRAG(Retrieval-Augmented Generation)アプリケーションにとって特に強力です。

検索結果機能は以下のモデルで利用可能です:

  • Claude 3.5 Haiku (claude-3-5-haiku-20241022)
  • Claude 3.5 Sonnet (claude-3-5-sonnet-20241022)
  • Claude 3.7 Sonnet (claude-3-7-sonnet-20250219)
  • Claude Opus 4.1 (claude-opus-4-1-20250805)
  • Claude Opus 4 (claude-opus-4-20250514)
  • Claude Sonnet 4 (claude-sonnet-4-20250514)

主な利点

  • 自然な引用 - あらゆるコンテンツに対してウェブ検索と同じ引用品質を実現
  • 柔軟な統合 - 動的RAGのツール戻り値として使用するか、事前取得データのトップレベルコンテンツとして使用
  • 適切なソース帰属 - 各結果にはソースとタイトル情報が含まれ、明確な帰属を提供
  • ドキュメントベースの回避策が不要 - ドキュメントベースの回避策の必要性を排除
  • 一貫した引用形式 - Claudeのウェブ検索機能の引用品質と形式に一致

仕組み

検索結果は2つの方法で提供できます:

  1. ツール呼び出しから - カスタムツールが検索結果を返し、動的RAGアプリケーションを可能にします
  2. トップレベルコンテンツとして - 事前取得またはキャッシュされたコンテンツのために、ユーザーメッセージで直接検索結果を提供します

どちらの場合でも、Claudeは適切なソース帰属を持つ検索結果からの情報を自動的に引用できます。

検索結果スキーマ

検索結果は以下の構造を使用します:

{
  "type": "search_result",
  "source": "https://example.com/article",  // 必須:ソースURLまたは識別子
  "title": "記事タイトル",                  // 必須:結果のタイトル
  "content": [ // 必須:テキストブロックの配列
    {
      "type": "text",
      "text": "検索結果の実際のコンテンツ..."
    }
  ],
  "citations": {                             // オプション:引用設定
    "enabled": true                          // この結果の引用を有効/無効にする
  }
}

必須フィールド

フィールドタイプ説明
typestring"search_result"である必要があります
sourcestringコンテンツのソースURLまたは識別子
titlestring検索結果の説明的なタイトル
contentarray実際のコンテンツを含むテキストブロックの配列

オプションフィールド

フィールドタイプ説明
citationsobjectenabledブールフィールドを持つ引用設定
cache_controlobjectキャッシュ制御設定(例:{"type": "ephemeral"}

content配列の各項目は以下を持つテキストブロックである必要があります:

  • type"text"である必要があります
  • text:実際のテキストコンテンツ(空でない文字列)

方法1:ツール呼び出しからの検索結果

最も強力な使用例は、カスタムツールから検索結果を返すことです。これにより、ツールが関連コンテンツを取得して自動引用付きで返す動的RAGアプリケーションが可能になります。

例:ナレッジベースツール

from anthropic import Anthropic
from anthropic.types import (
    MessageParam,
    TextBlockParam,
    SearchResultBlockParam,
    ToolResultBlockParam
)

client = Anthropic()

# ナレッジベース検索ツールを定義
knowledge_base_tool = {
    "name": "search_knowledge_base",
    "description": "会社のナレッジベースで情報を検索",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "検索クエリ"
            }
        },
        "required": ["query"]
    }
}

# ツール呼び出しを処理する関数
def search_knowledge_base(query):
    # ここに検索ロジック
    # 正しい形式で検索結果を返す
    return [
        SearchResultBlockParam(
            type="search_result",
            source="https://docs.company.com/product-guide",
            title="製品設定ガイド",
            content=[
                TextBlockParam(
                    type="text",
                    text="製品を設定するには、設定 > 構成に移動します。デフォルトのタイムアウトは30秒ですが、ニーズに応じて10-120秒の間で調整できます。"
                )
            ],
            citations={"enabled": True}
        ),
        SearchResultBlockParam(
            type="search_result",
            source="https://docs.company.com/troubleshooting",
            title="トラブルシューティングガイド",
            content=[
                TextBlockParam(
                    type="text",
                    text="タイムアウトエラーが発生した場合は、まず設定を確認してください。一般的な原因には、ネットワーク遅延と不正なタイムアウト値があります。"
                )
            ],
            citations={"enabled": True}
        )
    ]

# ツールを使用してメッセージを作成
response = client.messages.create(
    model="claude-sonnet-4-20250514",  # サポートされているすべてのモデルで動作
    max_tokens=1024,
    tools=[knowledge_base_tool],
    messages=[
        MessageParam(
            role="user",
            content="タイムアウト設定を構成するにはどうすればよいですか?"
        )
    ]
)

# Claudeがツールを呼び出すときに、検索結果を提供
if response.content[0].type == "tool_use":
    tool_result = search_knowledge_base(response.content[0].input["query"])
    
    # ツール結果を送り返す
    final_response = client.messages.create(
        model="claude-sonnet-4-20250514",  # サポートされているすべてのモデルで動作
        max_tokens=1024,
        messages=[
            MessageParam(role="user", content="タイムアウト設定を構成するにはどうすればよいですか?"),
            MessageParam(role="assistant", content=response.content),
            MessageParam(
                role="user",
                content=[
                    ToolResultBlockParam(
                        type="tool_result",
                        tool_use_id=response.content[0].id,
                        content=tool_result  # 検索結果をここに入れる
                    )
                ]
            )
        ]
    )

方法2:トップレベルコンテンツとしての検索結果

ユーザーメッセージで直接検索結果を提供することもできます。これは以下の場合に便利です:

  • 検索インフラストラクチャからの事前取得コンテンツ
  • 以前のクエリからのキャッシュされた検索結果
  • 外部検索サービスからのコンテンツ
  • テストと開発

例:直接検索結果

from anthropic import Anthropic
from anthropic.types import (
    MessageParam,
    TextBlockParam,
    SearchResultBlockParam
)

client = Anthropic()

# ユーザーメッセージで直接検索結果を提供
response = client.messages.create(
    model="claude-opus-4-1-20250805",
    max_tokens=1024,
    messages=[
        MessageParam(
            role="user",
            content=[
                SearchResultBlockParam(
                    type="search_result",
                    source="https://docs.company.com/api-reference",
                    title="APIリファレンス - 認証",
                    content=[
                        TextBlockParam(
                            type="text",
                            text="すべてのAPIリクエストは、AuthorizationヘッダーにAPIキーを含める必要があります。キーはダッシュボードから生成できます。レート制限:標準ティアで1時間あたり1000リクエスト、プレミアムで10000リクエスト。"
                        )
                    ],
                    citations={"enabled": True}
                ),
                SearchResultBlockParam(
                    type="search_result",
                    source="https://docs.company.com/quickstart",
                    title="はじめに",
                    content=[
                        TextBlockParam(
                            type="text",
                            text="開始するには:1)アカウントにサインアップ、2)ダッシュボードからAPIキーを生成、3)pip install company-sdkを使用してSDKをインストール、4)APIキーでクライアントを初期化。"
                        )
                    ],
                    citations={"enabled": True}
                ),
                TextBlockParam(
                    type="text",
                    text="これらの検索結果に基づいて、APIリクエストを認証し、レート制限は何ですか?"
                )
            ]
        )
    ]
)

print(response.model_dump_json(indent=2))

引用付きのClaudeの応答

検索結果がどのように提供されても、Claudeは検索結果からの情報を使用する際に自動的に引用を含めます:

{
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "APIリクエストを認証するには、AuthorizationヘッダーにAPIキーを含める必要があります",
      "citations": [
        {
          "type": "search_result_location",
          "source": "https://docs.company.com/api-reference",
          "title": "APIリファレンス - 認証",
          "cited_text": "すべてのAPIリクエストは、AuthorizationヘッダーにAPIキーを含める必要があります",
          "search_result_index": 0,
          "start_block_index": 0,
          "end_block_index": 0
        }
      ]
    },
    {
      "type": "text",
      "text": "。ダッシュボードからAPIキーを生成できます",
      "citations": [
        {
          "type": "search_result_location",
          "source": "https://docs.company.com/api-reference",
          "title": "APIリファレンス - 認証",
          "cited_text": "キーはダッシュボードから生成できます",
          "search_result_index": 0,
          "start_block_index": 0,
          "end_block_index": 0
        }
      ]
    },
    {
      "type": "text",
      "text": "。レート制限は、標準ティアで1時間あたり1,000リクエスト、プレミアムティアで1時間あたり10,000リクエストです。",
      "citations": [
        {
          "type": "search_result_location",
          "source": "https://docs.company.com/api-reference",
          "title": "APIリファレンス - 認証",
          "cited_text": "レート制限:標準ティアで1時間あたり1000リクエスト、プレミアムで10000リクエスト",
          "search_result_index": 0,
          "start_block_index": 0,
          "end_block_index": 0
        }
      ]
    }
  ]
}

引用フィールド

各引用には以下が含まれます:

フィールドタイプ説明
typestring検索結果引用では常に"search_result_location"
sourcestring元の検索結果からのソース
titlestring または null元の検索結果からのタイトル
cited_textstring引用されている正確なテキスト
search_result_indexinteger検索結果のインデックス(0ベース)
start_block_indexintegercontent配列内の開始位置
end_block_indexintegercontent配列内の終了位置

注:search_result_indexは、検索結果がどのように提供されたか(ツール呼び出しまたはトップレベルコンテンツ)に関係なく、検索結果コンテンツブロックのインデックス(0ベース)を指します。

複数のコンテンツブロック

検索結果はcontent配列に複数のテキストブロックを含むことができます:

{
  "type": "search_result",
  "source": "https://docs.company.com/api-guide",
  "title": "APIドキュメント",
  "content": [
    {
      "type": "text",
      "text": "認証:すべてのAPIリクエストにはAPIキーが必要です。"
    },
    {
      "type": "text",
      "text": "レート制限:APIはキーあたり1時間に1000リクエストを許可します。"
    },
    {
      "type": "text",
      "text": "エラー処理:APIは標準のHTTPステータスコードを返します。"
    }
  ]
}

Claudeはstart_block_indexend_block_indexフィールドを使用して特定のブロックを引用できます。

高度な使用法

両方の方法の組み合わせ

同じ会話でツールベースとトップレベルの検索結果の両方を使用できます:

# トップレベル検索結果を含む最初のメッセージ
messages = [
    MessageParam(
        role="user",
        content=[
            SearchResultBlockParam(
                type="search_result",
                source="https://docs.company.com/overview",
                title="製品概要",
                content=[
                    TextBlockParam(type="text", text="私たちの製品はチームのコラボレーションを支援します...")
                ],
                citations={"enabled": True}
            ),
            TextBlockParam(
                type="text",
                text="この製品について教えて、価格情報を検索してください"
            )
        ]
    )
]

# Claudeは応答し、価格を検索するためにツールを呼び出す可能性があります
# その後、より多くの検索結果を含むツール結果を提供します

他のコンテンツタイプとの組み合わせ

両方の方法で検索結果を他のコンテンツと混在させることができます:

# ツール結果内
tool_result = [
    SearchResultBlockParam(
        type="search_result",
        source="https://docs.company.com/guide",
        title="ユーザーガイド",
        content=[TextBlockParam(type="text", text="設定の詳細...")],
        citations={"enabled": True}
    ),
    TextBlockParam(
        type="text",
        text="追加のコンテキスト:これはバージョン2.0以降に適用されます。"
    )
]

# トップレベルコンテンツ内
user_content = [
    SearchResultBlockParam(
        type="search_result",
        source="https://research.com/paper",
        title="研究論文",
        content=[TextBlockParam(type="text", text="主要な発見...")],
        citations={"enabled": True}
    ),
    {
        "type": "image",
        "source": {"type": "url", "url": "https://example.com/chart.png"}
    },
    TextBlockParam(
        type="text",
        text="チャートは研究結果とどのように関連していますか?"
    )
]

キャッシュ制御

パフォーマンス向上のためにキャッシュ制御を追加:

{
  "type": "search_result",
  "source": "https://docs.company.com/guide",
  "title": "ユーザーガイド",
  "content": [{"type": "text", "text": "..."}],
  "cache_control": {
    "type": "ephemeral"
  }
}

引用制御

デフォルトでは、検索結果の引用は無効になっています。citations設定を明示的に設定することで引用を有効にできます:

{
  "type": "search_result",
  "source": "https://docs.company.com/guide",
  "title": "ユーザーガイド",
  "content": [{"type": "text", "text": "重要なドキュメント..."}],
  "citations": {
    "enabled": true  // この結果の引用を有効にする
  }
}

citations.enabledtrueに設定されている場合、Claudeは検索結果からの情報を使用する際に引用参照を含めます。これにより以下が可能になります:

  • カスタムRAGアプリケーションの自然な引用
  • 独自のナレッジベースとのインターフェース時のソース帰属
  • 検索結果を返すカスタムツールのウェブ検索品質の引用

citationsフィールドが省略された場合、引用はデフォルトで無効になります。

引用はオール・オア・ナッシング:リクエスト内のすべての検索結果で引用を有効にするか、すべてで無効にする必要があります。異なる引用設定を持つ検索結果を混在させるとエラーになります。一部のソースで引用を無効にする必要がある場合は、そのリクエスト内のすべての検索結果で無効にする必要があります。

ベストプラクティス

ツールベース検索(方法1)

  • 動的コンテンツ:リアルタイム検索と動的RAGアプリケーションに使用
  • エラー処理:検索が失敗した場合に適切なメッセージを返す
  • 結果制限:コンテキストオーバーフローを避けるため、最も関連性の高い結果のみを返す

トップレベル検索(方法2)

  • 事前取得コンテンツ:すでに検索結果がある場合に使用
  • バッチ処理:複数の検索結果を一度に処理するのに理想的
  • テスト:既知のコンテンツで引用動作をテストするのに最適

一般的なベストプラクティス

  1. 結果を効果的に構造化

    • 明確で永続的なソースURLを使用
    • 説明的なタイトルを提供
    • 長いコンテンツを論理的なテキストブロックに分割
  2. 一貫性を保つ

    • アプリケーション全体で一貫したソース形式を使用
    • タイトルがコンテンツを正確に反映することを確認
    • フォーマットの一貫性を保つ
  3. エラーを適切に処理

    def search_with_fallback(query):
        try:
            results = perform_search(query)
            if not results:
                return {"type": "text", "text": "結果が見つかりませんでした。"}
            return format_as_search_results(results)
        except Exception as e:
            return {"type": "text", "text": f"検索エラー:{str(e)}"}
    

制限事項

  • 検索結果コンテンツブロックはAnthropic APIとGoogle CloudのVertex AIで利用可能です
  • 検索結果内では、テキストコンテンツのみがサポートされています(画像や他のメディアは不可)
  • content配列には少なくとも1つのテキストブロックが含まれている必要があります