Du hast einen KI-Agenten und möchtest, dass er in einer sicheren Umgebung läuft, in der er Zugriff auf die richtigen Ressourcen hat – etwa auf ein Dateisystem und die Möglichkeit, Befehle (z. B. Shell-Befehle) auszuführen –, ohne dass die Gefahr besteht, etwas kaputtzumachen. Welche Optionen hast du also?
Der beste Ansatz ist, deinem KI-Agenten eine Sandbox zu geben. In einer Sandbox kann der Agent sicher mit einer Linux-Maschine interagieren, im Dateisystem arbeiten und bestimmte Befehle ausführen, während er daran gehindert wird, potenziell schädliche Operationen durchzuführen.
Mit diesem Setup können wir leistungsfähige Anwendungen bauen. Zum Beispiel einen Coding-Agenten, der:
- Code-Dateien im Dateisystem erstellen und bearbeiten kann
- Befehle wie git, python oder node ausführen kann
- Mit Entwicklern zusammenarbeiten kann, indem er Code direkt in der Umgebung ausführt und testet
In diesem Artikel zeigen wir dir, wie du einen solchen Coding-Agenten entwickelst. Wir verwenden Novitas LLMs mit Function Calling, kombiniert mit der Novita Agent Sandbox als sicherer Umgebung. Dazu erstellen wir eine benutzerfreundliche Oberfläche mit Gradio und stellen sie auf Hugging Face Spaces bereit.
Bevor du ein Modell für dieses Setup auswählst, sieh dir Large Language Model Use Cases for Coding Agents für praktische Muster wie Repository-Q&A, Test-Triage, Refactoring und Tool-Routed-Workflows an.
Lass uns direkt loslegen!
Agent Sandbox
Novitas Agent Sandbox ist eine Laufzeitumgebung, die speziell für KI-Agenten entwickelt wurde. Sie bietet ein sicheres und isoliertes Cloud-Setup, das wie ein virtueller Computer funktioniert. In dieser Umgebung können Agenten generierten Code sicher ausführen, ohne das zugrunde liegende System zu gefährden.
Hauptfunktionen der Novita Agent Sandbox
- Sicher: Die Sandbox ist vollständig isoliert, sodass der Agent nur auf seine eigenen Ressourcen zugreifen kann.
- Schneller Start: Neue Umgebungen starten in weniger als 200 ms.
- Virtuelle Maschine: Da sich die Sandbox wie eine VM verhält, können Agenten Code in jeder Programmiersprache ausführen.
- Pausieren und fortsetzen: Du kannst eine Sandbox jederzeit pausieren und später wieder fortsetzen.
- Hintergrundaufgaben: Agenten können Aufgaben im Hintergrund ausführen und Ergebnisse asynchron abrufen.
SDK installieren
Um die Novita Sandbox zu verwenden, benötigst du das SDK, das sowohl Python als auch TypeScript/JavaScript unterstützt. Für dieses Beispiel verwenden wir das Python-SDK:
pip install novita-sandbox
Nach der Installation setze deinen Novita-API-Key als Umgebungsvariable:
export NOVITA_API_KEY=your_api_key_here
Die Sandbox testen
Wenn alles eingerichtet ist, erstellen wir eine Sandbox und führen ein paar grundlegende Operationen aus:
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 du:
- Eine Sandbox-Instanz erstellst
- Mit dem
files-Objekt auf das Dateisystem zugreifst - Mit der Methode
commands.runBefehle ausführst - Ressourcen mit
killfreigibst, wenn du fertig bist
Nachdem wir nun die Grundlagen des Dateisystemzugriffs und der Befehlsausführung erkundet haben, sind wir bereit, unseren Coding-Agenten zu bauen, der diese Sandbox-Fähigkeiten als Tools nutzt.
Einen Coding-Agenten erstellen
Um unseren Coding-Agenten zu bauen, brauchen wir ein LLM, das Function Calling unterstützt. Novita bietet mehrere Modelle an, die das können. Damit sich unser Agent wie ein Coding-Assistent verhält, braucht er den richtigen Satz an Funktionen.
Lass uns überlegen, was ein menschlicher Coder tut. Normalerweise schreibt, liest und führt er Code aus. Unser Agent sollte also in der Lage sein:
- In eine Datei zu schreiben
- Aus einer Datei zu lesen
- Befehle auszuführen
- Mehrere Dateien gleichzeitig zu schreiben
Agent einrichten
Da Novitas Modelle OpenAI-kompatibel sind, können wir das OpenAI SDK zur Interaktion verwenden. Installieren wir es:
pip install openai
Nach der Installation setze deinen Novita-API-Key als Umgebungsvariable, genau wie zuvor. Danach können wir mit dem Codieren beginnen und 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 zeigen wir den Client auf Novitas Base-URL statt auf die von OpenAI und verwenden unseren Novita-API-Key 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 sie auf 10 Minuten gesetzt.
Funktionsdefinitionen
Jetzt können wir die Funktionen definieren, die unser Agent verwenden wird.
1. Datei lesen
Diese Funktion nimmt einen Dateipfad und liest ihren Inhalt mithilfe des files-Objekts 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 an 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 genau wie write_file, verarbeitet aber mehrere Dateien gleichzeitig.
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}"
Tools registrieren
Nachdem wir nun alle Funktionen haben, registrieren wir sie als Tools, die das LLM bei Bedarf aufrufen kann. Jede Tool-Definition enthält den Funktionsnamen, eine Beschreibung und das Parameterschema.
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"],
},
},
}
]
Mit den registrierten Tools schauen wir uns jetzt eine einfache Chat-Schleife an, mit der der Nutzer mit dem Coding-Agenten interagieren kann.
Chat-Schleife
Jetzt erstellen wir eine einfache Chat-Schleife, die dem Nutzer die Interaktion mit dem Coding-Agenten ermöglicht. Die Schleife verwaltet eine Nachrichtenliste und verarbeitet Funktionsaufrufe, sobald 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 am Laufen, erlaubt dem Agenten, bei Bedarf eines der registrierten Tools aufzurufen, und bereinigt die Sandbox, wenn der Nutzer das Programm beendet.
Eine UI mit Gradio erstellen
Wir haben jetzt einen voll funktionsfähigen Coding-Agenten, der mit uns chatten kann – aber die Interaktion über eine REPL ist nicht gerade spannend. Machen wir das Erlebnis ansprechender, indem wir unserem Agenten eine einfache Gradio-Oberfläche geben.
Eine Gradio-UI zu erstellen ist einfach. Wir verwenden gr.ChatInterface, um unsere Chat-Interaktionen zu verwalten und sie mit der zuvor aufgebauten Logik zu verbinden. Außerdem integrieren wir eine Befehlsschnittstelle zum Ausführen von Shell-Befehlen in der Sandbox sowie ein Dropdown-Menü, über das wir das zu verwendende Modell auswählen können.
Um unseren bisherigen Code für Gradio anzupassen, 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 übernimmt die Funktion chat_fn jeden Nachrichtenaustausch zwischen Nutzer und Agent. gr.ChatInterface nimmt diese Funktion als Eingabe und verwaltet die UI-Interaktionen automatisch.
Wenn die Gradio-App startet, läuft dein Agent im Browser und bietet dem Nutzer eine saubere, interaktive Chat-Oberfläche. Schließlich registrieren wir mit atexit eine Aufräumroutine, die sicherstellt, dass die Sandbox ordnungsgemäß beendet wird, wenn die App gestoppt wird.
Jetzt haben wir einen KI-gestützten Coding-Agenten, der sicher in einer Sandbox läuft – komplett mit einer benutzerfreundlichen Gradio-Chat-Oberfläche.
Den vollständigen Code findest du auf GitHub.
Den Coding-Agenten testen
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 Unterhaltungen 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. Wenn wir jedoch zum Terminal wechseln, sehen wir dort auch die Debug-Ausgaben darüber, welche Befehle bzw. Funktionen der Agent aufgerufen hat, um die Anfrage des Nutzers zu beantworten.
Dadurch, dass wir Zugriff auf ein Datei-Tool und ein Befehls-Tool haben, gibt es kaum etwas, das wir nicht programmieren könnten. Aber statt direkt zu codieren, geben wir unserem Agenten Anweisungen, und er schreibt und führt den Code für uns aus.
Auf Hugging Face Spaces bereitstellen
Aktuell 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 erlaubt es uns, Code und Anwendung an einem Ort zu hosten. Legen wir los.
Space erstellen
Gehe zu Hugging Face und erstelle einen neuen Space für deinen Coding-Agenten, indem du ihm einen eindeutigen Namen gibst.

