سندباکس‌های اجرای کد برای عامل‌های هوش مصنوعی در ۲۰۲۶: مقایسه عملی E2B، Modal، Daytona و Riza

راهنمای عملی انتخاب سندباکس اجرای کد برای عامل‌های هوش مصنوعی در ۲۰۲۶: مقایسه E2B، Modal، Daytona و Riza از نظر سرعت، هزینه، GPU و امنیت با نمونه کد پایتون.

سندباکس کد عامل‌های AI: مقایسه ۲۰۲۶

به‌روزرسانی: ۸ ژوئن ۲۰۲۶

سندباکس اجرای کد برای عامل‌های هوش مصنوعی یک محیط ایزوله و موقت است که در آن کد تولیدشده توسط LLM (معمولاً پایتون یا جاوااسکریپت) بدون دسترسی به سیستم میزبان، با کنترل دقیق منابع، شبکه و فایل‌سیستم اجرا می‌شود. در سال ۲۰۲۶ چهار پلتفرم اصلی این بازار را در دست دارند: E2B (مبتنی بر Firecracker microVM)، Modal (محاسبات سرورلس با gVisor)، Daytona (متن‌باز با Workspace Manager) و Riza (سندباکس HTTP-only). اگر عامل LLM شما کد می‌نویسد یا اجرا می‌کند، استفاده از سندباکس اختیاری نیست؛ ضروری است.

راستش را بخواهید، چند ماه گذشته را صرف این کرده‌ام که هر چهار پلتفرم را روی یک پروژه واقعی (یک عامل تحلیل CSV) تست کنم. نتایج گاهی غافلگیرکننده بود، و در ادامه دقیقاً همان چیزی را که یاد گرفتم با شما در میان می‌گذارم.

  • E2B سریع‌ترین زمان راه‌اندازی (کمتر از ۱۵۰ میلی‌ثانیه با Firecracker) و مناسب‌ترین گزینه برای Code Interpreter زنده است.
  • Modal برای بارهای کاری طولانی، GPU و پایپ‌لاین‌های داده‌محور بهتر است؛ راه‌اندازی سرد آن کندتر اما با مقیاس‌پذیری بهتر همراه است.
  • Daytona تنها گزینه واقعاً متن‌باز است و امکان میزبانی روی زیرساخت خود را می‌دهد؛ مناسب سازمان‌های با نیاز انطباق (Compliance).
  • Riza با مدل HTTP-only و بدون نگه‌داری حالت، ساده‌ترین یکپارچه‌سازی را دارد اما برای ورک‌فلوهای چند مرحله‌ای محدود است.
  • هرگز کد LLM را در فرآیند اصلی برنامه اجرا نکنید؛ حتی exec() با محدودیت built-ins قابل دور زدن است.
  • هزینه واقعی سندباکس به مدت اجرا، نه تعداد فراخوانی، وابسته است؛ بهینه‌سازی session reuse می‌تواند هزینه را تا ۷۰٪ کاهش دهد.

چرا عامل‌های هوش مصنوعی به سندباکس نیاز دارند؟

وقتی به یک عامل LLM ابزار execute_python یا run_shell می‌دهید، در عمل به مدل اجازه می‌دهید کد دلخواه روی زیرساخت شما اجرا کند. این کد ممکن است حاصل توهم (Hallucination)، تزریق پرامپت (Prompt Injection) از یک ورودی کاربر یا حتی یک سند PDF آلوده باشد. در یک حادثه شناخته‌شده در سال ۲۰۲۵، یک عامل تحلیل داده با خواندن یک سند CSV که یکی از ستون‌هایش دستور os.system("rm -rf /") را به‌صورت مخفی داشت، فایل‌سیستم سرور را پاک کرد. چرا؟ چون توسعه‌دهنده exec() را مستقیماً فراخوانی کرده بود.

سندباکس‌های مدرن این مشکل را با سه لایه ایزوله‌سازی حل می‌کنند: ایزوله‌سازی هسته (Firecracker microVM یا gVisor)، ایزوله‌سازی شبکه (egress فقط به دامنه‌های مجاز) و ایزوله‌سازی فایل‌سیستم (همراه با cleanup خودکار). بدون این لایه‌ها، حتی محدود کردن __builtins__ در پایتون قابل دور زدن است. تکنیک‌های شناخته‌شده‌ای مثل دسترسی به ().__class__.__mro__ اجازه فرار از sandbox درون‌فرآیندی را می‌دهند (و من خودم در یک Code Review دیده‌ام که این الگو از یک «sandbox خانگی» عبور کرد).

