Le SDK d'appel de fonction Edge AI (SDK FC) est une bibliothèque qui permet aux développeurs d'utiliser l'appel de fonction avec des LLM sur l'appareil. L'appel de fonction vous permet de connecter des modèles à des outils et des API externes, ce qui leur permet d'appeler des fonctions spécifiques avec les paramètres nécessaires pour exécuter des actions réelles.
Plutôt que de générer simplement du texte, un LLM utilisant le SDK FC peut générer un appel structuré à une fonction qui exécute une action, comme rechercher des informations à jour, définir des alarmes ou effectuer des réservations.
Ce guide vous explique comment ajouter l'API d'inférence LLM avec le SDK FC à une application Android. Ce guide explique comment ajouter des fonctionnalités d'appel de fonction à un LLM sur l'appareil. Pour en savoir plus sur l'utilisation de l'API LLM Inference, consultez le guide LLM Inference pour Android.
Guide de démarrage rapide
Pour utiliser le SDK FC dans votre application Android, procédez comme suit : Ce tutoriel de démarrage utilise l'API d'inférence LLM avec Hammer 2.1 (1,5 milliard). L'API d'inférence LLM est optimisée pour les appareils Android haut de gamme, tels que le Pixel 8 et le Samsung S23 ou modèles ultérieurs, et n'est pas fiable avec les émulateurs d'appareils.
Ajouter des dépendances
Le SDK FC utilise la bibliothèque com.google.ai.edge.localagents:localagents-fc
, et l'API d'inférence LLM utilise la bibliothèque com.google.mediapipe:tasks-genai
. Ajoutez les deux dépendances au fichier build.gradle
de votre application Android:
dependencies {
implementation 'com.google.mediapipe:tasks-genai:0.10.24'
implementation 'com.google.ai.edge.localagents:localagents-fc:0.1.0'
}
Pour les appareils équipés d'Android 12 (API 31) ou version ultérieure, ajoutez la dépendance de la bibliothèque OpenCL native. Pour en savoir plus, consultez la documentation sur la balise uses-native-library
.
Ajoutez les balises uses-native-library
suivantes au fichier AndroidManifest.xml
:
<uses-native-library android:name="libOpenCL.so" android:required="false"/>
<uses-native-library android:name="libOpenCL-car.so" android:required="false"/>
<uses-native-library android:name="libOpenCL-pixel.so" android:required="false"/>
Télécharger un modèle
Téléchargez Hammer 1B au format quantifié 8 bits depuis Hugging Face. Pour en savoir plus sur les modèles disponibles, consultez la documentation sur les modèles.
Transférez le contenu du dossier hammer2.1_1.5b_q8_ekv4096.task
vers l'appareil Android.
$ adb shell rm -r /data/local/tmp/llm/ # Remove any previously loaded models
$ adb shell mkdir -p /data/local/tmp/llm/
$ adb push hammer2.1_1.5b_q8_ekv4096.task /data/local/tmp/llm/hammer2.1_1.5b_q8_ekv4096.task
Déclarer des définitions de fonction
Définissez les fonctions qui seront mises à la disposition du modèle. Pour illustrer le processus, ce guide de démarrage rapide inclut deux fonctions en tant que méthodes statiques qui renvoient des réponses codées en dur. Une implémentation plus pratique consisterait à définir des fonctions qui appellent une API REST ou récupèrent des informations à partir d'une base de données.
Le code suivant définit les fonctions getWeather
et getTime
:
class ToolsForLlm {
public static String getWeather(String location) {
return "Cloudy, 56°F";
}
public static String getTime(String timezone) {
return "7:00 PM " + timezone;
}
private ToolsForLlm() {}
}
Utilisez FunctionDeclaration
pour décrire chaque fonction, en lui attribuant un nom et une description, et en spécifiant les types. Cela informe le modèle de ce que font les fonctions et du moment où les appeler.
var getWeather = FunctionDeclaration.newBuilder()
.setName("getWeather")
.setDescription("Returns the weather conditions at a location.")
.setParameters(
Schema.newBuilder()
.setType(Type.OBJECT)
.putProperties(
"location",
Schema.newBuilder()
.setType(Type.STRING)
.setDescription("The location for the weather report.")
.build())
.build())
.build();
var getTime = FunctionDeclaration.newBuilder()
.setName("getTime")
.setDescription("Returns the current time in the given timezone.")
.setParameters(
Schema.newBuilder()
.setType(Type.OBJECT)
.putProperties(
"timezone",
Schema.newBuilder()
.setType(Type.STRING)
.setDescription("The timezone to get the time from.")
.build())
.build())
.build();
Ajoutez les déclarations de fonction à un objet Tool
:
var tool = Tool.newBuilder()
.addFunctionDeclarations(getWeather)
.addFunctionDeclarations(getTime)
.build();
Créer le backend d'inférence
Créez un backend d'inférence à l'aide de l'API d'inférence LLM et transmettez-lui un objet de formatage pour votre modèle. Le formateur du SDK FC (ModelFormatter
) agit à la fois comme un formateur et un analyseur. Étant donné que ce guide de démarrage rapide utilise Gemma-3 1B, nous utiliserons GemmaFormatter
:
var llmInferenceOptions = LlmInferenceOptions.builder()
.setModelPath(modelFile.getAbsolutePath())
.build();
var llmInference = LlmInference.createFromOptions(context, llmInferenceOptions);
var llmInferenceBackend = new llmInferenceBackend(llmInference, new GemmaFormatter());
Pour en savoir plus, consultez les options de configuration de l'inférence LLM.
Instancier le modèle
Utilisez l'objet GenerativeModel
pour connecter le backend d'inférence, l'invite système et les outils. Nous disposons déjà du backend d'inférence et des outils. Il ne nous reste donc qu'à créer l'invite système:
var systemInstruction = Content.newBuilder()
.setRole("system")
.addParts(Part.newBuilder().setText("You are a helpful assistant."))
.build();
Instancier le modèle avec GenerativeModel
:
var generativeModel = new GenerativeModel(
llmInferenceBackend,
systemInstruction,
List.of(tool),
)
Démarrer une session de chat
Pour des raisons de simplicité, ce guide de démarrage rapide démarre une seule session de chat. Vous pouvez également créer plusieurs sessions indépendantes.
À l'aide de la nouvelle instance de GenerativeModel
, démarrez une session de chat:
var chat = generativeModel.startChat();
Envoyez des requêtes au modèle via la session de chat à l'aide de la méthode sendMessage
:
var response = chat.sendMessage("How's the weather in San Francisco?");
Analyser la réponse du modèle
Après avoir transmis une requête au modèle, l'application doit examiner la réponse pour déterminer si elle doit effectuer un appel de fonction ou générer du texte en langage naturel.
// Extract the model's message from the response.
var message = response.getCandidates(0).getContent().getParts(0);
// If the message contains a function call, execute the function.
if (message.hasFunctionCall()) {
var functionCall = message.getFunctionCall();
var args = functionCall.getArgs().getFieldsMap();
var result = null;
// Call the appropriate function.
switch (functionCall.getName()) {
case "getWeather":
result = ToolsForLlm.getWeather(args.get("location").getStringValue());
break;
case "getTime":
result = ToolsForLlm.getWeather(args.get("timezone").getStringValue());
break;
default:
throw new Exception("Function does not exist:" + functionCall.getName());
}
// Return the result of the function call to the model.
var functionResponse =
FunctionResponse.newBuilder()
.setName(functionCall.getName())
.setResponse(
Struct.newBuilder()
.putFields("result", Value.newBuilder().setStringValue(result).build()))
.build();
var functionResponseContent = Content.newBuilder()
.setRole("user")
.addParts(Part.newBuilder().setFunctionResponse(functionResponse))
.build();
var response = chat.sendMessage(functionResponseContent);
} else if (message.hasText()) {
Log.i(message.getText());
}
L'exemple de code est une implémentation trop simplifiée. Pour en savoir plus sur la façon dont une application peut examiner les réponses du modèle, consultez la section Mise en forme et analyse.
Fonctionnement
Cette section fournit des informations plus détaillées sur les concepts et composants clés du SDK d'appel de fonction pour Android.
Modèles
Le SDK d'appel de fonction nécessite un modèle avec un formateur et un analyseur. Le SDK FC contient un formateur et un analyseur intégrés pour les modèles suivants:
Pour utiliser un autre modèle avec le SDK FC, vous devez développer votre propre formateur et votre propre analyseur compatibles avec l'API d'inférence LLM.
Mise en forme et analyse
Une partie importante de la prise en charge des appels de fonction est la mise en forme des requêtes et l'analyse de la sortie du modèle. Bien qu'il s'agisse de deux processus distincts, le SDK FC gère à la fois le formatage et l'analyse avec l'interface ModelFormatter
.
Le formateur est chargé de convertir les déclarations de fonction structurées en texte, de mettre en forme les réponses de fonction et d'insérer des jetons pour indiquer le début et la fin des tours de conversation, ainsi que les rôles de ces tours (par exemple, "utilisateur", "modèle").
L'analyseur est chargé de détecter si la réponse du modèle contient un appel de fonction. Si l'analyseur détecte un appel de fonction, il l'analyse en type de données structuré. Sinon, il traite le texte comme une réponse en langage naturel.
Décodage contraint
Le décodage contraint est une technique qui guide la génération de sortie des LLM pour s'assurer qu'elle respecte un format structuré prédéfini, tel que des objets JSON ou des appels de fonction Python. En appliquant ces contraintes, le modèle met en forme ses sorties de manière à s'aligner sur les fonctions prédéfinies et leurs types de paramètres correspondants.
Pour activer le décodage contraint, définissez les contraintes dans un objet ConstraintOptions
et appelez la méthode enableConstraint
d'une instance ChatSession
.
Lorsqu'elle est activée, cette contrainte limite la réponse aux outils associés à GenerativeModel
.
L'exemple suivant montre comment configurer le décodage contraint pour limiter la réponse aux appels d'outils. Il contraint l'appel de l'outil à commencer par le préfixe ```tool_code\n
et à se terminer par le suffixe \n```
.
ConstraintOptions constraintOptions = ConstraintOptions.newBuilder()
.setToolCallOnly( ConstraintOptions.ToolCallOnly.newBuilder()
.setConstraintPrefix("```tool_code\n")
.setConstraintSuffix("\n```"))
.build();
chatSession.enableConstraint(constraintOptions);
Pour désactiver la contrainte active dans la même session, utilisez la méthode disableConstraint
:
chatSession.disableConstraint();