3行でいうと

  • APIのツールは2系統です。xAIのサーバーが実行する組み込みツール(web_search、x_search、code_interpreter、file_search、mcp など)と、自分のコードが実行する関数呼び出し(function)です。どちらも tools の配列に並べ、同じリクエストに混ぜられます。組み込みはサーバーで自動実行され、自分の関数は処理がそこで止まって自分のコードに戻ります。
  • 課金は「トークン」と「ツールの呼び出し」の2本立てです。Web検索とコード実行は1,000回あたり$5、X検索は取得した1,000投稿あたり$5と1,000プロフィールあたり$10、リモートMCPは呼び出し料金なしでトークン課金だけです。X検索の件数は重複を除かずに足されます。
  • エージェント的な長い作業は、Responses APIの previous_response_id(保存は30日)、暗号化された推論内容、コンテキストの圧縮、WebSocketモード、ベータのマルチエージェントで支えられます。ゼロデータ保持(ZDR)を有効にすると、サーバー側の保存に頼る機能は使えなくなります。
  • 安全面で公式が具体的に示しているのは、MCPサーバーの allowed_tools を読み取り専用に絞ること、HTTPSとサーバー側の認証、Web検索の allowed_domains、取り消せない操作の前に人の承認を置くこと、APIキーを環境変数に置くこと、です。プロンプトインジェクションについて、公式のCookbookは、対策なしでは10種類のうち8つの攻撃が通り、対策を1つずつ試しても攻撃が残り、4つすべてを有効にした報告では通らなかった、と実験で示しています。

この記事は公式ドキュメントを2026年10月24日に読んでまとめたもので、実際に使って確かめた記録ではありません。運営者はGrokを入れていますが、使い心地はこの記事には書いていません。コマンド、パラメータ名、料金、上限は公式のページに書かれたとおりに写しています。動作確認はしていません。公式の文章は要約の形で取得したため、ページ全体の長いコードは写せていません。コードブロックは、公式ページに書かれた項目名と値を使って、僕らが並べ直した最小の形です(どれが公式の記述でどれが僕らの組み立てかは、そのつど書き分けます)。読み切れていない箇所は「読んだ範囲では見つからなかった」と書いています。

先に結論

前提:用語をそろえる

この記事で使う言葉です。ツールやMCPの基本的な言葉は、04の記事に書きました。

この記事の位置づけ

APIキー、モデルの選び方、ティアとレート制限は03、ツールの種類名とMCPが3か所にあることは04、学習への利用とデータの保持は02に書きました。今回は、呼び出しの流れ、パラメータの意味、課金の数え方、組み合わせ、安全の注意に絞ります。Grok BuildやGrok Botの拡張には触れません。

1. 最小の形:Responses APIに tools を付ける

公式の Tools Overview が示す呼び出しは、次のとおりです。以下のcurlは、公式ページに載っているものです(動作確認はしていません)。

curl https://api.x.ai/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $XAI_API_KEY" \
  -d '{
  "model": "grok-4.7",
  "stream": true,
  "input": [{"role": "user", "content": "What are the latest updates from SpaceXSI?"}],
  "tools": [{"type": "web_search"}, {"type": "x_search"}, {"type": "code_interpreter"}]
}'

公式の「How It Works」を言い換えると、モデルが質問を分析し、ツールを呼ぶか答えるかを決め、組み込みツールはサーバーで実行され、関数呼び出しは自分のアプリへの要求として返り、十分な情報が集まるまで繰り返して、最終の応答に出典(citations)が付きます。SDKごとにツールの名前が違い、コード実行は、OpenAI互換のResponses APIでは code_interpreter、xAIのPython SDKでは code_execution()、JavaScriptのAI SDKでは xai.tools.codeExecution() です(検索は web_search、x_search と、それぞれの形)。

ストリーミングについて、公式のStreaming & Syncのページは、エージェント的なツール呼び出しではストリーミングを強く勧めています。同期(非ストリーミング)にすると、全体が終わるまで待たされ、途中で何を呼んだかが見えにくくなる、という理由です。タイムアウトの具体的な秒数は、読んだ範囲では書かれていませんでした。

