바이브코딩 2026.05.19

Gemini API 필수 업데이트: outputs 배열 사라진다: steps 마이그레이션 실전 코드 가이드

Gemini API 필수 업데이트: outputs 배열 사라진다: steps 마이그레이션 실전 코드 가이드

타임라인부터 확인하세요 — 이미 시작됐습니다

Google이 Gemini Interactions API의 핵심 구조를 바꿉니다. outputs 배열이 사라지고 steps 배열로 전면 교체됩니다. 이미 일정이 확정됐고, 일부는 진행 중입니다.

날짜 내용
2026-05-07 새 SDK 출시 (Python ≥2.0.0, JS ≥2.0.0). REST는 헤더로 선택적 적용 가능
2026-05-26 새 스키마(steps)가 REST API의 기본값으로 전환
2026-06-08 레거시 스키마(outputs) 완전 삭제

지금 당장 마이그레이션을 시작하지 않으면 6월 8일 이후 서비스가 예고 없이 실패합니다. 특히 REST API를 직접 호출하는 서버 사이드 코드, 또는 Python 1.x / JS 1.x SDK를 쓰는 프로젝트가 위험합니다.

Gemini API outputs→steps 마이그레이션 타임라인


왜 Google은 outputs를 없애는가?

기존 outputs 배열은 "모델이 생성한 결과물"만 담았습니다. 하지만 실제 AI 실행 흐름은 그것보다 훨씬 복잡합니다. 구글 검색 호출, 코드 실행, 함수 호출, 사용자 입력 등 여러 단계(step)가 뒤섞이는데, outputs로는 이 흐름을 표현할 방법이 없었습니다.

steps 배열은 이 문제를 해결합니다. 실행의 전체 타임라인을 순서대로 담을 수 있고, 각 step에 타입 식별자(type)가 붙어 어떤 작업이었는지 명확히 알 수 있습니다. GET 요청 시엔 사용자 입력(user_input)부터 모델 응답(model_output)까지 전체 히스토리가 담기고, POST 응답엔 출력 step들만 반환됩니다.

새 기능(예: 실행 중 개입, 새 서버 사이드 도구)은 steps 스키마에서만 제공됩니다. 레거시 outputs로는 새 기능을 받을 수 없습니다.


Before/After 실전 코드 비교

Python — 기본 응답 읽기

# ❌ Before (레거시 — 6월 8일 이후 동작 안 함)
response = client.interactions.create(...)
print(response.outputs[-1].text)

# ✅ After (새 스키마)
response = client.interactions.create(...)
print(response.steps[-1].content[0].text)

Python — 함수 호출(Function Calling) 처리

# ❌ Before
for output in response.outputs:
    if output.role == "tool_use":
        print(f"도구 호출: {output.name}")

# ✅ After
for step in response.steps:
    if step.type == "function_call":
        print(f"도구 호출: {step.name}")
        print(f"인수: {step.arguments}")

Python — Google 검색 같은 서버사이드 도구

# ✅ After — 서버사이드 도구 결과 파싱
for step in response.steps:
    if step.type == "google_search_call":
        print(f"검색어: {step.arguments.queries}")
    elif step.type == "model_output":
        print(step.content[0].text)

JavaScript — 기본 응답 읽기

// ❌ Before
const response = await client.interactions.create({...});
console.log(response.outputs[response.outputs.length - 1].text);

// ✅ After
const response = await client.interactions.create({...});
const lastStep = response.steps[response.steps.length - 1];
console.log(lastStep.content[0].text);

JavaScript — Step 타입 분기 처리

// ✅ After
for (const step of response.steps) {
    switch (step.type) {
        case 'model_output':
            console.log('모델 응답:', step.content[0].text);
            break;
        case 'function_call':
            console.log(`함수 호출: ${step.name}`);
            // 함수 실행 후 결과 제출
            break;
        case 'google_search_call':
            console.log('검색 실행:', step.arguments.queries);
            break;
    }
}

response_format 통합 — response_mime_type은 삭제됩니다

출력 형식 설정 방식도 바뀝니다. 기존에 따로 존재하던 response_mime_type이 사라지고, 모든 설정이 response_format 하나로 통합됩니다.

JSON 출력 설정

# ❌ Before
response = client.interactions.create(
    model="gemini-2.5-pro",
    response_mime_type="application/json",
    response_format={"type": "object", "properties": {...}}
)

# ✅ After
response = client.interactions.create(
    model="gemini-2.5-pro",
    response_format={
        "type": "text",
        "mime_type": "application/json",
        "schema": {"type": "object", "properties": {...}}
    }
)

이미지 출력 설정

