Startseite / Artikel

Aufschreiben der Schleifen, die ein KI-Agent in einer mobilen App ausführt.

Aufschreiben der Schleifen, die KI-Agenten in einer mobilen App ausführen: vier Fragen, die jede Schleife beantworten muss, sechs verschachtelte Schleifen vom Tippen bis zum Schneiden sowie Überprüfungen, die nichts feststellen.

Verlag: REACTAPP.TOP9 Min. Lesezeit2122 Wörter

Quellen: Loop Engineering on a Mobile App: What My AI Agent Runs, What It Reads, What Ends It, and When It Asks Me

Sagen Sie einem Agenten nur, dass er den Anmeldetest bestehen soll – dann entwirft er den Schleifenalgorithmus selbst in Echtzeit. In der Regel folgen dann zwei Möglichkeiten: Entweder versucht er es immer wieder, bis irgendetwas als erfolgreich angezeigt wird, auch wenn der Test nun weniger Anforderungen prüft, oder er liest seinen eigenen Protokollauszug, stellt keinen Fehler fest und gibt an, dass die Aufgabe abgeschlossen ist. Beide Verhaltensweisen sind Schleifen, und in beiden Fällen wählte das Modell den Algorithmus basierend auf dem, was es zufällig las.

Durch das Schleifen-Engineering wird diese Entscheidungsmöglichkeit dem Modell entzogen. Eine Person entscheidet im Voraus schriftlich, was ausgeführt wird, was das Modell zur Entscheidungsfindung liest, was die Ausführung beendet sowie wann es anhalten und einen Menschen um Hilfe bitten muss. Hier wird dieses Konzept auf eine Mobile-App angewandt.

Die Einrichtung

Das beispielhafte Projekt ist eine Sprachnachrichten-App für Android und iOS, die größtenteils mithilfe von Claude Code entwickelt wurde. Jede Sitzung erhält einen separaten Git-Checkout, der als Worktree bezeichnet wird. Darin baut das Agent die App, installiert sie auf einem Emulator, steuert die Benutzeroberfläche über Maestro – einen YAML-Testlaufwerkzeug, das den Zugänglichkeitsbaum des Bildschirms liest (die vom Betriebssystem bereitgestellten beschrifteten Steuerelemente) – und speichert seine Arbeit. Nichts in den Schleifen hängt von dieser spezifischen App ab; sie benötigen lediglich ein Agent, das handeln und anschließend beobachten kann.

Das „Harness“ sind die Werkzeuge, Dateien, Geräte und Regeln, die bestimmen, was das Agent sieht und tut. Die Schleifen beziehen sich auf etwas anderes, nämlich darauf, wie sich das Agent im Laufe der Zeit mit diesem Harness verhält.

Die vier Fragen

Betrachten Sie den kleinsten Schleifenzyklus: Tippen Sie auf eine Schaltfläche, lesen Sie den Zugänglichkeitsbaum und überprüfen Sie, ob die erwartete Beschriftung angezeigt wurde. Falls nicht, warten Sie und lesen Sie erneut – bei zehn Sekunden Versuch fehlschlagen Sie. Unabhängig von der Größe eines Schleifenzyklus in einer Agentenkonfiguration, bis hin zur Frage „Ist diese Funktion abgeschlossen?“, muss dieser vier Fragen beantworten:

  1. Was wird ausgeführt?
  2. Was liest es, um eine Entscheidung zu treffen?
  3. Was beendet den Zyklus?
  4. Wann stoppt er und bittet einen Menschen um Hilfe?

Ohne alle vier Antworten handelt es sich nicht um eine Schleife, sondern nur um ein Skript, das einmal ausgeführt wird und darauf hofft. Die Beantwortung dieser Fragen für jede Schleife, die der Agent ausführt, bildet die gesamte Disziplin – der Rest sind Beispiele.

Schleife 3, Anmelden, zeigt die vier Antworten auf einem echten Assistenten. Jeder staatsspezifische Testfluss beginnt damit:

- launchApp:
    stopApp: true                    # 1. what runs: a cold launch, every time
- retry:
    maxRetries: 3                    # 3. what ends it: Home on screen, or three tries
    commands:
      - runFlow:
          when:
            visible:
              text: "Continue"       # 2. what it reads: the Login screen's button
          file: login.yaml           #    -> sign in only if it's showing
      - runFlow: assert-home.yaml    #    -> then prove Home is on screen
# 4. when it asks a human: never. A fourth failure is red, and red is the answer.

Eine physische Ursache erklärt das erneute Versuchen. Unmittelbar nach einem Neustart bedeckt der Startbildschirm sowohl das Anmelde- als auch das Startmenü für etwa drei Sekunden, sodass beim ersten Blick weder eines sichtbar ist. Die Obergrenze liegt bei drei Versuchen. Ein einfaches „Weitermachen, bis das Startmenü erscheint“ würde bei einer fehlerhaften Konfiguration niemals enden, während drei Versuche auch einen langsamen Start ausgleichen und trotzdem bei einem echten Fehler eine rote Anzeige ermöglichen.

Sechs verschachtelte Schleifen

Die sechs Schleifen laufen von der kleinsten zur größten und jede befindet sich innerhalb der nächsten. Schleife 1 wird in jedem Test Dutzende Male ausgeführt, jeder Test läuft innerhalb einer Ausführung mit zwei Geräten, jede Ausführung innerhalb der Überprüfungen eines Commits und jeder Commit innerhalb eines Arbeitsteils.

Bauen Sie zunächst die innigste Schleife, da alle äußeren Schleifen von ihr abhängen. Schleifen 1, 3 und 6 sind die Tastenschleife, die Anmeldung sowie der Geräteverleih. Drei der übrigen Schleifen erfordern eine Erklärung.

Loop 2 ist ein begrenzter Wiederholungsversuch. Bei leeren Caches kann der erste „kalte“ Build in einem neuen Worktree im Kotlin-Compiler abstürzen. Die Speicherdatei des Agents enthält eine einzeilige Regel: Es soll einmal wiederholt werden, bevor man davon ausgeht, dass eine Änderung getestet wird. Diese Grenze ist wichtig – unbegrenzte Wiederholungsversuche bis zum Erfolg würden einen echten Fehler überdecken, während ein einziger Wiederholungsversuch bekannte Probleme beseitigt und einen zweiten Fehler bedeutungsvoll macht.

Loop 4 ist der pre-commit-Hook. In diesem Repository gibt es kein CI, daher ist dieser Hook die einzige Schleife, die bei jeder Änderung automatisch ausgelöst wird. Er führt zu einem fehlgeschlagenen Commit, wenn der Geheimnis-Scanner gitleaks fehlt. Zudem werden die eigenen Tests der Gates bereits vor deren Ausführung gestartet, da eine Gate, die ihre Eingaben nicht finden kann, einfach „OK“ ausgibt. Kurz gefasst lautet die Regel:

#!/bin/sh
set -u
if ! command -v gitleaks >/dev/null 2>&1; then
    echo "pre-commit: gitleaks not found — refusing to commit without a secret scan." >&2
    exit 1
fi
gitleaks git --pre-commit --staged --redact --no-banner || exit 1

Der zweite Teil sieht so aus:

# The gates' own tests run first: a discovery bug produces no answer,
# after which every gate iterates an empty list and prints OK.
python3 ./scripts/test_gates.py >/dev/null 2>&1 || exit 1for gate in check_string_parity audit_hardcoded_strings; do
    [ -x "./scripts/$gate.sh" ] && { "./scripts/$gate.sh" || exit 1; }
done

Loop 5 ist die äußere Schleife, die jede Arbeitseinheit umfasst. Ein Slice ist ein kleiner, versandfähiger Teil einer Funktion und durchläuft vier Schritte. In diesem Schritt wird das Änderungsprotokoll mit dem Was, dem Warum sowie den Akzeptanzkriterien erstellt. Im nächsten Schritt wird die Änderung umgesetzt. Im dritten Schritt wird das Ergebnis gegen dieses Protokoll überprüft. Im vierten Schritt werden die Spezifikationen synchronisiert und der Slice abgeschlossen. Die Überprüfung ist ein eigener Schritt mit eigenem Ausgabeergebnis – es handelt sich dabei nicht um eine nachträgliche Bemerkung des Implementierers, dass die Tests bestanden haben – sodass nicht nur der Agent, der den Code geschrieben hat, für dessen Qualität haftet.

Menschliche Kontrollpunkte sind in einer schriftlichen Tabelle dargestellt, die zeigt, welche Entscheidungen der Agent allein trifft und welche zunächst geprüft werden müssen. Eine einzige Regel gilt für diese Tabelle: Man soll zuerst prüfen, ob das Umkehren der Änderung mehr als etwa einen Tag an Nacharbeit kosten würde. Ein Agent, der einen Schritt überspringt, muss anhalten, dies erklären und Genehmigung einholen.

Das Gedächtnis ist das, was Informationen zwischen Schleifen und über Sessions hinweg weitergibt: eine Sammlung kurzer Notizen, die Claude Code jedes Mal neu liest, wenn eine Session beginnt. Dieses Projekt enthält 52 solcher Notizen, jede davon eine Regel in derselben Form wie die der Schleife 2. Ohne sie wiederholt eine neue Session die frühere Diagnose von vorne.

Prüfungen, die nicht fehlschlagen können

Sämtliche Schleifen enden, wenn eine Prüfung „erledigt“ anzeigt. Eine Prüfung, die „erledigt“ anzeigt, ohne etwas zu finden, bricht die Schleife stillschweigend ab. Das ist in diesem Repository fünfmal passiert.

Eine Schleuse, die nicht versagen konnte. Eine Lokalisierungsschleuse war ein Skript, das einen Commit blockierte, wenn englische Texte in der Benutzeroberfläche hardcodet waren und nicht aus dem Stringkatalog gelesen wurden. Es enthielt einen Filter mit dem Namen filter_animation_labels, der dazu diente, nur solche Einträge auszuschließen, die wie Animationsschilder aussahen. Der Filter prüfte in awk window ~ tagbuilder, doch es wurde niemals ein tagbuilder an awk übergeben. Eine ungesetzte awk-Variable ist eine leere Zeichenkette, und window ~ „“ stimmt mit allem überein, wodurch der Filter alle gefundenen Einträge verworfen hat. Die Schleuse wurde niemals aktiviert.

Der Filter fand 49 hardcodierte Zeichenketten in insgesamt 14 Dateien innerhalb der Notfallfunktion der App – darunter eine englische contentDescription für die SOS-Taste neben einer ungenutzten Übersetzung. Aufnahmen des Geräts zeigten alle tatsächlichen Lokalisierungsfehler in diesem Bereich, während der Prüfmechanismus keine feststellte. Als Endbedingung für Schleife 4 überprüfte er zwei Tage lang jeden Commit, ohne etwas aufzudecken.

Ein Prüfmechanismus, der zu nichts führte. Die Spezifikationen verlangten, dass der Build fehlschlägt, doch nichts sorgte dafür, da es keine CI-Systeme gibt. Auch der erste Entwurf des Hooks verwendete exec gitleaks, was den Shell-Prozess ersetzt und somit die Ausführung späterer Befehle verhinderte.

Ein Hook, der auf alles reagierte. Ein if:-Muster kann die Hooks von Claude Code auf bestimmte Befehle beschränken. Ein Hook, der für gh pr create vorgesehen war, verwendete nur Bash(gh pr create *) – was zu eng gefasst war. Muster, die über den reinen Befehlnamen hinausgehen, versagen bei Begegnung mit $(), $VAR oder Heredocs. Die Lösung bestand darin, if: Bash(gh *) zu verwenden, wobei das Skript selbst den aus stdin eingelesenen Befehl filtert.

Ein Suite, die nichts testete. Drei Wochen lang scheiterten die iOS-Testabläufe bereits beim ersten Klick, ohne dass etwas rot angezeigt wurde, da überhaupt keine Tests ausgeführt wurden. Der Schritt, der eigentlich den SOS-Button prüfen sollte, meldete „COMPLETED“, obwohl er nichts tat; dadurch ergaben sich bei einem SOS-Test identische Bestehenergebnisse sowohl für funktionierenden als auch für fehlerhaften Code.

Eine Prüfung, die für das Falsche positiv ausfällt. Drei grüne Ergebnisse bezogen sich auf eine APK, die in einer anderen Sitzung installiert worden war. Ein Spezifikationsvalidator genehmigte 182 von 182 Spezifikationen, obwohl eine davon eine Monate zuvor gelöschte Anzeige beschrieb. Ein PATCH erhielt von einem Backend, das die Migration noch nicht erhalten hatte, den Status 200 und ignorierte das Feld stillschweigend.

Bevor eine Prüfung Vertrauen erlangt, muss zunächst genau das Defekt wiederhergestellt werden, für dessen Erkennung sie konzipiert ist, und überprüft werden, ob sie rot anzeigt; anschließend wird das Defekt entfernt und überprüft, ob sie grün anzeigt – und das alles in derselben Sitzung, in der die Prüfung erstellt wurde. Das Dokumenten-Auditskript folgte diesem Verfahren: Jedes Mal, wenn die Prüfung rot anzeigte, wurde der Status geändert, ein fehlender Link hinzugefügt oder ein Delta entfernt. In den Designnotizen wird dieses Prinzip in einem Satz zusammengefasst: Eine Prüfung, die nicht fehlschlagen kann, ist nur Dekoration. Zudem wird keine Baseline-Datei gespeichert, da das Ausblenden von 292 bekannten Fehlern, um einen grünen Status zu erreichen, als Abdeckung gewertet wird.

Wo anzufangen

Fangen Sie damit an, die vier Antworten vor jedem Code als Kommentar oben im Flow-, Skript- oder Regeltext zu schreiben. Eine fehlende Antwort wird dann sofort sichtbar und nicht innerhalb eines stillschweigend abgeschlossenen Ablaufs.

Danach kommt die kleinste Schleife, die Tap-Schleife, die zwei Anforderungen hat. Die Steuerelemente müssen Labels enthalten: contentDescription oder testTag für Android, accessibilityLabel für iOS. Zudem benötigt der Agent eine permanente Regel für jede Interaktion mit dem Bildschirm. Diese Regel befindet sich in der Anleitungsdatei des Repositoriums, die Claude Code zu Beginn jeder Sitzung lädt, und lässt sich wie folgt zusammenfassen:

Driving the emulator:
- Before every tap: `adb shell uiautomator dump`, and find the label you intend to tap.
- Tap the centre of that node's bounds. Never reuse a coordinate from an earlier dump.
- After the tap: dump again and confirm the expected label appeared. Poll up to 10 s,
  then stop and report red — do not guess a second tap.
- If the app won't launch: `pm dump <pkg> | grep enabled=` before suspecting the build.

Diese vier Sätze bilden einen Schleifenablauf, den der Agent ausführt. Ausgeführt werden dabei „dump“, „tap“ und erneut „dump“. Er liest den Baum ein. Der Ablauf endet entweder bei dem erscheinenden Label oder nach 10 Sekunden. Er fragt niemals einen Menschen, denn Rot ist die Antwort.

Zum Schluss: Bevor man dem Prüfverfahren, das die Schleife schließt, vertraut, sollte man sie absichtlich unterbrechen. Ändern Sie den Namen des Labels und prüfen Sie, ob die Schleife rot wird. Bleibt sie grün, wird nichts gelesen.

Die gesamte Einrichtung besteht aus sechs Komponenten:

  1. Eine Tap-Schleife, wie die obige Regel im Anweisungsfile des Agents festgelegt. Alles Weitere setzt voraus, dass der Agent handeln und anschließend prüfen kann.
  2. Ein vor dem Commit fehlgeschlagener Hook, der in das Repository kommittiert und durch ein kurzes Einrichtungsskript in .git/hooks platziert wird, sodass bei jedem Checkout die kommitierte Version ausgeführt wird. Ohne Scanner gibt es keinen Commit.
  • Ein Mutationstest pro Schleuse, der am Tag der Implementierung durchgeführt wird: Bei einem vorhandenen Defekt erscheint Rot, bei dessen Verschwinden Grün. Dies muss in derselben Sitzung erfolgen, sonst findet es nie statt.
  • Eine begrenzte Anzahl an Wiederholungsversuchen pro bekanntem Problem, wie beispielsweise ein fehlerhafter Gradle-Build, das Starten des Simulators oder der Anmeldebildschirm – diese werden als eine Zeile im Speicher oder in der Anweisungsdatei gespeichert: Einmal wiederholen und anschließend die Änderung als Ursache betrachten.
  • Ein Überprüfungs Schritt getrennt von der Implementierung mit schriftlichem Ausgabeergebnis, d.h. eine Checkliste im Vergleich zum Änderungsprotokoll und nicht nur ein Satz, der besagt, die Tests seien bestanden.
  • Ein einzeiliger menschlicher Kontrollpunkt in der Anweisungsdatei: Zuerst prüfen, ob die Umkehrung mehr Zeit kostet als etwa ein Tag an Nacharbeiten.
  • Insgesamt ergibt sich daraus ein Arbeitsbaum zur Erstellung, ein Konto zum Anmelden, ein Bildschirm, den der Agent lesen kann, ein Gerät für die Ausführung sowie Schleifen, die abbrechen, sobald festgestellt wird, dass bestimmte Überprüfungen fehlgeschlagen sind.