For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
기본 탐색 메뉴
Theme

셸

호스팅 컨테이너나 자체 로컬 런타임에서 셸 명령어를 실행하세요.

셸 도구를 사용하면 모델이 완전한 터미널 환경에서 작업할 수 있습니다. Responses API는 로컬 환경과 호스팅 환경 모두에서 셸 실행을 지원합니다.

모델은 셸 도구로 다음 두 환경 중 하나에서 명령어를 실행할 수 있습니다.

  • OpenAI가 관리하는 호스팅 셸 컨테이너
  • 개발자가 직접 호스팅하고 명령어를 실행하는 로컬 셸 런타임

셸은 Responses API에서 사용할 수 있습니다. Chat Completions API에서는 사용할 수 없습니다.

임의의 셸 명령어를 실행하면 위험할 수 있습니다. 명령어는 항상 샌드박스에서 실행하고, 가능한 경우 개별 명령어의 실행을 허용하거나 차단하세요. 감사를 위해 도구 활동을 로그에 기록하세요.

호스팅 셸 빠른 시작

호스팅 셸은 계산부터 멀티미디어 처리까지, 다양한 작업을 결정론적으로 처리해야 할 때 간편하게 사용할 수 있는 기본 제공 환경입니다.

OpenAI가 요청에 필요한 컨테이너를 생성하고 관리하도록 하려면 container_auto를 사용하세요.

container_auto로 셸 도구 사용하기
curl -L 'https://api.openai.com/v1/responses' \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-6-astra",
    "tools": [
      { "type": "shell", "environment": { "type": "container_auto" } }
    ],
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": [
          { "type": "input_text", "text": "Execute: ls -lah /mnt/data && python --version && node --version" }
        ]
      }
    ],
    "tool_choice": "auto"
  }'

호스팅 런타임 세부 정보

  • 현재 런타임은 Debian 12를 기반으로 하며, 향후 변경될 수 있습니다.
  • 기본 작업 디렉터리는 /mnt/data입니다.
  • /mnt/data는 항상 존재하며, 사용자가 다운로드할 수 있는 결과물을 저장하는 경로로 지원됩니다.
  • 호스팅 셸은 대화형 TTY 세션을 지원하지 않습니다.
  • 호스팅 셸에서는 sudo로 명령어를 실행하지 않습니다.
  • 워크플로우에 필요한 서비스를 컨테이너 안에서 실행할 수 있습니다.

현재 다음 언어가 기본 설치되어 있습니다.

  • Python 3.11
  • Node.js 22.16
  • Java 17.0
  • PHP 8.2
  • Ruby 3.1
  • Go 1.23

여러 요청에서 컨테이너 재사용하기

반복 작업을 위해 장시간 유지되는 환경이 필요하다면 컨테이너를 생성한 뒤 후속 Responses API 호출에서 해당 컨테이너를 참조하세요.

1. 컨테이너 생성하기

재사용할 컨테이너 생성하기
curl -L 'https://api.openai.com/v1/containers' \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "name": "analysis-container",
    "memory_limit": "1g",
    "expires_after": { "anchor": "last_active_at", "minutes": 20 }
  }'

2. Responses API에서 컨테이너 참조하기

container_reference로 셸 사용하기
curl -L 'https://api.openai.com/v1/responses' \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-6-astra",
    "tools": [
      {
        "type": "shell",
        "environment": {
          "type": "container_reference",
          "container_id": "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe"
        }
      }
    ],
    "input": "List files in the container and show disk usage."
  }'

스킬 연결하기

스킬은 버전 관리와 재사용이 가능한 번들로, 호스팅 셸 환경에 마운트할 수 있습니다. 마운트한 스킬을 모델이 사용할 수 있으며, 셸 실행 시 스킬을 호출할지는 모델이 결정합니다.

업로드와 버전 관리 방법은 스킬 가이드를 참고하세요.

