Android 앱에서 하이브리드 환경을 위한 구조화된 출력 생성


Gemini 모델은 기본적으로 비구조화된 텍스트로 대답을 반환합니다. 하지만 일부 사용 사례에서는 구조화된 텍스트 (예: JSON 또는 열거형)가 필요합니다. 예를 들어 기존 데이터 스키마가 필요한 다른 다운스트림 작업에 대답을 사용할 수 있습니다.

모델에서 생성된 출력이 항상 특정 스키마를 준수하도록 하려면 모델 대답 청사진처럼 작동하는 스키마를 정의하면 됩니다. 그러면 후처리를 덜 거치고 모델 출력에서 데이터를 직접 추출할 수 있습니다.

몇 가지 사용 사례는 다음과 같습니다.

  • 모델의 대답이 유효한 JSON을 생성하고 제공된 스키마를 준수하도록 합니다.
    예를 들어 모델은 항상 레시피 이름, 재료 목록, 단계를 포함하는 레시피의 구조화된 항목을 생성할 수 있습니다. 그러면 앱의 UI에서 이 정보를 더 쉽게 파싱하고 표시할 수 있습니다.

  • 분류 작업 중에 모델이 응답하는 방식을 제한합니다.
    예를 들어 모델이 생성하는 라벨 (good, positive, negative, bad와 같이 어느 정도 가변성이 있을 수 있음) 대신 특정 라벨 세트 (예: positive, negative와 같은 특정 열거형 세트)로 텍스트에 주석을 달도록 할 수 있습니다.

이 페이지에서는 Android 앱의 하이브리드 환경에서 구조화된 출력 (예: JSON 및 enum)을 생성하는 방법을 설명합니다.

JSON 출력으로 이동 enum 출력으로 이동

구조화된 출력 구성

구조화된 출력 (예: JSON 및 enum) 생성은 온디바이스 추론과 클라우드 호스팅 추론 모두에서 지원됩니다.

구조화된 출력을 생성하려면 스키마를 generateObject()에 직접 전달하세요. 스키마 요구사항은 구성된 추론 모드에 따라 다릅니다.

  • 온디바이스 및 하이브리드 추론 (ONLY_ON_DEVICE, PREFER_ON_DEVICE, PREFER_IN_CLOUD):

    • KSP 프로세서가 있는 Kotlin data class에서 @Generable 주석을 사용해야 합니다. 수동 스키마와 직접 enum class 주석은 지원되지 않습니다.
    • 추론이 기기에서 실행되면 SDK는 ML Kit 프롬프트 API를 사용하여 스키마를 기기 내 모델의 제약 조건으로 자동 변환합니다.
    • 하이브리드 요청이 클라우드 추론으로 대체되면 SDK는 자동으로 responseMimeTypeapplication/json로 설정하고 스키마를 클라우드 호스팅 Gemini 모델에 전달합니다.
  • 클라우드 전용 추론 (ONLY_IN_CLOUD)의 경우:

    • @Generable 주석 (권장)과 수동 스키마(JsonSchema 도우미 메서드를 사용하여 빌드됨)를 모두 지원합니다.
    • SDK는 responseMimeTypeapplication/json로 자동 설정하고 스키마를 클라우드 호스팅 Gemini 모델에 전달합니다.

시작하기 전에

Gemini API 제공업체를 클릭하여 이 페이지에서 제공업체별 콘텐츠와 코드를 확인합니다.

구조화된 출력을 생성하기 전에 다음 설정을 완료해야 합니다.

  1. 하이브리드 환경 빌드 시작 가이드를 완료합니다. 여기에는 Firebase 프로젝트 설정, 온디바이스 모델 다운로드, App Check 구성이 포함됩니다.

  2. Kotlin Symbol Processing (KSP) 플러그인을 구성하고 앱에 Firebase AI KSP 종속 항목을 추가합니다.

    모듈 (앱 수준) Gradle 파일(예: <project>/<app-module>/build.gradle.kts)에서 KSP 플러그인, Kotlin Serialization 플러그인, 필수 종속 항목을 추가합니다.

    plugins {
       // ... other plugins
       id("com.google.gms.google-services")
       id("com.google.devtools.ksp") version "LATEST_VERSION"
       id("org.jetbrains.kotlin.plugin.serialization") version "LATEST_VERSION"
    }
    
    dependencies {
       // ... other androidx dependencies
    
       // Add the dependencies for the Firebase AI Logic and App Check libraries.
       implementation("com.google.firebase:firebase-ai:17.17.0")
       implementation("com.google.firebase:firebase-ai-ondevice:16.0.0-beta05")
       implementation("com.google.firebase:firebase-appcheck-debug:19.4.1")
    
       // Add the Firebase AI KSP processor for schema generation.
       ksp("com.google.firebase:firebase-ai-ksp-processor:16.0.2")
    
       // (Optional) Add kotlinx.serialization JSON library for object decoding.
       implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:LATEST_VERSION")
    }


