Startseite / Artikel

KI-Agenten gegen traditionelle Backends: Steuerfluss, Kosten und Fehlermöglichkeiten

Vergleichen Sie einen deterministischen Backend mit einem LLM-Agenten-Loop am Beispiel einer Rückerstattung: Latenz, Tokenkosten, Kontextwachstum, Fehlermöglichkeiten und wo ein hybrides Design am besten passt.

Verlag: REACTAPP.TOP9 Min. Lesezeit1966 Wörter

Quellen: AI Agents vs Traditional Backend Applications: What’s Actually Different?

Die Backend-Entwicklung hat seit langem auf eine beruhigende Eigenschaft gesetzt: den Determinismus. Schreibt einen Endpunkt, der eine Bestellung entgegennimmt, den Lagerbestand in PostgreSQL überprüft und per Stripe eine Karte belastet – dieselbe Abfolge läuft jedes Mal ab. Bei denselben Eingaben und dem gleichen Datenbankzustand wird Zeile 42 immer vor Zeile 43 ausgeführt.

Dann begann die Branche, KI-Agenten als die nächste Stufe von Backend-Systemen zu bezeichnen. Es ist leicht, das als Marketingstrategie abzutun, da ein Agent auch wie ein Service in einem Container aussieht, der externe APIs aufruft und in eine Datenbank schreibt. Tatsächlich hat sich jedoch der Steuerfluss geändert. Bei einem klassischen Backend bereinigt der Entwickler jeden Schritt, jede Abzweigung und jedes Randfall im Voraus. Bei einem Agenten liefert der Entwickler ein Ziel sowie eine Reihe von Werkzeugen, und ein probabilistisches Modell wählt die Schritte, ihre Reihenfolge sowie den Zeitpunkt, an dem die Aufgabe abgeschlossen wird. Wenn man einen Agenten einfach als weiteren Microservice betrachtet, gerät man bei Latenz, Zuverlässigkeit, Tests und Cloud-Kosten in ernsthafte Schwierigkeiten.

Festgelegter Pipeline versus Schlussfolgerungszyklus

Ein Standard-Backend bearbeitet eine Anfrage über ein gerichtetes azyklisches Graphen, das vom Programmierer hardcodet wurde:

[Request] ──> [Validate Input] ──> [Database Query] ──> [Transform Data] ──> [Response]
                     │
                     └── (Invalid) ──> [Return 400]

Jede Abzweigung – egal ob if/else, switch oder try/catch – wird im Voraus festgelegt. Der Code kann keinen Schritt einfügen, den Sie nicht geschrieben haben. Unerwartete Eingaben führen entweder zu einem Fehler oder zu einer vordefinierten Fallback-Lösung.

Ein Agent folgt nicht einer statischen Ablauffolge. Er befindet sich in einer Laufzeitschleife, die oft auf dem ReAct-Muster basiert – kurz für Reason plus Act. Der Backend-Teil überträgt den Kontrollfluss an ein großes Sprachmodell:

┌────────────────────────┐
                       ▼                        │
[Objective] ──> [LLM Evaluates State]           │
                       │                        │
             Does it need more info?            │
             ├── Yes ──> [Select Tool & Arguments]
             │                  │
             │           [Execute Tool] ────────┘
             │           (API, DB, Search)
             │
             └── No  ──> [Return Final Answer]

Eine Durchlaufschleife besteht aus vier Teilen:

  • Dem Modell werden das Ziel, der Kontext sowie die bisher ausgeführten Aktionen mitgeteilt.
  • Es prüft, ob es ausreichend Informationen hat oder ein externes Tool benötigt.
  • Falls Daten erforderlich sind, sendet es einen strukturierten Toolaufruf – beispielsweise das Lesen einer Datei, den Aufruf einer API oder die Ausführung einer Abfrage.
  • Ihr Laufzeitumfeld führt das Tool aus, legt die Rohausgabe in das Kontextfenster des Modells und startet die Schleife erneut.

Wichtig ist, dass das Modell die Reihenfolge der Schritte zur Laufzeit dynamisch auswählt.

Beispiel: Rückerstattung bei verspäteter Lieferung

