본문으로 건너뛰기

나노 바나나 프로 API 사용법: 공식 JSON·YAML 설정과 이미지 저장

나노 바나나 프로는 gemini-3-pro-image로 호출합니다. 공식 요청 JSON과 앱 설정을 구분하고, 응답의 모든 이미지 블록을 실제 MIME에 맞춰 저장하는 흐름을 코드로 구현합니다.

LaoZhang AI Team게시업데이트 9 분 소요
목차
앱 JSON·YAML에서 API 계약을 선택하고 모든 응답 이미지를 저장하는 흐름

나노 바나나 프로 API를 새로 연동한다면 gemini-3-pro-image 모델과 Google Interactions API로 시작하면 됩니다. 요청에는 model, input, response_format을 넣고, 응답에서는 steps 안의 이미지 블록을 찾아 저장합니다. 앱에서 쓰는 JSON·YAML 기획 데이터를 그대로 전송하거나, 다른 공급자의 요청 형식을 섞으면 안 됩니다. 공식 이미지 생성 가이드

2026년 10월 7일 확인한 공식 자료를 기준으로 아래에 요청 파일, 설정 변환기, 이미지 저장기를 제공합니다. 코드는 로컬에서 JSON 문법·자료형·합성 응답 처리만 확인했으며, 실제 API 수락 여부나 생성 품질·지연 시간·청구액을 측정한 결과는 아닙니다.

공식 Pro 요청 JSON부터 만듭니다

다음 내용을 request.json으로 저장합니다. 이 예시는 참조 이미지 없이 텍스트만으로 이미지를 만드는 요청입니다. mime_type은 원하는 출력 형식이고, 저장할 때는 실제 응답의 MIME을 다시 확인합니다.

json
{
  "model": "gemini-3-pro-image",
  "input": [
    {
      "type": "text",
      "text": "독립 커피 브랜드의 웹사이트 대표 이미지를 만들어 주세요. 무광 검정 커피백 한 개를 중앙에 배치하고 따뜻한 아침 창가광을 사용하세요. 좌우에는 여백을 남기고, 가격이나 새로운 로고는 넣지 마세요."
    }
  ],
  "response_format": {
    "type": "image",
    "mime_type": "image/png",
    "aspect_ratio": "16:9",
    "image_size": "2K"
  },
  "store": false
}

호출 주소는 https://generativelanguage.googleapis.com/v1beta/interactions입니다. Google 프로젝트의 사용 가능한 API 키와 유료 Pro 이용 조건을 준비한 뒤 실행합니다. 아래 YOUR_GOOGLE_API_KEY는 자리표시자이며, 운영 코드에서는 비밀 관리 기능으로 주입하고 브라우저나 공개 저장소에 노출하지 않습니다.

bash
curl --silent --show-error --fail-with-body \
  "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: YOUR_GOOGLE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @request.json \
  --output interaction-response.json

성공하면 interaction-response.json에서 모델 출력과 이미지 데이터를 확인합니다. HTTP 200만으로 이미지 파일이 생겼다고 판단하지 말고, 아래 저장기의 반환 파일 수까지 확인하세요. 오류 응답도 같은 파일에 남으므로 실패했을 때는 먼저 error.code와 error.message를 읽습니다.

store: false는 이 예시를 단발 요청으로 사용하는 선택입니다. 기본값인 true에서는 서버에 대화 상태가 저장되지만, false로 생성한 ID를 후속 서버 대화에 사용할 수 없습니다. 연속 편집이 필요하면 승인된 보존 설정으로 previous_interaction_id를 사용하거나, 필요한 전체 대화 기록을 직접 보내는 방식을 정합니다. 이전 ID가 이어 주는 것은 대화 기록이며, 도구·시스템 지시·생성 설정은 요청마다 다시 지정해야 합니다. store: false만으로 전체 경로의 ZDR을 보장하지는 않습니다. Interactions 상태 관리, 민감 자료 전송 전 데이터 보존 확인

모델 이름에 -preview를 덧붙이지 않습니다. Google은 Pro의 안정 버전과 이전 preview의 전환을 별도로 공지했으며, 다른 공급자가 사용하는 preview 별칭은 Google의 현재 모델 ID를 증명하지 않습니다. 지원 종료 및 전환 일정

응답의 모든 이미지를 실제 MIME에 맞춰 저장합니다

