- Was macht etwas zu einem KI-Agenten?
- Schritt 1: Planung – Die Reasoning-Ebene
- Schritt 2: Tool-Nutzung – Das Modell mit der Welt verbinden
- Schritt 3: Code-Ausführung – Code sicher ausführen
- Schritt 4: Evaluierung – Wissen, wann der Agent richtig liegt
- Ein Modell für das Agent-Reasoning auswählen
- Alles zusammenfügen – Ein minimaler funktionierender Agent
- FAQ
- Empfohlene Artikel
Einen KI-Agenten zu bauen beginnt mit einer einfachen Idee: Einem Modell die Fähigkeit zu geben, Aktionen auszuführen, die Ergebnisse zu beobachten und eine Schleife zu durchlaufen. Das Modell denkt über ein Ziel nach, entscheidet, was als Nächstes zu tun ist, ruft ein Tool auf, erhält ein Ergebnis zurück und fährt fort, bis die Aufgabe erledigt ist. Diese Lese-Bewerte-Handle-Schleife ist der Kern jedes Agenten, den Sie bauen werden – sei es ein einfacher Ein-Schritt-Tool-Aufrufer oder ein mehrstufiges System, das Code schreibt, ausführt und seine eigenen Fehler behebt.
Dieses Tutorial führt durch die vier Komponenten, die einen Agenten zum Funktionieren bringen: Planung, Tool-Nutzung, Code-Ausführung und Evaluierung. Sie erhalten ein funktionierendes mentales Modell und eine minimale Implementierung, die Sie noch heute ausführen können.
Was macht etwas zu einem KI-Agenten?
Ein KI-Agent unterscheidet sich in einem entscheidenden Punkt von einem einfachen LLM-Aufruf: Er führt Aktionen aus und beobachtet deren Ergebnisse.
Eine einfache Chat-Vervollständigung erzeugt Text. Ein Agent verwendet diesen Text, um eine Funktion aufzurufen, eine API abzufragen, einen Befehl auszuführen oder eine Datei zu lesen – und speist das Ergebnis als Eingabe für den nächsten Schritt zurück. Diese Rückkopplungsschleife macht Agenten nützlich für Aufgaben, die nicht mit einer einzigen Antwort beantwortet werden können.
Drei Fähigkeiten definieren einen Agenten:
- Tool-Aufruf – das Aufrufen definierter Funktionen anhand ihres Namens mit strukturierten Argumenten
- Kontextakkumulation – das Weitergeben von Tool-Ergebnissen im Verlauf des Gesprächs
- Zielgerichtete Schleife – Fortsetzung, bis eine Abbruchbedingung erfüllt ist, nicht nur nach einer Antwort
Wenn ein System alle drei hat, bauen Sie einen Agenten. Fehlt die Kontextakkumulation oder die Schleife, handelt es sich um einen tool-unterstützten Chatbot.
Dieselbe Architektur bewältigt eine breite Palette von Aufgaben: Recherche-Agenten, die suchen und synthetisieren, Codierungs-Agenten, die Code schreiben und ausführen, Daten-Agenten, die Datenbanken abfragen und Berichte erstellen. Das Implementierungsmuster ist in jedem Fall nahezu identisch.
Schritt 1: Planung – Die Reasoning-Ebene
Die Planungsebene ist der Ort, an dem das Modell entscheidet, was als Nächstes zu tun ist. Sie benötigen kein separates Planer-Modell – dasselbe Modell, das Text generiert, kann über ein Ziel nachdenken und in jedem Schritt eine strukturierte Aktion (einen Tool-Aufruf) erzeugen.
Der System-Prompt erledigt den Großteil der Arbeit. Ein guter Planungs-Prompt teilt dem Modell mit:
- Auf welches Ziel es hinarbeitet
- Welche Tools verfügbar sind und was jedes tut
- Welches Format beim Aufruf eines Tools verwendet werden soll
- Wann es aufhören soll (die Fertigstellungsbedingung)
Mit der Novita-LLM-API – die OpenAI-kompatibel ist – sieht das so aus:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.novita.ai/v3/openai",
api_key=os.environ["NOVITA_API_KEY"],
)
tools = [
{
"type": "function",
"function": {
"name": "run_code",
"description": "Python-Code ausführen und stdout/stderr zurückgeben.",
"parameters": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "Auszuführender Python-Code"
}
},
"required": ["code"]
}
}
}
]
messages = [
{
"role": "system",
"content": "Sie sind ein Codierungs-Assistent. Verwenden Sie das Tool run_code, um Python auszuführen und Aufgaben zu lösen. Halten Sie an, wenn Sie eine endgültige Antwort haben."
},
{
"role": "user",
"content": "Finde alle Primzahlen unter 50."
}
]
response = client.chat.completions.create(
model="meta-llama/llama-3.1-8b-instruct",
messages=messages,
tools=tools,
tool_choice="auto",
)
Das Modell gibt einen Tool-Aufruf zurück – ein JSON-Objekt mit dem Funktionsnamen und den Argumenten – anstatt einer reinen Textantwort. Ihr Code extrahiert dies, führt die Funktion aus und geht mit dem an messages angehängten Ergebnis zurück in die Schleife.
Schritt 2: Tool-Nutzung – Das Modell mit der Welt verbinden
Tools sind das, was Agenten tatsächlich tun. Ohne sie kann das Modell nur Text produzieren. Mit ihnen kann es Dateien lesen, APIs aufrufen, Code ausführen, Datenbanken durchsuchen oder jede von Ihnen definierte Funktion auslösen.
Tools definieren
Jedes Tool ist ein JSON-Schema, das eine Funktion beschreibt. Das Modell liest dieses Schema, um seinen Aufruf korrekt zu formatieren. Einige praktische Regeln:
- Halten Sie Beschreibungen kurz und präzise. Das Modell liest sie bei jedem Schritt. Ausführliche Beschreibungen verschwenden Tokens.
- Passen Sie die Parameternamen an das an, was die Funktion tatsächlich akzeptiert. Abweichungen zwischen dem Schema und Ihrer Implementierung führen zu stillen Fehlern.
- Geben Sie strukturierte Ausgaben zurück. Wenn Ihr Tool rohes HTML oder unformatierten Prosa zurückgibt, verschwendet das Modell Tokens beim Parsen. Geben Sie saubere Strings oder JSON mit klaren Bezeichnungen zurück.
Die Tool-Aufruf-Schleife
Nachdem das Modell einen Tool-Aufruf getätigt hat, führt Ihr Code Folgendes aus:
- Extrahiert den Tool-Namen und die Argumente aus der Antwort
- Sucht die passende Python-Funktion
- Ruft sie mit den extrahierten Argumenten auf
- Hängt das Ergebnis mit
role: "tool"anmessagesan - Stellt eine weitere Vervollständigungsanfrage
Die Schleife wird fortgesetzt, bis das Modell eine reine Textnachricht ohne Tool-Aufruf zurückgibt (die Fertigstellungsbedingung).
import json
def run_agent_loop(client, model, messages, tools, tool_fns, max_steps=10):
for _ in range(max_steps):
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
tool_choice="auto",
)
choice = response.choices[0]
# Fertig – kein Tool-Aufruf
if choice.finish_reason == "stop":
return choice.message.content
# Tool-Aufruf ausführen
tool_call = choice.message.tool_calls[0]
fn_name = tool_call.function.name
fn_args = json.loads(tool_call.function.arguments)
result = tool_fns[fn_name](**fn_args)
# Sowohl den Tool-Aufruf des Modells als auch das Ergebnis anhängen
messages.append(choice.message)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": str(result),
})
return "Maximale Schrittzahl ohne endgültige Antwort erreicht."
Dies ist die vollständige Agenten-Schleife. Die max_steps-Begrenzung verhindert Endlosschleifen – wenn das Modell immer wieder dasselbe Tool aufruft, wird die Schleife beendet, anstatt unbegrenzt weiterzulaufen. Alles andere – Multi-Tool-Orchestrierung, Gedächtnis, Streaming – baut auf diesem Muster auf.
Häufige Tool-Muster
Dateizugriff: Lesen und Schreiben von Dateien im Arbeitsverzeichnis des Agenten. Geben Sie Dateiinhalte als Strings zurück.
Websuche: Suchergebnisse als Liste von {title, url, snippet}-Objekten zurückgeben. Halten Sie Ausschnitte kurz.
Code-Ausführung: Code in einer isolierten Umgebung ausführen und stdout/stderr zurückgeben (behandelt im nächsten Abschnitt).
Strukturierte Datenabfrage: Eine Datenbank oder API abfragen und Datensätze als JSON zurückgeben. Das Modell übernimmt die Zusammenfassung.
Jedes Tool sollte eine Sache tun und bei gleichen Eingaben eine deterministische Ausgabe liefern. Agenten, die versuchen, zu viel Logik in ein einziges Tool zu packen, werden schwerer zu debuggen und zu evaluieren.
Schritt 3: Code-Ausführung – Code sicher ausführen
Wenn Ihr Agent Code generiert und ausführt, benötigen Sie eine isolierte Umgebung. Code, der von einem Modell generiert wurde, direkt auf Ihrem Rechner auszuführen, ist ein Sicherheitsrisiko: Das Modell könnte zerstörerische Shell-Befehle, Endlosschleifen oder Code produzieren, der sensible Dateien liest, auf die es keinen Zugriff haben sollte.
Der Standardansatz ist eine Sandbox – eine kurzlebige, isolierte Linux-Umgebung, in der der Agent Code frei ausführen kann, ohne das Hostsystem zu beeinträchtigen. Novitas Agent Sandbox ist genau für diesen Anwendungsfall entwickelt: eine cloudbasierte Ausführungsumgebung, die in unter 200 ms startet, jeden vom Agenten produzierten Code ausführt und die Umgebung verwirft, wenn die Sitzung endet.
So würde das Tool run_code aus dem Planungsabschnitt mit der Sandbox implementiert werden:
from novita_sandbox.code_interpreter import Sandbox
sandbox = Sandbox.create()
def run_code(code: str) -> str:
result = sandbox.run_code(code)
output = ""
if result.logs.stdout:
output += "\n".join(result.logs.stdout)
if result.logs.stderr:
output += "\nSTDERR: " + "\n".join(result.logs.stderr)
return output or "(keine Ausgabe)"
Wenn der Agent run_code aufruft, führt diese Funktion den Code in der isolierten Umgebung aus und gibt stdout/stderr als String zurück. Der Agent sieht das Ergebnis und entscheidet, was als Nächstes zu tun ist – ob es darum geht, einen Fehler zu beheben, mit der Ausgabe fortzufahren oder die Aufgabe als erledigt zu erklären.
Diese Architektur trennt sauber die Reasoning-Ebene von der Ausführungsebene. Das LLM plant und ruft Tools auf; die Sandbox führt Code aus, ohne etwas außerhalb des Containers freizulegen.
Was die Sandbox handhabt
- Shell-Befehle (
bash,git,python,node) - Dateisystemoperationen innerhalb der Sandbox
- Netzwerkanfragen aus dem Container heraus
- Lang laufende Hintergrundaufgaben mit asynchronem Ergebnisabruf
- Pause und Fortsetzen für Multi-Session-Workflows
Was sie nicht erlaubt: Zugriff auf das Hostsystem, andere Sandboxes oder Anmeldeinformationen, die Sie nicht explizit übergeben haben. Diese Eingrenzung macht es sicher, dem Modell zu erlauben, beliebigen Code zu schreiben und auszuführen.
Schritt 4: Evaluierung – Wissen, wann der Agent richtig liegt
Evaluierung ist der am häufigsten übersprungene Schritt bei der Agentenentwicklung. Ein Agent, der eine Ausgabe produziert, ist nicht dasselbe wie ein Agent, der eine korrekte Ausgabe produziert.
Drei Stufen der Evaluierung
1. Deterministische Prüfungen
Für Aufgaben mit bekannten korrekten Antworten – Datum parsen, Wert berechnen, Feld extrahieren – schreiben Sie Unit-Tests gegen die Ausgabe des Agenten. Diese sind billig auszuführen und erkennen Regressionen schnell.
2. Ausführungsbasierte Prüfungen
Für Codierungs-Agenten ist das zuverlässigste Signal: Läuft der Code tatsächlich und produziert das richtige Ergebnis? Führen Sie die Ausgabe des Agenten in der Sandbox aus und vergleichen Sie stdout mit erwarteten Werten. Dies ist aussagekräftiger als der Vergleich von Code-Text, da es das Verhalten testet, nicht die Syntax.
def evaluate_code_task(agent_code: str, expected_stdout: str) -> bool:
result = run_code(agent_code)
return result.strip() == expected_stdout.strip()
3. LLM-as-Judge
Für offene Aufgaben – Zusammenfassung schreiben, Recherchefrage beantworten – verwenden Sie einen zweiten LLM-Aufruf, um die Ausgabe anhand einer Rubrik zu bewerten. Halten Sie die Rubrik spezifisch: „Hat die Antwort ein funktionierendes Codebeispiel enthalten?" ist besser als „Ist die Antwort gut?" Vage Rubriken führen zu inkonsistenten Ergebnissen.
Fehlermodi verfolgen
Agenten scheitern in einer wiederkehrenden Reihe von Mustern:
| Fehler | Ursache | Behebung |
|---|---|---|
| Tool-Aufruf-Schleife | Modell ruft immer wieder dasselbe Tool auf | max_steps setzen; Zwischenschritte protokollieren |
| Argumentkonflikt | Schema stimmt nicht mit Implementierung überein | Tool-Argumente vor dem Aufruf validieren |
| Kontextüberlauf | Sitzung überschreitet Kontextgrenze des Modells | Ältere Tool-Ergebnisse zusammenfassen oder kürzen |
| Halluzinierter Tool-Name | Modell erfindet ein nicht existierendes Tool | Strikte Tool-Liste mit tool_choice: "auto" verwenden |
Evaluierung ist keine separate Phase am Ende – sie ist Teil der Entwicklung. Jedes Mal, wenn Sie die Fähigkeiten eines Agenten erweitern, schreiben Sie mindestens einen Test, der eine Regression im neuen Verhalten erkennen würde.
Ein Modell für das Agent-Reasoning auswählen
Die meisten Tutorials standardmäßig auf Closed-Source-Modelle für das Agent-Reasoning. Das funktioniert gut für Prototypen, aber in der Produktion – wo ein Agent pro Aufgabe 20 LLM-Aufrufe tätigen könnte – werden Modellkosten und Ratenlimits zu echten Einschränkungen.
Open-Source-Modelle, die über die Novita-LLM-API gehostet werden, erreichen zunehmend die Leistung von Closed-Source-Modellen bei den Aufgaben, die Agenten tatsächlich benötigen: Funktionsaufruf, strukturierte Ausgabe und mehrstufiges Reasoning. Modelle wie Llama 3.3 70B und DeepSeek-V3 erzielen Benchmarks auf GPT-4-Niveau bei Codierung und Befehlsausführung, kosten aber nur einen Bruchteil. Bei Workloads mit hohem Durchsatz von Agenten summiert sich dieser Unterschied schnell.
Die Novita-API ist vollständig OpenAI-kompatibel, sodass der Wechsel von einem Closed-Source-Modell zu einem Open-Source-Modell eine einzeilige Änderung ist:
# Vorher
model = "gpt-4o"
# Nachher – gleicher API-Vertrag, niedrigere Kosten
model = "meta-llama/llama-3.3-70b-instruct"
Für latenzempfindliche Agenten-Schleifen antworten kleinere Modelle wie meta-llama/llama-3.1-8b-instruct schneller und kosten weniger pro Schritt, was wichtig ist, wenn jede Benutzeraufgabe viele sequenzielle Aufrufe umfasst. Ein praktisches Muster: Verwenden Sie ein schnelleres, kleineres Modell für Routing- und Klassifizierungsschritte und ein größeres Modell für komplexe Reasoning-Schritte, die mehr Kapazität benötigen.
Die Novita-Modellbibliothek enthält auch starke Optionen für spezifische agentische Unteraufgaben – Vision-Modelle für bildbasierte Tool-Ergebnisse, Embedding-Modelle für das Abrufen und code-spezialisierte Modelle für Codierungs-Agenten – alle über denselben API-Endpunkt zugänglich.
Alles zusammenfügen – Ein minimaler funktionierender Agent
Hier ist ein vollständiger Agent, der eine Matheaufgabe nimmt, Python-Code zur Lösung generiert, ihn in einer Sandbox ausführt und das verifizierte Ergebnis zurückgibt:
import os
import json
from openai import OpenAI
from novita_sandbox.code_interpreter import Sandbox
client = OpenAI(
base_url="https://api.novita.ai/v3/openai",
api_key=os.environ["NOVITA_API_KEY"],
)
sandbox = Sandbox.create()
def run_code(code: str) -> str:
result = sandbox.run_code(code)
stdout = "\n".join(result.logs.stdout)
stderr = "\n".join(result.logs.stderr)
return stdout or stderr or "(keine Ausgabe)"
tool_fns = {"run_code": run_code}
tools = [
{
"type": "function",
"function": {
"name": "run_code",
"description": "Python-Code ausführen. Gibt stdout oder stderr zurück.",
"parameters": {
"type": "object",
"properties": {
"code": {"type": "string"}
},
"required": ["code"]
}
}
}
]
messages = [
{
"role": "system",
"content": "Lösen Sie die Aufgabe, indem Sie Python-Code schreiben und ausführen. Verwenden Sie run_code zur Ausführung. Halten Sie an, wenn Sie eine verifizierte Antwort haben."
},
{
"role": "user",
"content": "Was ist die Summe aller geraden Fibonacci-Zahlen unter 1.000.000?"
}
]
for _ in range(10):
response = client.chat.completions.create(
model="meta-llama/llama-3.1-8b-instruct",
messages=messages,
tools=tools,
tool_choice="auto",
)
choice = response.choices[0]
if choice.finish_reason == "stop":
print(choice.message.content)
break
tool_call = choice.message.tool_calls[0]
fn_args = json.loads(tool_call.function.arguments)
result = tool_fns[tool_call.function.name](**fn_args)
messages.append(choice.message)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result,
})
sandbox.kill()
Dies deckt die vollständige Agenten-Schleife in etwa 50 Zeilen ab: Planung, Tool-Aufruf, Ausführung, Kontextakkumulation, max-step-Begrenzung und sauberes Sandbox-Cleaning. Der Agent schreibt Code, führt ihn aus, sieht die Ausgabe und fährt entweder fort oder gibt eine endgültige Antwort.
Um es zu erweitern: Fügen Sie weitere Tools zu tool_fns und tools hinzu, tauschen Sie ein größeres Modell für schwierigere Aufgaben ein oder ersetzen Sie das Sandbox-run_code durch eine beliebige andere Funktion – eine Websuche, eine Datenbankabfrage, einen API-Aufruf. Die Schleife bleibt gleich.
FAQ
Was ist der Unterschied zwischen einem KI-Agenten und einem Chatbot?
Ein Chatbot generiert Textantworten. Ein Agent führt Aktionen aus – ruft Tools auf, führt Code aus, fragt APIs ab – und verwendet die Ergebnisse, um weiter auf ein Ziel hin zu reasoning. Das Vorhandensein von Tool-Aufrufen und einer Rückkopplungsschleife ist das, was etwas zu einem Agenten macht.
Brauche ich ein Framework wie LangChain, um einen KI-Agenten zu bauen?
Nein. Die Kern-Agenten-Schleife ist einfach genug, um sie direkt gegen jede OpenAI-kompatible API zu implementieren. Frameworks bieten Mehrwert für komplexe Orchestrierung (Multi-Agenten-Systeme, persistentes Gedächtnis, Streaming-Ausgabe), fügen aber Abstraktionsebenen hinzu, die das Debuggen erschweren können. Beginnen Sie mit der rohen API und fügen Sie ein Framework hinzu, wenn Sie wirklich brauchen, was es bietet.
Wie verhindere ich, dass der Agent gefährlichen Code ausführt?
Verwenden Sie eine sandboxed Ausführungsumgebung. Der Code des Agenten läuft in einem isolierten Container, der keinen Zugriff auf Ihr Hostsystem oder andere Prozesse hat. Die Sandbox wird nach Ende der Sitzung verworfen, sodass alle Änderungen, die der Agent vornimmt, auf diesen Container beschränkt sind.
Können Open-Source-Modelle zuverlässig Funktionsaufrufe verarbeiten?
Ja – mit Einschränkungen bezüglich der Modellgröße. Llama 3.3 70B, DeepSeek-V3 und Qwen 2.5 72B beherrschen alle strukturierte Tool-Aufrufe gut. Kleinere Modelle (7B–8B) funktionieren für einfache, klar definierte Tool-Schemata, können aber mit mehrdeutigen Anweisungen oder komplexen mehrstufigen Reasoning-Ketten kämpfen. Testen Sie für Produktions-Agenten auf Ihrer tatsächlichen Aufgabenverteilung, bevor Sie sich auf ein Modell festlegen.
Wie viele Schritte sollte ein Agent pro Aufgabe unternehmen?
Setzen Sie ein hartes Limit – 10 bis 20 Schritte sind für die meisten Aufgaben üblich. Protokollieren Sie Zwischenschritte, damit Sie genau sehen, was der Agent getan hat, und Fehler debuggen können. Aufgaben, die konsequent mehr Schritte benötigen, profitieren in der Regel davon, in Unteragenten oder Unteraufgaben aufgeteilt zu werden, anstatt das Schleifenlimit zu erweitern.
