Udhëzues për thirrjen e funksionit të AI Edge për Android

SDK-ja e Thirrjes së Funksioneve AI Edge (FC SDK) është një bibliotekë që u mundëson zhvilluesve të përdorin thirrjen e funksioneve me LLM-të në pajisje. Thirrja e funksioneve ju lejon të lidhni modelet me mjete dhe API të jashtme, duke u mundësuar modeleve të thërrasin funksione specifike me parametrat e nevojshëm për të ekzekutuar veprime në botën reale.

Në vend që të gjenerojë vetëm tekst, një LLM që përdor FC SDK mund të gjenerojë një thirrje të strukturuar për një funksion që ekzekuton një veprim, siç është kërkimi i informacionit të azhurnuar, vendosja e alarmeve ose bërja e rezervimeve.

Ky udhëzues ju udhëzon përmes një nisjeje të shpejtë bazë për të shtuar API-në LLM Inference me FC SDK në një aplikacion Android. Ky udhëzues përqendrohet në shtimin e aftësive të thirrjes së funksioneve në një LLM në pajisje. Për më shumë informacion mbi përdorimin e API-së LLM Inference, shihni udhëzuesin LLM Inference për Android .

Nisje e shpejtë

Ndiqni hapat e mëposhtëm për të përdorur FC SDK në aplikacionin tuaj Android. Ky udhëzues i shpejtë përdor LLM Inference API me Hammer 2.1 (1.5B) . LLM Inference API është i optimizuar për pajisjet Android të nivelit të lartë, siç janë Pixel 8 dhe Samsung S23 ose më të ri, dhe nuk mbështet në mënyrë të besueshme emulatorët e pajisjeve.

Shto varësi

FC SDK përdor bibliotekën com.google.ai.edge.localagents:localagents-fc dhe LLM Inference API përdor bibliotekën com.google.mediapipe:tasks-genai . Shtoni të dy varësitë në skedarin build.gradle të aplikacionit tuaj Android:

dependencies {
    implementation 'com.google.mediapipe:tasks-genai:0.10.24'
    implementation 'com.google.ai.edge.localagents:localagents-fc:0.1.0'
}

Për pajisjet me Android 12 (API 31) ose më të lartë, shtoni varësinë e bibliotekës vendase OpenCL. Për më shumë informacion, shihni dokumentacionin mbi etiketën uses-native-library .

Shtoni etiketat e mëposhtme uses-native-library në skedarin 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"/>

Shkarkoni një model

Shkarkoni Hammer 1B në një format të kuantizuar 8-bitësh nga Hugging Face . Për më shumë informacion mbi modelet e disponueshme, shihni dokumentacionin e Modeleve .

Vendos përmbajtjen e dosjes hammer2.1_1.5b_q8_ekv4096.task në pajisjen 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

Deklaroni përkufizimet e funksioneve

Përcaktoni funksionet që do t'i vihen në dispozicion modelit. Për të ilustruar procesin, ky udhëzues i shpejtë përfshin dy funksione si metoda statike që kthejnë përgjigje të koduara në mënyrë të ngurtë. Një zbatim më praktik do të përcaktonte funksionet që thërrasin një REST API ose marrin informacion nga një bazë të dhënash.

Më poshtë përcaktohen funksionet getWeather dhe 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() {}
}

Përdorni FunctionDeclaration për të përshkruar çdo funksion, duke i dhënë secilit një emër dhe përshkrim, dhe duke specifikuar llojet. Kjo informon modelin se çfarë bëjnë funksionet dhe kur duhet të bëhen thirrje të funksioneve.

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();

Shtoni deklaratat e funksionit në një objekt Tool :

var tool = Tool.newBuilder()
    .addFunctionDeclarations(getWeather)
    .addFunctionDeclarations(getTime)
    .build();

Krijo backend-in e përfundimit

Krijo një backend për përfundime duke përdorur LLM Inference API dhe kaloji atij një objekt formatuesi për modelin tënd. Formatter FC SDK ( ModelFormatter ) vepron si formatues dhe analizues. Meqenëse ky fillim i shpejtë përdor Gemma-3 1B, ne do të përdorim GemmaFormatter :

var llmInferenceOptions = LlmInferenceOptions.builder()
    .setModelPath(modelFile.getAbsolutePath())
    .build();
var llmInference = LlmInference.createFromOptions(context, llmInferenceOptions);
var llmInferenceBackend = new llmInferenceBackend(llmInference, new GemmaFormatter());

Për më shumë informacion, shihni opsionet e konfigurimit të LLM Inference .

Ngritja e modelit

Përdorni objektin GenerativeModel për të lidhur backend-in e inferencës, promptin e sistemit dhe mjetet. Ne tashmë kemi backend-in e inferencës dhe mjetet, kështu që na duhet vetëm të krijojmë promptin e sistemit:

var systemInstruction = Content.newBuilder()
      .setRole("system")
      .addParts(Part.newBuilder().setText("You are a helpful assistant."))
      .build();

Instanconi modelin me GenerativeModel :

var generativeModel = new GenerativeModel(
    llmInferenceBackend,
    systemInstruction,
    List.of(tool),
)

Filloni një seancë bisede

Për thjeshtësi, ky udhëzues i shpejtë fillon një seancë të vetme bisede. Gjithashtu mund të krijoni seanca të shumëfishta, të pavarura.

Duke përdorur instancën e re të GenerativeModel , filloni një seancë bisede:

var chat = generativeModel.startChat();

Dërgo mesazhe te modeli përmes seancës së bisedës, duke përdorur metodën sendMessage :

var response = chat.sendMessage("How's the weather in San Francisco?");

Analizoni përgjigjen e modelit

Pasi i kalon një mesazh modelit, aplikacioni duhet të shqyrtojë përgjigjen për të përcaktuar nëse duhet të bëjë një thirrje funksioni apo të nxjerrë tekst në gjuhë natyrore.

// 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());
}

Kodi shembull është një implementim tepër i thjeshtuar. Për më shumë informacion se si një aplikacion mund të shqyrtojë përgjigjet e modelit, shihni Formatimi dhe Analiza .

Si funksionon

Ky seksion ofron informacion më të thelluar mbi konceptet dhe komponentët kryesorë të SDK-së së Thirrjes së Funksioneve për Android.

Modele

SDK-ja e Thirrjes së Funksionit kërkon një model me një formatues dhe një analizues. SDK-ja FC përmban një formatues dhe analizues të integruar për modelet e mëposhtme:

  • Gemma : përdor GemmaFormatter .
  • Llama : përdor LlamaFormatter .
  • Hammer : përdorni HammerFormatter .

Për të përdorur një model të ndryshëm me FC SDK, duhet të zhvilloni formatuesin dhe analizuesin tuaj që është i pajtueshëm me LLM Inference API.

Formatimi dhe analizimi

Një pjesë kyçe e mbështetjes për thirrjen e funksioneve është formatimi i kërkesave dhe analizimi i rezultateve të modelit. Ndërsa këto janë dy procese të ndara, FC SDK trajton si formatimin ashtu edhe analizimin me ndërfaqen ModelFormatter .

Formatuesi është përgjegjës për konvertimin e deklaratave të funksioneve të strukturuara në tekst, formatimin e përgjigjeve të funksioneve dhe futjen e tokenëve për të treguar fillimin dhe mbarimin e raundeve të bisedës, si dhe rolet e këtyre raundeve (p.sh. "përdorues", "model").

Analizuesi është përgjegjës për zbulimin nëse përgjigja e modelit përmban një thirrje funksioni. Nëse analizuesi zbulon një thirrje funksioni, ai e analizon atë në një lloj të dhënash të strukturuara. Përndryshe, ai e trajton tekstin si një përgjigje në gjuhën natyrore.

Dekodim i kufizuar

Dekodimi i kufizuar është një teknikë që udhëzon gjenerimin e rezultateve të LLM-ve për të siguruar që ato i përmbahen një formati të strukturuar të paracaktuar, siç janë objektet JSON ose thirrjet e funksioneve Python. Duke zbatuar këto kufizime, modeli formaton rezultatet e tij në një mënyrë që përputhet me funksionet e paracaktuara dhe llojet përkatëse të parametrave të tyre.

Për të aktivizuar dekodimin e kufizuar, përcaktoni kufizimet në një objekt ConstraintOptions dhe thirrni metodën enableConstraint të një instance ChatSession . Kur aktivizohet, ky kufizim do ta kufizojë përgjigjen që të përfshijë vetëm mjetet e shoqëruara me GenerativeModel .

Shembulli i mëposhtëm demonstron se si të konfigurohet dekodimi i kufizuar për të kufizuar përgjigjen ndaj thirrjeve të mjeteve. Ai e kufizon thirrjen e mjetit të fillojë me parashtesën ```tool_code\n dhe të mbarojë me prapashtesën \n``` .

ConstraintOptions constraintOptions = ConstraintOptions.newBuilder()
.setToolCallOnly( ConstraintOptions.ToolCallOnly.newBuilder()
.setConstraintPrefix("```tool_code\n")
  .setConstraintSuffix("\n```"))
.build(); chatSession.enableConstraint(constraintOptions);

Për të çaktivizuar kufizimin aktiv brenda të njëjtës seancë, përdorni metodën disableConstraint :

chatSession.disableConstraint();