스킬을 연결한 컨테이너 생성하기
curl -L 'https://api.openai.com/v1/containers' \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "name": "skill-container",
    "skills": [
      { "type": "skill_reference", "skill_id": "skill_4db6f1a2c9e73508b41f9da06e2c7b5f" },
      { "type": "skill_reference", "skill_id": "openai-spreadsheets", "version": "latest" }
    ]
  }'

네트워크 액세스

기본적으로 호스팅 컨테이너에서는 외부 네트워크에 접속할 수 없습니다.

외부 네트워크 접속을 허용하려면 다음 두 가지 설정이 필요합니다.

  1. 관리자가 대시보드에서 조직의 허용 목록을 구성해야 합니다.
  2. 개발자가 요청을 보낼 때 컨테이너 환경에 network_policy를 명시적으로 설정해야 합니다.
네트워크 허용 목록을 적용한 셸 도구
curl -L 'https://api.openai.com/v1/responses' \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-astra",
    "tool_choice": "required",
    "tools": [
      {
        "type": "shell",
        "environment": {
          "type": "container_auto",
          "network_policy": {
            "type": "allowlist",
            "allowed_domains": ["pypi.org", "files.pythonhosted.org", "github.com"]
          }
        }
      }
    ],
    "input": [
      {
        "role": "user",
        "content": "In the container, pip install httpx beautifulsoup4, fetch release pages, and write /mnt/data/release_digest.md."
      }
    ]
  }'

도메인을 허용 목록에 추가하면 프롬프트 인젝션으로 인한 데이터 유출 등의 보안 위험이 생깁니다. 신뢰할 수 있고 공격자가 탈취한 데이터를 받는 데 이용할 수 없는 도메인만 허용하세요. 이 도구를 사용하기 전에 아래 위험 및 안전 조치 섹션을 주의 깊게 읽어 보세요.

네트워크 정책 우선순위

여러 제어 설정을 함께 사용하면 다음 규칙이 적용됩니다.

  • 조직의 허용 목록은 allowed_domains에 지정할 수 있는 도메인의 전체 범위를 정의합니다.
  • 요청별 network_policy는 이 범위 안에서 액세스를 더 제한합니다.
  • allowed_domains에 조직의 허용 목록에 없는 도메인이 포함되면 요청이 실패합니다.

데이터 보존 및 컨테이너 수명 주기

호스팅 셸과 코드 인터프리터가 사용하는 호스팅 컨테이너는 활성 상태인 동안 애플리케이션의 임시 상태를 컨테이너 파일 시스템에 기록할 수 있습니다. 이 파일 시스템은 임시 블록 스토리지를 사용합니다. 컨테이너가 만료되거나 명시적으로 삭제되면 컨테이너 데이터도 삭제됩니다.

데이터 제어에 관한 자세한 내용은 ZDR 및 데이터 레지던시를 참고하세요.

결과물 다운로드하기

호스팅 셸은 다운로드할 수 있는 파일을 생성할 수 있습니다. 코드 인터프리터와 동일한 컨테이너 및 파일 API를 사용해 /mnt/data 아래에 저장된 결과물을 가져오세요.

추가 데이터 제어

콘텐츠와 파일을 호스팅 컨테이너의 수명 주기 동안만 유지하려면 요청에 파일을 인라인으로 포함하고 컨테이너에 인라인 스킬을 마운트할 수 있습니다.

인라인 파일 및 인라인 스킬 사용하기
INLINE_ZIP=$(base64 -i ./csv_insights.zip)
REPORT_CSV=$(base64 -i ./report.csv)

CONTAINER_ID=$(
  curl -sL 'https://api.openai.com/v1/containers' \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -d '{
      "name": "inline-skill-container",
      "skills": [
        {
          "type": "inline",
          "name": "csv-insights",
          "description": "Summarize CSV files and produce a markdown report.",
          "source": {
            "type": "base64",
            "media_type": "application/zip",
            "data": "'"$INLINE_ZIP"'"
          }
        }
      ]
    }' | jq -r '.id'
)

