s08
Hintergrundaufgaben
NebenläufigkeitBackground Threads + Notifications
198 LOC6 ToolsBackgroundManager + notification queue
Run slow operations in the background; the agent keeps thinking ahead
s01 > s02 > s03 > s04 > s05 > s06 | s07 > [ s08 ] s09 > s10 > s11 > s12
"Langsame Operationen im Hintergrund ausführen; der Agent denkt weiter" -- Daemon-Threads führen Befehle aus und fügen Benachrichtigungen nach Abschluss ein.
Problem
Manche Befehle dauern Minuten: npm install, pytest, docker build. Mit einer blockierenden Schleife sitzt das Modell untätig da. Wenn der Benutzer "installiere Abhängigkeiten und während das läuft, erstelle die Konfigurationsdatei" fragt, führt der Agent sie sequenziell aus, nicht parallel.
Lösung
Hauptthread Hintergrund-Thread
+-----------------+ +-----------------+
| agent loop | | subprocess runs |
| ... | | ... |
| [LLM call] <---+------- | enqueue(result) |
| ^drain queue | +-----------------+
+-----------------+
Zeitachse:
Agent --[spawn A]--[spawn B]--[andere Arbeit]----
| |
v v
[A läuft] [B läuft] (parallel)
| |
+-- Ergebnisse eingefügt vor nächstem LLM-Aufruf --+
Wie es funktioniert
- BackgroundManager verfolgt Aufgaben mit einer threadsicheren Benachrichtigungs-Warteschlange.
class BackgroundManager:
def __init__(self):
self.tasks = {}
self._notification_queue = []
self._lock = threading.Lock()
run()startet einen Daemon-Thread und kehrt sofort zurück.
def run(self, command: str) -> str:
task_id = str(uuid.uuid4())[:8]
self.tasks[task_id] = {"status": "running", "command": command}
thread = threading.Thread(
target=self._execute, args=(task_id, command), daemon=True)
thread.start()
return f"Background task {task_id} started"
- Wenn der Subprocess fertig ist, geht sein Ergebnis in die Benachrichtigungs-Warteschlange.
def _execute(self, task_id, command):
try:
r = subprocess.run(command, shell=True, cwd=WORKDIR,
capture_output=True, text=True, timeout=300)
output = (r.stdout + r.stderr).strip()[:50000]
except subprocess.TimeoutExpired:
output = "Error: Timeout (300s)"
with self._lock:
self._notification_queue.append({
"task_id": task_id, "result": output[:500]})
- Die Agent-Schleife leert die Benachrichtigungen vor jedem LLM-Aufruf.
def agent_loop(messages: list):
while True:
notifs = BG.drain_notifications()
if notifs:
notif_text = "\n".join(
f"[bg:{n['task_id']}] {n['result']}" for n in notifs)
messages.append({"role": "user",
"content": f"<background-results>\n{notif_text}\n"
f"</background-results>"})
messages.append({"role": "assistant",
"content": "Noted background results."})
response = client.messages.create(...)
Die Schleife bleibt Single-Threaded. Nur die Subprocess-E/A wird parallelisiert.
Was sich von s07 geändert hat
| Komponente | Vorher (s07) | Nachher (s08) |
|---|---|---|
| Tools | 8 | 6 (basis + background_run + check) |
| Ausführung | Nur blockierend | Blockierend + Hintergrund-Threads |
| Benachrichtigung | Keine | Warteschlange pro Schleife geleert |
| Parallelität | Keine | Daemon-Threads |
Ausprobieren
python agents/s08_background_tasks.py
Führe "sleep 5 && echo done" im Hintergrund aus, erstelle dann eine Datei während es läuftStarte 3 Hintergrundaufgaben: "sleep 2", "sleep 4", "sleep 6". Überprüfe ihren Status.Führe pytest im Hintergrund aus und arbeite weiter an anderen Dingen