2. 自分の関数を呼んでもらう(関数呼び出し)

2-1. 流れ

公式の Function Calling のページの流れは、(1) name、description、JSON Schemaの parameters を付けて定義し tools に入れる、(2) モデルが外部のデータを必要とすると応答に function_call の項目が入る、(3) 自分のコードで実行する、(4) 結果を call_id に結びつけた function_call_output として送り返す、(5) モデルが最終の答えを作る、です。Responses APIでは、previous_response_id で前のやりとりにつなぎます。

公式の例の項目は次のとおりです。関数名は get_temperature、説明は「Get current temperature for a location」、引数は location(文字列、必須、説明は「City name」)と unit(celsius か fahrenheit、既定は fahrenheit)で、問い合わせの文は「What is the temperature in San Francisco?」、モデルは grok-4.7 です。公式の例の関数は、華氏なら59、摂氏なら15を返す固定値です。

下のJSONは、その項目を使って僕らが並べた最小の形です(公式ページの全文ではなく、この記事では実行も確認していません)。

{
  "model": "grok-4.7",
  "input": [{"role": "user", "content": "What is the temperature in San Francisco?"}],
  "tools": [{
    "type": "function",
    "name": "get_temperature",
    "description": "Get current temperature for a location",
    "parameters": {
      "type": "object",
      "properties": {
        "location": {"type": "string", "description": "City name"},
        "unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "default": "fahrenheit"}
      },
      "required": ["location"]
    }
  }]
}

応答の出力に function_call の項目が入っていたら、その arguments(JSONの文字列)を読んで関数を実行し、次のように送り返します。公式の説明にある項目は、type が function_call_output、call_id(モデルの function_call にあったもの)、output(結果をJSON文字列にしたもの)で、同じ tools と、前の応答の id を入れた previous_response_id を付けます。

{
  "model": "grok-4.7",
  "previous_response_id": "<前の応答のid>",
  "input": [{
    "type": "function_call_output",
    "call_id": "<function_callのcall_id>",
    "output": "{\"location\": \"San Francisco\", \"temperature\": 59, \"unit\": \"fahrenheit\"}"
  }],
  "tools": [ /* 前と同じtools */ ]
}

2-1b. Pythonで書くと(OpenAI SDKの形)

公式のFunction Callingのページには、OpenAI SDK(Python)で base_url="https://api.x.ai/v1" を指定して、1往復を処理する例があります。下は、その流れをこの記事で並べ直した最小の形です(動作確認はしていません)。

import os, json
from openai import OpenAI

client = OpenAI(api_key=os.getenv("XAI_API_KEY"), base_url="https://api.x.ai/v1")

def get_temperature(location, unit="fahrenheit"):
    # 公式の例と同じ固定値。本物のAPIに置き換える
    return {"location": location, "temperature": 59 if unit == "fahrenheit" else 15, "unit": unit}

tools_map = {"get_temperature": get_temperature}
question = [{"role": "user", "content": "What is the temperature in San Francisco?"}]
response = client.responses.create(model="grok-4.7", input=question, tools=tools)  # tools は上のJSONの配列

outputs = []
for item in response.output:
    if item.type == "function_call":
        args = json.loads(item.arguments)          # arguments はJSON文字列
        result = tools_map[item.name](**args)
        outputs.append({"type": "function_call_output",
                        "call_id": item.call_id,
                        "output": json.dumps(result)})

if outputs:
    response = client.responses.create(model="grok-4.7", input=outputs,
                                       tools=tools, previous_response_id=response.id)
print(response.output_text)

この例は1往復だけです。モデルが続けて別の関数を要求することもあるので、公式の説明どおり、function_call が出なくなるまで「実行して送る」を繰り返します。そのとき、僕らの見立てでは、for _ in range(5): のように回数の上限を自分のコードに置きます。tools_map を使うと、モデルが要求した名前のうち、自分が登録した関数だけが実行されるので、未登録の名前を実行しない作りにもなります(これも僕らの見立てです)。