curl -L 'https://api.openai.com/v1/responses' \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-6-astra",
    "tools": [
      {
        "type": "shell",
        "environment": {
          "type": "container_reference",
          "container_id": "'"$CONTAINER_ID"'"
        }
      }
    ],
    "input": [
      {
        "role": "user",
        "content": [
          {
            "type": "input_file",
            "filename": "report.csv",
            "file_data": "data:text/csv;base64,'"${REPORT_CSV}"'"
          },
          {
            "type": "input_text",
            "text": "Use the csv-insights skill to summarize report.csv."
          }
        ]
      }
    ]
  }'

후속 요청에서는 동일한 container_id를 container_reference와 함께 전달하세요. 컨테이너가 활성 상태인 동안에는 마운트한 스킬과 컨테이너의 기존 파일을 계속 사용할 수 있습니다.

컨테이너 미리 삭제하기

작업이 끝나면 비활성 상태로 만료될 때까지 기다리지 않고 컨테이너를 직접 삭제할 수 있습니다.

컨테이너 삭제하기
curl -L -X DELETE 'https://api.openai.com/v1/containers/container_id' \
  -H "Authorization: Bearer $OPENAI_API_KEY"

도메인 시크릿

다음과 같은 경우에는 domain_secrets를 사용하세요. allowed_domains 목록에 있는 도메인이 Authorization: Bearer <token>처럼 비밀 값을 담은 인증 헤더를 요구하는 경우입니다.

각 시크릿 항목에는 다음 정보가 포함됩니다.

  • 대상 도메인
  • 알아보기 쉬운 시크릿 이름
  • 시크릿 값

실행 시에는 다음과 같이 처리됩니다.

  • 모델과 런타임에는 실제 자격 증명 대신 플레이스홀더 이름(예: $API_KEY)이 표시됩니다.
  • 인증 정보를 치환하는 사이드카는 승인된 대상으로 보내는 요청에만 실제 시크릿 값을 적용합니다.
  • 실제 시크릿 값은 API 서버에 영구 저장되지 않으며 모델이 볼 수 있는 컨텍스트에도 나타나지 않습니다.

이렇게 하면 어시스턴트가 자격 증명 유출 위험을 줄이면서 보호된 서비스를 호출할 수 있습니다.

domain_secrets로 셸 도구 사용하기
curl -L 'https://api.openai.com/v1/responses' \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-astra",
    "input": [
      {
        "role": "user",
        "content": "Use curl to call https://httpbin.org/headers with header Authorization: Bearer $API_KEY. Tell me what you see in the final text response."
      }
    ],
    "tool_choice": "required",
    "tools": [
      {
        "type": "shell",
        "environment": {
          "type": "container_auto",
          "network_policy": {
            "type": "allowlist",
            "allowed_domains": ["httpbin.org"],
            "domain_secrets": [
              {
                "domain": "httpbin.org",
                "name": "API_KEY",
                "value": "debug-secret-123"
              }
            ]
          }
        }
      }
    ]
  }'

멀티턴 워크플로우

동일한 호스팅 환경에서 작업을 이어가려면 컨테이너를 재사용하고 previous_response_id를 전달하세요.

셸 워크플로우 이어가기
curl -L 'https://api.openai.com/v1/responses' \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-6-astra",
    "previous_response_id": "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",
    "tools": [
      {
        "type": "shell",
        "environment": {
          "type": "container_reference",
          "container_id": "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041"
        }
      }
    ],
    "input": "Read /mnt/data/top5.csv and report the top candidate."
  }'

Responses API의 셸 출력

호스팅 셸과 로컬 셸은 동일한 출력 항목 유형을 사용합니다. 셸 실행은 다음 두 출력 항목의 쌍으로 표현됩니다.

  • shell_call: 모델이 실행을 요청한 명령어
  • shell_call_output: 명령어 출력 및 종료 결과
shell_call 항목 예시
{
  "type": "shell_call",
  "call_id": "call_9d14ac6f2b73485e91c0f4da6e1b27c8",
  "action": {
    "commands": ["ls -l"],
    "timeout_ms": 120000,
    "max_output_length": 4096
  },
  "status": "in_progress"
}

로컬 셸 모드

자체 로컬 런타임에서도 셸 명령어를 실행할 수 있습니다. shell_call 작업을 실행한 뒤 shell_call_output을 모델에 반환하세요.

