ML Kit'in cihaz üzerinde çalışan temsilci tabanlı iş akışları (com.google.mlkit:genai-agent, AICore Geliştirici Önizlemesi programı aracılığıyla kullanılabilir) sayesinde Gemini Nano ve Android AICore sistem hizmeti tarafından desteklenen otonom, çok turlu etkileşimli temsilciler oluşturabilirsiniz.
Doğrudan model erişimi sağlayan GenerativeModel sınıfı üzerine inşa edilen AgentRunner sınıfı, tüm aracı döngülerini otomatikleştirir: çok adımlı işlemleri planlama, yazılı araçları çağırma (ör. uygulama deposunu sorgulama, arka uç API'sini çağırma veya yerel veritabanını okuma), araç sonuçlarını değerlendirme ve sohbet bağlamını sıfır ağ gecikmesi ve tam kullanıcı gizliliğiyle cihaz üzerinde yerel olarak yönetme. GenerativeModel sınıfı, List<Content> nesnesi (USER ve MODEL rolleriyle) ve sessionId değeri kullanarak istemci tarafından yönetilen çok turlu geçmişi destekler. AgentRunner sınıfı ise AgentSession arayüzünü kullanarak yönetilen çok turlu oturumlar sağlar. Bu oturumlar, bellek içi sohbet geçmişini turlar arasında otomatik olarak kaydeder. Böylece transkriptleri manuel olarak yönetmeniz gerekmez. Statik araç bildirimleri ve sistem talimatları da cihaz üzerinde otomatik olarak önbelleğe alınır. Böylece ek yapılandırma olmadan ilk jeton süresi gecikmesi azaltılır.
Temel bileşenler
Agentsınıfı:Agent.builder()yöntemini kullanarak talimatları, kullanılabilir araçları ve yürütme önlemlerini tanımlar. Otomatik olarakmaxTurns = 10değerine ayarlanır.AgentRunnersınıfı:GenerativeModelsınıfının üzerine inşa edilmiştir. Otonom akıl yürütme döngülerini ve yönetilen oturumları cihaz üzerinde modellerle yönetir.Dispatchers.IOüzerinde varsayılan olarak ana iş parçacığı için güvenlidir.temperature, varsayılan olaraknulldeğerine ayarlanır (bu değer, modelin varsayılan değerine göre belirlenir; açgözlü kod çözme içintemperature = 0.0fdeğerini iletin).AgentSessionarayüzü:runAsync(content)veclose()yöntemleriyle, bellek içi görüşme geçmişini otomatik olarak kaydedenrunner.getOrCreateSession(sessionId)yöntemi kullanılarak elde edilen kapsamlı çok aşamalı görüşme oturumu işleyicisi.AgentEventarayüzü: Metin jetonları ve araç güncellemeleri yayınlayan reaktif KotlinFlowakışı.AgentToolsınıfı: Android AppFunctions (@AppFunctionDeclaration) kullanılarak tanımlanan, model tarafından çağrılabilen tür atanmış işlevler.GenAiExceptionsınıfı:MAX_TURNS_EXCEEDED,NOT_AVAILABLEveyaBUSYgibi hata durumlarını bildiren yazılı istisna hiyerarşisi (com.google.mlkit.genai.common.GenAiException).
Android becerileri
GitHub'da gösterML Kit Agent API'yi kullanma
android skills add mlkit-agent-apiÖn koşullar ve bağımlılıklar
Agent API'yi entegre etmeden önce geliştirme ortamınızın ve Gradle yapılandırmanızın aşağıdaki şartları karşıladığından emin olun.
Platform ve donanım gereksinimleri
- Android sürümü: AICore Geliştirici Önizlemesi programına kayıtlı Android 14 (API düzeyi 34) veya sonraki sürümler.
- Desteklenen cihazlar: Desteklenen cihazların ve Gemini Nano model sürümlerinin listesi için Özel içerik üretme ve temsilci cihaz desteği başlıklı makaleyi inceleyin.
- Minimum SDK:
minSdk 26veya sonraki sürümler. - Kotlin: Kotlin 2.3 veya sonraki sürümler.
Gradle yapılandırması
Modülünüzün build.gradle.kts dosyasına genai-agent bağımlılığını ekleyin:
dependencies {
// Gemini Nano agentic workflows
implementation("com.google.mlkit:genai-agent:1.0.0-alpha1")
// Optional: Only required when defining tools using Android AppFunctions
implementation("androidx.appfunctions:appfunctions:1.0.0-alpha13")
ksp("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha13")
}
genai-agent için ek açıklama işleyicisi veya derleyici eklentisi gerekmez ancak androidx.appfunctions ile araç tanımlamak için appfunctions-compiler KSP eklentisi gerekir.
Hızlı başlangıç: Temsilci başlatma
Aşağıdaki kod örneğinde, cihaz üzerinde çalışan bir temsilcinin ve çalıştırıcının nasıl örneklendirileceği gösterilmektedir:
import com.google.mlkit.genai.agent.Agent
import com.google.mlkit.genai.agent.AgentRunner
// Configure the agent with system instructions
val agent = Agent.builder()
.setInstructions("You are a helpful on-device assistant.")
.build()
// Create the runner to execute prompts
val runner = AgentRunner(agent)
Araçları tanımlama
Model, uygulama verilerini sorgulamak, arka uç hizmetleriyle iletişim kurmak veya uygulama içi işlemleri tetiklemek için yazılı araçları çağırabilir. Araçlar, Android AppFunctions (androidx.appfunctions) kullanılarak bildirimli olarak tanımlanır:
package com.example.ai.agent.tools
import androidx.appfunctions.AppFunctionDeclaration
import androidx.appfunctions.AppFunctionSerializable
import androidx.appfunctions.AppFunctionService
import androidx.appfunctions.AppFunctionServiceEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@AppFunctionSerializable
data class OrderDetails(
val orderId: String,
val status: String,
val eta: String,
)
@AppFunctionServiceEntryPoint(
serviceName = "OrderAppFunctionService",
appFunctionXmlFileName = "order_app_functions",
)
abstract class OrderTools : AppFunctionService() {
/**
* Fetches details and delivery status for an in-app order.
*
* @param orderId The alphanumeric order identifier
*/
@AppFunctionDeclaration(isDescribedByKDoc = true)
suspend fun fetch_order_details(
orderId: String
): OrderDetails = withContext(Dispatchers.IO) {
// Query local database or call your backend API
OrderDetails(
orderId = orderId,
status = "Out for delivery",
eta = "2:30 PM",
)
}
}
Oluşturulan hizmeti uygulamanızın AndroidManifest.xml dosyasına kaydedin:
<service
android:name=".OrderAppFunctionService"
android:permission="android.permission.BIND_APP_FUNCTION_SERVICE"
android:exported="true">
<property
android:name="android.app.appfunctions.schema"
android:value="app_functions_schema.xsd" />
<property
android:name="android.app.appfunctions.v2"
android:value="order_app_functions.xml" />
<intent-filter>
<action android:name="android.app.appfunctions.AppFunctionService" />
</intent-filter>
</service>
ACCESS_LEVEL_SELF sabitiyle arayan erişimini kısıtlama
AppFunctions'ın sisteme veya harici arayanlara açık olması gerekmez. Android'de erişim denetimi, arayan kimliklerini incelemek yerine arayan erişim düzeyleri aracılığıyla gerçekleştirilir.
Varsayılan olarak (ACCESS_LEVEL_ANDROID_TRUSTED sabiti kullanılarak) AppFunctions, EXECUTE_APP_FUNCTIONS sistem iznine sahip platform sertifikalı cihaz üzerinde asistanlar tarafından çağrılabilir. Aracınız yalnızca uygulamanızın dahili temsilcisi için tasarlanmışsa (ör. kullanıcı sepetlerini veya özel veritabanı kayıtlarını yönetme) ACCESS_LEVEL_SELF sabitini kullanarak arayan erişimini kısıtlayın:
import androidx.appfunctions.AppFunctionAccessLevel
import androidx.appfunctions.AppFunctionDeclaration
import androidx.appfunctions.AppFunctionService
import androidx.appfunctions.AppFunctionServiceEntryPoint
import androidx.appfunctions.ExperimentalAppFunctionsApi
import androidx.appfunctions.metadata.AppFunctionMetadata
@AppFunctionServiceEntryPoint(
serviceName = "OrderAppFunctionService",
appFunctionXmlFileName = "order_app_functions",
)
abstract class OrderTools : AppFunctionService() {
/**
* Cancels an order. Restricted strictly to this app's internal agent.
*/
@OptIn(ExperimentalAppFunctionsApi::class)
@AppFunctionDeclaration(isDescribedByKDoc = true)
@AppFunctionAccessLevel(
level = AppFunctionMetadata.ACCESS_LEVEL_SELF,
isCompatEnforcementEnabled = true,
)
fun cancel_order(
orderId: String
): String {
// Only your app's internal agent can invoke this function
return "Order $orderId cancelled successfully."
}
}
ACCESS_LEVEL_SELF sabitiyle kısıtlandığında platform, harici platformların ve sistem asistanlarının işlevi IPC üzerinden keşfetmesini veya yürütmesini engeller.
Temsilciyi yapılandırma
Sistem talimatlarıyla bir Agent örneği yapılandırın ve AppFunctions'ı etkinleştirin, ardından AgentRunner örneğini ilk kullanıma hazırlayın:
import com.google.mlkit.genai.agent.Agent
import com.google.mlkit.genai.agent.AgentRunner
// Configure the agent with system instructions and enable AppFunctions
val agent = Agent.builder()
.setName("OrderAssistant")
.setInstructions(
"You are a helpful assistant for looking up store orders. " +
"Use available tools to fetch order information."
)
.enableAppFunctions(true) // Automatically discovers all registered AppFunctions in your app
.build()
// Initialize the runner
val runner = AgentRunner(agent)
İsteğe bağlı olarak, tüm uygulama içi işlevleri göstermek yerine keşfi yalnızca belirli AppFunction kimlikleriyle sınırlamak için addAppFunctionIds("fetch_order_details", "cancel_order") yöntemini çağırın.
Temsilci varsayılanları
- Sıra sınırları:
Agent.Buildersınıfı, sonsuz araç çağırma döngülerini önlemek için otomatik olarakmaxTurns = 10değerini sonlandırma koşulu olarak varsayılan olarak ayarlar. Standart sohbet veya araç çağırma iş akışları içinsetMaxTurns(10)yöntemini manuel olarak çağırmanız gerekmez. - Deterministik açgözlü kod çözme:
AgentRunnersınıfı, varsayılantemperatureparametresininullolarak ayarlar ve temel modelin varsayılan değerini kullanır. Cihaz üzerinde deterministik araç seçimi ve JSON şeması uyumluluğu içinAgentRunneroluşturucusunatemperature = 0.0f(temperature) değerini iletin. Mobil modellerde halüsinasyon riskini ve şema bozulmasını artıran bulut tarzı sıcaklıklar (> 0,4f) ayarlamaktan kaçının.
Çok turlu yürütme ve akış etkinlikleri
Android ViewModel sınıfındaki runner.getOrCreateSession(sessionId) yöntemini kullanarak bir AgentSession örneği alın. Oturum, anlık metin jetonları ve araç yürütme güncellemeleri yayınlayan bir Flow<AgentEvent> akışı döndürür:
package com.example.ai.agent
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.mlkit.genai.agent.AgentEvent
import com.google.mlkit.genai.agent.AgentRunner
import com.google.mlkit.genai.agent.AgentSession
import com.google.mlkit.genai.common.GenAiException
import com.google.mlkit.genai.prompt.Content
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
data class AgentUiState(
val messages: List<String> = emptyList(),
val currentResponse: String = "",
val activeToolStatus: String? = null,
val isLoading: Boolean = false,
val errorMessage: String? = null
)
class ChatViewModel(
private val runner: AgentRunner,
private val sessionId: String = "chat_session"
) : ViewModel() {
// Scoped session preserves conversation history across configuration changes (screen rotations)
private val session: AgentSession = runner.getOrCreateSession(sessionId)
private val _uiState = MutableStateFlow(AgentUiState())
val uiState: StateFlow<AgentUiState> = _uiState.asStateFlow()
fun sendMessage(userText: String) {
_uiState.update {
it.copy(
messages = it.messages + userText,
currentResponse = "",
activeToolStatus = null,
isLoading = true,
errorMessage = null
)
}
viewModelScope.launch {
val content = Content.builder().text(userText).build()
session.runAsync(content)
.catch { e ->
val message = when {
e is GenAiException && e.errorCode == GenAiException.ErrorCode.MAX_TURNS_EXCEEDED ->
"Agent exceeded the maximum reasoning turns allowed."
e is GenAiException && e.errorCode == GenAiException.ErrorCode.NOT_AVAILABLE ->
"On-device AI is currently unavailable."
e is GenAiException && e.errorCode == GenAiException.ErrorCode.BUSY ->
"On-device AI is busy. Please try again."
else -> e.localizedMessage ?: "Agent error"
}
_uiState.update {
it.copy(
isLoading = false,
activeToolStatus = null,
errorMessage = message
)
}
}
.collect { event ->
when (event) {
is AgentEvent.TextMessage -> {
_uiState.update {
it.copy(
currentResponse = if (event.isPartial) {
it.currentResponse + event.text
} else {
event.text.ifEmpty { it.currentResponse }
},
activeToolStatus = null
)
}
}
is AgentEvent.FunctionCall -> {
_uiState.update {
it.copy(activeToolStatus = "Executing ${event.name}...")
}
}
is AgentEvent.FunctionResponse -> {
_uiState.update {
it.copy(activeToolStatus = "Received data from ${event.name}")
}
}
else -> {}
}
}
// Finalize message once stream completes
_uiState.update {
it.copy(
messages = it.messages + it.currentResponse,
currentResponse = "",
activeToolStatus = null,
isLoading = false
)
}
}
}
override fun onCleared() {
super.onCleared()
// Cleanly evicts conversation memory from RAM when ViewModel is destroyed
session.close()
}
}
Metin jetonlarını doğrudan aktarma
Araç yürütme ayrıntılarının kullanıcı arayüzünde ayrı olarak gösterilmesi gerekmeyen etkileşimli arayüzler için Flow<AgentEvent> arayüzündeki textTokens() uzantı işlevini kullanın:
import com.google.mlkit.genai.agent.textTokens
import com.google.mlkit.genai.prompt.Content
val content = Content.builder().text("What is my order status?").build()
session.runAsync(content)
.textTokens()
.collect { token ->
print(token)
}
Tek adımlı yürütme
Diyalog geçmişinin RAM'de saklanmaması gereken tek seferlik görevler (ör. fotoğraf etiketleme veya geçici metin özetleme) için doğrudan runner.runSingleTurnAsync(content) yöntemini çağırın:
// Ephemeral single-turn: cleans up session state from RAM automatically upon completion
val content = Content.builder()
.text("Summarize the order history for customer #1042: ...")
.build()
runner.runSingleTurnAsync(content)
.textTokens()
.collect { token ->
displaySummary(token)
}
runner.runSingleTurnAsync(content) yöntemini doğrudan çağırırken AgentRunner örneği, dahili olarak geçici bir oturum kimliği tahsis eder ve tamamlandığında görüşme durumunu bellekten otomatik olarak silerek bellek sızıntılarını önler.
Oturum yaşam döngüsü ve bellek yönetimi
Çok turlu diyalog geçmişi, bellekte saklanır ve sessionId değeriyle dizine eklenir:
- Yapılandırma değişiklikleri:
AgentSessionörneğini bir AndroidViewModelsınıfında tutmak, her dönüşte dize eklemeye gerek kalmadan ekran döndürme işlemlerinde sohbet geçmişini otomatik olarak korur. - Oturum çıkarma: Bir görüşme dizisi kapatıldığında oturumu eşzamanlı olarak çıkarmak için
session.delete()yöntemini çağırın veya RAM'i boşaltmak içinViewModel.onCleared()yönteminde askıya alınmayansession.close()yöntemini çağırın. - Toplu çıkarma: Belirli bir oturumu serbest bırakmak için
runner.deleteSession(sessionId)yöntemini, önbelleğe alınmış tüm sohbetleri çıkarmak içinrunner.clearAllSessions()yöntemini çağırın. - Çalıştırıcı yaşam döngüsü:
AgentRunnersınıfı,AutoCloseablearayüzünü uygular. Bir çalıştırıcıyı ekranlar arasında paylaşırken her ekranınViewModel.onCleared()yönteminde bağımsızAgentSessiontutamaçlarını kapatın ve çalıştırıcıyı tamamen kapatırkenrunner.close()yöntemini çağırın. - Eşzamanlı oturumlar: Tek bir
AgentRunnerörneği, aynı anda birden fazla farklı oturumu barındırabilir. HersessionIddeğeri, ayrı bir görüşme geçmişi tutar.
GenAiException sınıfıyla hata işleme
Temsilci yürütme sırasında oluşan çalışma zamanı hataları (ör. temsilci yanıt oluşturmadan maksimum araç sırasına ulaştığında veya cihaz üzerinde yapay zeka geçici olarak kullanılamadığında) GenAiException istisnası (com.google.mlkit.genai.common.GenAiException) olarak yayınlanır veya atılır. Kotlin Coroutines Flow catch operatörünü kullanarak hataları reaktif bir şekilde işleyin:
session.runAsync(content)
.catch { e ->
if (e is GenAiException) {
when (e.errorCode) {
GenAiException.ErrorCode.MAX_TURNS_EXCEEDED -> {
// Turn limit exceeded
}
GenAiException.ErrorCode.NOT_AVAILABLE -> {
// Gemini Nano or AICore unavailable
}
GenAiException.ErrorCode.BUSY -> {
// System busy or rate limit reached
}
else -> {
// Other GenAiException errors
}
}
}
}
.collect { event ->
// Process response events
}
Anahtar hata kodları
GenAiException.ErrorCode.MAX_TURNS_EXCEEDED(-112): Temsilci, nihai bir yanıt oluşturmadan maksimum sıra sınırını (maxTurnssınırı) aştı.GenAiException.ErrorCode.NOT_AVAILABLE(8): Gemini Nano modeli veya AICore sistem hizmeti kullanılamıyor ya da hazır değil.GenAiException.ErrorCode.BUSY(9): Sistem meşgul veya arama uygulaması kotasını aştı.