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 작업이 완료되면 알림 큐에 결과를 넣습니다.

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할 수 있습니다. 두 스레드가 "drain 지점"에서 어떻게 합쳐지는지 보세요.

어떤 명령을 백그라운드로 보내야 하나?

모든 명령을 백그라운드로 보낼 필요는 없습니다. 두 가지 기준이 있습니다:

  1. 소요 시간: 몇 초 이내라면 동기 실행이 더 간단합니다. 큐 관리 비용이 0.1초 기다리는 것보다 비쌉니다.
  2. 결과의 중요도: 다음 단계에서 이 결과가 바로 필요하다면 (예: cat file.txt 다음에 바로 grep), 백그라운드는 의미가 없습니다—어차피 기다려야 합니다.
Interactive

Widget 1 · Timeline · 메인 스레드 + 2개 bg 스레드

Spawn을 클릭해 bg 스레드에 작업을 할당하세요. 메인 스레드는 매 tick마다 notification queue를 확인합니다. 세 개의 swim lane이 어떻게 교차하는지 보세요.

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

Widget 2 · Fire & Forget 판별 · 8개 명령 중 어떤 것을 백그라운드로?

각 명령에 대해 foreground(동기 대기) 또는 background(비동기 spawn)를 선택하세요. "결과가 필요한가" + "소요 시간" 두 차원을 고려하세요.

0 / 8 정답
Interactive

Widget 3 · Drain Timing · 알림이 어느 라운드에 agent에게 보여지나

핵심 규칙: 메인 스레드는 매 LLM 호출 전에 큐를 drain합니다. 5개 시나리오에서 bg 작업 완료 후 결과가 몇 번째 라운드에 agent의 시야에 들어오는지 답하세요.

0 / 5 정답