Sie haben einen KI-Agenten und möchten, dass er in einer sicheren Umgebung läuft, in der er Zugriff auf die richtigen Ressourcen wie ein Dateisystem und die Möglichkeit hat, Befehle (z. B. Shell-Befehle) auszuführen, ohne Gefahr zu laufen, „etwas zu zerstören“. Welche Optionen haben Sie also?
Der beste Ansatz ist, Ihrem KI-Agenten eine Sandbox zur Verfügung zu stellen. Innerhalb einer Sandbox kann der Agent sicher mit einem Linux-Rechner interagieren, mit dem Dateisystem arbeiten und bestimmte Befehle ausführen, während er von der Ausführung potenziell schädlicher Operationen ausgeschlossen ist.
Mit dieser Einrichtung können wir leistungsstarke Anwendungen erstellen. Zum Beispiel einen Coding-Agenten, der:
- Code-Dateien im Dateisystem erstellen und bearbeiten
- Befehle wie git, python oder node ausführen
- Mit Entwicklern zusammenarbeiten, indem Code direkt in der Umgebung ausgeführt und getestet wird
In diesem Artikel führen wir Sie durch die Erstellung eines solchen Coding-Agenten. Wir verwenden Novitas LLMs mit Funktionsaufrufen, kombiniert mit der Novita Agent Sandbox als unserer sicheren Umgebung. Als Krönung erstellen wir eine benutzerfreundliche Oberfläche mit Gradio und stellen sie auf Hugging Face Spaces bereit.
Legen wir los!
Agent Sandbox
Novitas Agent Sandbox ist eine speziell für KI-Agenten entwickelte Laufzeitumgebung. Sie bietet eine sichere und isolierte Cloud-Einrichtung, die wie ein virtueller Computer funktioniert. Innerhalb dieser Umgebung können Agenten generierten Code sicher ausführen, ohne das zugrundeliegende System zu gefährden.
Hauptmerkmale der Novita Agent Sandbox
- Sicher: Die Sandbox ist vollständig isoliert, sodass der Agent nur Zugriff auf seine eigenen Ressourcen hat.
- Schneller Start: Neue Umgebungen werden in weniger als 200 ms hochgefahren.
- Virtuelle Maschine: Da sich die Sandbox wie eine VM verhält, können Agenten Code in jeder Programmiersprache ausführen.
- Pausieren und Fortsetzen: Sie können eine Sandbox jederzeit pausieren und später fortsetzen.
- Hintergrundaufgaben: Agenten können Aufgaben im Hintergrund ausführen und Ergebnisse asynchron abrufen.
Installation des SDKs
Um die Novita Sandbox zu verwenden, benötigen Sie das SDK, das sowohl Python als auch TypeScript/JavaScript unterstützt. Für diese Anleitung verwenden wir das Python-SDK:
pip install novita-sandbox
Nach der Installation setzen Sie Ihren Novita API-Schlüssel als Umgebungsvariable:
export NOVITA\_API\_KEY=your\_api\_key\_here
Testen der Sandbox
Wenn alles eingerichtet ist, erstellen wir eine Sandbox und führen einige grundlegende Operationen durch:
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()
Dieses Beispiel zeigt, wie man:
- Eine Sandbox-Instanz erstellt
- Auf das Dateisystem mit dem
files-Objekt zugreift - Befehle mit der Methode
commands.runausführt - Ressourcen mit
killfreigibt, sobald man fertig ist
Nachdem wir die Grundlagen des Zugriffs auf das Dateisystem und der Ausführung von Befehlen erkundet haben, sind wir bereit, unseren Coding-Agenten zu erstellen, der diese Sandbox-Funktionen als Tools nutzt.
Erstellen eines Coding-Agenten
Um unseren Coding-Agenten zu erstellen, benötigen wir ein LLM, das Funktionsaufrufe unterstützt. Novita bietet mehrere Modelle, die dies können. Damit sich unser Agent wie ein Coding-Assistent verhält, benötigt er den richtigen Satz an Funktionen.
Denken wir darüber nach, was ein menschlicher Programmierer tut. Er schreibt, liest und führt normalerweise Code aus. Unser Agent sollte also in der Lage sein,:
- In eine Datei zu schreiben
- Aus einer Datei zu lesen
- Befehle auszuführen
- Gleichzeitig in mehrere Dateien zu schreiben
Einrichtung des Agenten
Da Novitas Modelle mit OpenAI kompatibel sind, können wir das OpenAI-SDK verwenden, um mit ihnen zu interagieren. Lassen Sie es uns installieren:
pip install openai
Nach der Installation setzen Sie Ihren Novita API-Schlüssel als Umgebungsvariable, genau wie wir es zuvor getan haben. Sobald das erledigt ist, können wir mit dem Codieren beginnen, indem wir unsere Importe hinzufügen:
from openai import OpenAI
import os
import json
from novita_sandbox.code_interpreter import Sandbox
Jetzt erstellen wir unsere OpenAI-Client-Instanz:
client = OpenAI(
base_url="https://api.novita.ai/openai",
api_key=os.environ["NOVITA_API_KEY"],
)
Hier verweisen wir den Client auf die Basis-URL von Novita statt auf die von OpenAI und verwenden unseren Novita API-Schlüssel zur Authentifizierung.
Als Nächstes erstellen wir die Sandbox-Instanz, die unser Agent verwenden wird:
sandbox = Sandbox.create(timeout=1200)
Der Parameter timeout gibt an, wie lange die Sandbox aktiv bleiben soll. In diesem Fall haben wir ihn auf 10 Minuten eingestellt.
Funktionsdefinitionen
Jetzt können wir die Funktionen definieren, die unser Agent verwenden wird.
1. Datei lesen
Diese Funktion nimmt einen Dateipfad entgegen und liest deren Inhalt mit dem files-Objekt der Sandbox.
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 # returns string content
except Exception as e:
print(f"[DEBUG] read_file error: {e}")
return f"Error reading file: {e}"
2. Datei schreiben
Diese Funktion schreibt Daten in einen angegebenen Dateipfad.
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. Mehrere Dateien schreiben
Diese Funktion funktioniert genauso wie write_file, verarbeitet aber mehrere Dateien auf einmal.
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. Befehle ausführen
Diese Funktion führt Shell-Befehle innerhalb der Sandbox aus und gibt die Standardausgabe zurück.
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 # returns CommandResult object
except Exception as e:
print(f"[DEBUG] run_commands error: {e}")
return f"Error running commands: {e}"
Tool-Registrierung
Jetzt, da wir alle unsere Funktionen haben, registrieren wir sie als Tools, die das LLM bei Bedarf aufrufen kann. Jede Tool-Definition enthält den Funktionsnamen, die Beschreibung und das Parameter-Schema.
tools = [
{
"type": "function",
"function": {
"name": "read_file",
"description": "Read contents of a file inside the sandbox",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path in the sandbox"}
},
"required": ["path"],
},
},
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "Write a single file inside the sandbox",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path in the sandbox"},
"data": {"type": "string", "description": "Content to write"},
},
"required": ["path", "data"],
},
},
},
{
"type": "function",
"function": {
"name": "write_files",
"description": "Write multiple files inside the sandbox",
"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": "Run a single shell command inside the sandbox working directory",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The shell command to run, e.g. 'ls' or 'python main.py'",
}
},
"required": ["command"],
},
},
}
]
Nachdem die Tools registriert sind, gehen wir zur Erstellung einer Chat-Schleife über, die unseren Agenten und alle von uns definierten Tools nutzt.
Chat-Schleife
Jetzt erstellen wir eine einfache Chat-Schleife, die es dem Benutzer ermöglicht, mit dem Coding-Agenten zu interagieren. Die Schleife verwaltet eine Liste von Nachrichten und verarbeitet Funktionsaufrufe, wann immer der Agent einen anfordert.
messages = []
print("💬 Enter your queries (type 'exit' to quit):")
while True:
user_input = input("You: ")
if user_input.lower() == "exit":
break
# Append user message
messages.append({"role": "user", "content": user_input})
# Send to model
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] Assistant requested {len(assistant_msg.tool_calls)} tool call(s).")
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] Tool call detected: {fn_name} with args {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}"
print(f"[DEBUG] Unknown tool requested: {fn_name}")
# Append result back
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"content": str(fn_result),
})
# Get model's final answer with tool results
follow_up = client.chat.completions.create(
model=model,
messages=messages,
)
final_answer = follow_up.choices[0].message
messages.append(final_answer)
print("Assistant:", final_answer.content)
else:
print("Assistant:", assistant_msg.content)
sandbox.kill()
print("[DEBUG] Sandbox terminated. 👋")
Diese Chat-Schleife hält die Interaktion aufrecht, ermöglicht es dem Agenten, bei Bedarf eines der registrierten Tools aufzurufen, und bereinigt die Sandbox, wenn der Benutzer die Sitzung beendet.
Erstellen einer Benutzeroberfläche mit Gradio
Wir haben jetzt einen voll funktionsfähigen Coding-Agenten, der mit uns chatten kann, aber die Interaktion über ein REPL ist nicht gerade spannend. Machen wir die Erfahrung ansprechender, indem wir unserem Agenten eine einfache Gradio-Oberfläche geben.
Das Erstellen einer Gradio-Benutzeroberfläche ist einfach. Wir verwenden gr.ChatInterface, um unsere Chat-Interaktionen zu verwalten und sie mit der von uns zuvor erstellten Logik zu verknüpfen. Zusätzlich fügen wir eine Befehlsoberfläche zum Ausführen von Shell-Befehlen innerhalb der Sandbox sowie ein Dropdown-Menü hinzu, mit dem wir das zu verwendende Modell auswählen können.
Um unseren vorherigen Code für Gradio zu aktualisieren, ersetzen wir die Chat-Schleife und die letzten beiden Zeilen durch Folgendes:
# --- Persistent chat messages ---
messages = []
# --- Global model setter ---
def set_model(selected_model):
global model
model = selected_model
print(f"[DEBUG] Model switched to: {model}")
return f"✅ Model switched to **{model}**"
def chat_fn(user_message, history):
global messages, model
messages.append({"role": "user", "content": user_message})
# Send to model
response = client.chat.completions.create(
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] Assistant requested {len(assistant_msg.tool_calls)} tool call(s).")
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] Tool call detected: {fn_name} with args {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
# --- Command Interface function ---
def execute_command(command):
if not command.strip():
return "⚠️ Please enter a command."
print(f"[DEBUG] Executing command from interface: {command}")
output = run_commands(command)
return f"```bash\
{output}\
```" if output else "✅ Command executed (no output)."
# --- Gradio UI ---
with gr.Blocks(title="Novita Sandbox App") as demo:
gr.Markdown("## 🧠 Novita Sandbox Agent")
gr.Markdown(
"This app is an AI-powered **code agent** that lets you chat with intelligent assistants backed by **Novita AI LLMs**. These agents can write, read, and execute code safely inside a **Novita sandbox**, providing a secure environment for running commands, testing scripts, and managing files, all through an intuitive chat interface with model selection and command execution built right in."
)
with gr.Row(equal_height=True):
# Left: Chat Interface
with gr.Column(scale=2):
gr.Markdown("### 💬 Chat Interface")
gr.ChatInterface(chat_fn)
# Right: Command Interface
with gr.Column(scale=1):
gr.Markdown("### 💻 Command Interface")
# Model selector
model_selector = gr.Dropdown(
label="Select Model",
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"✅ Current model: **{model}**")
model_selector.change(set_model, inputs=model_selector, outputs=model_status)
command_input = gr.Textbox(
label="Command",
placeholder="e.g., ls, python main.py",
lines=1,
)
with gr.Row():
run_btn = gr.Button("Run", variant="primary", scale=0)
command_output = gr.Markdown("Command output will appear here...")
run_btn.click(execute_command, inputs=command_input, outputs=command_output)
# --- Cleanup on exit ---
atexit.register(lambda: (sandbox.kill(), print("[DEBUG] Sandbox terminated. 👋")))
if __name__ == "__main__":
demo.launch()
In dieser Version verarbeitet die Funktion chat_fn jeden Nachrichtenaustausch zwischen Benutzer und Agent. gr.ChatInterface verwendet diese Funktion als Eingabe und verwaltet die UI-Interaktionen automatisch.
Wenn die Gradio-App startet, führt sie Ihren Agenten im Browser aus und bietet dem Benutzer eine saubere, interaktive Chat-Oberfläche. Abschließend registrieren wir eine Bereinigungsroutine mit atexit, um sicherzustellen, dass die Sandbox ordnungsgemäß beendet wird, wenn die App stoppt.
Jetzt haben wir einen KI-gestützten Coding-Agenten, der sicher in einer Sandbox läuft, komplett mit einer freundlichen Gradio-Chat-Oberfläche.
Den vollständigen Code finden Sie auf GitHub.
Testen des Coding-Agenten
Um den Agenten zu verwenden, müssen wir unseren Gradio-Code als Skript ausführen:
python gradio_chat.py
Wenn wir das tun, läuft unsere Gradio-App auf localhost. Damit können wir Gespräche mit unserem Coding-Agenten führen, und der Agent führt alle unsere Aktionen innerhalb der Sandbox aus.
In der Gradio-Anwendung sehen wir nur die Chats unseres Agenten, aber wenn wir zum Terminal wechseln, können wir auch die Debug-Ausgaben sehen, also welchen Befehl die Funktion aufgerufen hat, die der Agent zur Unterstützung der Benutzeranfrage verwendet hat.
Die Tatsache, dass wir Zugriff auf ein Datei-Tool und ein Befehl-Tool haben, bedeutet, dass es fast nichts gibt, was wir nicht codieren können. Statt direkt zu codieren, geben wir unserem Agenten Anweisungen, und er schreibt und führt den Code für uns aus.
Bereitstellung auf Hugging Face Spaces
Derzeit läuft unser Coding-Agent lokal auf unserem Computer. Jetzt machen wir ihn für den Rest der Welt zugänglich, indem wir ihn auf Hugging Face Spaces bereitstellen. Hugging Face Spaces ermöglicht es uns, sowohl unseren Code als auch die Anwendung an einem Ort zu hosten. Lassen Sie uns anfangen.
Erstellen des Spaces
Gehen Sie zu Hugging Face und erstellen Sie einen neuen Space für Ihren Coding-Agenten, indem Sie ihm einen eindeutigen Namen geben.

Wählen Sie als Nächstes das SDK für den Space aus, in unserem Fall Gradio. Wählen Sie die leere Vorlage, da wir unseren Anwendungscode bereits haben.

Wählen Sie dann die Hardware aus. Da unser Agent und die Sandbox von Novita betrieben werden, benötigen wir keine spezielle Hardware. Die Option Basic CPU ist ausreichend. Klicken Sie nach Abschluss auf Space erstellen.

Hugging Face erstellt den Space mit einer README.md und einer .gitignore-Datei.
Es gibt mehrere Möglichkeiten, Ihren Code hinzuzufügen, aber die einfachste ist, auf Beitragen → Datei hinzufügen zu klicken.

Erstellen Sie eine Datei requirements.txt und fügen Sie die folgenden Abhängigkeiten hinzu:
openai
novita-sandbox
Hinzufügen von Umgebungsvariablen
Bevor wir unsere Anwendung ausführen können, müssen wir unseren NOVITA_API_KEY als Umgebungsvariable festlegen.
Navigieren Sie dazu zu den Einstellungen Ihres Spaces, scrollen Sie zum Abschnitt Variablen und Geheimnisse und fügen Sie ein neues Geheimnis mit dem Namen NOVITA_API_KEY hinzu, wobei Ihr API-Schlüssel als Wert dient.
Einrichtung der Anwendung
Nachdem die Umgebungsvariable festgelegt ist, ist es Zeit, unsere Anwendung zu erstellen.
Erstellen Sie eine neue Datei mit dem Namen app.py und fügen Sie unseren vollständigen Gradio-Agenten-Code hinein.

Sobald Sie die Datei speichern, beginnt Hugging Face automatisch mit dem Erstellen Ihres Spaces.

Nach Abschluss des Build-Prozesses ist Ihr Coding-Agent live und auf Hugging Face Spaces zugänglich.
Sie können jetzt über die interaktive Chat-Oberfläche mit Ihrem Agenten chatten.
Zusätzlich können Sie die Protokolle überwachen, um zu sehen, welche Tools Ihr Agent während der Ausführung aufruft.
Und das war’s! Sie haben jetzt einen voll funktionsfähigen Coding-Agenten, der in einer sicheren Sandbox läuft, mit einer Gradio-Oberfläche ausgestattet ist und nahtlos auf Hugging Face Spaces bereitgestellt wurde.
Fazit
In diesem Artikel haben wir untersucht, wie Sie Novitas Sandbox nutzen können, um einen voll funktionsfähigen Coding-Agenten zu erstellen, der Dateien lesen und erstellen, Befehle ausführen und sicher in einer geschützten Umgebung arbeiten kann.
Was wir hier erstellt haben, ist erst der Anfang. Die Sandbox öffnet die Tür zu unzähligen Möglichkeiten, von der Erstellung von KI-gestützten Datenvisualisierungs-Agenten bis hin zur Entwicklung von Computer-Nutzungs-Agenten, die intelligent mit Systemen interagieren können.
Fast alles ist möglich, wenn Sie einen Agenten mit einem dedizierten Toolset wie der Sandbox kombinieren.
