CodeGym /Kurse /ChatGPT Apps /Produktivbetrieb und Sicherheit: Berechtigungen, Sandbox,...

Produktivbetrieb und Sicherheit: Berechtigungen, Sandbox, Secrets, Monitoring

ChatGPT Apps
Level 12 , Lektion 4
Verfügbar

1. Warum braucht ein Agent „Produktionsdenken“

Wenn Sie ein gewöhnliches Backend schreiben, schaltet allein die Idee „in Produktion gehen“ automatisch in den Paranoia‑Modus: Autorisierung, Logging, Fehlerbehandlung, Limits, Secrets in .env statt im Code.

Beim Agenten müssen Sie denselben Modus aktivieren – nur noch strenger. Der Grund ist einfach: Ein normales Backend führt genau das aus, was Sie geschrieben haben, ein Agent hingegen das, wozu sich das Modell selbst entscheidet – innerhalb der vorgegebenen Tools und Instruktionen. Die Kontrollillusion ist hier stärker als im klassischen Code: Es scheint, als beschreibe der Prompt alles, aber in Wahrheit kontrollieren Sie nur die Umgebung und die verfügbaren Aktionen, nicht alle „Gedanken“ des Modells.

Deshalb werden wir unseren Agenten in dieser Vorlesung Schritt für Schritt mit „Schutzschichten“ umgeben:

  • zuerst beschränken wir, was er überhaupt tun darf (Tool‑Rechte und Trennung von Agenten),
  • dann isolieren wir die Ausführungsumgebung (Sandbox und Limits),
  • bringen Ordnung in Secrets und PII,
  • und schließlich schalten wir Observability ein: Logs, Metriken und grundlegendes Tracing.

Damit es konkret bleibt, setzen wir die Geschichte mit unserem GiftGenius fort: ein Agent, der bei der Geschenkauswahl hilft und ein bisschen in die Commerce‑Welt eintaucht (über Bestellung und Checkout, aber vorerst ohne ACP‑Details – das kommt später).

2. Berechtigungen: Ein Agent braucht nicht „alle Knöpfe der Welt“

Prinzip der geringsten Privilegien (Least Privilege)

Erste Regel: Ein Agent muss nicht alles können. Je mehr Tools er hat, desto höher die Chance, dass er „die falsche“ Funktion „im falschen“ Moment aufruft. Anstatt eines monströsen manageEverything(), das alles liest und schreibt, entwerfen wir kleine, klare Funktionen, zumindest getrennt in Lesen und Schreiben.

Für GiftGenius ist das besonders klar: Es ist etwas anderes, eine Liste von Geschenken und Benutzerpräferenzen zu lesen, als eine Bestellung zu erstellen oder zu bestätigen (da geht es um Geld). Deshalb machen wir üblicherweise:

  • einen Satz sicherer „read‑only“‑Tools (Geschenke suchen, Details ansehen),
  • separate „write“‑Tools (Erstellen eines Bestellentwurfs, Stornieren einer Bestellung),
  • und, falls nötig, noch eine Ebene für besonders gefährliche Operationen (Zahlungsbestätigung, Massenänderungen).

Getrennte Agenten für unterschiedliche Aufgaben

Ein weiterer starker Ansatz ist, Agenten nach Verantwortungsbereichen zu trennen. Ein Agent: „Geschenkauswahl“, ein anderer: „Bestellverwaltung“. Dann kann selbst wenn das Modell im Gift‑Agent ein wenig „aus der Spur gerät“, dieser physisch kein Zahlungs‑Tool aufrufen, weil es in seiner Konfiguration schlicht nicht vorhanden ist.

Stellen wir uns einen minimalistischen Typ für Agent‑ und Tool‑Konfigurationen vor:


// Vereinfachte Typen zur Erläuterung der Ideen
type ToolName = 'suggest_gifts' | 'get_gift_details' |
  'create_order_draft' | 'confirm_order';

type AgentConfig = {
  id: string;
  allowedTools: ToolName[];
  maxSteps: number;
};

Beschreiben wir zwei GiftGenius‑Agenten:

export const giftPlannerAgent: AgentConfig = {
  id: 'gift-planner',
  allowedTools: ['suggest_gifts', 'get_gift_details'],
  maxSteps: 6,
};

export const orderAgent: AgentConfig = {
  id: 'order-manager',
  allowedTools: ['create_order_draft', 'confirm_order'],
  maxSteps: 4,
};

Ja, das ist noch abstrakt, aber der Kern ist einfach: Selbst wenn es im Code alle vier Tools gibt, erhält ein konkreter Agent nur die benötigte Teilmenge.

Rechte an Benutzer und Rollen binden

Wichtig ist, dass wir zwei unterschiedliche Entitäten haben:

  • den Benutzer und seine Rechte (darf dieser user_id überhaupt etwas kaufen, stornieren, den Verlauf sehen),
  • den Agenten und seine erlaubten Tools.

Im Idealfall sollte jeder Tool‑Aufruf beide Prüfungen bestehen: „Ist es dem Agent erlaubt?“ und „Ist es dem Benutzer ebenfalls erlaubt?“.

Vereinfacht:

type UserRole = 'guest' | 'customer' | 'admin';

function canUserCallTool(role: UserRole, tool: ToolName): boolean {
  if (tool === 'confirm_order') {
    return role === 'customer' || role === 'admin';
  }
  if (tool === 'create_order_draft') {
    return role !== 'guest';
  }
  return true; // Lesen erlauben wir allen
}

Auf der MCP-/Backend-Seite können wir beim Verarbeiten eines Tool‑Aufrufs die Doppelprüfung durchführen:

function assertToolAllowed(
  agent: AgentConfig,
  userRole: UserRole,
  tool: ToolName,
) {
  if (!agent.allowedTools.includes(tool)) {
    throw new Error(`Tool ${tool} ist für Agent ${agent.id} verboten`);
  }
  if (!canUserCallTool(userRole, tool)) {
    throw new Error(`Benutzer mit Rolle ${userRole} darf ${tool} nicht aufrufen`);
  }
}

Am Ende gilt: Selbst wenn das Modell plötzlich versucht, confirm_order aus dem falschen Agent oder im Namen eines Gasts aufzurufen – der Aufruf prallt an dieser Prüfung ab und wird zu einem kontrollierten Fehler statt zu einer ungeplanten Zahlung.

Verschiedene Konfigurationen je Umgebung

In den Umgebungen dev und staging möchten Sie dem Agenten oft mehr Freiheiten geben: Test‑Tools, Fake‑Zahlungsdienste, experimentelle Funktionen. In production ist die Konfiguration dagegen maximal strikt: manche Tools sind deaktiviert, Endpoints ausschließlich produktiv, Tokens ausschließlich real.

Ein einfaches Schema:

type Env = 'dev' | 'staging' | 'production';

const env = (process.env.APP_ENV as Env) ?? 'dev';

const orderAgentByEnv: Record<Env, AgentConfig> = {
  dev: {
    id: 'order-manager-dev',
    allowedTools: ['create_order_draft', 'confirm_order'],
    maxSteps: 8,
  },
  staging: {
    id: 'order-manager-staging',
    allowedTools: ['create_order_draft', 'confirm_order'],
    maxSteps: 6,
  },
  production: {
    id: 'order-manager-prod',
    allowedTools: ['create_order_draft'], // confirm nur über einen separaten Pfad
    maxSteps: 4,
  },
};

export const currentOrderAgent = orderAgentByEnv[env];

In prod kann confirm_order komplett in einen separaten „gefährlichen“ Agent ausgelagert sein, den Sie nur nach einem expliziten Klick „Bestellung bestätigen“ im Widget und nach zusätzlichen Prüfungen aufrufen.

3. Sandbox: Ein Agent braucht keinen Root‑Zugriff auf Ihr Universum

Ebenen der Isolation

Nachdem wir Rechte für Agenten und Benutzer festgelegt haben, gehen wir zur nächsten Schutzebene über – Sandbox und Isolierung der Ausführungsumgebung.