2-2. 選び方と制約

項目 公式の書き方(読んだ範囲)
tool_choice "auto"(既定。モデルが決める)、"required"(少なくとも1つ呼ぶ)、"none"(呼ばない)、特定の関数を指定する形
並列の呼び出し 既定で有効。1つの応答に複数の呼び出しが入りうるので、全部処理してから続ける。止めるなら parallel_tool_calls: false
ツールの数 名前は重複不可で、1リクエストに最大350個(Function Callingのページ)
parameters のルート オブジェクトであること。ルートの anyOf と oneOf は、全部の枝がオブジェクトのときだけ可。違うと、ツール名つきで400エラー
description 省略できるが、書くとモデルが呼ぶべき場面を判断しやすくなる
ストリーミング 関数呼び出しは、1つのチャンクにまとまって届く

注意として、REST APIのリファレンスの要約には、tools の説明に「関数とWeb検索のツールのみ、1リクエストあたり最大1,000」とも読める記述があり、Function Callingのページの350個、Toolsのページの組み込みツール一覧と食い違って見えます。僕らはこの違いを解消できていません。数を多く使う設計では、公式の最新のリファレンスで確かめてください。

厳密モード(strict)については、Function Callingのページ自体には記述がありませんでした。一方、Structured Outputsのページは、ツール呼び出しの引数は、ツールの入力スキーマに従い、strict は常に暗黙に true と書いています。2つのページの書き方の違いは、僕らは確かめきれていません。

2-3. 自分の関数と組み込みツールを混ぜる

公式のAdvanced Usageのページによると、サーバー側ツールは自動で実行され、クライアント側の呼び出しは処理を止めて自分のアプリに戻します。ループの考え方は、次のとおりです(ここは僕らの整理で、公式の手順を言い換えたものです)。

  1. リクエストを送る。
  2. 応答の出力に function_call があるかを見る(OpenAI SDKの例は if item.type == "function_call":)。
  3. なければ終わり。あれば、すべて実行して、function_call_output を作る。
  4. previous_response_id を付けて、結果を送る。1に戻る。

max_turns は、1つのリクエストの中の、サーバー側ツールのターンだけを数えます。関数呼び出しで止まるとそのリクエストは終わり、次のリクエストでは数え直しになります。つまり、上のループを自分で回すなら、無限に回さないための上限は自分のコードで持ちます(僕らの見立てです)。なお、ここで紹介した混ぜ方などの高度な使い方は、Vercel AI SDKではサポートされておらず、xAIのSDKかOpenAIのSDKを使うよう書かれています。

3. 組み込みツールのオプションと、返ってくるもの

3-1. ツールごとのオプション

Toolsの各ページの内容を、使うときの目線で並べ直します。

ツール 公式が書くオプション 制約・注意(公式の書き方)
Web検索 filters の中に allowed_domains か excluded_domains。enable_image_understanding、enable_image_search それぞれ最大5ドメイン。allowed_domains と excluded_domains は同時に使えない。enable_image_understanding をオンにすると、同じリクエストのX検索でも画像理解が有効になる
X検索 allowed_x_handles、excluded_x_handles、from_date、to_date、enable_image_understanding、enable_video_understanding ハンドルは最大20(Vercel AI SDKは10)で、許可と除外は同時に使えない。日付は YYYY-MM-DD だけで、それ以外の形式は適用されない。to_date の当日は含まれない。ハンドルと日付は、キーワード検索と意味検索に効き、スレッドの取得には効かない
コード実行 Pythonを隔離環境で実行 時間とメモリに制限があるが、数値は書かれていない。ネットワークには出られない。ファイルシステムは、「限定的」と「なし」の2通りの書き方が同じページにある
コレクション検索 vector_store_ids(xAI SDKでは collection_ids)、max_num_results 事前にコレクションを作り、文書を入れ、処理済み(DOCUMENT_STATUS_PROCESSED)になるのを待つ。ファイルの種類の完全な一覧と、サイズの上限は、読んだ範囲では書かれていない
リモートMCP server_url、server_label ほか(次の節) Streaming HTTPとSSEのみ

