코드를 쓰는 에이전트는 그 코드를 안전하게 실행하고 결과를 알려 주는 무언가가 있어야 쓸모가 있습니다. 이 가이드는 그 루프를 처음부터 끝까지 만듭니다. 모델이 Python 스크립트를 쓰고, 샌드박스가 실행하고, 실패하면 오류가 모델에게 돌아갑니다. 그다음 같은 작업을 코드 한 줄 없이 MCP로 해 봅니다.
Python 3.8+, EQVPS 계정 토큰(계정 연결 참고), 그리고 모델의 API 키가 필요합니다.
1. 먼저 지출 한도 설정하기
에이전트는 샌드박스를 스스로 만드므로 시작 전에 상한을 정해 두세요. 실험이라면 하루 2달러, 한 달 20달러면 충분합니다.
curl -X PUT https://api.eqvps.com/api/v1/eqvps/sandboxes/budget \
-H "Authorization: Bearer $EQVPS_API_KEY" -H "Content-Type: application/json" \
-d '{"daily_usd": 2, "monthly_usd": 20}'
한도에 도달하면 새 샌드박스는 429 budget_exceeded를 받고, 실행 중인 임시 샌드박스는 삭제됩니다. 자세한 내용은 샌드박스 한도와 과금에 있습니다.
2. 라이브러리 두 개 설치
pip install eqvps anthropic
export EQVPS_API_KEY="your-eqvps-token"
export ANTHROPIC_API_KEY="your-model-key"
예제는 한 곳의 모델 제공자를 쓰지만, 그에 의존하는 부분은 없습니다. 모델과 대화하는 것은 ask() 함수뿐입니다.
3. 작성-실행-수정 루프
아래 내용을 agent.py로 저장합니다.
import re
import anthropic
from eqvps import Sandbox
TASK = "Count the prime numbers below 1,000,000 and print only the number."
client = anthropic.Anthropic()
def ask(messages):
msg = client.messages.create(model="claude-sonnet-5", max_tokens=2000, messages=messages)
return msg.content[0].text
def extract_code(text):
m = re.search(r"`{3}(?:python)?\n(.*?)`{3}", text, re.S)
return m.group(1) if m else text
messages = [{"role": "user", "content": "Write a Python 3 script for this task. "
"Reply with a single code block and nothing else.\n\nTask: " + TASK}]
with Sandbox.create(tariff="small", idle_timeout=120) as sb:
for attempt in range(1, 4):
reply = ask(messages)
r = sb.run(extract_code(reply), timeout=55)
print(f"attempt {attempt}: exit code {r.exit_code}")
if r.ok:
print(r.stdout.strip())
break
messages += [
{"role": "assistant", "content": reply},
{"role": "user", "content": f"The script failed with exit code {r.exit_code}.\n"
f"stderr:\n{r.stderr[-3000:]}\nFix it. Reply with a single code block."},
]
실행합니다.
python3 agent.py
일반적인 실행에서는 attempt 1: exit code 0에 이어 78498이 출력됩니다. 첫 스크립트가 실패하면 오류를 고친 두 번째 시도가 보입니다.
각 부분이 하는 일:
Sandbox.create(..., idle_timeout=120)는 약 1초 만에 microVM을 띄웁니다. 스크립트가 중간에 죽어도 샌드박스는 2분간 활동이 없으면 스스로 삭제됩니다.sb.run(code, timeout=55)는 코드를 실행하고 종료 코드, stdout, stderr를 반환합니다. 코드가 죽는 것은 예외가 아니라 정상적인 결과이므로 루프가 이를 모델에게 보여 줄 수 있습니다.r.stderr[-3000:]는 오류의 끝부분만 보냅니다. 큰 스크립트의 전체 traceback은 모델의 컨텍스트를 크게 낭비할 수 있습니다.- 시도는 최대 3번이라는 것은 의도된 제한입니다. 세 번 안에 스크립트를 고치지 못한 모델에게 필요한 것은 대개 네 번째 시도가 아니라 더 나은 작업 설명입니다.
4. 작업이 55초보다 오래 걸릴 때
동기 호출은 최대 55초입니다. 더 긴 작업은 백그라운드로 시작하고 기다리세요.
task = sb.run(code, background=True)
result = task.wait(timeout=1800)
wait가 타임아웃에 걸려도 작업은 계속 실행되며, sb.task(task_id)로 다시 이어서 다룰 수 있습니다.
5. 같은 작업을 MCP로, 코드 없이
Claude Desktop이나 Cursor 같은 MCP 클라이언트에서 EQVPS MCP 서버를 쓰고 있다면, 에이전트에게는 이미 샌드박스 도구가 있습니다. create_sandbox, run_code, exec_command, upload_file, download_file, kill_sandbox입니다. 프롬프트 하나면 됩니다.
작은 임시 샌드박스를 만들어 줘. 1,000,000 미만의 소수 개수를 세는 Python 스크립트를 써서 거기서 실행하고, 실패하면 고치고, 결과를 알려 준 다음 샌드박스를 삭제해 줘.
에이전트는 위 스크립트와 같은 호출을 합니다. 어떤 도구를 확인 없이 허용해도 되는지는 MCP 보호 장치에서 다룹니다.
든 비용
샌드박스는 1분보다 훨씬 짧게 존재했고 최소 60초로 과금되었습니다. small에서 0.00055달러입니다. 모델 호출이 샌드박스보다 더 비쌉니다. 새 계정의 1달러 체험 크레딧이면 이런 실행을 약 1,800번 할 수 있습니다.
다음으로 볼 것
- SDK를 단계별로: 5분 만에 시작하는 샌드박스 Python SDK 또는 TypeScript 버전
- 모든 메서드와 오류: SDK 레퍼런스
- 요금제와 체험 크레딧: 샌드박스 페이지
댓글
아직 댓글이 없습니다. 첫 번째가 되세요.