Die Sandbox für den Agenten und seine Tools lässt sich grob in mehrere Ebenen teilen:

  1. Ebene des Tool‑Codes. Wir beschränken den Zugriff auf Dateisystem, Netzwerk und Prozessressourcen: nicht irgendwohin schreiben lassen, nicht in beliebige Domains gehen, nicht endlos CPU drehen oder Gigabytes an Speicher konsumieren.
  2. Ebene des Agents‑SDK. Wir definieren Limits für die Schritte des Run‑Zyklus, für die Anzahl der Tool‑Aufrufe und für die Kontextgröße (Token‑Limit). Das Modell kann nicht unendlich „nachdenken“ und Tool‑Calls erzeugen – irgendwann endet der Run mit „Schrittlimit“ oder „Zeitlimit“.

All das ergibt eine klassische „defensive Architektur“, die sich gut schematisch darstellen lässt.

graph TD
    A[Prompt / Systemanweisungen] --> B[JSON‑Schema der Tools]
    B --> C[Berechtigungen von Agent und Benutzer]
    C --> D[Sandbox der Infrastruktur]
    D --> E[Externe Dienste / DB]

    subgraph Agent
      A
      B
      C
    end

    subgraph Infrastruktur
      D
    end

Der Prompt ist der schwächste Schutz; die eigentliche Stärke beginnt dort, wo Sie physisch einschränken, was Ihr Code tun kann und welche APIs verfügbar sind.

Limits für den Run‑Zyklus: Schritte, Zeit, Tool‑Calls

Einen Teil der Sandbox können Sie direkt in der Agent‑Konfiguration ausdrücken: maximale Schrittzahl, Gesamtzeit, Limit für Tool‑Aufrufe. Das ist nicht nur Schutz vor Runaway‑Zyklen, sondern auch Kostenkontrolle.

Beispiel einer abstrakten Run‑Options‑Konfiguration:

type RunLimits = {
  maxSteps: number;
  maxToolCalls: number;
  timeoutMs: number;
};

const defaultLimits: RunLimits = {
  maxSteps: 8,
  maxToolCalls: 10,
  timeoutMs: 30_000,
};

Solche Limits geben Sie dann an den Wrapper weiter, der den Agenten startet. Falls das Modell plötzlich ein 11. Mal ein Tool aufrufen will – brechen Sie den Lauf ab und sagen dem Benutzer ehrlich, dass die Aufgabe zu komplex ist, statt den Agenten das Budget unkontrolliert verbrennen zu lassen.

Isolation von Code und Netzwerk

Auf Container-/Prozessebene sind die üblichen Praktiken:

Der Code des MCP‑Servers und/oder des Agent‑Dienstes läuft in einem Container mit schreibgeschütztem Dateisystem (außer einem speziell vorgesehenen Arbeitsverzeichnis) und begrenzten Ressourcen (CPU, RAM). Das Netzwerk ist per Allow‑List konfiguriert: Es ist nur der Zugriff auf die benötigten externen Dienste erlaubt (Ihr Commerce‑Backend, Payment, ein paar externe APIs), nicht das gesamte Internet.

Für Agent‑Szenarien ist das besonders kritisch: Das Modell könnte versuchen, zu irgendeiner „fremden“ API zu gehen oder unerwartete Dateien zu lesen – gut, wenn es selbst dabei physisch keine Rechte hat, auf zusätzliche Ressourcen zuzugreifen.

Im Code sieht das normalerweise nicht wie eine „magische TypeScript‑Zeile“ aus, sondern wie Einstellungen Ihres Orchestrators (Docker Compose, Kubernetes, Vercel, Fly.io usw.). Trotzdem ist es hilfreich, schon beim Design daran zu denken:

  • ein Tool, das fremden Code ausführt (z. B. Report‑Generierung mit Shell‑Kommandos), sollte in einer eigenen, strikt isolierten Umgebung laufen;
  • Tools sollten keine Möglichkeit haben, fremde Dateien, Secrets oder Konfigurationen zu lesen;
  • den Netzwerkzugriff begrenzt man besser explizit nach Domains oder IPs.

