모범 사례
이 문서는 영문 원고를 AI로 번역한 내용이라 표현이 어색할 수 있습니다.
모비두 백엔드 연동용 사례 하나입니다. create → receipt → 클립 재시도가 어떻게 이어질 수 있는지 보여주는 예이며, 계약서가 아닙니다.
팀 워크스페이스 API 키: 팀 Format에는 팀 키가 필요합니다.
API 표면: 라이브 커머스 API.
input과 typed receipt 깊이:
Format 호출하기 — 요청 본문,
구조화 출력.
1. Create 예시
instruction + 편한 형태의 input + 파트너 output_schema(typed receipt —
완성본과 씬별 클립). 탭은 같은 body의 cURL / TypeScript / JavaScript /
Python입니다.
Example create — AHC 30 s live cut
POST /v1/formats/{handle}/{slug}/runs
create body에서 반드시 맞춰야 하는 것
이 body에서 실제로 하중을 받는 것은 네 가지입니다. 위 탭이 보내는 body를 그대로 펼친 것입니다 — 이 호출은 34.72초 컷, 씬 7개, $7.02로 돌아왔습니다. 긴 문자열만 길이 때문에 줄였습니다:
output_schema는 객체 전체입니다 — { name, strict, schema }이고 JSON
Schema를 그 안에 그대로 실어야 합니다. 등록된 이름만 보내는 것으로는 부족합니다.
primary_output_key와 함께 보내고, 적용됐는지 확인하세요. create 응답이
output_schema.source를 돌려주는데, 보낸 스키마가 적용됐다면
request_override입니다.
generation_spend_cap_usd는 0이 아니어야 하고 예상치보다 넉넉해야 합니다.
0이거나 빠뜨린 것은 "무제한"이 아닙니다. 위 실행의 cap은 $20이었고 실제 청구는
$7.02였습니다.
input은 평평한 snake_case입니다 — product_url, product_name,
on_card_name, host_image_url, vo_language, price, highlights,
script.segments. 래퍼 키 아래로 감싸지도, camelCase로 바꾸지도 마세요.
파트너 쪽 대문자 태그가 그대로 동작합니다. INTRO / MID / FIN을 보내기
전에 변환할 필요가 없습니다. receipt는 act와 tags에서 Intro / Mid /
Fin으로 정규화해 돌려줍니다. 비교는 보낸 표기가 아니라 receipt의 표기를
기준으로 하세요.
인식되는 input 키가 없는 요구사항은 전부 instruction으로 갑니다. 위 실행도
"segments를 그대로 사용", "대본을 늘리지 말 것", "무BGM·무자막·9:16"을 거기에
넣었습니다.
길이를 정하는 것은 대본 분량입니다
길이 파라미터는 없습니다. 완성본 길이는 대본을 읽는 데 걸리는 시간이고, 따라서
길이를 조절하는 유일한 손잡이는 script.segments에 넣는 글자 수입니다. 이
자료에서 한국어 기준으로 유지된 비율은 초당 약 8.2자였습니다 — 283자가
34.72초 컷으로 돌아왔습니다. 대본을 쓰기 전에 분량을 가늠하는 용도로 쓰세요.
SLA가 아니라 기획용 숫자입니다.
run이 돌아옵니다:
terminal까지 기다리세요 — status_url / result_url 폴링이나
run 웹훅(format.run.terminal)입니다. 웹훅은 씬마다가
아니라 턴마다 한 번입니다.
받은 뒤에는 운영자에게 보여주기 전에 receipt가 보낸 대본을 실제로 담고 있는지
확인하세요. middle: []와 closing: []도 스키마상 유효하기 때문에, 대본 일부만
읽은 실행이 오류 없이 completed로 돌아올 수 있습니다. 돌아온 행의 script
텍스트를 보낸 segments와 대조하는 것이 값싼 방어선입니다.
2. Receipt 예시
위 스니펫은 값을 채워 쓰는 템플릿입니다. 여기서부터는 전부 실제 프로덕션
실행을 그대로 옮긴 것입니다 — Format v5의 arun_42ed6a48b3d44092, 한국어
선크림 컷, 씬 11개, 73.36초, $14.96. 그래서 아래 media.sume.com URL은 지금
열리는 실제 파일입니다. 길이 때문에 씬 11개 중 3개만 남겼습니다(sc_1–sc_3,
sc_5, sc_6, sc_8–sc_10 생략). 스키마 세부:
구조화 출력.
“이 클립 다시 만들기”를 붙이려면 이 턴에서 네 가지를 저장해 두세요:
| 저장 | 어디서 | 쓰임 |
|---|---|---|
run.id | create 응답 | 재시도의 previous_run_id가 됩니다 |
thread_id | create 응답 | 한 제작물의 모든 턴을 묶습니다 — 읽기 전용, 요청 body에는 절대 넣지 않습니다 |
scene.id | receipt의 각 행 | 재시도할 클립을 지목합니다 — 제작물 동안 고정이므로 배열 인덱스로 잡지 마세요 |
scene.status | receipt의 각 행 | stand-in / failed이 재시도 버튼을 켜는 신호입니다 |
scene.id는 불투명한 문자열로 저장하세요. 이 실행은 sc_0 … sc_10을
돌려줬지만, 이전 Format 버전의 제작물은 다른 모양을 돌려줬습니다. receipt가
주는 값을 그대로 저장하고, 파싱하거나 직접 만들어 쓰지 마세요.
이 실행은 모든 씬이 succeeded로 돌아왔습니다. 그래서 아래 재시도는 실패
복구가 아니라 운영자가 다른 테이크를 요청한 경우입니다. 다른 트리거는 재시도
대상으로 돌아온 행입니다 — 대시보드는 아래 둘 중 하나에서 “이 클립 다시
만들기”를 켭니다:
status는 설명용 예시입니다 — 이 제작물은 11/11 succeeded였습니다.
3. Retry 예시
대시보드 루프: 운영자가 클립을 고름 → 백엔드는 이미 previous_run_id(create
run id)와 scene_id(receipt 행)를 갖고 있음. 같은 Format 엔드포인트에
input.scene_id + **create와 같은 output_schema**를 실어 보냅니다. typed
receipt 모양이 그대로 유지됩니다.
thread_id는 body에 넣지 마세요. 응답 전용 필드이며, 보내면
unknown_parameter로 거절됩니다. 대화를 잇는 키는 previous_run_id
하나뿐입니다.
남는 것은 instruction이고, 무엇이 돌아올지를 결정하는 필드가 바로 이것입니다.
씬별 구체 피드백을 넣으세요
운영자가 테이크가 마음에 들지 않아 “이 클립 다시 만들기”를 누른 경우라면, 그
이유를 물어보고 그 답을 instruction에 실어 보내세요 — 어느 씬인지, 무엇이
잘못됐는지, 어떻게 바꿔야 하는지. 실제 피드백을 담은 재시도가 권장 형태이고,
아래의 고정 템플릿은 기본값이 아니라 대체 수단입니다.
instruction에 넣을 네 부분입니다. 제작물이 돌아가는 언어 그대로 쓰면 됩니다:
- 씬 —
scene_id와 role을 산문으로도 한 번 더 적어 지목을 분명히 - 관찰된 결함 — 운영자가 이 테이크에서 실제로 본 것
- 구체적인 수정 — 형용사가 아니라 지시로, 대신 무엇을 할지
- 가드레일 — VO 스파인·대본 텍스트·인물·의상·세트 유지, 세로 9:16, 무BGM, 무자막
아래 두 instruction 예시는 같은 레시피의 다른 제작물에서 그대로 가져온
것입니다. 위 receipt들과는 다른 스레드라 previous_run_id가 §2와 다릅니다.
receipt가 아니라 요청 body로 보세요.
첫 번째는 빈 공간에 제품만 떠 있는 패키지샷으로 돌아온 broll 씬입니다. 배너
규칙을 눈여겨보세요 — 화면 안 카드/배너 타이포는 프레임 높이 상단 40%
안에서 끝나야 합니다. 하단은 라이브 UI가 덮기 때문입니다.
Example retry — scene note in the instruction
POST /v1/formats/{handle}/{slug}/runs
두 번째 talk 씬도 같은 방식입니다 — 같은 네 부분, 다른 결함. 인사 구간에서
호스트의 시선이 떨어지고 눈이 감기는 프레임이 있었던 경우입니다:
왜 이렇게까지 하냐면: 고정 템플릿으로 재시도한 talk 씬이 운영자가 거절한
바로 그 테이크와 바이트 단위로 동일하게 돌아온 적이 있고, 같은 씬을 위와
같은 피드백과 함께 재시도했을 때는 다시 렌더링되어 시선이 고쳐졌습니다. API
보장이 아니라 연동 가이드로 받아들이세요 — 고정 템플릿 재시도가 항상 동일하게
돌아온다는 보장도, 구체 피드백이 항상 바뀐다는 보장도 없습니다. 통제할 수
있는 것은 instruction이 얼마나 많이 알려주는가입니다. §5에서 이런 재시도를 끝까지
측정했습니다 — 가격 카드에 지시한 여덟 가지 수정이 전부 반영됐고, 나머지 여섯
클립은 그대로였습니다.
기본 템플릿은 기계적 재시도용입니다
stand-in / failed로 돌아온 행에는 설명할 것이 없습니다 — 운영자가 거절할
테이크 자체를 본 적이 없으니까요. 이 경우에는 고정 템플릿이 맞고, 단순히 “한
번 더 돌려”인 경우에도 정직한 기본값입니다:
Example retry — selected scene on the same thread
POST /v1/formats/{handle}/{slug}/runs
새 run, 같은 thread:
여러 클립을 한 번에 재시도하는 것도 같은 호출입니다 — scene_ids와 복수형
instruction만 바뀝니다:
클립 재시도는 씬이 어떻게 보이는지를 다시 렌더링합니다. 무엇을 말하는지 — 문구, 가격 낭독, 길이 — 를 바꾸는 것은 새 씬 id가 붙는 새 제작입니다. 클립 재시도로 바꿀 수 있는 것과 없는 것을 보세요.
버튼을 붙이기 전에 알아둘 두 가지
한 스레드의 재시도는 직렬로. 같은 previous_run_id로 재시도를 두 개
동시에 보내지 마세요 — 제작 스레드 하나에 진행 중인 턴 하나입니다. 첫 재시도가
terminal에 도달할 때까지 두 번째는 큐에 넣어 두세요. 한 턴에서 여러 씬을
고치는 용도로는 scene_ids가 있습니다.
previous_run_id는 스레드를 고르는 것이지 스냅샷을 고르는 것이 아닙니다.
예전 run id를 넣어도 그 시점 receipt에서 분기되지 않습니다. 새 receipt는
스레드의 최신 씬 상태로 조립되므로, 앞선 턴이 이미 바꾼 씬은 바뀐 채로
남습니다. 재시도를 비교할 때는 create가 아니라 직전 턴의 receipt와
비교하세요.
4. Retry receipt 예시
다시 전체 receipt입니다 — opening / middle / closing 목록 전체이며,
패치도 변경분도 아닙니다. sc_7만 새 미디어 URL을 갖고, 나머지 씬은 갖고
있던 URL을 그대로 유지하며 full_video가 다시 조립됩니다. 눈으로 비교할
수 있게 위와 같은 세 행을 실었습니다:
두 receipt가 실제로 증명한 것:
Create arun_42ed6a48b3d44092 | Retry arun_808e4eb3e6c04cf7 | |
|---|---|---|
thread_id | thr_96012fce-… | 동일 |
| 돌아온 씬 행 수 | 11 | 11 — 패치가 아니라 전체 목록 |
| 나머지 씬 URL | — | 11개 중 10개가 바이트 단위로 동일 |
sc_7 URL | artf_nlQMSVkb… | 새 URL — artf_Hy18xtqP… |
sc_7 길이 | 17.76초 | 17.76초 — VO 스파인 안 움직임 |
full_video | 73.360초, 12,049,030 B | 재조립, 73.360초, 12,080,322 B |
| 청구액 | $14.959638 | $0.742530 — 약 20분의 1 |
| 소요 시간 | 11분 08초 | 2분 53초 |
재시도 뒤에도 이전 sc_7 URL은 여전히 200으로 열립니다. 이전 턴의
아티팩트는 변경되지 않으므로, 이미 저장해 둔 create receipt는 계속 유효합니다.
두 테이크를 모두 보관하고 운영자가 고르게 해도 됩니다.
다시 만든 클립은 재인코딩이 아니라 새 생성입니다. 프레임 안의 생성물은 테이크마다 달라질 수 있습니다. 위 사례에서도 구조화된 오버레이 사실(가격, 할인 표기, SPF 등급, 구성)은 정확히 유지됐지만, 제품 아트에 렌더링된 장식용 패키지 문구는 표현이 바뀌었습니다. 운영자에게 “한 군데만 고쳐진 똑같은 프레임”을 약속하지 마세요. 약속할 수 있는 것은 다른 테이크입니다.
5. 더 짧은 한 쌍, 측정값
§2–§4는 73초, 씬 11개짜리 제작물입니다. §1에 나온 34.72초 컷에서 같은 루프를 한 번 더 볼 만합니다. 한 씬만 고치는 재시도가 전체를 다시 만드는 것에 비해 얼마나 싼지 숫자로 나오기 때문입니다:
Create arun_206837aa88d34c8d | 지시형 retry arun_0c315b373e24433a | |
|---|---|---|
| thread | thr_45c64858-… | 동일 |
previous_run_id | null | arun_206837aa88d34c8d |
| 보낸 대본 | 한국어 283자, INTRO / MID / FIN | — |
| 결과 | 34.72초, 씬 7개 전부 succeeded | 34.72초, 씬 7개 중 하나만 이동 |
| 청구액 | $7.0221 | $0.7361 |
| 소요 시간 | 10분 08초 | 2분 24초 |
retry body는 §3의 모양 그대로이고 그 이상은 없습니다 — previous_run_id,
input: { "scene_id": "sc_5" }, create와 동일한 output_schema, 그리고
씬·결함·수정을 지목하는 instruction. sc_5는 클로징 가격 카드로, 제품명과
가격만 얹힌 under_banner 씬이었습니다. 줄여서 옮기면:
고칠 씬: sc_5 (under_banner / Fin, 클로징 가격 카드, 9.44초).
지금 무엇이 잘못됐는지: 카드에 제품명과 가격만 있고, 이 상품의 핵심 소구점인 자외선 차단 지수(SPF50+ PA++++)가 빠져 있습니다. … "30% 할인"이 카드에서 가장 크게 잡혀 있고, 정작 소비자가 결제하는 금액인 23,030원이 그보다 작게 보입니다. … 제품 이미지 위쪽에 빈 여백이 크게 남아 카드 상단이 비어 보입니다.
어떻게 바꿀지: 제품명 바로 아래에 "SPF50+ PA++++" 한 줄을 배지 형태로 추가해 주세요. … 판매가 23,030원을 카드에서 가장 큰 요소로 만들어 주세요. "30% 할인"은 그보다 작게, 보조 배지로 내려 주세요. 정가 32,900원은 취소선을 유지해 주세요. … 배경 톤, 카드 색감, 제품 사진 구도(박스 1개 + 튜브 2개)는 지금 그대로 두세요.
형용사가 아니라 편집 지시로 된 요구 여덟 개, 그리고 그 뒤에 바꾸지 말 것
목록. 여덟 개가 모두 반영됐고, sc_5 밖은 아무것도 움직이지 않았습니다:
| 행 | 변경 |
|---|---|
sc_0–sc_4, sc_6 | 없음 — 여섯 개 모두 아티팩트 URL 동일 |
sc_5 | 있음 — artf_psot5zRM…/images.png → artf_GWQTB6n2…/timeline.mp4 |
full_video | 있음 — 재조립, 34,720 ms 그대로, 바이트는 다름 |
full_video가 아니라 씬별 URL을 비교하세요. full_video는 턴마다 다시
조립되므로 클립이 실제로 다시 렌더링됐는지와 무관하게 URL이 바뀝니다. 그것만으로는
아무것도 증명하지 못합니다. 신호는 씬별 URL이고, talk 씬은 바이트 해시까지
비교하세요 — talk 재시도가 새 URL에 바이트 단위로 동일한 미디어를 돌려준 사례가
있습니다.
scene.video가 항상 영상인 것은 아닙니다. create receipt에서 sc_5.video는
PNG 스틸이었습니다 — "type": "image", "content_type": "image/png"이고
width·height·duration_ms가 전부 null, 길이는 행의
duration_seconds: 9.44에만 있었습니다. 재시도 뒤 같은 씬 id는 MP4를 들고
있었습니다 — "type": "video", 720×1280, duration_ms: 9440. 영상 엘리먼트가
재생할 수 있다고 가정하지 말고 행마다 type과 content_type을 읽고, 길이는
duration_seconds에서 가져오세요. 같은 씬 id에서도 턴이 바뀌면 타입이 바뀔 수
있습니다.
한 씬만 고치는 재시도가 여기서는 재생성의 약 10분의 1이었습니다 — $7.02 대비 $0.74, 10분 08초 대비 2분 24초. 운영자가 클립 하나를 바꾸고 싶어 한다면 그 클립을 재시도하세요. 제작물을 다시 돌리는 것은 같은 수정을 비싸게 얻는 방법입니다.
루프는 여기까지입니다. 세부는 라이브 커머스 API와 구조화 출력에 있습니다.

