“Self-hosted sandboxes”(自托管沙箱)将智能体的工具执行从 Anthropic 托管的云沙箱迁移到您控制的基础设施中,而 Anthropic 继续运行智能体本身。要了解这意味着什么并判断它是否适合您的智能体,请参阅选择智能体环境。

工作原理

self_hosted 环境充当一个工作队列。您运行一个 environment worker(环境工作进程),这是在您自己的基础设施上为该队列提供服务的进程:

  1. 您创建一个以该环境为目标的会话。Anthropic 将该会话作为工作项加入队列。
  2. 您的工作进程认领该工作项,并下载智能体的 skills 和会话的 memory stores。
  3. Claude 在 Anthropic 一侧运行并请求工具调用。您的工作进程在本地运行每个调用,并将结果回传。

工具的输入和输出仍会流向 Anthropic 的 control plane(控制平面),以便模型接收结果并决定下一步操作。技能和记忆存储由 Anthropic 存储,您的沙箱会为该会话保存一份副本。有关完整的数据流边界,请参阅安全模型。

自托管沙箱支持 Managed Agents 中可用的所有 Claude 模型。模型是在智能体上配置的,而不是在环境上。

ant CLI 以及 Python、TypeScript 和 Go SDK 都附带预构建的工作进程。Cloudflare、Daytona 和 Modal 等沙箱提供商也发布了各自的平台指南。

快速入门

本快速入门使用 ant CLI 运行一个常驻工作进程,向其发送一个会话,并确认智能体的工具调用在您的主机上运行。

前提条件

  • 一个智能体: 如果您还没有,请先完成开始使用 Claude Managed Agents,并记下智能体 ID。
  • 一台 Linux 或 macOS 主机: 主机需要在该确切路径下有 /bin/bash。worker 只需要出站 HTTPS。
  • 一个 Claude API 密钥: 您在自己的机器上使用它来创建会话和读取队列统计信息。不要将它放在 worker 主机上,因为智能体的工具调用可能会读取到它。
  • 您自己机器上的 ant CLI 或 SDK: 本快速入门中的统计和会话步骤在您自己的机器上运行,而不是在 worker 主机上。请按照安装步骤为 worker 安装 CLI 的相同方式安装 CLI,或者安装 SDK。

注意

在 Claude Platform on AWS 上,工作进程使用 AWS IAM(SigV4)或在 AWS Console 中生成的 API 密钥进行身份验证,而不是使用环境密钥。请将 AnthropicSelfHostedEnvironmentAccess 托管策略附加到运行工作进程的 IAM 主体上。在 Claude Console 中生成的环境密钥不适用于 Claude Platform on AWS 端点。

在 Claude Models on Google Cloud (Anthropic managed) 上,工作进程使用 Google Cloud 凭据进行身份验证,而不是使用环境密钥。请在项目上为您的工作进程所使用的 Google Cloud 身份授予 roles/claude.user 或 roles/claude.admin 角色。这两个角色都包含 environments.processWork(工作进程需要该权限来轮询和管理工作项),以及运行会话所需的会话和技能权限。在 Claude Console 中生成的环境密钥不适用于 Claude Models on Google Cloud (Anthropic managed) 端点。ant CLI 以及 Python、TypeScript 和 Go SDK 中的预构建工作进程不支持 Claude Models on Google Cloud (Anthropic managed),因此请实现您自己的工作进程,直接调用 Environments Work 端点。请参阅不支持的功能。

注意

在 macOS 上,即使您使用 Homebrew 安装了较新版本的 Bash,worker 的 bash 工具仍会运行位于 /bin/bash 的系统 Bash 3.2。要在 macOS 上使用记忆存储,请先准备 macOS 主机。

