Panduan Panggilan Fungsi AI Edge untuk Android

AI Edge Function Calling SDK (FC SDK) adalah library yang memungkinkan developer menggunakan panggilan fungsi dengan LLM di perangkat. Panggilan fungsi memungkinkan Anda menghubungkan model ke alat dan API eksternal, sehingga model dapat memanggil fungsi tertentu dengan parameter yang diperlukan untuk menjalankan tindakan dunia nyata.

Daripada hanya membuat teks, LLM yang menggunakan FC SDK dapat membuat panggilan terstruktur ke fungsi yang menjalankan tindakan, seperti menelusuri informasi terbaru, menyetel alarm, atau membuat reservasi.

Panduan ini akan memandu Anda melalui langkah-langkah memulai dasar untuk menambahkan LLM Inference API dengan FC SDK ke aplikasi Android. Panduan ini berfokus pada penambahan kemampuan panggilan fungsi ke LLM di perangkat. Untuk mengetahui informasi selengkapnya tentang penggunaan LLM Inference API, lihat panduan LLM Inference for Android.

Panduan memulai

Gunakan langkah-langkah berikut untuk menggunakan FC SDK di aplikasi Android Anda. Panduan memulai ini menggunakan LLM Inference API dengan Hammer 2.1 (1,5 Miliar). LLM Inference API dioptimalkan untuk perangkat Android kelas atas, seperti Pixel 8 dan Samsung S23 atau yang lebih baru, dan tidak mendukung emulator perangkat secara andal.

Menambahkan dependensi

FC SDK menggunakan library com.google.ai.edge.localagents:localagents-fc dan LLM Inference API menggunakan library com.google.mediapipe:tasks-genai. Tambahkan kedua dependensi ke file build.gradle aplikasi Android Anda:

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

Untuk perangkat dengan Android 12 (API 31) atau yang lebih tinggi, tambahkan dependensi library OpenCL native. Untuk mengetahui informasi selengkapnya, lihat dokumentasi tentang tag uses-native-library.

Tambahkan tag uses-native-library berikut ke 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"/>

Mendownload model

Download Hammer 1B dalam format terkuantisasi 8-bit dari Hugging Face. Untuk mengetahui informasi selengkapnya tentang model yang tersedia, lihat dokumentasi Model.

Kirim konten folder hammer2.1_1.5b_q8_ekv4096.task ke perangkat 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

Mendeklarasikan definisi fungsi

Tentukan fungsi yang akan tersedia untuk model. Untuk menggambarkan prosesnya, panduan memulai ini menyertakan dua fungsi sebagai metode statis yang menampilkan respons hard-coded. Implementasi yang lebih praktis akan menentukan fungsi yang memanggil REST API atau mengambil informasi dari database.

Berikut ini menentukan fungsi getWeather dan 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() {}
}

Gunakan FunctionDeclaration untuk mendeskripsikan setiap fungsi, dengan memberikan nama dan deskripsi untuk setiap fungsi, serta menentukan jenisnya. Hal ini memberi tahu model tentang fungsi yang tersedia dan kapan harus melakukan panggilan fungsi.

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

Tambahkan deklarasi fungsi ke objek Tool:

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

Membuat backend inferensi

Buat backend inferensi menggunakan LLM Inference API dan teruskan objek formatter untuk model Anda. FC SDK Formatter (ModelFormatter) berfungsi sebagai formatter dan parser. Karena panduan memulai ini menggunakan Gemma-3 1B, kita akan menggunakan GemmaFormatter:

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

Untuk mengetahui informasi selengkapnya, lihat opsi konfigurasi Inferensi LLM.

Buat instance model

Gunakan objek GenerativeModel untuk menghubungkan backend inferensi, perintah sistem, dan alat. Kita sudah memiliki backend dan alat inferensi, jadi kita hanya perlu membuat perintah sistem:

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

Buat instance model dengan GenerativeModel:

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

Memulai sesi chat

Untuk mempermudah, panduan memulai cepat ini memulai satu sesi chat. Anda juga dapat membuat beberapa sesi independen.

Dengan menggunakan instance GenerativeModel yang baru, mulai sesi percakapan:

var chat = generativeModel.startChat();

Kirim perintah ke model melalui sesi chat, menggunakan metode sendMessage:

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

Mengurai respons model

Setelah meneruskan perintah ke model, aplikasi harus memeriksa respons untuk menentukan apakah akan melakukan panggilan fungsi atau menghasilkan teks bahasa alami.

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

Kode contoh adalah implementasi yang terlalu disederhanakan. Untuk mengetahui informasi selengkapnya tentang cara aplikasi dapat memeriksa respons model, lihat Pemformatan dan Penguraian.

Cara kerjanya

Bagian ini memberikan informasi yang lebih mendalam tentang konsep dan komponen inti Function Calling SDK for Android.

Model

Function Calling SDK memerlukan model dengan pemformat dan parser. FC SDK berisi pemformat dan parser bawaan untuk model berikut:

  • Gemma: gunakan GemmaFormatter.
  • Llama: gunakan LlamaFormatter.
  • Hammer: gunakan HammerFormatter.

Untuk menggunakan model yang berbeda dengan FC SDK, Anda harus mengembangkan formatter dan parser sendiri yang kompatibel dengan LLM Inference API.

Memformat dan mengurai

Bagian penting dari dukungan panggilan fungsi adalah pemformatan perintah dan penguraian output model. Meskipun ini adalah dua proses terpisah, FC SDK menangani pemformatan dan penguraian dengan antarmuka ModelFormatter.

Formatter bertanggung jawab untuk mengonversi deklarasi fungsi terstruktur menjadi teks, memformat respons fungsi, dan menyisipkan token untuk menunjukkan awal dan akhir giliran percakapan, serta peran giliran tersebut (misalnya, "pengguna", "model").

Parser bertanggung jawab untuk mendeteksi apakah respons model berisi panggilan fungsi. Jika mendeteksi panggilan fungsi, parser akan menguraikannya menjadi jenis data terstruktur. Jika tidak, teks akan diperlakukan sebagai respons bahasa alami.

Decoding terbatas

Dekode terbatas adalah teknik yang memandu pembuatan output LLM untuk memastikan output tersebut mematuhi format terstruktur yang telah ditentukan sebelumnya, seperti objek JSON atau panggilan fungsi Python. Dengan menerapkan batasan ini, model memformat outputnya dengan cara yang selaras dengan fungsi yang telah ditentukan sebelumnya dan jenis parameter yang sesuai.

Untuk mengaktifkan decoding yang dibatasi, tentukan batasan dalam objek ConstraintOptions dan panggil metode enableConstraint dari instance ChatSession. Jika diaktifkan, batasan ini akan membatasi respons untuk hanya menyertakan alat yang terkait dengan GenerativeModel.

Contoh berikut menunjukkan cara mengonfigurasi decoding terbatas untuk membatasi respons pada panggilan alat. Fungsi ini membatasi panggilan alat agar dimulai dengan awalan ```tool_code\n dan diakhiri dengan akhiran \n```.

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

Untuk menonaktifkan batasan aktif dalam sesi yang sama, gunakan metode disableConstraint:

chatSession.disableConstraint();