Gemini API로 구조화된 JSON 출력 마스터하기

발행: (2026년 5월 27일 AM 04:47 GMT+9)
5 분 소요
원문: Dev.to

출처: Dev.to

인터랙티브 스키마 샌드박스

전체 기사에는 실시간 인터랙티브 스키마 샌드박스가 포함되어 있어 3개의 실제 제약 스키마를 전환하면서 Gemini 추론 엔진이 실시간으로 제한된 토큰을 스트리밍하는 모습을 확인할 수 있습니다.
전체 인터랙티브 버전 읽기 →


구조화된 출력이 중요한 이유

언어 모델은 도움이 되는 커뮤니케이터가 되도록 최적화됩니다. 이는 인간에게 강력한 인터페이스가 되지만 소프트웨어 아키텍처에 대한 통합은 매우 취약합니다.

간단한 추출 요청

“다음 텍스트에서 제품 이름, 가격, 재고 여부를 추출하고 JSON 형태로 반환하세요.”

문제일반적인 모델 동작
대화형 패딩“요청하신 데이터는 다음과 같습니다: …”
키 이름 변동"product_name" vs. "product" vs. "name"
취약한 타입 지정숫자형 가격 279.99 가 원시 문자열 "$279.99" 로 변환됨

이러한 불일치는 다운스트림 TypeScript 클래스가 처리되지 않은 KeyError 예외를 발생시켜 실행이 중단됩니다.

고전적인 해결책 (그리고 한계)

"RETURN ONLY a raw JSON object. DO NOT wrap in markdown. NEVER write conversational text."

소량의 요청에서는 동작하지만, 지시문을 따르는 것은 확률적입니다.
예상치 못한 장문 컨텍스트가 들어오면 모델이 대화형 기본 모드로 다시 흐트러집니다.
하루 50 000건의 호출을 처리하는 시스템에서 1 % 실패율은 500건의 치명적인 오류와 같습니다.

맞춤형 정규식 파싱은 더욱 위험합니다—모델 업데이트가 정규식을 조용히 깨뜨려 프로덕션 데이터를 오염시킬 수 있습니다.

Gemini의 구조화된 출력 시스템

Gemini는 추론 단계 중 어휘 마스킹을 통해 제약을 강제하며, 사후 처리 방식이 아닙니다.

  1. 모델은 약 32 000개의 어휘 토큰 각각에 대해 확률을 예측합니다.
  2. JSON Schema를 제공하면 Gemini는 이를 상태 머신으로 컴파일합니다.
  3. 각 생성 단계에서 불법 토큰은 확률 0으로 마스킹됩니다.

예시: 필드가 숫자를 기대한다면, 모든 텍스트 토큰("twenty", "$", 알파벳 문자 등)은 수학적으로 배제됩니다.

표준 디코딩 vs. 제한 디코딩

표준 디코딩제한 디코딩 (Gemini)
$279.99 → 45 % 확률$279.99 → 0 % 확률
279.99 → 40 % 확률279.99 → 100 % 확률
in stock → 15 % 확률in stock → 0 % 확률

구조화된 실행 활성화

import { GoogleGenerativeAI, SchemaType } from "@google/generative-ai";

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);

const model = genAI.getGenerativeModel({
  model: "gemini-2.0-flash",
  generationConfig: {
    responseMimeType: "application/json",   // Pillar 1
    responseSchema: {                       // Pillar 2
      type: SchemaType.OBJECT,
      properties: {
        sentiment: {
          type: SchemaType.STRING,
          enum: [
            "VERY_POSITIVE",
            "POSITIVE",
            "NEUTRAL",
            "NEGATIVE",
            "VERY_NEGATIVE"
          ]
        },
        csat_risk_score: {
          type: SchemaType.NUMBER,
          description: "0=no risk, 10=certain churn"
        },
        requires_human: { type: SchemaType.BOOLEAN }
      },
      required: ["sentiment", "csat
0 조회
Back to Blog

관련 글

더 보기 »