파일 시스템을 직접 제어하거나 내부 도구에 접근해야 할 때 이 모드를 사용하세요. 도구 유형은 shell로, 해당 도구의 환경 유형은 local로 설정하세요. 지원이 종료된 local_shell 도구에서 마이그레이션하는 경우 요청을 업데이트하고 실행 루프에서 shell_call과 shell_call_output을 처리하세요.

로컬 셸 요청
curl -L 'https://api.openai.com/v1/responses' \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-6-astra",
    "instructions": "The local bash shell environment is on Mac.",
    "input": "find me the largest pdf file in ~/Documents",
    "tools": [{ "type": "shell", "environment": { "type": "local" } }]
  }'

모델에서 shell_call 출력 항목을 받으면 다음과 같이 처리하세요.

  • 실행 전에 각 명령어를 검토하세요. 허용 목록을 사용하고, 파괴적인 명령어나 민감한 데이터에 접근하는 명령어는 반드시 승인을 받은 후에 실행하세요.
  • 파일 시스템과 네트워크 접근 범위, 메모리 사용량, 실행 시간을 명시적으로 제한한 샌드박스에서 승인된 명령어를 실행하세요. 모델이 제한 시간을 제안하더라도 직접 설정한 제한 시간을 적용하세요.
  • 감사를 위해 명령어와 실행 결과를 로그에 기록하세요.
  • 명령어의 stdout과 stderr, 실행 결과를 수집하세요.
  • 다음 요청에서 결과를 shell_call_output으로 반환하세요.
로컬 셸 실행기 예제
from contextlib import suppress
from dataclasses import dataclass
import os
import signal
import subprocess


@dataclass
class CmdResult:
    stdout: str
    stderr: str
    exit_code: int | None
    timed_out: bool


class ShellExecutor:
    def __init__(self, default_timeout: float = 60):
        self.default_timeout = default_timeout

    def run(self, cmd: str, timeout: float | None = None) -> CmdResult:
        t = self.default_timeout if timeout is None else timeout
        p = subprocess.Popen(
            cmd,
            shell=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            start_new_session=True,
        )
        try:
            out, err = p.communicate(timeout=t)
            return CmdResult(out, err, p.returncode, False)
        except subprocess.TimeoutExpired:
            # Stop the shell and its children before draining their output pipes.
            with suppress(ProcessLookupError):
                os.killpg(p.pid, signal.SIGKILL)
            out, err = p.communicate()
            return CmdResult(out, err, p.returncode, True)

이 예제를 실행하려면 Linux 또는 macOS가 필요합니다. 예제의 실행기는 명령어의 실행 제한 시간이 지나면 해당 명령어의 프로세스 그룹 전체를 종료합니다.

shell_call_output 페이로드 예시
{
  "type": "shell_call_output",
  "call_id": "call_3ef1b8c79a4d6520f9e3ab7d41c68f25",
  "max_output_length": 4096,
  "output": [
    {
      "stdout": "...",
      "stderr": "...",
      "outcome": {
        "type": "exit",
        "exit_code": 0
      }
    },
    {
      "stdout": "...",
      "stderr": "...",
      "outcome": {
        "type": "timeout"
      }
    }
  ]
}

명령어 실행이 실패하거나 제한 시간을 초과하면 모델이 재시도 여부를 결정할 수 있도록 해당 결과를 반환하세요. 기존 도구 지원 종료 공지를 참고하세요.

Agents SDK에서 로컬 셸 사용하기

애플리케이션에서 Agents SDK를 사용한다면 직접 구현한 셸 실행기를 셸 도구 헬퍼에 전달할 수 있습니다.

Agents SDK에서 로컬 셸 사용하기
import { Agent, run, withTrace, shellTool } from "@openai/agents";

class LocalShell {
  async run(action) {
    return {
      output: [
        {
          stdout: "Shell is not available. Needs to be implemented first.",
          stderr: "",
          outcome: {
            type: "exit",
            exitCode: 1,
          },
        },
      ],
      maxOutputLength: action.maxOutputLength,
    };
  }
}

const shell = new LocalShell();

const agent = new Agent({
  name: "Shell Assistant",
  model: "gpt-6-astra",
  instructions:
    "You can execute shell commands to inspect the repository. Keep responses concise and include command output when helpful.",
  tools: [
    shellTool({
      shell,
      needsApproval: true,
      onApproval: async (_ctx, _approvalItem) => {
        return { approve: true };
      },
    }),
  ],
});

await withTrace("shell-tool-example", async () => {
  const result = await run(agent, "Show the Node.js version.");
  console.log(`\nFinal response:\n${result.finalOutput}`);
});

SDK 레포지토리에서 실행 가능한 예제를 확인할 수 있습니다.

셸 도구 예제 - TypeScript

Agents SDK에서 셸 도구를 사용하는 TypeScript 예제입니다.

셸 도구 예제 - Python

Agents SDK에서 셸 도구를 사용하는 Python 예제입니다.

일반적인 오류 처리하기

  • 명령어가 실행 제한 시간을 초과하면 시간 초과 결과를 반환하고 그때까지 수집한 출력을 포함하세요.
  • 매개변수 max_output_length가 shell_call에 있으면 shell_call_output에도 포함하세요.
  • 셸 도구는 비대화형으로 실행해야 하므로 대화형 명령어에 의존하지 마세요.
  • 모델이 복구 방법을 판단할 수 있도록 종료 코드가 0이 아닌 경우에도 출력을 보존하세요.

위험 및 안전 조치

Containers API에서 네트워크 액세스를 활성화하면 활용 범위가 넓어지는 만큼 보안 및 데이터 거버넌스 측면에서 상당한 위험이 생깁니다. 네트워크 액세스는 기본적으로 비활성화되어 있습니다. 활성화하더라도 외부 접속은 작업에 필요한 신뢰할 수 있는 도메인으로 엄격히 제한하세요.

네트워크 액세스가 활성화된 컨테이너는 외부 서비스 및 패키지 레지스트리와 통신할 수 있습니다. 이로 인해 데이터가 유출되거나, 프롬프트 인젝션으로 도구가 오용되거나, 의도한 범위를 벗어난 리소스에 실수로 접근할 수 있습니다. 정책이 지나치게 광범위하거나 고정되어 있거나 일관되게 적용되지 않으면 이러한 위험이 커집니다.

네트워크에서 가져온 콘텐츠의 프롬프트 인젝션 위험 이해하기

네트워크에서 가져온 외부 콘텐츠에는 모델의 동작을 조작하려는 지시가 숨겨져 있을 수 있습니다. 신뢰할 수 없는 네트워크 콘텐츠는 공격에 사용될 가능성이 있다고 보고, 데이터나 시스템을 변경할 수 있는 작업에는 더욱 주의하세요.

신뢰할 수 있는 대상에만 연결하기

신뢰할 수 있고 직접 지속적으로 관리하는 도메인만 허용하세요. 다른 서비스로 요청을 중계하는 중개 서비스나 집계 서비스를 이용할 때는 주의하세요. 해당 도메인을 허용 목록에 추가하기 전에 서비스의 데이터 처리 및 보존 방식을 검토하세요.

요청 실행 전후에 검토 절차 마련하기

Responses API 응답에 포함된 셸 도구 명령어와 실행 출력을 검토하세요. 세션마다 요청에 지정된 호스트와 실제 외부 접속 대상을 기록하세요. 로그를 정기적으로 검토해 액세스 패턴이 예상과 일치하는지 확인하고, 패턴의 변화와 의심스러운 동작을 파악하세요.

데이터 레지던시 및 보존 요건 확인하기

OpenAI 데이터 제어는 OpenAI 환경 내에서 적용됩니다. 네트워크를 통해 외부 서비스로 전송한 데이터에는 해당 서비스의 데이터 보존 정책이 적용됩니다. 외부 엔드포인트가 조직의 데이터 레지던시, 보존 및 규정 준수 요건을 충족하는지 확인하세요.