以编程方式使用文档

认证代理允许沙箱代码调用外部 API(OpenAI、Anthropic、GitHub 等)而无需硬编码凭证。在沙箱上配置后,代理 sidecar 会自动使用您工作区中的密钥或在代理配置中提供的只写凭证,将认证头注入匹配出站请求。

出口和网络访问控制

相同的 proxy_config 注入凭证的机制也可以控制沙箱可以访问的目标。

默认出口策略

默认情况下(未配置 access_control ):

  • 允许访问任何主机的 HTTP 和 HTTPS(端口 80 和 443)。 出站 HTTP(S) 会透明地通过代理路由,在那里您的 rulescallbacks 注入凭证。
  • 所有其他原始 TCP 连接均被阻止。 非 HTTP 端口的连接(如数据库(psql/dbt 5432 上的 PostgreSQL)、SSH(22)、Redis(6379)等——除非明确允许,否则将被丢弃。

这意味着原始协议被阻止并非因为代理"无法理解"它们——而是默认被阻止,并通过 access_control.

允许和拒绝列表

添加一个 access_control 对象到 proxy_config ,包含 **以下之一** an allow_list **or** a deny_list (不能同时设置——如果两者都设置了,请求将被拒绝):

模式行为
allow_list**Default-deny.** Only listed destinations are reachable—including HTTP/HTTPS. If you set an allow_list,您还必须列出沙箱所需的每个 HTTP(S) 主机。
deny_list**Default-allow for HTTP/HTTPS.** 所有 HTTP(S) 主机保持可访问,列出的除外。一个 deny_list 无法打开原始 TCP 端口。

模式语法

每个 allow_list/deny_list 条目使用以下形式:

模式含义
host裸主机 → 端口 **仅 80 和 443** (HTTP/S).
host:PORT精确主机 PORT. :22 仅授予 22, **不是** additive with 80/443—list the host twice if you need both.
*.example.comGlob 模式(RFC 1034 风格)。顶级域名(example.com) is **不** 包含。
~regex不透明正则匹配;不解析端口后缀。
1.2.3.4 / 10.0.0.0/8字面 IP 或 CIDR。CIDR **不能** carry a port (HTTP/S only in allow mode; block all ports in deny mode).
[::1]:22IPv6 字面量在指定端口时使用带括号的形式。

连接数据库(原始 TCP)

要使沙箱代码能够访问外部 PostgreSQL 数据库 psql, dbt,或任何驱动程序,请在对应端口上将主机列入白名单。因为 allow_list 默认为拒绝,还需列出沙箱需要访问的所有 HTTP(S) 主机:

curl -X POST "$LANGSMITH_ENDPOINT/v2/sandboxes/boxes" \
  -H "x-api-key: $LANGSMITH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "db-sandbox",
    "wait_for_ready": true,
    "proxy_config": {
      "access_control": {
        "allow_list": [
          "db.example.com:5432",
          "api.openai.com"
        ]
      }
    }
  }'

db.example.com:5432 的连接在 TCP 层直接透传,不会被拦截,因此 PostgreSQL 协议——以及 TLS、主机密钥检查和在其之上的任何其他端到端协议——均能正常工作。

通过 SDK 配置

from langsmith.sandbox import SandboxClient

client = SandboxClient()

client.create_sandbox(
    name="db-sandbox",
    proxy_config={
        "access_control": {
            "allow_list": ["db.example.com:5432", "api.openai.com"]
        }
    },
)
const client = new SandboxClient();

await client.createSandbox({
  name: "db-sandbox",
  proxyConfig: {
    access_control: {
      allow_list: ["db.example.com:5432", "api.openai.com"],
    },
  },
});

配置身份验证代理规则

在创建沙箱时添加一个 proxy_config ,或通过修补其来更新现有沙箱 proxy_config。每条规则指定:

字段描述
match_hosts要拦截的主机(支持通配符,如 *.github.com)
match_paths要匹配的路径(留空 = 所有路径)
headers要注入的头部,每个包含一个 name, typevalue
no_proxy完全绕过代理的主机(例如 localhost)

头部类型

每个头部都有一个 type 来控制其值的存储和显示方式:

类型描述
workspace_secret使用 {KEY} 语法引用工作区密钥。在应用代理配置时解析。
plaintext值按原样存储和返回。用于非敏感头部。
opaque只写。值在静态时加密,且永远不会通过 API 返回。

AWS 请求身份验证

当沙箱代码需要使用 AWS SDK 或 CLI 调用 AWS 服务时,请使用 AWS 身份验证规则。代理将真实的 AWS 凭据保留在沙箱外部,然后使用 AWS SigV4 对支持的出站 HTTPS 请求进行签名。

这在代理代码需要检查 S3 对象、调用 Bedrock 或使用其他支持的 AWS HTTPS 端点时非常有用,同时不会在沙箱文件、环境变量、Shell 历史记录或日志中暴露长期有效的 AWS 访问密钥。沙箱接收兼容的 AWS 凭据占位符以使 SDK 凭据检测正常工作,而代理使用配置的凭据对出站请求进行签名。

AWS 身份验证规则与头部注入规则不同:

  • - 设置 type to aws.
  • - 将凭据放在 aws object.
  • - 不要设置 match_hosts, match_paths, or headers;AWS 主机匹配已内置到代理中。
  • - 每个沙箱最多配置一个 AWS 身份验证规则。
curl -X POST "$LANGSMITH_ENDPOINT/v2/sandboxes/boxes" \
  -H "x-api-key: $LANGSMITH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "aws-sandbox",
    "wait_for_ready": true,
    "proxy_config": {
      "rules": [
        {
          "name": "aws",
          "type": "aws",
          "enabled": true,
          "aws": {
            "access_key_id": {
              "type": "workspace_secret",
              "value": "{AWS_ACCESS_KEY_ID}"
            },
            "secret_access_key": {
              "type": "workspace_secret",
              "value": "{AWS_SECRET_ACCESS_KEY}"
            }
          }
        }
      ]
    }
  }'

通过 SDK 配置 AWS 身份验证

from langsmith.sandbox import (
    SandboxClient,
    aws_auth,
    proxy_config,
    workspace_secret,
)

client = SandboxClient()

client.create_sandbox(
    name="aws-sandbox",
    proxy_config=proxy_config(
        rules=[
            aws_auth(
                access_key_id=workspace_secret("AWS_ACCESS_KEY_ID"),
                secret_access_key=workspace_secret("AWS_SECRET_ACCESS_KEY"),
            )
        ]
    ),
)
  SandboxClient,
  awsAuth,
  proxyConfig,
  workspaceSecret,
} from "langsmith/sandbox";

const client = new SandboxClient();

await client.createSandbox({
  name: "aws-sandbox",
  proxyConfig: proxyConfig({
    rules: [
      awsAuth({
        accessKeyId: workspaceSecret("AWS_ACCESS_KEY_ID"),
        secretAccessKey: workspaceSecret("AWS_SECRET_ACCESS_KEY"),
      }),
    ],
  }),
});

沙箱就绪后,在沙箱内正常使用 AWS SDK 或 CLI。SDK 或 CLI 可以发现占位符 AWS 环境变量,代理会对出站 AWS 请求应用真实的 SigV4 签名。

GCP 请求身份验证

当沙盒代码需要使用 Google SDK 或 CLI 调用 Google API 时,请使用 GCP 身份验证规则。代理将服务帐号 JSON 保存在沙盒外部,然后对与沙盒代理匹配的 Google API 主机的出站 HTTPS 请求进行身份验证。

当代理代码需要检查 GCS 对象或调用其他 Google API,但不想在沙盒文件、环境变量、shell 历史记录或日志中暴露服务帐号 JSON 时,此功能非常有用。沙盒会收到兼容性凭证以便 SDK 凭证检测正常工作,同时代理使用配置的服务帐号对出站请求进行身份验证。

