ツールランナーは、エージェントループ、エラーラッピング、型安全性を処理するため、自分で実装する必要がありません。人間によるループ内承認(human-in-the-loop)、カスタムロギング、または条件付き実行が必要な場合は、代わりに手動ループを使用してください。
ツール呼び出し、ツール結果、会話管理を手動で処理する代わりに、ツールランナーは自動的に以下を行います。
SDKヘルパーを使用してツールを定義し、ツールランナーを使用してそれらを実行します。
SDKのツールシグネチャに応じて、ツールは結果を文字列またはコンテンツブロック(テキスト、画像、ドキュメントブロック)として返すため、ツールはマルチモーダルな結果を返すことができます。返された文字列は単一のテキストコンテンツブロックになります。JSONオブジェクトや数値などの構造化データを返すには、まず文字列としてエンコードしてください。
@beta_toolデコレータを使用して、型ヒントとdocstringでツールを定義します。
import json
from anthropic import Anthropic, beta_tool
client = Anthropic()
@beta_tool
def get_weather(location: str, unit: str = "fahrenheit") -> str:
"""Get the current weather in a given location.
Args:
location: The city and state, e.g. San Francisco, CA
unit: Temperature unit, either 'celsius' or 'fahrenheit'
"""
return json.dumps({"temperature": "20°C", "condition": "Sunny"})
@beta_tool
def calculate_sum(a: int, b: int) -> str:
"""Add two numbers together.
Args:
a: First number
b: Second number
"""
return str(a + b)
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[get_weather, calculate_sum],
messages=[
{
"role": "user",
"content": "What's the weather like in Paris? Also, what's 15 + 27?",
}
],
)
for message in runner:
print(message)@beta_toolデコレータは、関数の引数とdocstringを検査して、JSONスキーマを自動的に導出します。
ツールランナーは、Claudeからのメッセージを生成するイテラブルです。各反復で、ランナーはClaudeがツール使用をリクエストしたかどうかを確認します。リクエストされた場合、ツールを実行して結果を自動的にClaudeに送り返し、ループを継続するためにClaudeからの次のメッセージを生成します。
任意の反復でbreak文を使用してループを終了できます。ランナーは、Claudeがツール使用のないメッセージを返すまで、またはmax_iterationsを設定した場合はそれに達するまでループします。
中間メッセージが不要な場合は、最終メッセージを直接取得できます。
runner.until_done()を使用して最終メッセージを取得します。
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[get_weather, calculate_sum],
messages=[
{
"role": "user",
"content": "What's the weather like in Paris? Also, what's 15 + 27?",
}
],
)
final_message = runner.until_done()
for block in final_message.content:
if block.type == "text":
print(block.text)ループ内では、各レスポンスメッセージを読み取り、次のAPI呼び出しの前にランナーの状態を変更できます。各反復は次のライフサイクルに従います。
デフォルトでは、ランナーが会話の状態を管理します。各ツール呼び出しターンの後、アシスタントメッセージとツール結果を自身のメッセージ履歴に追加します。ターンを再試行したい(レスポンスを破棄して再送信する)、フォローアップメッセージを挿入したい、またはツール結果を自分で構築したい場合に、メッセージ履歴を引き継ぎます。
ループ本体の内部からランナーのメッセージを変更することで引き継ぎます。正確な方法はSDKによって異なります。以下の言語別タブを参照してください。
ある反復で引き継ぐと、ランナーはそのターンのアシスタントメッセージやツール結果を追加しません。会話を有効に保つ責任はあなたにあります。アシスタントメッセージとツール結果を自分で追加し(そのターンをカウントしたい場合)、ツール呼び出しがないときにループが終了できるように状態を条件付きで変更し、ループを制限するためにmax_iterationsを渡してください。7つのSDKすべてがmax_iterationsをサポートしています。
generate_tool_call_response()を使用してツール結果を検査または計算します。ループ内でappend_messages()を呼び出すと、履歴を自分で管理していることをランナーに伝えるため、追加する内容にアシスタントメッセージとツール結果を含めてください。
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
max_iterations=10,
tools=[get_weather],
messages=[{"role": "user", "content": "What's the weather in San Francisco?"}],
)
for message in runner:
tool_response = runner.generate_tool_call_response()
if tool_response is not None:
# append_messages() は状態を変更済みとしてフラグを立てるため、ランナーはこの
# イテレーションでの自動追加をスキップします。アシスタントメッセージと
# tool result、および任意のフォローアップを自分で追加してください。
runner.append_messages(
message,
tool_response,
{"role": "user", "content": "Please be concise."},
)
# ツール呼び出しがない場合は、ループが終了するように状態をそのままにします。メッセージ履歴を引き継がずにmax_tokensなどのリクエストパラメータを変更するには、set_messages_params()を使用します。ランナーは引き続きアシスタントメッセージとツール結果を自動的に追加します。
for message in runner:
runner.set_messages_params(lambda params: {**params, "max_tokens": 2048})長時間実行されるエージェントタスクの場合、Python、TypeScript、Rubyのツールランナーは自動コンパクションをサポートしています。これは、トークン使用量がしきい値を超えたときに要約を生成し、会話がコンテキストウィンドウの制限を超えて継続できるようにします。3つのSDKすべてで、このクライアント側のオプションは非推奨となり、すべてのSDKで利用可能なサーバー側のコンテキスト編集が推奨されています。Go、Java、C#、PHPのツールランナーにはクライアント側のコンパクションは含まれていません。
ツールが例外をスローすると、ツールランナーはそれをキャッチし、is_error: trueを持つツール結果としてエラーをClaudeに返します。ツール結果には例外のメッセージ(Pythonではその型とメッセージ)が含まれ、完全なスタックトレースは含まれません。
SDKが何をログに記録するかは言語によって異なります。Python SDKは、ツールが未処理の例外を発生させるたびに、標準のloggingモジュールを通じてスタックトレースを含む完全な例外をログに記録します。Python、TypeScript、Java SDKは、ANTHROPIC_LOG環境変数を読み取ってSDKのロギングを有効にします。これにはリクエストとレスポンスの詳細が含まれます。
# infoレベルでログを出力
export ANTHROPIC_LOG=info
# より詳細な出力のためdebugレベルでログを出力
export ANTHROPIC_LOG=debugGo、Ruby、C#、PHP SDKはANTHROPIC_LOGを読み取りません。Python以外では、失敗したツールをログに記録するSDKはありません。ツールが失敗した理由を確認するには、戻るか再スローする前に、ツール関数内で例外をキャッチしてログに記録してください。
デフォルトでは、ツールエラーはClaudeに返され、Claudeは適切に応答できます。ただし、エラーを検出して異なる方法で処理したい場合があります。たとえば、実行を早期に停止したり、カスタムエラー処理を実装したりする場合です。
PythonとTypeScript SDKでは、ツールレスポンスメソッド(Pythonではgenerate_tool_call_response()、TypeScriptではgenerateToolResponse())を使用して、ツール結果がClaudeに送信される前にインターセプトしてエラーを確認します。他のSDKはそのフックを公開していません。それぞれのタブで最も近い代替手段を説明しています。
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[my_tool],
messages=[{"role": "user", "content": "Run my_tool with the query 'hello'."}],
)
for message in runner:
tool_response = runner.generate_tool_call_response()
if tool_response is not None:
# tool_responseはdictです: {"role": "user", "content": [...]}
# いずれかのツール結果にエラーがあるか確認
for block in tool_response["content"]:
if block.get("is_error"):
# オプション1: 例外を発生させてループを停止
raise RuntimeError(f"Tool failed: {json.dumps(block['content'])}")
# オプション2: ログに記録して続行(Claudeに処理を任せる)
# logger.error(f"Tool error: {json.dumps(block['content'])}")
# メッセージを通常どおり処理
print(message.content)ツール結果をClaudeに送り返す前に変更できます。これは、ツール結果でプロンプトキャッシングを有効にするためにcache_controlなどのメタデータを追加したり、ツール出力を変換したりするのに便利です。
PythonとTypeScript SDKでは、ツールレスポンスメソッドを使用してツール結果を取得し、ランナーが続行する前にそれを変更します。変更した結果を明示的に追加するか、その場で変更するかはSDKによって異なります。各タブのコードコメントを参照してください。
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[search_documents],
messages=[
{
"role": "user",
"content": "Search for information about the climate of San Francisco",
}
],
)
for message in runner:
tool_response = runner.generate_tool_call_response()
if tool_response is not None:
# tool_responseはdict形式です: {"role": "user", "content": [...]}
# ツール結果を変更してキャッシュ制御を追加します
for block in tool_response["content"]:
if block["type"] == "tool_result":
# cache_controlを追加してこのツール結果をキャッシュします
block["cache_control"] = {"type": "ephemeral"}
# 変更したレスポンスを追加します(これにより元のレスポンスの自動追加が防止されます)
runner.append_messages(message, tool_response)
print(message.content)ストリーミングを有効にすると、各ターンのレスポンスを段階的に処理できます。各反復は、イベントを反復処理できるストリームオブジェクトを生成します。
stream=Trueを設定し、get_final_message()を使用して蓄積されたメッセージを取得します。
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[calculate_sum],
messages=[{"role": "user", "content": "What is 15 + 27?"}],
stream=True,
)
# ストリーミング時、ランナーはBetaMessageStreamを返します
for message_stream in runner:
for event in message_stream:
print("event:", event)
print("message:", message_stream.get_final_message())
print(runner.until_done())文法制約付きサンプリングにより、Claudeのツール入力にJSON Schema準拠を強制します。
tool_useブロックのパース、tool_resultレスポンスのフォーマット、is_errorによるエラー処理を行います。
並列ツール呼び出しの有効化、フォーマット、無効化を、メッセージ履歴のガイダンスとトラブルシューティングとともに説明します。
ツールスキーマの指定、効果的な説明の記述、Claudeがツールを呼び出すタイミングの制御を行います。
Was this page helpful?