X検索は、モデルが自分でクエリを決めるので結果は毎回変わる、と公式は書いています。コード実行は、実行の状態がリクエストをまたいで保たれないと書かれ、数学の計算には低い temperature(0.0〜0.3)が勧められています。会話の文脈を引き継ぐ例も同じページにありますが、変数などの実行の状態が引き継がれるかは、書かれていませんでした。

3-1b. 設定の書き方の例(Web検索のドメインの絞り込み)

公式のWeb Searchのページは、ドメインの絞り込みの例を、OpenAI SDK(Python)の形で載せています。REST(curl)の例には filters は載っていません。

response = client.responses.create(
    model="grok-4.7",
    input=[{"role": "user", "content": "What is SpaceXSI?"}],
    tools=[{
        "type": "web_search",
        "filters": {"allowed_domains": ["grokipedia.com"]},
    }],
)

除外にしたいときは、allowed_domains の代わりに excluded_domains を書きます。どちらも最大5ドメインで、同時には使えません。max_turns は、このリクエストに並べて指定します(X検索のページの例は2です)。

3-2. 出典(citations)の読み方

公式のCitationsのページによると、response.citations は、エージェントが調べたすべての出典のURLの一覧で、既定で返ります。ただし、最終の答えの中で実際に参照されたURLだけではありません。一方、本文中の [[1]](URL) のような印は、Responses APIでは既定でオンで、include=["no_inline_citations"] でオフにできます(xAIのPython SDKでは逆に既定がオフで、include=["inline_citations"] でオンにします)。本文の各主張に出典が付くことは保証されない、とも書かれています。僕らの見立てですが、出典のURLは「どこを見たか」の記録であって、「内容が正しい」という保証ではないので、重要な回答は、元のページを自分で開いて確かめるのが安全です。

3-3. 応答の中で、ツールの呼び出しを見分ける

公式のTool Usage Detailsのページに、Responses APIの出力の項目の型が書かれています。

response.output[].type 意味
function_call クライアント側。自分のコードで実行する
web_search_call Web検索(サーバー側)
custom_tool_call X検索。call_id は xs_ で始まる(添付ファイルの検索は as_)
code_interpreter_call コード実行(サーバー側)
file_search_call コレクション検索(サーバー側)
mcp_call MCP(サーバー側)

数え方に関する項目は次のとおりです。

サーバー側ツールの出力そのものは、既定では返りません。見たいときの include の値や、MCPの出力の扱いは、読んだ範囲のページ(Tool Usage Details、Web Search、Remote MCP Tools、REST APIリファレンス)には見つかりませんでした。RESTリファレンスは include に「ツール出力のオプション」があるとだけ書いています。

4. リモートMCP:xAIのサーバーが外のMCPサーバーにつなぐ

4-1. 公式の例

公式のRemote MCP Toolsのページのcurlの例は、次の本体を送ります。公開されているDeepWikiのMCPサーバーへつなぐ例です(動作確認はしていません)。

{
  "model": "grok-4.7",
  "input": [
    {
      "role": "user",
      "content": "What can you do with https://github.com/xai-org/xai-sdk-python?"
    }
  ],
  "tools": [
    {
      "type": "mcp",
      "server_url": "https://mcp.deepwiki.com/mcp",
      "server_label": "deepwiki"
    }
  ]
}

4-2. パラメータ

パラメータ 必須 公式の説明(読んだ範囲)
server_url はい MCPサーバーのURL。対応する通信方式は、Streaming HTTPとSSEだけ
server_label はい サーバーを見分ける名前。ツール呼び出しの接頭辞に使われる
server_description いいえ サーバーが何を提供するかの説明
allowed_tools いいえ 使えるツールの名前を限る。空なら全部が有効(xAI SDKでは allowed_tool_names)
authorization いいえ MCPサーバーへのリクエストの Authorization ヘッダーに入れる値
headers いいえ 追加のヘッダー(xAI SDKでは extra_headers)

