Background Tasks — 빠른 두뇌, 느린 손
이전 이야기에서: 지민은 Subagent로 코드 리뷰의 노이즈를 격리했다. code-reviewer가 깨끗한 컨텍스트에서 정확한 리뷰를 해줬다. 하지만 CI/CD 파이프라인을 구축하면서 새로운 벽에 부딪혔다...
Harness = Tools + Knowledge + Context + Permissions
Background Tasks는 Tools 실행 방식을 확장하고 Context 오염을 최소화한다. "Run slow operations in the background; the agent keeps thinking"
30초의 침묵
지민이 Enter를 눌렀다.
지민: 의존성 설치하고 그 동안 설정 파일 만들어줘
Claude: npm install 실행합니다...
30초가 지났다. 터미널에는 아무 변화가 없었다.
지민은 커피를 한 모금 마셨다. 다시 터미널을 봤다. 여전히 돌아가고 있었다.
[30초 더 대기]
설치 완료! 이제 설정 파일 만들겠습니다.
총 60초. 그 중 절반은 Claude가 아무것도 하지 않고 기다리기만 한 시간이었다.
"설정 파일은 npm install 끝나기 전에도 만들 수 있잖아." 지민이 중얼거렸다. "왜 기다리는 거야?"
이건 사소한 불편이 아니었다. 현실의 블로킹 시간을 합산하면:
npm install → 30초~3분
docker build → 1분~10분
pytest → 30초~5분
cargo build → 1분~10분
database migration → 10초~1분
하루에 빌드를 20번 돌린다면? 최소 30분이 Claude가 멍하니 앉아 있는 시간이다.
지민의 론칭 데드라인은 다가오고 있었다. 이 30분을 버릴 여유가 없었다.
"왜 기다리지?": Agent Loop의 구조적 한계
문제의 원인은 Agent Loop(00에서 배운 것)의 구조에 있었다.
def agent_loop(messages):
while True:
response = client.messages.create(...)
for tool_call in response.content:
if tool_call.type == "tool_use":
output = TOOL_HANDLERS[tool_call.name](**tool_call.input)
# ↑ 여기서 30초 블로킹
# 이 줄이 끝나야 다음 줄로 간다
results.append(...)
messages.append({"role": "user", "content": results})
# 모든 툴 결과가 모여야 다음 LLM 호출
execute_tool() 한 줄이 끝나야 다음 줄로 넘어간다.
npm install이 3분 걸리면, Claude는 3분 동안 생각도 하지 않는다.
지민은 처음에 이것이 버그라고 생각했다. "고치면 되지 않나?"
하지만 곧 깨달았다. 이건 버그가 아니라 올바른 설계였다.
올바른 설계가 문제인 이유
에이전트의 추론은 반드시 순차적이어야 한다.
왜? Claude가 파일을 읽고, 결과를 보고, 다음 행동을 결정한다. 만약 두 개의 LLM 호출이 동시에 진행된다면?
Claude A: auth.ts를 읽었다 → "JWT 방식으로 가자"
Claude B: auth.ts를 읽었다 → "세션 방식으로 가자"
→ 충돌. 어느 쪽의 판단을 따라야?
추론의 순차성은 에이전트의 일관성을 보장한다. 이건 건드리면 안 된다.
그런데 npm install은 추론이 아니다. 순수한 I/O 대기다. CPU를 쓰지 않는다. 네트워크에서 패키지를 다운로드하는 것을 기다릴 뿐이다.
구분:
추론 (reasoning): Claude가 생각하는 것 → 순차적이어야 함 ✅
I/O 대기 (waiting): 외부 프로세스를 기다리는 것 → 병렬화 가능 ✅
지민의 눈이 커졌다. "추론은 순차적으로 두고, I/O만 빼내면 되잖아."