JSON 출력으로 이동 enum 출력으로 이동

JSON 출력

다음 예에서는 하이브리드 추론 (예: PREFER_ON_DEVICE)을 수용하도록 일반 JSON 출력 예를 조정합니다.

이 예시의 시나리오에서 모델은 이름, 나이, 종, 선택적 액세서리와 같은 구조화된 속성을 사용하여 판타지 이야기의 캐릭터 프로필 목록을 생성합니다.

다음 방법 중 하나를 사용하여 응답 스키마를 정의할 수 있습니다.

  • KSP 주석 (@Generable@Guide)

    • 모든 추론 모드에서 지원되며 온디바이스 및 하이브리드 추론 (특히 ONLY_ON_DEVICE, PREFER_ON_DEVICE, PREFER_IN_CLOUD)에 필요합니다.
    • 컴파일 시간에 스키마를 자동으로 생성하고 getObject()를 사용하여 응답을 강력한 유형의 객체로 직접 역직렬화하도록 Kotlin 데이터 클래스를 정의합니다.
  • 수동 JsonSchema 도우미 메서드

    • 클라우드 기반 추론 (특히 ONLY_IN_CLOUD)에 지원됩니다.
    • KSP 프로세서를 사용하지 않고 코드에서 JsonSchema를 수동으로 구성하고 response.response.text에서 원시 JSON 문자열을 읽습니다.

예 1: KSP와 함께 @Generable@Guide 주석 사용

@Serializable@Generable로 주석이 지정된 Kotlin data class를 정의합니다. 속성에 @Guide 주석을 사용하여 모델에 설명, 값 범위 또는 항목 제약 조건을 제공합니다.

이 접근 방식은 모든 추론 모드에서 지원되며 온디바이스 및 하이브리드 환경 (특히 ONLY_ON_DEVICE, PREFER_ON_DEVICE, PREFER_IN_CLOUD)에 필수입니다.

이 샘플을 사용해 보기 전에 이 가이드의 시작하기 전에 섹션을 완료하여 프로젝트와 앱을 설정하세요.
이 섹션에서는 선택한 Gemini API 제공업체의 버튼을 클릭하여 이 페이지에 제공업체별 콘텐츠가 표시되도록 합니다.

Kotlin의 경우 이 SDK의 메서드는 정지 함수이며 코루틴 범위에서 호출해야 합니다.
import com.google.firebase.Firebase
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.InferenceMode
import com.google.firebase.ai.OnDeviceConfig
import com.google.firebase.ai.annotations.Generable
import com.google.firebase.ai.annotations.Guide
import com.google.firebase.ai.ai
import kotlinx.serialization.Serializable

// Define data classes representing the schema, annotated with @Serializable and @Generable.
// You can provide descriptions on @Generable and @Guide to guide the model's output.
@Serializable
@Generable(description = "A character profile for a fantasy story")
data class Character(
    val name: String,
    val age: Int,
    val species: String,
    // Use @Guide to add property descriptions, value bounds (minimum/maximum), or formats.
    // Properties with default values or nullable types are treated as optional in the schema.
    @Guide(description = "An accessory the character wears or carries")
    val accessory: String? = null
) {
    // An empty companion object is required for KSP to generate the firebaseAISchema() extension.
    companion object
}

@Serializable
@Generable(description = "A list of character profiles")
data class CharacterList(
    // Use minItems or maxItems to specify collection size bounds for the model.
    @Guide(description = "List of characters", minItems = 1)
    val characters: List<Character>
) {
    // An empty companion object is required for KSP to generate the firebaseAISchema() extension.
    companion object
}

// Initialize the Gemini Developer API backend service.
// Create a GenerativeModel instance configured for hybrid inference (like PREFER_ON_DEVICE).
val model = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "CLOUD_MODEL_NAME",
        onDeviceConfig = OnDeviceConfig(mode = InferenceMode.INFERENCE_MODE)
    )