1つのリクエストに、ラベルを変えた複数の mcp を並べることもできます。OpenAIのResponses APIにある require_approval と connector_id は、現時点では対応していない、と書かれています。

読み取り専用に絞る書き方として、公式のRemote MCP Toolsのページは、xAI SDK(Python)で次の形を示しています。ツール名は公式の例の名前で、実在のサーバーのものではありません。

mcp(
    server_url="https://comprehensive-tools.example.com/mcp",
    allowed_tool_names=["search_database", "format_data"]
)

REST(OpenAI互換)の tools では、同じ項目を allowed_tools と書きます(僕らが表の名前に合わせて並べた形で、公式ページに同じJSONがあるわけではありません)。

{
  "type": "mcp",
  "server_url": "https://comprehensive-tools.example.com/mcp",
  "server_label": "db",
  "allowed_tools": ["search_database", "format_data"]
}

authorization と headers は、読んだページには値の例がありませんでした。表の説明だけです。

4-3. 公式が書く、使い方の注意

4-4. 僕らの見立て:MCPは「相手のサーバーに任せる」道具です

ここは僕らの見立てで、公式の文ではありません。この mcp ツールは、接続をxAIのサーバーが行うので、手元だけで動かしている公開していないサーバーは、そのままでは使えません。authorization に入れたトークンも、xAIのサーバーを経由してMCPサーバーへ届くので、権限は最小にします。MCPサーバーの返事やツールの説明は、モデルの文脈に入るので、そこに混じった文章が指示として働くおそれがあります(後ろの「安全の注意」で扱います)。

音声のAPIにも同じ形があります。公式のSpeech to Speechのページによると、セッションの設定(session.update)の tools に、file_search、web_search、x_search、mcp と自分の関数を入れられます。複数の関数が呼ばれたら、すべての結果を function_call_output で送ってから response.create を1回だけ送ります。先に送ると、一部の結果が抜けた応答になることがある、と書かれています。

5. エージェントとして長く動かす:状態、長さ、複数のエージェント

5-1. 状態をどこに置くか

公式のResponses APIのページによると、保存は既定でオンで、前の入力、推論の内容、モデルの応答が保存されます。続けるときは、新しいメッセージだけを送って、previous_response_id で前を指します。

second = client.responses.create(
    model="grok-4.7",
    previous_response_id=response.id,
    input=[{"role": "user", "content": "How do stars form?"}],
)

上のコードは、公式の説明(previous_response_id に前の応答の id を渡し、新しいメッセージだけを送る)に沿って僕らが組んだ最小の形です。守る点を表にします。

項目 公式の書き方
保存の期間 30日。その後は削除される。30日を超えて続けたいときは、履歴と暗号化された推論内容を自分で持って、送り直す
保存しない store=False で、サーバーに残さない
取り出し・削除 GET /v1/responses/{response_id}、DELETE /v1/responses/{response_id}
instructions との併用 previous_response_id と同時には使えない。前の応答のシステムプロンプトが使われる(REST APIのリファレンスと、Cookbookの両方に書かれている)
暗号化された推論内容 include=["reasoning.encrypted_content"] で受け取る。grok-4.7 は、include に書かなくても常に返す。次のリクエストの input に、前の response.output を並べて送ると、previous_response_id なしで引き継げる
xAI SDKでの2択 store_messages=True と previous_response_id の組み合わせ、または use_encrypted_content=True と chat.append(response)。公式は、この2つを別々の選択肢として並べている(「両方は使うな」とまでは読んだ範囲に書かれていない)

5-2. 長くなった会話を縮める:コンテキストの圧縮

公式のContext Compactionのページによると、POST /v1/responses/compact に model と input を送ると、encrypted_content つきの compaction という1つの項目が返ります。返ってきた output は、そのまま次のリクエストの input の先頭に展開し、そのあとに新しい発言を置きます。「刈り込んではいけない」と書かれていて、解析、編集、結合、並べ替えもしてはいけません。すでに文脈の上限に収まっている会話にしか使えず、1回の呼び出しで圧縮は1回だけです。ZDRとの関係は、読んだページには書かれていませんでした。