GCP 身份验证规则与 header 注入规则不同:

  • - 设置 type to gcp.
  • - 将凭证放在 gcp.service_account_json.
  • - 设置 gcp.scopes 为非空的 OAuth scope 列表。
  • - 代理自动匹配 Google API 主机,并使用配置的服务帐号对这些请求进行身份验证。
  • - 每个沙盒最多配置一个启用的 GCP 身份验证规则。

SDK gcp_authgcpAuth 辅助函数以相同方式构建此规则。

curl -X POST "$LANGSMITH_ENDPOINT/v2/sandboxes/boxes" \
  -H "x-api-key: $LANGSMITH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "gcp-sandbox",
    "wait_for_ready": true,
    "proxy_config": {
      "rules": [
        {
          "name": "gcp",
          "type": "gcp",
          "enabled": true,
          "gcp": {
            "service_account_json": {
              "type": "workspace_secret",
              "value": "{GCP_SERVICE_ACCOUNT_JSON}"
            },
            "scopes": [
              "https://www.googleapis.com/auth/devstorage.read_only"
            ]
          }
        }
      ]
    }
  }'

通过 SDK 配置 GCP 身份验证

from langsmith.sandbox import (
    SandboxClient,
    gcp_auth,
    proxy_config,
    workspace_secret,
)

client = SandboxClient()

client.create_sandbox(
    name="gcp-sandbox",
    proxy_config=proxy_config(
        rules=[
            gcp_auth(
                service_account_json=workspace_secret("GCP_SERVICE_ACCOUNT_JSON"),
                scopes=["https://www.googleapis.com/auth/devstorage.read_only"],
            )
        ]
    ),
)
  SandboxClient,
  gcpAuth,
  proxyConfig,
  workspaceSecret,
} from "langsmith/sandbox";

const client = new SandboxClient();

await client.createSandbox({
  name: "gcp-sandbox",
  proxyConfig: proxyConfig({
    rules: [
      gcpAuth({
        serviceAccountJson: workspaceSecret("GCP_SERVICE_ACCOUNT_JSON"),
        scopes: ["https://www.googleapis.com/auth/devstorage.read_only"],
      }),
    ],
  }),
});

沙盒就绪后,在沙盒内正常使用 Google SDK 或 CLI 发起支持的 Google API 请求。SDK 或 CLI 可以发现兼容性凭证,代理应用真实的 GCP 身份验证而不将服务帐号 JSON 暴露在沙盒内。

单 API 示例

创建一个自动向出站请求注入 OpenAI API 密钥的沙盒:

curl -X POST "$LANGSMITH_ENDPOINT/v2/sandboxes/boxes" \
  -H "x-api-key: $LANGSMITH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "openai-sandbox",
    "wait_for_ready": true,
    "proxy_config": {
      "rules": [
        {
          "name": "openai-api",
          "match_hosts": ["api.openai.com"],
          "headers": [
            {
              "name": "Authorization",
              "type": "workspace_secret",
              "value": "Bearer {OPENAI_API_KEY}"
            }
          ]
        }
      ]
    }
  }'

沙盒现在可以调用 OpenAI,无需设置 API 密钥——代理会自动注入。

多 API 示例

添加多个规则以同时向多个服务进行身份验证:

