セルフホストワーカーをデプロイする
セルフホスト型サンドボックスワーカーがワークを取得する方法とセッションの実行場所を選択します。常時稼働またはWebhookトリガー型、単一プロセスまたはセッションごとに1つのサンドボックスから選べます。
クイックスタートでは、継続的にポーリングし、すべてのセッションを1つのプロセスで実行する ant CLIワーカーを1つ実行します。このページでは、ワーカーを実行するその他の方法と、それらの選び方について説明します。
デプロイパターンを選択する
ワーカーをデプロイする際には、ワーカーがワークを取得する方法と、各セッションを実行する場所の2つを選択する必要があります。
ワーカーがワークを取得する方法:
- 常時稼働: 長時間実行されるプロセスがキューを継続的にポーリングし、必要なのはアウトバウンドHTTPSのみです。これが最もシンプルな構成です。
- Webhookトリガー型: ハンドラーが
session.status_run_startedで起動し、ポーリングを開始します。これによりアイドル状態のポーラーを回避できますが、Anthropicから到達可能なWebhookエンドポイントが必要です。
各セッションを実行する場所:
- プロセス内: セッションを取得したワーカーが、そのツール呼び出しも1つの共有作業ディレクトリで実行します。
- セッションごとのサンドボックス: ポーラーが、取得したセッションごとに新しいサンドボックスを起動します。新しいファイルシステム、リソース制限、セッションごとのネットワーク制御など、より強力な分離が必要な場合はこちらを選択してください。
CLIワーカーとSDKワーカーは、それぞれ異なる組み合わせをサポートしています:
| 機能 | ant CLI | SDK(Python、TypeScript、Go) |
|---|---|---|
| 常時稼働のポーリング | はい | はい |
| Webhookトリガー型 | いいえ | はい |
| セッションごとのサンドボックス | はい | はい |
| メモリストア | はい(デフォルトの同期設定) | はい(同期を設定可能) |
| カスタムツール | いいえ | はい |
すべてのCLIフラグとSDKオプションについては、セルフホストワーカーリファレンスを参照してください。より細かく制御したい場合は、Environments Workエンドポイントを直接呼び出して独自のワーカーを実装してください。
常時稼働ワーカーを実行する
どちらのワーカーも、クイックスタートで取得した環境キーで認証します。
ant CLIの場合:
ant beta:worker poll --workdir /workspaceSDKの場合は、EnvironmentWorker が同じ処理を行います:
import asyncio
import contextlib
import os
import signal
from anthropic import AsyncAnthropic
from anthropic.lib.environments import EnvironmentWorker
async def main() -> None:
environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
async with AsyncAnthropic(auth_token=environment_key) as client:
worker = EnvironmentWorker(
client,
environment_id=environment_id,
environment_key=environment_key,
workdir="/workspace",
)
task = asyncio.create_task(worker.run())
# プロセスを強制終了するのではなくタスクをキャンセルすることで、ワーカーは処理中の
# 作業項目を停止し、変更されたメモリファイルを終了前にアップロードできます。
loop = asyncio.get_running_loop()
for signum in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(signum, task.cancel)
with contextlib.suppress(asyncio.CancelledError):
await task
asyncio.run(main())Webhookからワーカーをトリガーする
Webhook署名キーをエクスポートする
クイックスタートで取得した環境IDとキーに加えて、ハンドラーのホストでWebhook署名キーをエクスポートします。ハンドラーはこれを使用して受信ペイロードを検証します。
export ANTHROPIC_WEBHOOK_SIGNING_KEY="whsec_..."Webhookハンドラーを実装する
session.status_run_startedが発火したときにワーカーを呼び出します。ハンドラーはキューを処理し尽くし、取得した各ワークアイテムをhandle_item()に渡します。これはスキルをダウンロードし、ツール呼び出しを実行し、結果を送り返してから戻ります。Webhook署名を検証するには、webhooksエクストラをインストールしてください:
pip install "anthropic[webhooks]"。import asyncio import os import anthropic import standardwebhooks # installed by the anthropic[webhooks] extra environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"] environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"] client = anthropic.AsyncAnthropic( auth_token=environment_key, ) # shutdown() によってキャンセルされ、実行中の作業項目が変更されたメモリファイルをアップロードし、 # プロセス終了前にストアディレクトリを削除できるようにします。 inflight: set[asyncio.Task[None]] = set() # ホストのシャットダウンフックから await してください。例: ASGI lifespan のシャットダウン(FastAPI lifespan の # `yield` 以降のコード)。uvicorn は SIGTERM 時にこれを実行します。uvicorn は未完了のリクエストを # フック実行前に完了させるため、--timeout-graceful-shutdown を設定して待機時間を制限してください。 async def shutdown() -> None: for task in inflight: task.cancel() await asyncio.gather(*inflight, return_exceptions=True) async def handle(raw: bytes, headers: dict[str, str]) -> tuple[dict[str, str], int]: try: event = client.beta.webhooks.unwrap(raw.decode(), headers=headers) except standardwebhooks.WebhookVerificationError: return {"error": "signature verification failed"}, 401 if event.data.type != "session.status_run_started": return {"status": "ignored"}, 200 task = asyncio.create_task(run_queued_work()) inflight.add(task) task.add_done_callback(inflight.discard) try: # シールド済み: 配信の切断やタイムアウトで項目をキャンセルしてはなりません。キャンセルは shutdown() が行います。 await asyncio.shield(task) except asyncio.CancelledError: return {"status": "shutting down"}, 503 return {"status": "ok"}, 200 async def run_queued_work() -> None: async for work in client.beta.environments.work.poller( environment_id=environment_id, environment_key=environment_key, block_ms=None, reclaim_older_than_ms=2000, drain=True, auto_stop=False, ): await client.beta.environments.work.worker(workdir="/workspace").handle_item( work_id=work.id, environment_id=environment_id, session_id=work.data.id, environment_key=environment_key, # セッションごとのシークレットにより、ワーカーはセッションのメモリストアをマウントできます。 work_secret=work.secret, )ハンドラーは自らワークを取得するため、ここでの
work_secret引数のように、ワークアイテムのシークレットを転送する必要があります。
このハンドラーは、取得したすべてのアイテムを1つのホスト上の1つのプロセスで実行します。セッションが同じメモリストアをアタッチする場合は、ストアを共有するセッションを分離するを参照してください。
セッションごとに1つのサンドボックスを実行する
ホスト上のポーラーがワークを取得し、ワークアイテムごとに1回スクリプトを呼び出します。スクリプトはその1つのセッション用のサンドボックスを起動します。
サンドボックスイメージをビルドする
antをインストールし、ant beta:worker runをエントリポイントとして設定します。サンドボックスが起動すると、環境変数からセッションの詳細を読み取り、そのセッションを処理して終了します。ベースイメージには/bin/bashが必要です。curlはビルド時にのみ使用されます。FROM your-base-image ARG ANT_VERSION=1.39.0 ARG TARGETARCH RUN ARCH=$([ "$TARGETARCH" = "arm64" ] && echo arm64 || echo amd64) && \ curl -fsSL "https://github.com/anthropics/anthropic-cli/releases/download/v${ANT_VERSION}/ant_${ANT_VERSION}_linux_${ARCH}.tar.gz" \ | tar -xz -C /usr/local/bin ant WORKDIR /workspace VOLUME /workspace ENTRYPOINT ["ant", "beta:worker", "run"]スポーンスクリプトを作成する
スクリプトはセッションの詳細を新しいサンドボックスに転送します。ポーラーのホストに
jqが必要です。#!/bin/bash # spawn.sh: 取得した作業項目ごとに1回呼び出されます # 取得した作業項目は stdin から JSON として渡されます。 ANTHROPIC_WORK_SECRET="$(jq -r '.secret // empty')" export ANTHROPIC_WORK_SECRET mkdir -p "/host/outputs/$ANTHROPIC_SESSION_ID" exec docker run --rm \ -e ANTHROPIC_SESSION_ID -e ANTHROPIC_ENVIRONMENT_KEY \ -e ANTHROPIC_WORK_ID -e ANTHROPIC_ENVIRONMENT_ID -e ANTHROPIC_BASE_URL \ -e ANTHROPIC_WORK_SECRET \ -v "/host/outputs/$ANTHROPIC_SESSION_ID":/workspace \ your-imageポーラーは、スクリプトが転送する
ANTHROPIC_*変数を設定します(シークレットを除く)。環境変数を参照してください。/host/outputsは任意に選択するホストディレクトリです。これを/workspaceにマウントすると、サンドボックスの終了後にセッションの成果物を取得できます。このマウントには、ダウンロードされたskills/ツリーや中間ファイルも含まれます。ポーラーを起動する
ant beta:worker poll --on-work ./spawn.sh
ワークアイテムのシークレットを転送する
取得された各ワークアイテムには、Anthropicが発行するセッションごとの secret が含まれる場合があります。セッションを実行するワーカーは、メモリストアをマウントするためにこれを必要とします。
セッションの取得と実行を1つのプロセスで行うワーカー(--on-work なしの ant beta:worker poll、または run() を使用する EnvironmentWorker)は、シークレットを自ら受け渡します。取得とワーカーの間に独自のコードが入る場合は、自分で転送します:
| ワークの取得方法 | シークレットの受け取り方 | ワーカーへの渡し方 |
|---|---|---|
ant beta:worker poll --on-work | スクリプトの標準入力に渡されるワークアイテムのJSONの secret フィールド | サンドボックスの環境内の ANTHROPIC_WORK_SECRET |
SDKの work.poller() | 取得した各ワークアイテムの secret フィールド | サンドボックスの環境内の ANTHROPIC_WORK_SECRET、または handle_item() への work_secret 引数 |
シークレットは、そのセッションを処理するサンドボックスにのみ渡し、決してログに記録しないでください。環境キーとの関係については、セキュリティモデルを参照してください。
SDKポーラーからサンドボックスを起動する
ant beta:worker poll --on-work の代わりに独自のコードからワークを取得するには、work.poller() を使用します。これはキューをポーリングして取得した各セッションを渡すので、お客様がサンドボックスを起動します:
import asyncio
import os
from anthropic import AsyncAnthropic
from anthropic.types.beta.environments import BetaSelfHostedWork
SANDBOX_ENV = (
"ANTHROPIC_ENVIRONMENT_ID",
"ANTHROPIC_ENVIRONMENT_KEY",
"ANTHROPIC_WORK_ID",
"ANTHROPIC_SESSION_ID",
"ANTHROPIC_WORK_SECRET",
"ANTHROPIC_BASE_URL", # forwarded only when set on this host
)
async def launch_container(work: BetaSelfHostedWork) -> None:
print(f"claimed session {work.data.id}")
# `docker run` は独自のサンドボックス起動ツールに置き換えてください。環境
# キー(APIキーは絶対に渡さないでください)と作業項目のセッションごとのシークレットを転送します。内部のワーカーは
# セッションのメモリストアをマウントするためにこのシークレットを必要とします。
env = os.environ | {
"ANTHROPIC_WORK_ID": work.id,
"ANTHROPIC_SESSION_ID": work.data.id,
"ANTHROPIC_WORK_SECRET": work.secret or "",
}
forward = [arg for name in SANDBOX_ENV for arg in ("-e", name)]
launcher = await asyncio.create_subprocess_exec(
"docker", "run", "--rm", "--detach", *forward, "your-image", env=env
)
await launcher.wait()
async def main() -> None:
environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
async with AsyncAnthropic(auth_token=environment_key) as client:
async for work in client.beta.environments.work.poller(
environment_id=environment_id,
environment_key=environment_key,
auto_stop=False, # the launched sandbox owns the stop call
):
await launch_container(work)
asyncio.run(main())サンドボックス内でSDKワーカーを実行する
サンドボックスでカスタムツールを提供する必要がある場合や、デフォルト以外のメモリ同期設定を使用する必要がある場合は、ant beta:worker run エントリポイントをSDKエントリポイントに置き換えます。エントリポイントは EnvironmentWorker を構築して handle_item() を呼び出します。これはスポーンスクリプトが転送するのと同じ ANTHROPIC_* 変数を読み取ります。
import asyncio
import contextlib
import os
import signal
from anthropic import AsyncAnthropic
from anthropic.lib.environments import EnvironmentWorker
async def main() -> None:
async with AsyncAnthropic(auth_token=os.environ["ANTHROPIC_ENVIRONMENT_KEY"]) as client:
worker = EnvironmentWorker(client, workdir="/workspace")
# 引数なしの場合、handle_item() は spawn スクリプトが転送した ANTHROPIC_* 変数を読み取ります。
# これには ANTHROPIC_WORK_SECRET も含まれます。
task = asyncio.create_task(worker.handle_item())
# コンテナ停止時にタスクをキャンセルすることで、ワーカーは終了前に
# 変更されたメモリファイルをアップロードし、ストアディレクトリを削除できます。
loop = asyncio.get_running_loop()
for signum in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(signum, task.cancel)
with contextlib.suppress(asyncio.CancelledError):
await task
asyncio.run(main())セッション用のファイルをステージングする
Anthropicは、セルフホスト型サンドボックスにファイルやGitHubリポジトリをマウントしません。セッション固有のファイルを利用可能にするには:
- S3パスやコミットSHAなどのファイル参照を、セッションの
metadataフィールドで渡します。 - スポーンスクリプトまたは
--on-workハンドラーで、セッションを取得(GET /v1/sessions/{session_id})してmetadataを読み取ります。取得したワークアイテムにはセッションIDは含まれますが、メタデータは含まれません。 - ツールの実行が始まる前に、ファイルを作業ディレクトリにステージングします。
session = client.beta.sessions.create(
agent=agent.id,
environment_id=environment.id,
metadata={"input_file": "s3://my-bucket/data.csv"},
)次のステップ
キューの深さを確認し、セッションとワーカーを正常に停止し、一般的な障害を修正します。
セルフホスト型サンドボックス環境における責任共有モデル。
Was this page helpful?