Agent 장시간 작업은 왜 진행률을 회신해야 하는가
진행률 회신은 프런트엔드 애니메이션도 아니고 단지 「사용자 경험이 좋아서」도 아니다. 그것은 Agent 통제 가능성의 입구다. 장시간 작업을 상태·소요·에러·산출물을 가진 관찰 가능한 단계로 쪼개어 외부에 노출해야 비로소 관측성, 중도 개입(일시정지/재시도/스킵/롤백/사람 전환), 이상 복구를 논할 수 있다. 진행률 회신은 Agent 통제 가능성의 입구다.
작업을 「관찰 가능한 단계」로 쪼개기
- 요구 이해
- 자료 검색
- 시스템 호출
- 결과 생성
- 확인 대기
반드시 기록해야 할 필드
| 필드 | 용도 |
|---|
| 상태 | 사용자는 진행 상황을 보고, 시스템은 흐름을 제어 |
| 시작 시각 | 병목 지점 특정 |
| 종료 시각 | 병목 지점 특정 |
| 소요 | 성능과 타임아웃 판정 |
| 에러 정보 | 실패 위치를 정확히 특정 |
멈췄을 때 「로딩 중」만 표시해서는 안 된다 — 이상은 분류 가능해야 한다 (이것이 곧 관측성의 가치다)
| 이상 유형 | 의미 |
|---|
| 모델 타임아웃 | 대모델 측이 제한 시간 내에 반환하지 않음 |
| 도구 타임아웃 | 도구/함수 호출이 반환하지 않음 |
| 권한 실패 | 인증/인가 미통과 |
| 외부 서비스 불가 | 하류 시스템 다운 또는 도달 불가 |
반면 경고
- 가짜 진행률을 보고하지 말 것
- 진행률에도 권한과 마스킹을 적용할 것
정리
Agent 장시간 작업은 실시간으로 진행률을 회신해야 한다. 경험을 개선할 뿐 아니라 작업 통제, 이상 복구, 관측성을 뒷받침하기 때문이다. 작업을 여러 관찰 가능한 단계로 쪼개고 각 단계마다 상태, 소요, 에러, 산출물을 기록한다. 프런트엔드가 표시하는 것은 마스킹된 진짜 진행률이며, 백엔드는 이 상태들로 취소, 재시도, 일시정지, 확인, 사람 전환을 지원한다. 어떤 단계가 실패하면 시스템은 실패 위치를 설명할 수 있어야지 「일반 실패」 하나만 주면 안 된다.
핵심 통찰
- 진행률은 「제어면」이지 「표시면」이 아니다 — 대부분의 사람이 진행률 회신을 프런트엔드 경험으로 분류하지만, 이것은 시스템 통제 가능성에 속한다. 판단 기준은 간단하다. 진행률이 UI에만 공급되고 백엔드는 같은 상태를 가져오지 못한다면 그것은 장식일 뿐이고, 백엔드도 이 상태에 의존해 취소/재시도/롤백을 한다면 그것이 제어면이다.
- 관측성의 전제는 「열거 가능한 단계」다 — 쪼개지지 않은 블랙박스 장시간 작업에는 태생적으로 관측성이 없다. 먼저 작업 분해를 해야 상태 보고가 가능하고, 그래야 개입 지점이 가능하다. 순서를 뒤집으면 안 된다.
- 이상은 반드시 분류해야 하며, 그러지 않으면 예외 처리가 없는 것과 같다 — 「로딩 중」과 「실패」는 같은 부류의 오류다. 완전히 다른 네 가지 장애(모델 타임아웃/도구 타임아웃/권한 실패/하류 불가)를 행동 불가능한 신호 하나로 압축한다. 행동 가능성 = 이것을 근거로 다음 동작을 고를 수 있는가.
- 무상태 = 블랙박스 = 전부 다시 하기 — 중간 상태가 없으면 사용자의 유일한 교정 수단은 처음부터 다시 돌리는 것이며, 비용은 작업 길이에 비례해 커진다. 중간 상태의 진짜 가치는 「다시 하기」의 입도를 작업 전체에서 단일 단계로 낮추는 것이다.
- 가짜 진행률은 기술 부채이며 신뢰를 역습한다 — 「심층 사고 중」 같은 실제 이벤트와 디커플링된 문구는 단기적으로는 똑똑해 보이지만, 장기적으로는 사용자가 진행률로 개입 여부를 판단할 수 없게 만들어 진행률 신호의 정보량을 0으로 만든다.
- 진행률은 외부로 나가는 데이터 채널이므로 데이터 채널의 기준으로 거버넌스해야 한다 — 많은 팀이 반환 결과에는 권한과 마스킹을 적용하면서, 진행률 문구가 똑같이 계약명, 고객명, 견적을 경계 밖으로 내보낸다는 것을 잊는다. 시스템 밖으로 나가는 모든 문자열은 마스킹을 거쳐야 한다.
엔지니어링 실전 Tips
- 2분을 설계 레드라인으로 삼을 것: 경험값은 「십수 초는 수용 가능, 2분 무반응이면 반드시 문제」다. P95가 십수 초를 넘는 Agent 링크라면 타임아웃 컴플레인을 기다리지 말고 진행률 회신을 올려야 한다.
- 진행률 보고는 멱등이어야 하고 단계 ID를 가져야 한다: 사용자의 반복 클릭은 필연적 행동이므로, 프런트는 작업 ID + 단계 순번으로 중복을 제거해 중복 제출이 작업 상태를 망가뜨리지 않게 해야 한다.
- 상태 필드는 한 번에 제대로 설계할 것: 상태 / 시작 시각 / 종료 시각 / 소요 / 에러 / 산출물, 여섯 필드 중 하나만 빠져도 나중에 재시도나 롤백을 만들 때 데이터 구조를 다시 손봐야 한다.
- 「산출물(artifact)」 필드를 빠뜨리기 쉽다: 이것이 「스킵」과 「롤백」을 구현할 수 있는 전제다. 단계별 산출물이 없으면 롤백은 시작점으로밖에 갈 수 없다.
- 타임아웃은 계층별로 설정할 것: 모델 타임아웃과 도구 타임아웃은 서로 다른 두 예산이며, 전역 타임아웃 하나를 공용하면 이상 분류가 무효화된다.
- 마스킹은 서버 출구에 두고 프런트엔드에 두지 말 것: 프런트 마스킹은 데이터가 이미 나갔다는 뜻이며 패킷을 잡으면 보인다.
- 실패 정보에 위치 좌표를 붙일 것:
문서 파싱 ✓ → 엔티티 추출 ✗ TimeoutError → 요약 생성 (미실행) 같은 3단 형식이 어떤 에러 코드보다도 트러블슈팅 시간을 줄여준다.
- 진행률 입도는 개입 지점 기준으로 나누고 코드 모듈 기준으로 나누지 말 것: 사용자나 시스템이 「중단/재실행」할 수 있는 경계만이 진행 단계가 될 가치가 있으며, 그렇지 않으면 무의미한 상태 노이즈만 대량 생산된다.