OpenAI 호스팅 샌드박스
OpenAI 호스팅 샌드박스 (OpenAI-hosted sandboxes)
OpenAI 호스팅 샌드박스는 에이전트에게 Python, Node.js, 커맨드라인 도구가 있는 Linux 워크스페이스를 제공해요. OpenAI가 프로비저닝하고 연결하며, 애플리케이션은 작업을 제공하고 결과를 가져와요. 샌드박스 설정, 네트워크 접근, 파일, 가격, 예시를 다루는 가이드예요.
출처: 문서
본문
OpenAI 호스팅 샌드박스는 에이전트에게 Python, Node.js, 커맨드라인 도구가 있는 Linux 워크스페이스를 제공해요. OpenAI가 프로비저닝하고 연결하며, 여러분의 애플리케이션은 작업을 공급하고 결과를 검색해요. 자체 이미지, 컴퓨팅, 또는 프라이빗 네트워크가 필요할 때는 self-hosted sandbox를 선택하세요.
샌드박스 설정하기
environment.type을 openai_hosted로 설정하고 워크로드에 필요한 설정만 추가하세요. 작업 디렉토리는 /workspace예요.
packages:python,system,npm목록으로 Python, 시스템, 또는 전역npm패키지를 설치해요. 필요할 때pandas==2.2.3처럼 버전을 고정하세요.setup_commands: 에이전트가 시작하기 전에 순서대로 셸 명령을 실행해요(예:[{ "command": "mkdir -p reports" }]). 각 명령은 선택적cwd를 가지며 기본값은/workspace예요.files: Files API ID 또는 인라인 base64 콘텐츠로 입력 파일을 제공해요.env: 문자열 값 환경 변수를 설정해요. 에이전트가 생성한 코드가 이 값을 읽을 수 있어요. 중요: 비밀(secret)의 경우 vault credentials를 사용해 실제 값이 샌드박스 밖에 있게 하세요.PATH,CODEX_*,OPENAI_API_KEY같은 런타임 예약 이름은 거부돼요.skills,plugins,capability_directories: skills와 plugins을 추가해요.environment_template_id: 세션 간에 저장된 설정을 재사용해요. 생략된 설정은 템플릿을 상속하며, 네트워크 재정의는 그 정책을 넓힐 수 없어요.
패키지와 입력 파일은 setup 명령이 실행되기 전에 준비돼요. 0이 아닌 setup 종료 상태는 에이전트가 시작되는 것을 막아요. setup 명령을 사용해 필수 의존성이나 파일을 확인하세요. 템플릿은 실행 중인 워크스페이스가 아니라 설정을 저장해요.
네트워크 접근 제어하기
network.access |
동작 |
|---|---|
enabled |
아웃바운드 접근을 허용해요. 템플릿 정책을 상속하지 않는 한 이것이 기본값이에요. |
disabled |
아웃바운드 접근을 차단해요. |
restricted |
allowed_domains에 나열된 호스트만 허용해요. |
Restricted 모드는 api.example.com 같은 정확한 호스트 이름 1~100개를 받아요. 와일드카드, 프로토콜, 경로, 포트는 포함하지 마세요. 서브도메인과 리다이렉트 대상은 별도 항목이 필요해요. 호스팅 stdio MCP 서버는 현재 enabled 접근을 요구해요(stdio MCP requirements 참고).
설정 성공 확인하기
create-session 응답은 설정이 시작되었음을 의미해요. 세션의 environment.id를 사용해 GET /v1/agents/environments/{environment_id}를 검색하세요: provisioning은 설정이 진행 중임을, connected는 설정이 성공했음을 의미해요. failed의 경우 agent.session.environment.failed 이벤트에서 environment.error를 읽으세요. 라이브 파일을 추가하거나 나열하기 전에 connected를 기다리세요.
파일과 수명
각 세션은 별도의 워크스페이스를 가져요. 샌드박스가 존재하는 동안 파일은 턴을 거쳐 유지돼요. /workspace/outputs 아래 파일은 턴이 완료되면 불변 아티팩트로 게시되며, 그 복사본은 샌드박스가 만료된 후에도 다운로드할 수 있어요.
업로드, 경로 규칙, 라이브 파일 작업, 다운로드, 제한은 Files and artifacts를 사용하세요. 세션을 삭제하기 전에 필요한 출력을 저장하세요.
샌드박스 만료
연결된 샌드박스는 턴 사이를 포함해 keep-alive를 받아요. 활동과 keep-alive가 한 시간 동안 중단되면 샌드박스가 삭제될 수 있어요. 이 타임아웃은 설정할 수 없어요.
작업이 끝나면 샌드박스 정리를 위해 세션을 삭제하세요. 설정 또는 실행이 끝나는 동안 삭제가 409를 반환하면 기다렸다가 시도 횟수에 제한을 두고 재시도하세요. 이벤트 스트림을 닫는 것은 작업을 취소하지 않아요.
가격
OpenAI 호스팅 샌드박스는 표준 container rates를 사용해요. 모델 사용량은 선택한 모델의 API rates로 별도 청구돼요.
예시: 리포트 만들기
에이전트에게 10, 20, 30이 포함된 CSV를 주어요. 에이전트는 Python을 실행해 합계를 계산하고 /workspace/outputs/summary.json을 작성해요.
quickstart prerequisites를 사용해 애플리케이션 터미널에서 OPENAI_API_KEY를 설정하세요. 이 키는 샌드박스 밖에 두세요. beta Agents API가 포함된 OpenAI SDK 버전을 사용하세요.
summary.json 만들기
import OpenAI from "openai";
const client = new OpenAI();
const stream = await client.beta.agents.sessions.create({
agent: { model: "gpt-6-astra" },
environment: {
type: "openai_hosted",
network: { access: "disabled" },
files: [
{
type: "inline",
path: "/workspace/amounts.csv",
data: "YW1vdW50CjEwCjIwCjMwCg==",
},
],
},
input:
"Use Python to sum the amount column in /workspace/amounts.csv. Write a JSON object with the total to /workspace/outputs/summary.json, then read it back to verify it.",
stream: true,
});
for await (const event of stream) {
console.log(event);
}
from openai import OpenAI
client = OpenAI()
stream = client.beta.agents.sessions.create(
agent={"model": "gpt-6-astra"},
environment={
"type": "openai_hosted",
"network": {"access": "disabled"},
"files": [
{
"type": "inline",
"path": "/workspace/amounts.csv",
"data": "YW1vdW50CjEwCjIwCjMwCg==",
}
],
},
input="Use Python to sum the amount column in /workspace/amounts.csv. Write a JSON object with the total to /workspace/outputs/summary.json, then read it back to verify it.",
stream=True,
)
with stream:
for event in stream:
print(event.model_dump_json())
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
func main() {
ctx := context.Background()
client := openai.NewClient()
stream := client.Beta.Agents.Sessions.NewStreaming(ctx, openai.BetaAgentSessionNewParams{
Agent: openai.BetaAgentSessionNewParamsAgent{Model: openai.String("gpt-6-astra")},
Environment: openai.EnvironmentParamUnion{OfParamOpenAIHosted: &openai.EnvironmentParamOpenAIHosted{
Network: openai.EnvironmentParamOpenAIHostedNetwork{Access: "disabled"},
Files: []openai.HostedEnvironmentFileParamUnion{{OfParamInline: &openai.HostedEnvironmentFileParamInline{
Path: "/workspace/amounts.csv",
Data: "YW1vdW50CjEwCjIwCjMwCg==",
}}},
}},
Input: openai.BetaAgentSessionNewParamsInputUnion{OfString: openai.String("Use Python to sum the amount column in /workspace/amounts.csv. Write a JSON object with the total to /workspace/outputs/summary.json, then read it back to verify it.")},
})
defer stream.Close()
for stream.Next() {
fmt.Println(stream.Current().RawJSON())
}
if err := stream.Err(); err != nil {
panic(err)
}
}
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.beta.agents.EnvironmentParam;
import com.openai.models.beta.agents.HostedEnvironmentFileParam;
import com.openai.models.beta.agents.sessions.SessionCreateParams;
public class HostedReport {
public static void main(String[] args) throws Exception {
var client = OpenAIOkHttpClient.fromEnv();
var params =
SessionCreateParams.builder()
.agent(SessionCreateParams.Agent.builder().model("gpt-6-astra").build())
.environment(
EnvironmentParam.OpenAIHosted.builder()
.network(
EnvironmentParam.OpenAIHosted.Network.builder()
.access(EnvironmentParam.OpenAIHosted.Network.Access.DISABLED)
.build())
.addFile(
HostedEnvironmentFileParam.Inline.builder()
.path("/workspace/amounts.csv")
.data("YW1vdW50CjEwCjIwCjMwCg==")
.build())
.build())
.input(
"Use Python to sum the amount column in /workspace/amounts.csv. Write a JSON object"
+ " with the total to /workspace/outputs/summary.json, then read it back to"
+ " verify it.")
.build();
try (var stream = client.beta().agents().sessions().createStreaming(params)) {
stream.stream().forEach(System.out::println);
}
}
}
require "openai"
require "json"
client = OpenAI::Client.new
stream = client.beta.agents.sessions.create_streaming(
agent: { model: "gpt-6-astra" },
environment: {
type: :openai_hosted,
network: { access: :disabled },
files: [
{
type: :inline,
path: "/workspace/amounts.csv",
data: "YW1vdW50CjEwCjIwCjMwCg=="
}
]
},
input: "Use Python to sum the amount column in /workspace/amounts.csv. Write a JSON object with the total to /workspace/outputs/summary.json, then read it back to verify it."
)
begin
stream.each { |event| puts event.to_json }
ensure
stream.close
end
curl --no-buffer --fail-with-body https://api.openai.com/v1/agents/sessions \\\n -H "OpenAI-Beta: agents=v1" \\\n -H "Authorization: Bearer ***" \\\n -H "Content-Type: application/json" \\\n -d \'{\n "agent": {\n "model": "gpt-6-astra"\n },\n "environment": {\n "type": "openai_hosted",\n "network": {\n "access": "disabled"\n },\n "files": [\n {\n "type": "inline",\n "path": "/workspace/amounts.csv",\n "data": "YW1vdW50CjEwCjIwCjMwCg=="\n }\n ]\n },\n "input": "Use Python to sum the amount column in /workspace/amounts.csv. Write a JSON object with the total to /workspace/outputs/summary.json, then read it back to verify it.",\n "stream": true\n}\'
files의 base64 값은 CSV 입력을 담고 있어요. 코드는 세션 이벤트를 출력해요. agent.session.created에서 session.id를 저장하세요. agent.session.turn.completed 이후 아티팩트를 나열하고 summary.json을 찾아 다운로드하세요. 그 내용은 다음과 같아야 해요:
{ "total": 60 }
완료된 턴이 모든 도구가 성공했다는 것을 보장하지는 않아요. 작업이 실패하거나 스트림이 완료 전에 끝나면 저장된 세션 아이템을 검사하세요. 작업이 끝나면 세션을 삭제하세요.
트러블슈팅
| 문제 | 확인할 것 |
|---|---|
| 설정 실패 | 환경-실패 이벤트를 검사하고, 새 세션을 만들기 전에 패키지, 입력 파일, 또는 setup 명령 오류를 고치세요. |
| 샌드박스 요청 차단 | network와 리다이렉트로 도달하는 호스트를 확인하세요. |
| 라이브 파일 작업 실패 | 샌드박스가 connected인지 확인하세요. 만료됐다면 새 세션을 만들고 입력을 다시 공급하세요. |
상태 또는 파일 목록 요청이 5xx 반환 |
지연을 늘리며 마감 시한까지 재시도하세요. 오류가 지속되면 요청 ID를 보관하세요. |
더 알아보기 (Learn more)
관련 문서: 파일과 아티팩트와 샌드박스 수명 주기를 참고하세요.