여러 이미지나 텍스트가 함께 반환될 수 있으므로 첫 번째 항목만 읽는 코드는 피합니다. SDK의 output_image 단축 속성도 마지막 이미지 하나만 반환합니다. 여기서는 REST 응답의 steps 중 type: model_output인 단계에서 type: image인 블록만 저장합니다. 같은 이미지를 단축 속성과 단계 목록에서 중복 저장하지 않습니다. 공식 응답 처리 설명

아래 전체 코드를 save_images.py로 저장합니다. Python 표준 라이브러리만 사용하며 API를 호출하지 않습니다. 기존 파일을 덮어쓰지 않도록 호출마다 새 출력 폴더를 지정하세요.

python
import base64
import binascii
import json
import sys
from pathlib import Path

EXTENSIONS = {
    "image/png": ".png",
    "image/jpeg": ".jpg",
    "image/webp": ".webp",
}


def save_images(response, destination):
    if not isinstance(response, dict):
        raise ValueError("응답의 최상위 값은 객체여야 합니다.")
    if response.get("error"):
        raise ValueError(f"API 오류: {response['error']}")
    steps = response.get("steps", [])
    if not isinstance(steps, list):
        raise ValueError("steps는 배열이어야 합니다.")

    images = []
    for step in steps:
        if not isinstance(step, dict):
            raise ValueError("단계 값은 객체여야 합니다.")
        if step.get("type") != "model_output":
            continue
        content = step.get("content", [])
        if not isinstance(content, list):
            raise ValueError("content는 배열이어야 합니다.")
        for block in content:
            if not isinstance(block, dict):
                raise ValueError("출력 블록은 객체여야 합니다.")
            if block.get("type") != "image":
                continue
            mime = block.get("mime_type")
            data = block.get("data")
            if not isinstance(mime, str) or mime not in EXTENSIONS:
                raise ValueError(f"처리하지 않은 이미지 MIME: {mime}")
            if not isinstance(data, str) or not data:
                raise ValueError("이미지의 raw base64 데이터가 없습니다.")
            try:
                raw = base64.b64decode(data, validate=True)
            except (binascii.Error, ValueError) as exc:
                raise ValueError("유효하지 않은 base64입니다.") from exc
            if not raw:
                raise ValueError("빈 이미지 데이터입니다.")
            images.append((mime, raw))

    if not images:
        raise ValueError("최종 이미지가 없습니다. 응답과 차단 사유를 확인하세요.")
    target = Path(destination)
    target.mkdir(parents=True, exist_ok=False)
    paths = []
    for index, (mime, raw) in enumerate(images, start=1):
        path = target / f"image-{index:03d}{EXTENSIONS[mime]}"
        path.write_bytes(raw)
        paths.append(str(path))
    return paths


if __name__ == "__main__":
    if len(sys.argv) != 3:
        raise SystemExit("사용법: python save_images.py 응답.json 새출력폴더")
    response = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
    print(json.dumps(save_images(response, sys.argv[2]), ensure_ascii=False))
bash
python save_images.py interaction-response.json output-coffee-001

예를 들어 PNG와 JPEG가 하나씩 들어 있으면 image-001.png, image-002.jpg로 저장합니다. 이 검사는 MIME과 base64의 형식 및 파일 저장을 확인합니다. 실제 이미지 바이트가 열리는지, 필요한 글자가 맞는지, 결과물을 납품할 수 있는지는 저장 후 별도로 확인합니다. 알 수 없는 MIME이나 잘못된 base64가 있으면 파일을 쓰기 전에 멈추므로, 확장자를 무조건 .png로 바꾸며 오류를 숨기지 않습니다.

앱 JSON·YAML을 공식 요청으로 변환합니다

JSON에는 두 가지 역할이 있습니다. 하나는 HTTP 요청의 전송 형식이고, 다른 하나는 앱이 이미지 작업을 관리하는 데이터 형식입니다. 후자의 필드를 공식 요청에 그대로 넣을 수는 없습니다. 또한 Pro 모델 카드에는 Structured Output이 지원되지 않는 기능으로 표시되어 있습니다. 요청이 JSON이라는 사실이나 아래와 같은 앱 객체를 쓴다는 사실은 모델이 엄격한 JSON 스키마로 답한다는 의미가 아닙니다. Pro 모델 카드

먼저 아래 데이터를 spec.json으로 저장합니다. references는 로컬 참조 이미지 목록이며, 빈 배열이면 텍스트만으로 생성합니다. 모든 필드는 이 예시 앱이 정한 항목입니다.

