이미지 생성 Agent — 중복 과금·결과 뒤섞임·원본 유실을 어떻게 막나
← 전체 목차 · 이전: 전자상거래 Agent는 어떻게 가격을 약속해야 틀리지 않는가 · 다음: AI 숏드라마 캐릭터가 계속 변하는 이유 — 프롬프트가 아니라 자산 관리
"사용자가 생성 버튼을 연속 두 번 누르면 어떻게 하나"라는 질문은 표면일 뿐이고, 실제로는 이미지 생성 Agent의 프로덕션급 실행 사슬 설계를 묻는 것이다. 버튼 디바운스 같은 프런트엔드 패치가 아니라, 비동기 작업·멱등 키·오브젝트 스토리지·상태 머신을 하나의 Agent 실행 사슬 안에 넣고 실패했을 때 안전하게 수습할 수 있는지가 관건이다.
책임 분할은 명확하다. 대규모 모델은 의도 이해, 후보 계획 생성, 다음 호출 결정만 담당하고, 확정적 서비스가 실제 상태와 최종 제약을 담당한다. 그리고 과금과 산출물 귀속은 일률적으로 작업 번호를 기준으로 하며, 재시도는 두 번째 비용을 만들어서는 안 된다.
Agent가 관리해야 할 범위
이미지 생성은 모델의 능력일 뿐이고 Agent가 관리해야 할 범위는 그보다 훨씬 넓다.
| 층위 | 책임 |
|---|
| 대규모 모델 | 이미지 생성 능력만 제공 |
| Agent 시나리오 | 업로드·생성·심사 관리, 과금과 산출물 생명주기 |
대규모 모델이 알아서 우회해 주기를 기대할 수 없다. "비동기 작업 + 멱등 키 + 오브젝트 스토리지 + 상태 머신"을 실행 사슬 전체에 편입시키고 정상 경로, 실패 상태, 다운그레이드 방식 세 가지를 명확히 해야 한다.
업로드: 원본은 오브젝트 스토리지, DB에는 인덱스만
업로드 시 DB에 적재할 필드: 사용자, 파일 해시, 크기, 포맷, 저장 주소. 원본 자체는 오브젝트 스토리지에 두고 DB에는 인덱스만 저장한다.
여기서 도출되는 안전 철칙: 파일명은 사용자 입력을 그대로 신뢰할 수 없다. 다운로드와 표시 모두 현재 사용자와 프로젝트 권한을 재검증해야 한다.
생성: 비동기 작업 + 작업 상태 머신
클라이언트 → 인터페이스 서비스 (생성 요청 수신)
└─ job_id 생성 후 즉시 반환
컨슈머 → 모델 서비스 호출 (실제로 오래 걸리는 부분)
작업 상태는 최소 다섯 가지를 포함하고, 변경될 때마다 시각과 오류 사유를 기록한다.
- 대기
- 처리 중
- 성공
- 실패
- 취소
멱등: 같은 파라미터면 재사용, 재생성은 요청 번호를 바꿔야 한다
| 요청 | 멱등 키 / 요청 번호 | 서버 동작 |
|---|
| 요청 A | 멱등 키 ID_123 | 신규 작업 생성 |
| 요청 A(중복) | 멱등 키 ID_123 | 작업 재사용 |
| 요청 B(재생성) | 새 요청 번호 ID_456 | 신규 작업 생성 |
판정 근거는 같은 입력·파라미터·모델 버전이면 작업을 재사용할 수 있다는 것이다. 정말 다시 생성해야 한다면 클라이언트가 새 요청 번호를 제공한다 — 재생성 의도는 클라이언트가 명시적으로 표현해야 하고 서버가 추측하지 않는다.
과금 시점과 산출물 생명주기
- 과금 시점을 미리 정의해야 한다: 제출 / 성공 / 다운로드 중 하나만 고르고, 작업 상태와 일치시킨다.
- 성공 결과는 영속 스토리지로 옮기고 생명주기와 삭제 정책을 설정한다.
- 실패 로그에 민감한 원본을 무한 보관하면 안 된다.
- 사용자가 프로젝트를 삭제할 때 원본·결과·썸네일과 파생 파일을 함께 처리한다.
과금은 작업 생성과 따로 놀면 안 된다 → 선차감 / 확정 / 실패 시 환급 3단계로 추적 가능한 상태를 만든다.
큐 스케줄링, 타임아웃, 취소
- 큐는 작업 비용과 우선순위로 스케줄링한다. 고해상도 작업 한 묶음이 작은 작업을 막아 세우게 두면 안 된다.
- 모델 서비스 타임아웃 후에는 먼저 이미 생성 성공했는지 조회한 뒤 재시도·환불을 결정한다 — 타임아웃 즉시 재시도가 아니다.
- 취소도 작업 상태를 근거로 한다. 아직 시작하지 않았거나 중단 가능한 단계만 막을 수 있다.
- 다운로드 인터페이스는 프런트엔드 경로를 신뢰하지 않는다: 썸네일, 원본, 공유 링크 모두 권한 검증을 거친다.
한 번의 이미지 생성을 하나의 비동기 작업으로 다루는 절차
0. 클라이언트가 먼저 멱등 요청 번호를 생성
1. 서버가 task_id 생성
2. 사용자 Prompt 요약, 모델 버전, 과금 상태, 출력 자산 위치를 기록
3. 사용자가 연속 클릭 → 같은 멱등 키면 작업 하나만 생성
정말 두 번 생성해야 함 → 명확히 구분되는 작업 두 개를 얻어야 함
4. 과금과 작업 생성이 각자 따로 놀지 않게 → 선차감 / 확정 / 실패 환급으로 추적 가능한 상태 형성
5. 생성 완료 → 이미지·썸네일·심사 결과를 같은 작업에 바인딩
6. 클라이언트는 task_id로 조회. "가장 최근 이미지"로 귀속을 추측하면 안 됨
7. 타임아웃을 즉시 실패로 판정하지 않음 → 재시도 전에 백엔드 실제 상태를 먼저 조회
8. 취소는 아직 시작하지 않았거나 중단 가능한 단계만 막을 수 있음
버튼 디바운스만 답하고 놓치는 업무 클로즈드 루프 다섯 가지: 업무 멱등, 과금 상태 머신, 비동기 조회, 자산 연관, 보상 메커니즘. 이것들이 프로덕션에서 주문이 뒤섞이는지를 결정한다.
검증과 파일 권한 경계
정상 요청 하나만 돌리지 말고 피크 트래픽, 중복 이벤트, 의존 지연, 노드 재시작, 복구 후 상태를 테스트한다.
| 층 | 지표 |
|---|
| 기본 모니터링 | 인터페이스 성공률, 요청 지연 |
| 심층 리소스 지표 | 큐, 커넥션 풀, 캐시 원본 조회, 상태 적체, 사람 인계 건수 |
파일 접근 측면:
- 임시 다운로드 링크에 만료 시각을 설정하고, 프로젝트 삭제 후 기존 링크는 즉시 무효화한다.
- 모델 공급자는 작업 완수에 필요한 파일만 받고 약정에 따라 사본을 삭제한다.
- 이미지 생성 제품은 비용뿐 아니라 원본 소재의 프라이버시 경계도 함께 봐야 한다.
- 업로드부터 삭제까지 모든 단계에 프로젝트 경계와 권한 판단이 있어야 한다. 반증: 어느 한 단계라도 프런트엔드가 넘겨준 파일 주소를 계속 믿는다면 결과 뒤섞임과 월권 다운로드가 다시 나타날 수 있다.
핵심 통찰
- "두 번 누름"은 인터랙션 문제가 아니라 권한과 상태의 문제다 — 버튼 디바운스는 발동 확률만 낮출 뿐 시스템 의미론을 바꾸지 않는다. 중복 과금 여부를 실제로 결정하는 것은 멱등 키, 과금 상태 머신, 작업 번호 귀속이다. 클라이언트에서만 하는 중복 방지는 네트워크 재전송, 페이지 새로고침, 멀티 디바이스 동시 요청에서 전부 무력화된다.
- 모델은 판단을 담당하고 확정적 서비스는 제약을 담당한다 — 모델은 틀려도 되지만 그 오류는 계획 층에서 멈춰야 하고 과금과 산출물 귀속까지 뚫고 내려오면 안 된다.
- 모든 귀속은 작업 번호에 매단다 — 과금, 이미지, 썸네일, 심사 결과가 전부 같은 task_id에 바인딩되고 클라이언트도 task_id로 조회한다. "가장 최근 이미지로 귀속을 추측"하는 것을 허용하는 순간 뒤섞임은 시간문제다.
- 재시도의 전제는 먼저 조회하는 것이지 바로 재발송하는 것이 아니다 — 타임아웃은 실패가 아니다. 모델 서비스 타임아웃 후 백엔드 실제 상태를 먼저 조회한 뒤 재시도·환불을 결정하며, 재시도는 두 번째 비용을 만들면 안 된다. 이것이 "타임아웃 → 재시도 → 중복 과금"이라는 가장 흔한 사고 사슬을 끊는다.
- 과금과 작업 생성이 각자 따로 놀면 안 된다 — 선차감·확정·실패 환급 3단계로 모든 비용이 추적 가능한 상태에 놓여야 한다. 그렇지 않으면 작업은 성공했는데 과금이 실패했거나, 과금은 성공했는데 작업이 유실된 대사 불가능한 더러운 데이터가 된다.
- "프런트엔드 경로를 신뢰하지 않는다"는 점이 아니라 전 사슬을 관통하는 선이다 — 업로드 시 파일명 불신, 다운로드·표시 시 사용자·프로젝트 권한 재검증, 썸네일과 공유 링크도 동일하게 검증. 한 단계라도 남으면 월권 다운로드가 되살아난다.
- 산출물에는 생명주기가 있고 그 안에 비용과 프라이버시가 함께 있다 — 성공 결과의 생명주기·삭제 정책, 실패 로그의 민감 원본 무한 보관 금지, 프로젝트 삭제 시 파생 파일 일괄 정리, 임시 링크 만료, 공급자 사본 삭제. 이미지 생성 제품의 비용 리스크와 프라이버시 리스크는 모두 "산출물이 얼마나 오래 남아 있었나" 안에 숨어 있다.
- 검증의 기준은 정상 경로 통과율이 아니라 이상 경로 커버리지다 — 피크 트래픽, 중복 이벤트, 의존 지연, 노드 재시작, 복구 후 상태가 이 설계의 성립 여부를 가리는 시험장이다.
엔지니어링 실전 Tips
- 멱등 키는 클라이언트가 생성하고, 재생성도 클라이언트가 번호를 바꾼다: 서버가 "이번 클릭이 오조작인지 정말 한 장 더 원하는 것인지"를 추측하지 않는다. 의도 표현의 책임을 클라이언트에 맡겨야 규칙이 확정적이 된다.
- 과금 시점은 하나만: 제출·성공·다운로드 중 하나를 고르고 설계 문서에 명시할 것. 과금 시점이 불확정이면 환불과 대사 로직이 클로즈드 루프를 이룰 수 없다.
- 큐는 등급을 나눌 것: 작업 비용과 우선순위로 스케줄링해 고해상도 작업 묶음이 작은 작업을 전부 막는 것을 방지한다. 이미지 생성 시나리오 고유의 대기 리스크다.
- 작업 상태 변경에는 시각과 오류 사유를 실을 것: 이것이 트러블슈팅 근거이자 보상·사람 인계의 입력이다. 상태만 기록하고 사유를 기록하지 않으면 실패 복구는 추측에 의존하게 된다.
- 모니터링 지표를 제대로 고를 것: 이미지 생성 Agent의 핵심 지표는 큐와 상태 적체이지 인터페이스 성공률만 보는 것이 아니다.
- 사람 인계 건수 자체가 모니터링 지표다: 자동 보상이 실패를 정말 받아냈는지를 재는 최종 건강검진 항목이다.
- 답변 순서를 고정할 것: "목표와 근거 → 핵심 컴포넌트의 역할 → 타임아웃/재시도/버전/권한/실패 복구". 이 순서가 답변을 컴포넌트 나열에서 방안 층위로 끌어올린다.