// Obtain the schema generated by KSP via the firebaseAISchema() extension.
val schema = CharacterList.firebaseAISchema()
val prompt = "Create profiles for some characters for a fantasy story."

// Generate the structured object (the SDK applies the schema to on-device or cloud models).
val response = model.generateObject(schema, prompt)

// Access the strongly-typed deserialized object directly via getObject().
val characterList: CharacterList? = response.getObject()
characterList?.characters?.forEach { character ->
    println("Name: ${character.name}, Species: ${character.species}, Age: ${character.age}")
    println("Accessory: ${character.accessory ?: "None"}")
}

예 2: 수동 JsonSchema 도우미 메서드 사용

앱에서 클라우드 기반 추론 (특히 ONLY_IN_CLOUD) 사용하는 경우 Firebase AI Logic SDK에서 제공하는 도우미 메서드를 사용하여 JsonSchema을 수동으로 빌드할 수 있습니다.

이 샘플을 사용해 보기 전에 이 가이드의 시작하기 전에 섹션을 완료하여 프로젝트와 앱을 설정하세요.
이 섹션에서는 선택한 Gemini API 제공업체의 버튼을 클릭하여 이 페이지에 제공업체별 콘텐츠가 표시되도록 합니다.

Kotlin의 경우 이 SDK의 메서드는 정지 함수이며 코루틴 범위에서 호출해야 합니다.
import com.google.firebase.Firebase
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.InferenceMode
import com.google.firebase.ai.OnDeviceConfig
import com.google.firebase.ai.ai
import com.google.firebase.ai.type.JsonSchema

// Define the schema manually using JsonSchema helper methods.
// Properties are required by default unless specified in optionalProperties.
val jsonSchema = JsonSchema.obj(
    properties = mapOf(
        "characters" to JsonSchema.array(
            items = JsonSchema.obj(
                properties = mapOf(
                    "name" to JsonSchema.string(),
                    "accessory" to JsonSchema.string(),
                    "age" to JsonSchema.integer(),
                    "species" to JsonSchema.string()
                ),
                optionalProperties = listOf("accessory")
            )
        )
    )
)

// Initialize the Gemini Developer API backend service.
// Manual schemas are only supported for cloud-based inference (specifically, ONLY_IN_CLOUD).
val model = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "CLOUD_MODEL_NAME",
        onDeviceConfig = OnDeviceConfig(mode = InferenceMode.ONLY_IN_CLOUD)
    )

// Call generateObject() with the manual schema and prompt.
val response = model.generateObject(
    jsonSchema,
    "Create profiles for some characters for a fantasy story."
)

// Access the generated JSON string conforming to the schema from response.response.text.
println(response.response.text)

열거형 출력

다음 예에서는 하이브리드 추론 (예: PREFER_ON_DEVICE)을 수용하도록 일반 열거형 출력 예를 조정합니다.

이 예시의 시나리오에서 모델은 허용된 옵션의 사전 정의된 목록(drama, comedy 또는 documentary)에서 단일 장르를 선택하여 영화 설명을 분류합니다.

다음 방법 중 하나를 사용하여 응답 스키마를 정의할 수 있습니다.

  • KSP 주석 (@Generable)

    • 모든 추론 모드에서 지원되며 온디바이스 및 하이브리드 추론 (특히 ONLY_ON_DEVICE, PREFER_ON_DEVICE, PREFER_IN_CLOUD)에 필요합니다.
    • Kotlin data class로 래핑된 enum을 정의하여 스키마를 자동으로 생성하고 getObject()를 사용하여 응답을 강력한 유형의 객체로 직접 역직렬화합니다.
  • 수동 JsonSchema 도우미 메서드

    • 클라우드 기반 추론 (특히 ONLY_IN_CLOUD)에 지원됩니다.
    • KSP 프로세서를 사용하지 않고 JsonSchema.enumeration()를 사용하여 열거형 JsonSchema를 수동으로 빌드하고 response.response.text에서 선택한 문자열을 읽습니다.

예 1: KSP와 함께 @Generable 주석 사용

허용된 값을 나타내는 enum class를 정의하고 @Serializable@Generable로 주석이 지정된 Kotlin data class 내의 속성으로 래핑합니다.

이 접근 방식은 모든 추론 모드에서 지원되며 온디바이스 및 하이브리드 환경 (특히 ONLY_ON_DEVICE, PREFER_ON_DEVICE, PREFER_IN_CLOUD)에 필수입니다.

