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


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

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

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

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

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

이 페이지에서는 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 Prompt API를 사용하여 스키마를 온디바이스 모델의 제약 조건으로 자동 변환합니다.
    • 하이브리드 요청이 클라우드 추론으로 대체되면 SDK는 자동으로 responseMimeType을 application/json로 설정하고 스키마를 클라우드 호스팅 Gemini 모델에 전달합니다.
  • 클라우드 전용 추론 (ONLY_IN_CLOUD):

    • @Generable 주석 (권장)과 수동 스키마(JsonSchema 도우미 메서드를 사용하여 빌드됨)를 모두 지원합니다.
    • SDK는 responseMimeType을 application/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 직렬화 플러그인, 필수 종속 항목을 추가합니다.

    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:18.0.0")
       implementation("com.google.firebase:firebase-ai-ondevice:16.0.0-beta06")
       implementation("com.google.firebase:firebase-appcheck-debug:20.0.0")
    
       // Add the Firebase AI KSP processor for schema generation.
       ksp("com.google.firebase:firebase-ai-ksp-processor:17.0.0")
    
       // (Optional) Add kotlinx.serialization JSON library for object decoding.
       implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:LATEST_VERSION")
    }


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

JSON 출력

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

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

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

  • KSP 주석 (@Generable 및 @Guide)

    • 모든 추론 모드에서 지원되며 온디바이스 및 하이브리드 추론 (특히 ONLY_ON_DEVICE, PREFER_ON_DEVICE, PREFER_IN_CLOUD)에 필수 입니다.
    • Kotlin 데이터 클래스를 정의하여 컴파일 시간에 스키마를 자동으로 생성하고 getObject()를 사용하여 응답을 강력한 유형의 객체로 직접 역직렬화합니다.
  • 수동 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의 메서드는 정지 함수이며 Coroutine 범위에서 호출해야 합니다.
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의 메서드는 정지 함수이며 Coroutine 범위에서 호출해야 합니다.
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)

enum 출력

다음 예에서는 일반적인 enum 출력 예시 를 조정하여 하이브리드 추론 (예: 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()을 사용하여 enum 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의 메서드는 정지 함수이며 Coroutine 범위에서 호출해야 합니다.
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에서 제공하는 도우미 메서드를 사용하여 enum JsonSchema 을 수동으로 빌드할 수 있습니다.

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

Kotlin의 경우 이 SDK의 메서드는 정지 함수이며 Coroutine 범위에서 호출해야 합니다.
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 사용 경험에 관한