4. Secrets und vertrauliche Daten: Was ein Agent nicht wissen muss

Wo Secrets leben sollten – und wo nicht

Grundregel: Keine Secrets – API‑Keys, Passwörter, Access‑Tokens – dürfen in den Prompt des Modells, in das Widget, in Logs oder ins Repository gelangen. Sie leben:

  • in Umgebungsvariablen (process.env.SOMETHING),
  • in Secret‑Managern (AWS Secrets Manager, GCP Secret Manager, Vault usw.),
  • in separaten verschlüsselten Stores mit streng kontrolliertem Zugriff.

In unserem GiftGenius gibt es beispielsweise einen Key für das Commerce‑API des Shops. Wir brauchen, dass der Agent über ein MCP‑Tool einen Bestellentwurf anlegen kann, aber das Modell darf den Key nicht sehen.

// mcp/tools/createOrderDraft.ts
const COMMERCE_API_KEY = process.env.COMMERCE_API_KEY!;

export async function createOrderDraft(args: {
  userId: string;
  giftId: string;
  quantity: number;
}) {
  // Das Modell wird COMMERCE_API_KEY niemals sehen – er liegt nur hier auf dem Server
  const res = await fetch(`${process.env.COMMERCE_API_URL}/orders/draft`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${COMMERCE_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(args),
  });

  if (!res.ok) {
    throw new Error(`Commerce API returned ${res.status}`);
  }

  return res.json(); // In der Antwort geben wir dem Agenten bereits ein sicheres Objekt zurück
}

Wichtig: In der Tool‑Antwort sollten Sie keine Keys oder andere sensible Details „durchschleifen“. Dem Agenten reicht draftOrderId, die Artikelliste und ggf. ein Status.

PII und Datenminimierung im Kontext

Neben Secrets gibt es die Kategorie PII (personenbezogene Daten der Nutzer): Namen, Telefonnummern, Lieferadressen, E‑Mails usw. Der Agent braucht häufig nicht den gesamten „Rohtext“. Ausreichend ist ein strukturierter, aggregierter Profil‑Auszug: „mag Brettspiele“, „Alter 30–35“, „ungefähres Budget 50–70 $“.

Anstatt die vollständige Bestellhistorie in den Prompt zu werfen, können Sie ein Tool get_user_profile_summary bauen, das ein bereits aggregiertes und anonymisiertes Profil zurückgibt.

type ProfileSummary = {
  ageRange: '18-25' | '26-35' | '36-50' | '50+';
  interests: string[];
  preferredBudget: { min: number; max: number };
};

export async function getUserProfileSummary(userId: string): Promise<ProfileSummary> {
  // Hier greifen Sie auf die DB zu, geben aber nach außen nur aggregierte Informationen zurück
  return {
    ageRange: '26-35',
    interests: ['Brettspiele', 'Gadgets'],
    preferredBudget: { min: 30, max: 80 },
  };
}

Das Modell sieht genau so viel, wie es für die Geschenkauswahl braucht – und nicht mehr.

Scrubbing der Logs

Logs sind ein natürlicher Ort, an dem Secrets und PII versehentlich auftauchen. Besonders, wenn man einen „bequemen“ Logger wie console.log(...) schreibt und „alles“ ausgibt.

Ein guter Ansatz ist ein zentraler Logger, der vor dem Ausgeben die Payload durchläuft und sensible Felder maskiert.

type LogPayload = Record<string, unknown>;

const SENSITIVE_KEYS = ['email', 'phone', 'cardNumber', 'token'];

function scrub(payload: LogPayload): LogPayload {
  const result: LogPayload = {};
  for (const [key, value] of Object.entries(payload)) {
    if (SENSITIVE_KEYS.includes(key)) {
      result[key] = '***redacted***';
    } else {
      result[key] = value;
    }
  }
  return result;
}

export function logEvent(event: string, payload: LogPayload) {
  const safe = scrub(payload);
  console.log(JSON.stringify({ event, ...safe }));
}

