Wie man spezialisierte KI-Agenten mit CrewAI orchestriert – und was sich ändert, wenn die Crew in Produktion läuft. Mit Lektionen aus zwei eigenen Systemen.
Ein einzelner KI-Agent stößt bei komplexen, mehrstufigen Aufgaben schnell an Grenzen. Die naheliegende Lösung: mehrere spezialisierte Agenten, die wie ein Team zusammenarbeiten.
CrewAI ist ein Python-Framework genau dafür, Stand Oktober 2026 in Version 1.15. Ich setze es in zwei eigenen Systemen ein: bei Erst Recht, einer KI-Plattform für rechtliche Ersteinschätzungen nach deutschem Recht, und in einem Research-Projekt, in dem ein autonomes Multi-Agenten-System Studien zu Nahrungsergänzungsmitteln auswertet. Dieser Artikel zeigt zuerst die Grundlagen und dann, was davon in Produktion übrig bleibt. Kurz gesagt: weniger Agenten-Magie, mehr Code.
Die drei Kernkonzepte
Statt eines Agenten, der alles kann, stellst du ein Team zusammen: Rollen, Aufgaben, Ablauf. Die Beispiele zeigen eine generische Crew, die eingehende Support-Anfragen einordnet.
1. Agents: Die Spezialisten
Jeder Agent hat eine Rolle, ein Ziel und einen Hintergrund. Das Modell bindest du über die LLM-Klasse ein, mit einem Provider-Präfix im Modellnamen.
from crewai import Agent, LLM
llm = LLM(
model="provider/model-name",
max_tokens=4096,
timeout=120, # harte Obergrenze pro Aufruf
)
analyst = Agent(
role="Support-Analyst",
goal="Anfragen einordnen und ihre Dringlichkeit bewerten",
backstory="""Du analysierst Support-Anfragen für eine B2B-Software.
Antworte nur mit der Einschätzung, ohne Einleitung.""",
llm=llm,
allow_delegation=False,
)
Best Practice: Spezifische Rollen
Statt „Analyst“ lieber „Support-Analyst für B2B-Software“ mit klar umrissenem Ziel. Genauso wichtig ist, was der Agent nicht tun soll.
2. Tasks: Die Aufgaben
Tasks definieren, was getan werden soll. Über context bekommt eine Task das Ergebnis einer vorherigen Task, über output_pydantic erzwingst du ein festes Ausgabeformat statt Freitext.
from crewai import Task
task_bewertung = Task(
description="Bewerte diese Anfrage: {anfrage}",
expected_output="Kategorie, Priorität und kurze Begründung",
agent=analyst,
output_pydantic=TicketAssessment, # Schema statt Freitext
context=[task_klassifizierung], # Ergebnis des vorherigen Agents
)
3. Crew: Das Team
Die Crew bringt Agents und Tasks zusammen und legt fest, wie sie zusammenarbeiten.
from crewai import Crew, Process
crew = Crew(
agents=[klassifizierer, analyst, autor],
tasks=[task_klassifizierung, task_bewertung, task_antwort],
process=Process.sequential,
)
result = crew.kickoff(inputs={"anfrage": text})
bewertung = result.tasks_output[1].pydantic # typisiert, kein Regex
Alternativ gibt es Process.hierarchical: Ein Manager-LLM verteilt die Tasks dynamisch und prüft die Ergebnisse. Dafür brauchst du laut Doku ein manager_llm oder einen manager_agent. In Produktion setze ich auf feste Reihenfolgen. Einen Ablauf, den ich vorher kenne, kann ich testen und debuggen.
Crews vs. Flows: der Teil, den Tutorials überspringen
Eine Crew ist eine Gruppe von Agenten. Ein Flow ist ein ereignisgesteuerter Ablauf drumherum: Methoden mit @start() und @listen(), Verzweigungen mit @router(), dazu ein typisierter Zustand als Pydantic-Modell. In einem Flow-Schritt kann eine Crew laufen – oder normaler Python-Code. CrewAI selbst empfiehlt für Produktion, mit einem Flow zu beginnen. So sieht das Prinzip, stark vereinfacht, in meinem Research-Projekt aus:
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel
class RunState(BaseModel):
topic_id: str = ""
paper_ids: list[str] = []
evaluation_ids: list[str] = []
draft_id: str | None = None
class ResearchFlow(Flow[RunState]):
@start()
async def discover(self):
# reiner Code: Studien laden und deduplizieren
self.state.paper_ids = await discover_papers(self.state.topic_id)
@listen(discover)
async def evaluate(self):
# feste Bewertungsformel
self.state.evaluation_ids = await evaluate_papers(self.state.paper_ids)
@listen(evaluate)
async def synthesize(self):
# LLM-Schritt mit festem Ausgabeschema
self.state.draft_id = await write_draft(self.state.evaluation_ids)
# danach: redigieren → Fakten prüfen → validieren → veröffentlichen
Bemerkenswert ist, was fehlt: In diesem System gibt es keine einzige Crew. Geplant hatte ich pro Stufe eine Crew. Gebaut habe ich die Stufen als normale async-Funktionen, die das Modell direkt aufrufen, jede mit festem Ausgabeschema. Von CrewAI nutze ich dort nur die Flows: Reihenfolge, Zustand, zeitgesteuerter Start. Jede Stufe hat einen klaren Input und einen klaren Output. Für einen Agenten, der selbst plant, bleibt da wenig zu entscheiden.
Zwei Systeme im Überblick
Erst Recht
Mehrere spezialisierte Agents, orchestriert mit CrewAI, dazu eine juristische Wissensbasis. Das Ergebnis ist eine strukturierte rechtliche Ersteinschätzung für Laien.
Research-Projekt Nahrungsergänzungsmittel
Ein Flow mit festen Stufen: Studien finden, bewerten, Artikel entwerfen, redigieren, Fakten prüfen, Evidenz validieren, veröffentlichen. Die letzte Stufe ist reiner Code ohne LLM.
Fünf Regeln für Crews in Produktion
1. Ein zu strenges Schema kann den ganzen Lauf abbrechen
Harte Wertebereiche im Ausgabeschema, etwa ein Literal, sind riskant. Liefert das Modell ein Synonym, wirft Pydantic einen ValidationError, und je nach Version reicht CrewAI ihn aus crew.kickoff() heraus. Dann bricht der ganze Lauf ab, bezahlte Tokens sind verloren, und Fallback-Code hinter kickoff() läuft nie.
Die Lösung: Das Schema beschreibt nur die Struktur. Die erlaubten Werte prüft der Code nach dem Parsen. Am Beispiel eines Prioritätsfelds:
# vorher: zu streng, ein Synonym bricht den ganzen Lauf ab
class TicketAssessment(BaseModel):
priority: Literal["hoch", "mittel", "niedrig"]
# nachher: Schema für die Struktur ...
class TicketAssessment(BaseModel):
priority: str = Field(description="Erlaubt: 'hoch', 'mittel', 'niedrig'")
# ... und Code für die Werte, nach dem Parsen
ALLOWED = {"hoch", "mittel", "niedrig"}
assessment = result.tasks_output[1].pydantic
if assessment.priority.strip().lower() not in ALLOWED:
flag_for_review(assessment) # Wert markieren, der Lauf bleibt erhalten
Neuere CrewAI-Versionen bieten zusätzlich Task-Guardrails: Eine Funktion prüft die Ausgabe, bei einem Fehlschlag geht der Fehler zurück an den Agenten, standardmäßig bis zu dreimal (guardrail_max_retries). Für Formatfehler ist das sauberer. Jeder Retry ist aber ein weiterer bezahlter Modell-Aufruf.
2. Agents erfinden Quellen
Im Research-Projekt muss jede Aussage im Artikel mit Paper-IDs belegt sein. Der Prompt verbietet erfundene IDs. Der Code verlässt sich trotzdem nicht darauf:
known_ids = set(paper_abstracts.keys())
for p in parsed.paragraphs:
support = [pid for pid in p.supporting_paper_ids if pid in known_ids]
if p.is_claim and not support:
continue # Aussage ohne echten Beleg fliegt raus
paragraphs.append(...)
Jede zitierte ID wird gegen die Paper geprüft, die tatsächlich im Prompt standen. Danach folgen weitere harte Prüfungen: Lässt sich eine Aussage nicht auf eine echte Quelle zurückführen, bricht die Stufe ab, ohne Retry. Der Fact-Check prüft, ob zitierte DOIs existieren und ob das Paper die Aussage tatsächlich stützt.
3. Kein Modell prüft sich selbst
Im Research-Projekt stammen das Modell, das schreibt, und das Modell, das prüft, aus unterschiedlichen Modellfamilien. Ein Modell, das seinen eigenen Text gegenliest, übersieht leicht dieselben Fehler, die es gemacht hat. Die Prüfung ist Pflicht: Läuft sie nicht, wird nicht veröffentlicht, statt still auf „ungeprüft“ herunterzustufen.
4. Nutzereingaben sind Daten, keine Befehle
Alles, was von außen kommt, ist Datum, kein Befehl: Nutzereingaben, hochgeladene Dokumente, Abstracts aus Datenbanken. Solche Texte gehören im Prompt klar abgegrenzt vom Auftrag. Im Research-Projekt prüft zusätzlich ein deterministischer Scanner jeden Abstract auf typische Injection-Muster, bevor er ein Modell erreicht. Auffällige Texte gehen nicht ungefiltert weiter. Warum das kein Luxus ist, steht im Artikel zur Lethal Trifecta.
5. Kosten und Laufzeit brauchen harte Grenzen
Im Research-Projekt geht jeder Modell-Aufruf vorher durch einen Cost Governor mit festen Limits pro Lauf, Tag und Monat. Reißt ein Lauf sein Limit, wird er abgebrochen. Reißt der Monat sein Limit, schaltet sich das Veröffentlichen automatisch ab.
Genauso wichtig ist ein Timeout für jeden Modell-Aufruf. Ein hängender Call darf keinen Worker blockieren. Lange Crew-Läufe gehören außerdem nicht in einen synchronen API-Request; die CrewAI-Doku empfiehlt dafür kickoff_async. Wer Agents mit Tools baut, sollte die Limits pro Agent bewusst setzen: max_iter (Standard: 20), max_execution_time, max_rpm.
Code oder Agent? Wo ich die Grenze ziehe
Die wichtigste Lektion aus beiden Systemen: Ein großer Teil der Arbeit gehört gar nicht in einen Agenten.
- Datenbeschaffung: Im Research-Projekt holen normale Adapter die Studien aus Datenbanken wie PubMed, mit Rate-Limits und Deduplizierung. Kein Agent sucht dort selbst.
- Wissen bereitstellen: Arbeiten Agents mit einer Wissensbasis, entscheide bewusst, ob der Agent selbst sucht oder ob Code die passenden Passagen vorab holt. Vorab geholter Kontext ist reproduzierbar und lässt sich protokollieren. Ein Such-Tool gibt dem Agenten mehr Freiheit, und mehr Möglichkeiten, sich zu verlaufen. Wie man eine solche Wissensbasis aufbaut, beschreibe ich im Docling-Artikel.
- Bewertung: Der Qualitäts-Score einer Studie ist eine feste Formel aus klassischen Kriterien wie Studiendesign und Stichprobengröße.
- Evidenz-Level: Der Validator nimmt immer den niedrigeren Wert aus Modell-Vorschlag und berechnetem Wert. Hochstufen ist ausgeschlossen.
- Veröffentlichen: Reiner Code ohne LLM, mit mehrfach abgesicherter Freigabe.
Faustregel
Alles mit einer eindeutig richtigen Antwort gehört in Code. Agents bekommen die Schritte, die Urteilsvermögen brauchen. Und auch dort prüft Code das Ergebnis.
Und dann ist da der Mensch. Im ursprünglichen Design war das Research-Projekt „vollständig autonom“. Gebaut habe ich ein Freigabe-Gate: Die ersten Artikel gehen nur mit menschlicher Freigabe live. Wie das System seine Fehlschläge in Issues und Pull Requests verwandelt, beschreibe ich in Loops statt Prompts.
Wann du keine Crew brauchst
- Die Schritte stehen fest. Hat jeder Schritt einen klaren Input und ein festes Ausgabeschema, reicht ein Flow mit normalen Funktionen. So läuft mein Research-Projekt.
- Die Antwort muss schnell kommen. Jeder sequenzielle Agent ist ein weiterer LLM-Aufruf. Für eine Analyse, auf die niemand live wartet, ist das in Ordnung. Im Chat-Tempo wird es zäh.
- Mehr Agents als Selbstzweck. Jeder zusätzliche Agent kostet Tokens und Latenz. Ob eine aufwendigere Topologie bessere Ergebnisse liefert, muss ein Test zeigen, nicht das Architekturdiagramm.
- Du kannst das Ergebnis nicht prüfen. Ohne Schema, Prüfschritt und Kostendeckel gehört eine Crew nicht vor Nutzer.
Checkliste für die erste Crew in Produktion
- Mit einem Flow starten. Langlebiger Zustand gehört in die Datenbank, nicht in den Flow-State.
- Jede Task mit
output_pydantic: Schema für die Struktur, Code für die Werte. - Jede Quelle, ID und Zahl im Code gegen den Input prüfen.
- Mit einer anderen Modellfamilie prüfen als mit der, die geschrieben hat.
- Timeouts und Kostendeckel einbauen, bevor der erste Nutzer kommt.
- Nutzereingaben und externe Texte klar abgrenzen und als Daten behandeln.
- Am Anfang steht ein Mensch vor dem Veröffentlichen.
Fazit
CrewAI macht den Einstieg leicht: Rollen, Tasks, Crew, fertig. In Produktion verschiebt sich der Schwerpunkt. Die meiste Arbeit steckt bei mir im Code um die Agents herum: Schemas, die keinen Lauf abbrechen, Prüfungen, die erfundene Quellen aussortieren, Limits, die Kosten deckeln. Die Agents übernehmen, was Urteilsvermögen braucht. Alles andere erledigt Code.
Verwendete Tools:
Planst du ein Multi-Agent-System oder willst du eine bestehende Crew produktionsreif machen? Schreib mir, ich helfe gerne bei Architektur und Implementierung.