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 menghasilkan teks, LLM yang menggunakan FC SDK dapat menghasilkan panggilan terstruktur ke fungsi yang menjalankan tindakan, seperti menelusuri informasi terbaru, menyetel alarm, atau membuat reservasi.

Panduan ini akan memandu Anda melalui panduan 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 informasi selengkapnya tentang penggunaan LLM Inference API, lihat panduan LLM Inference untuk 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 dengan 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 kuantisasi 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 mengilustrasikan prosesnya, panduan memulai ini menyertakan dua fungsi sebagai metode statis yang menampilkan respons hard code. Implementasi yang lebih praktis akan menentukan fungsi yang memanggil REST API atau mengambil informasi dari database.

Berikut adalah definisi 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 menjelaskan setiap fungsi, memberi nama dan deskripsi, serta menentukan jenisnya. Hal ini memberi tahu model tentang fungsi yang dilakukan dan waktu untuk 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 formator untuk model Anda. FC SDK Formatter (ModelFormatter) berfungsi sebagai formator 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.

Membuat instance model

Gunakan objek GenerativeModel untuk menghubungkan backend inferensi, perintah sistem, dan alat. Kita sudah memiliki backend dan alat inferensi, sehingga 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 memudahkan, panduan memulai ini memulai satu sesi chat. Anda juga dapat membuat beberapa sesi independen.

Dengan menggunakan instance GenerativeModel baru, mulai sesi chat:

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 menampilkan 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 informasi selengkapnya tentang cara aplikasi memeriksa respons model, lihat Pemformatan dan Pemrosesan.

Cara kerjanya

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

Model

SDK Panggilan Fungsi memerlukan model dengan pemformat dan parser. FC SDK berisi pemformat dan parser bawaan untuk model berikut:

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

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

Pemformatan dan penguraian

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.

Formator 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 mengurainya menjadi jenis data terstruktur. Jika tidak, sistem akan memperlakukan teks sebagai respons bahasa alam.

Decoding terbatas

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

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

Contoh berikut menunjukkan cara mengonfigurasi decoding terbatas untuk membatasi respons terhadap panggilan alat. Ini membatasi panggilan alat untuk 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();