curl -X POST "$LANGSMITH_ENDPOINT/v2/sandboxes/boxes" \
  -H "x-api-key: $LANGSMITH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "multi-api-sandbox",
    "wait_for_ready": true,
    "proxy_config": {
      "rules": [
        {
          "name": "openai-api",
          "match_hosts": ["api.openai.com"],
          "headers": [
            {
              "name": "Authorization",
              "type": "workspace_secret",
              "value": "Bearer {OPENAI_API_KEY}"
            }
          ]
        },
        {
          "name": "anthropic-api",
          "match_hosts": ["api.anthropic.com"],
          "headers": [
            {
              "name": "x-api-key",
              "type": "workspace_secret",
              "value": "{ANTHROPIC_API_KEY}"
            },
            {
              "name": "anthropic-version",
              "type": "plaintext",
              "value": "2023-06-01"
            }
          ]
        },
        {
          "name": "github-api",
          "match_hosts": ["api.github.com"],
          "match_paths": ["/repos/*", "/user"],
          "headers": [
            {
              "name": "Authorization",
              "type": "workspace_secret",
              "value": "Bearer {GITHUB_TOKEN}"
            }
          ]
        }
      ],
      "no_proxy": ["localhost", "127.0.0.1"]
    }
  }'

GitHub 示例

Open SWE 通过在沙盒外部生成短期 GitHub App 安装令牌,然后使用只写方式修补沙盒来对 GitHub 访问进行身份验证。 opaque 代理规则。这使短期 GitHub 访问令牌远离沙盒文件系统和部署环境变量。

配置两条规则:

主机Header
api.github.comAuthorization: Bearer <github-token> 用于 gh 和 REST API 调用
github.com, *.github.comAuthorization: Basic <base64("x-access-token:<github-token>")> 用于通过 HTTPS 进行的 Git 操作,如 clone、fetch 和 push
from typing import Any



def github_proxy_rules(github_token: str) -> list[dict[str, Any]]:
    basic_auth = base64.b64encode(
        f"x-access-token:{github_token}".encode()
    ).decode()

    return [
        {
            "name": "github-api",
            "match_hosts": ["api.github.com"],
            "headers": [
                {
                    "name": "Authorization",
                    "type": "opaque",
                    "value": f"Bearer {github_token}",
                }
            ],
        },
        {
            "name": "github",
            "match_hosts": ["github.com", "*.github.com"],
            "headers": [
                {
                    "name": "Authorization",
                    "type": "opaque",
                    "value": f"Basic {basic_auth}",
                }
            ],
        },
    ]


def configure_github_proxy(sandbox_name: str, github_token: str) -> None:
    endpoint = os.environ.get(
        "LANGSMITH_ENDPOINT", "https://api.smith.langchain.com"
    )
    response = httpx.patch(
        f"{endpoint}/v2/sandboxes/boxes/{sandbox_name}",
        headers={"x-api-key": os.environ["LANGSMITH_API_KEY"]},
        json={"proxy_config": {"rules": github_proxy_rules(github_token)}},
        timeout=30.0,
    )
    response.raise_for_status()

configure_github_proxy 创建或重新连接到沙盒后调用。由于 GitHub App 安装令牌会过期,因此在为新运行重用沙盒时需要刷新代理配置。

在沙盒内,当 CLI 在发送请求前需要本地凭证时,设置一个非密钥占位符令牌:

GH_TOKEN=dummy gh repo view langchain-ai/langchain
GH_TOKEN=dummy gh pr list --repo langchain-ai/langchain
GH_TOKEN=dummy gh repo clone langchain-ai/langchain

占位符仅满足 gh CLI 的本地检查。代理注入真实的 Authorization header 到出站请求中。

通过 SDK 配置

from langsmith.sandbox import SandboxClient

client = SandboxClient()

client.create_sandbox(
    name="openai-sandbox",
    proxy_config={
        "rules": [
            {
                "name": "openai-api",
                "match_hosts": ["api.openai.com"],
                "headers": [
                    {
                        "name": "Authorization",
                        "type": "workspace_secret",
                        "value": "Bearer {OPENAI_API_KEY}",
                    }
                ],
            }
        ]
    },
)
const client = new SandboxClient();