5-3. 通信の形:WebSocketモード、Batch API

5-4. マルチエージェント(ベータ)

公式のMulti Agentのページは、これをベータと書き、API の形や挙動が、互換性を壊す形で変わる可能性がある、としています。

項目 公式の書き方
モデル grok-4.20-multi-agent(唯一の対応モデル)。複数のエージェントが協力し、リーダーが最終回答をまとめる
エージェントの数 4か16。xAI SDKは agent_count、OpenAI SDKとRESTは reasoning.effort(low と medium が4、high と xhigh が16)、Vercel AI SDKは reasoningEffort
使えるツール web_search、x_search、code_execution(collections_search)、リモートMCP。ツールなしでも動く
使えないもの 関数呼び出しとカスタムツール、Chat Completions API、max_tokens
返ってくるもの 既定では、ツール呼び出しとリーダーの最終回答だけ。サブエージェントの状態は暗号化され、use_encrypted_content を設定したときだけ含まれる
続きの会話 previous_response_id で続けられる
課金 リーダーとサブエージェントのすべてのトークン(入力、出力、推論)と、どのエージェントのサーバー側ツール呼び出しも課金される

公式は、並列のエージェントが普通のリクエストよりずっと多くのトークンとツール呼び出しを使うことがあると明記し、使用量は usage と server_side_tool_usage で見るよう書いています。僕らの見立てでは、16エージェントは最初から使わず、4で費用と答えの質を見てから決めるのが安全です。

公式の最小の例は、次のとおりです(REST。動作確認はしていません)。reasoning.effort が low なので、エージェントは4つです。

curl https://api.x.ai/v1/responses \
  -H "Authorization: Bearer $XAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-4.20-multi-agent",
    "reasoning": {"effort": "low"},
    "input": "Summarize recent open-source vector database releases.",
    "tools": [{"type": "web_search"}, {"type": "x_search"}]
  }'

high に変えると16になり、公式は、トークンを多く使い、遅延も増えると書いています。

6. 課金の仕組み

6-1. 何に、いくらかかるか

公式のPricingのページ(ページ内の「最終更新」の表示は2026年10月10日)が示す、ツールの料金です。トークンの料金は別に、使ったモデルの単価でかかります。

ツール 公式の価格表示 数え方の注意(公式)
Web Search $5 / 1k calls 画像検索はWeb検索の一部で、同じ料金
X Search $5 / 1k posts、$10 / 1k profiles 呼び出し回数ではなく、返ってきた投稿とプロフィールの数。親の投稿や引用された投稿も数える
Code Execution $5 / 1k calls code_execution と code_interpreter は同じ料金
File Attachments(attachment_search) $5 / 1k calls
Collections Search(collections_search。OpenAI互換のResponses APIでは file_search) $2.50 / 1k calls Pricingの脚注は、gRPC(xAIのPython SDK)では file_search は使えないと書く
Image Generation Imagine APIの料金 解像度や品質ごとの表は、別にある(03に書いた)
Image Understanding(view_image)、X Video Understanding(view_x_video) トークン課金のみ 検索ツールが見つけたメディアに限る。リクエストに直接添えたメディアは別
Remote MCP Tools 呼び出し料金なし 使ったトークンには課金される。MCPサーバー側に別の料金があるかは、公式のページには書かれていない

そのほかに、ファイルとコレクションの保管料が書かれています。Filesは1GiBあたり1日$0.025、Collectionsは1GiBあたり1日$0.10で、どちらもダウンロードは1GiBあたり$0.20です。

使用ガイドラインに違反した、と判断されたリクエストについて、公式は、生成が行われた分は課金される、と書いています。Responses APIで、生成の前に違反が見つかった場合は、1リクエストあたり$0.05の料金になります。

X Searchの数字には、日付がつきます。X Searchのページは、料金は2026年9月21日時点、と書いています。

6-2. 失敗した呼び出しと、重複の数え方

6-3. 僕らの計算の例

