Android 適用的 AI Edge 函式呼叫指南

AI Edge 函式呼叫 SDK (FC SDK) 是一項程式庫,可讓開發人員搭配使用函式呼叫與裝置端大型語言模型。函式呼叫功能可將模型連結至外部工具和 API,讓模型呼叫特定函式,並使用必要參數執行現實世界的動作。

使用 FC SDK 的 LLM 不僅能生成文字,還能生成函式的結構化呼叫,執行搜尋最新資訊、設定鬧鐘或預訂等動作。

本指南將逐步說明如何透過 FC SDK,將 LLM Inference API 新增至 Android 應用程式。本指南的重點在於為裝置端 LLM 新增函式呼叫功能。如要進一步瞭解如何使用 LLM 推論 API,請參閱 Android 適用的 LLM 推論指南

快速入門導覽課程

請按照下列步驟,在 Android 應用程式中使用 FC SDK。本快速入門導覽課程會搭配 Hammer 2.1 (15 億個參數) 使用 LLM 推論 API。LLM 推論 API 專為高階 Android 裝置 (例如 Pixel 8 和 Samsung S23 以上機型) 最佳化,無法穩定支援裝置模擬器。

新增依附元件

FC SDK 使用 com.google.ai.edge.localagents:localagents-fc 程式庫,而 LLM 推論 API 則使用 com.google.mediapipe:tasks-genai 程式庫。將這兩個依附元件新增至 Android 應用程式的 build.gradle 檔案:

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

如果是搭載 Android 12 (API 31) 以上版本的裝置,請新增原生 OpenCL 程式庫依附元件。詳情請參閱 uses-native-library 標記的說明文件。

將下列 uses-native-library 標記新增至 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"/>

下載模型

Hugging Face 下載 8 位元量化格式的 Hammer 1B。如要進一步瞭解可用模型,請參閱模型說明文件

hammer2.1_1.5b_q8_ekv4096.task 資料夾的內容推送到 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

宣告函式定義

定義模型可用的函式。為說明這個程序,本快速入門導覽課程包含兩個函式,做為傳回硬式編碼回應的靜態方法。更實用的做法是定義函式,呼叫 REST API 或從資料庫擷取資訊。

以下定義 getWeathergetTime 函式:

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() {}
}

使用 FunctionDeclaration 說明每個函式,為每個函式提供名稱和說明,並指定類型。這會告知模型函式的功能,以及何時要呼叫函式。

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

將函式宣告新增至 Tool 物件:

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

建立推論後端

使用 LLM Inference API 建立推論後端,並將模型適用的格式化工具物件傳遞給後端。FC SDK Formatter (ModelFormatter) 可做為格式器和剖析器。由於本快速入門導覽課程使用 Gemma-3 1B,我們會使用 GemmaFormatter

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

詳情請參閱 LLM 推論設定選項

將模型例項化

使用 GenerativeModel 物件連結推論後端、系統提示和工具。我們已有推論後端和工具,因此只需要建立系統提示:

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

使用 GenerativeModel 例項化模型:

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

發起即時通訊工作階段

為簡化起見,本快速入門導覽課程會啟動單一即時通訊工作階段。您也可以建立多個獨立的工作階段。

使用新版 GenerativeModel 啟動對話工作階段:

var chat = generativeModel.startChat();

使用 sendMessage 方法,透過對話工作階段向模型傳送提示:

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

剖析模型回覆

將提示傳遞至模型後,應用程式必須檢查回覆,判斷是否要呼叫函式或輸出自然語言文字。

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

範例程式碼是過度簡化的實作方式。如要進一步瞭解應用程式如何檢查模型回應,請參閱「格式設定和剖析」。

運作方式

本節將深入說明 Android 適用的函式呼叫 SDK 的核心概念和元件。

模型

函式呼叫 SDK 需要具備格式化工具和剖析器的模型。FC SDK 內建下列模型的格式器和剖析器:

  • Gemma:使用 GemmaFormatter
  • Llama:使用 LlamaFormatter
  • 鐵鎚:使用 HammerFormatter

如要在 FC SDK 中使用其他模型,您必須開發與 LLM Inference API 相容的格式器和剖析器。

格式化和剖析

函式呼叫支援功能的重要部分,就是提示的格式設定和模型輸出內容的剖析。雖然這是兩個獨立的程序,但 FC SDK 會透過 ModelFormatter 介面處理格式設定和剖析作業。

格式化工具負責將結構化函式宣告轉換為文字、格式化函式回應,以及插入權杖來標示對話輪流的開始和結束,以及這些輪流的角色 (例如「使用者」、「模型」)。

剖析器負責偵測模型回覆是否包含函式呼叫。如果剖析器偵測到函式呼叫,就會剖析成結構化資料類型。否則會將文字視為自然語言回應。

受限解碼

受限解碼是一種技術,可引導大型語言模型產生輸出內容,確保輸出內容符合預先定義的結構化格式,例如 JSON 物件或 Python 函式呼叫。強制執行這些限制後,模型會以符合預先定義函式及其對應參數類型的方式,格式化輸出內容。

如要啟用受限解碼,請在 ConstraintOptions 物件中定義限制,並叫用 ChatSession 例項的 enableConstraint 方法。啟用這項限制後,回覆內容只會包含與 GenerativeModel 相關聯的工具。

以下範例示範如何設定受限解碼,將回應限制為工具呼叫。這會將工具呼叫限制為以前置字元 ```tool_code\n 開頭,並以後置字元 \n``` 結尾。

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

如要在同一工作階段中停用有效限制,請使用 disableConstraint 方法:

chatSession.disableConstraint();