# ❌ Before
config = GenerationConfig(
    image_config=ImageConfig(image_size="1024x1024")
)

# ✅ After
response_format = {
    "type": "image",
    "image_size": "1024x1024"
}

핵심은 type 필드가 텍스트/이미지/기타를 명시적으로 구분한다는 점입니다. 기존의 암묵적 mime_type 방식보다 코드 가독성과 유지보수성이 올라갑니다.


Streaming 이벤트 타입 변경

SSE(Server-Sent Events) 기반 스트리밍을 사용 중이라면 이벤트 이름도 업데이트해야 합니다.

레거시 이벤트 새 이벤트
content.start step.start
content.delta step.delta
content.stop step.stop
interaction.start interaction.created
interaction.complete interaction.completed
(없음) interaction.in_progress (신규)
(없음) interaction.requires_action (신규)

interaction.requires_action은 특히 중요합니다. 함수 호출 결과를 제출해야 하거나, 실행 중 개입이 필요한 시점에 발생하는 새 이벤트입니다. 기존 코드에 이 이벤트 핸들러가 없으면 에이전트 루프가 멈출 수 있습니다.

// ✅ 스트리밍 이벤트 처리 (새 스키마)
const stream = await client.interactions.stream({...});

for await (const event of stream) {
    if (event.type === 'step.delta') {
        process.stdout.write(event.delta.text ?? '');
    } else if (event.type === 'interaction.requires_action') {
        // 함수 호출 결과 제출 등 처리
        await handleRequiredAction(event);
    } else if (event.type === 'interaction.completed') {
        console.log('\n완료');
    }
}

레거시 유지 방법 (임시 opt-out)

5월 26일~6월 8일 사이에 작업이 필요하지만 당장 마이그레이션이 어렵다면, 임시로 레거시 스키마를 유지할 수 있습니다.

REST API (헤더 방식):

POST https://generativelanguage.googleapis.com/v1beta/...
Api-Revision: 2026-05-07
Authorization: Bearer {YOUR_API_KEY}

SDK 사용자: Python 1.x.x 또는 JS 1.x.x 버전을 유지하면 자동으로 레거시 응답을 받습니다. 단, 6월 8일 이후엔 이 방법도 동작하지 않습니다. 임시방편일 뿐, 반드시 마이그레이션을 완료해야 합니다.


마이그레이션 체크리스트

아래 항목을 순서대로 점검하세요.

  • SDK 버전 업그레이드 — Python google-genai>=2.0.0, JS @google/genai>=2.0.0
  • outputs 참조 전수 검색grep -r "\.outputs" ./src 로 모든 사용처 파악
  • response.outputs[n].textresponse.steps[n].content[0].text 로 교체
  • 함수 호출 분기문role == "tool_use" 등 레거시 조건 → step.type == "function_call" 로 교체
  • response_mime_type 제거response_format.mime_type 으로 이동
  • 스트리밍 이벤트 핸들러content.*step.*, interaction.completeinteraction.completed
  • interaction.requires_action 핸들러 추가 — 에이전트 루프에 신규 이벤트 처리 코드 추가
  • 테스트 환경에서 5월 26일 이전 검증Api-Revision: 2026-05-20 헤더로 새 스키마 미리 활성화하여 테스트
  • 레거시 opt-out 헤더 제거 — 검증 완료 후 Api-Revision: 2026-05-07 헤더 코드 삭제

개발자가 놓치기 쉬운 함정

1. GET vs POST 응답 차이

GET /interactions/{id}user_input step부터 전체 히스토리를 반환하지만, POST /interactions 는 출력 step만 반환합니다. 대화 히스토리를 파싱하는 코드라면 step 타입 필터링이 필수입니다.

# GET 응답 파싱 예시 — user_input은 건너뜀
for step in interaction.steps:
    if step.type == "model_output":
        print(step.content[0].text)

2. 새 기능은 steps에서만

5월 7일 이후 출시된 신규 기능(새 서버사이드 도구, 실행 중 개입 등)은 steps 스키마를 써야만 받을 수 있습니다. 레거시 outputs를 유지하면 새 기능에 접근 자체가 불가능합니다.


마무리

이번 Gemini API 변경은 단순한 필드명 교체가 아닙니다. AI 실행 흐름 전체를 "타임라인"으로 모델링하는 구조적 전환입니다. 단기적으로 마이그레이션 비용이 생기지만, 장기적으론 함수 호출·검색·코드 실행이 섞인 복잡한 에이전트 로직을 훨씬 깔끔하게 다룰 수 있게 됩니다.

6월 8일이 데드라인입니다. 지금 바로 outputs 검색을 시작하세요.


출처

공유

Threads X