AI 에이전트 개발의 리드 타임을 분해하여 알게 된 '4가지 대기 시간'
요약
AI 에이전트 개발 파이프라인의 리드 타임을 분석한 글입니다. 단순히 GitHub 타임스탬프만으로는 '대기 시간'과 '실제 구현 시간'을 정확히 분리할 수 없음을 지적합니다. 정확한 측정을 위해서는 할당(dispatch), 구현 완료, 인계(handoff) 등 외부 시스템에서 시각 기록이 필요하다고 강조합니다.
핵심 포인트
- AI 에이전트 리드 타임은 대기 시간이 대부분을 차지한다.
- GitHub의 기본 타임스탬프만으로는 '대기'와 '구현' 분리가 불가능하다.
- 정확한 측정을 위해 할당, 구현 완료, 인계 등 외부 시각 기록 장치가 필요하다.
- 단순 병렬화는 재작업으로 인해 오히려 느려질 수 있다.
이 글에서 알 수 있는 것
- AI 에이전트에 구현시키도록 하는 개발에서는, 리드 타임의 대부분이 '대기 시간'이 될 수 있습니다.
- 대기 시간은 적어도 4가지 종류가 있으며, 성격이 다르므로 대책도 달라집니다.
- 에이전트 수를 늘려도, 스케줄러가 막혀 있다면 리드 타임은 줄어들지 않습니다.
- GitHub의 타임스탬프만으로는 '대기'와 '구현'을 분리할 수 없습니다. 순진하게 측정하면 잘못된 숫자가 나옵니다.
- 의존 관계를 무시한 병렬화는, 재작업으로 인해 오히려 느려집니다.
배경
GitHub Issue를 기점으로 AI 에이전트가 구현하여 PR을 만드는 파이프라인을 운영하고 있습니다. 시스템 자체에 대한 이야기(3계층 구성, Issue를 신뢰할 수 없는 입력으로 취급하는 설계, 구현 중에 겪은 구체적인 문제점)는 다른 글에 작성했으므로 여기서는 다루지 않겠습니다.
이 글은 '그래서 빨라졌는지'를 측정하려는 기록입니다.
실감하기로는 '1건의 구현은 빠르다'고 느껴졌지만, Issue가 줄어드는 속도는 생각만큼 올라가지 않았습니다. 에이전트를 늘리면 해결될 것 같은 느낌이었지만, 측정해 보니 늘려도 줄어들지 않는 부분이 대부분이었습니다.
먼저, 순진한 측정 방식은 잘못되었다
처음에 한 것은 Issue 생성부터 Close까지의 시간을 집계하는 것이었습니다. 이것은 실패였습니다. 이 구간에는 적어도 다음 모든 것들이 섞여 있습니다.
- Issue가 만들어지고 나서, 모니터링 시스템이 감지할 때까지
- 감지된 후, 실제로 에이전트에게 할당될 때까지
- 할당된 후 구현이 끝날 때까지
- PR 생성부터 CI・리뷰・머지까지
- 머지되어 Issue가 Close될 때까지
밤에 Issue를 올렸는데 아침에 처리되면, 실제 작업 시간이 10분이라도 구간은 몇 시간이 됩니다. 이 숫자를 '개발 속도'라고 부르면, 어디를 고쳐야 할지 알 수 없습니다.
분해하려고 하다가, 또 두 번 실수했다
다음으로 '첫 번째 커밋 시각'을 사용해서 착수 대기와 구현을 분리하려고 했습니다. 'Issue 생성 → 첫 번째 커밋'이 대기이고, '첫 번째 커밋 → PR 생성'이 구현이라는 가정이었습니다.
나온 구현 시간의 중앙값은 1분이었습니다.
물론 AI가 1분에 구현한 것은 아닙니다. 이 파이프라인은 작업을 끝내고 나서 한 번에 커밋하고, 그 직후에 PR을 만듭니다. 첫 번째 커밋은 구현 시작 시점이 아니라, 마무리 단계에서 찍힌 것이었습니다. 측정했던 것은 '푸시하여 PR을 여는 수십 초'였습니다.
그렇다면 반대로 'PR 생성 → 머지'를 대기 시간으로 취급하면 될까 하니, 이것도 아니었습니다. PR마다 마지막 커밋 시각을 조사해 보니, 많은 PR에서 마지막 커밋이 PR 생성보다 나중에 있었습니다. 차이는 수십 분에서 3시간 반입니다. PR을 먼저 만들고 나서, 리뷰 지적에 대응하는 커밋을 쌓기 때문입니다.
즉 이 구간에는 CI 대기・리뷰 대기에 더해 리뷰 대응이라는 구현 작업 자체가 포함되어 있습니다. 통째로 '대기'라고 부르면 과대평가됩니다.
결론: 측정 장치를 설치하지 않으면 분해할 수 없다
순진하게 측정하면 '구현은 거의 0, 나머지는 전부 대기'라는 숫자가 나옵니다. 실제로 나왔습니다. 하지만 그것은 측정의 인공물입니다.
GitHub의 타임스탬프에는, 대기와 구현을 분리하기 위한 정보가 들어있지 않습니다. 커밋은 구현의 끝 무렵에 떨어지고, 리뷰 대응 구현은 PR 이후 구간에 섞이기 때문입니다.
분리하려면, GitHub 외부에서 시각을 기록해야 합니다.
- dispatch 시간: 어떤 Issue를, 언제, 어느 에이전트에게 할당했는지 -
- 구현 완료 시간: 결과물이 나온 시각(PR 생성 시각으로 대용 가능) -
- handoff 시간: PR 이후의 추적을 구현 담당자로부터 분리한 시각
이 3가지가 있으면, 착수 대기・구현・리뷰 구간을 별개로 읽을 수 있습니다. 반대로 말하면, 이것을 설치하기 전까지는, 아무리 집계해도 개선점은 특정할 수 없습니다. 처음에 손대야 할 것은 스케줄러의 개선이 아니라, 측정의 추가였습니다.
여기가 가장 큰 배움이었습니다. 아래의 4가지 분류는, 이 측정과 운영 중 관측을 통해 정리한 것입니다.
대기 시간은 4가지 종류가 있다
1. 감지 대기 (polling 간격)
Issue가 만들어져도, 모니터링이 다음 번 실행할 때까지는 아무도 알아차리지 못합니다. polling 방식이라면 평균적으로 polling 간격의 절반입니다.
다소 까다로운 점은, 이 대기가 작업 크기와 무관하게 일정량 걸린다는 것입니다. 1분으로 끝나는 수정이라도 똑같이 기다립니다. 짧은 시간으로 끝나는 태스크를 많이 흘릴수록, polling 간격이 전체에 차지하는 비율이 커지고, 간격 자체가 처리량의 상한선이 됩니다.
간격을 좁히면 좋겠지만, API 속도 제한(rate limit)과 모니터링 비용이 올라갑니다. 본질적으로는 이벤트 기반(event-driven)으로 전환하는 이야기이며, 어느 정도까지 할지는 규모에 따라 다릅니다.
2. dispatch 대기 시간 (할당하는 쪽의 점유)
감지되었더라도, 할당하는 쪽이 다른 작업으로 바쁘면 진행할 수 없습니다. 이것이 실제로 가장 효과적이었습니다.
오케스트레이터(orchestrator) 자체가 조사나 보고를 하는 구성이라면, 그 시간 동안은 할당이 멈춥니다. 비어 있는 에이전트가 있는데도, 할당하는 쪽이 바빠서 멈추는 경우입니다. 에이전트를 늘려도 이 대기 시간은 줄어들지 않습니다.
대책은 할당만 담당하는 가벼운 경로를 분리하는 것입니다.
【분리 전】
Issue → 오케스트레이터 (조사・보고・할당 겸임) → worker
↑ 여기가 막히면 후속 작업 전체가 멈춥니다.
...
디스패처(Dispatcher) 쪽은 '의존성이 해소된 Issue를, 비어 있는 worker에게 전달하는' 역할만 합니다. 판단을 줄일수록 병목 현상이 적어집니다.
3. 의존 대기 시간과, 의존성을 무시한 병렬화로 인한 재작업(手戻り)
의존성이 있는 Issue를 동시에 실행하면, 빨라지기는커녕 느려집니다.
실제로 일어난 일은 이렇습니다. 어떤 Issue를 구현하는 도중에, 같은 파일을 건드리는 다른 Issue가 먼저 병합(merge)되어 나중에 제출된 PR이 충돌(conflict)했습니다. main을 가져와서 CI를 다시 돌리고, 리뷰도 처음부터 다시 해야 했습니다. 병렬화로 얻은 시간보다 재작업이 더 컸습니다.
여기서 효과적인 것은 '의존 대상이 끝나지 않은 Issue는 dispatch하지 않는다'라는 제어입니다. 부모 Issue를 분할할 때 의존 관계를 적어두고, 투입 순서를 그것으로 결정합니다.
병렬도를 높이는 것보다, 같은 파일을 건드리는 Issue를 동시에 실행하지 않는 것이 리드 타임을 단축시켰습니다.
4. PR 후 대기 시간 (CI・리뷰・승인・Merge)
PR을 만든 시점부터 병합까지의 기다림입니다. 실측 결과 중앙값은 10여 분으로, 이것만 보면 빠릅니다. 하지만 상위 10%에서는 2~3시간, 최대는 반나절이 넘었습니다.
평균이나 중앙값만 보면 이 긴 꼬리(long tail)를 놓치게 됩니다. 대기 시간 문제는 '가끔 매우 길다'라는 형태로 나타나므로, 분포의 상측을 봐야 합니다.
늘어나는 요인은 CI 실행 시간, 리뷰 봇 응답 대기 시간, 리뷰 지적 사항 대응, 승인 필수 설정에서의 승인 대기 등입니다. 리뷰 봇에 속도 제한이 있으면 급격히 늘어납니다.
중요한 것은, 이 구간을 구현 담당자에게 맡겨두지 않는 것입니다. 맡겨둔 채로 두면 그 에이전트는 다음 작업을 시작할 수 없습니다. PR을 만든 시점에서 추적(tracking)을 다른 경로로 넘겨서 해방시키면, 대기 시간은 '아무도 작업하지 않은 시간'이 아니라 '다른 Issue를 진행하고 있는 시간'이 됩니다.
대기 시간 자체는 0으로 만들 수 없습니다. 할 수 있는 것은, 기다리는 동안 다른 업무가 진행되는 구조로 만드는 것입니다.
'속도'를 하나의 숫자로 말하는 것을 그만두자
4가지 종류를 다루려면 지표를 분리해야 합니다.
lead time: Issue 생성부터 병합까지의 전체 시간. 사용자 관점의 속도 -
queue time: 아무도 작업하지 않는 대기 시간 -
cycle time: 실제로 작업하고 있는 시간 -
throughput: 단위 시간당 완료 건수
에이전트를 늘리면 throughput은 올라가지만, queue time이 지배적이라면 lead time은 줄어들지 않습니다. 동시에 진행되는 건수가 늘어날 뿐, 1건당 체감 속도는 변하지 않습니다.
'빨라지고 싶은 것'이 lead time인지 throughput인지를 결정해야 손쓸 방법을 틀리지 않습니다. cycle time이 지배적(AI 구현 자체가 느린 경우)이라면, 모델이나 컨텍스트나 태스크의 입자 크기에 대한 이야기입니다. 어느 것이 지배적인지는 측정해봐야 압니다. 제 환경에서는 queue time 쪽이었습니다.
개선 방향
정리하자면, 목표로 하는 흐름은 이렇습니다.
Issue 생성
↓ (감지 대기: polling 간격 좁히기 / 이벤트 기반화)
Dispatcher (할당 전담・상태 없음)
...
에이전트 수를 늘리는 항목이 하나도 없습니다. 들어간 것은, 측정 지점을 늘리는 것, 기다리는 동안 worker를 구속하지 않는 것, 의존성을 무시하고 병렬화하지 않는 것입니다.
요약
⚠️ [IMG:N] 형식 토큰은 이미지 placeholder 입니다. 번역하지 말고 원래 위치에 그대로 유지하세요.
- Issue 생성 → Close를 '개발 속도'로 간주하면 개선점을 찾기 어렵다.
- GitHub의 타임스탬프로는 대기 시간과 구현 시간을 분리할 수 없다. 먼저 측정 장치를 마련해야 한다.
- 대기는 감지(detect)・디스패치(dispatch)・종속성(dependency)・PR 이후 4가지 종류가 있다. 성질이 다르므로 대응책도 별도로 필요하다.
- 에이전트를 늘려도 큐 시간(queue time)은 줄어들지 않는다.
- 종속성을 무시한 병렬화는 재작업을 유발하여 역효과다.
- 분포의 상위 부분(상위 10%)을 보지 않으면, 긴 꼬리(long tail)를 놓치게 된다.
AI 에이전트를 사용하면 '모델 성능'이나 '에이전트 수'에 시선이 집중되지만, 실제로 측정해보니 리드 타임의 대부분은 대기열 문제였습니다. 이는 AI 고유의 이야기가 아니라, 플로우 관리(flow management)로서 이전부터 알려진 이야기로 돌아갑니다.
상세 버전
실측 데이터 읽는 법, 스토리 포인트와 소요 시간의 관계 (결론적으로 스토리 포인트는 '언제 끝날지' 예측하는 데 사용될 수 없었습니다), 큐(queue)/사이클(cycle)/리드 타임 측정 설계, 디스패처의 상태 전이, 종속성을 고려한 디스패치, 리뷰/머지 과정에서의 핸드오프(handoff), 부모 Issue와 서브 Issue를 같은 잔여 작업으로 계산하는 집계상의 함정, 개선 전후를 어떻게 측정할 것인가—이러한 내용은 Book 측 장에 자세히 추가했습니다.
Windows를 메인 환경으로 Claude Code와 Codex를 운영해 온 기록을 정리한 책이며, 이번 대기 시간 분석은 Issue → PR 장에 포함되어 있습니다.
논의(Discussion)

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기