코드 샌드박스 에이전트 — 모델이 짠 코드를 Docker에서 실행
실제로 실행 가능한 미니 프로젝트입니다. 받아서 Docker로 실행해 보세요.
2026년 6월 28일
코드 샌드박스 에이전트 — 모델이 짠 코드를 Docker에서 실행약 50줄짜리 LangGraph ReAct
에이전트로, run_python 도구 하나를 답니다. 실제 계산이 필요한 일 — "30번째
피보나치 수는?" — 을 주면 모델이 파이썬을 작성하고, 도구가 그 코드를 일회용 Docker
컨테이너 안에서 실행하며(네트워크 없음·CPU/메모리 제한·자동 삭제), 에이전트는 그
출력을 읽고 답합니다. 코드는 호스트에서 절대 돌지 않습니다. 모델은 LiteLLM으로
라우팅되므로 같은 코드가 Anthropic Claude·OpenAI·Google AI
Studio(Gemini)에서 그대로 동작합니다 — 코드가 아니라 .env의 MODEL만 바꾸면
됩니다.
설정
cd samples/docker_1
cp .env.sample .env
# .env 편집: MODEL과 해당 제공자 키 설정
MODEL이 제공자를 고릅니다:
| 제공자 | MODEL 예시 |
.env 키 |
|---|---|---|
| Anthropic Claude | claude-opus-4-8 |
ANTHROPIC_API_KEY |
| OpenAI | gpt-4o |
OPENAI_API_KEY |
| Google AI Studio | gemini/gemini-2.5-flash |
GEMINI_API_KEY |
.env는 gitignore 대상이라 .env.sample만 커밋됩니다. 샌드박스용 API 키는 없습니다 —
도구가 로컬 Docker이기 때문입니다.
Docker로 실행
Docker가 있어야 합니다. 샌드박스 이미지를 한 번 미리 받아 둡니다:
docker pull python:3.12-slim
에이전트 자체를 컨테이너로 띄웁니다 — 호스트 소켓을 마운트해 형제 샌드박스 컨테이너를 띄우는 Docker-out-of-Docker 방식입니다:
docker build -t aas-code-sandbox .
docker run --rm --env-file .env \
-v /var/run/docker.sock:/var/run/docker.sock \
aas-code-sandbox "30번째 피보나치 수는? 코드로 계산해줘"
소켓을 마운트하면 에이전트 안에서 부르는 docker run이 호스트의 Docker 데몬과
통신하므로, 각 샌드박스는 중첩이 아니라 호스트의 형제 컨테이너로 뜹니다. 이것이
Docker-out-of-Docker(DooD) 패턴으로, 이 저장소가 도는 데브컨테이너가 에이전트에게
다룰 수 있는 Docker를 내주는 방식과 같습니다.
Docker로 실행 (DooD를 쓰는 devcontainer에서)
중첩 Docker-outside-of-Docker에서는 포그라운드 docker run이 (초반 이후) 아무것도
출력하지 않을 수 있습니다 — detached로 실행하고 로그를 따라가세요. 데몬 로그엔 출력이
전부 남아 있습니다:
docker logs -f "$(docker run -d --env-file .env \
-v /var/run/docker.sock:/var/run/docker.sock \
aas-code-sandbox "30번째 피보나치 수는? 코드로 계산해줘")"
로컬에서 실행
에이전트가 호스트의 Docker를 직접 호출합니다:
pip install -r requirements.txt
python app.py "30번째 피보나치 수는? 코드로 계산해줘"
어떻게 동작하나
flowchart LR model[모델] -- 코드 작성 --> tool[run_python] tool --> box[docker run python:3.12-slim] box --> out[(표준출력 · 오류)] out --> model box -. 차단 .- host[호스트 · 네트워크]
run_python은 코드를 프로세스 안에서 exec하지 않고, docker run으로 새 컨테이너에
흘려보냅니다. 실제 격리는 플래그들이 합니다:
| 플래그 | 막는 것 |
|---|---|
--rm |
실행이 끝나면 컨테이너를 버림 |
--network none |
네트워크 차단 — 무엇도 밖으로 내보낼 수 없음 |
--memory 256m |
메모리 폭주가 호스트를 무너뜨리지 못함 |
--cpus 1 |
CPU 상한 — 무한 루프가 머신을 독점하지 못함 |
--pids-limit 128 |
포크 폭탄 방어 |
--user 65534:65534 |
root가 아닌 nobody로 실행 |
timeout=30 |
폭주 코드를 끊는 벽시계 차단기 |
샌드박싱 개념의 코드 실행 역할을 그대로 구현한 셈입니다 — 모델은 제안하고, 샌드박스는 가둡니다.
실행 결과
모델이 직접 코드를 짜고 답을 문장으로 정리하므로, 표현이 실행마다 조금씩 달라질 수 있습니다.
gemini/gemini-2.5-flash로 실행한 한 예입니다:
30번째 피보나치 수는 832040입니다.