Statt irgendwann einen Production‑Vorfall „wir loggen seit Monaten Telefonnummern und Tokens“ zu erleben, bauen Sie das System von Anfang an so, dass das schlicht unmöglich ist. Das ist nicht nur eine Frage der Sorgfalt, sondern auch künftiger Compliance‑Anforderungen (DSGVO und lokale Gesetze): Je weniger PII in Logs, desto einfacher das Produktleben.

5. Monitoring und Observability des Agenten

Was man konkret sehen sollte

Wir haben eingeschränkt, was der Agent tun darf, welche Daten er sieht und was in die Logs kommt. Nächste Frage: Wie verstehen wir, ob sich der Agent im Produktionsbetrieb so verhält, wie wir es intendiert haben?

„Service lebt / lebt nicht“‑Monitoring ist für Agenten fast nutzlos. Wichtig ist nicht nur zu wissen, dass der Prozess läuft, sondern sein Verhalten zu verstehen: welche Schritte er macht, welche Tools er aufruft, wo er scheitert, wo er in Schleifen gerät.

Minimaler Datensatz pro Run:

  • agent_run_id – eindeutiger Kennzeichner des Laufs;
  • anonymisierte user_id oder Session‑ID;
  • Name des Agenten und Umgebung;
  • Liste aufgerufener Tools: Name, Anzahl, Gesamtzeit;
  • Workflow‑Schritte und bei welchem Schritt gestoppt wurde;
  • Endstatus: success, partial_success, failed, canceled, timeout, limits_exceeded.

Das lässt sich als Struktur abbilden:

type RunStatus =
  | 'success'
  | 'partial_success'
  | 'failed'
  | 'canceled'
  | 'timeout'
  | 'limits_exceeded';

type ToolCallLog = {
  name: ToolName;
  durationMs: number;
  success: boolean;
};

type AgentRunLog = {
  runId: string;
  agentId: string;
  userId: string;
  env: Env;
  startedAt: string;
  finishedAt: string;
  status: RunStatus;
  toolCalls: ToolCallLog[];
  errorMessage?: string;
};

Beispiel einer „Wrapper“‑Funktion um den Agentenstart

Angenommen, Sie haben eine Funktion runAgent, die den eigentlichen Aufruf des Agents‑SDK kapselt. Wir umbrechen sie mit Monitoring:

async function runAgentWithLogging(
  agent: AgentConfig,
  input: string,
  userId: string,
): Promise<string> {
  const runId = crypto.randomUUID();
  const startedAt = new Date();

  const toolCalls: ToolCallLog[] = [];

  try {
    const result = await runAgent(agent, input, {
      userId,
      limits: defaultLimits,
      onToolCall: (name, durationMs, success) => {
        toolCalls.push({ name, durationMs, success });
      },
    });

    const finishedAt = new Date();

    const log: AgentRunLog = {
      runId,
      agentId: agent.id,
      userId,
      env,
      startedAt: startedAt.toISOString(),
      finishedAt: finishedAt.toISOString(),
      status: 'success',
      toolCalls,
    };

    logEvent('agent_run', log);
    return result;
  } catch (err) {
    const finishedAt = new Date();
    const log: AgentRunLog = {
      runId,
      agentId: agent.id,
      userId,
      env,
      startedAt: startedAt.toISOString(),
      finishedAt: finishedAt.toISOString(),
      status: 'failed',
      toolCalls,
      errorMessage: (err as Error).message,
    };
    logEvent('agent_run', log);
    throw err;
  }
}

Hier ist runAgent eine Blackbox, die über ein echtes Agents‑SDK implementiert sein kann; wir zeigen, wie man Observability ergänzt, ohne sich an eine konkrete API zu binden.

Logs vs. Metriken vs. Tracing

Es ist hilfreich, drei Ebenen der Observability zu unterscheiden:

Ebene Was ist das Beispiel für den Agenten GiftGenius
Logs „Geschichten“ über konkrete Runs Detaillierter AgentRunLog mit Schritten und Tools
Metriken Aggregierte Kennzahlen p95‑Dauer des Runs, durchschnittliche Zahl der Tool‑Calls, Error‑Rate
Tracing Baum/Graph von Anfragen und Unteranfragen Run → Schritte → Tool‑Calls → Aufrufe externer APIs (Commerce, DB usw.)