json
{
  "provider": "google",
  "api": "interactions",
  "model": "gemini-3-pro-image",
  "brief": "독립 커피 브랜드의 웹사이트 대표 이미지",
  "must_include": ["무광 검정 커피백 한 개", "좌우 여백", "따뜻한 창가광"],
  "avoid": ["가격", "새로운 로고"],
  "references": [],
  "output": {
    "aspect_ratio": "16:9",
    "image_size": "2K",
    "mime_type": "image/png"
  },
  "store": false
}

같은 앱 데이터를 YAML로 보관하려면 다음처럼 표현합니다. "16:9", "2K"는 문자열이고 false는 불리언입니다. 파서가 "false" 문자열을 반환하게 만들면 아래 검사를 통과하지 못합니다. YAML은 서버에 보내는 형식이 아니라 JSON 요청을 만들기 전의 설정 파일입니다.

yaml
provider: google
api: interactions
model: gemini-3-pro-image
brief: 독립 커피 브랜드의 웹사이트 대표 이미지
must_include:
  - 무광 검정 커피백 한 개
  - 좌우 여백
  - 따뜻한 창가광
avoid:
  - 가격
  - 새로운 로고
references: []
output:
  aspect_ratio: "16:9"
  image_size: "2K"
  mime_type: image/png
store: false

아래 build_request.py는 JSON과 YAML에서 같은 객체를 읽어 동일한 요청을 만듭니다. JSON은 표준 라이브러리만 사용합니다. YAML을 선택하면 실행 환경에 PyYAML이 필요하며 safe_load로 읽습니다. 앱 검사는 허용되지 않은 필드와 잘못된 자료형을 거부하지만, 공급자 서버의 실제 요청 수락을 보장하지는 않습니다.

python
import base64
import json
import sys
from pathlib import Path

RATIOS = {
    "1:1", "2:3", "3:2", "3:4", "4:3",
    "4:5", "5:4", "9:16", "16:9", "21:9",
}
SIZES = {"1K", "2K", "4K"}
MIMES = {"image/png", "image/jpeg", "image/webp"}
FIELDS = {
    "provider", "api", "model", "brief", "must_include",
    "avoid", "references", "output", "store",
}


def text(value, name):
    if not isinstance(value, str) or not value.strip():
        raise ValueError(f"{name}: 비어 있지 않은 문자열이 필요합니다.")
    return value.strip()


def strings(value, name):
    if not isinstance(value, list):
        raise ValueError(f"{name}: 문자열 배열이 필요합니다.")
    return [text(item, name) for item in value]


def build_request(spec, base_dir):
    if not isinstance(spec, dict) or set(spec) != FIELDS:
        raise ValueError("앱 설정의 필드가 예시 스키마와 다릅니다.")
    if (spec["provider"], spec["api"], spec["model"]) != (
        "google", "interactions", "gemini-3-pro-image"
    ):
        raise ValueError("이 변환기는 Google Interactions Pro 전용입니다.")
    if type(spec["store"]) is not bool:
        raise ValueError("store는 true 또는 false 불리언이어야 합니다.")
    output = spec["output"]
    if not isinstance(output, dict) or set(output) != {
        "aspect_ratio", "image_size", "mime_type"
    }:
        raise ValueError("output 필드가 올바르지 않습니다.")
    ratio = text(output["aspect_ratio"], "aspect_ratio")
    size = text(output["image_size"], "image_size")
    mime = text(output["mime_type"], "mime_type")
    if ratio not in RATIOS or size not in SIZES or mime not in MIMES:
        raise ValueError("지원 목록 밖의 비율·해상도·MIME입니다.")

    prompt = " ".join([
        text(spec["brief"], "brief") + ".",
        "포함할 요소: " + ", ".join(strings(spec["must_include"], "must_include")) + ".",
        "넣지 않을 요소: " + ", ".join(strings(spec["avoid"], "avoid")) + ".",
    ])
    references = spec["references"]
    if not isinstance(references, list) or len(references) > 14:
        raise ValueError("references는 최대 14개인 배열이어야 합니다.")
    parts = [{"type": "text", "text": prompt}]
    for reference in references:
        if not isinstance(reference, dict) or set(reference) != {"path", "mime_type"}:
            raise ValueError("참조 이미지에는 path와 mime_type이 필요합니다.")
        image_mime = text(reference["mime_type"], "참조 MIME")
        if image_mime not in MIMES:
            raise ValueError("참조 이미지 MIME을 확인하세요.")
        path = Path(text(reference["path"], "참조 파일"))
        if not path.is_absolute():
            path = Path(base_dir) / path
        raw = path.read_bytes()
        if not raw:
            raise ValueError("참조 이미지가 비어 있습니다.")
        parts.append({
            "type": "image",
            "mime_type": image_mime,
            "data": base64.b64encode(raw).decode("ascii"),
        })
    return {
        "model": spec["model"],
        "input": parts,
        "response_format": {
            "type": "image", "mime_type": mime,
            "aspect_ratio": ratio, "image_size": size,
        },
        "store": spec["store"],
    }


