LLM 에이전트는 메일함(inbox)을 생성하는 도구를 호출하고, 인증 메시지를 기다린 다음 코드를 추출할 수 있습니다. 데모의 경우 몇 분 안에 작동하는 경우가 많습니다. 하지만 실제 운영 환경에서는 문제가 발생합니다. 공급업체 측에서 시간이 오래 걸리거나, 모델이 다시 질문하도록 결정하여 흐름 전체가 명확한 실패 신호 없이 시간과 비용을 소모하게 됩니다.
해결책은 단순히 거대한 타임아웃(timeout)을 설정하는 것이 아닙니다. 에이전트에게 지연 시간 예산(latency budget)을 부여하고, 모든 도구가 이 예산을 준수하도록 만드는 것입니다. 이러한 맥락에서 temporary email generator는 단순한 보조 서비스가 아니라, 생명 주기와 한계점, 그리고 모델이 이해할 수 있어야 하는 증거(evidence)를 가진 의존성입니다.
문제: 예산 없이 기다리는 에이전트
다음 과정을 상상해 보세요:
- 에이전트가 임시 주소를 생성합니다.
- 애플리케이션이 확인 이메일을 전송합니다.
- 에이전트가 주기적으로 메일함을 조회합니다.
- 메시지를 읽고 다음 행동으로 진행합니다.
만약 각 단계마다 자체적인 타임아웃을 사용한다면, 전체 흐름은 아무도 시간 소모 지점을 알지 못한 채 작업 제한 시간을 초과할 수 있습니다. 에이전트는 일반적인 오류를 보고 다시 시도합니다. 두 번째 시도는 또 다른 메일함을 생성하고, 첫 번째 이메일을 고아(huerfano) 상태로 남겨 진단 과정을 더 어렵게 만듭니다.
이는 온콜링(on-call) 근무 중 핸드오프(handoff)를 검증하는 것처럼 보이는 매우 작은 내부 프로세스에서도 발생합니다. SRE 근무 중 핸드오프 이메일 테스트 방법와 마찬가지로, 이메일 증거를 주요 작업과 분리하는 것이 좋습니다. 중요한 것은 메시지가 도착했는지 여부뿐만 아니라, 얼마나 많은 시간과 조회 횟수가 필요했는가입니다.
타임아웃을 선택하기 전에 흐름도를 그리세요
프롬프트(prompt)를 작성하기 전에, 저는 단어 다이어그램을 만듭니다:
총 예산
├─ 메일함 생성: 2초
├─ 액션 실행: 5초
...
숫자는 시작점일 뿐이며 공급업체의 약속이 아닙니다. 중요한 것은 이들이 전체 작업 예산에 합쳐진다는 것입니다. 폴링(polling) 도구가 남은 시간만 받으면 실수로 다른 60초를 기다릴 수 없습니다.
간단한 방법은 각 호출마다 마감일(deadline)을 전달하는 것입니다:
{
"task_id": "signup-1842",
"deadline_at": "2026-10-16T02:23:10Z",
...
}
오케스트레이터(orchestrator)가 사용 가능한 시간을 계산합니다. 도구는 이를 자체 최대치로 제한하고 작업을 완료할 수 없는 경우 이유를 반환합니다. 따라서 LLM은 조용한 대기 대신 유용한 신호를 받게 됩니다.
이메일 도구를 위한 작은 계약서
에이전트에게 있어 메일 기능들은 단순한 상태(status)를 노출해야 합니다. 최소한의 계약서는 다음과 같은 작업을 가질 수 있습니다:
create_mailbox(deadline): 사서함을 생성하거나 예약하고 식별자를 반환합니다.
wait_for_message(mailbox_id, after, deadline): 이메일을 보낸 이벤트 이후의 메시지만 관찰합니다.
read_message(message_id, deadline): 전체 사서함이 아닌 필요한 제목, 발신자 및 내용을 반환합니다.
release_mailbox(mailbox_id): 작업에 실패하더라도 리소스를 해제합니다.
각 응답에는 status, elapsed_ms, attempt, 그리고 next_action이 포함되어야 합니다. 예를 들어, status: "not_found"는 status: "provider_error"와 다릅니다. 전자는 추가적인 짧은 조회를 정당화할 수 있지만, 후자는 경로를 변경하거나 진단과 함께 종료해야 함을 의미합니다.
모델에게 모든 세부 사항을 숨길 필요는 없습니다. 다음과 같은 요약만으로 충분합니다:
{
"status": "not_found",
"elapsed_ms": 18000,
...
}
이 계약서와 함께라면, 에이전트는 대기 정책을 스스로 만들 필요가 없습니다. 아키텍처 자체가 제약을 표현하고 있기 때문입니다.
폴링(Polling), 재시도 및 증거
매 초마다 폴링(polling)하는 것은 무해해 보이지만, API를 포화시키고 실행 간 비교를 어렵게 만들 수 있습니다. 대신 짧은 백오프(backoff) 시퀀스, 예를 들어 1초, 2초, 4초, 6초, 8초와 같은 순서를 선호하며, 항상 데드라인에 의해 잘려야 합니다. 만약 이메일이 그 이후에 도착하면, 무한 대기 상태로 만드는 대신 지연된 것으로 기록됩니다.
또한 모든 쿼리(query)마다 영수증을 보관해야 합니다:
- 함(mailbox) 및 작업 식별자;
- 이메일을 발생시킨 이벤트 시점;
- 메시지를 찾기 위해 사용된 필터;
- 관찰된 메시지 수량;
- 각 재시도의 이유;
- 종료까지 남은 시간.
온보딩(onboarding) 흐름에서는 이 규율이 노이즈 없이 온보딩 이메일을 테스트하는 전략과 잘 결합됩니다. 동일한 에이전트가 많은 시나리오를 테스트할 경우, 영수증은 오래된 함과 현재 실행을 혼합하는 것을 방지합니다.
QA 환경의 경우, 일회용 이메일(generate throwaway email)을 생성하고 테스트를 격리하는 데 임시 주소가 유용할 수 있습니다. 이를 실제 신원으로 취급하거나 필요한 것보다 오랫동안 내용을 보관해서는 안 됩니다. 다른 팀의 로그에서는 tamp mail com 또는 temp org mail과 같은 검색이 나타나는데, 이는 에이전트가 추측해야 할 API 이름이 아니라 테스트 의도의 단서입니다.
Q&A: 실질적인 결정 사항
LLM이 타임아웃을 선택해야 하나요?
사전 정의된 예산 중에서 선택할 수는 있지만, 무제한으로 밀리초(milliseconds)를 만들어내서는 안 됩니다. 서버가 최대값을 적용하고 남은 시간을 반환해야 합니다.
이메일이 도착하지 않을 때 재시도하는 것이 좋나요?
시간이 남아 있고 영수증에 쿼리가 유효했음을 보여줄 경우에만 해야 합니다. 두 번째 함을 자동으로 생성하면 원래의 동작과 기대되는 메시지 간의 관계가 손실될 수 있습니다.
공급자가 느리게 응답하면 어떻게 되나요?
제공자 타임아웃(provider_timeout)을 반환하고 증거를 보존합니다. 에이전트는 사용자에게 아무것도 받지 못했다고 주장하는 대신, 의존성이 예산을 초과했음을 설명할 수 있습니다.
기존 프로젝트에서 시작하려면 어떻게 해야 하나요?
먼저 elapsed_ms, remaining_ms 및 mailbox_id를 측정합니다. 그런 다음 마감 기한(deadline)을 추가하고 not_found를 제공자 오류와 분리합니다. 이들은 작은 변경이지만, 전체 자동화 시스템을 재설계하기 전에 실제 비용을 가시화합니다.
신뢰할 수 있는 LLM 에이전트는 기다리는 시간이 가장 긴 것이 아닙니다. 얼마나 오래 기다릴 수 있는지, 어떤 증거를 보존해야 하는지, 그리고 언제 멈춰야 하는지 아는 것입니다. 이 계약은 이메일 도구를 재시도(re-try)가 발생하는 블랙박스가 아니라 시스템의 예측 가능한 구성 요소로 만듭니다.