AI agent tool call timeout 설계: 중복 실행과 취소를 테스트하기
사용자가 AI 에이전트에게 “고객에게 메일을 보내 달라”고 요청했는데 진행 표시만 돌다가 멈춘다. 여기서 AI agent tool call timeout 설계가 다루는 문제는 오류 문구 하나가 아니다. AI 에이전트(AI agent)는 사용자의 목표를 받아 판단과 실행을 이어 가는 프로그램이고, 도구 호출(tool call)은 이 프로그램이 메일 발송이나 티켓 생성 같은 외부 기능에 보내는 요청이다. 제한 시간 초과(timeout)는 화면이 정해 둔 시간 안에 답을 받지 못했다는 뜻일 뿐, 메일이 발송되지 않았다는 뜻은 아니다.
사용자는 더 기다릴지, 취소할지, 다시 실행할지를 화면에서 결정해야 한다. 이 글은 2026년 8월 16일 기준 RFC(Request for Comments, 인터넷 통신 규칙을 기록한 표준 문서), WHATWG(Web Hypertext Application Technology Working Group, 웹 플랫폼 표준을 관리하는 공동체), MCP(Model Context Protocol, AI 애플리케이션과 도구 서버가 취소를 주고받는 공개 규격), Microsoft, Stripe, AWS(Amazon Web Services, timeout과 재시도 운영 지침을 제공하는 클라우드 서비스)의 공식 자료를 대조해 그 결정에 필요한 화면 상태와 서버 책임을 연결한다. 실제 결제·메일·MCP 서버에서 경쟁 상황을 재현한 글은 아니며, 기존 공개 글 ID 257과 현재 주소를 유지해 갱신하기 위한 초안이다.
20초 핵심 요약
- 무엇: timeout 뒤에도 하나의 사용자 요청을 같은 작업 ID로 추적하는 상태 설계다.
- 왜: 실패로 단정하고 다시 실행하면 메일·주문·티켓이 두 번 생기고, 취소로 단정하면 이미 끝난 작업을 화면이 숨길 수 있다.
- 어떻게: 요청·대기·시간 초과·취소 또는 재실행·완료 확인의 다섯 행동마다 화면 문구, 서버 상태, 최종 효과 수를 함께 검사한다.
1. 요청을 받으면 버튼보다 먼저 같은 작업을 식별한다
사용자가 실행 버튼을 누르면 화면은 버튼을 잠그고 요청을 받았습니다를 보여줘야 한다. 회전하는 표시만 보여주면 사용자는 요청이 접수됐는지 알 수 없어 다시 누르기 쉽다. 이때 작업 ID(operation identifier, 작업 식별자)는 한 번의 사용자 의도를 재전송이나 재접속 뒤에도 같은 작업으로 찾는 표식이다. 새 요청과 재시도를 구분하려면 이 표식이 필요하다.
오래 걸릴 수 있는 작업은 접수와 완료를 나눠야 흐름이 명확해진다. 서버는 요청을 검증하고 202 Accepted를 반환할 수 있다. 이는 HTTP(Hypertext Transfer Protocol, 웹에서 요청과 응답을 주고받는 통신 규칙)에서 “요청을 접수했지만 처리는 끝나지 않았다”는 응답이다. Microsoft의 비동기 요청-응답 패턴은 상태를 조회할 위치와 다음 조회 간격을 함께 돌려주는 방식을 설명한다.
여기서 중복을 막는 두 번째 표식이 멱등성 키다. 멱등성(idempotency)은 같은 논리 요청을 여러 번 보내도 사용자가 의도한 최종 효과가 한 번 보낸 것과 같게 남는 성질이다. 같은 작업의 네트워크 재전송에는 같은 키를 써야 하며, 서버는 이미 접수한 작업의 상태를 반환하고 새 작업을 또 만들지 않아야 한다.
2. 기다리는 동안에는 실제로 아는 상태만 보여준다
접수 뒤 화면은 요청됨 → 실행 중으로 바뀌고, 마지막 상태 갱신 시각이나 다음 확인 시점을 보여줄 수 있다. 완료 비율을 계산할 근거가 없다면 90%에서 멈춘 가짜 진행률보다 실행 중이 정확하다. 사용자가 기다림과 멈춤을 구분하는 단서는 숫자 자체가 아니다. 상태를 계속 확인하고 있다는 표시다.
서버 쪽에는 화면을 다시 열어도 조회할 수 있는 상태 기록이 필요하다. 아직 끝나지 않은 대기 중·실행 중과 끝난 완료·실패·취소됨을 구분하고, 생성 시각·마지막 갱신 시각·오류 내용을 보존한다. 상태 조회를 반복하는 폴링(polling)은 화면이 일정 간격으로 서버에 결과를 묻는 방식이다. 구현은 비교적 단순하지만 조회 트래픽과 기록 보존 비용이 생기므로 서버가 알려준 조회 간격을 따라야 한다.
진행 상황을 더 빠르게 보여줘야 한다면 스트림, SSE(Server-Sent Events, 서버가 한 연결로 진행 이벤트를 계속 보내는 방식), WebSocket(화면과 서버가 양방향 메시지를 주고받는 연결), 웹훅(webhook, 완료 뒤 미리 정한 서버 주소로 알리는 방식)을 쓸 수 있다. 하지만 연결이 끊긴 뒤의 복구와 최종 상태 저장은 여전히 필요하다. 전달 방식이 상태 기록을 대신하지는 않는다.
3. 화면의 제한 시간이 끝나도 실패 버튼부터 열지 않는다
화면이 기다릴 수 있는 시간이 끝나면 실패 대신 응답이 늦어 완료 여부를 확인 중입니다를 보여줘야 한다. 상태를 다시 확인하는 버튼은 같은 작업 ID를 조회해야 한다. 메일이나 주문처럼 중복 효과가 생길 수 있는 도구라면, 결과를 확인하기 전에는 새 작업을 만드는 다시 실행을 바로 열지 않는다.
완료 시한(deadline)은 여러 처리 단계가 공유하는 절대 종료 시각이다. 각 단계가 진입할 때마다 새 timeout을 시작하면 전체 작업이 계속 늘어질 수 있으므로, 에이전트 전체 시간에서 남은 시간을 개별 도구 호출에 나눠야 한다. 너무 긴 시간은 연결과 실행 자원을 오래 잡고, 너무 짧은 시간은 불필요한 재시도를 늘린다. AWS의 timeout 지침은 timeout과 재시도 정책을 함께 정해야 하는 이유를 설명한다.
브라우저나 실행기가 취소 신호를 보냈다는 사실도 외부 효과의 중단을 보장하지 않는다. WHATWG의 AbortSignal 규격은 시간이 지나면 중단 의사를 나타내는 신호를 만들 수 있지만, 신호를 관찰하는 쪽이 이미 작업을 끝냈다면 이를 무시할 수 있음을 설명한다. 연결을 닫는 일과 이미 시작된 업무를 되돌리는 일은 별개의 책임이다.
RFC 9110의 멱등 메서드 규정도 응답을 받기 전에 연결이 끊겼다는 이유만으로 중복 위험이 있는 요청을 자동 반복해서는 안 된다고 설명한다. 원 요청이 적용되지 않았다고 확인했거나, 애플리케이션이 같은 효과를 보장할 때만 재시도할 수 있다.
4. 취소와 다시 실행은 서로 다른 사용자 의도로 처리한다
사용자가 취소를 누른 직후 화면에 보여줄 상태는 취소됨이 아니라 취소 요청을 보냈습니다. 결과를 확인 중입니다다. 취소 신호는 “가능하면 그만해 달라”는 의사 전달이며 완료 증명은 아니다. MCP 취소 규격은 취소 알림이 늦게 도착하거나 이미 끝난 작업에서는 무시될 수 있다고 명시한다.
효과 확정(commit)은 메일 발송이나 주문 생성처럼 외부 변경이 되돌리기 어렵게 반영되는 지점이다. 서버가 이 지점 전에 중단을 확인하면 취소됨으로 확정할 수 있다. 효과 확정 뒤 취소가 도착했다면 성공을 취소로 덮지 말고 이미 완료됨 또는 별도의 보상이 필요하다는 결과를 보여줘야 한다.
다시 실행에는 두 의미가 섞일 수 있다. 끊긴 화면에서 같은 의도를 되살리는 행동이라면 기존 작업 ID와 멱등성 키를 재사용한다. 사용자가 정말 새 메일을 한 번 더 보내려는 것이라면 새 작업 ID를 만들되, 기존 작업이 아직 완료될 수 있다는 사실을 먼저 알려야 한다.
Stripe의 멱등 요청 계약은 이를 구체적으로 보여주는 구현 사례다. 같은 키에는 첫 결과를 다시 돌려주고, 같은 키인데 입력 내용이 다르면 오류로 막는다. 키 보존 기간과 결과 저장 시점도 계약에 포함한다. 다만 Stripe의 보존 정책을 모든 도구 서버의 표준처럼 복사해서는 안 된다. 각 서비스는 사용자가 작업을 복구할 수 있는 기간보다 키를 얼마나 오래 보존할지 직접 정해야 한다.
아래 그림은 왼쪽의 사용자 화면에서 시작해 에이전트 실행기, 도구 서버, 실제 메일·주문·티켓이 남는 저장소 순으로 읽는다. 화살표는 호출 횟수가 아니라 어떤 상태를 누가 확정하는지를 나타낸다.