Betrachten wir ein internes Tool, das einem Kunden, dessen Lieferung verspätet ist, eine Rückerstattung gewährt.

Die traditionelle Methode

In einem Express- oder FastAPI-Dienst könnte man einen Handler schreiben, der die Bestellung abruft, eine strenge Regel anwendet, die Rückerstattung ausstellt und eine Benachrichtigung sendet:

// Traditional Backend: Strict, deterministic logic
async function handleRefund(orderId: string, customerReason: string) {
  const order = await db.orders.findById(orderId);
  if (!order) {
    throw new NotFoundError("Order not found");
  }
  // Strict business rule written by an engineer
  const isEligible = order.status === "DELAYED" && order.daysDelayed > 5;

  if (!isEligible) {
    return { status: "rejected", reason: "Delay does not meet refund criteria." };
  }
  const refund = await paymentGateway.refund(order.paymentIntentId);
  await db.orders.update(orderId, { status: "REFUNDED" });
  await emailService.sendRefundNotice(order.customerEmail);
  return { status: "success", refundId: refund.id };
}

Dieser Code läuft in weniger als 100 Millisekunden ab, kostet fast nichts an Rechenleistung und verhält sich jedes Mal identisch. Gleichzeitig ist er anfällig für Fehler. Angenommen, ein Kunde schreibt, dass die Sendung pünktlich angekommen ist, aber der Fahrer den Briefkasten überfahren hat. Der Bearbeiter lehnt die Rückerstattung ab, weil daysDelayed null ist – schließlich erlauben die in ihm fest programmierten Regeln keine weitere Abwägung.

Der Ansatz mit Agenten

Ein Agent entscheidet je nach Erklärung des Kunden, welche Tools aufgerufen werden sollen:

// Agent Loop: The model decides which tools to call
import { generateText, tool } from "ai";
import { z } from "zod";
const tools = {
  fetchOrder: tool({
    description: "Fetch order details and shipping history",
    parameters: z.object({ orderId: z.string() }),
    execute: async ({ orderId }) => db.orders.findById(orderId),
  }),
  issueRefund: tool({
    description: "Issue a monetary refund to the customer",
    parameters: z.object({
      paymentIntentId: z.string(),
      amount: z.number(),
      reason: z.string()
    }),
    execute: async (args) => paymentGateway.refund(args.paymentIntentId, args.amount),
  }),
  escalateToHuman: tool({
    description: "Escalate edge cases or physical damage to a support manager",
    parameters: z.object({ ticketSummary: z.string() }),
    execute: async ({ ticketSummary }) => supportDesk.createEscalation(ticketSummary),
  })
};
// The execution is governed by an evaluation loop
const response = await generateText({
  model: yourConfiguredLLM,
  tools,
  maxSteps: 5, // Prevents infinite execution loops
  prompt: `Customer Issue: "The package arrived on time, but the driver ran over my mailbox. Order #1234."
           Evaluate policy guidelines and take appropriate action.`,
});

Hier liest das Modell die Beschwerde, holt die Bestellung ab, stellt fest, dass es sich um Schadensersatz wegen Sachschäden und nicht um Probleme in der Lieferlogistik handelt, überspringt die übliche Rückerstattungsprüfung und ruft escalateToHuman auf. Diese Flexibilität hat ihren Preis: Der Prozess erforderte drei Aufrufe an den LLM, verbrauchte einige Cent an Token und dauerte 4 Sekunden, während der Mensch nur 50 Millisekunden benötigte.

Vergleich der beiden Ansätze