运行您的第一个会话

  1. 创建自托管环境

    在 Claude Console 中,前往 Environments 页面(platform.claude.com/environments),点击 Create environment,然后在 Hosting 下选择 Self-hosted。

    或者通过 API:

    cURL

    curl -sS --fail-with-body https://api.anthropic.com/v1/environments \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "anthropic-beta: managed-agents-2026-04-01" \
      -H "content-type: application/json" \
      -d '{
        "name": "self-hosted",
        "config": {"type": "self_hosted"}
      }'

    CLI

    ant apply environment.yaml

    environment.yaml

    # yaml-language-server: $schema=https://platform.claude.com/schemas/ant/beta/environment.json
    name: self-hosted
    config:
      type: self_hosted

    Python

    client = anthropic.Anthropic()
    
    environment = client.beta.environments.create(
        name="self-hosted", config={"type": "self_hosted"}
    )
    print(environment.id)

    TypeScript

    const client = new Anthropic();
    
    const environment = await client.beta.environments.create({
      name: "self-hosted",
      config: { type: "self_hosted" }
    });
    console.log(environment.id);

    C#

    using Anthropic.Models.Beta.Environments;
    
    var client = new AnthropicClient();
    
    var environment = await client.Beta.Environments.Create(
        new EnvironmentCreateParams
        {
            Name = "self-hosted",
            Config = new BetaSelfHostedConfigParams(),
        }
    );
    Console.WriteLine(environment.ID);

    Go

    client := anthropic.NewClient()
    
    environment, err := client.Beta.Environments.New(context.Background(), anthropic.BetaEnvironmentNewParams{
    	Name: "self-hosted",
    	Config: anthropic.BetaEnvironmentNewParamsConfigUnion{
    		OfSelfHosted: &anthropic.BetaSelfHostedConfigParams{},
    	},
    })
    if err != nil {
    	panic(err)
    }
    fmt.Println(environment.ID)

    Java

    import com.anthropic.models.beta.environments.BetaSelfHostedConfigParams;
    import com.anthropic.models.beta.environments.EnvironmentCreateParams;
    
    void main() {
        var client = AnthropicOkHttpClient.fromEnv();
    
        var environment = client.beta().environments().create(
            EnvironmentCreateParams.builder()
                .name("self-hosted")
                .config(BetaSelfHostedConfigParams.builder().build())
                .build()
        );
        IO.println(environment.id());
    }

    PHP

    $client = new Client();
    
    $environment = $client->beta->environments->create(
        name: 'self-hosted',
        config: ['type' => 'self_hosted'],
    );
    echo $environment->id, PHP_EOL;

    Ruby

    client = Anthropic::Client.new
    
    environment = client.beta.environments.create(
      name: "self-hosted",
      config: {type: :self_hosted}
    )
    puts environment.id
  2. 生成环境密钥

    在 Console 中,打开该环境并点击 Generate environment key。环境密钥用于向其队列验证 worker 的身份。即使是通过 API 创建的环境,也只能在 Console 中生成环境密钥。

    在 worker 主机上导出环境 ID 和密钥:

    export ANTHROPIC_ENVIRONMENT_KEY="sk-ant-oat01-..."
    export ANTHROPIC_ENVIRONMENT_ID="env_..."
  3. 安装 ant CLI

    在 worker 主机上运行以下命令。

    Homebrew (macOS)

    brew install anthropics/tap/ant

    curl (Linux/WSL)

    对于 Linux 环境,请直接下载发布版二进制文件。

    VERSION=2.4.0
    OS=$(uname -s | tr '[:upper:]' '[:lower:]')
    case $(uname -m) in
      x86_64) ARCH=amd64 ;;
      aarch64) ARCH=arm64 ;;
    esac
    curl -fsSL "https://github.com/anthropics/anthropic-cli/releases/download/v${VERSION}/ant_${VERSION}_${OS}_${ARCH}.tar.gz" \
      | sudo tar -xz -C /usr/local/bin ant

    您可以在 GitHub 发布页面上找到所有发布版本。

    Go

    您也可以使用 go install 从源代码安装 CLI。需要 Go 1.25 或更高版本。

    go install github.com/anthropics/anthropic-cli/v2/cmd/ant@latest

    二进制文件会被放置在 $(go env GOPATH)/bin 中。如果该目录尚未添加到您的 PATH 中,请将其添加进去:

    export PATH="$PATH:$(go env GOPATH)/bin"

    检查安装情况:

    ant --version
  4. 启动 worker

    创建工作目录,然后将 --workdir 设置为该目录来启动 worker。如果不使用该标志,worker 将使用当前目录。

    Linux

    传入 /workspace 以与系统默认值保持一致。

    sudo mkdir -p /workspace && sudo chown "$USER" /workspace
    ant beta:worker poll --workdir /workspace

    macOS

    根卷是只读的,因此 mkdir 无法创建 /workspace。请改用您主目录中的某个目录。如果智能体使用 skills,请按照沙箱文件系统中的说明,将此目录的完整路径(echo ~/workspace 会打印该路径)添加到其系统提示中。

    mkdir -p ~/workspace
    ant beta:worker poll --workdir ~/workspace

    worker 会读取您导出的两个变量,并持续轮询,直到您停止它。

  5. 验证 worker 已连接

    在您自己的机器上,将 ANTHROPIC_API_KEY 设置为您的 Claude API 密钥(而不是环境密钥),并将 ANTHROPIC_ENVIRONMENT_ID (python, ruby: environment_id; typescript, java, csharp: environmentId; go: environmentID; php: $environmentId) 设置为环境 ID。确认 workers_polling (java, php: workersPolling; csharp, go: WorkersPolling) 至少为 1:

    cURL

    curl -sS --fail-with-body "https://api.anthropic.com/v1/environments/$ANTHROPIC_ENVIRONMENT_ID/work/stats" \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "anthropic-beta: managed-agents-2026-04-01"

    CLI

    ant beta:environments:work stats --environment-id "$ANTHROPIC_ENVIRONMENT_ID"

    Python

    client = anthropic.Anthropic()
    
    stats = client.beta.environments.work.stats(environment_id)
    print(f"workers_polling={stats.workers_polling}")

    TypeScript

    const client = new Anthropic();
    
    const stats = await client.beta.environments.work.stats(environmentId);
    
    console.log(`workers_polling=${stats.workers_polling}`);

    C#

    var client = new AnthropicClient();
    
    var stats = await client.Beta.Environments.Work.Stats(environmentId);
    
    Console.WriteLine($"workers_polling={stats.WorkersPolling}");

    Go

    client := anthropic.NewClient()
    
    stats, err := client.Beta.Environments.Work.Stats(
    	context.Background(),
    	environmentID,
    	anthropic.BetaEnvironmentWorkStatsParams{},
    )
    if err != nil {
    	panic(err)
    }
    
    fmt.Printf("workers_polling=%d\n", stats.WorkersPolling)

    Java

    var client = AnthropicOkHttpClient.fromEnv();
    
    var stats = client.beta().environments().work().stats(environmentId);
    
    IO.println("workers_polling=" + stats.workersPolling().orElse(null));

    PHP

    $client = new Client();
    
    $stats = $client->beta->environments->work->stats($environmentId);
    
    printf("workers_polling=%d\n", $stats->workersPolling);

    Ruby

    client = Anthropic::Client.new
    
    stats = client.beta.environments.work.stats(environment_id)
    
    puts "workers_polling=#{stats.workers_polling}"

    如果 workers_polling (java, php: workersPolling; csharp, go: WorkersPolling) 一直为 0,请参阅故障排除。

  6. 启动会话

    将 AGENT_ID (python, ruby: agent_id; typescript, java, csharp: agentId; go: agentID; php: $agentId) 设置为您的智能体 ID。创建一个以该环境为目标的会话,然后向其发送一个任务:

    cURL

    # 创建会话
    curl -sS --fail-with-body https://api.anthropic.com/v1/sessions \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "anthropic-beta: managed-agents-2026-04-01" \
      -H "content-type: application/json" \
      -d '{
        "agent": "'"$AGENT_ID"'",
        "environment_id": "'"$ANTHROPIC_ENVIRONMENT_ID"'"
      }'
    
    # 向其发送任务:SESSION_ID 是创建响应中返回的 ID
    curl -sS --fail-with-body "https://api.anthropic.com/v1/sessions/$SESSION_ID/events" \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "anthropic-beta: managed-agents-2026-04-01" \
      -H "content-type: application/json" \
      -d '{
        "events": [
          {
            "type": "user.message",
            "content": [
              {
                "type": "text",
                "text": "Write the output of \"uname -a\" to hello.txt in your working directory."
              }
            ]
          }
        ]
      }'

    CLI

    # 创建会话
    ant beta:sessions create \
      --agent "$AGENT_ID" \
      --environment-id "$ANTHROPIC_ENVIRONMENT_ID"
    
    # 向其发送任务:SESSION_ID 是创建响应中返回的 ID
    ant beta:sessions:events send --session-id "$SESSION_ID" <<'YAML'
    events:
      - type: user.message
        content:
          - type: text
            text: Write the output of "uname -a" to hello.txt in your working directory.
    YAML

    Python

    session = client.beta.sessions.create(
        agent=agent_id,
        environment_id=environment_id,
    )
    
    client.beta.sessions.events.send(
        session.id,
        events=[
            {
                "type": "user.message",
                "content": [
                    {
                        "type": "text",
                        "text": 'Write the output of "uname -a" to hello.txt in your working directory.',
                    },
                ],
            },
        ],
    )

    TypeScript

    const session = await client.beta.sessions.create({
      agent: agentId,
      environment_id: environmentId
    });
    
    await client.beta.sessions.events.send(session.id, {
      events: [
        {
          type: "user.message",
          content: [
            {
              type: "text",
              text: 'Write the output of "uname -a" to hello.txt in your working directory.'
            }
          ]
        }
      ]
    });

    C#

    var session = await client.Beta.Sessions.Create(new()
    {
        Agent = agentId,
        EnvironmentID = environmentId,
    });
    
    await client.Beta.Sessions.Events.Send(session.ID, new()
    {
        Events =
        [
            new BetaManagedAgentsUserMessageEventParams
            {
                Content =
                [
                    new BetaManagedAgentsTextBlock
                    {
                        Text = "Write the output of \"uname -a\" to hello.txt in your working directory.",
                    },
                ],
            },
        ],
    });

    Go

    session, err := client.Beta.Sessions.New(context.Background(), anthropic.BetaSessionNewParams{
    	Agent:         anthropic.BetaSessionNewParamsAgentUnion{OfString: anthropic.String(agentID)},
    	EnvironmentID: environmentID,
    })
    if err != nil {
    	panic(err)
    }
    
    _, err = client.Beta.Sessions.Events.Send(context.Background(), session.ID, anthropic.BetaSessionEventSendParams{
    	Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
    		OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
    			Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
    				OfText: &anthropic.BetaManagedAgentsTextBlockParam{
    					Text: "Write the output of \"uname -a\" to hello.txt in your working directory.",
    				},
    			}},
    		},
    	}},
    })
    if err != nil {
    	panic(err)
    }

    Java

    var session = client.beta().sessions().create(SessionCreateParams.builder()
        .agent(agentId)
        .environmentId(environmentId)
        .build());
    
    client.beta().sessions().events().send(
        session.id(),
        EventSendParams.builder()
            .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
                .addTextContent("Write the output of \"uname -a\" to hello.txt in your working directory.")
                .build())
            .build());

    PHP

    $session = $client->beta->sessions->create(
        agent: $agentId,
        environmentID: $environmentId,
    );
    
    $client->beta->sessions->events->send(
        $session->id,
        events: [
            [
                'type' => 'user.message',
                'content' => [['type' => 'text', 'text' => 'Write the output of "uname -a" to hello.txt in your working directory.']],
            ],
        ],
    );

    Ruby

    session = client.beta.sessions.create(
      agent: agent_id,
      environment_id: environment_id
    )
    
    client.beta.sessions.events.send_(
      session.id,
      events: [
        {
          type: :"user.message",
          content: [{type: :text, text: 'Write the output of "uname -a" to hello.txt in your working directory.'}]
        }
      ]
    )

    会话会在环境的队列中等待,直到有 worker 认领它。如果没有连接任何 worker,会话将保持排队状态,而不会失败。

  7. 确认工具在您的主机上运行

    在 worker 主机上,读取智能体写入的文件:

    Linux

    cat /workspace/hello.txt

    macOS

    cat ~/workspace/hello.txt

    该文件描述的是您自己主机的内核,因此智能体的工具调用是在那里运行的。要实时跟踪智能体的工作,请参阅会话事件流。