上の表の公式の単価を使った、僕らの計算です(トークン料金は含みません)。1回の質問でWeb検索が6回なら、6回 × $5 / 1,000回 で$0.03です。X検索で合計200件の投稿を取得すると、200件 × $5 / 1,000件 で$1.00です。同じ質問を1,000回流して毎回Web検索が2回なら、2,000回で$10です。公式のCookbook(プロンプトインジェクションの対策)には、Web検索が2回呼ばれた例が約3セントだった実測があります。これはトークンも含めた値で、上の計算とは別のものです。

6-4. 自分の使った分を見る

リクエストごとの費用は、03に書いた usage の cost_in_usd_ticks(10,000,000,000で割るとドル)で見られ、トークンとサーバー側ツールの料金を含みます。往復の上限は max_turns で決め、上限に達すると、そこまでに集めた情報で答えます。未設定のときは、サーバー側の全体の上限が適用されます(REST APIのリファレンス)。長い会話では入力が積み上がり、prompt_tokens は、すべての推論リクエストの入力の累計だとTool Usage Detailsに書かれています。キャッシュに当たった分は、安い単価で数えられます。

6-5. 費用を毎回記録する手順(僕らの整理)

公式の項目だけで組める、費用の見張り方です。(1) 各リクエストの usage から cost_in_usd_ticks を取り、10,000,000,000で割ってドルにして、日時・使ったツール・server_side_tool_usage と一緒にログに書く。(2) 1日や1ジョブの合計に上限を決め、超えたら自分のコードで止める。(3) 最初の数日は、max_turns を小さくして、ツールの回数が想定と合うかを見る。(4) マルチエージェントやX検索は、1回分の費用が大きくぶれうるので、別にグラフ化する。トークンの単価は、モデルごとに公式のPricingで確かめてください。この記事には、grok-4.7 の単価の数字は載せていません(03の記事を参照)。

7. 安全の注意

7-1. 公式が示すプロンプトインジェクションの実験

公式のCookbook「プロンプトインジェクションの対策」は、メール係のアシスタントが2つのWebページを取得して要約をメールで送る実験です。片方のページに、アカウントIDを外部のアドレスへ送らせる罠があります。対策なしだと、10種類の攻撃のうち8つが成功した、と書かれています。罠は、HTMLのコメント、画面の外の文字、画像の代替テキスト、偽の「SYSTEM」ブロック、偽のツール出力などの形をとり、隠し文字を使わない攻撃もありました。

試された対策は4つです。(1) ページをデータとして扱い、取得したページを <untrusted> のタグで囲む(fence)。ただし、正直な要約がリンクを伝えることは止められません。(2) 段階ごとにツールを絞り、読む段階は取得だけ、送る段階は送信だけにする(gate)。ただし、送る段階は要約に混じった指示に従いえます。(3) 引数を検査し、宛先、リンク、取得先を既知のものに限る(validate)。ただし、文字の間を空けたIDは通りました。(4) 送る前に人が確認する(confirm)。ただし、実験の確認役は模擬で、検査を通るものは何でも承認しました。

公式の結論は、1つの対策ではすべてを止められず、4つすべてを有効にした報告の1回では、10種類の攻撃が成功しなかった、というものです。結果は実行ごとにばらつき、モデルが存在しないURLを取りに行くこともあった、とも書かれています。

僕らの見立てです。「従うな」とプロンプトに書くだけで済ませず、ツールは必要な段階だけに渡し、引数は自分のコードで検査し、取り消せない操作は人の確認の後ろに置く、という多層で考えます。公式の実験は小さな模擬環境のもので、自分のシステムで同じ結果になるとは限りません。

7-2. 人の承認を挟む:公式の返金エージェントの作り

