Seedream 5.5 마이그레이션에서 중요한 것은 단순히 모델 이름을 바꾸는 것이 아니라 파일 워크플로입니다. 이미지를 생성하고, 반환된 작업을 확인한 다음, 이미지를 저장하고, 저장한 바이트를 편집용 참조 이미지로 전송합니다.
AIHubMix의 Seedream 5.5는 현재 doubao-seedream-5-5 및 POST /ai/v1/images/generations를 사용합니다. 이 튜토리얼에서는 세라믹 머그 제품 이미지를 생성한 뒤 색상만 바꾸도록 요청합니다.
범위: 2026년 11월 12일에 문서를 확인했습니다. 코드는 로컬 구문 검사와 오프라인 헬퍼 검사만 거쳤으며, 생성 요청은 실행하지 않았습니다. 따라서 출력 품질, 편집 충실도, 지연 시간 또는 실제 청구 금액을 입증하지 않습니다.
1. 간결하고 명확한 요청 준비하기
Python 3.10 이상과 requests를 사용합니다. Bash에서 종속성을 설치하고 셸 기록에 키 값이 남지 않도록 입력합니다.
python3 -m pip install requests
read -r -s -p 'AIHubMix API key: ' AIHUBMIX_API_KEY
printf '\n'
export AIHUBMIX_API_KEY
배포 코드에서는 비밀 관리자를 통해 환경 변수를 주입하세요. 키를 소스 파일, 요청 예시, 로그, 노트북, 브라우저 측 코드에 넣지 마세요. 두 POST 요청을 보내기 전에 비동기 작업 가이드에서 안내한 대로 계정의 작업 기능을 활성화하세요. 이 사전 조건은 동기 대기를 포함한 네이티브 /ai/v1 미디어 작업 엔드포인트에 적용되며, 백그라운드 실행 여부와는 별개입니다.
현재 모델 엔드포인트 스키마를 확인하고, 배열의 위치가 아니라 path를 기준으로 항목을 선택하세요. 모델별 제약 사항은 공통 매개변수 목록보다 우선합니다.
| 설정 | 여기서 사용한 값 |
|---|---|
| 모델 | doubao-seedream-5-5 |
| 경로 | POST /ai/v1/images/generations |
| 본문 | 평면 JSON |
| 크기 | 2048x2048 |
| 이미지 개수 | n = 1 |
| 파일 형식 | png |
| 응답 형식 | url |
스키마는 model과 비어 있지 않은 prompt를 필수로 요구하고, n은 1로 제한하며, 출력 형식으로 png와 jpeg를 명시합니다. image에는 URL, Base64 입력 또는 {url} 객체를 사용할 수 있으며, images는 참조 이미지 최대 14개가 명시된 배열을 받습니다. 이 제한은 여기서 런타임 테스트를 거치지 않았습니다. 이 예시에서는 참조 이미지 하나와 기본 크기를 명시적으로 사용하고, 바깥쪽 input 객체나 extra 확장 항목은 사용하지 않습니다.
2. 이미지 생성, 작업 확인, PNG 저장
통합 이미지 API 문서에는 id, object: image, model, status, output, error가 포함된 작업 응답이 정의되어 있습니다. 이를 이전 형식인 data[0].url로 읽지 마세요.
먼저 간단한 워크플로를 확인하세요. 전체 설정 및 다운로드 헬퍼는 아래의 접힌 부록에 있습니다. 이 예시를 실행하기 전에 부록 코드를 같은 Python 세션에 한 번 불러오세요. 이 코드는 이미지 요청을 제출하지 않고 settings, api_json, collect를 정의합니다. 그런 다음 간단한 코드 블록을 순서대로 실행하세요. 각 POST는 별도의 유료 작업이므로 응답이 없거나 다운로드에 실패했다고 다시 실행하지 마세요.
이미지 요청을 한 번 제출하기
generation = {
**settings,
"prompt": "Product photograph of one matte blue ceramic mug on a cream tabletop, "
"soft side lighting, plain warm-gray background, no text or logos.",
}
task = api_json("POST", IMAGES + "/generations", generation)
작업을 확인한 다음 PNG 저장하기
async를 생략하면 동기 대기 방식이 됩니다. HTTP 200 응답에 status: failed가 포함될 수도 있습니다. 헬퍼는 상태를 확인하기 전에 작업 ID를 저장합니다. completed인 경우에만 다운로드를 진행하고, failed, cancelled 및 알 수 없는 상태에서는 중단합니다. pending과 in_progress 상태라면 새로 생성하는 대신 기존 작업을 확인해야 합니다.
collect(task, "mug-blue")
이 단일 호출은 생성할 때 사용한 키로 완료된 출력을 가져오고, PNG 바이트를 확인한 뒤 mug-blue.png에 저장합니다. 자동 생성 재시도는 하지 않으며, 키를 전달하기 전에 예상하지 못한 다운로드 호스트나 리디렉션은 거부합니다. 전체 구현은 부록에 있습니다. 이는 문서를 바탕으로 설명한 동작이지, 검증된 생성 결과가 아닙니다.
모델 가이드에 따르면 출력 URL은 약 30분 동안 유효합니다. 동일한 Bearer 헤더를 사용해 신속하게 다운로드하고 바이트를 직접 저장하세요. expires_at: null은 영구 보관을 보장한다는 뜻이 아닙니다. b64_json에 값이 있으면 URL을 다운로드하지 말고 이를 디코딩하세요.
3. 보호된 다운로드 URL이 아닌 로컬 파일 편집하기
편집에 비용을 지출하기 전에 저장한 이미지를 직접 확인하세요. 인증된 클라이언트로 다운로드할 수 있는 content_url이 이미지 공급자가 가져올 수 있는 공개 URL이라는 보장은 없습니다. 로컬 PNG를 Data URI로 다시 업로드하세요.
reference = Path("mug-blue.png").read_bytes()
if not reference.startswith(b"\x89PNG\r\n\x1a\n"):
raise SystemExit("The editing reference must be the saved PNG.")
edit = {
**settings,
"prompt": "Change only the mug color from blue to forest green. Preserve the mug shape, "
"camera angle, tabletop, background, lighting, and shadows.",
"image": "data:image/png;base64," + base64.b64encode(reference).decode("ascii"),
}
task = api_json("POST", IMAGES + "/generations", edit)
collect(task, "mug-green")
이 요청은 보존을 요구할 뿐, 실제로 보존됐음을 입증하지는 않습니다. 다음 유료 작업을 진행하기 전에 결과를 검토하세요. 인라인 인코딩을 포함한 전체 JSON 요청은 32 MiB 이하여야 하며, 모델별 미디어 제한도 적용됩니다. 공급자가 실제로 접근할 수 있는 공개 이미지 URL도 허용되는 입력 방식입니다.
4. 선택 사항: 비동기 대기 및 중단 후 복구
1절의 계정 사전 조건은 실행 모드와 별개입니다. 403 async_not_enabled 오류가 표시되면 콘솔에서 작업 기능을 활성화해야 합니다. 선택 사항인 것은 백그라운드 실행뿐입니다.
백그라운드 생성을 원한다면 동일한 generation 딕셔너리를 만든 다음, 아래 두 줄을 동기 방식의 task = api_json(...) 줄과 별도의 collect(...) 호출 대신 사용하세요. 제출 전에 실행 모드를 선택하고 두 버전을 모두 실행하지 마세요.
task = api_json("POST", IMAGES + "/generations", {**generation, "async": True})
collect(task, "mug-blue", poll=True)
헬퍼는 종료 상태에 도달할 때까지 약 15초 간격으로 GET /ai/v1/images/{id}를 조회합니다. 이는 문서에 권장된 폴링 간격이지, 서버가 강제하는 간격은 아닙니다. 웹훅을 사용하려면 async: true가 필요하며, 수신기 설정은 이 튜토리얼의 범위에 포함되지 않습니다.
작업 수집이 중단됐다면 새 세션이 필요한 경우 부록의 공통 설정/헬퍼 블록만 다시 불러오고, 생성 블록은 실행하지 마세요. ID를 저장했다면 POST 없이 재개할 수 있습니다.
task_id = Path("mug-blue.task-id").read_text(encoding="utf-8").strip()
task = api_json("GET", IMAGES + "/" + quote(task_id, safe=""))
collect(task, "mug-blue", poll=True)
편집 작업을 복구할 때는 이에 해당하는 mug-green 이름을 사용하세요. 생성 응답이 사라져 ID를 저장하지 못했다면 최근 작업을 대신 확인합니다.
recent = api_json("GET", IMAGES + "?limit=20&order=desc")
for row in recent.get("data", []):
print(row.get("id"), row.get("model"), row.get("status"), row.get("created_at"))
모델과 생성 시간을 대조하고, 무작정 가장 최근 작업을 선택하지 마세요. 필요한 경우 다음 요청에서 next_after를 after 커서로 사용하세요. 일치 항목이 명확하지 않으면 다시 제출하지 말고 지원팀에 문의하세요. 목록은 특정 시점의 스냅샷이므로 폴링할 때는 작업 상세 정보를 사용하세요. 행에 표시된 output_error는 출력을 읽지 못했다는 뜻이지, 생성 결과가 없거나 요금이 달라졌다는 뜻은 아닙니다.
생성할 때 사용한 키를 계속 사용하세요. 특히 통합 작업 목록, 상세 정보, 콘텐츠 접근은 토큰별로 격리됩니다. 같은 계정의 다른 키로는 해당 작업을 읽을 수 없습니다. 로컬에서 작업이 중단됐다고 해서 실패했거나 요금이 청구되지 않았다는 뜻은 아닙니다.
5. 마이그레이션 실수와 현재 오류
기존 Doubao 어댑터 문서에는 /v1/models/doubao/<id>/predictions 경로와 input 래퍼를 사용하는 이전 ID가 나와 있습니다. 해당 목록에는 5.5가 없습니다. 여기서는 확인 가능한 5.5 경로와 평면 본문을 사용하세요. 이전 방식으로 생성할 때 오류가 나는지는 테스트하지 않았습니다. 점이 포함된 표기가 별칭일 것이라고 가정하지 말고, 현재 하이픈 표기 ID를 그대로 복사하세요.
이 모델의 현재 스키마에 없는 최상위 quality, background, aspect_ratio, seed는 이전 방식 그대로 가져오지 마세요. ByteDance의 출시 발표에는 네이티브 투명 RGBA 출력이 설명되어 있지만, 게이트웨이 스키마에는 background나 layer_decomposition이 없습니다. PNG만 선택한다고 해서 투명 배경을 구현하는 방법이 검증된 것은 아닙니다.
이는 문서에 명시된 통합 이미지 오류이며, 5.5에서 실제로 관찰된 응답은 아닙니다. HTTP 상태와 작업 상태를 따로 확인하고, 전체 메시지 문자열이 아니라 code에 따라 분기하세요.
| 위치 | 코드 | 다음 조치 |
|---|---|---|
| HTTP 400 | schema_violation | 스키마 필드 수정 |
| HTTP 400 | capability_not_supported | 지원되지 않는 옵션 제거 |
| HTTP 504 | sync_timeout | 복구하고 지원팀에 문의 |
| HTTP 502 | task_status_unavailable | 다시 제출하지 않기 |
| HTTP 422 | output_blocked | 콘텐츠 수정 |
| HTTP 403 | async_not_enabled | 작업 기능 활성화 |
| 실패한 작업 | result_delivery_failed | 기존 결과 확인 |
HTTP 502 task_status_unavailable의 경우 가이드에는 다음과 같이 나와 있습니다.
모델 공급자의 작업 상태를 확인할 수 없습니다. 다시 제출하지 마세요. 작업 ID 또는 요청 ID를 알려 지원팀에 문의하세요.
작업 수준의 result_delivery_failed에 대해서는 다음과 같이 안내합니다.
생성된 결과를 전달할 수 없습니다. 자동으로 다시 제출하지 마세요. 작업 ID를 알려 지원팀에 문의하세요.
sync_timeout이 발생했다고 해서 실행이 아예 이뤄지지 않았다는 뜻은 아닙니다. error.tid를 보관하고, 실제로 반환된 경우에만 작업 ID를 사용하세요. 결과가 불확실하면 지원팀에 문의해 해결하세요. 복구 가능한 다운로드 오류가 발생한 경우에는 생성을 다시 하지 말고 결과를 다시 가져오세요. 410 artifact_expired는 다릅니다. 해당 아티팩트는 더 이상 가져올 수 없습니다. 먼저 저장된 파일을 확인하고, 대체 파일이 여전히 필요하면 새 유료 생성을 명시적으로 승인하세요. 429 too_many_downloads가 표시되면 저장된 사본을 확인하거나 지원팀에 문의하세요. 기다리기만 해서는 접근 권한이 다시 생긴다고 보장할 수 없습니다.
가이드에서는 실패한 작업에서 보고된 경우를 포함해 output_blocked에 대한 생성 요금을 명시적으로 면제합니다. 이 예외를 모든 실패 또는 검토 대상 요청에 적용하지 마세요. output_policy_violation에는 기존 콘텐츠 검토 요금 규칙이 적용됩니다.
6. 결과물 하나가 아니라 전체 워크플로를 기준으로 예산 책정하기
Sina Technology의 출시 보도에 따르면 정사각형 2K 이미지 편집 한 번의 비용은 이미지 입력과 출력을 합쳐 약 CNY 0.28이며, 텍스트 토큰은 무료입니다. 이는 언론 보도일 뿐, 공식 요금표나 AIHubMix의 견적으로 검증된 수치는 아닙니다.
예를 들어 기존 이미지를 유료로 두 차례 편집하고, 각각 이 반올림된 시나리오에 해당한다면 비용은 약 2 × CNY 0.28 = CNY 0.56입니다. 초기 텍스트-이미지 생성, 추가 참조 이미지, 추가 후보 이미지, 재시도 비용은 포함하지 않았습니다. 실제 청구 금액을 측정한 값이 아닙니다.
이 생성 후 편집 예시에서는 총액 = 최초 생성 요금 + 참조 이미지 편집 요금으로 계산하세요. 검토한 페이지에서 5.5의 공식 전체 요금표를 확인하지 못했으므로, 이 튜토리얼에서는 고정 총액이나 정확한 구버전 대비 절감 비율을 제시하지 않습니다.
제출 전 확인 사항:
- 현재 ID, 경로, 평면 본문, 모델 스키마를 확인합니다.
- 키는 환경 변수에 보관하고, 복구에 사용할 작업 ID를 저장합니다.
- 각 POST는 별도의 유료 작업이며, 다운로드 재시도가 아님을 유념합니다.
- 편집하기 전에 작업 상태와 저장된 이미지를 확인하세요.
- 올바른 MIME 유형으로 로컬 바이트를 다시 업로드하세요.
- 다시 생성하기 전에 결과가 불확실한 작업부터 복구하세요.
이미지 하나와 의도적인 편집 하나로 시작하고, 파일을 확인한 뒤에만 추가 작업을 진행하세요.
부록: 공통 설정 및 다운로드 도우미
워크플로를 읽을 때는 이 부록을 건너뛰세요. 짧은 예제를 실행하기 전에 이 블록을 펼쳐 같은 Python 세션에 한 번 로드하세요. 세션을 설정하고 함수를 정의할 뿐 이미지를 생성하지는 않습니다. 새 세션에서 중단된 작업을 복구하려면 생성 또는 편집 블록이 아니라 이 블록만 다시 로드하세요.
전체 도우미 펼치기 — 짧은 예제 실행 전에 한 번 로드하세요. 이미지 요청 없음
import base64
import os
import time
from pathlib import Path
from urllib.parse import quote, urlsplit
import requests
BASE = "https://aihubmix.com"
IMAGES = "/ai/v1/images"
settings = {
"model": "doubao-seedream-5-5",
"size": "2048x2048",
"n": 1,
"output_format": "png",
"response_format": "url",
}
client = requests.Session()
client.headers["Authorization"] = "Bearer " + os.environ["AIHUBMIX_API_KEY"]
def api_json(method, path, body=None):
try:
response = client.request(
method, BASE + path, json=body,
timeout=(15, 600), allow_redirects=False,
)
except requests.RequestException:
raise SystemExit(
"Connection interrupted. Recover the existing task before another POST."
) from None
try:
data = response.json()
except ValueError:
raise SystemExit(
f"HTTP {response.status_code}: non-JSON response; recover before another POST."
) from None
if not isinstance(data, dict):
raise SystemExit("Unexpected response; recover before another POST.")
if not 200 <= response.status_code < 300:
error = data.get("error") or {}
raise SystemExit(
f"HTTP {response.status_code}: code={error.get('code')}, "
f"tid={error.get('tid')}. No automatic generation retry."
)
return data
def collect(task, stem, poll=False):
task_id = task.get("id")
if not isinstance(task_id, str) or not task_id:
raise SystemExit("No task ID returned. Recover from the task list; do not resubmit.")
Path(stem + ".task-id").write_text(task_id + "\n", encoding="utf-8")
while True:
status = task.get("status")
print("Task:", task_id, "status:", status)
if status == "completed":
break
if status not in {"pending", "in_progress"}:
error = task.get("error") or {}
raise SystemExit(
f"Stopped: status={status}, code={error.get('code')}; task={task_id}."
)
if not poll:
raise SystemExit("Task still active. Query the saved ID; do not recreate it.")
time.sleep(15)
task = api_json("GET", IMAGES + "/" + quote(task_id, safe=""))
output = task.get("output") or []
if not output:
raise SystemExit("Completed without readable output; investigate the saved task.")
item = output[0]
if item.get("b64_json"):
image_bytes = base64.b64decode(item["b64_json"], validate=True)
else:
url = item.get("content_url")
if not isinstance(url, str):
raise SystemExit("Missing content_url; investigate the saved task.")
parsed = urlsplit(url)
if (parsed.scheme, parsed.netloc) != ("https", "aihubmix.com"):
raise SystemExit("Unexpected download origin; key was not forwarded.")
try:
response = client.get(url, timeout=(15, 120), allow_redirects=False)
except requests.RequestException:
raise SystemExit("Download interrupted; recover this task, not a new generation.") from None
if not 200 <= response.status_code < 300:
try:
detail = response.json()
except ValueError:
detail = {}
error = detail.get("error", {}) if isinstance(detail, dict) else {}
code = error.get("code") if isinstance(error, dict) else None
if response.status_code == 410 or code == "artifact_expired":
raise SystemExit("Artifact expired; retrieval cannot recover it. Check saved files first.")
if code == "too_many_downloads":
raise SystemExit("Download allowance exhausted; check saved files or contact support.")
raise SystemExit(
f"Download HTTP {response.status_code}, code={code}; "
"inspect the saved task. Retry retrieval only if recoverable."
)
image_bytes = response.content
if not image_bytes.startswith(b"\x89PNG\r\n\x1a\n"):
raise SystemExit("Expected PNG bytes; stopped before saving or reusing the result.")
destination = Path(stem + ".png")
destination.write_bytes(image_bytes)
print("Saved:", destination)
return destination
600초 읽기 제한 시간은 클라이언트 설정이지, 서비스 지연 시간에 대한 보장이 아닙니다. PNG 검사는 이 튜토리얼에서 명시한 출력 형식에 맞춘 것으로, JPEG를 선택한다면 그에 맞게 조정하세요.
FAQ
Seedream 5.5에는 어떤 모델 ID와 엔드포인트를 사용해야 하나요?
doubao-seedream-5-5를 사용하고, 평면 JSON과 함께 POST /ai/v1/images/generations를 호출하세요. 다른 표기나 레거시 어댑터가 동일하다고 가정하지 마세요.
이 튜토리얼에 테스트된 생성 결과가 포함되어 있나요?
아니요. 코드는 문서에 기반하며, 로컬 구문 및 오프라인 도우미 검사만 수행했습니다. 추론 요청, 이미지 품질 측정, 지연 시간 측정 또는 요금 청구 테스트는 실행하지 않았습니다.
비동기 처리가 필수인가요?
아니요. 기본값은 동기 대기입니다. 백그라운드 실행에는 불리언 값인 async: true를 사용합니다. 동기적으로 대기하더라도 네이티브 미디어 작업 엔드포인트를 이용하려면 계정 수준에서 작업 기능이 활성화되어 있어야 합니다.
HTTP 200이면 이미지 생성에 성공한 건가요?
아니요. 작업 상태와 오류를 확인하세요. HTTP 요청이 성공해도 작업은 실패했을 수 있습니다. 완료된 후에만 다운로드하세요.
결과 다운로드 URL을 다음 편집의 참조 이미지로 사용할 수 있나요?
그렇다고 가정하지 마세요. 생성에 사용한 API 키로 이미지를 다운로드한 다음, 로컬 이미지를 Data URI로 인코딩하거나 실제로 공개된 이미지 URL을 제공하세요.
시간 초과가 발생하거나 응답을 받지 못했다면 어떻게 해야 하나요?
자동으로 생성을 반복하지 마세요. 저장된 작업 ID를 확인하거나 생성에 사용한 API 키로 이미지 목록에서 작업을 복구하세요. 요청 ID를 보관하고 결과가 불확실하면 지원팀에 문의하세요.
PNG를 선택하면 투명 배경 출력이 보장되거나 CNY 0.28이 청구되나요?
둘 다 아닙니다. 스키마에는 검증된 투명도 제어 기능이 없습니다. CNY 0.28은 보도에서 언급된 대략적인 2K 편집 사례일 뿐, AIHubMix의 견적도 텍스트-이미지 생성과 편집을 합친 고정 요금도 아닙니다.
계속 읽기: Seedream 5.5 시리즈
- 기존 5.0 Pro 워크플로를 변경하기 전에 업그레이드의 가치를 따져보세요: Seedream 5.5 vs 5.0 Pro: 업그레이드할 가치가 있을까요?
- 같은 워크플로에 다른 이미지 모델을 사용할 수 있다면 장단점을 비교해 보세요: Seedream 5.5 vs GPT Image 2.6 Sunburst: 어떤 모델을 선택해야 할까요?
출처
- Seedream 5.5 출시 발표 — ByteDance Seed. 공급자가 발표한 기능 정보.
- 현재 Seedream 5.5 엔드포인트 스키마 — AIHubMix. 요청 필드 및 모델별 제약 조건.
- 통합 이미지 생성 API — AIHubMix. 작업, 다운로드 및 최신 오류 정보.
- Seedream 5.5 모델 가이드 — AIHubMix. 모델 ID 및 유효 기간이 짧은 인증 다운로드. 경로별 오류는 통합 API 문서를 참조하세요.
- Seedream 5.5 출시 보도 — Sina Technology. 공식 요금이 아닌 대략적인 편집 비용 사례.



