Le SDK AI Edge Function Calling (FC SDK) 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 API externes. Les modèles peuvent ainsi appeler des fonctions spécifiques avec les paramètres nécessaires pour exécuter des actions réelles.
Plutôt que de simplement générer 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 de démarrage rapide vous explique comment ajouter l'API LLM Inference 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
Suivez les étapes ci-dessous pour utiliser le SDK FC dans votre application Android. Ce guide de démarrage rapide utilise l'API LLM Inference avec Hammer 2.1 (1,5 milliard). L'API LLM Inference est optimisée pour les appareils Android haut de gamme, tels que le Pixel 8 et le Samsung S23 ou les modèles ultérieurs, et n'est pas compatible 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 LLM Inference 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é de 8 bits depuis HuggingFace. 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 définirait des fonctions qui appellent une API REST ou récupèrent des informations à partir d'une base de données.
Les fonctions getWeather et getTime sont définies comme suit :
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 indique au modèle ce que font les fonctions et quand 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 fonctions à 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 LLM Inference et transmettez-lui un objet de mise en forme pour votre modèle. Le Formatter FC SDK (ModelFormatter) sert à la fois de formateur et d'analyseur. Comme ce guide de démarrage rapide utilise Gemma-3 1B, nous allons utiliser 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 et des outils d'inférence. 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();
Instanciez le modèle avec GenerativeModel :
var generativeModel = new GenerativeModel(
llmInferenceBackend,
systemInstruction,
List.of(tool),
)
Démarrer une session de chat
Pour plus de simplicité, ce guide de démarrage rapide lance 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 un prompt au modèle, l'application doit examiner la réponse pour déterminer s'il faut 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 Mise en forme et analyse.
Fonctionnement
Cette section fournit des informations plus détaillées sur les concepts et les composants clés du SDK Function Calling pour Android.
Modèles
Le SDK Function Calling 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 :
- Gemma : utilisez
GemmaFormatter. - Llama : utilisez
LlamaFormatter. - Marteau : utilisez l'outil
HammerFormatter.
Pour utiliser un autre modèle avec le SDK FC, vous devez développer votre propre formateur et analyseur compatibles avec l'API LLM Inference.
Mise en forme et analyse
La mise en forme des requêtes et l'analyse de la sortie du modèle sont des éléments clés de la compatibilité avec l'appel de fonction. Bien qu'il s'agisse de deux processus distincts, le SDK FC gère la mise en forme 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 dans un type de données structurées. 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 à ce qu'elles correspondent aux 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 d'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 au cours de la même session, utilisez la méthode disableConstraint :
chatSession.disableConstraint();