def load_spec(path):
    source = path.read_text(encoding="utf-8")
    if path.suffix.lower() == ".json":
        return json.loads(source)
    if path.suffix.lower() in {".yaml", ".yml"}:
        try:
            import yaml
        except ImportError as exc:
            raise RuntimeError("YAML 읽기에는 PyYAML이 필요합니다.") from exc
        return yaml.safe_load(source)
    raise ValueError("설정 파일은 JSON 또는 YAML이어야 합니다.")


if __name__ == "__main__":
    if len(sys.argv) != 3:
        raise SystemExit("사용법: python build_request.py 설정파일 요청.json")
    source_path = Path(sys.argv[1])
    request = build_request(load_spec(source_path), source_path.parent)
    Path(sys.argv[2]).write_text(
        json.dumps(request, ensure_ascii=False, indent=2), encoding="utf-8"
    )
bash
python build_request.py spec.json request.json
# 같은 설정을 spec.yaml로 저장하고 PyYAML을 준비한 환경이라면:
python build_request.py spec.yaml request-from-yaml.json

참조 이미지를 넣으려면 설정 파일 기준 상대 경로와 실제 파일 MIME을 지정합니다. 예를 들어 references 값을 [{"path": "assets/coffee.png", "mime_type": "image/png"}]로 바꾸면 원본 바이트가 input의 이미지 블록으로 변환됩니다. 파일 이름만 바꾼 PDF나 JPEG를 PNG라고 선언하지 마세요. 앱 기획값은 텍스트로, 출력 설정은 response_format으로, 참조 이미지는 type: image로 각각 연결됩니다.

PDF는 문서 분석 후 필요한 정보만 Pro에 넘깁니다

Pro 모델 카드에 선언된 입력은 이미지와 텍스트입니다. 일반 Gemini 문서 처리 가이드의 PDF 지원을 그대로 Pro에 적용해서 type: document를 보내는 흐름은 사용하지 않습니다. 문서 이해와 이미지 생성을 다음 두 단계로 나누면 필요한 출처를 보존하면서 요청을 만들 수 있습니다. Pro 입력 지원 범위

1단계: 문서 모델에서 사실과 페이지 번호를 추출합니다

공식 PDF 처리 가이드는 문서 지원 모델로 gemini-3.8-flash를 예시로 사용합니다. 다음 prepare_pdf.py는 로컬 PDF를 읽어 그 경로의 요청 파일만 만듭니다. 실제 호출과 파일 전송은 위 공식 호출 절차에서 별도의 문서 요청으로 실행해야 합니다.

python
import base64
import json
import sys
from pathlib import Path

if len(sys.argv) != 3:
    raise SystemExit("사용법: python prepare_pdf.py 문서.pdf pdf-request.json")
source = Path(sys.argv[1])
raw = source.read_bytes()
if not raw.startswith(b"%PDF-"):
    raise ValueError("PDF 파일을 준비하세요.")
request = {
    "model": "gemini-3.8-flash",
    "input": [
        {"type": "document", "mime_type": "application/pdf",
         "data": base64.b64encode(raw).decode("ascii")},
        {"type": "text", "text": (
            "제품 소개 이미지에 필요한 사실만 추출하세요. "
            "각 사실의 원문과 PDF 페이지 번호를 함께 적고, "
            "명시되지 않은 내용은 추측하지 마세요. "
            "브랜드명, 제품명, 색상 규칙, 금지 표현을 구분하세요."
        )},
    ],
    "store": False,
}
Path(sys.argv[2]).write_text(
    json.dumps(request, ensure_ascii=False, indent=2), encoding="utf-8"
)
bash
python prepare_pdf.py catalog.pdf pdf-request.json

실제 문서 요청은 다음처럼 별도 응답 파일로 받습니다. 이 전송은 PDF 내용을 외부 서비스에 보내므로 승인된 자료와 처리 경로를 사용합니다.

bash
curl --silent --show-error --fail-with-body \
  "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: YOUR_GOOGLE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @pdf-request.json \
  --output pdf-response.json