Fast jede betriebliche Annahme ändert sich, wenn man von einem deterministischen Backend zu einem agierenden System wechselt.

  • Ablaufsteuerung: Im einen Fall definiert der Code die Schritte, im anderen wählt der LLM sie innerhalb einer Schleife aus.
  • Ausführungspfad: Im Backend ist er zur Kompilierzeit bekannt, beim agierenden System wird er zur Laufzeit ermittelt.
  • Latenz: Beim Backend liegen die Werte bei etwa 10 bis 200 Millisekunden und sind vorhersehbar, beim agierenden System liegen sie bei 2 bis 30 Sekunden oder mehr und sind je nach Anzahl der Iterationen variabel.
  • Fehlermöglichkeiten: Syntaxfehler, unverarbeitete Ausnahmen und Null-Werte für Backend-Systeme sowie falsche Argumente, endlose Schleifen und nicht eingehaltene Einschränkungen für Agenten.
  • Testing: Einerseits Unit-, Integrationstests sowie End-to-End-Prüfungen, andererseits LLM-as-a-Judge, Bewertungsbenchmarks und semantische Prüfungen.
  • Zustand: Transaktionale SQL- oder NoSQL-Daten im Vergleich zur Konversationsgeschichte, Grenzen des Kontextfensters und Arbeitsgedächtnis.
  • Kosten: CPU- und Speicherkosten, die konstant und günstig sind, im Gegensatz zu Eingangs- und Ausgabetoken bei jeder Schleifeniteration, die schnell ansteigen können.
  • Das Kontextfenster als Arbeitsgedächtnis

    Ein Backend speichert den Zustand in Variablen, Redis-Schlüsseln oder Datenbankzeilen, und eine Funktion liest nur die benötigten Felder. Für einen Agenten ist das Kontextfenster die kurzfristige Arbeitsgedächtnisfunktion. Immer wenn ein Tool ausgeführt wird, wird seine Ausgabe in Text – meist als JSON – serialisiert und dem Prompt-Historie hinzugefügt. Ein typischer Ablauf verläuft wie folgt:

    • Schritt 1: der Benutzerprompt, etwa 50 Token.
    • Schritt 2: die Anfrage des Modells an das Tool, etwa 40 Token.
    • Schritt 3: das Ergebnis des Tools, das etwa 500 Token hinzufügt.
    • Schritt 4: Das Modell analysiert den erweiterten Prompt und sendet einen zweiten Aufruf, der etwa 80 Token hinzufügt.
    • Schritt 5: Das zweite Ergebnis trifft ein und fügt etwa 1.200 Token hinzu.

    Jeder Zyklus vergrößert den Prompt. Da sowohl die Kosten als auch die Latenz mit der Eingabegröße zunehmen, ist der fünfte Schritt deutlich langsamer und teurer als der erste.

    Ein häufiger Produktionsfehler besteht darin, ganze Datenbankzeilen oder riesige API-Datenmengen an den Agent zurückzusenden. Wenn ein searchUsers()-Tool 50 vollständige Profile in den Kontext lädt, wird bald das effektive Denkfenster des Modells erschöpft sein. Entwerfen Sie Agent-Tools wie öffentliche APIs: Kürzen und bereinigen Sie die Ausgaben, sodass nur die Felder enthalten sind, die das Modell für seine nächste Entscheidung benötigt.

    Warum Agenten schwieriger am Laufen zu halten sind

    Ein fehlerhafter Backend liefert Ihnen einen Stack-Trace. Sie führen dieselbe Datenmenge lokal erneut aus, überprüfen die Variablen und beheben den Fehler. Agenten versagen hingegen probabilistisch.

    Endlose Schleifen. Angenommen, der Agent ruft eine API auf und erhält einen feinen Validierungsfehler wie invalid_date_format. Er versucht es erneut mit einer leicht abweichenden Datumszeichenkette und probiert anschließend wieder. Da es keine feste Obergrenze für die Anzahl der Iterationen (maxSteps) gibt, kann er Hunderte von Dollar an API-Krediten verbrauchen, indem er sich mit einem Validierer herumstritt.

    Einfundene Tool-Argumente. Schemata und Validierungen bieten gewöhnlichem Code Laufzeit-Typsicherheit. Ein LLM kann zu 98 Prozent gültiges JSON erzeugen, das Ihrem Schema entspricht, und gelegentlich einen imaginären Parameter einfügen. Was Sie erwarten:

    // Expected:
    { "customerId": "cust_123", "amount": 50 }
    

    Was das Modell bei hoher Temperatur manchmal aussendet:

    // What the model occasionally outputs under high temperature:
    { "user_id": "cust_123", "refund_value": "$50.00" }
    

    Falls die Laufzeitumgebung vor dem Ausführen der eigentlichen Funktion keine strenge Schema-Analyse mit Werkzeugen wie Zod oder Pydantic durchführt, wird Ihr Backend abstürzen.

    Unerwartetes Routing. Eine Abfrage, die gestern zwei Schritte benötigte, kann heute vier Schritte erfordern, weil der Benutzer sie etwas anders formuliert hat. Dadurch ist es schwierig, verbindliche Aussagen zu den Antwortzeiten zu machen.

    Die richtige Architektur wählen

    Agenten ziehen so viel Aufmerksamkeit auf sich, dass Entwickler versuchen, ganze Systeme daraus zu bauen – was ein teurer Fehler ist.

    Bleiben Sie bei herkömmlichem Backend-Code, wenn:

    • Die Geschäftslogik bekannt und stabil ist, wie bei Rechnungsstellung, Authentifizierung, CRUD-Operationen und Warenkorbberechnungen.
    • Die Latenz niedrig sein muss, wie bei Zahlvorgängen, Suchfunktionen mit Autocomplete und Echtzeit-Kommunikation.
    • Fehler zu Compliance- oder Finanzrisiken führen können, wie bei Buchhaltungsdaten, Gesundheitsakten und Berechtigungsverwaltung.
  • Die Kosten pro Anfrage sind bei großer Skalierung von Bedeutung, beispielsweise bei der Verarbeitung von Millionen von Ereignissen pro Stunde.
  • Wenden Sie sich an einen Agenten, wenn:

    • Der Weg zu einer Lösung unklar ist, zum Beispiel die Suche nach einem Flug mit einer dreistündigen Zwischenlandung, vegetarischen Mahlzeiten und einem Preis unter 800 Dollar.
    • Die Eingaben unstrukturiert und unübersichtlich sind, wie beispielsweise unterschiedliche PDF-Rechnungen, freiformige E-Mails oder Kundenberichte über Fehler.
    • Das System verschiedene Tools ohne gemeinsame API koordinieren muss, zum Beispiel das Durchsuchen externer Websites, das Durchforsten von Dokumentationen oder die Sortierung von Problemen über mehrere Produkte hinweg.

    Das funktionierende hybride Design

    In praktischen Anwendungen ist das zuverlässigste Design selten ein reiner Agent. Es handelt sich um einen deterministischen Backend mit einem Agenten, der innerhalb einer kontrollierten Grenze platziert wird:

    [Incoming Request] ──> [Traditional API Gateway] ──> Authentication / Rate Limiting
                                  │
                                  ▼
                          [Standard Business Logic] ──> Fast DB Reads / Validation
                                  │
                                  ▼
                        [Targeted Agent Boundary]  ──> Handles unstructured task
                                  │                    (Restricted to 3 safe tools)
                                  ▼
                          [Standard Business Logic] ──> Validates agent output
                                  │
                                  ▼
    [Final Response] <─── [Structured DB Write]
    

    Bewahren Sie Routing, Autorisierung, Persistenz sowie kritische Geschäftsvalidierungen in deterministischem Code auf. Rufen Sie den Agenten nur für die Unteraufgabe auf, die tatsächlich menschenähnliches Denken und eine lockere Tool-Orchestrierung erfordert.

    Fazit

    Ein Agent ist nicht besser als ein traditioneller Backend. Es handelt sich um ein anderes Rechenparadigma. Backends bevorzugen Vorhersehbarkeit, Geschwindigkeit und niedrige Kosten durch die Befolgung expliziter Anweisungen, während Agenten Anpassungsfähigkeit und Problemlösung fördern, indem sie einem LLM erlauben, den Ausführungsweg in einer Denkschleife zu wählen.

    Bevor Sie also die nächste Funktion entwickeln, überspringen Sie die Frage, ob ein Agent es bewältigen könnte – schließlich könnte er es voraussichtlich mit genügend Tokens. Fragen Sie stattdessen, ob Sie bereits die notwendigen Schritte zum Lösen des Problems kennen. Wenn ja, schreiben Sie den Code selbst und reservieren Sie Agenten für offene Probleme, die herkömmlicher Code nie flexibel genug war zu bewältigen.