Leçon 08 · concurrent

Laissez l'agent s'exécuter tout seul sans le bloquer.

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

⏱ ~10 min · 📝 3 widgets interactifs · 🧑‍💻 Basé sur shareAI-lab · s08_background_tasks.py

La douleur de bloquer les appels

L'outil bash dans S02 est synchrone : subprocess.run(..., timeout=120). L'exécution d'une commande telle que npm install prend 90 secondes et toute la boucle de l'agent est bloquée pendant 90 secondes. L'utilisateur regarde le terminal sans savoir s'il est raccroché ou s'il fonctionne.

Solution à s08 : donnez à l'agent un outil background_run. Il renvoie immédiatement un task_id et la commande est exécutée sur un autre thread. L'agent continue de boucler et de faire autre chose ; lorsque la tâche bg est terminée, les résultats sont ajoutés à la file d'attente de notification.

def run(self, commande : 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()
    retour f"Tâche en arrière-plan {task_id} démarrée" # Retour immédiatement

Comment retourner le résultat à l'agent ?

La clé est une file d'attente thread-safe : lorsque le thread bg se termine, il s'ajoute à la file d'attente ; avant chaque appel LLM par le thread principal, la file d'attente est vidée et la notification d'achèvement est insérée dans les messages en tant que messages utilisateur.

def agent_loop(messages) :
    pendant Vrai :
        # Drainer les notifications de bg avant chaque appel LLM
        notifications = BG.drain_notifications()
        if notifications :
            messages.append({
                "role" : "utilisateur",
                "content" : f"<background-results>{notif_text}</background-results>",
            })
        réponse = client.messages.create(...)
        ...

De cette façon, l'agent génère une tâche bg au Nième tour. Lorsque la tâche est terminée au cycle N+3, le prochain appel LLM apportera automatiquement les résultats - le modèle saura quand il verra le bloc <background-results> : "Oh, cette tâche est terminée, je vais continuer."

Démo de la chronologie

Le widget suivant vous permet de simuler : le thread principal fait un tick toutes les secondes (simulant le rythme du cycle de l'agent) ; vous pouvez générer la tâche bg à tout moment. Regardez comment les deux indices se rencontrent au « point de vidange ».

Quelles commandes doivent être placées en arrière-plan ?

Toutes les commandes ne doivent pas être passées en arrière-plan. Il y a deux critères :

  1. Prend du temps : l'exécution synchrone en quelques secondes est plus simple, éliminant ainsi le besoin de maintenir des files d'attente.
  2. Importance du résultat : si le résultat est utilisé immédiatement à l'étape suivante (comme cat file.txt immédiatement suivi de grep), l'arrière-plan n'a aucun sens - vous devez toujours l'attendre.
Interactif

Widget 1 · Chronologie · Fil principal + 2 fils bg

Cliquez sur Spawn pour répartir le travail vers le thread bg. Le thread principal vérifie la file d'attente de notification à chaque tick. Regardez comment les trois couloirs de nage s'entrelacent.

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

Widget 2 · Fire & Forget Judgment · 8 commandes, lesquelles valent la peine d'être soutenues ?

Choisissez le premier plan (synchrone, etc.) ou l'arrière-plan (apparition asynchrone) pour chaque commande. Faites attention aux deux dimensions « faut-il attendre le résultat » + « prend du temps ».

答对 0 / 8
Interactif

Widget 3 · Calendrier de vidange · Dans quel tour la notification a été vue

Règle clé : le thread principal vide la file d'attente avant chaque appel LLM. Donnez-vous 5 scénarios. Réponse : Une fois la tâche bg terminée, à quel tour les résultats entreront-ils dans le champ de vision de l'agent.

答对 0 / 5