pdf-response.json의 모델 출력 텍스트에서 원문·페이지 번호를 읽고 PDF와 대조합니다. 이 코드는 응답이 엄격한 JSON이 되도록 보장하지 않습니다. 검토가 끝난 정보는 아래와 같은 앱의 인계 파일 verified-facts.json에 저장합니다. 다음 값은 구성 설명용 가상 예시이며 실제 카탈로그 추출 결과가 아닙니다.

json
{
  "source_file": "catalog.pdf",
  "verified": true,
  "facts": [
    {"page": 1, "text": "제품명: 새벽 블렌드"},
    {"page": 12, "text": "포장색: 무광 검정"}
  ],
  "reference_images": []
}

일반 PDF 경로의 한도는 50MB 또는 1,000페이지이며, 여러 PDF와 텍스트를 함께 넣으면 전체 문맥 한도도 적용됩니다. 이 숫자는 Pro에 PDF를 직접 넣을 수 있다는 한도가 아닙니다. 필요 없는 페이지를 제외하고, 개인정보나 전송 금지 자료가 있다면 승인된 문서 처리 경로가 준비될 때까지 전송하지 않습니다. 문서 입력 조건

2단계: 검토된 사실과 필요한 페이지 이미지를 넣습니다

페이지의 배치나 제품 사진이 필요하면 필요한 페이지만 실제 PNG·JPEG로 렌더링합니다. 사용한 페이지, 해상도와 자르기 범위를 기록하고, reference_images에 {"path": "pages/page-12.png", "mime_type": "image/png"}처럼 넣습니다. 텍스트 정보만 필요하면 이미지 목록을 비워 둡니다.

다음 handoff_to_spec.py는 위에서 제공한 build_request.py와 같은 폴더에 저장합니다. 검토 완료 상태와 페이지 번호가 없는 정보는 거부하고, 공식 Pro 요청을 직접 만듭니다. verified: true는 검토자가 기록한 상태이지 모델이 사실의 정확성을 보증한 값이 아닙니다.

python
import json
import sys
from pathlib import Path
from build_request import build_request, strings, text

if len(sys.argv) != 3:
    raise SystemExit("사용법: python handoff_to_spec.py 인계.json 요청.json")
source = Path(sys.argv[1])
handoff = json.loads(source.read_text(encoding="utf-8"))
if not isinstance(handoff, dict) or set(handoff) != {
    "source_file", "verified", "facts", "reference_images"
}:
    raise ValueError("인계 파일의 필드를 확인하세요.")
text(handoff["source_file"], "PDF 출처")
if handoff["verified"] is not True:
    raise ValueError("원문 검토를 먼저 완료하세요.")
if not isinstance(handoff["facts"], list) or not handoff["facts"]:
    raise ValueError("검토된 사실 목록이 필요합니다.")
facts = []
for item in handoff["facts"]:
    if not isinstance(item, dict) or set(item) != {"page", "text"}:
        raise ValueError("각 사실에는 page와 text가 필요합니다.")
    if type(item["page"]) is not int or item["page"] < 1:
        raise ValueError("페이지 번호는 1 이상의 정수여야 합니다.")
    facts.append(text(item["text"], "검토된 사실"))
spec = {
    "provider": "google", "api": "interactions",
    "model": "gemini-3-pro-image",
    "brief": "검토된 제품 정보로 웹사이트 대표 이미지를 만들어 주세요",
    "must_include": strings(facts, "사실 목록"),
    "avoid": ["자료에 없는 효능", "새로운 가격", "추가 로고"],
    "references": handoff["reference_images"],
    "output": {"aspect_ratio": "16:9", "image_size": "2K", "mime_type": "image/png"},
    "store": False,
}
request = build_request(spec, source.parent)
Path(sys.argv[2]).write_text(
    json.dumps(request, ensure_ascii=False, indent=2), encoding="utf-8"
)
bash
python handoff_to_spec.py verified-facts.json request.json

이제 request.json은 PDF가 들어 있지 않은 Pro의 텍스트·이미지 요청입니다. 첫 절의 공식 Pro 호출과 저장기로 이어집니다. 80페이지를 모두 참조 이미지로 보내기보다 검토된 사실과 필요한 몇 페이지만 골라 쓰면, 어떤 정보가 생성에 사용됐는지 추적하기도 쉽습니다.

Google·generateContent·공급자의 요청을 구분합니다