Wähle als Nächstes das SDK für den Space aus – in unserem Fall Gradio. Wähle die Blank-Vorlage, da wir bereits unseren Anwendungscode haben.

Dann wähle die Hardware. Da unser Agent und die Sandbox von Novita betrieben werden, benötigen wir keine spezielle Hardware. Die Option Basic CPU ist ausreichend. Klicke anschließend auf Create Space.

Hugging Face erstellt den Space mit einer README.md und einer .gitignore-Datei.
Es gibt mehrere Möglichkeiten, deinen Code hinzuzufügen. Am einfachsten klickst du auf Contribute → Add file.

Erstelle eine Datei requirements.txt und füge folgende Abhängigkeiten hinzu:
openai
novita-sandbox
Umgebungsvariablen hinzufügen
Bevor wir unsere Anwendung ausführen können, müssen wir NOVITA_API_KEY als Umgebungsvariable setzen.
Navigiere dazu zu den Settings deines Spaces, scrolle zum Abschnitt Variables and secrets und füge ein neues Secret mit dem Namen NOVITA_API_KEY und deinem API-Key als Wert hinzu.
Anwendung einrichten
Nachdem die Umgebungsvariable gesetzt ist, wird es Zeit, unsere Anwendung zu erstellen.
Erstelle eine neue Datei mit dem Namen app.py und füge unseren vollständigen Gradio-Agenten-Code ein.

Sobald du die Datei speicherst, beginnt Hugging Face automatisch mit dem Build deines Spaces.

Nachdem der Build abgeschlossen ist, ist dein Coding-Agent live und über Hugging Face Spaces erreichbar.
Du kannst jetzt über die interaktive Chat-Oberfläche mit deinem Agenten chatten.
Außerdem kannst du die Logs überwachen, um zu sehen, welche Tools dein Agent während der Ausführung aufruft.
Und das war’s: Du hast jetzt einen voll funktionsfähigen Coding-Agenten, der sicher in einer Sandbox läuft, mit einer Gradio-Oberfläche ausgestattet und nahtlos auf Hugging Face Spaces bereitgestellt ist.
Fazit
In diesem Artikel haben wir untersucht, wie wir Novitas Sandbox nutzen können, um einen voll funktionsfähigen Coding-Agenten zu bauen, der Dateien lesen und erstellen, Befehle ausführen und sicher in einer geschützten Umgebung arbeiten kann.
Was wir hier gebaut haben, ist erst der Anfang. Die Sandbox eröffnet unzählige Möglichkeiten – von KI-gestützten Datenvisualisierungs-Agenten bis hin zur Entwicklung von Computer-Use-Agenten, die intelligent mit Systemen interagieren können.
Fast alles ist möglich, wenn du einen Agenten mit einem dedizierten Werkzeugsatz wie der Sandbox kombinierst.