await client.createSandbox({
  name: "openai-sandbox",
  proxyConfig: {
    rules: [
      {
        name: "openai-api",
        match_hosts: ["api.openai.com"],
        headers: [
          {
            name: "Authorization",
            type: "workspace_secret",
            value: "Bearer {OPENAI_API_KEY}",
          },
        ],
      },
    ],
  },
});

回调凭证示例

静态 workspace_secret 规则在应用代理配置时从您的工作区拉取凭证, opaque 规则允许您的应用修补短期凭证(如 GitHub 令牌示例。对于必须在代理时由您自己的服务解析的凭据,请使用 **回调**。代理向您提供的 URL 发送 POST 请求,您的端点返回要注入的标头,代理会缓存结果。

回调与规则一起配置在 proxy_config:

字段描述
match_hosts要拦截的主机(语法与规则相同;支持通配符如 *.github.com).
url您的回调端点。必须是可从代理访问的 http:// or https:// URL。
request_headers附加到代理 → 回调请求的标头,例如您的端点用于验证请求的 HMAC 或共享密钥。仅支持 plaintextopaque 类型(不支持 workspace_secret).
ttl_seconds解析后的标头在重新调用回调之前的缓存时间。必须介于 60 到 3600 之间。

静态规则优先。 如果 rules 中有任何规则匹配该主机,则该主机会跳过回调。在规则内采用首次匹配优先原则;如果多个回调匹配,相同原则也适用于回调之间。

回调约定

当缓存未命中且需要为匹配的主机解析凭据时,代理会发出以下请求:

POST <callback.url>
Content-Type: application/json
<request_headers from your config, attached verbatim>

{"host": "api.example.com", "port": 443}

您的端点必须响应 2xx 并返回 JSON 正文:

{
  "headers": {
    "Authorization": "Bearer <token>",
    "X-Org-Id": "..."
  }
}

代理将响应中的每个标头注入沙箱的出站请求,并缓存响应 ttl_seconds。任何非 2xx 响应、传输错误或格式错误的 JSON 都会导致失败关闭:沙箱的请求被拒绝,并返回 502 callback resolution failed (不注入标头,不缓存响应)。

示例

当您的 OAuth 令牌由您自己的服务按需生成时,请使用回调:

curl -X POST "$LANGSMITH_ENDPOINT/v2/sandboxes/boxes" \
  -H "x-api-key: $LANGSMITH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "snapshot_id": "<snapshot-uuid>",
    "name": "callback-sandbox",
    "wait_for_ready": true,
    "proxy_config": {
      "callbacks": [
        {
          "match_hosts": ["api.github.com", "*.githubusercontent.com"],
          "url": "https://auth.your-app.example.com/sandbox-credentials",
          "request_headers": [
            {
              "name": "X-Integrator-Secret",
              "type": "opaque",
              "value": "<shared-secret-your-endpoint-verifies>"
            }
          ],
          "ttl_seconds": 300
        }
      ]
    }
  }'

通过 SDK 配置

from langsmith.sandbox import SandboxClient

client = SandboxClient()

client.create_sandbox(
    name="callback-sandbox",
    proxy_config={
        "callbacks": [
            {
                "match_hosts": ["api.github.com", "*.githubusercontent.com"],
                "url": "https://auth.your-app.example.com/sandbox-credentials",
                "request_headers": [
                    {
                        "name": "X-Integrator-Secret",
                        "type": "opaque",
                        "value": "<shared-secret-your-endpoint-verifies>",
                    }
                ],
                "ttl_seconds": 300,
            }
        ]
    },
)
const client = new SandboxClient();

await client.createSandbox({
  name: "callback-sandbox",
  proxyConfig: {
    callbacks: [
      {
        match_hosts: ["api.github.com", "*.githubusercontent.com"],
        url: "https://auth.your-app.example.com/sandbox-credentials",
        request_headers: [
          {
            name: "X-Integrator-Secret",
            type: "opaque",
            value: "<shared-secret-your-endpoint-verifies>",
          },
        ],
        ttl_seconds: 300,
      },
    ],
  },
});