이 샘플을 사용해 보기 전에 이 가이드의 시작하기 전에 섹션을 완료하여 프로젝트와 앱을 설정하세요.
이 섹션에서는 선택한 Gemini API 제공업체의 버튼을 클릭하여 이 페이지에 제공업체별 콘텐츠가 표시되도록 합니다.

Kotlin의 경우 이 SDK의 메서드는 정지 함수이며 코루틴 범위에서 호출해야 합니다.
import com.google.firebase.Firebase
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.InferenceMode
import com.google.firebase.ai.OnDeviceConfig
import com.google.firebase.ai.annotations.Generable
import com.google.firebase.ai.annotations.Guide
import com.google.firebase.ai.ai
import kotlinx.serialization.Serializable

// Define an enum class representing the allowed options.
@Serializable
enum class FilmGenre {
    DRAMA,
    COMEDY,
    DOCUMENTARY
}

// Wrap the enum in a data class annotated with @Serializable and @Generable.
// On-device inference requires an @Generable data class.
// Direct enum annotations are not supported on-device.
@Serializable
@Generable(description = "The classification result for the film")
data class FilmClassification(
    @Guide(description = "The genre of the film")
    val genre: FilmGenre
) {
    // An empty companion object is required for KSP to generate the firebaseAISchema() extension.
    companion object
}

// Initialize the Gemini Developer API backend service.
// Create a GenerativeModel instance configured for hybrid inference (like PREFER_ON_DEVICE).
val model = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "CLOUD_MODEL_NAME",
        onDeviceConfig = OnDeviceConfig(mode = InferenceMode.INFERENCE_MODE)
    )

// Obtain the schema generated by KSP via the firebaseAISchema() extension.
val schema = FilmClassification.firebaseAISchema()
val prompt = """
    The film aims to educate and inform viewers about real-life subjects, events, or people.
    It offers a factual record of a particular topic by combining interviews, historical footage,
    and narration. The primary purpose of a film is to present information and provide insights
    into various aspects of reality.
    """

// Generate the structured object (the SDK applies the schema to on-device or cloud models).
val response = model.generateObject(schema, prompt)

// Access the strongly-typed deserialized object and enum value directly via getObject().
val classification: FilmClassification? = response.getObject()
val genre: FilmGenre? = classification?.genre
println("Selected genre: $genre")

예 2: 수동 JsonSchema 도우미 메서드 사용

앱에서 클라우드 기반 추론 (특히 ONLY_IN_CLOUD) 사용하는 경우 Firebase AI Logic SDK에서 제공하는 도우미 메서드를 사용하여 열거형 JsonSchema을 수동으로 빌드할 수 있습니다.

이 샘플을 사용해 보기 전에 이 가이드의 시작하기 전에 섹션을 완료하여 프로젝트와 앱을 설정하세요.
이 섹션에서는 선택한 Gemini API 제공업체의 버튼을 클릭하여 이 페이지에 제공업체별 콘텐츠가 표시되도록 합니다.

Kotlin의 경우 이 SDK의 메서드는 정지 함수이며 코루틴 범위에서 호출해야 합니다.
import com.google.firebase.Firebase
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.InferenceMode
import com.google.firebase.ai.OnDeviceConfig
import com.google.firebase.ai.ai
import com.google.firebase.ai.type.JsonSchema

// Define an enum schema with allowed string values and a description.
val enumSchema = JsonSchema.enumeration(
    values = listOf("drama", "comedy", "documentary"),
    description = "The genre of the film"
)

// Initialize the Gemini Developer API backend service.
// Manual schemas are only supported for cloud-based inference (specifically, ONLY_IN_CLOUD).
val model = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "CLOUD_MODEL_NAME",
        onDeviceConfig = OnDeviceConfig(mode = InferenceMode.ONLY_IN_CLOUD)
    )

val prompt = """
    The film aims to educate and inform viewers about real-life subjects, events, or people.
    It offers a factual record of a particular topic by combining interviews, historical footage,
    and narration. The primary purpose of a film is to present information and provide insights
    into various aspects of reality.
    """

// Call generateObject() with the enum schema and prompt.
val response = model.generateObject(enumSchema, prompt)

// Access the selected enum value string from response.response.text.
println(response.response.text)


Firebase AI Logic 사용 경험에 관한 의견 보내기