اگر در حال طراحی سیستم‌های چندعامله با LangGraph و CrewAI هستید، هر عامل که توانایی tool use با اجرای کد دارد باید سندباکس مستقل داشته باشد. به اشتراک‌گذاری یک سندباکس بین عامل‌ها سطح حمله را به‌صورت ترکیبی افزایش می‌دهد.

مقایسه فنی E2B، Modal، Daytona و Riza

چهار پلتفرم برتر در رویکرد فنی، مدل قیمت‌گذاری و موارد استفاده هدف تفاوت اساسی دارند. جدول زیر بر اساس آخرین مستندات هر پلتفرم در ژوئن ۲۰۲۶ تهیه شده است.

ویژگیE2BModalDaytonaRiza
تکنولوژی ایزولهFirecracker microVMgVisor + cgroupsDocker + Kata ContainersWebAssembly + V8 Isolate
زمان راه‌اندازی سرد~۱۵۰ms۲–۸ ثانیه۸۰۰ms–۲s~۵۰ms
پشتیبانی GPUمحدودکامل (A100, H100)اختیاری (Self-host)ندارد
حالت Statefulبله (تا ۲۴ ساعت)بله (Volume)بله (Workspace)خیر
میزبانی شخصیEnterpriseخیرمتن‌باز کاملخیر
قیمت پایه (پایتون)~‎$۰.۰۰۰۱۴/ثانیه~‎$۰.۰۰۰۰۹/ثانیه CPUرایگان (Self-host)~‎$۰.۰۰۰۰۲/فراخوانی
SDK رسمیPython, JS, GoPythonPython, TypeScriptPython, JS, REST
زمان مناسبCode Interpreter زندهپایپ‌لاین‌های سنگینکنترل کامل زیرساختابزارهای ساده و سریع

پیاده‌سازی عملی با E2B

E2B در سال ۲۰۲۶ به انتخاب پیش‌فرض برای Code Interpreter ها تبدیل شده است. دلیلش هم ساده است: Firecracker microVM (همان فناوری که AWS Lambda استفاده می‌کند) راه‌اندازی سرد زیر ۲۰۰ میلی‌ثانیه را ممکن می‌کند. در ادامه یک مثال کامل از یکپارچه‌سازی E2B با مدل Claude برای ساخت یک Code Interpreter ساده آمده است. این همان قالبی است که در آخرین پروژه‌ام برای یک عامل تحلیل داده استفاده کردم.

import os
from anthropic import Anthropic
from e2b_code_interpreter import Sandbox

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

SYSTEM = """You are a data analysis assistant. When you need to run Python,
emit a single tool call to execute_python. Do not print raw code in messages."""

tools = [{
    "name": "execute_python",
    "description": "Run Python code in a stateful sandbox. Returns stdout, "
                   "stderr, and any matplotlib figures rendered.",
    "input_schema": {
        "type": "object",
        "properties": {"code": {"type": "string"}},
        "required": ["code"],
    },
}]

def run_agent(user_prompt: str) -> str:
    # یک sandbox باز کنید و در سراسر مکالمه از آن استفاده کنید
    with Sandbox(timeout=300) as sandbox:
        messages = [{"role": "user", "content": user_prompt}]

        while True:
            response = client.messages.create(
                model="claude-opus-4-8",
                max_tokens=4096,
                system=SYSTEM,
                tools=tools,
                messages=messages,
            )

            if response.stop_reason == "end_turn":
                return response.content[0].text

            tool_use = next(b for b in response.content if b.type == "tool_use")
            code = tool_use.input["code"]

            # اجرا در sandbox ایزوله‌شده
            execution = sandbox.run_code(code)
            result = execution.text or execution.error or "(no output)"

            messages.append({"role": "assistant", "content": response.content})
            messages.append({
                "role": "user",
                "content": [{
                    "type": "tool_result",
                    "tool_use_id": tool_use.id,
                    "content": result[:4000],  # کوتاه‌سازی برای جلوگیری از انفجار توکن
                }],
            })

