Araçlar, cihaz üzerindeki temsilcinizin uygulama verilerine erişmesine, arka uç hizmetleriyle iletişim kurmasına ve kullanıcı adına işlem yapmasına olanak tanır.
Araçların işleyiş şekli
Kullanıcı bir istem gönderdiğinde AgentRunner sınıfı, dört aşamada bir aracı döngüsü yürütür:
- Gözlem: Gemini Nano, kullanıcının istemini ve mevcut sohbet bağlamını kayıtlı araç bildirimlerine (temsilcinin eylem alanı) göre analiz eder.
- Neden: Model, uygulama içi bir aracın gerekli olup olmadığını belirler. Bir araç gerekiyorsa Gemini Nano, işlev adını ve yazılı bağımsız değişkenleri içeren yapılandırılmış bir araç çağrısı yayınlar.
- İşlem:
AgentRunnerörneği bu çağrıyı otomatik olarak yakalar ve uygulamanızdaki ilgili Kotlin işlevini yürütür. - Geri bildirimi değerlendirme: Aracın çıkışı Gemini Nano'ya geri gönderilir. Model, geri bildirimi değerlendirir ve kullanıcıya yanıt verir ya da bir sonlandırma koşulu karşılanana kadar (hedefe ulaşma veya
maxTurnssınırına ulaşma) başka bir araç çağırır.
Android AppFunctions ile bildirime dayalı araçlar
Araçları tanımlamanın önerilen yolu, Android AppFunctions (androidx.appfunctions) kullanarak bildirimde bulunmaktır. AppFunctions, otomatik şema oluşturma ile yazılı uygulama içi özellikleri bildirmek için standartlaştırılmış bir platform modeli sağlar.
1. Gradle bağımlılıkları ekleme
Modülünüzün build.gradle.kts dosyasına genai-agent ile birlikte AppFunctions yapılarını ekleyin:
dependencies {
implementation("com.google.mlkit:genai-agent:1.0.0-alpha1")
implementation("androidx.appfunctions:appfunctions:1.0.0-alpha13")
ksp("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha13")
}
2. Araç yöntemlerine @AppFunctionDeclaration ek açıklamasıyla not ekleyin.
Herkese açık araç yöntemlerine @AppFunctionDeclaration(isDescribedByKDoc = true) ek açıklamasını ekleyin. Parametre açıklamaları, standart KDoc @param etiketlerinde belgelenir.
AppFunctions, dönüş değerlerinin temel türler (ör. String, Int veya Boolean) ya da @AppFunctionSerializable ek açıklamasıyla ek açıklama eklenmiş yapılandırılmış veri sınıfları olmasını gerektirir.
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
/**
* Structured details for an order.
*/
@AppFunctionSerializable
data class OrderDetails(
val orderId: String,
val status: String,
val estimatedDelivery: String?,
val itemCount: Int,
)
/**
* Result returned when cancelling an order.
*/
@AppFunctionSerializable
data class CancelOrderResult(
val orderId: String,
val cancelled: Boolean,
val message: String,
)
@AppFunctionServiceEntryPoint(
serviceName = "OrderAppFunctionService",
appFunctionXmlFileName = "order_app_functions",
)
abstract class OrderTools : AppFunctionService() {
private val orderRepository = OrderRepository()
/**
* Fetches details and delivery status for a customer order by ID.
*
* @param orderId The alphanumeric order identifier (for example, ORD-8492)
*/
@AppFunctionDeclaration(isDescribedByKDoc = true)
suspend fun fetch_order_details(
orderId: String
): OrderDetails = withContext(Dispatchers.IO) {
val order = orderRepository.findOrder(orderId)
if (order != null) {
OrderDetails(
orderId = order.id,
status = order.status,
estimatedDelivery = order.deliveryEstimate,
itemCount = order.items.size,
)
} else {
OrderDetails(
orderId = orderId,
status = "NOT_FOUND",
estimatedDelivery = null,
itemCount = 0,
)
}
}
/**
* Requests a cancellation or return for an active order.
*
* @param orderId The order identifier to cancel
* @param reason The reason provided by the user for cancellation
*/
@AppFunctionDeclaration(isDescribedByKDoc = true)
suspend fun cancel_order(
orderId: String,
reason: String? = null
): CancelOrderResult = withContext(Dispatchers.IO) {
val success = orderRepository.cancelOrder(orderId, reason)
CancelOrderResult(
orderId = orderId,
cancelled = success,
message = if (success) {
"Order cancellation processed."
} else {
"Order cannot be cancelled at this stage."
}
)
}
}
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>
3. ACCESS_LEVEL_SELF sabitiyle arayan erişimini kısıtlama
AppFunctions'ın sistemde veya harici asistanlarda herkese açık olması gerekmez. Android'de erişim denetimi, manuel arayan kimliği kontrolleri yerine arayan erişim düzeyleri aracılığıyla yönetilir.
Varsayılan olarak (ACCESS_LEVEL_ANDROID_TRUSTED sabiti kullanılarak) bir AppFunction, EXECUTE_APP_FUNCTIONS sistem iznine sahip platform sertifikalı cihaz üzerinde asistanlar tarafından bulunabilir ve yürütülebilir. Ancak yalnızca uygulamanızın dahili temsilcisi için tasarlanmış özellikler (ör. kullanıcı alışveriş sepetlerini inceleme, yerel jetonlara erişme veya uygulama içi işlemler gerçekleştirme) oluştururken ACCESS_LEVEL_SELF sabitini kullanarak erişimi yalnızca kendi uygulamanızla kısıtlayabilirsiniz:
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() {
private val orderRepository = OrderRepository()
/**
* Cancels an order. Restricted exclusively to this app's internal agent.
*/
@OptIn(ExperimentalAppFunctionsApi::class)
@AppFunctionDeclaration(isDescribedByKDoc = true)
@AppFunctionAccessLevel(
level = AppFunctionMetadata.ACCESS_LEVEL_SELF,
isCompatEnforcementEnabled = true,
)
suspend fun cancel_order(orderId: String): CancelOrderResult {
// Only your app's internal agent can invoke this function
val success = orderRepository.cancelOrder(orderId)
return CancelOrderResult(
orderId = orderId,
cancelled = success,
message = if (success) "Cancelled." else "Failed."
)
}
}
Platform, üç arayan erişim düzeyini destekler:
ACCESS_LEVEL_SELF(100): Kesinlikle ana makine uygulamasıyla sınırlıdır. Harici asistanlar, sistem yüzeyleri ve diğer uygulamalar, IPC üzerinden işlevi keşfedemez veya çağıramaz. Bu seviyeyi, hassas işlemler veya yalnızca uygulamanızın dahili temsilcisine hizmet etmesi gereken araçlar için kullanın.ACCESS_LEVEL_SYSTEM(200):android.Manifest.permission#EXECUTE_APP_FUNCTIONS_SYSTEMiznine sahip ayrıcalıklı sistem çağırıcıları (ör. sistem başlatıcı veya son kullanılanlar) ve ana makine uygulamasının kendisiyle sınırlıdır.ACCESS_LEVEL_ANDROID_TRUSTED(300, varsayılan):EXECUTE_APP_FUNCTIONSiznine sahip platform sertifikalı cihaz üzerinde çalışan aracılara, sistem yüzeylerine ve ana uygulamaya açıktır.
4. Araçları temsilciye kaydetme
AppFunctions'ı temsilciye otomatik olarak enableAppFunctions() yöntemini kullanarak veya programatik olarak AppFunctionAgentTools.discover() yöntemini kullanarak kaydedebilirsiniz:
enableAppFunctions() yöntemiyle otomatik keşif
AppFunctions'ın, model tarafından çağrıldığında otomatik olarak yürütüldüğü basit uygulamalar için:
import com.google.mlkit.genai.agent.Agent
import com.google.mlkit.genai.agent.AgentRunner
val agent = Agent.builder()
.setName("OrderAssistant")
.setInstructions("Assist users with order tracking.")
.enableAppFunctions(true) // Automatically discovers all AppFunctions in your app package
.setMaxTurns(10)
.build()
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.
AppFunctionAgentTools.discover() yöntemiyle programatik keşif
Uygulamanızın, keşfedilen AppFunctions'ı incelemesi, filtrelemesi veya temsilciye kaydetmeden önce süslemesi gerektiğinde:
import com.google.mlkit.genai.agent.Agent
import com.google.mlkit.genai.agent.AgentRunner
import com.google.mlkit.genai.agent.AppFunctionAgentTools
val discoveredTools = AppFunctionAgentTools.discover(
enabledAppFunctionIds = listOf("fetch_order_details", "cancel_order") // Optional ID filter
)
val agent = Agent.builder()
.setName("OrderAssistant")
.setInstructions("Assist users with order tracking.")
.addTools(discoveredTools)
.build()
val runner = AgentRunner(agent)
Dekoratör deseni ve insan müdahalesi gerektiren
Sipariş iptalleri, ödemeler veya kullanıcı verilerini silme gibi hassas işlemler için kullanıcı onayı zorunlu tutularak insan müdahalesi gerektiren (HITL) bir süreç izlenmelidir. Agent sınıfına eklenen tüm araçlar Android AppFunctions'tan gelir. AgentTool sınıfı, keşfedilen AppFunction araçlarını Decorator kalıbını kullanarak sarmalayabilmeniz için yetki veren bir kurucu AgentTool(delegate) sağlar:
import com.google.mlkit.genai.agent.AgentTool
class HitlConfirmationTool(
delegate: AgentTool,
private val onConfirm: suspend (toolName: String, args: Map<String, Any>) -> Boolean
) : AgentTool(delegate) {
override suspend fun execute(args: Map<String, Any>): Map<String, Any?> {
val confirmed = onConfirm(name, args)
if (!confirmed) {
return mapOf(
"status" to "CANCELLED_BY_USER",
"message" to "Action was declined by the user."
)
}
return checkNotNull(delegate).execute(args)
}
}
Araç tasarımıyla ilgili en iyi uygulamalar
- İşlem alanını belirleyin:
addAppFunctionIds()yöntemini veACCESS_LEVEL_SELFsabitini kullanarak temsilcinin işlem alanını (temsilciye sunulan araç ve izinler grubu) yalnızca görevini yerine getirebileceği kadar geniş tutun. Aşırı büyük bir işlem alanı, cihaz üzerinde çalışan modeli hataya daha açık hale getirir ve bağlam penceresi jetonlarını tüketir. - Açıklamalarda net olun: Gemini Nano, bir aracın ne zaman çağrılacağına karar vermek için araç ve parametre açıklamalarını kullanır. Aracın amacını net bir şekilde belirtin ve beklenen bağımsız değişken biçimlerini (tarihler veya kimlikler gibi) açıklayın.
- Yapılandırılmış hata eşlemeleri döndürme: Beklenen bir hata oluştuğunda
mapOf("error" to "Order not found")gibi açıklayıcı hata eşlemeleri döndürün. Bu sayede Gemini Nano, sorunu kullanıcıya düzgün bir şekilde açıklayabilir. Bir araç beklenmedik bir istisna oluşturursa çalışma zamanı bunu otomatik olarak yakalar ve hata mesajını kendi kendini düzeltme için modele geri yansıtır. - Döndürülen yükleri odaklanmış tutun: Cihaz üzerinde çalışan modeller, sunucu modellerine göre daha küçük bağlam pencerelerine sahiptir. Tüm veritabanı satırlarını veya ham ağ yanıtlarını dökümlemek yerine yalnızca kullanıcının sorgusunu yanıtlamayla alakalı alanları döndürün.
- G/Ç'yi
Dispatchers.IOdağıtıcısında çalıştırın: Eş yordam çağırıcısının engellenmesini önlemek için araçlardaki ağ isteklerinin ve Room veritabanı sorgularının her zamanDispatchers.IOdağıtıcısında yürütüldüğünden emin olun.
Sonraki adımlar
- Oturumları ve yaşam döngüsünü yönetme bölümünde, uygulama döndürme işlemleri sırasında görüşme bağlamını nasıl koruyacağınızı ve oturumları nasıl temizleyeceğinizi öğrenin.
- Akış etkinlikleri ve kullanıcı arayüzü entegrasyonu bölümünde, akış metni jetonlarını ve araç yürütme durumlarını işleyin.