لديك وكيل ذكاء اصطناعي، وتريد تشغيله في بيئة آمنة حيث يمكنه الوصول إلى الموارد المناسبة مثل نظام الملفات والقدرة على تنفيذ الأوامر (مثل أوامر shell) دون خطر “تدمير أي شيء”. إذًا، ما هي خياراتك؟
أفضل نهج هو إعطاء وكيل الذكاء الاصطناعي الخاص بك صندوق رمل (sandbox). داخل الصندوق الرملي، يمكن للوكيل التفاعل بأمان مع جهاز Linux، والعمل مع نظام الملفات، وتشغيل أوامر محددة مع تقييده من تنفيذ عمليات قد تكون ضارة.
مع هذا الإعداد، يمكننا بناء تطبيقات قوية. على سبيل المثال، وكيل برمجة يمكنه:
- إنشاء وتعديل ملفات الكود في نظام الملفات
- تشغيل أوامر مثل git أو python أو node
- التعاون مع المطورين من خلال تنفيذ واختبار الكود مباشرة في البيئة
في هذه المقالة، سنشرح كيفية بناء مثل هذا الوكيل البرمجي. سنستخدم نماذج Novita’s LLM مع استدعاء الدوال (function calling)، إلى جانب صندوق الرمل الخاص بـ Novita كبيئة آمنة. ولإكمال الأمر، سننشئ واجهة سهلة الاستخدام باستخدام Gradio، وننشرها على Hugging Face Spaces.
قبل اختيار نموذج لهذا الإعداد، راجع حالات استخدام نماذج اللغة الكبيرة لوكلاء البرمجة للحصول على أنماط عملية مثل الأسئلة والأجوبة على المستودعات، فرز الاختبارات، إعادة الهيكلة، وسير العمل الموجه بالأدوات.
لنبدأ!
صندوق الرمل للوكيل (Agent Sandbox)
صندوق الرمل للوكيل من Novita هو بيئة تشغيل مصممة خصيصًا لوكلاء الذكاء الاصطناعي. فهو يوفر إعدادًا سحابيًا آمنًا ومعزولًا يعمل مثل كمبيوتر افتراضي. داخل هذه البيئة، يمكن للوكلاء تنفيذ الكود المُنشأ بأمان دون المخاطرة بالنظام الأساسي.
الميزات الرئيسية لصندوق رمل وكيل Novita
- آمن: الصندوق الرملي معزول تمامًا، لذا يمكن للوكيل الوصول فقط إلى موارده الخاصة.
- بدء سريع: يتم تشغيل البيئات الجديدة في أقل من 200 مللي ثانية.
- جهاز افتراضي: نظرًا لأن الصندوق الرملي يتصرف مثل جهاز افتراضي، يمكن للوكلاء تشغيل الكود بأي لغة برمجة.
- إيقاف مؤقت واستئناف: يمكنك إيقاف الصندوق الرملي مؤقتًا في أي وقت واستئنافه لاحقًا.
- مهام الخلفية: يمكن للوكلاء تشغيل المهام في الخلفية واسترجاع النتائج بشكل غير متزامن.
تثبيت SDK
لاستخدام صندوق رمل Novita، ستحتاج إلى SDK الذي يدعم كل من Python و TypeScript/JavaScript. في هذا الشرح، سنستخدم Python SDK:
pip install novita-sandbox
بعد التثبيت، قم بتعيين مفتاح API الخاص بـ Novita كمتغير بيئة:
export NOVITA_API_KEY=your_api_key_here
اختبار الصندوق الرملي
بعد إعداد كل شيء، دعنا ننشئ صندوقًا رمليًا ونشغل بعض العمليات الأساسية:
from novita_sandbox.code_interpreter import Sandbox
sandbox = Sandbox.create()
files = sandbox.files.list("/")
for file in files:
print(file.name)
result = sandbox.commands.run('pwd')
print(result)
sandbox.kill()
يوضح هذا المثال كيفية:
- إنشاء مثيل صندوق رملي
- الوصول إلى نظام الملفات باستخدام كائن files
- تنفيذ الأوامر باستخدام طريقة commands.run
- تحرير الموارد باستخدام kill بمجرد الانتهاء
الآن بعد أن استكشفنا أساسيات الوصول إلى نظام الملفات وتنفيذ الأوامر، نحن مستعدون لبناء وكيلنا البرمجي الذ يستخدم قدرات الصندوق الرملي كهوات.
بناء وكيل برمجي
لبناء وكيلنا البرمجي، نحتاج إلى نموذج LLM يدعم استدعاء الدوال. توفر Novita عدة نماذج يمكنها فعل ذلك. لكي يتصرف وكيلنا كمساعد برمجة، يجب أن يكون لديه المجموعة الصحيحة من الدوال.
دعنا نفكر فيما يفعله المبرمج البشري عادة. هم عادة يكتبون ويقرؤون ويونفذون الكود. لذا يجب أن يكون وكيلنا قادرًا على:
- الكتاية إلى ملف
- القراءة من ملف
- تنفيذ الأوامر
- الكتاية إلى ملفات متعددة في وقت واحد
إعداد الوكيل
نظرًا لأن نماذج Novita متوافقة مع OpenAI، يمكننا استخدام OpenAI SDK للتفاعل معها. دعنا نثبته:
pip install openai
بعد التثبيت، قم بتعيين مفتاح API الخاص بـ Novita كمتغير بيئة تمامًا كما فعلنا سابقًا. بمجرد الانتهاء، يمكننا البدء في البرمجة بإضافة imports:
from openai import OpenAI
import os
import json
from novita_sandbox.code_interpreter import Sandbox
الآن، دعنا ننشئ مثال عميل OpenAI الخاص بنا:
client = OpenAI(
base_url="https://api.novita.ai/openai",
api_key=os.environ["NOVITA_API_KEY"],
)
هنا، نقوم بتوجيه العميل إلى عنوان URL الأساسي لـ Novita بدلاً من عنوان OpenAI واستخدام مفتاح API الخاص بنا من Novita للمصادقة.
بعد ذلك، سننشئ مثيل الصندوق الرملي الذي سيستخدمه وكيلنا:
sandbox = Sandbox.create(timeout=1200)
تحدد معلمة timeout المدة التي يجب أن يظل فيها الصندوق الرملي نشطًا. في هذه الحالة، قمنا بتعيينها على 10 دقائق.
تعريفات الدوال
الآن يمكننا تعريف الدوال التي سيستخدمها وكيلنا.
1. قراءة ملف
تأخذ هذه الدالة مسار ملف وتقرأ محتوياته باستخدام كائن files الخاص بالصندوق الرملي.
def read_file(path: str):
print(f"[DEBUG] read_file called with path: {path}")
try:
content = sandbox.files.read(path)
print(f"[DEBUG] read_file result: {content}")
return content # يعيد محتوى سلسلة
except Exception as e:
print(f"[DEBUG] read_file error: {e}")
return f"Error reading file: {e}"
2. كتابة ملف
تكتب هذه الدالة بيانات إلى مسار ملف محدد.
def write_file(path: str, data: str):
print(f"[DEBUG] write_file called with path: {path}")
try:
sandbox.files.write(path, data)
msg = f"File created successfully at {path}"
print(f"[DEBUG] {msg}")
return msg
except Exception as e:
print(f"[DEBUG] write_file error: {e}")
return f"Error writing file: {e}"
3. كتابة ملفات متعددة
تعمل هذه الدالة تمامًا مثل write_file ولكنها تتعامل مع ملفات متعددة في وق واح.
def write_files(files: list):
print(f"[DEBUG] write_files called with {len(files)} files")
try:
sandbox.files.write_files(files)
msg = f"{len(files)} file(s) created successfully"
print(f"[DEBUG] {msg}")
return msg
except Exception as e:
print(f"[DEBUG] write_files error: {e}")
return f"Error writing multiple files: {e}"
4. تشغيل الأوامر
تنفذ هذه الدالة أوامر shell داخل الصندوق الرملي وتعيد المخرجات القياسية.
def run_commands(command: str):
print(f"[DEBUG] run_commands called with commands: {command}") try:
result = sandbox.commands.run(command)
print(f"[DEBUG] run_commands result: {result}")
return result.stdout # يعيد كائن CommandResult
except Exception as e:
print(f"[DEBUG] run_commands error: {e}")
return f"Error running commands: {e}"
تسجيل الأدوات
الآن بعد أن لدينا جميع دالنا، سنقوم بتسجيلها كأدوات يمكن لـ LLM استدعاءها عن الحاجة. يتضمن كل تعريف أداة اسم الدالة ووصفها ومخطط المعلامات.
tools = [
{
"type": "function",
"function": {
"name": "read_file",
"description": "قراءة محتويات ملف داخل الصندوق الرملي",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "مسار الملف في الصندوق الرملي"}
}, "required": ["path"],
},
},
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "كتابة ملف واح داخل الصندوق الرملي",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "مسار الملف في الصندوق الرملي"},
"data": {"type": "string", "description": "المحتوى ال كتايته"},
}, "required": ["path", "data"],
}, },
},
{
"type": "function",
"function": {
"name": "write_files",
"description": "كتابة ملفات متعددة داخ الصندوق الرملي",
"parameters": {
"type": "object",
"properties": {
"files": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": {"type": "string"},
"data": {"type": "string"},
},
"required": ["path", "data"],
}, }
},
"required": ["files"],
}, },
},
{
"type": "function",
"function": {
"name": "run_commands",
"description": "تشغيل أمر shell واح داخ دليل العمل في الصندوق الرملي",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "أمر shell الذي سيتم تشغيله، مثل 'ls' أو 'python main.py'",
}
}, "required": ["command"],
},
},
}
]
مع تسجيل الأدوات، دعن ننتقل إلى إنشاء حلقة محادثة تسستغل وكيلنا وجميع الأدوات التي حددناها.
حلقة المحادثة
الآن سنقوم بإنشاء حلقة محادثة بساطة تسمح للمستخدم بالتفاعل مع وكيل البرمجة. ستحافظ الحلقة على قائمة من الرسائل وتتعامل مع استدعاءات الدوال كلما طلب الوكيل ذالك.
messages = []
print("💬 أدخل استفساراتك (اكتب 'exit' للخروج):")
while True:
user_input = input("أنت: ")
if user_input.lower() == "exit":
break
# إضافة رسالة المستخدم
messages.append({"role": "user", "content": user_input})
# إرسال إلى النموذج
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
)
assistant_msg = response.choices[0].message
messages.append(assistant_msg)
if assistant_msg.tool_calls:
print(f"[DEBUG] طلب المساعد {len(assistant_msg.tool_calls)} استدعاء أداة.")
for tool_call in assistant_msg.tool_calls:
fn_name = tool_call.function.name
fn_args = json.loads(tool_call.function.arguments)
print(f"[DEBUG] تم الكشف عن استدعاء أداة: {fn_name} مع الوسائط {fn_args}")
if fn_name == "read_file":
fn_result = read_file(**fn_args)
elif fn_name == "write_file":
fn_result = write_file(**fn_args)
elif fn_name == "write_files":
fn_result = write_files(**fn_args)
elif fn_name == "run_commands":
fn_result = run_commands(**fn_args)
else:
fn_result = f"خطأ: أدوة غي معروفة {fn_name}"
print(f"[DEBUG] طلب أداة غي معروفة: {fn_name}")
# إضافة النتيجة مرة أخرى
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"content": str(fn_result),
})
# الحصول على الإجابة النهائية للنموذج مع نتائج الأدوات
follow_up = client.chat.completions.creat(
model=model,
messages=messages,
)
final_answer = follow_up.choices[0].message
messages.append(final_answer)
print("المساعد:", final_answer.content)
else:
print("المساعد:", assistant_msg.content)
sandbox.kill()
print("[DEBUG] تم إنهاء الصندوق الرملي. 👋")
تحافظ حلقة المحادثة هذ على استمرار التفاعل، وتسمح للوكيل بإستدعاء أي من الأدوات المسجلة عند الحاجة، وتنظف الصندوق الرملي عنما يخروج المستخدم.
إنشاء واجهة م سستخدام Gradio
لدينا الآن وكيل برمجة كامل ال وظائف يمكنه المحادثة معنا، وللن التفاعل م خلال REPL ليس مثيرًا جدًا. دعنا نجع التجربة أكث جاذبية من خلال إعطاء وكيلنا واجهة Gradio بسطة.
إنشاء واجهة Gradio أمر بسط. سنستخدم gr.ChatInterface لإدارة تفاعلات المحادثة الخاصة بنا وربطها بالمنطق الذ بنيناه سابقًا. إلى جان ذالك، سنضمن واجة أوامر لتشغيل أوامر shell داخل الصندوق الرملي، بالإضافة إلى قائمة منسدلة تسمح لنا بتحديد النموذج الذي نريد استخدامه.
لتحديث الكود السابق لدعم Gradio، سنستبدل حلقة المحادثة والسطرين الأخيرين بما يلي:
# --- رسائل المحادثة المستمرة ---
messages = []
# --- محدد النموذج العالامي ---
def set_model(selected_model):
global model
model = selected_model
print(f"[DEBUG] تم التبديل إلى النموذج: {model}")
return f"✅ تم تبديل النموذج إلى **{model}**"
def chat_fn(user_message, history):
global messages, model
messages.append({"role": "user", "content": user_message})
# إرسال إلى النموذج
response = client.chat.completions.creat(
model=model,
messages=messages,
tools=tools,
)
assistant_msg = response.choices[0].message
messages.append(assistant_msg)
output_text = ""
if assistant_msg.tool_calls:
print(f"[DEBUG] طلب المساعد {len(assistant_msg.tool_calls)} استدعاء أداة.")
for tool_call in assistant_msg.tool_calls:
fn_name = tool_call.function.name
fn_args = json.loads(tool_call.function.arguments)
print(f"[DEBUG] تم الكشف عن استدعاء أداة: {fn_name} مع الوسائط {fn_args}")
if fn_name == "read_file":
fn_result = read_file(**fn_args)
elif fn_name == "write_file":
fn_result = write_file(**fn_args)
elif fn_name == "write_files":
fn_result = write_files(**fn_args)
elif fn_name == "run_commands":
fn_result = run_commands(**fn_args)
else:
fn_result = f"Error: Unknown tool {fn_name}"
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"content": str(fn_result),
})
follow_up = client.chat.completions.create(
model=model,
messages=messages,
)
final_answer = follow_up.choices[0].message
messages.append(final_answer)
output_text = final_answer.content
else:
output_text = assistant_msg.content
return output_text
# --- واجهة الأوامر ---
def execute_command(command):
if not command.strip():
return "⚠️ يرجى إدخال أمر."
print(f"[DEBUG] تنفيذ الأمر من الواجهة: {command}")
output = run_commands(command)
return f"```bash\ n{output}\n```" if output else "✅ تم تنفيذ الأمر (بدون مخرجات).ن"
# --- واجهة Gradio ---
with gr.Blocks(title="تطببيق صندوق رمل Novita") as demo:
gr.Markdown("## 🧠 وكيل صندوق رمل Novita"
gr.Markdown(
"هذا التطبيق هو **وكيل برمجة** مدعوم بالذكاء الاصطناعي يتيح لك المحادثة م مساعدين أذكياء مدعومين بـ **نماذج Novita AI LLM**. يمكن لهؤلاء الوكلاء كتابة وقراءة وتنفيذ الكود بأمان داخل **صندوق رمل Novita**، مما يوفر بيئة أمنا لتنفيذ الأوامر واختبار النصوص البرمجية وإدارة الملفات، كل ذالك من خلل واجهة محادثة بديهية مع اختيار النموذج وتنفيذ الأوامر مبنية داخليًا."
)
with gr.Row(equal_height=True):
# اليسار: واجهة المحادثة
with gr.Column(scale=2):
gr.Markdown("### 💬 واجهة المحادثة")
gr.ChatInterface(chat_fn)
# اليمين: واجهة الأوامر
with gr.Column(scale=1):
gr.Markdown("### 💻 واجهة الأوامر"
# محدد النموذج
model_selector = gr.Dropdown(
label="اختر النموذج",
choices=[
"meta-llama/llama-3.3-70b-instruct",
"deepseek/deepseek-v3.2-exp",
"qwen/qwen3-coder-30b-a3b-instruct",
"openai/gpt-oss-120b",
"moonshotai/kimi-k2-instruct",
],
value=model,
interactive=True,
)
model_status = gr.Markdown(f"✅ النموذج الحالي: **{model}**")
model_selector.change(set_model, inputs=model_selector, outputs=model_status)
command_input = gr.Textbox(
label="الأمر",
placeholder="مثلا: ls, python main.py",
lines=1,
)
with gr.Row():
run_btn = gr.Button("تشغيل", variant="primary", scale=0)
command_output = gr.Markdown("ستظهر مخرجات الأوامر هنا...")
run_btn.click(execute_command, inputs=command_input, outputs=command_output)
# --- التنظيف عن الخروج ---
atexit.register(lambda: (sandbox.kill(), print("[DEBUG] تم إنهاء الصندوق الرملي. 👋")))
if __name__ == "__main__":
demo.launch()
في هذه النسخة، تتعامل دالة chat_fn مع كل تبادل رسالة بين المستخدم والوكيل. تأخذ gr.ChatInterface هذه الدالة كمدخل وتدير تفاعلات واجهة المستخدم تلقائيًا.
عندما يبدأ تطبيق Gradio، يقوم بتشغيل وكيلك داخل المتصفح مما يمنح المستخدم واجهة محادثة نظيفة وتفاعلية. أخيرًا، نسجل روتين تنظيف باستخدام atexit لضمان إنهاء الصندوق الرملي بشكل صحيح عند توقف التطبيق.
الآن لدينا وكيل برمجة مدعوم بالذكاء الاصطناعي يعمل بأمان داخل صندوق رمل، مع واجهة محادثة Gradio ودية.
يمكنك العثور على الكود الكامل على GitHub.
اختبار وكيل البرمجة
لاستخدام الوكيل نحتاج إل تشغيل كود Gradio الخاص بنا كنص برمجي.
python gradio_chat.py
عند القيام بذالك، سيكون لدينا تطبيق Gradio يعمل على localhost. بهذا يمكننا إجراء محادثات مع وكيل البرمجة الخاص بنا وسيقوم الوكيل بتنفيذ جميع إجراءاتنا داخل الصندوق الرملي.
من تطبيق Gradio، كل ما نراه هو المحادثات من وكيلنا، وللكن إذا ذهبنا إل الطراف الخاص بنا يمكننا أيًا رؤية مخرجات التصحح حول الأمر الاذي استدعاه الوكيل لمساعدة طلب المستخدم.
حقيقة أن لدينا إمكانية الوصول إلى أداة ملف وأداة أمر تعني أنه لا يوجد تقرًا ما لا يمكنا برمجته، ولكن بدل من البرمجة مباشرة نحن نعطي تعليمات لوكيلنا وه يكتب وينفذ الكود لنا.
النشر على Hugging Face Spaces
لدينا حاليًا وكيل البرمجة الخاص بنا يعمل محليًا على جهااز الكمبيوتر. الأن، دعنا نجعله في متناول باقي العالام من خلال نشره على Hugging Face Spaces. يسمح لنا Hugging Face Spaces باستضافة كل من الكود والتطبيق في مكان واحد. لنبدأ.
إنشاء المساحة
اhead إلى Hugging Face وقم بإنشاء مساحة جديدة لوكيل البرمجة الخاص بك عن طرق إعطائه اسمًا فريدًا.

بعد ذلك، حتار SDK للمساحة وه في حالتنا هو Gradio. اختر القال ب الفارغ (Blank) نظرًا لأن لدينا كود التطبيق خاصتنا.

ثم، حدد العتاد. نظرًا لأن وكيلنا وصندوقنا الرملي مدعومان من قبل Novita، لسنا بحاجة إلى أي عتاد متخصص. خيار المعالج الأساسي (Basic CPU) كاف. بعد الانتهاء، انقر على إنشاء مساحة.

سينشئ Hugging Face المساحة مع ملف README.md وملف .gitignore.
هناك طرق متعددة لإضافة الكود، ولكن أبسطها هو النقر على المساهمة (Contribute) → إضافة ملف (Add file).

أنشئ ملف requirements.txt وضع فيه التبعيات التالية:
openai
novita-sandbox
إضافة متغيرات البيئة
قبل أن نتمكن من تشغيل تطبيقنا، نحتاج إلى تعيين NOVITA_API_KEY كمتغير بيئة.
لفعل ذلك، انتقل إلى إعدادات المساحة (Settings)، واتمرر إلى قس الم تغيرات والأسرار (Variables and secrets)، وأضف سرًا جددا باس NOVITA_API_KEY مع مفاح API الخاص بك كقيمة له.
إعداد التطبيق
مع تعيين متغير البئة، حان الوق لتشء تطبيقنا.
أنشئ ملفًا جددا باس app.py والصق كود وكيل Gradio الكامل فيه.

بع حفظ الملف، سيب Hugging Face تلقائيًا باء مساحتك.

بعد انتهاء عملة البناء، سيكون وكيل البرمجة خاصتك م توفره على Hugging Face Spaces.
يمكنك الآن الدردشة مع وكيلك من خلال واجة المحادثة التفاعلية.
بالإضافة إلى ذلك، يمكنك مراقبة السجلات لرؤية الأدوات التي استدعاها وكيلك أثناء التنفيذ.
وهذا كل شيء، لديك الآن وكيل برمجة كامل الوظائف يعمل في صندوق رملي آمن، ومزود بواجة Gradio، ونش بسلاسة على Huging Face Spaces.
الخاتمة
في هذ المقة، استكشفنا كيفة تسخير صندوق رمل Novita لبناء وكيل برمجة كامل الوظائف قادر على قراءة وإنشاء الملفات وتنفيذ الأوامر والعمل بأمان داخل بيئة آمنة.
ما بنيناه هنا هو مجرد بداية. يفتح الصندوق الرملي الباب أمام إمكانيات لا تعد ولا تحصى، بدءًا من إنشاء وكلاء تصور بيانات مدعومين بالذكاء الاصطناعي إلى تطوير وكلاء اسخدام كمبيوتر يمكنهم التفاعل مع الأنظمة بذكاء.
كل شيء تقريبًا ممكن عندما تجمع بين وكيل ومجموعة أدوات مخصصة مثل الصندوق الرملي.
