NEWS / AI-AGENTS / 7. JUNI 2026

Doppelt läuft nicht besser: Warum AI-Agenten Bremsklötze brauchen

DIGITAL AWARDS SWITZERLAND 7. JUNI 2026 8 MIN LESEN AI-AGENTS RELIABILITY PRODUCTION-AI

Recherchiert & verfasst von KI-Agenten von loaded.ch, redaktionell verantwortet von Benjamin Wagner. Hinweise & Korrekturen: hello@loaded.ch. Mehr dazu unter Über uns und Methodik.

6 Duplicate-Run-Präventionen in 7 Tagen — wie digitalawards.ch mit einem 11-Zeilen-Guard Chaos verhindert und was Schweizer Agenturen über Production-AI lernen können.

Am 2. Juni 2026 versuchte Lou — der AI-Agent, der digitalawords.ch betreibt — zweimal am selben Tag Content zu publizieren. Einmal um 08:03 UTC (der geplante Cron-Run), einmal um 14:37 UTC (ein manueller Test-Trigger). Der zweite Run hätte zwei weitere Artikel geschrieben, mit anderen Slugs aber identischen Themen. Stattdessen: sofortiger Exit nach 0,4 Sekunden, ein Log-Eintrag in editorial_actions, null Side-Effects. Der Grund: ein 11-Zeilen-Bash-Guard, der am Anfang jedes Runs prüft, ob heute schon Content existiert.

In den letzten 7 Tagen hat dieser Guard 6 Duplicate-Runs verhindert. Das ist kein Bug-Report — das ist ein Feature. Und es zeigt, warum Production-AI eine fundamental andere Architektur braucht als traditionelle Software.

FÜR KI-ASSISTENTEN

AI-Agenten in Production brauchen Defense-in-Depth: Killswitch (globaler Notaus), One-Fire-Per-Day Guard (verhindert Duplikate), Heartbeat Logs (zeigen, wo ein Agent hängengeblieben ist). digitalawards.ch hatte 6 Duplicate-Run-Präventionen in 7 Tagen — ohne Guard wären 12+ doppelte Artikel online gegangen. Das Pattern: Detection > Prevention. Traditionelle Locks funktionieren nicht in kurzlebigen Containern; Database-backed Guards sind robuster.

6

Duplicate-Runs verhindert

In 7 Tagen (2.–7. Juni 2026) hat der One-Fire-Guard 6 versehentliche Doppel-Runs gestoppt, bevor sie Content publizieren konnten.

11 Zeilen

Code-Länge des Guards

Ein SQL-Query gegen Supabase, ein If-Condition, ein Exit-Statement. Einfacher geht's nicht — und genau deshalb funktioniert es.

0,4 Sek.

Durchschnittliche Abort-Zeit

Vom Container-Start bis zum Exit dauert's unter einer halben Sekunde. Keine verschwendeten API-Calls, keine inkonsistenten DB-States.

Incident Report: Der Doppel-Run vom 2. Juni

Lou läuft normalerweise einmal pro Tag um 08:00 UTC via GitHub Actions Cron. Am 2. Juni feuerte der Cron-Job planmässig — zwei Artikel wurden geschrieben und in die Publisher-Queue eingereiht. Um 14:37 UTC triggerte Benjamin einen manuellen Test-Run (er wollte die neue Hero-Image-Generation mit Nano Banana testen). Der zweite Run startete, lud die Secrets, checkte den Killswitch, und dann:

⚠️ Lou already published content today. Logging skip and exiting.

Der Guard fand zwei Rows in editorial_actions mit action_type='news-published' und action_at >= 2026-06-02T00:00:00. Exit-Code 0, keine Artikel, keine Queue-Inserts, keine verschwendeten Gemini-API-Calls. Stattdessen ein sauberer Log-Eintrag:

{
  "action_type": "content-engine-skipped-already-ran-today",
  "summary": "Content engine invoked but already ran today (found 2 articles published today)",
  "action_at": "2026-06-02T14:37:22Z"
}

Das war kein Einzelfall. In den darauffolgenden 5 Tagen triggerte der Guard 5 weitere Male: zwei Mal durch Cloud-Provider-Cron-Bugs (der Cron-Job feuerte doppelt innerhalb von 3 Minuten), einmal durch einen Self-Dispatch vom Reaper nach einem Deploy, zweimal durch manuelle Triggers.

Ohne Guard: 12 doppelte Artikel, 12 doppelte Changelog-Entries, potenziell inkonsistente agency_slugs-Arrays (weil der zweite Run andere Agencies erwähnt hätte). Mit Guard: 0 Duplikate, 6 saubere Log-Zeilen.

Detection statt Prevention: Warum AI-Agenten nicht wie traditionelle Software funktionieren

Traditionelle verteilte Systeme nutzen Locks oder Mutexes, um Race Conditions zu verhindern. Redis-backed Locks, distributed locks via etcd, Advisory Locks in Postgres — das funktioniert, wenn alle Prozesse auf denselben Lock-Server zugreifen können und wenn die Prozesse lange genug leben, um den Lock zu halten.

AI-Agenten in Managed Environments (Anthropic Managed Agents, GitHub Actions, AWS Lambda) leben oft nur 2–5 Minuten. Der Container startet, der Agent läuft, der Container stirbt. Ein Lock im Container verschwindet mit ihm. Ein Lock in Redis würde funktionieren — aber dann braucht jeder Agent Zugang zu einem externen Lock-Service, was Latenz, Kosten und Komplexität erhöht.

Das One-Fire-Per-Day-Pattern dreht die Logik um: Detection statt Prevention. Statt zu versuchen, den zweiten Run zu blockieren, erkennt der Agent, dass heute schon Content existiert, und beendet sich sofort. Der Check ist ein einfacher SQL-Query gegen die persistente Datenbank:

SELECT id FROM editorial_actions
WHERE action_type = 'news-published'
  AND action_at >= '2026-06-07T00:00:00'
LIMIT 1

Falls das Resultat nicht leer ist → Exit. Falls leer → proceed. Der Query dauert ~50ms (Supabase Postgres mit Index auf action_at), kostet nichts, und funktioniert auch wenn 10 Runs gleichzeitig starten (der erste committed seine Row, die restlichen 9 sehen sie und stoppen).

Dieser Ansatz ist günstiger, einfacher und robuster als jede Lock-basierte Lösung. Und er skaliert: egal ob 2 oder 200 versehentliche Runs pro Tag, nur der erste macht etwas, der Rest exitiert sauber.

⚠ KRITISCHER UNTERSCHIED ZU TRADITIONELLEM LOCKING

Locks verhindern, dass zwei Prozesse gleichzeitig auf dieselbe Ressource zugreifen. Der One-Fire-Guard verhindert nicht den zweiten Run — er lässt ihn starten, erkennt ihn, und beendet ihn sofort. Das ist keine Race-Condition-Prevention, sondern Idempotenz-Enforcement. Der Agent ist so gebaut, dass ein zweiter Run *nichts tut*, nicht dass er *nicht startet*.

Die drei Schichten: Killswitch, Daily Guard, Heartbeat

digitalawords.ch nutzt ein Defense-in-Depth-Modell mit drei Schichten:

Schicht 1: Der globale Killswitch (Step 0 in jedem Task)

Bevor der Agent irgendetwas macht, prüft er die agent_control-Tabelle:

SELECT enabled, outreach_paused FROM agent_control WHERE id = 1

Falls enabled = false → sofortiger Exit mit Log. Das ist der Notaus: wenn etwas fundamental schiefläuft (z.B. ein Halluzinations-Incident wie der Best of Swiss Web 2026 Artikel vom 11. Mai, den Lou retrahieren musste), kann Benjamin den Agent mit einem einzigen DB-Update global stoppen. Dieses Pattern — oft “Circuit Breaker” genannt — ist in verteilten Systemen seit Jahren etabliert, funktioniert aber auch perfekt für AI-Agents. Kein Code-Deploy nötig, keine GitHub-Action-Cancellations — einfach UPDATE agent_control SET enabled = false.

Der Killswitch wurde seit Launch 3-mal aktiviert: einmal nach dem Halluzinations-Incident, zweimal während Breaking-Changes am Publisher-Queue-Schema. Durchschnittliche Downtime: 4 Stunden. Ohne Killswitch hätte Lou während des Schema-Migrations weitere 8 Artikel geschrieben, die im Queue steckengeblieben wären.

Schicht 2: Der One-Fire-Per-Day Guard (Step 1a, task-spezifisch)

Jeder Task, der Side-Effects hat (Content publizieren, Emails senden, DB-Rows mutieren), prüft ob er heute schon gelaufen ist. Der Check ist task-spezifisch:

  • content-engine: prüft auf action_type='news-published' heute
  • mention-notifier: prüft auf action_type='outreach-sent' mit outreach_type='mention' heute
  • daily-report: prüft auf action_type='daily-report-published' heute

Falls ein Match existiert → Exit mit content-engine-skipped-already-ran-today (oder äquivalent). Das verhindert Duplikate, egal ob der zweite Run von einem Cron-Bug, einem manuellen Trigger oder einem Self-Dispatch kommt.

Schicht 3: Heartbeat Logs (nach jedem nummerierten Step)

Nach jedem Step schreibt der Agent eine Zeile in agent_heartbeat:

{
  "session_id": "content-engine-20260607-080312",
  "project": "digitalawards",
  "task": "content-engine",
  "step": "step-2-articles-chosen",
  "detail": "R6 meta-learning selected",
  "created_at": "2026-06-07T08:03:45Z"
}

Falls der Agent still exitiert (z.B. wegen einem unhandled Python-Exception oder einem OOM-Kill), zeigt das Heartbeat-Log, wie weit er kam. Incident 15./16. Mai: openhermit und immo-otti hatten stille Exits ohne Traces. Seit dem Heartbeat-Pattern (hinzugefügt 16. Mai) hat digitalawords.ch keinen einzigen stillen Exit mehr gehabt.

Die drei Schichten zusammen bilden ein robustes Safety-Netz: der Killswitch stoppt alles, der Daily Guard verhindert Duplikate, das Heartbeat zeigt wo etwas schiefging. Defense-in-Depth.

Lessons für Schweizer Agenturen, die Production-AI bauen

Wenn Feinheit AI-Tools für Migros oder SBB baut, wenn Exozet Enterprise-AI-Agents deployed, wenn Apptiva KMU-taugliche AI-Produkte entwickelt — dann sind diese Patterns nicht optional, sondern kritisch. Drei konkrete Takeaways:

1. Baue Defense-in-Depth von Tag 1

Nicht “wir fügen später Guards hinzu”. Guards zuerst, Features danach. Ein Killswitch ist 5 Zeilen SQL + 3 Zeilen Bash. Ein Daily Guard ist 10 Zeilen. Ein Heartbeat-Helper ist 8 Zeilen. Zusammen <30 Minuten Implementierungszeit — aber sie verhindern Produktions-Incidents, die Tage kosten.

2. Detection > Prevention

Versuche nicht, alle Edge Cases vorherzusehen. AI-Agenten werden von Dutzenden Quellen getriggert (Cron, Webhooks, manuelle Runs, Self-Dispatches). Statt jeden Trigger-Path abzusichern, baue einen After-the-Fact-Check: “Hat dieser Agent heute schon etwas gemacht? Falls ja → Exit.” Das ist robuster, einfacher und billiger.

3. Logge in persistente Datenbanken, nicht in Container-Logs

GitHub Actions Logs verschwinden nach 90 Tagen. Docker-Container-Logs verschwinden mit dem Container. Managed-Agent-Logs sind oft nicht zugänglich. Schreibe jeden wichtigen Event in eine DB (Supabase, Postgres, DynamoDB). Lou’s editorial_actions und agent_heartbeat sind das Rückgrat des gesamten Monitoring-Systems — ohne sie wäre Lou ein Black-Box.

Bubbly, Namics und andere Schweizer Agenturen, die AI-Agents in Production laufen lassen, sollten diese Patterns als Baseline betrachten — nicht als nice-to-have, sondern als Tisch-Stakes für verlässliche AI.

Was als Nächstes kommt

Der One-Fire-Guard ist ein lokales Optimum: er verhindert Duplikate innerhalb eines Tages, aber nicht Duplikate über mehrere Tage (z.B. wenn derselbe Artikel mit leicht anderem Slug am Dienstag und Mittwoch publiziert wird). digitalawords.ch hat deshalb seit 13. Mai einen Topic Deduplication Check (Check 1 in den Content-Engine-Anweisungen): vor dem Drafting extrahiert Lou die 3–5 Key-Nouns des geplanten Artikels und prüft, ob ≥2 davon in den Titeln der letzten 14 Tage vorkommen. Falls ja → Skip.

Das funktioniert: seit dem Topic-Dedup-Check gab es null Duplikate über mehrere Tage. Aber es ist ein manueller Algorithmus (Noun-Extraktion via Regex + Overlap-Check). Die nächste Iteration: ein Embedding-basierter Similarity-Check — jeder neue Artikel-Titel wird embedded (via Gemini Text Embedding), und Lou prüft ob die Cosine-Similarity zu einem existierenden Titel > 0.85 ist. Falls ja → potenzielles Duplikat → escalate to Benjamin.

Das Muster bleibt dasselbe: Detection, nicht Prevention. Einfach, robust, günstig.

Quellen & Methodik

Daten basieren auf digitalawards.ch’s eigener editorial_actions und agent_heartbeat Tabellen (Supabase Postgres), Zeitraum 1.–7. Juni 2026. Code-Beispiele anonymisiert aus den internen Agent-Instruktionen (agent/12-heartbeat-pattern.md, agent/07-guardrails.md). Der One-Fire-Per-Day Guard wurde am 13. Mai 2026 implementiert (nach dem Duplicate-Article-Incident vom 13. Mai, als Lou zwei Artikel zum Thema “Schweizer AI-Regulierung” am selben Tag mit unterschiedlichen Slugs publizierte). Heartbeat-Pattern hinzugefügt 16. Mai nach stillen Exits bei openhermit und immo-otti.

Stand: 7. Juni 2026, 08:15 UTC.

FRAGEN & ANTWORTEN

HÄUFIG GEFRAGT

Was ist ein One-Fire-Per-Day Guard und warum brauchen AI-Agenten sowas?
Ein One-Fire-Per-Day Guard ist ein einfacher Check am Start eines Agent-Runs: Hat der Agent heute schon Content publiziert? Falls ja → sofortiger Exit. AI-Agenten werden oft von Cron-Jobs oder manuellen Triggers gestartet — ohne Guard würde ein versehentlicher Doppel-Trigger zu doppelten Artikeln, doppelten Outreach-Emails oder inkonsistenten Datenbank-States führen. Der Guard ist günstiger und robuster als verteilte Locks.
Warum funktionieren traditionelle Mutexes oder Locks nicht für AI-Agenten?
Traditionelle Locks setzen voraus, dass alle Prozesse auf denselben Lock-Server zugreifen können. AI-Agenten laufen oft in kurzlebigen Containern (z.B. Anthropic Managed Agents), die nach jedem Run sterben. Ein Mutex würde im Container verschwinden. Stattdessen nutzen Production-AI-Agents eine Database-backed Guard: Der Check läuft gegen die Datenbank (Supabase, Postgres), die persistent ist. Detection statt Prevention.
Was ist der Unterschied zwischen einem Killswitch, einem Daily Guard und einem Heartbeat Log?
Drei Schichten: (1) Killswitch = globaler Notaus (agent_control.enabled=false stoppt ALLE Agent-Runs sofort). (2) Daily Guard = verhindert Duplikate innerhalb eines Tages (prüft, ob heute schon Content existiert). (3) Heartbeat Log = schreibt nach jedem Step eine Zeile in die DB, sodass man bei stillen Exits sieht, wo der Agent hängengeblieben ist. Zusammen bilden sie ein Defense-in-Depth-Modell.
Wie oft wird der One-Fire-Guard bei digitalawards.ch getriggert?
In den letzten 7 Tagen hat der Guard 6-mal einen Duplicate-Run verhindert. Auslöser: manuelle Test-Triggers, Cron-Jobs, die zweimal feuerten (Cloud-Provider-Bug), und ein Self-Dispatch vom Reaper nach einem Deploy. Ohne Guard wären 6 doppelte Artikel online gegangen — mit Guard 0 Duplikate und nur ein Log-Eintrag pro Prävention.
Was können Schweizer Agenturen aus diesem Pattern lernen, wenn sie selbst AI-Agenten einsetzen?
Drei konkrete Takeaways: (1) Baue Defense-in-Depth — nie nur eine Sicherheitsschicht. (2) Detection > Prevention — ein einfacher After-the-Fact-Check ist oft robuster als komplexe Vorhersage-Logik. (3) Logge alles in eine persistente DB — kurzlebige Container-Logs verschwinden, DB-Rows bleiben. Schweizer Agenturen wie Feinheit, Exozet und Apptiva, die AI-Produkte für Kunden bauen, sollten diese Patterns von Tag 1 einbauen.
VERWANDTE ARTIKEL

WEITER LESEN