주문 한 건에는 어떤 실행이 속하는가

가상의 도매 주문 접수입니다. 담당자가 대화창에서 ‘승인된 발주서 37번을 공급사에 넣어 주세요’라고 요청합니다. 에이전트는 발주서와 승인 기록을 찾고 공급사 주문 생성 도구를 호출합니다. 공급사는 주문을 받았지만 응답이 사내 서버에 돌아오지 않습니다. 시간이 지난 뒤 담당자가 다시 요청하고 워커도 이전 실행이 끝나지 않아 재시도합니다. 모델 로그에는 도구 호출 세 건이 남을 수 있습니다. 업무에서 허용한 결과는 발주서 37번의 승인 범위에 속한 공급사 주문 한 건입니다.

도구 호출 ID는 그 시도에서 발생한 일을 추적할 때 씁니다. 대화 ID는 사용자가 어떤 맥락에서 요청했는지 찾을 때 씁니다. 두 값은 새 세션이나 재계획에서 바뀔 수 있습니다. 서버에서는 테넌트, 발주서, 외부 공급사 계정, 허용된 발주 실행 단위를 연결하는 업무 작업 ID를 별도로 저장합니다. 주문 생성과 확인 메일 전송도 각각 식별합니다. 메일에서 응답을 잃어버렸을 때 주문 생성 단계까지 다시 시작하면 이미 확인한 결과가 바뀔 수 있습니다.

업무 키에 원본 문장 전체를 넣으면 문장 표현이 달라질 때 중복이 생깁니다. JSON이 같다는 이유로 같은 업무라고 보는 방식도 위험합니다. 공동구매에서 같은 상품·수량·주소로 두 주문을 승인할 수 있습니다. 담당자가 명시적으로 새 주문을 승인한 경우에는 별도의 업무 의도와 작업 ID가 필요합니다. 반대로 물품이 같아도 공급사 계정이나 납품 주소가 바뀌면 기존 승인과 충돌할 수 있습니다. AWS Builders’ Library는 호출자가 지정한 고유 요청 식별자를 받아 원래 매개변수와 함께 기록하고 같은 키로 다른 조건을 보내는 요청을 거부하는 설계를 제시합니다. AWS의 재시도와 멱등 API 설계[1]

작업 ID는 신뢰된 서버가 발급합니다. 에이전트에 키를 고를 권한을 주면 재계획이 중복 방지 규칙을 바꿀 수 있습니다. 멱등성은 동일한 논리 작업을 반복 요청해도 업무에 추가 효과를 만들지 않도록 하는 성질입니다. 식별자는 그 작업을 참조하는 수단이므로 기존 결과 조회에도 접근권한이 필요합니다. 부서가 다른 사용자가 우연히 같은 발주 번호를 입력하거나 이전 도구 응답에서 작업 ID를 얻더라도 자신의 테넌트와 권한 범위에 속한 상태만 볼 수 있어야 합니다.

승인을 그대로 재사용할 수 있는 범위

승인에는 공급사 계정, 납품 대상, 수량, 가격, 통화, 도구 이름, 승인자, 정책 버전, 만료 시각을 둡니다. 승인된 입력을 서버에서 정규화하고 실행 시 대조합니다. 모델이 줄바꿈을 바꾸거나 JSON 키 순서를 바꾸는 일과 주소·금액을 수정하는 일을 구별하기 위해서입니다. 정규화 규칙을 바꾸면 기존 기록을 어떻게 다시 검증할지도 정합니다.

같은 작업 ID로 요청을 받아도 인자가 다르면 기존 결과를 반환하기 전에 충돌로 분류합니다. 변경 요청은 업무 정책에 따른 별도 승인 경로로 보냅니다. 원래 작업이 아직 결과 불명이면 두 실행이 동시에 살아남을 수 있으므로 외부에 반영된 원래 주문의 상태를 먼저 확인합니다. 원래 주문이 이미 생성됐다면 새 주문과 기존 주문의 변경 중 어느 절차가 맞는지 담당자가 고릅니다. 승인 만료·권한 회수 뒤에는 그 승인을 근거로 쓰기를 재송신할 수 없습니다. 필요한 대사를 허용하는 읽기 권한은 별도로 관리할 수 있습니다. OWASP의 고위험 에이전트 행동 통제[2]

업무 시스템은 승인 이력과 실제 실행 이력을 모두 보존합니다. ‘실행 승인’ 이벤트가 남았는데 외부 주문 ID가 없다면 실행 결과는 별도 조사 대상입니다. 승인 뒤 작업을 두 워커가 동시에 읽고 실행하는 경우에는 실행기나 저장소에서 통제가 이뤄져야 합니다. 대화에서 생성한 문장은 저장소의 유일성 제약과 실행 시 권한 검사를 대신할 수 없습니다.

