Özgür Işık Damar
7 Min Lesezeit

Agentic-AI-Guardrails: Den while(true) davon abhalten, dein Token-Budget zu verbrennen

Vier Guardrails, die eine Vibes-Schleife in etwas verwandeln, das du in Produktion laufen lässt: Budget-Hülle, Retry-Kurven, Break-Bedingungen und eine echte Fallback-Kette.

agentic-aiproductionengineering-lessons

Letztes Mal habe ich gesagt, dass agentische KI größtenteils eine while(true)-Schleife mit Vibes ist. Auf den Beitrag kamen ein paar "Was ist denn der Fallback?"-Antworten, und die ehrliche Antwort lautet: Der Fallback ist der Schleifenkörper. Ohne ihn hast du ein Ding, das in Kreisen Geld verbrennt, bis du dich per SSH einloggst und kill -9 machst.

Dieser Beitrag ist das technische Follow-up. Vier Guardrails, die eine Vibes-Schleife in etwas verwandeln, das du auf Produktions-Traffic laufen lassen würdest.

Guardrail 1 — Budget-Hülle vor dem ersten Call

Die meisten Agent-Fehler sind nicht logisch. Sie sind finanziell. Token-Kosten sind bei $0,0001 pro Request egal — und werden in dem Moment teuer, in dem eine einzelne User-Query 47 Tool-Calls auslöst, weil der Planner entschieden hat: "Lass mich auch noch das Wetter checken."

Die Lösung ist eine harte Hülle am Eintrittspunkt. Kein weiches "Warnung bei 80%" — eine harte Decke, die wirft.

class BudgetGuard {
  private spent = 0;
  constructor(private readonly cap: number) {}
 
  charge(inputTokens: number, outputTokens: number) {
    this.spent += inputTokens + outputTokens;
    if (this.spent > this.cap) {
      throw new BudgetExceeded(this.spent, this.cap);
    }
  }
 
  remaining() {
    return Math.max(0, this.cap - this.spent);
  }
}
 
const budget = new BudgetGuard(50_000); // Tokens, keine Dollars — beim Abrechnen umrechnen

Jeder Model-Call zahlt, bevor er weitermacht. Der erste Agent, den ich in Produktion laufen ließ, beschloss, einen Service zu refaktorisieren, während er eine Bestellung nachschlagen sollte. Die Rechnung am nächsten Morgen war hundert Dollar für eine Query, die einen Cent hätte kosten sollen. Nach diesem Guard wirft dieselbe Query bei Hop 8 ein BudgetExceeded: 51200 > 50000, gibt eine höfliche "Mir geht der Platz aus"-Nachricht zurück, und der Worst Case ist ein 10-Cent-Fehler.

Guardrail 2 — Retry-Kurven, die heilen, nicht stochern

Wenn du "exponential backoff" googelst, bekommst du ein 5-Zeilen-Snippet, das die Verzögerung zwischen Retries verdoppelt. Das ist nicht der Sinn von Backoff. Der Sinn ist nicht, höfliche Retries zeitlich zu staffeln. Der Sinn ist, dem Downstream-Service Zeit zur Erholung zu geben.

Echte Kurve:

  • Jitter (weil synchronisierte Retries aus 1000 Instanzen denselben Service killen)
  • Cap (weil 17 Minuten auf einen API-Call zu warten schlimmer ist als zu scheitern)
  • Circuit Breaker (weil wenn 50 in Folge gefailt sind, der 51. auch nicht durchgeht)
async function callWithBackoff<T>(
  fn: () => Promise<T>,
  { maxAttempts = 5, baseMs = 200, capMs = 8_000 } = {},
): Promise<T> {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (!isRetryable(err) || attempt === maxAttempts) throw err;
      const delay = Math.min(capMs, baseMs * 2 ** (attempt - 1));
      const jittered = delay * (0.5 + Math.random() / 2);
      await sleep(jittered);
    }
  }
  throw new Error("unreachable");
}

isRetryable ist wichtiger als die Kurve. 429er und 503er sind retryable. 400er und 401er nicht — sie zu retryen heißt nur, denselben Fehler lauter zu machen.

Guardrail 3 — Wann man die Schleife bricht

Der schwerste Teil von while(true) ist nicht das while. Es ist das break. Fünf Bedingungen gehören in den Körper:

while (true) {
  if (budget.remaining() < 1_000) break;        // 1. finanziell
  if (Date.now() - started > 30_000) break;     // 2. Wanduhr
  if (lowConfidenceStreak >= 3) break;          // 3. Modell sagte 3x "ich bin nicht sicher"
  if (outputUnchanged >= 2) break;              // 4. es kreist nur
  if (cancellationToken.aborted) break;         // 5. User hat aufgegeben
 
  const step = await agent.step({ budget: budget.remaining() });
  budget.charge(step.inputTokens, step.outputTokens);
 
  if (step.isDone) break;
  lowConfidenceStreak = step.confidence < 0.4 ? lowConfidenceStreak + 1 : 0;
  outputUnchanged = sameAsLast(step.output) ? outputUnchanged + 1 : 0;
}

Der "Output unchanged"-Check fängt die meisten Produktionsschleifen ab. Ein Agent, der beim Denken feststeckt, produziert oft dieselbe Teilantwort 4-5 Mal in Folge in der Hoffnung, der nächste Sample sei der richtige. Ist er nicht. Brich aus, gib auf, gib zurück, was du hast.

Der Agent, an den ich gerade denke, hat 47 Mal retryed, weil ihm niemand gesagt hat aufzuhören. Der 48. war derselbe wie der 47. Die Retry-Kosten in Tokens waren höher als die ursprüngliche Antwort zu GPT-4-Preisen gewesen wäre.

Guardrail 4 — Fallback-Kette, nicht Fallback-Nachricht

"Ich habe mein Bestes gegeben" ist kein Fallback. Es ist Aufgabe. Echter Fallback ist eine Kette:

async function answer(query: string): Promise<string> {
  try {
    return await runAgent(query, { model: "claude-opus" });
  } catch (err) {
    if (err instanceof BudgetExceeded) {
      // Günstigeres Modell, engere Schleife
      return await runAgent(query, { model: "claude-haiku", maxSteps: 3 });
    }
    if (err instanceof TimeExceeded) {
      // Kein Agent — direkter LLM-Call ohne Tools
      return await directCompletion(query);
    }
    // Sonst: rule-based
    return ruleBased(query) ?? "Ich habe keine sichere Antwort.";
  }
}

Die Kette ist wichtig, weil die Fehler unterschiedlich sind. Budget-Überschreitung heißt "ich muss billiger denken." Zeit-Überschreitung heißt "ich muss einfacher denken." Logikfehler heißt "ich darf nicht denken." Jeder Zweig sollte auf der Ursache retryen, nicht auf dem Symptom.

Schluss

Agentische KI ohne Guardrails ist Autocomplete im Kreis. Der schwerste Teil ist nicht, das while(true) zu schreiben. Es ist, das break zu schreiben.

Wenn du eine Sache mitnimmst: Setz die Budget-Hülle als allererstes um die Schleife. Die anderen drei Guards sind Qualität. Budget ist Überleben.

Letzte Anmerkung: Ich fahre diese Patterns auf einem System, das Tools für einen Marketplace-Katalog mit 7 Millionen Produkten auswählt. Es läuft auf etwa 40 Dollar pro Monat an API-Kosten — auf Traffic, der vor zwei Iterationen 4.000 Dollar pro Monat gekostet hätte. Der Unterschied sind nicht smartere Agenten. Es sind bessere Breaks.

// wenn du schon hier bist