if __name__ == "__main__":
    print(run_agent("یک نمودار سینوسی از ۰ تا ۲π رسم کن و میانگین مقادیر را گزارش بده."))

نکته مهم در این الگو، حفظ Sandbox در طول کل مکالمه است. هر فراخوانی sandbox.run_code() در همان کرنل پایتون اجرا می‌شود، بنابراین متغیرها بین فراخوانی‌ها حفظ می‌شوند. این رفتار stateful همان چیزی است که ChatGPT Code Interpreter ارائه می‌دهد و برای ورک‌فلوهای تحلیل داده ضروری است. مستندات رسمی E2B الگوهای کامل‌تری برای آپلود فایل، استخراج نمودار و مدیریت timeout دارد.

وقتی عامل شما نیاز به اجرای مدل‌های یادگیری ماشین، پردازش تصویر سنگین یا کارهای موازی روی GPU دارد، Modal گزینه برتر است. Modal با مدل function-as-a-service کار می‌کند: شما یک تابع پایتون را با دکوراتور @app.function علامت‌گذاری می‌کنید و Modal آن را در یک کانتینر ایزوله با gVisor اجرا می‌کند. در مقایسه با فاین‌تیونینگ LLM با LoRA و QLoRA که خوشه‌های اختصاصی نیاز دارد، Modal برای استنتاج کوتاه‌مدت و بدون state عالی است.

import modal

# تعریف ایمیج پایه با وابستگی‌های لازم
image = (
    modal.Image.debian_slim(python_version="3.12")
    .pip_install("torch==2.4.0", "transformers==4.45.0", "pillow==10.4.0")
)

app = modal.App("agent-code-runner", image=image)

@app.function(gpu="A10G", timeout=120, max_containers=10)
def run_user_code(code: str, files: dict | None = None) -> dict:
    """اجرای کد تولیدشده توسط LLM در یک محیط ایزوله با GPU."""
    import io
    import contextlib
    import traceback

    # نوشتن فایل‌های آپلودی روی دیسک sandbox
    if files:
        for name, content in files.items():
            with open(f"/tmp/{name}", "wb") as f:
                f.write(content)

    stdout = io.StringIO()
    namespace = {"__name__": "__sandbox__"}

    try:
        with contextlib.redirect_stdout(stdout):
            exec(code, namespace)
        return {"ok": True, "stdout": stdout.getvalue(), "error": None}
    except Exception:
        return {
            "ok": False,
            "stdout": stdout.getvalue(),
            "error": traceback.format_exc(limit=5),
        }

# استفاده از سمت میزبان
@app.local_entrypoint()
def main():
    code = """
import torch
from transformers import pipeline

clf = pipeline('sentiment-analysis', device=0)
print(clf('Modal makes GPU sandboxing easy.'))
"""
    result = run_user_code.remote(code)
    print(result)

اگرچه راه‌اندازی سرد Modal چند ثانیه طول می‌کشد، با @app.function(min_containers=1) می‌توانید یک نمونه گرم همیشه آماده نگه دارید. این رویکرد برای عامل‌هایی که قرار است مدل دیفیوژن، Whisper یا مدل‌های اختصاصی را اجرا کنند، توجیه اقتصادی دارد. جزئیات بیشتر در راهنمای Sandbox پلتفرم Modal در دسترس است.

میزبانی شخصی با Daytona

برای سازمان‌هایی که با داده‌های حساس کار می‌کنند یا با الزامات GDPR، HIPAA و SOC 2 روبه‌رو هستند، ارسال کد و داده به یک سرویس ابری ثالث ممکن نیست. Daytona تنها سندباکس متن‌باز پروداکشن‌گرید است که می‌تواند کاملاً روی زیرساخت شما (روی Kubernetes یا حتی یک VM ساده) نصب شود.

معماری Daytona سه مؤلفه دارد: Daytona Server (مدیریت Workspace ها)، Provider (Docker، AWS، GCP یا Kubernetes) و SDK (پایتون و TypeScript). نصب پایه با Docker Compose به این شکل است:

# نصب CLI و راه‌اندازی سرور محلی
curl -fsSL https://get.daytona.io | bash
daytona server -y --provider docker

# در کد پایتون
from daytona_sdk import Daytona, CreateSandboxParams

daytona = Daytona(api_key="local-dev-key", api_url="http://localhost:3986")