로컬 기록과 외부 효과가 갈라지는 순간

두 워커가 한 작업을 동시에 잡을 때는 저장소의 유일성 제약과 조건부 상태 변경을 이용해 하나만 실행권을 얻도록 합니다. 업무 작업과 발송할 레코드를 한 데이터베이스 트랜잭션으로 기록할 수 있다면 업무 접수는 남았지만 전달할 작업이 사라지는 구간을 줄입니다. 발송 레코드를 다시 읽을 수 있는 구조에서는 같은 이벤트가 재전달될 수 있으므로, 외부 호출에 쓰는 식별자도 처음 보낸 값으로 고정합니다.

로컬에서 한 워커가 소유권을 갖더라도 그 소유권의 유효시간이 끝날 때 외부 요청이 끝날지는 알 수 없습니다. 이전 워커가 이미 공급사에 보냈거나 중단 직전에 연결이 끊겼을 수 있습니다. 새 워커는 유효시간 만료를 발견하면 실행권 복구와 결과 확인을 분리합니다. 이전 워커의 늦은 결과가 새 상태를 덮지 않도록 변경 버전이나 현재 실행자의 식별자를 대조하되, 외부에서 실제 성공했다는 늦은 증거는 대사 기록에 남깁니다.

내부 ‘전송 중’에 공급사의 주문이 이미 존재할 수 있습니다. 외부 조회가 한 차례 빈 결과를 반환했더라도 조회 API의 반영 지연이나 다른 계정·환경 조회 여부를 확인합니다. 조회가 어느 시점부터 신뢰할 수 있는 부존재 증거인지 공급사 계약과 운영 문서로 확인합니다. 문의나 대사에 쓸 수 있도록 요청에 거래 참조값을 포함하고 당시의 공급사 계정과 운영·시험 환경 구분을 함께 남깁니다.

실행 상태별 재시도 허용표

아래 상태명은 설계 예시입니다. 운영자는 마지막으로 확정된 사실과 다음으로 확인할 사실부터 고릅니다.

작업 상태외부 쓰기 판단다음 행동과 확인 증거
승인 대기 또는 만료우선 실행 보류승인 기록과 만료 시각, 원래 요청의 상태 확인
준비 완료·한 번도 전송하지 않음실행권을 얻은 워커 한 곳에서 진행현재 승인·권한·입력과 조건부 상태 변경을 대조
전송 중·접수 처리 중동시 송신 제한외부 접수 참조값과 상태 조회, 완료 또는 대사 시한 기록
성공 확인기존 실행 결과 반환같은 작업 ID에 연결된 공급사 주문과 사내 상태 대조
실패 확정·외부 효과 없음계약상 재처리 가능하고 승인 유효할 때 허용확정 거부 응답 또는 공급사 확인, 같은 인자와 기존 참조값 유지
결과 불명우선 결과 조회, 계약이 보장하는 범위에서만 동일 요청 허용외부 검색·웹훅·대사 기록 확인, 확인 불가 시 담당자 이관
취소 또는 정정이 필요함기존 실행의 재시도 종료승인된 취소·정정 작업을 별도 ID로 기록하고 결과 대사

HTTP 500이나 연결 오류의 의미는 실행 경계와 공급사 계약으로 정합니다. Stripe는 공식 문서에서 API v1이 실행을 시작한 첫 요청의 상태 코드와 본문을 보관하며 같은 키에 500 응답을 다시 돌려줄 수 있다고 설명합니다. 또한 보관에서 제거된 키를 재사용하면 새 요청이 될 수 있다고 설명하며 API v2의 동작은 따로 기술합니다. 통합 명세에는 공급사별 키 유효기간, 엔드포인트, 입력 충돌, 진행 중 재호출, 오류 응답의 의미를 고정합니다. Stripe의 멱등 요청 문서[3]

외부 서비스에 멱등 키가 없으면 사내에서 문서를 한 번만 전송하도록 제어해도 외부 응답 유실을 끝까지 해결하기 어렵습니다. 고유한 외부 참조값으로 결과를 찾을 수 있는지, 그 참조값을 외부에서도 유일하게 강제하는지 각각 확인합니다. 조회도 불가능하고 결과를 대사할 자료도 없다면 결과 불명 상태에서 자동 재송신을 멈춥니다. 업무에 자동 처리가 필요하면 사람이 공급사 상태를 확인할 운영 경로를 마련하거나 초안 작성과 확인 요청까지로 자동 실행 범위를 제한합니다.

