ML Kit의 직접 모델 액세스를 사용하면 함수 호출을 사용하여 Gemini Nano 모델이 일반 텍스트 응답 대신 구조화된 함수 실행 요청 (도구 호출)을 출력하도록 할 수 있습니다. 함수 호출을 사용하면 기기 내 생성형 AI 모델을 외부 도구, API, 로컬 앱 기능에 연결할 수 있습니다.
주요 기능
함수 호출은 다음과 같은 주요 기능을 제공합니다.
- 싱글턴 함수 호출: Gemini Nano가 하나 이상의 도구 호출(
FunctionCall)을 예측하고, 앱이 로컬에서 함수를 실행하며, 후속 모델 응답 없이 흐름이 완료됩니다. - 멀티턴 함수 호출: Gemini Nano가 하나 이상의 도구 호출(
FunctionCall)을 예측하고, 앱이 로컬에서 함수를 실행하고, 결과를 다시 전달 (FunctionResponsePart)하여 더 많은 도구 호출 또는 최종 합성된 텍스트 응답을 가져옵니다.
함수 호출을 구현할 때 다음을 활용할 수 있습니다.
- 프로그래매틱 도구 정의: ML Kit GenAI 스키마 API (
com.google.mlkit:genai-schema)를 사용하여 런타임에 동적FunctionDeclaration및FunctionSchema도구 정의를 구성합니다. - 구조화된 인수 파싱: 모델 응답 후보에서 직접 강력한 유형의 인수 값을 수신하여 로컬 앱 로직을 실행합니다.
결과 예시
함수 호출은 싱글턴 및 멀티턴 흐름을 모두 지원합니다. 두 경우 모두 모델은 함수 이름과 인수로 구성된 하나 이상의 도구 호출을 예측합니다. 멀티턴 흐름의 경우 앱은 앱의 실행 결과를 수신한 후 전체 대화 기록과 함께 모델에 다른 요청을 전송하여 더 많은 도구 호출 또는 사용자에 대한 최종 텍스트 응답을 가져올 수 있습니다.
| 실행 흐름 | 사용자 프롬프트 | 모델 출력 |
|---|---|---|
| 싱글턴 | "거실 조명 밝기 80% 로 켜 줘." |
도구 호출:turn_on_light(room="living room", brightness=80)
|
| 싱글턴 | "카메라 앱 열어 줘." |
도구 호출:open_app(appName="Camera")
|
| 멀티턴 | "샌프란시스코 날씨는 섭씨로 어때?" |
중간 도구 호출:get_current_weather(location="San Francisco, CA", unit="celsius")
사용자에게 표시되는 최종 모델 출력: In SF it's currently 25 degrees Celsius.
|
기본 요건
함수 호출을 사용하려면 다음 기기 및 계정 요구사항을 충족해야 합니다.
- 기기에서 Prompt API를 지원합니다.
- 기기의 Google 계정이 AICore 개발자 프리뷰 프로그램에 참여 중입니다.
이러한 요구사항을 충족하는지 확인하려면 AICore 앱에서 Gemini Nano 4 Fast 모델을 사용할 수 있는지 확인하세요. AICore 앱을 열고 모델 선택 드롭다운을 클릭한 후 Gemini Nano 4 Fast가 표시되는지 확인합니다. 모델이 없으면 기기 지원 또는 계정 등록에 문제가 있는 것이며 함수 호출이 작동하지 않습니다.
또한 프로젝트는 다음 요구사항을 충족해야 합니다.
- Kotlin 버전 2.3.0 이상
- 최소 SDK (
minSdk) 버전 26 이상
시작하기
함수 호출을 시작하는 단계는 다음과 같습니다.
프로젝트 수준
settings.gradle.kts(또는settings.gradle) 파일에서mavenCentral()를repositories {}블록에 추가합니다.dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }모듈 수준
build.gradle.kts(또는build.gradle파일)에 ML Kit Prompt API 및 스키마 종속 항목을 추가합니다.Kotlin
plugins { id("com.android.application") id("org.jetbrains.kotlin.android") } dependencies { // ML Kit GenAI Prompt and Schema SDKs implementation("com.google.mlkit:genai-prompt:1.0.0-beta5") implementation("com.google.mlkit:genai-schema:1.0.0-alpha2") }Groovy
plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' } dependencies { // ML Kit GenAI Prompt and Schema SDKs implementation 'com.google.mlkit:genai-prompt:1.0.0-beta5' implementation 'com.google.mlkit:genai-schema:1.0.0-alpha2' }모듈 수준
build.gradle(또는build.gradle.kts파일)에서minSdk버전을26이상으로 설정합니다.Kotlin
android { defaultConfig { // ... minSdk = 26 // ... } }Groovy
android { defaultConfig { // ... minSdk 26 // ... } }
함수 호출 API 사용 방법
함수 호출을 구현하려면 다음 단계를 따르세요.
- 도구를 정의합니다.
- 모델을 선택합니다.
- 요청에 도구를 연결합니다.
- 도구 호출 (싱글턴 또는 멀티턴)을 처리합니다.
다음 섹션에서는 이러한 단계를 보여주는 예시를 살펴봅니다.
도구 정의
com.google.mlkit.genai.schema.tools 패키지의 FunctionDeclaration, FunctionSchema, FunctionType를 사용하여 프로그래매틱 방식으로 도구 스키마를 구성합니다. (자동 실행과 함께 Android의 @AppFunction 주석을 사용하여 컴파일 시간에 선언적으로 도구를 정의하려면 도구 정의를 참고하세요.)
예를 들어 단일 차례 실행을 위해 스마트 조명을 켜는 것과 같은 작업 지향 도구를 정의할 수 있습니다.
import com.google.mlkit.genai.schema.tools.FunctionDeclaration
import com.google.mlkit.genai.schema.tools.FunctionSchema
import com.google.mlkit.genai.schema.tools.FunctionType
val turnOnLightTool = FunctionDeclaration(
name = "turn_on_light",
description = "Turn on the lights in a room and set the brightness",
parameters = FunctionSchema(
type = FunctionType.OBJECT,
properties = mapOf(
"room" to FunctionSchema(
type = FunctionType.STRING,
description = "The room name"
),
"brightness" to FunctionSchema(
type = FunctionType.INTEGER,
description = "Brightness level from 0 to 100"
)
),
required = listOf("room")
)
)
또는 데이터 검색 도구를 정의합니다 (예: 멀티턴 합성을 위해 현재 날씨 가져오기).
import com.google.mlkit.genai.schema.tools.FunctionDeclaration
import com.google.mlkit.genai.schema.tools.FunctionSchema
import com.google.mlkit.genai.schema.tools.FunctionType
val getWeatherTool = FunctionDeclaration(
name = "get_current_weather",
description = "Get the current weather for a location",
parameters = FunctionSchema(
type = FunctionType.OBJECT,
properties = mapOf(
"location" to FunctionSchema(
type = FunctionType.STRING,
description = "The city and state, e.g. San Francisco, CA"
),
"unit" to FunctionSchema(
type = FunctionType.STRING,
description = "The temperature unit, either 'celsius' or 'fahrenheit'"
)
),
required = listOf("location")
)
)
모델 선택
함수 호출에는 Gemini Nano 4가 필요합니다. Gemini Nano 4에 액세스하려면 모델 선택 API를 사용하여 GenerativeModel 인스턴스가 ModelReleaseStage.PREVIEW 및 ModelPreference.FAST를 타겟팅하도록 구성합니다.
import com.google.mlkit.genai.prompt.Generation
import com.google.mlkit.genai.prompt.ModelPreference
import com.google.mlkit.genai.prompt.ModelReleaseStage
import com.google.mlkit.genai.prompt.generationConfig
import com.google.mlkit.genai.prompt.modelConfig
// Target the preview fast model (Gemini Nano 4)
val config = generationConfig {
modelConfig = modelConfig {
releaseStage = ModelReleaseStage.PREVIEW
preference = ModelPreference.FAST
}
}
val generativeModel = Generation.getClient(config)
요청에 도구 연결
GenerateContentRequest 객체를 만들 때 요청 빌더에서 FunctionDeclaration 목록을 setTools()에 전달합니다.
예를 들어 시스템 안내가 포함된 싱글턴 작업 요청에 도구를 연결하려면 다음을 실행합니다.
import com.google.mlkit.genai.prompt.SystemInstruction
import com.google.mlkit.genai.prompt.TextPart
import com.google.mlkit.genai.prompt.generateContentRequest
val requestText = "Turn on the living room lights and set brightness to 50"
val request = generateContentRequest(
SystemInstruction("You are a helpful home automation assistant."),
TextPart(requestText)
) {
// Attach the FunctionDeclaration tool schemas
setTools(listOf(turnOnLightTool))
temperature = 0.2f
}
// Run non-streaming inference
val response = generativeModel.generateContent(request)
또는 멀티턴 쿼리에 FunctionDeclaration 목록을 연결하려면 다음 안내를 따르세요.
import com.google.mlkit.genai.prompt.SystemInstruction
import com.google.mlkit.genai.prompt.TextPart
import com.google.mlkit.genai.prompt.generateContentRequest
val availableTools = listOf(getWeatherTool)
// Use the generateContentRequest DSL
val request = generateContentRequest(
TextPart("What is the weather in San Francisco, CA in celsius?")
) {
setTools(availableTools)
}
val response = generativeModel.generateContent(request)
도구 호출 처리
Gemini Nano가 도구를 호출하기로 결정하면 모델의 응답 후보에는 candidate.functionCalls에 하나 이상의 FunctionCall 객체가 포함됩니다. 도구 호출을 처리하려면 앱에서 먼저 응답 후보를 검사하여 도구 호출이 예측되었는지 확인해야 합니다.
import com.google.mlkit.genai.common.FunctionArgValue
import com.google.mlkit.genai.prompt.Content
import com.google.mlkit.genai.prompt.FunctionCallPart
import com.google.mlkit.genai.prompt.FunctionResponsePart
import com.google.mlkit.genai.prompt.GenerateContentRequest
import com.google.mlkit.genai.prompt.TextPart
import com.google.mlkit.genai.prompt.content
val candidate = response.candidates.firstOrNull()
val functionCalls = candidate?.functionCalls ?: emptyList()
if (functionCalls.isNotEmpty()) {
// Process tool calls using either the single-turn or multi-turn flow
// described in the following sections
}
싱글턴 함수 호출
앱이 요청을 직접 처리하는 작업 지향 작업 (예: '카메라 앱 열기' 또는 '거실 조명 켜기')에는 싱글턴 함수 호출을 사용합니다. 앱이 로컬에서 함수를 실행하면 흐름이 완료되며 후속 모델 응답이 필요하지 않습니다.
for (functionCall in functionCalls) {
val name = functionCall.name
val args = functionCall.arguments // Map<String, FunctionArgValue>
when (name) {
"open_app" -> {
val appName = (args["appName"] as? FunctionArgValue.StringValue)?.value
launchApp(appName)
}
"turn_on_light" -> {
val room = (args["room"] as? FunctionArgValue.StringValue)?.value
val brightness = (args["brightness"] as? FunctionArgValue.IntValue)?.value ?: 100
setLightState(room, brightness)
}
else -> Log.w(TAG, "Unhandled tool call: $name")
}
}
멀티턴 함수 호출
사용자가 도구에서 검색한 데이터를 기반으로 자연어 답변을 기대하는 경우 (예: '샌프란시스코의 날씨는 어때?') 멀티턴 함수 호출을 사용합니다.
멀티턴 흐름에서 앱은 다음을 수행합니다.
- 요청된 함수를 로컬에서 실행합니다.
- 결과를
FunctionResponsePart객체로 패키징합니다. - 모델의 호출 (
MODEL역할)과 실행 결과(USER역할)를 모두 대화 기록에 추가합니다. - Gemini Nano에 후속 요청을 다시 전송하여 최종 자연어 답변을 합성합니다.
// 1. Execute each predicted tool call and collect results
val responseParts = mutableListOf<FunctionResponsePart>()
for (functionCall in functionCalls) {
val responsePart: FunctionResponsePart = when {
functionCall.name == "get_current_weather" -> {
val location = (functionCall.arguments["location"] as? FunctionArgValue.StringValue)?.value ?: ""
val unit = (functionCall.arguments["unit"] as? FunctionArgValue.StringValue)?.value ?: "celsius"
val weatherData = fetchWeather(location, unit) // Local network/API call
// Package the tool execution result as a key-value map
FunctionResponsePart(
id = functionCall.id,
name = functionCall.name,
response = mapOf("result" to weatherData)
)
}
else -> throw IllegalArgumentException("Unknown tool: ${functionCall.name}")
}
responseParts.add(responsePart)
}
// 2. Append turns to conversation history to construct the multi-turn context
val history = request.contents.toMutableList().apply {
// Turn 1: Model's request containing the predicted FunctionCallPart object
add(
content(Content.Role.MODEL) {
for (call in functionCalls) {
addPart(FunctionCallPart(call))
}
}
)
// Turn 2: User's response containing the executed FunctionResponsePart object
add(
content(Content.Role.USER) {
for (responsePart in responseParts) {
addPart(responsePart)
}
}
)
}
// 3. Send the updated history back to Gemini Nano for final text synthesis
val followUpRequest = GenerateContentRequest.Builder(history)
.setTools(availableTools) // Include tools in case the model requires subsequent tool calls
.build()
val finalResponse = generativeModel.generateContent(followUpRequest)
val answer = finalResponse.candidates.firstOrNull()?.text
Log.d(TAG, "Final Model Response: $answer")
샘플 코드
Android 앱에서 함수 호출이 작동하는 전체 예시는 이 ML Kit 샘플 앱을 참고하세요.
알려진 문제
- 직접 모델 액세스 (
genai-prompt)의 AndroidX AppFunctions(@AppFunction): Prompt API(com.google.mlkit:genai-prompt:1.0.0-beta5)를 통해 컴파일 시간@AppFunction도구를 직접 검색하고 실행하는 기능은 아직 제공되지 않습니다.genai-prompt라이브러리의 도구는FunctionDeclaration클래스를 사용하여 프로그래매틱 방식으로 정의해야 합니다. 현재@AppFunction도구를 사용하려면 에이전트 워크플로(com.google.mlkit:genai-agent)를 사용하세요. - 스트리밍 요청 (
generateContentStream)을 사용할 때는 도구 호출이 토큰별로 스트리밍되지 않습니다. 대신 모델이 도구 호출 생성을 완료하면 완전한FunctionCall객체가StreamingCallback.onNewFunctionCall를 통해 또는 최종 스트리밍된GenerateContentResponse.candidates[0].functionCalls로 내보내집니다.