새 공식 연동에는 Interactions를 쓰되 기존 generateContent 연동도 계속 지원됩니다. 요청 필드와 응답 구조가 다르므로 주소만 바꿔서 이전 파서를 재사용하지 않습니다. Interactions 공식 개요, generateContent 이미지 가이드

경로주소와 인증요청·응답의 핵심 필드
Google Interactionsgenerativelanguage.googleapis.com/v1beta/interactions, Google 키의 x-goog-api-keymodel, input, response_format → steps[].content[]
Google generateContentgenerativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image:generateContent, Google 키contents[].parts[], generationConfig → candidates[].content.parts[]
LaoZhang generateContent 호환api.laozhang.ai/v1beta/models/gemini-3-pro-image:generateContent, 공급자 키의 Bearer 인증공급자 문서의 contents, generationConfig.imageConfig → inlineData
LaoZhang OpenAI 호환 채팅api.laozhang.ai/v1/chat/completions, 공급자 키의 Bearer 인증model, messages, stream: false; 문서상 텍스트 생성은 1:1·1K

안내: laozhang.ai는 이 블로그 운영팀의 자사 서비스입니다. 그 가격은 독립적인 비교가 아니라 자사 제시 가격입니다.

앱 변환기의 provider와 api 검사는 이 경로를 섞지 않기 위한 것입니다. generationConfig.imageConfig.imageSize와 response_format.image_size는 이름만 다른 같은 입력 필드로 취급해 한 요청에 넣을 수 없습니다. 이전 코드에서 참조 이미지의 URI 오류가 나면 실제 이미지 값과 native 파일 전송 형식 확인으로 이어서 점검합니다. generateContent의 HTTPS 파일 입력 조건을 Interactions의 모든 URI 입력이나 Pro의 URL Context 도구 지원으로 확대하지 않습니다.

공급자별 인증·요청·응답 저장과 과금 조건 확인

여러 모델을 한 공급자 경로로 연동해야 한다면 LaoZhang Pro 이미지 문서를 비교 대상으로 사용할 수 있습니다. 이 문서에는 Pro가 호출당 0.09달러로 표시되어 있고, HTTP 200이면 이미지가 없어도 한 번 과금한다고 설명합니다. 2026년 10월 7일 읽은 공개 문서의 조건이며, 현재 계정의 실제 단가나 청구액을 확인한 값은 아닙니다. 커스텀 비율과 2K·4K가 필요하면 공급자의 generateContent 호환 경로를 확인하며, OpenAI 호환 채팅에 Interactions 설정을 넣어 같은 기능을 기대하지 않습니다.

Google 기능·프로젝트 할당량·보존 조건이 그대로 필요한 경우에는 Google 직접 연결을 사용합니다. 공급자 경로를 선택할 때는 별도 키, 실제 지원 기능, 응답 저장 방식, 이미지 없는 성공 응답의 과금과 데이터 보존을 요구사항에 맞춰 확인합니다. 문서의 가격 차이만으로 결과 품질이나 안정성이 같다고 판단할 수는 없습니다.

비율·4K 크기·비용·할당량을 함께 확인합니다

Pro에서 문서화된 비율은 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9이고, 해상도는 대문자 K를 쓰는 1K, 2K, 4K입니다. 4K가 항상 4096×4096은 아닙니다. 공식 16:9 표에서는 1K가 1376×768, 2K가 2752×1536, 4K가 5504×3072로 표시됩니다. 다른 이미지 모델 전용 초광각 비율이나 512px 옵션을 Pro에 그대로 옮기지 않습니다. Pro 이미지 설정과 크기표

참조 이미지 최대 14개는 모든 사진을 동일하게 보존한다는 보장이 아닙니다. 공식 가이드는 물체 6개·인물 5개·스타일 3개와 같은 안내를 주면서, 별도 제한 설명에서는 고충실도 이미지 5개도 언급합니다. 코드의 14개 검사는 요청 구성의 상한 검사일 뿐입니다. 중요한 제품·인물·글자는 반환 결과에서 확인해야 합니다. Pro의 Thinking은 기본 활성화되어 끌 수 없으며, 일반 문제 해결 가이드의 비활성화 조언을 그대로 적용하지 않습니다. 공식 Pro 제한 설명

2026년 10월 7일 Google 가격표의 Standard 기준은 다음과 같습니다. 통화는 미국 달러이며 이미지 출력 외의 항목도 총비용에 들어갑니다.