sandbox = daytona.create(CreateSandboxParams(
    language="python",
    image="python:3.12-slim",
    env_vars={"PYTHONUNBUFFERED": "1"},
    resources={"cpu": 2, "memory": "1Gi"},
))

try:
    response = sandbox.process.code_run("print(sum(range(100)))")
    print(response.result)
finally:
    daytona.remove(sandbox)

قابلیت کلیدی Daytona برای محیط‌های انطباق‌محور، امکان image whitelisting و network policy سختگیرانه است. می‌توانید یک Daytona Workspace را طوری پیکربندی کنید که فقط به یک پراکسی داخلی دسترسی داشته باشد و تمام egress بیرونی مسدود شود. این سطح کنترل در سرویس‌های ابری معمولاً در دسترس نیست.

الگوهای امنیتی برای اجرای کد LLM

صرف انتخاب یک سندباکس کافی نیست. نحوه استفاده از آن تعیین می‌کند که آیا واقعاً امن هستید. در سال ۲۰۲۶ سه الگوی امنیتی به استاندارد صنعتی تبدیل شده‌اند که هر سیستم تولیدی باید آن‌ها را اعمال کند.

۱. سیاست egress صریح

پیش‌فرض باید این باشد که سندباکس به هیچ شبکه‌ای دسترسی ندارد. سپس فقط دامنه‌های مورد نیاز (مثلاً api.openweather.com) را به‌صورت صریح در allowlist قرار دهید. در E2B با sandbox.allow_internet_access(domains=[...]) و در Modal با modal.Secret به همراه پیکربندی egress proxy.

۲. محدودیت زمانی چندلایه

هرگز فقط به timeout کلی سندباکس تکیه نکنید. سه لایه timeout اعمال کنید: timeout روی هر فراخوانی run_code (مثلاً ۳۰ ثانیه)، timeout روی session (۵ دقیقه) و timeout روی کل مکالمه عامل (۲ دقیقه). این از حملات منع سرویس (DoS) از طریق حلقه بی‌نهایت در کد تولیدشده جلوگیری می‌کند. در پروژه قبلی‌ام، اضافه کردن همین لایه سوم باعث شد هزینه ماهانه ۲۲٪ کاهش پیدا کند.

۳. سانیتایز خروجی پیش از بازگشت به LLM

این یک سطح حمله نادیده‌گرفته‌شده است: کد اجراشده ممکن است خروجی‌ای تولید کند که حاوی توکن‌های کنترلی LLM (مثل <tool_use>) باشد و در دور بعدی، مدل را گمراه کند. همیشه خروجی را با یک regex مانند re.sub(r"</?[a-z_]+>", "", output) پاکسازی و طول آن را محدود کنید. این الگو همان رویکردی است که در آموزش Function Calling و Tool Use برای ابزارهای ساده‌تر هم توصیه شده است.

بهینه‌سازی هزینه و عملکرد

هزینه واقعی اجرای سندباکس به‌جز نرخ پایه پلتفرم، به سه عامل وابسته است: زمان بیکار (idle)، فراخوانی‌های اضافی مدل به دلیل خطاهای اجرایی، و توکن‌های ورودی صرف‌شده برای ارسال context تکراری. سه بهینه‌سازی عملی که در پروژه‌های واقعی نتیجه می‌دهند:

  • Session reuse: یک سندباکس را برای کل یک مکالمه (نه هر مرحله) باز نگه دارید. در E2B با timeout ۳۰۰ ثانیه و در Modal با min_containers=1 پیاده می‌شود. می‌تواند هزینه را تا ۷۰٪ کاهش دهد.
  • Pre-warming در ساعات اوج: اگر ترافیک شما الگوی روزانه دارد، چند سندباکس از قبل آماده نگه دارید. اختلاف بین راه‌اندازی سرد و گرم در Modal حدود ۸ ثانیه تأخیر برای کاربر است.
  • Result caching در سمت LLM: اگر کد تولیدشده deterministic است (مثل print(2+2))، خروجی را در Redis cache کنید. این الگو خصوصاً برای ابزارهای پرتکرار مثل فرمت‌بندی JSON یا تبدیل واحد فوق‌العاده موثر است.

