L'SDK di chiamata di funzioni di IA Edge (FC SDK) è una libreria che consente agli sviluppatori di utilizzare la chiamata di funzioni con LLM on-device. La chiamata di funzioni ti consente di collegare i modelli a strumenti e API esterni, consentendo ai modelli di chiamare funzioni specifiche con i parametri necessari per eseguire azioni reali.
Anziché generare solo testo, un LLM che utilizza l'SDK FC può generare una chiamata strutturata a una funzione che esegue un'azione, ad esempio la ricerca di informazioni aggiornate, l'impostazione di sveglie o la prenotazione.
Questa guida illustra una procedura di avvio rapido di base per aggiungere l'API di inferenza LLM con l'SDK FC a un'applicazione per Android. Questa guida si concentra sull'aggiunta di funzionalità di chiamata di funzioni a un LLM on-device. Per ulteriori informazioni sull'utilizzo dell'API LLM Inference, consulta la guida LLM Inference per Android.
Guida rapida
Per utilizzare l'SDK FC nella tua applicazione per Android: Questo quickstart utilizza l'API di inferenza LLM con Hammer 2.1 (1,5 miliardi). L'API LLM Inference è ottimizzata per i dispositivi Android di fascia alta, come Pixel 8 e Samsung S23 o versioni successive, e non supporta in modo affidabile gli emulatori di dispositivi.
Aggiungi dipendenze
L'SDK FC utilizza la libreria com.google.ai.edge.localagents:localagents-fc e
l'API di inferenza LLM utilizza la libreria com.google.mediapipe:tasks-genai. Aggiungi entrambe le dipendenze al file build.gradle della tua app per Android:
dependencies {
implementation 'com.google.mediapipe:tasks-genai:0.10.24'
implementation 'com.google.ai.edge.localagents:localagents-fc:0.1.0'
}
Per i dispositivi con Android 12 (API 31) o versioni successive, aggiungi la dipendenza dalla libreria OpenCL nativa. Per ulteriori informazioni, consulta la documentazione relativa al
tag
uses-native-library.
Aggiungi i seguenti tag uses-native-library al file 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"/>
Scaricare un modello
Scarica Hammer 1B in un formato quantizzato a 8 bit da Hugging Face. Per ulteriori informazioni sui modelli disponibili, consulta la documentazione relativa ai modelli.
Invia i contenuti della cartella hammer2.1_1.5b_q8_ekv4096.task al dispositivo 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
Dichiarare le definizioni di funzione
Definisci le funzioni che verranno rese disponibili al modello. Per illustrare la procedura, questa guida rapida include due funzioni come metodi statici che restituiscono risposte predefinite. Un'implementazione più pratica consisterebbe nel definire funzioni che chiamano un'API REST o recuperano informazioni da un database.
Di seguito sono definite le funzioni getWeather e 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() {}
}
Utilizza FunctionDeclaration per descrivere ogni funzione, assegnando a ciascuna un nome e una descrizione e specificando i tipi. In questo modo il modello viene informato sulle funzioni e su quando effettuare le chiamate di funzione.
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();
Aggiungi le dichiarazioni di funzione a un oggetto Tool:
var tool = Tool.newBuilder()
.addFunctionDeclarations(getWeather)
.addFunctionDeclarations(getTime)
.build();
Crea il backend di inferenza
Crea un backend di inferenza utilizzando l'API LLM Inference e passa un oggetto formatter per il tuo modello. Lo strumento di formattazione dell'SDK FC (ModelFormatter) funge da visualizzatore e analizzatore. Poiché questa guida rapida utilizza Gemma-3 1B, utilizzeremo
GemmaFormatter:
var llmInferenceOptions = LlmInferenceOptions.builder()
.setModelPath(modelFile.getAbsolutePath())
.build();
var llmInference = LlmInference.createFromOptions(context, llmInferenceOptions);
var llmInferenceBackend = new llmInferenceBackend(llmInference, new GemmaFormatter());
Per ulteriori informazioni, consulta le opzioni di configurazione dell'inferenza LLM.
Esegui l'inizializzazione del modello
Utilizza l'oggetto GenerativeModel per collegare il backend di inferenza, il prompt di sistema e gli strumenti. Abbiamo già il backend e gli strumenti di inferenza, quindi dobbiamo solo creare il prompt di sistema:
var systemInstruction = Content.newBuilder()
.setRole("system")
.addParts(Part.newBuilder().setText("You are a helpful assistant."))
.build();
Esegui l'inizializzazione del modello con GenerativeModel:
var generativeModel = new GenerativeModel(
llmInferenceBackend,
systemInstruction,
List.of(tool),
)
Avviare una sessione di chat
Per semplicità, questa guida rapida avvia una singola sessione di chat. Puoi anche creare più sessioni indipendenti.
Utilizza la nuova istanza di GenerativeModel per avviare una sessione di chat:
var chat = generativeModel.startChat();
Invia prompt al modello tramite la sessione di chat utilizzando il metodo sendMessage:
var response = chat.sendMessage("How's the weather in San Francisco?");
Analizza la risposta del modello
Dopo aver passato un prompt al modello, l'applicazione deve esaminare la risposta per determinare se eseguire una chiamata di funzione o produrre un testo in linguaggio naturale.
// 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());
}
Il codice di esempio è un'implementazione eccessivamente semplificata. Per ulteriori informazioni su come un'applicazione può esaminare le risposte del modello, consulta Formattazione e analisi sintattica.
Come funziona
Questa sezione fornisce informazioni più approfondite sui concetti e sui componenti di base dell'SDK di chiamata delle funzioni per Android.
Modelli
L'SDK di chiamata di funzione richiede un modello con un formattatore e un parser. L'SDK FC contiene un formattatore e un parser integrati per i seguenti modelli:
- Gemma: utilizza
GemmaFormatter. - Llama: utilizza
LlamaFormatter. - Martello: utilizza il pulsante
HammerFormatter.
Per utilizzare un modello diverso con l'SDK FC, devi sviluppare il tuo formatore e il tuo parser compatibili con l'API di inferenza LLM.
Formattazione e analisi
Un aspetto fondamentale del supporto delle chiamate di funzioni è la formattazione dei prompt e l'analisi sintattica
dell'output del modello. Anche se si tratta di due processi distinti, l'SDK FC gestisce sia la formattazione sia l'analisi con l'interfaccia ModelFormatter.
Il formatter è responsabile della conversione delle dichiarazioni di funzioni strutturate in testo, della formattazione delle risposte di funzione e dell'inserimento di token per indicare l'inizio e la fine dei turni di conversazione, nonché i relativi ruoli (ad es. "utente", "modello").
Il parser è responsabile del rilevamento della presenza di una chiamata di funzione nella risposta del modello. Se il parser rileva una chiamata di funzione, la analizza in un tipo di dati strutturati. In caso contrario, tratta il testo come una risposta in linguaggio naturale.
Decodifica vincolata
La decodifica vincolata è una tecnica che guida la generazione dell'output degli LLM per assicurarsi che rispetti un formato strutturato predefinito, ad esempio oggetti JSON o chiamate di funzioni Python. Attuando questi vincoli, il modello formatta i suoi risultati in modo che siano in linea con le funzioni predefinite e i relativi tipi di parametri.
Per attivare la decodifica vincolata, definisci le limitazioni in un oggetto ConstraintOptions
e invoca il metodo enableConstraint di un'istanza ChatSession.
Se abilitato, questo vincolo limita la risposta a includere solo gli strumenti associati a GenerativeModel.
L'esempio seguente mostra come configurare la decodifica vincolata per limitare la risposta alle chiamate dello strumento. Obbliga la chiamata allo strumento a iniziare con il prefisso ```tool_code\n e a terminare con il suffisso \n```.
ConstraintOptions constraintOptions = ConstraintOptions.newBuilder()
.setToolCallOnly( ConstraintOptions.ToolCallOnly.newBuilder()
.setConstraintPrefix("```tool_code\n")
.setConstraintSuffix("\n```"))
.build();
chatSession.enableConstraint(constraintOptions);
Per disattivare la limitazione attiva all'interno della stessa sessione, utilizza il metodo
disableConstraint:
chatSession.disableConstraint();