항목Standard 요금읽는 방법
텍스트·이미지 입력100만 토큰당 2달러이미지 입력 560토큰은 약 0.0011달러
텍스트·Thinking 출력100만 토큰당 12달러생성 이미지 외에 추가되는 출력 비용
이미지 출력100만 토큰당 120달러1K·2K는 1,120토큰으로 0.1344달러, 표의 반올림값은 0.134달러
4K 이미지 출력2,000토큰이미지 출력분만 0.24달러

따라서 2K 이미지 100장의 출력분만 계산하면 100 × 1,120 × 120 / 1,000,000 = 13.44달러입니다. 입력·Thinking·검색·재시도·세금과 사용할 수 없는 결과물은 이 계산에 포함되지 않습니다. Batch는 별도 처리 경로의 요금이며 /interactions/batch라는 주소를 임의로 만들지 않습니다. Flex·Priority는 가격표 행과 모델 카드의 지원 표시가 일치하지 않으므로, 가격만 보고 현재 계정에서 사용할 수 있다고 가정하지 않습니다.

공식 Pro API 가격표에는 무료 티어가 없습니다. API 키를 발급받는 것, AI Studio에서 시험하는 것, 소비자 Gemini 이용 한도는 유료 Pro API 호출 비용과 다른 항목입니다. Google Search grounding은 Gemini 3.x에서 공유하는 월 5,000회 이후 실제 검색 질의 1,000회당 14달러로 표시되며, API 요청 한 번이 검색 질의 한 번이라는 의미는 아닙니다. 검색을 추가할 때도 같은 공식 가격표를 기준으로 계산합니다.

API 키 인증과 프로젝트 결제·할당량의 역할 구분

키를 더 만들어도 같은 프로젝트의 할당량은 늘어나지 않습니다. RPM·입력 TPM·RPD·이미지 IPM과 지출 제한을 프로젝트 기준으로 확인하고, RPD는 태평양 시간 자정에 재설정된다는 점을 고려합니다. 실제 허용량은 프로젝트의 현재 상태를 확인해야 하며 문서의 예시 등급을 내 키의 실시간 한도로 쓰지 않습니다. 공식 속도 제한

키 정책도 구분합니다. 2026년 5월 28일부터 새 AI Studio 키는 기본적으로 서비스 계정에 연결되는 auth key입니다. 제한 없는 standard key 요청은 거부되지만, 제한 설정이 적용된 standard key는 계속 동작한다고 안내되어 있습니다. “9월 이후 모든 standard key가 거부된다”는 설명으로 기존 키를 판단하면 안 됩니다. 공식 API 키 정책

오류는 상태 코드와 응답 본문을 함께 읽습니다

아래 코드 이름은 Google Interactions 오류 기준입니다. 공급자의 오류나 generateContent의 다른 형식과 일대일로 대응한다고 가정하지 않습니다. Interactions 오류 목록

증상먼저 읽을 내용다음 행동
400 invalid_request·parameter_unknown잘못된 필드, 자료형, 비율·해상도주소에 맞는 요청으로 다시 만들고 앱 기획 필드를 제거합니다.
400 failed_precondition결제 등 충족되지 않은 조건메시지에 적힌 전제 조건부터 확인합니다.
401 authentication·403 permission_denied인증과 사용 권한의 차이대상 공급자의 키·헤더·프로젝트 제한을 각각 확인합니다.
402 payment_required지불 조건반복 재시도를 멈추고 결제 조건을 확인합니다.
404 model_not_found·not_found모델 ID와 호출 주소현재 Pro ID, API 버전, 공급자의 별칭을 구분합니다.
429rate_limit_exceeded·quota_exceeded·too_many_requests요청 속도, 할당량, 동시 요청 중 어떤 원인인지 나눠 대응합니다.
500·503·504api_error·service_unavailable·deadline_exceeded기존 작업·응답이 있는지 확인한 뒤 횟수를 제한해 재시도합니다.
이미지가 없음image_safety·image_prohibited_content·image_recitation·image_other·no_image반환된 사유를 확인하고 저장 실패와 생성 차단을 구분합니다.

일시 장애에는 대기 시간을 늘리고 무작위 지연을 더할 수 있지만, 이미지 생성의 타임아웃 뒤 재시도는 중복 작업과 비용을 만들 수 있습니다. “5xx는 모두 무료”라고 가정하거나 무한 반복하지 않습니다. 안전 관련 거절은 제한을 낮추는 방법으로 해결하지 않습니다. 로그에는 호출 주소·모델·요청 시각·상태·오류 코드·확인 가능한 작업 ID를 남기고, 키와 민감한 원문은 제외하세요. 공식 문제 해결

