راهنمای فراخوانی عملکرد AI Edge برای اندروید

کیت توسعه نرم‌افزاری فراخوانی تابع لبه هوش مصنوعی (FC SDK) کتابخانه‌ای است که توسعه‌دهندگان را قادر می‌سازد تا از فراخوانی تابع با LLMهای روی دستگاه استفاده کنند. فراخوانی تابع به شما امکان می‌دهد مدل‌ها را به ابزارها و APIهای خارجی متصل کنید و مدل‌ها را قادر می‌سازد تا توابع خاصی را با پارامترهای لازم برای اجرای اقدامات دنیای واقعی فراخوانی کنند.

یک LLM با استفاده از FC SDK می‌تواند به جای تولید متن، یک فراخوانی ساختاریافته برای تابعی ایجاد کند که عملی مانند جستجوی اطلاعات به‌روز، تنظیم هشدار یا رزرو را اجرا می‌کند.

این راهنما شما را با یک شروع سریع و ساده برای افزودن API استنتاج LLM به همراه FC SDK به یک برنامه اندروید آشنا می‌کند. این راهنما بر افزودن قابلیت‌های فراخوانی تابع به یک LLM روی دستگاه تمرکز دارد. برای اطلاعات بیشتر در مورد استفاده از API استنتاج LLM، به راهنمای استنتاج LLM برای اندروید مراجعه کنید.

شروع سریع

برای استفاده از FC SDK در برنامه اندروید خود، مراحل زیر را دنبال کنید. این راهنمای سریع از LLM Inference API با Hammer 2.1 (1.5B) استفاده می‌کند. LLM Inference API برای دستگاه‌های اندروید رده بالا مانند Pixel 8 و Samsung S23 یا بالاتر بهینه شده است و به طور قابل اعتمادی از شبیه‌سازهای دستگاه پشتیبانی نمی‌کند.

وابستگی‌ها را اضافه کنید

کیت توسعه نرم‌افزار FC از کتابخانه com.google.ai.edge.localagents:localagents-fc و API استنتاج LLM از کتابخانه com.google.mediapipe:tasks-genai استفاده می‌کند. هر دو وابستگی را به فایل build.gradle برنامه اندروید خود اضافه کنید:

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

برای دستگاه‌هایی با اندروید ۱۲ (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"/>

دانلود یک مدل

Hammer 1B را با فرمت کوانتیزه ۸ بیتی از Hugging Face دانلود کنید. برای اطلاعات بیشتر در مورد مدل‌های موجود، به مستندات Models مراجعه کنید.

محتوای پوشه hammer2.1_1.5b_q8_ekv4096.task را به دستگاه اندروید منتقل کنید.

$ 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 را فراخوانی می‌کنند یا اطلاعات را از یک پایگاه داده بازیابی می‌کنند.

در ادامه توابع getWeather و 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() {}
}

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 یک inference backend ایجاد کنید و یک شیء formatter برای مدل خود به آن منتقل کنید. FC SDK Formatter ( ModelFormatter ) هم به عنوان formatter و هم به عنوان parser عمل می‌کند. از آنجایی که این راهنمای سریع از 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 Inference مراجعه کنید.

نمونه‌سازی مدل

از شیء 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());
}

کد نمونه، یک پیاده‌سازی بیش از حد ساده‌شده است. برای اطلاعات بیشتر در مورد اینکه چگونه یک برنامه می‌تواند پاسخ‌های مدل را بررسی کند، به بخش قالب‌بندی و تجزیه مراجعه کنید.

چگونه کار می‌کند؟

این بخش اطلاعات عمیق‌تری در مورد مفاهیم اصلی و اجزای SDK فراخوانی تابع برای اندروید ارائه می‌دهد.

مدل‌ها

SDK فراخوانی تابع به مدلی با قالب‌بندی و تجزیه‌گر نیاز دارد. SDK FC شامل قالب‌بندی و تجزیه‌گر داخلی برای مدل‌های زیر است:

  • Gemma : از GemmaFormatter استفاده کنید.
  • لاما : از LlamaFormatter استفاده کنید.
  • Hammer : از HammerFormatter استفاده کنید.

برای استفاده از یک مدل متفاوت با FC SDK، باید قالب‌بند و تجزیه‌کننده‌ی خودتان را توسعه دهید که با LLM Inference API سازگار باشد.

قالب‌بندی و تجزیه

بخش کلیدی پشتیبانی از فراخوانی تابع، قالب‌بندی اعلان‌ها و تجزیه خروجی مدل است. در حالی که این دو فرآیند جداگانه هستند، FC SDK هم قالب‌بندی و هم تجزیه را با رابط ModelFormatter مدیریت می‌کند.

قالب‌دهنده مسئول تبدیل اعلان‌های تابع ساختاریافته به متن، قالب‌بندی پاسخ‌های تابع و درج توکن‌ها برای نشان دادن شروع و پایان نوبت‌های مکالمه و همچنین نقش‌های آن نوبت‌ها (مثلاً "کاربر"، "مدل") است.

تجزیه‌گر مسئول تشخیص این است که آیا پاسخ مدل شامل فراخوانی تابع است یا خیر. اگر تجزیه‌گر فراخوانی تابع را تشخیص دهد، آن را به یک نوع داده ساختاریافته تجزیه می‌کند. در غیر این صورت، متن را به عنوان یک پاسخ زبان طبیعی در نظر می‌گیرد.

رمزگشایی محدود

رمزگشایی مقید، تکنیکی است که تولید خروجی LLMها را هدایت می‌کند تا از پایبندی آن به یک قالب ساختاریافته از پیش تعریف‌شده، مانند اشیاء JSON یا فراخوانی‌های تابع پایتون، اطمینان حاصل شود. با اعمال این محدودیت‌ها، مدل خروجی‌های خود را به گونه‌ای قالب‌بندی می‌کند که با توابع از پیش تعریف‌شده و انواع پارامترهای مربوطه آنها همسو باشد.

برای فعال کردن رمزگشایی مقید، قیدها را در یک شیء ConstraintOptions تعریف کنید و متد enableConstraint از یک نمونه ChatSession را فراخوانی کنید. وقتی این قید فعال شود، پاسخ را محدود می‌کند تا فقط شامل ابزارهای مرتبط با 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();