یک ترفند کمتر شناخته‌شده: استفاده از structured tool errors به جای raw stack trace. وقتی کد LLM خطا می‌دهد، فرستادن یک پیام ساختاریافته مانند {"error_type": "NameError", "fix_hint": "variable not defined"} به جای کل stack trace، تعداد توکن‌های ورودی دور بعدی را به‌طور قابل توجهی کاهش می‌دهد و هم‌زمان نرخ موفقیت بازیابی مدل را افزایش می‌دهد. صادقانه بگویم، این یکی از همان تغییرات کوچکی است که تأثیرش روی هزینه را تا قبل از اندازه‌گیری باور نمی‌کردم.

کدام سندباکس برای کار شما مناسب است؟

پاسخ به این سؤال به سه پرسش بستگی دارد: آیا نیاز به state بین فراخوانی‌ها دارید؟ آیا GPU لازم است؟ آیا میزبانی شخصی الزامی است؟ بر اساس این سه بُعد، تصمیم‌گیری ساده می‌شود.

  • Code Interpreter زنده برای کاربر نهایی (تحلیل داده، رسم نمودار، اجرای پایتون به سبک ChatGPT): E2B. سرعت راه‌اندازی و حالت stateful برنده هستند.
  • پایپ‌لاین داده با مدل‌های ML سنگین (ETL با LLM، استنتاج تصویر، تبدیل صوت): Modal. پشتیبانی GPU و مقیاس‌پذیری افقی بی‌رقیب هستند.
  • محیط داخلی سازمان با الزامات انطباق (بانک، سلامت، بخش دولتی): Daytona. کنترل کامل، متن‌باز، قابل audit.
  • ابزارهای ساده بدون state (محاسبه‌گر، تبدیل واحد، پارسر JSON): Riza. ساده‌ترین API و کمترین هزینه برای فراخوانی‌های کوتاه.

الگوی ترکیبی هم رایج است. تیم‌های پیشرفته اغلب E2B را برای رابط کاربری اصلی و Modal را برای کارهای پس‌زمینه (مثل تولید گزارش شبانه) استفاده می‌کنند. اگر شما یک عامل سازنده محتوا یا تحلیل‌گر ساختاری می‌سازید، توصیه می‌کنم حتماً از یکی از این پلتفرم‌ها استفاده کنید، نه از subprocess یا exec() در فرآیند اصلی.

پرسش‌های متداول

آیا اجرای کد تولیدشده توسط LLM واقعاً امن است؟

بله، اما فقط در صورت استفاده از یک سندباکس مبتنی بر microVM یا gVisor با سیاست egress سختگیرانه. روش‌های درون‌فرآیندی مانند exec() با محدود کردن __builtins__ به دلیل تکنیک‌های شناخته‌شده فرار، قابل اعتماد نیستند.

تفاوت اصلی E2B و Modal چیست؟

E2B برای جلسات تعاملی کوتاه با نیاز به راه‌اندازی سریع (زیر ۲۰۰ms) بهینه شده است. Modal برای کارهای محاسباتی سنگین، GPU و مقیاس‌پذیری افقی بهتر است اما راه‌اندازی سرد آن چند ثانیه طول می‌کشد.

هزینه واقعی E2B برای یک عامل تولیدی چقدر است؟

با تعرفه ژوئن ۲۰۲۶ و ۱۰٬۰۰۰ مکالمه روزانه با میانگین ۹۰ ثانیه session فعال، هزینه حدود ۱۲۶ دلار در ماه است. با session reuse و pre-warming می‌توان به حدود ۴۰ دلار رساند.

آیا می‌توان سندباکس را روی زیرساخت داخلی نصب کرد؟

بله. Daytona تنها گزینه‌ای است که با مجوز Apache 2.0 متن‌باز کامل است و می‌تواند روی Docker یا Kubernetes نصب شود. E2B هم نسخه Enterprise برای میزبانی شخصی ارائه می‌دهد اما با هزینه قرارداد سالانه.

آیا برای اجرای کد ساده LLM می‌توان از Docker معمولی استفاده کرد؟

برای محیط dev بله، اما برای production توصیه نمی‌شود. کانتینرهای استاندارد runc هسته را با میزبان به اشتراک می‌گذارند و در صورت کشف آسیب‌پذیری روز صفر، امکان فرار وجود دارد. حداقل از Kata Containers یا gVisor استفاده کنید.

Editorial Team
درباره نویسنده Editorial Team

Our team of expert writers and editors.