会话资源

自托管沙箱仅支持 memory_store 资源。在自托管环境上包含 file 或 github_repository 资源的会话会被拒绝,并返回 400 错误:

Environment env_... is a self-hosted environment. `resources` are not supported with self-hosted environments.

以自托管环境为目标的部署遵循相同的规则。要为会话提供其自己的输入文件,请参阅为会话暂存文件。

自托管沙箱与 MCP 隧道

自托管控制的是智能体代码在哪里运行。MCP 隧道控制的是 Anthropic 如何访问您网络中的 MCP 服务器。两者相互独立:

  • 在 Anthropic 云沙箱中的会话可以通过隧道访问私有 MCP 服务器。例如,私有 MCP 服务器可能部署在您防火墙后的数据库或内部 API 前面。
  • 自托管会话可以使用经隧道连接的 MCP 服务器或公共 MCP 服务器。

当您希望执行和工具访问都保留在您的边界内时,请同时使用两者。要跳过隧道,请将 MCP 服务器封装为自定义工具,由您的工作进程提供服务。

平台指南

这些页面介绍了如何在任何沙箱平台上构建工作进程。此外还提供以下特定平台的指南:

后续步骤

可用性

自托管沙箱在所有模型上可用。

API 支持

Managed Agents

  • 可用性:可用
状态 云平台 模型
可用 Claude API, Claude Platform on AWS, Claude Models on Google Cloud (Anthropic managed) 所有模型

所需的 beta 请求头

Beta 请求头概览

Beta 请求头让您可以在实验性功能和新模型能力成为标准 API 的一部分之前访问它们。

  • managed-agents-2026-04-01

数据处理

数据处理概览

项目 零数据保留 HIPAA
状态 不具备资格 不具备资格
详细信息 会话是有状态的资源;对话记录会一直保留,直到您将其删除。适用于所有 Managed Agents 子功能,包括自托管沙箱。 适用于所有 Managed Agents 子功能,包括自托管沙箱。

适用的端点:

  • /v1/agents
  • /v1/sessions
  • /v1/environments