公式のCookbook「人の承認つきの返金エージェント」は、取り消せない操作の前に処理を止め、承認後に同じ流れを再開する作りです。読んだ範囲の要点は次のとおりです。

  1. 各ターンを store: true で呼ぶ(保存は30日)。2ターン目からは、関数の結果だけを、直前の応答を指す previous_response_id つきで送る。instructions とは併用できないので、システムプロンプトは最初の入力に入れる。parallel_tool_calls: false で、1ターンに1つの呼び出しにする。
  2. モデルが issue_refund を呼んでも、すぐには実行しない。引数を注文と照らして検証し、保留の記録(id、run、response_id、call_id、arguments、status)を作って、処理を止める。
  3. 人が決めたら、承認者と決定を、実行の前に状態ファイル(公式の例は output/state.json)と監査ログ(output/audit.log)に書く。保留の承認は、再起動のあとも、同じ状態ファイルから読み直される。同じ項目を2回決定すると409を返す。承認後は、結果(返金の結果か、却下のメモ)を previous_response_id つきで送って再開する。
  4. 返金は call_id を重複防止のキーにして、再試行で二重に返金しないようにする。公式は、call_id を、決済事業者が受け取る Idempotency-Key ヘッダーのような重複防止のキーだと説明しています。僕らの見立てですが、これが効くのは、決済側が同じキーで作った返金を返してくれる場合です。保存した応答が30日で消えると、その実行は失敗として扱います。

サンプルの決済とメールは、ログファイルに書くだけの代用品で、本番の前に置き換えるよう書かれています。

7-3. ツールごとに気をつけること(僕らの整理)

自分の関数は、引数を信頼できない入力として検査し、送金や削除のような関数は承認の後ろに置きます。Web検索は allowed_domains で範囲を絞り、X検索で拾った他人の投稿は信頼できない文章として扱います。コード実行は隔離環境でも、出力した数字を検算します。リモートMCPは、信頼できるサーバーだけを使い、トークンの権限を最小にします。マルチエージェントは、max_turns と予算の監視で費用の上限を持ちます。

7-4. データの行き先:保存、ZDR、キー、地域

公式のSecurity FAQ(Data & Privacy FAQ)の要点です。

8. 最初の10分でやること

公式に書かれた範囲の手順です。後ろの括弧は根拠にした公式のページで、「僕らの整理」と書いたものは公式の手順ではありません。

  1. APIキーを環境変数に入れる。 export XAI_API_KEY="..."(03に書いたQuickstartの手順)。コードにもリポジトリにも書かない(Security FAQ)。
  2. ツールなしで1回呼ぶ。 POST https://api.x.ai/v1/responses に model と input だけを送る(Responses APIのページ)。
  3. web_search を1つだけ足して呼ぶ。 "tools": [{"type": "web_search"}] を足し、可能ならドメインを絞り(3-1bの例)、"stream": true で途中の様子を見る(Web Search、Streaming & Sync)。
  4. 応答の usage を見る。 server_side_tool_usage と cost_in_usd_ticks で、何回呼ばれ、いくらかかったかを確かめる(Tool Usage Details、03)。
  5. max_turns を小さく決める。 例:2(X Searchのページの例)。
  6. 読み取りだけの関数を1つ作る。 function_call の取り出しと function_call_output の返し方を、2-1bのコードで確かめる。回数の上限を自分のコードに置く(Function Calling、僕らの整理)。
  7. MCPは最後に足す。 公式の例のような公開の読み取り用のサーバーで試し、allowed_tools で絞る(4-2の例。Remote MCP Tools)。
  8. 取り消せない操作は、承認の仕組み(7-2)ができるまで作らない。(僕らの整理)

9. 目的別の選び方(僕らの整理)

やりたいこと 候補 先に決めること
最新のWebの情報で答えさせたい web_search(必要なら x_search) ドメインの絞り込み、max_turns、出典の確認
自分のデータベースやAPIを呼ばせたい 関数呼び出し 関数の権限、引数の検査、承認
社内の文書を引かせたい コレクション検索(file_search) 保管料、ZDRとの関係、処理待ち
既存のMCPサーバーの道具を使わせたい リモートMCP 公開URLか、信頼できるか、allowed_tools
広く調べる作業を任せたい grok-4.20-multi-agent(ベータ) 費用、関数が使えないこと、仕様の変更
大量の質問を一括で処理したい Batch API 完了までの時間、ZDRとの関係

気をつけること

出典