Metriken helfen zu verstehen „ist überhaupt alles OK?“ (z. B. Error‑Rate der letzten Stunde). Logs und Tracing helfen zu klären „warum ist es genau hier schlecht?“ und einen konkreten problematischen Run zu reproduzieren.

Einen einfachen Ansatz für Metriken kann man auf Logs aufbauen: Ein periodischer Job aggregiert agent_run‑Events und berechnet p95‑Dauern, Fehlerzahlen usw.

6. Wie das im Ganzen bei GiftGenius aussieht

Damit das nicht wie eine Ansammlung von Abstraktionen wirkt, setzen wir das Bild für unsere Lern‑App zusammen.

Der Agent gift-planner hat in der Produktionsumgebung nur sichere Tools: Geschenke finden und Details abrufen. Er sieht weder Zahlungen noch Bestellverwaltung. Seine Systemanweisungen sagen, dass er dem Benutzer nicht versprechen soll „ich bezahle alles für dich“, sondern maximal Empfehlungen vorbereitet und eventuell eine Entwurfs‑Geschenkeliste.

Der Agent order-manager existiert separat und kann nur mit Bestellungen arbeiten. In Produktion darf er nur einen Bestellentwurf erstellen (create_order_draft), während die Bestätigung (confirm_order) entweder vom Menschen über einen expliziten UI‑Trigger im Widget ausgeführt wird oder nur in dev/staging verfügbar ist. Seine Tools verwenden Secrets (Shop‑API‑Keys) ausschließlich auf der Backend‑Seite und geben in der Antwort nur die nötigen Felder weiter.

Beide Agenten werden über den Wrapper runAgentWithLogging gestartet, der Limits anlegt und Logs mit agent_run_id, userId, Umgebung und Tool‑Liste schreibt. In den Logs stehen weder E‑Mails noch Telefonnummern; diese Felder werden vorher vom Scrubber maskiert. Das Benutzerprofil wird in anonymisierter Form verwendet: Altersbereich, Interessen, Budget – nicht der vollständige Text der Kaufhistorie.

Die Infrastruktur, in der MCP‑Server und Agent‑Service leben, ist isoliert: Container mit schreibgeschütztem Dateisystem (außer /tmp oder einem speziell zugewiesenen Verzeichnis), CPU-/RAM‑Limits, Netzwerk per Allow‑List von Domains. Falls der Agent plötzlich „irgendetwas Fremdes“ aufrufen will, kommt er physisch nicht dorthin.

Wenn Sie irgendwann einen Ausschlag bei der Metrik „Anteil der Runs mit Status limits_exceeded“ oder „durchschnittliche Zahl der Tool‑Calls > 10“ sehen, wissen Sie: Entweder ist der Prompt zu geschwätzig geworden oder eines der Tools spinnt und zwingt den Agenten, Schritte neu zu starten.

Das ist das Verhalten eines erwachsenen Services – nicht eines experimentellen Agents nach dem Motto „wird schon irgendwie passen“.

7. Typische Fehler beim Gang in die Produktion

Alles, was wir oben besprochen haben, ist das „richtige“ Bild eines Produktions‑Agenten. In der Praxis stolpert man jedoch oft über typische Stolpersteine. Fassen wir sie in einer Liste zusammen: Wenn Sie zumindest diese Fehler vermeiden, verläuft der Produktionsstart deutlich ruhiger.

Fehler Nr. 1: Dem Agenten ist „alles erlaubt“.
Häufiges Szenario: Sie haben viele MCP‑Tools beschrieben (Suche, Änderung, Löschung, Zahlungen) und dem Agenten beim Erstellen einfach die gesamte Liste gegeben. Das Modell kann dadurch versehentlich Löschen oder Zahlen aufrufen, wo Sie nur Lesen wollten. Heilbar durch Trennung der Tools nach Rollen und das Erstellen mehrerer enger gefasster Agenten, von denen jeder seine eigenen allowedTools hat.