그림에서 기억할 결론은 하나다. timeout과 취소 요청은 최종 상태가 아니며, 같은 작업 ID로 서버의 확정 결과를 다시 확인해야 하는 중간 상태다.
5. 완료 화면은 응답 횟수가 아니라 실제 효과를 확인한다
사용자가 마지막에 봐야 하는 것은 완료, 실패, 취소됨, 또는 이미 완료되어 취소할 수 없음 중 하나로 확정된 상태다. 늦은 성공 응답과 취소 응답이 앞뒤로 도착하더라도 마지막으로 도착한 메시지가 기존 상태를 덮어쓰게 해서는 안 된다. 서버에 남은 작업 상태와 실제 외부 결과를 함께 조회해 하나의 최종 상태를 정해야 한다.
영속 효과 수(durable effect count)는 프로그램이나 연결이 끝난 뒤에도 남는 주문·메일·티켓이 몇 건인지 세는 값이다. 중복 실행 테스트에서는 HTTP 응답이 몇 번 왔는지보다 이 값이 한 건인지가 중요하다. Amazon SQS(Simple Queue Service, 메시지를 보관해 작업자에게 전달하는 대기열 서비스)의 최소 한 번 전달 설명처럼 같은 메시지가 한 번 이상 도착할 수 있는 시스템에서는, 전달 횟수와 효과 횟수를 분리해 검사해야 한다.
상태 기록과 실제 결과가 어긋나면 정합성 복구(reconciliation)로 넘긴다. 이는 내부 기록과 외부 결과를 다시 조회해 어느 결과가 실제인지 맞추는 복구 절차다. 자동으로 새 효과를 만드는 대신 사람 검토가 필요하다는 상태를 남기는 것도 유효한 최종 처리다.
timeout·취소·중복 실행 테스트는 이 표를 통과해야 한다
| 장면 | 화면에서 보여줄 결과 | 서버에서 확인할 결과 | 합격 조건 |
|---|---|---|---|
| 정상 완료 | 실행 중 → 완료 | 시한 전에 완료 상태 저장 | 작업 1개, 실제 효과 1개 |
| 효과 확정 뒤 응답만 timeout | 완료 여부 확인 중 → 완료 | 같은 작업 ID 조회에서 성공 | 실제 효과 1개 |
| timeout 뒤 같은 작업 재시도 | 기존 작업 확인 또는 기존 결과 | 같은 작업 ID·키 재사용 | 요청 횟수와 무관하게 실제 효과 1개 |
| 같은 키에 다른 입력 | 충돌을 알리고 새 작업 여부 확인 | 두 번째 입력 거부 | 두 번째 입력의 효과 0개 |
| 효과 확정 전 취소 | 취소 요청됨 → 취소됨 | 중단 뒤 취소 상태 확정 | 실제 효과 0개 |
| 효과 확정 후 취소 | 취소 요청됨 → 이미 완료됨 또는 보상 필요 | 성공 상태를 취소로 덮지 않음 | 실제 효과 1개 |
| 완료 응답과 취소가 경쟁 | 결과 확인 중 → 서버 최종 상태 | 도착 순서가 달라도 한 상태로 수렴 | 최종 상태 1개 |
| 탭이나 연결 종료 | 재접속 뒤 기존 작업 표시 | 작업 ID로 기존 상태 복구 | 새 작업 0개 |
재시도 간격 늘리기(backoff)는 실패가 반복될수록 다음 요청을 늦춰 서버가 회복할 시간을 주는 방법이다. 무작위 지연(jitter)은 여러 사용자가 같은 순간에 다시 요청하지 않도록 간격을 흩뜨린다. 두 방법 모두 과부하를 낮추지만 중복 효과까지 막아 주지는 않는다. AWS의 재시도 지침에 따라 재시도 횟수와 총 시간을 제한하고, 재시도 책임은 한 계층에 둬야 한다.
소프트웨어 개발 도구 모음(SDK)은 API(Application Programming Interface, 프로그램끼리 기능을 요청하는 접점) 호출 코드를 쉽게 쓰게 하는 라이브러리다. SDK, 에이전트 실행기, 전체 작업 관리자가 각각 재시도하면 실제 시도 횟수가 곱해질 수 있다. 지속적 통합(CI)은 코드가 바뀔 때마다 자동 테스트하는 절차이며, 위 경쟁 조건을 여러 이벤트 순서로 반복해 이전에 막은 중복이 다시 생기지 않는지 확인하는 역할을 맡는다.
동기 대기와 상태 조회 중 무엇을 선택할까
| 선택 | 맞는 조건 | 얻는 것 | 지불하는 비용 |
|---|---|---|---|
| 같은 연결에서 완료까지 대기 | 짧고 지연 변화가 작은 읽기 작업 | 단순한 구현과 화면 흐름 | 긴 작업에서 연결 점유와 완료 불명 위험 |
| 202 응답 뒤 상태 조회 | 수초에서 수분 걸리고 외부 효과가 있는 작업 | 재접속·취소·최종 상태를 같은 작업으로 확인 | 상태 저장, 조회 트래픽, 인증·보존 정책 |
| 스트림 또는 양방향 연결 | 진행 상황을 즉시 보여줄 가치가 큰 작업 | 빠른 진행 이벤트 | 재연결과 유실 복구가 복잡하며 상태 저장은 별도 필요 |
| 웹훅 | 신뢰할 콜백 주소가 있는 서버 간 장기 작업 | 반복 조회 감소 | 콜백 인증·재전송·수신 서버 운영 |
외부 효과가 없는 짧은 조회라면 동기 대기가 더 단순할 수 있다. 메일·주문·티켓처럼 되돌리기 어렵고 실행 시간이 흔들리는 작업이라면 202 응답, 상태 조회, 멱등성 기록을 함께 두는 편이 사용자에게도 운영자에게도 안전하다. 다만 멱등성 기록과 외부 효과 저장 사이에서 프로세스가 멈추는 구간, 여러 작업자가 같은 키를 동시에 잡는 상황, 키 만료 뒤 재사용은 이번 조사에서 직접 검증하지 않았다. 실제 도입 전에는 해당 저장소와 도구 API의 원자성 및 보상 방식을 별도로 시험해야 한다.
적용 전에는 세 분류부터 끝낸다
모든 도구에 같은 무거운 구조가 필요한 것은 아니다. 운영 중인 도구를 읽기 전용, 반복해도 같은 효과, 중복되면 손실이 생김으로 먼저 나눈다. 세 번째 그룹에는 작업 ID, 같은 멱등성 키, 상태 조회, 취소 확인, 영속 효과 수 테스트가 함께 있어야 한다.
기존 공개 글에 기록된 2026년 8월 5일 Linux·Node.js v18.19.1 로컬 모의 실험은 키가 없을 때 요청 2건과 효과 2건, 같은 키일 때 요청 2건과 효과 1건을 보였다. 이 수치는 이번 조사에서 재실행한 결과가 아니라 기존 글의 좁은 비교 기록이며, 실제 다중 작업자나 외부 서비스의 보장으로 확대할 수 없다. 조사 시점 Node.js 문서는 v26.7.0이므로 버전 간 세부 이벤트 순서도 동일하다고 단정하지 않는다.
운영 중인 도구를 세 그룹으로 분류한 뒤 timeout, 취소와 완료의 경쟁, 같은 키 재시도를 CI에 넣는다. 새 기능을 더하기 전 화면의 최종 상태가 하나인가, 같은 작업 ID로 복구되는가, 실제 효과가 의도한 수만 남는가를 통과시키면 된다.