서비스 작동 방식

주문에서 승인과 환불까지 상태를 연결 — 결제수단을 주문 흐름에 붙이고 응답 지연과 재시도, 취소와 환불의 예외를 검증합니다.

실패주입 시나리오 여섯 가지

아래 시나리오는 공급사 모의 서버나 승인된 시험 환경에서 수행합니다. 사용자의 화면, 작업 DB, 외부 원장의 결과를 함께 봅니다. 에이전트의 최종 문장을 성공 판정의 유일한 증거로 쓰면 ‘주문이 들어갔습니다’라는 답과 실제 주문 생성이 어긋난 경우를 놓칩니다. Anthropic의 에이전트 평가에서 실행 기록과 실제 결과를 구분하는 방법[4]

시험실패를 만드는 경계통과 증거
1. 응답 유실공급사가 주문을 저장한 직후 응답을 끊음같은 업무 작업의 외부 주문 한 건 확인, 결과 불명에서 성공으로 복구
2. 새 대화와 재계획사용자가 같은 발주서를 다시 요청하는 동안 모델도 도구를 다시 호출여러 호출이 같은 작업 ID에 연결되고 승인된 주문 한 건 유지
3. 동시 실행과 복구첫 워커가 외부 호출 뒤 정지, 임대 만료 후 두 번째 워커 실행두 번째 워커의 결과 조회와 상태 전이 확인, 외부 신규 주문 없음
4. 입력 변경같은 작업 ID로 수량이나 납품 주소를 바꿔 호출충돌 판정, 외부 호출 없음, 원래 승인과 충돌 값이 구분되어 기록
5. 승인 만료와 지연 응답결과 불명 상태에서 승인을 만료시키고 원래 성공 응답을 늦게 전달추가 쓰기 거부, 늦게 확인된 외부 주문 사실은 대사에 반영
6. 키 만료 또는 미지원외부 조회 응답에 지연을 넣고 유효한 멱등 계약을 제거빈 조회 직후 새 쓰기를 보내지 않음, 담당자가 확인할 발주 참조와 시한 생성

각 시험에서 외부 주문 수와 인자 일치 여부, 고객에게 표시한 상태, 이관 건수, 접근권한 위반 여부를 기록합니다. 성공 후 고객이 다시 같은 작업을 열었을 때 새 작업이 생기는지도 봅니다. 첫 응답이 끊긴 뒤 새 승인을 강제로 받게 하는 방식은 업무 결과 불명 문제를 가립니다. 키를 너무 넓게 공유하면 명시적으로 승인한 두 주문 중 하나가 사라질 수 있으므로 정상적으로 두 번 발주하는 대조군도 필요합니다.

대사로도 바로 결론을 낼 수 없는 경우

대사는 사내 작업 목록과 외부 주문 사실을 양쪽에서 대조하는 일입니다. 주문 ID, 외부 참조값, 공급사 계정, 주문 시각 범위, 수량·금액의 기대값을 이용합니다. 한 작업이 외부 주문 두 건과 일치하거나 다른 발주서의 주문으로도 해석될 때는 자동으로 한 건을 골라 성공으로 확정하지 않습니다. 참조가 빠진 건을 예외 대기열로 보내고 공급사 확인을 연결합니다. 업무 담당자가 읽을 수 있는 시각과 서버에서 비교할 기준 시각을 함께 남기면 교대 인계 과정에서 검색 범위를 놓치지 않습니다.

운영 화면에는 불명 상태의 체류 시간과 담당자, 마지막으로 확정된 결과, 조회가 신뢰할 수 있는 시점, 자동 재처리 가능 여부를 둡니다. 조회 응답의 민감한 원문을 운영 로그에 복제하는 대신 복구에 필요한 식별자에 접근을 제한하고 변경 증거를 남깁니다. 외부 주문이 잘못 생성된 사실을 확인했다면 취소 가능 시간, 이미 발송된 상품, 공급사 상태를 확인한 뒤 승인된 보상 작업을 실행합니다. 보상 자체에도 실패나 응답 유실이 생길 수 있으므로 그 작업에 별도 식별자와 대사 기준을 둡니다.

발주와 결제의 상태를 연결해야 하는 팀은 결제·주문 상태 정합성에서 주문·결제·제공 기록의 범위를 확인할 수도 있습니다. 금액이나 수량이 일부만 바뀐 상황은 부분 취소와 환불액 검증의 원장 비교 기준을 적용할 수도 있습니다. 에이전트 쪽에서는 두 시스템 사이를 다시 호출할 때 유지해야 할 업무 ID와 승인 범위를 함께 시험합니다.