Fehler Nr. 2: Rechteprüfung nur im Prompt.
Manchmal schreiben Entwickler in die Systemanweisungen: „Kaufe niemals etwas ohne Bestätigung des Benutzers“ und beruhigen sich. Aber der Prompt ist ein schwacher Schutz, und Jailbreaks oder Fehler sind nicht ausgeschlossen. Es braucht echte Prüfungen auf Backend‑Ebene: „Ist dieses Tool dem Agent erlaubt?“ und „Ist dieses Tool dem Benutzer erlaubt?“, sonst kann eine unvorsichtige Generierung zu Handlungen führen, mit denen niemand gerechnet hat.

Fehler Nr. 3: Secrets in Prompts und Logs.
Mitunter möchte man die Integration „beschleunigen“ und legt den API‑Key einfach in den System‑Prompt oder übergibt ihn als Tool‑Argument, damit der Agent selbst eine externe API aufruft. Am Ende landet der Key sowohl in den Logs des Modells als auch potenziell in Fremdsystemen. Das ist ein direkter Weg zu Leaks und zum Bann im Store. Secrets müssen ausschließlich auf der Serverseite leben, in Umgebungsvariablen oder Secret‑Managern, und dürfen nie in den Modellkontext gelangen.

Fehler Nr. 4: „Rohlogs“ ohne Scrubbing.
Beim Debuggen ist es bequem, console.log(...) zu schreiben und es dabei zu belassen. Nach ein paar Monaten stellt sich heraus, dass in den Logs Nutzeradressen, Telefonnummern und Bestellnummern mit PII liegen. Besonders unangenehm in der Welt der DSGVO und anderer Regulierungen. Richten Sie lieber sofort einen zentralen Logger ein und führen Sie automatisches Maskieren sensibler Felder ein – selbst wenn es scheint, „wir loggen nur in dev“.

Fehler Nr. 5: Keine Limits für das Agentenverhalten.
Ohne Limits für Schritte, Zeit und Anzahl der Tool‑Aufrufe kann der Agent in Schleifen geraten: immer wieder dasselbe Tool aufrufen, denselben Fehler endlos zu „korrigieren“ versuchen, Unmengen an Token verbrauchen und externe APIs belasten. Im besten Fall erhalten Sie riesige Rechnungen für Modelle, im schlimmsten Fall legen Sie das Backend lahm und verärgern alle Nutzer. Limits für den Run‑Zyklus und sinnvolle Defaults für Timeouts sind Pflichtbestandteil der Konfiguration.

Fehler Nr. 6: Mischen von Read‑ und Write‑Operationen in einem Tool.
Mitunter entstehen „bequeme“ Methoden wie getOrCreateOrder, die bei fehlender Bestellung eine neue erstellen. Für klassisches Backend ist das ein zulässiges Muster, in der Agentenwelt kann es jedoch zu unerwarteten Nebeneffekten führen: Das Modell wollte nur den Zustand abfragen, das Tool hat aber etwas erstellt. Viel sicherer ist es, get_order_details und create_order_draft zu trennen – dann sind selbst bei Wiederholungen die Folgen besser kontrollierbar.

Fehler Nr. 7: Ignorieren von Observability.
Viele starten mit „Logs und Metriken bauen wir später an, Hauptsache es läuft“. Agenten ohne Monitoring sind eine Blackbox: Sie wissen nicht, welche Tools sie aufrufen, wie viele Schritte sie machen, wo sie scheitern. Jede Nutzerbeschwerde wird zur Ermittlung im dunklen Raum. Es ist viel einfacher, sofort eine Log‑Struktur (agent_run_id, Tools, Status) und Basis‑Metriken vorzusehen, als das später über chaotischen Code zu stülpen.

1
Umfrage/Quiz
Agenten-Orchestrierung, Level 12, Lektion 4
Nicht verfügbar
Agenten-Orchestrierung
Agenten-Orchestrierung mit dem Agents SDK
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION