Lektion 08 · gleichzeitig

Lassen Sie den Agenten selbstständig laufen, ohne ihn zu blockieren.

「Fire and forget — the agent doesn't block while the command runs.」

⏱ ~10 Min · 📝 3 interaktive Widgets · 🧑‍💻 Basiert auf shareAI-lab · s08_background_tasks.py

Der Schmerz, Anrufe zu blockieren

Das bash-Tool in S02 ist synchron: subprocess.run(..., timeout=120). Das Ausführen eines Befehls wie npm install dauert 90 Sekunden und die gesamte Agentenschleife bleibt 90 Sekunden lang hängen. Der Benutzer starrt auf das Terminal und weiß nicht, ob es aufgehängt ist oder funktioniert.

Lösung für s08: Geben Sie dem Agenten ein background_run-Tool. Es gibt sofort eine task_id zurück und der Befehl wird in einem anderen Thread ausgeführt. Der Agent durchläuft weiterhin eine Schleife und führt andere Dinge aus. Wenn die BG-Aufgabe abgeschlossen ist, werden die Ergebnisse zur Benachrichtigungswarteschlange hinzugefügt.

def run(self, command: str) -> str:
    task_id = str(uuid.uuid4())[:8]
    self.tasks[task_id] = {"status":"running", ...}
    thread = threading.Thread(target=self._execute, args=(task_id, command), daemon=True)
    thread.start()
    zurück f"Hintergrundaufgabe {task_id} gestartet" # Sofort zurückkehren

Wie kann ich das Ergebnis an den Agenten zurückgeben?

Der Schlüssel ist eine Thread-sichere Warteschlange: Wenn der BG-Thread abgeschlossen ist, wird er an die Warteschlange angehängt. Vor jedem LLM-Aufruf durch den Hauptthread wird die Warteschlange geleert und die Abschlussbenachrichtigung wird als Benutzernachrichten in Nachrichten gestopft.

def agent_loop(messages):
    while True:
        # Blutzuckerbenachrichtigungen vor jedem LLM-Aufruf löschen
        notifs = BG.drain_notifications()
        if Benachrichtigungen:
            message.append({
                "role": "user",
                "content": f"<background-results>{notif_text}</background-results>",
            })
        Antwort = client.messages.create(...)
        ...

Auf diese Weise erzeugt der Agent in der N-ten Runde eine BG-Aufgabe. Wenn die Aufgabe in der N+3-Runde abgeschlossen ist, liefert der nächste LLM-Aufruf automatisch die Ergebnisse – das Modell erkennt, wenn es den Block <background-results> sieht: „Oh, diese Aufgabe ist erledigt, ich werde fortfahren.“

Timeline-Demo

Mit dem folgenden Widget können Sie Folgendes simulieren: Der Hauptthread tickt jede Sekunde (simuliert den Takt des Agentenzyklus); Sie können die BG-Aufgabe jederzeit starten. Beobachten Sie, wie sich die beiden Hinweise am „Abflusspunkt“ treffen.

Welche Befehle sollten im Hintergrund platziert werden?

Nicht alle Befehle sollten in den Hintergrund gedrängt werden. Es gibt zwei Kriterien:

  1. Zeitaufwändig: Die synchrone Ausführung innerhalb weniger Sekunden ist einfacher und macht die Wartung von Warteschlangen überflüssig.
  2. Ergebniswichtigkeit: Wenn das Ergebnis sofort im nächsten Schritt verwendet wird (z. B. cat file.txt direkt gefolgt von grep), ist der Hintergrund bedeutungslos – Sie müssen immer noch darauf warten.
Interaktiv

Widget 1 · Zeitleiste · Hauptthread + 2 BG-Threads

Klicken Sie auf Spawn, um die Arbeit an den BG-Thread zu verteilen. Der Hauptthread überprüft die Benachrichtigungswarteschlange bei jedem Tick. Schauen Sie sich an, wie die drei Schwimmbahnen ineinandergreifen.

🧠 Main (agent loop)
⚙ Background thread A
(idle)
⚙ Background thread B
(idle)
queue: []
Interaktiv

Widget 2 · Fire & Forget Judgment · 8 Befehle, welche sind es wert, unterstützt zu werden?

Wählen Sie für jeden Befehl den Vordergrund (synchron usw.) oder den Hintergrund (asynchroner Spawn). Achten Sie auf die beiden Dimensionen „sollten Sie auf das Ergebnis warten“ + „zeitaufwändig“.

答对 0 / 8
Interaktiv

Widget 3 · Ablaufzeitpunkt · In welcher Runde die Benachrichtigung gesehen wurde

Schlüsselregel: Der Hauptthread leert die Warteschlange vor jedem LLM-Aufruf. Geben Sie 5 Szenarien an. Antwort: In welcher Runde werden die Ergebnisse nach Abschluss der BG-Aufgabe in das Sichtfeld des Agenten gelangen?

答对 0 / 5