Lesson 08 · 並列処理

処理を自走させて agent をブロックしない

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

⏱ 約 10 分 · 📝 3 つのインタラクティブ要素 · 🧑‍💻 出典 shareAI-lab · s08_background_tasks.py

同期呼び出しの辛さ

S02 の bash ツールは同期だ:subprocess.run(..., timeout=120) で、npm install のような90秒かかるコマンドを実行すると、agent loop 全体が90秒間ブロックされる。ユーザーはターミナルを見つめ、ハングしているのか作業中なのか判断できない。

s08 の解決策:agent に background_run ツールを与える。これは即座に task_id を返し、コマンドは別のスレッドで実行される。agent はループを続けて他の作業をこなし、bg タスクが完了したら通知キューに結果を push する。

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()
    return f"Background task {task_id} started"   # 即座に返る

結果はどうやって agent に届くのか

鍵はスレッドセーフなキューだ:bg スレッドが完了したらキューに append し、メインスレッドは毎回の LLM 呼び出し前にキューを drain して、完了通知を user メッセージとして messages に追加する。

def agent_loop(messages):
    while True:
        # Drain bg notifications before each LLM call
        notifs = BG.drain_notifications()
        if notifs:
            messages.append({
                "role": "user",
                "content": f"<background-results>{notif_text}</background-results>",
            })
        response = client.messages.create(...)
        ...

こうして agent が第 N ターンに bg タスクを spawn し、第 N+3 ターンでそのタスクが完了すると、次の LLM 呼び出しには自動的に結果が含まれる——モデルは <background-results> ブロックを見て「あのタスクが終わった、続けよう」と認識する。

タイムラインのデモ

以下の widget でシミュレートしよう:メインスレッドが毎秒 tick する(agent ループのリズムを模擬)。任意のタイミングで bg タスクを spawn できる。2つの流れが「drain ポイント」でどう合流するかを確認しよう。

どのコマンドをバックグラウンドに回すべきか

すべてのコマンドをバックグラウンドに送るべきではない。判断基準は2つ:

  1. 実行時間:数秒以内なら同期で実行した方がシンプルで、キューを管理するオーバーヘッドがない。
  2. 結果の即時性:次のステップがすぐにその結果を必要とする場合(例:cat file.txt の直後に grep)、バックグラウンドに意味はない——どうせ待つことになる。
Interactive

Widget 1 · Timeline · メインスレッド + 2つの bg スレッド

Spawn を押して bg スレッドに仕事を割り当てよう。メインスレッドは毎 tick に notification queue を確認する。3つの swim lane がどう交差するかを確認しよう。

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

Widget 2 · Fire & Forget 判定 · 8つのコマンド、バックグラウンドに向いているか

各コマンドについて foreground(同期で待つ)か background(非同期 spawn)かを選択しよう。「結果がすぐに必要か」と「実行時間」の2軸で考えてほしい。

正解 0 / 8
Interactive

Widget 3 · Drain Timing · 通知は何ターン目に agent の視野に入るか

重要なルール:メインスレッドは毎回の LLM 呼び出し前にキューを drain する。5つのシナリオで、bg タスクが完了した後、結果が何ターン目に agent に届くかを答えよう。

正解 0 / 5