자주 묻는 질문

나노 바나나 프로 API 키를 만들면 무료로 생성할 수 있나요?

아닙니다. 공식 Pro API에는 무료 티어가 없고, 키 발급과 이미지 생성 비용은 별개입니다. Standard 1K·2K 이미지 출력분은 공식 표의 반올림 기준 0.134달러이며 입력과 다른 출력 비용이 추가될 수 있습니다. 공식 가격표

JSON 프롬프트를 쓰면 Pro가 정확한 JSON으로 답하나요?

그렇게 보장되지 않습니다. 앱의 JSON 기획 데이터는 요청을 만들기 위한 도구이고, Pro는 모델 카드에서 Structured Output을 지원하지 않는 것으로 표시되어 있습니다. 이미지 생성 요청을 JSON으로 전송하는 것과 응답 스키마 보장은 다른 기능입니다. Pro 모델 카드

YAML 파일을 API에 직접 보내도 되나요?

이 글의 공식 요청은 Content-Type: application/json으로 전송합니다. YAML은 safe_load로 앱 객체를 읽고, 자료형을 검사한 뒤 input과 response_format이 들어 있는 JSON으로 변환합니다. YAML에 API 키를 함께 저장하지 않습니다.

SDK의 output_image만 저장하면 충분한가요?

마지막 이미지 한 장만 필요한 경우에는 단축 속성이 편리하지만, 모든 이미지를 저장하려면 모델 출력 단계의 이미지 블록을 순회해야 합니다. 텍스트·추론 항목을 이미지로 저장하지 말고, 반환된 mime_type에 맞춰 확장자를 결정하세요. 공식 이미지 응답 처리

PDF를 Pro에 바로 넣어서 이미지로 바꿀 수 있나요?

현재 Pro 카드의 선언된 입력은 이미지와 텍스트입니다. 문서 지원 모델에서 필요한 내용을 추출하고 원문과 대조한 뒤, 검토한 사실과 필요한 페이지 이미지만 Pro 요청에 넣습니다. 일반 PDF 처리 가이드의 입력 지원을 Pro에 직접 적용하지 않습니다. Pro 모델 카드, PDF 처리 가이드

Google 키와 LaoZhang 키를 같은 코드에서 바꿔 쓰면 되나요?

키만 바꾸면 안 됩니다. 호출 주소와 인증, 요청 필드, 응답 파서, 과금 조건까지 해당 공급자의 문서에 맞춰 바꿔야 합니다. LaoZhang의 OpenAI 호환 채팅과 generateContent 호환 경로도 지원하는 이미지 설정이 다릅니다. 공급자 Pro 문서

참고 자료11

이 글이 링크한 외부 페이지를 본문에 나온 순서대로 정리했습니다. 마지막 업데이트: 2026년 10월 7일.

  1. 1.공식 이미지 생성 가이드ai.google.dev/gemini-api/docs/image-generation
  2. 2.Interactions 상태 관리ai.google.dev/gemini-api/docs/interactions-overview
  3. 3.지원 종료 및 전환 일정ai.google.dev/gemini-api/docs/deprecations
  4. 4.Pro 모델 카드ai.google.dev/gemini-api/docs/models/gemini-3-pro-image
  5. 5.공식 PDF 처리 가이드ai.google.dev/gemini-api/docs/document-processing
  6. 6.generateContent 이미지 가이드ai.google.dev/gemini-api/docs/generate-content/image-generation
  7. 7.Google 가격표ai.google.dev/gemini-api/docs/pricing
  8. 8.공식 속도 제한ai.google.dev/gemini-api/docs/rate-limits
  9. 9.공식 API 키 정책ai.google.dev/gemini-api/docs/api-key
  10. 10.Interactions 오류 목록ai.google.dev/gemini-api/docs/api-errors
  11. 11.공식 문제 해결ai.google.dev/gemini-api/docs/troubleshooting
Nano Banana Pro의 429 응답에서 한도 확인, 대기, 중단을 구분하고 이미지 결과를 보존하는 흐름
API 가이드

Nano Banana Pro RESOURCE_EXHAUSTED 해결: 429 재시도와 이미지 작업 복구

Nano Banana Pro에서 429가 발생하면 명시적 한도 0·일일 한도·결제 중단은 먼저 처리하고, 일시적 제한만 서버가 요구한 시간 이후 재시도합니다. Python과 Node.js 예제는 총 시도와 누적 시간을 제한하며 실제 이미지와 완료 기록을 저장합니다.

7 분