Modal

deepagents와 함께 Modal 샌드박스 백엔드를 사용하면 GPU 지원으로 격리된 코드 실행이 가능해요.

Modal은 GPU 지원을 갖춘 서버리스 컨테이너 인프라를 제공해요. ML/AI 워크로드와 Python 개발에 가장 적합합니다.

출처: 문서

본문

설정

npm install @langchain/modal
yarn add @langchain/modal
pnpm add @langchain/modal

인증

modal.com/settings/tokens에서 토큰을 받으세요.

export MODAL_TOKEN_ID=your_token_id
export MODAL_TOKEN_SECRET=your_token_secret

또는 자격 증명을 직접 전달하세요:

const sandbox = await ModalSandbox.create({
  auth: {
    tokenId: "your-token-id",
    tokenSecret: "your-token-secret",
  },
});

deepagents와 함께 사용하기

import { createDeepAgent } from "deepagents";
import { ChatAnthropic } from "@langchain/anthropic";
import { ModalSandbox } from "@langchain/modal";

const sandbox = await ModalSandbox.create({
  imageName: "python:3.12-slim",
  timeoutMs: 600_000, // 10 minutes
});

try {
  const agent = createDeepAgent({
    model: new ChatAnthropic({ model: "claude-sonnet-4-20250514" }),
    systemPrompt: "You are a coding assistant with sandbox access.",
    backend: sandbox,
  });

  const result = await agent.invoke({
    messages: [{ role: "user", content: "Install numpy and calculate pi" }],
  });
} finally {
  await sandbox.close();
}

단독 사용(Standalone usage)

import { ModalSandbox } from "@langchain/modal";

const sandbox = await ModalSandbox.create({
  imageName: "python:3.12-slim",
  timeoutMs: 600_000,
});

const result = await sandbox.execute("python --version");
console.log(result.output);

await sandbox.close();

구성(Configuration)

옵션(Option) 타입(Type) 기본값(Default) 설명(Description)
imageName string "alpine:3.21" 사용할 Docker 이미지
timeoutMs number 300000 최대 수명(밀리초)
workdir string - 작업 디렉터리
gpu string - GPU 타입("T4", "A100", "H100" 등)
cpu number - CPU 코어 수(소수 허용)
memoryMiB number - 메모리 할당량(MiB)
volumes Record<string, string> - 볼륨 이름 매핑(마운트 경로 → 볼륨 이름)
secrets string[] - 주입할 Modal Secret 이름
initialFiles Record<string, string | Uint8Array> - 시작 시 생성할 파일
env Record<string, string> - 환경 변수
blockNetwork boolean - 네트워크 접근 차단
name string - 샌드박스 이름(앱 내에서 고유)

GPU 지원

Modal은 ML 워크로드를 위한 NVIDIA GPU를 지원합니다:

const sandbox = await ModalSandbox.create({
  imageName: "python:3.12-slim",
  gpu: "T4",  // or "L4", "A10G", "A100", "H100"
});

볼륨과 시크릿(Volumes and secrets)

영속적 저장을 위해 Modal Volumes를 마운트하고 시크릿을 환경 변수로 주입하세요:

// Volumes and secrets must be created in Modal first
const sandbox = await ModalSandbox.create({
  imageName: "python:3.12-slim",
  volumes: {
    "/data": "my-data-volume",
    "/models": "my-models-volume",
  },
  secrets: ["my-api-keys", "database-credentials"],
});

// Files in /data and /models persist across sandbox restarts
await sandbox.execute("echo 'Hello' > /data/test.txt");

// Secrets are available as environment variables
await sandbox.execute("echo $API_KEY");

초기 파일(Initial files)

생성 중 샌드박스를 파일로 미리 채우세요:

const sandbox = await ModalSandbox.create({
  imageName: "python:3.12-slim",
  initialFiles: {
    "/app/main.py": 'print("Hello from Python!")',
    "/app/config.json": JSON.stringify({ name: "my-app" }, null, 2),
  },
});

const result = await sandbox.execute("python /app/main.py");

BaseSandbox가 노출하지 않는 고급 기능을 위해 기본 Modal SDK에 접근하세요:

const modalSandbox = await ModalSandbox.create();

const client = modalSandbox.client;     // ModalClient
const instance = modalSandbox.instance;  // Sandbox

// Direct SDK operations
const process = await instance.exec(["python", "-c", "print('Hello')"], {
  stdout: "pipe",
  stderr: "pipe",
});

기존 샌드박스에 재연결하기

// Reconnect by ID
const reconnected = await ModalSandbox.fromId(sandboxId);

// Reconnect by name
const reconnected2 = await ModalSandbox.fromName("my-app", "my-sandbox");

팩토리 함수(Factory functions)

import { createModalSandboxFactory, createModalSandboxFactoryFromSandbox } from "@langchain/modal";

// Create new sandbox per invocation
const factory = createModalSandboxFactory({ imageName: "python:3.12-slim" });

// Or reuse an existing sandbox across invocations
const sandbox = await ModalSandbox.create();
const reuseFactory = createModalSandboxFactoryFromSandbox(sandbox);

오류 처리(Error handling)

import { ModalSandboxError } from "@langchain/modal";

try {
  await sandbox.execute("some command");
} catch (error) {
  if (error instanceof ModalSandboxError) {
    switch (error.code) {
      case "NOT_INITIALIZED":
        await sandbox.initialize();
        break;
      case "COMMAND_TIMEOUT":
        console.error("Command took too long");
        break;
      case "AUTHENTICATION_FAILED":
        console.error("Check your Modal token credentials");
        break;
    }
  }
}

오류 코드(Error codes)

코드(Code) 설명(Description)
NOT_INITIALIZED 샌드박스가 초기화되지 않음 - initialize() 호출
ALREADY_INITIALIZED 두 번 초기화할 수 없음
AUTHENTICATION_FAILED 유효하지 않거나 누락된 Modal 토큰
SANDBOX_CREATION_FAILED 샌드박스 생성 실패
SANDBOX_NOT_FOUND 샌드박스 ID/이름을 찾을 수 없거나 만료됨
COMMAND_TIMEOUT 명령 실행 타임아웃
COMMAND_FAILED 명령 실행 실패
FILE_OPERATION_FAILED 파일 읽기/쓰기 실패
RESOURCE_LIMIT_EXCEEDED CPU, 메모리, 스토리지 제한 초과
VOLUME_ERROR 볼륨 작업 실패

환경 변수(Environment variables)

변수(Variable) 설명(Description)
MODAL_TOKEN_ID Modal API 토큰 ID
MODAL_TOKEN_SECRET Modal API 토큰 시크릿

더 알아보기 (Learn more)