같은 모델, 더 나은 결과: 소비자용 이미지 앱이 API 위에 더하는 것들 — 프롬프트 재작성 계층, 레퍼런스 앵커링, 비전 모델 선택이 포함된 병렬 샘플링, 단계별 리터칭입니다. 복사해 붙여넣을 수 있는 사실감 관련 어휘, 나란히 비교하는 테스트, 비용 계산도 포함합니다.
원하는 이미지를 얻는 방법은 “이 한 번의 시도는 실패했습니다. 어떻게 복구하나요”에 대한 답변입니다. 이 페이지는 다음 질문에 답합니다: 매번 시도가 성공하도록 하려면 어떻게 해야 하나요.늘 나오는 질문이 있습니다. freepik.com과 higgsfield.ai 같은 소비자용 이미지 제품은 여러분이 사용하는 것과 같은 기반 모델, 즉 같은 Nano Banana, GPT-이미지, FLUX 계열 위에서 동작합니다. 그런데도 출력은 더 완성도 있어 보입니다. 차이는 모델 가중치에 있지 않습니다. 그것은 모델을 감싸고 있는 레이어입니다. 그리고 그 레이어는 직접 구축할 수 있습니다. 이 페이지에서 그 방법을 보여드립니다.
APIYI에는 그런 엔드포인트가 없습니다. 대신 생성 시 고해상도 티어를 사용하십시오(아래 경계 참고)
네거티브 prompt와 안전 폴백
알려진 모델의 습관을 피하고, moderation이 거절할 요청을 걸러냄
고정된 네거티브 표현을 템플릿에 내장하고, moderation 실패 시 하위 대체 경로도 마련합니다
에셋 라이브러리와 재호스팅
사용자 이미지가 만료되거나 사라지지 않음
모든 결과를 즉시 자체 오브젝트 스토리지에 복사합니다
경쟁사 기능 목록을 그대로 복사하기 전에 정리해야 할 플랫폼 경계 두 가지:
APIYI에는 업스케일링, 배경 제거, 얼굴 복원 엔드포인트가 없습니다. 큰 이미지가 필요하다면, 나중에 키우는 계획보다는 생성 시점에 고해상도 티어를 선택하십시오(gpt-image-2는 4K, Nano Banana Pro는 4K). 투명 배경이 필요하다면, 오직 seedream-5-0와 seedream-5-0-pro만 알파 채널이 있는 PNG로 반환하도록 요청할 수 있습니다.
APIYI는 LoRA나 아이덴티티 학습을 제공하지 않습니다.Soul ID 뒤에 있는 “한 번 학습하면 얼굴을 영원히 고정” 기능은 참조 이미지로만 근사할 수 있습니다. 같은 캐릭터라도 장면과 조명 변화에 따라 여전히 흔들리며, 새 샷이 정면에 가까운 구도와 원래 조명에 가까울수록 가장 잘 유지됩니다. 엄격한 일관성이 필요한 상업용 캐릭터라면 사람 검수 단계를 예산에 반영하십시오.
브리프는 “커피용 이커머스 상품 사진”입니다. 왼쪽은 사용자가 실제로 입력한 내용이고, 오른쪽은 빠진 결정을 채워 넣은 같은 브리프입니다. 두 경우 모두 gemini-3-pro-image (Nano Banana Pro)에서 2K, 1:1에 한 번씩 실행되었습니다:
Casual prompt: 'Make me a coffee product shot, make it look nice, make it feel premium'
Structured prompt: subject, environment, light position, lens, grading, imperfections and composition all specified
왼쪽 이미지는 보기 흉하지는 않지만, 사용할 수는 없습니다. 모델은 아무도 승인하지 않은 결정을 잔뜩 내렸습니다. 그라인더와 삼베 자루를 추가하고, 향수 어린 따뜻한 그레이딩으로 정하고, 컵에는 만들어낸 브랜드명을 인쇄했습니다. 그런 자동 생성 텍스트는 상업적으로 그 프레임을 쓸모없게 만듭니다. 오른쪽 이미지는 바로 상품 페이지에 올릴 수 있습니다. 중립적인 배경, 말로 설명할 수 있는 조명 구성, 그리고 카피를 넣을 여유가 있기 때문입니다.“보기 좋다”와 “실제로 사용할 수 있다”는 서로 다른 목표입니다. 일반적인 prompt로는 첫 번째만 도달할 수 있습니다.
import osimport requestsBASE = "https://api.apiyi.com/v1"API_KEY = os.environ["APIYI_API_KEY"] # never hard-code the keyREWRITE_SYSTEM = """You are an image prompt engineer. Rewrite the user's casual briefinto one structured image prompt.Fill in all six elements. Supply whatever is missing; never ask the user:1 Subject: material, colour, count, state2 Environment: what the background is, what is sharp and what is blurred3 Light: direction, hardness, fill or no fill — there must be one identifiable key light4 Lens and angle: focal length, aperture, camera height, tilt5 Grading and medium: white balance bias, saturation, film or digital character6 Composition: where the subject sits in the frame, where the negative space isRules:- Output only the prompt body: no explanation, no bullet points, no heading- No brand names, logos, or legible text unless the user asked for them- Never use vague quality words such as 8K, ultra HD, masterpiece, perfect- Keep any element the user specified exactly as written"""def rewrite(user_prompt: str) -> str: r = requests.post( f"{BASE}/chat/completions", headers={"Authorization": f"Bearer {API_KEY}"}, json={ "model": "gemini-3.5-flash", "messages": [ {"role": "system", "content": REWRITE_SYSTEM}, {"role": "user", "content": user_prompt}, ], }, timeout=60, ) r.raise_for_status() return r.json()["choices"][0]["message"]["content"].strip()
“8K, ultra HD, masterpiece, perfect”를 금지하는 규칙에 유의하십시오 — 4절에서 그 이유를 설명합니다.
지켜야 할 두 가지 규칙이 있습니다: prompt의 “이미지 1 / 이미지 2”는 배열 순서에 엄격히 대응합니다. 따라서 어느 것이 어느 것인지 명시하십시오. 또한 Grok은 /v1/images/edits에서만 레퍼런스 이미지를 인정합니다 — 이를 /v1/images/generations에 넘기면 조용히 버려지지만 여전히 과금됩니다.
3
샘플: N개를 병렬로 생성하고 n에 의존하지 마십시오
소비자용 제품이 「첫 시도에 바로 맞췄다」는 느낌은 사실 제품이 대신 여러 장의 카드를 뽑아 보는 것과 같습니다.하지만 서버 측 n 매개변수는 대부분의 이미지 모델에 영향을 주지 않습니다(Seedream은 아예 무시합니다). 여러 후보를 얻으려면 클라이언트에서 여러 요청을 동시에 보내십시오 — 이 사이트의 스킬 페이지는 한 번에 5개로 제한합니다. 채널별로 동시 실행 수를 조정하십시오. 일부는 2개부터 429를 반환하기 시작하므로 지수 백오프를 추가하십시오.
4
선택: 비전 모델을 판정자로 사용하십시오
N개의 후보를 확보한 뒤에는 자동으로 선택해야 합니다. 그렇지 않으면 선택을 사용자에게 떠넘긴 것에 불과합니다.후보들을 표준 /v1/chat/completions 이미지 입력으로 비전 모델에 다시 보내 채점하십시오. 지원 가능한 모델은 비전 이해를 참조하십시오. 평가 기준은 다섯 가지 차원으로 고정하고 JSON 반환을 요구하십시오: 지시 준수, 구조와 해부학, 텍스트 정확성, 텍스처 사실성, 구도.
이 용도로는 /v1/rerank를 사용하지 마십시오. bge-reranker-v2-m3은 텍스트 전용 재정렬 모델이며 이미지를 받지 않습니다. 이미지 채점에는 비전 이해 모델이 필요합니다.
5
보정하고 마무리하십시오
구도가 확정된 뒤에는 로컬에서 조정하십시오 — 하나의 복합 지시문보다 성공률이 훨씬 높습니다:
import base64import jsonimport osfrom concurrent.futures import ThreadPoolExecutorimport requestsBASE = "https://api.apiyi.com"API_KEY = os.environ["APIYI_API_KEY"]HEAD = {"Authorization": f"Bearer {API_KEY}"}STYLE_CONST = "Cool neutral white balance, low saturation, clean frame with generous negative space."def draw(prompt: str, size: str = "2K", aspect: str = "1:1") -> bytes: """Generate one image (Nano Banana Pro, native Gemini endpoint).""" url = f"{BASE}/v1beta/models/gemini-3-pro-image:generateContent" body = { "contents": [{"parts": [{"text": prompt}]}], "generationConfig": { "responseModalities": ["IMAGE"], "imageConfig": {"aspectRatio": aspect, "imageSize": size}, }, } r = requests.post(url, headers=HEAD, json=body, timeout=600) # headroom for 4K r.raise_for_status() parts = r.json()["candidates"][0]["content"]["parts"] part = next((p for p in parts if p.get("inlineData")), None) if part is None: # HTTP 200 with no image usually means moderation raise RuntimeError("no image returned: " + json.dumps(parts)[:300]) return base64.b64decode(part["inlineData"]["data"])def score(image: bytes, prompt: str) -> dict: """Score a candidate with a vision model; returns per-dimension scores and one issue line.""" data_url = "data:image/png;base64," + base64.b64encode(image).decode() rubric = ( "Score this image and return strict JSON: " '{"instruction":0-10,"anatomy":0-10,"text":0-10,"texture":0-10,' '"composition":0-10,"total":0-50,"issue":"one sentence"}. ' "instruction = does it satisfy the brief below; anatomy = errors in hands, limbs, object structure; " "text = is any text in the image correct (score 10 if there is none); " "texture = does it read as a real photograph rather than a render; " "composition = is the framing usable. The brief:\n" + prompt ) r = requests.post( f"{BASE}/v1/chat/completions", headers=HEAD, json={ "model": "gemini-3.5-flash", "messages": [{"role": "user", "content": [ {"type": "text", "text": rubric}, {"type": "image_url", "image_url": {"url": data_url}}, ]}], "response_format": {"type": "json_object"}, }, timeout=120, ) r.raise_for_status() return json.loads(r.json()["choices"][0]["message"]["content"])def best_of(user_input: str, n: int = 4) -> bytes: prompt = rewrite(user_input) + "\n" + STYLE_CONST # steps 1 and 2 with ThreadPoolExecutor(max_workers=n) as pool: # step 3: client-side fan-out results = list(pool.map(lambda _: _safe(draw, prompt), range(n))) cands = [img for ok, img in results if ok] if not cands: raise RuntimeError("all candidates failed; check moderation or fall back to another model") with ThreadPoolExecutor(max_workers=len(cands)) as pool: # step 4: score in parallel scores = list(pool.map(lambda im: score(im, prompt), cands)) ranked = sorted(zip(cands, scores), key=lambda x: x[1]["total"], reverse=True) return ranked[0][0] # step 5 retouch/rehost hooks in heredef _safe(fn, *args): try: return True, fn(*args) except Exception as e: # one failure must not sink the batch return False, str(e)
동일한 모델(gemini-3-pro-image), 동일한 피사체, 두 가지 prompt 스타일, 각각 두 장의 이미지, 각 배치에서 첫 번째 이미지를 보여줍니다:
Bare prompt: 'A photorealistic half-body portrait of a young woman by a cafe window, smiling at the camera, 8K, ultra HD, ultra detailed, flawless skin, beautiful, perfect lighting, masterpiece'
The same subject after adding four blocks of control language: light position, lens, medium, imperfections
왼쪽 이미지는 나쁘지 않습니다 — 기본 모델이 충분히 강해서 아무 장식 없는 prompt만으로도 보기 좋은 이미지를 만들어냅니다. 하지만 그 안에는 특징 세트가 고스란히 들어 있습니다. 피사체가 정중앙에 고정되어 있고, 빛은 어디서 오는지 알 수 없을 정도로 고르며, 모든 요소가 무난합니다. 그리고 이것은 우연도 아닙니다. 그 배치의 두 이미지 모두 본질적으로 같은 구도와 조명 패턴을 공유했습니다.오른쪽 이미지는 접근 방식을 바꿨습니다. 빛에는 방향이 생겼고, 얼굴의 절반은 그림자에 잠기도록 두었으며, 피부에는 유분과 모공이 드러나고, 볼에는 점이 있으며, 삐져나온 머리카락은 빗질되지 않았고, 피사체는 중앙보다 오른쪽에 있습니다. 이것은 “카페에서 미소 짓는 여성의 스톡 이미지”가 아니라 특정한 순간에 촬영된 특정 인물로 읽힙니다.
파이프라인의 진짜 가치는 바로 여기서도 드러납니다. 그것은 못난 출력을 예쁜 출력으로 바꾸는 것이 아니라, “운 좋게 잘 나온 것”을 “여러분이 지정했고, 설명할 수 있고, 재현할 수 있는 좋은 결과”로 바꿉니다. 이해관계자는 오른쪽 이미지를 더 선호하지 않을 수도 있지만, 왼쪽 이미지로는 왜 그런 모습인지 설명할 수 없고, 다음 이미지에 그것을 맞추라고 요청할 수도 없습니다.
배치를 구체적으로 지정하십시오: “피사체를 중앙의 오른쪽에 배치하고 왼쪽에 네거티브 스페이스를 두기"
"완벽한 구도”, “황금비”
모공이 없는 플라스틱 같은 피부
”자연스러운 피부 질감, 보이는 모공과 잔털, 코에 약간의 광택, 보정 없음"
"흠잡을 데 없는 피부”, “정교한”, “아름다운”
식별 가능한 광원이 없는 균일한 조명
키 라이트 하나와 그 강도를 지정하십시오: “왼쪽 창광만이 유일한 광원이며 얼굴 오른쪽 절반은 그림자에 있게 하기"
"완벽한 조명”, “부드러운 조명”
가짜 심도, 배경이 붙여넣은 듯 보임
초점거리와 조리개를 제시하십시오: “85mm, f/2.8, 가까운 눈에 초점"
"흐릿한 배경”, “시네마틱”
과채도에 빛나는 색감
매체와 화이트 밸런스를 제시하십시오: “Kodak Portra 400 특성, 따뜻한 하이라이트와 차가운 그림자, 낮은 채도"
"선명한 색감”, “HDR”
모든 것이 새것처럼 보이고 닳지 않음
일부러 사용감을 추가하십시오: “보풀이 생긴 스웨터, 테이블 위의 물자국과 빵 부스러기"
"깨끗하고 정돈된”, “프리미엄 질감”
포스터나 렌더처럼 읽힘
촬영 상황을 구체적으로 지정하십시오: “자연스러운 순간”, “옆 테이블에서 눈높이로"
"8K”, “울트라 HD”, “걸작”
8K, ultra HD, ultra detailed, masterpiece 및 perfect와 같은 모호한 품질 표현은 순효과가 마이너스입니다. 이것들은 아무 해상도도 더하지 못하며(해상도를 더하는 것은 오직 파라미터뿐입니다), 모델을 과도하게 선명하고 과채도인 렌더 쪽으로 밀어붙입니다. 바로 이것이 AI스러운 모습의 핵심입니다. 위의 왼쪽 prompt는 그런 표현들로 가득 차 있었고, 그 결과가 그것을 보여줍니다. 품질을 원하시면, 대신 구체적인 조명, 렌즈, 매체를 작성하십시오.
자연스러운 반신 인물 사진: 카페 창가에 선 20대 중반의 여성이 옆으로 몸을 돌린 채 바깥을 바라보고 있으며, 입가의 미소를 간신히 참는 듯합니다. 왼쪽에서 들어오는 창문빛만이 프레임의 유일한 광원이며, 얼굴 오른쪽 절반은 그림자에 잠기고 코 다리 아래에는 작고 선명한 그림자가 있습니다. 85mm 렌즈, f/2.8, 눈높이, 가까운 쪽 눈에 초점. Kodak Portra 400의 특성과 같은 미세하고 눈에 보이는 그레인, 따뜻한 하이라이트와 차가운 그림자, 전반적으로 낮은 채도. 자연스러운 피부: 보이는 모공과 솜털, 코 옆면의 약간의 윤기, 왼쪽 볼의 작은 점, 몇 가닥 삐져나온 눈썹 털, 이마에 정리되지 않은 느슨한 머리카락. 피부 보정 없음, 미용 리터칭 없음, 샤프닝 없음. 피사체는 중앙 오른쪽에 배치하고, 왼쪽에는 여백을 둡니다.
제품 사진: 제품 페이지에 바로 사용할 수 있음
이커머스 히어로 샷: 매트한 검은색 세라믹 푸어오버 컵에 블랙 커피가 80% 채워져 있고, 표면에는 얇은 크레마 고리가 떠 있습니다. 컵은 연한 회색 마이크로시멘트 표면 위에 놓여 있으며, 같은 톤의 벽이 뒤에서 흐릿하게 보입니다. 왼쪽 위 45도 방향의 소프트박스에서 들어오는 키라이트, 오른쪽의 흰색 바운스 카드가 컵 오른쪽 가장자리를 따라 좁은 하이라이트를 남기고, 부드러운 캐스트 섀도우가 뒤쪽 오른편으로 떨어집니다. 85mm 매크로 렌즈, f/5.6, 앞면을 15도 아래로 기울인 시점, 컵 전체가 선명합니다. 차갑고 중립적인 화이트 밸런스, 전반적으로 낮은 채도. 유약에는 약간의 수공예적 불균일함과 아주 작은 가마 자국이 있으며, 가장자리에는 매우 희미한 사용 흔적이 보입니다. 넉넉한 여백, 컵은 프레임의 왼쪽 1/3에 배치합니다. 이미지 어디에도 브랜드명이나 텍스트는 없습니다.
환경: 특정 시간과 날씨를 부여합니다
비가 막 그친 오후 6시의 좁은 구시가지 거리로, 양쪽 가게의 라이트박스가 물웅덩이에 비치고 있습니다. 유일한 키라이트는 거리 끝의 따뜻한 가로등이며, 가게 창문빛이 필라이트 역할을 하고, 하늘에는 아직 차가운 황혼의 기운이 남아 있어 따뜻함과 차가움의 대비를 만듭니다. 28mm 렌즈, f/4, 카메라는 눈높이, 약간 위로 기울임. 전반적으로 낮은 채도, 그림자에는 노이즈를 유지하고, 그림자 들어올리기는 하지 않습니다. 벽에는 물때 자국, 찢어진 낡은 포스터, 에어컨 실외기가 있고, 전선이 프레임 상단을 가로지릅니다. 아무도 카메라를 정면으로 바라보지 않으며, 지나가는 사람들은 뒤에서 보이고 약간 모션 블러가 있습니다.
파이프라인은 성공률을 위해 비용을 치르는 방식입니다. 비용은 이미지 생성 비용에서 출력이 대부분을 차지합니다(gpt-image-2는 출력에 토큰 100만 개당 $30를 청구합니다). 반면 재작성과 채점에 사용되는 텍스트 및 비전 모델 비용은 거의 무시해도 될 수준입니다. 따라서 비용은 본질적으로 “몇 개의 후보를 생성했는가”에 달려 있습니다.모든 항목에 하나의 설정을 쓰기보다, 세 가지 등급을 사용하세요.
등급
구성
상대 비용
용도
초안
Lite 모델에서 단일 샷
1×
내부 미리보기, 대량 플레이스홀더, 일반 사용자 실험
표준
재작성 + 후보 2개 + 점수 기반 선택
약 2×
소비자용 제품의 기본 경로
프리미엄
재작성 + 후보 4개 + 채점 + 로컬 보정 1회
약 5×
제품 대표 이미지, 광고 크리에이티브, 외부에 전달되는 모든 것
테스트는 간단합니다. 이 이미지를 팀 밖의 누군가가 보게 됩니까? 그렇다면 표준 이상은 충분히 값을 합니다. 내부 검토용이라면 초안이면 충분합니다. 그 사이에 게이트를 하나 더 넣을 수도 있습니다. 즉, 최고 점수가 임계값 아래로 떨어질 때만 더 많은 후보를 생성하면 대부분의 요청이 2개에서 수렴하게 만들 수 있습니다.