অ্যান্ড্রয়েডে LiterRT-LM দিয়ে শুরু করুন

অ্যান্ড্রয়েড এবং জেভিএম (লিনাক্স, ম্যাকওএস, উইন্ডোজ) -এর জন্য LiteRT-LM-এর কোটলিন এপিআই, জিপিইউ ও এনপিইউ অ্যাক্সিলারেশন , মাল্টি-মোডালিটির মতো বৈশিষ্ট্যসহ বিভিন্ন টুল ব্যবহার করে

ভূমিকা

এখানে কোটলিন এপিআই দিয়ে তৈরি একটি নমুনা টার্মিনাল চ্যাট অ্যাপ দেওয়া হলো:

import com.google.ai.edge.litertlm.*

suspend fun main() {
  Engine.setNativeMinLogSeverity(LogSeverity.ERROR) // Hide log for TUI app

  val engineConfig = EngineConfig(modelPath = "/path/to/model.litertlm")
  Engine(engineConfig).use { engine ->
    engine.initialize()

    engine.createConversation().use { conversation ->
      while (true) {
        print("\n>>> ")
        conversation.sendMessageAsync(readln()).collect { print(it) }
      }
    }
  }
}

কোটলিন নমুনা কোডের ডেমো

উপরের নমুনাটি পরীক্ষা করার জন্য, রিপোজিটরিটি ক্লোন করুন এবং example/Main.kt দিয়ে চালান:

bazel run -c opt //kotlin/java/com/google/ai/edge/litertlm/example:main -- <abs_model_path>

উপলব্ধ .litertlm মডেলগুলো HuggingFace LiteRT কমিউনিটিতে রয়েছে। উপরের অ্যানিমেশনটি Gemma3-1B-IT ব্যবহার করে তৈরি করা হয়েছিল।

অ্যান্ড্রয়েড নমুনার জন্য, Google AI Edge Gallery অ্যাপটি দেখুন ( Google Play-তে উপলব্ধ )।

গ্রেডল দিয়ে শুরু করা

যদিও LiteRT-LM বেজেল দিয়ে তৈরি করা হয়েছে, আমরা গ্রেডল বা মেভেন ব্যবহারকারীদের জন্য মেভেন প্যাকেজ সরবরাহ করি।

১. গ্রেডল নির্ভরতা যোগ করুন

dependencies {
    // For Android
    implementation("com.google.ai.edge.litertlm:litertlm-android:latest.release")

    // For JVM (Linux, macOS, Windows)
    implementation("com.google.ai.edge.litertlm:litertlm-jvm:latest.release")
}

আপনি Google Maven-এ litertlm-android এবং litertlm-jvm- এ উপলব্ধ সংস্করণগুলো খুঁজে পেতে পারেন।

সর্বশেষ রিলিজ পেতে latest.release ব্যবহার করা যেতে পারে।

২. ইঞ্জিন চালু করুন

Engine হলো এপিআই-এর প্রবেশদ্বার। মডেল পাথ এবং কনফিগারেশন দিয়ে এটি চালু করুন। রিসোর্স মুক্ত করতে ইঞ্জিনটি বন্ধ করতে মনে রাখবেন।

দ্রষ্টব্য: engine.initialize() মেথডটি মডেল লোড করতে উল্লেখযোগ্য পরিমাণ সময় (যেমন, ১০ সেকেন্ড পর্যন্ত) নিতে পারে। UI থ্রেডকে ব্লক হওয়া থেকে বাঁচাতে, এটিকে একটি ব্যাকগ্রাউন্ড থ্রেড বা কো-রুটিনে কল করার জন্য দৃঢ়ভাবে সুপারিশ করা হচ্ছে।

import com.google.ai.edge.litertlm.Backend
import com.google.ai.edge.litertlm.Engine
import com.google.ai.edge.litertlm.EngineConfig

val engineConfig = EngineConfig(
    modelPath = "/path/to/your/model.litertlm", // Replace with your model path
    backend = Backend.GPU(), // Or Backend.NPU(nativeLibraryDir = "...")
    // Optional: Pick a writable dir. This can improve 2nd load time.
    // cacheDir = "/tmp/" or context.cacheDir.path (for Android)
)

val engine = Engine(engineConfig)
engine.initialize()
// ... Use the engine to create a conversation ...

// Close the engine when done
engine.close()

অ্যান্ড্রয়েডে GPU ব্যাকএন্ড ব্যবহার করার জন্য, অ্যাপটিকে তার AndroidManifest.xml ফাইলের <application> ট্যাগের ভিতরে নিম্নলিখিত কোডটি যোগ করে নির্ভরশীল নেটিভ লাইব্রেরিগুলির জন্য স্পষ্টভাবে অনুরোধ করতে হবে:

  <application>
    <uses-native-library android:name="libvndksupport.so" android:required="false"/>
    <uses-native-library android:name="libOpenCL.so" android:required="false"/>
  </application>

NPU ব্যাকএন্ড ব্যবহার করার জন্য, আপনাকে NPU লাইব্রেরিগুলো ধারণকারী ডিরেক্টরিটি নির্দিষ্ট করে দিতে হতে পারে। অ্যান্ড্রয়েডে, যদি লাইব্রেরিগুলো আপনার অ্যাপের সাথে বান্ডল করা থাকে, তবে সেটিকে context.applicationInfo.nativeLibraryDir এ সেট করুন। NPU নেটিভ লাইব্রেরিগুলো সম্পর্কে আরও বিস্তারিত জানতে LiteRT-LM NPU দেখুন।

val engineConfig = EngineConfig(
    modelPath = modelPath,
    backend = Backend.NPU(nativeLibraryDir = context.applicationInfo.nativeLibraryDir)
)

৩. একটি কথোপকথন তৈরি করুন

ইঞ্জিনটি চালু হয়ে গেলে, একটি Conversation ইনস্ট্যান্স তৈরি করুন। এর আচরণ কাস্টমাইজ করার জন্য আপনি একটি ConversationConfig প্রদান করতে পারেন।

import com.google.ai.edge.litertlm.ConversationConfig
import com.google.ai.edge.litertlm.Message
import com.google.ai.edge.litertlm.SamplerConfig

// Optional: Configure the system instruction, initial messages, sampling
// parameters, etc.
val conversationConfig = ConversationConfig(
    systemInstruction = Contents.of("You are a helpful assistant."),
    initialMessages = listOf(
        Message.user("What is the capital city of the United States?"),
        Message.model("Washington, D.C."),
    ),
    samplerConfig = SamplerConfig(topK = 10, topP = 0.95, temperature = 0.8),
)

val conversation = engine.createConversation(conversationConfig)
// Or with default config:
// val conversation = engine.createConversation()

// ... Use the conversation ...

// Close the conversation when done
conversation.close()

Conversation AutoCloseable ইমপ্লিমেন্ট করা আছে, তাই আপনি এককালীন বা স্বল্পস্থায়ী কথোপকথনের জন্য স্বয়ংক্রিয় রিসোর্স ব্যবস্থাপনার উদ্দেশ্যে use ব্লকটি ব্যবহার করতে পারেন:

engine.createConversation(conversationConfig).use { conversation ->
    // Interact with the conversation
}

৪. বার্তা পাঠানো

বার্তা পাঠানোর তিনটি উপায় আছে:

  • sendMessage(contents): Message : একটি সিনক্রোনাস কল যা মডেল থেকে একটি সম্পূর্ণ প্রতিক্রিয়া না পাওয়া পর্যন্ত ব্লক করে রাখে। সাধারণ অনুরোধ এবং প্রতিক্রিয়ার আদান-প্রদানের জন্য এটি সহজতর।
  • sendMessageAsync(contents, callback) : রেসপন্স স্ট্রিমিং করার জন্য অ্যাসিঙ্ক্রোনাস কল। দীর্ঘ সময় ধরে চলা রিকোয়েস্টের জন্য অথবা রেসপন্সটি তৈরি হওয়ার সাথে সাথেই প্রদর্শন করতে চাইলে এটি বেশি উপযোগী।
  • sendMessageAsync(contents): Flow<Message> : একটি অ্যাসিঙ্ক্রোনাস কল যা রেসপন্স স্ট্রিমিং করার জন্য একটি কোটলিন ফ্লো (Kotlin Flow) রিটার্ন করে। কোরাউটিন (Coroutine) ব্যবহারকারীদের জন্য এটিই প্রস্তাবিত পদ্ধতি।

সিঙ্ক্রোনাস উদাহরণ:

import com.google.ai.edge.litertlm.Content
import com.google.ai.edge.litertlm.Message

print(conversation.sendMessage("What is the capital of France?"))

কলব্যাক সহ অ্যাসিঙ্ক্রোনাস উদাহরণ:

মডেলে বার্তা পাঠাতে এবং কলব্যাকের মাধ্যমে প্রতিক্রিয়া গ্রহণ করতে sendMessageAsync ব্যবহার করুন।

import com.google.ai.edge.litertlm.Content
import com.google.ai.edge.litertlm.Message
import com.google.ai.edge.litertlm.MessageCallback
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

val callback = object : MessageCallback {
    override fun onMessage(message: Message) {
        print(message)
    }

    override fun onDone() {
        // Streaming completed
    }

    override fun onError(throwable: Throwable) {
        // Error during streaming
    }
}

conversation.sendMessageAsync("What is the capital of France?", callback)

ফ্লো সহ অ্যাসিঙ্ক্রোনাস উদাহরণ:

মডেলে মেসেজ পাঠাতে এবং কোটলিন ফ্লো-এর মাধ্যমে রেসপন্স গ্রহণ করতে sendMessageAsync (callback আর্গুমেন্ট ছাড়া) ব্যবহার করুন।

import com.google.ai.edge.litertlm.Content
import com.google.ai.edge.litertlm.Message
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.launch

// Within a coroutine scope
conversation.sendMessageAsync("What is the capital of France?")
    .catch { ... } // Error during streaming
    .collect { print(it.toString()) }

৫. বহু-পদ্ধতি

Message অবজেক্টে বিভিন্ন ধরনের Content থাকতে পারে, যার মধ্যে রয়েছে Text , ImageBytes , ImageFile , এবং AudioBytesAudioFile

// Initialize the `visionBackend`, `audioBackend`, or both
val engineConfig = EngineConfig(
    modelPath = "/path/to/your/model.litertlm", // Replace with your model path
    backend = Backend.CPU(), // Or Backend.GPU() or Backend.NPU(...)
    visionBackend = Backend.GPU(), // Or Backend.NPU(...)
    audioBackend = Backend.CPU(), // Or Backend.NPU(...)
)

// Sends a message with multi-modality.
// See the Content class for other variants.
conversation.sendMessage(Contents.of(
    Content.ImageFile("/path/to/image"),
    Content.AudioBytes(audioBytes), // ByteArray of the audio
    Content.Text("Describe this image and audio."),
))

৬. সরঞ্জামের সংজ্ঞা ও ব্যবহার

সরঞ্জাম সংজ্ঞায়িত করার দুটি উপায় আছে:

  1. কোটলিন ফাংশন ব্যবহার করে (বেশিরভাগ ক্ষেত্রে এটিই সুপারিশ করা হয়)
  2. ওপেন এপিআই স্পেসিফিকেশনের মাধ্যমে (টুল স্পেক এবং এক্সিকিউশনের উপর সম্পূর্ণ নিয়ন্ত্রণ)

কোটলিন ফাংশন দিয়ে টুলস সংজ্ঞায়িত করা

আপনি কাস্টম কোটলিন ফাংশনগুলোকে টুল হিসেবে সংজ্ঞায়িত করতে পারেন, যেগুলোকে মডেল বিভিন্ন কাজ সম্পাদন করতে বা তথ্য সংগ্রহ করতে কল করতে পারে।

ToolSet ইমপ্লিমেন্ট করে একটি ক্লাস তৈরি করুন এবং এর মেথডগুলোকে @Tool ও প্যারামিটারগুলোকে @ToolParam দিয়ে অ্যানোটেট করুন।

import com.google.ai.edge.litertlm.Tool
import com.google.ai.edge.litertlm.ToolParam

class SampleToolSet: ToolSet {
    @Tool(description = "Get the current weather for a city")
    fun getCurrentWeather(
        @ToolParam(description = "The city name, e.g., San Francisco") city: String,
        @ToolParam(description = "Optional country code, e.g., US") country: String? = null,
        @ToolParam(description = "Temperature unit (celsius or fahrenheit). Default: celsius") unit: String = "celsius"
    ): Map<String, Any> {
        // In a real application, you would call a weather API here
        return mapOf("temperature" to 25, "unit" to  unit, "condition" to "Sunny")
    }

    @Tool(description = "Get the sum of a list of numbers.")
    fun sum(
        @ToolParam(description = "The numbers, could be floating point.") numbers: List<Double>,
    ): Double {
        return numbers.sum()
    }
}

নেপথ্যে, এপিআই এই অ্যানোটেশনগুলো এবং ফাংশন সিগনেচার পরীক্ষা করে একটি ওপেনএপিআই-ধাঁচের স্কিমা তৈরি করে। এই স্কিমাটি ল্যাঙ্গুয়েজ মডেলকে টুলটির কার্যকারিতা, প্যারামিটার (যার মধ্যে @ToolParam থেকে প্রাপ্ত তাদের টাইপ ও বিবরণ অন্তর্ভুক্ত) এবং রিটার্ন টাইপ বর্ণনা করে।

প্যারামিটারের প্রকারভেদ

@ToolParam দিয়ে চিহ্নিত প্যারামিটারগুলোর টাইপ হতে পারে String , Int , Boolean , Float , Double , অথবা এই টাইপগুলোর একটি List (যেমন, List<String> )। নালযোগ্য প্যারামিটার বোঝাতে নালযোগ্য টাইপ (যেমন, String? ) ব্যবহার করুন। প্যারামিটারটি ঐচ্ছিক বোঝাতে একটি ডিফল্ট মান সেট করুন এবং @ToolParam এর বিবরণে সেই ডিফল্ট মানটি উল্লেখ করুন।

রিটার্ন টাইপ

আপনার টুল ফাংশনের রিটার্ন টাইপ যেকোনো কোটলিন টাইপ হতে পারে। ফলাফলটি মডেলে ফেরত পাঠানোর আগে একটি JSON এলিমেন্টে রূপান্তরিত হবে।

  • List টাইপগুলোকে JSON অ্যারেতে রূপান্তর করা হয়।
  • Map টাইপগুলোকে JSON অবজেক্টে রূপান্তর করা হয়।
  • প্রিমিটিভ টাইপগুলো ( String , Number , Boolean ) সংশ্লিষ্ট JSON প্রিমিটিভে রূপান্তরিত হয়।
  • toString() মেথডের মাধ্যমে অন্যান্য টাইপের ডেটাকে স্ট্রিং-এ রূপান্তর করা হয়।

স্ট্রাকচার্ড ডেটার জন্য, Map অথবা এমন একটি ডেটা ক্লাস রিটার্ন করার পরামর্শ দেওয়া হয় যা JSON অবজেক্টে রূপান্তরিত হবে।

ওপেনএপিআই স্পেসিফিকেশনের মাধ্যমে টুলস সংজ্ঞায়িত করা

বিকল্পভাবে, আপনি OpenApiTool ক্লাসটি ইমপ্লিমেন্ট করে এবং ওপেন এপিআই স্পেসিফিকেশন অনুযায়ী একটি JSON স্ট্রিং হিসেবে টুলটির বিবরণ প্রদান করে একটি টুল সংজ্ঞায়িত করতে পারেন। এই পদ্ধতিটি তখন উপযোগী যখন আপনার টুলের জন্য আগে থেকেই একটি ওপেনএপিআই স্কিমা থাকে অথবা টুলের সংজ্ঞার উপর আপনার সূক্ষ্ম নিয়ন্ত্রণের প্রয়োজন হয়।

import com.google.ai.edge.litertlm.OpenApiTool

class SampleOpenApiTool : OpenApiTool {

    override fun getToolDescriptionJsonString(): String {
        return """
        {
          "name": "addition",
          "description": "Add all numbers.",
          "parameters": {
            "type": "object",
            "properties": {
              "numbers": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "description": "The list of numbers to sum."
            },
            "required": [
              "numbers"
            ]
          }
        }
        """.trimIndent() // Tip: trim to save tokens
    }

    override fun execute(paramsJsonString: String): String {
        // Parse paramsJsonString with your choice of parser or deserializer and
        // execute the tool.

        // Return the result as a JSON string
        return """{"result": 1.4142}"""
    }
}

নিবন্ধন সরঞ্জাম

আপনার টুলগুলির ইনস্ট্যান্সগুলিকে ConversationConfig এ অন্তর্ভুক্ত করুন।

val conversation = engine.createConversation(
    ConversationConfig(
        tools = listOf(
            tool(SampleToolSet()),
            tool(SampleOpenApiTool()),
        ),
        // ... other configs
    )
)

// Send messages that might trigger the tool
conversation.sendMessageAsync("What's the weather like in London?", callback)

মডেলটি কথোপকথনের উপর ভিত্তি করে টুলটিকে কখন কল করতে হবে তা সিদ্ধান্ত নেবে। টুলটি সম্পাদনের ফলাফল চূড়ান্ত প্রতিক্রিয়া তৈরি করার জন্য স্বয়ংক্রিয়ভাবে মডেলে ফেরত পাঠানো হয়।

ম্যানুয়াল টুল কলিং

ডিফল্টরূপে, মডেল দ্বারা তৈরি টুল কলগুলো LiteRT-LM দ্বারা স্বয়ংক্রিয়ভাবে সম্পাদিত হয় এবং টুল সম্পাদনের ফলাফল পরবর্তী প্রতিক্রিয়া তৈরি করার জন্য স্বয়ংক্রিয়ভাবে মডেলে ফেরত পাঠানো হয়।

যদি আপনি ম্যানুয়ালি টুলগুলো চালাতে এবং ফলাফল মডেলে ফেরত পাঠাতে চান, তাহলে ConversationConfigautomaticToolCalling কে false সেট করতে পারেন।

val conversation = engine.createConversation(
    ConversationConfig(
        tools = listOf(
            tool(SampleOpenApiTool()),
        ),
        automaticToolCalling = false,
    )
)

আপনি যদি স্বয়ংক্রিয় টুল কলিং নিষ্ক্রিয় করেন, তাহলে আপনার অ্যাপ্লিকেশন কোডে আপনাকে ম্যানুয়ালি টুলগুলো চালাতে হবে এবং ফলাফল মডেলে ফেরত পাঠাতে হবে। যখন automaticToolCalling এর মান false সেট করা থাকবে, তখন OpenApiTool এর execute মেথডটি স্বয়ংক্রিয়ভাবে কল হবে না

// Send a message that triggers a tool call.
val responseMessage = conversation.sendMessage("What's the weather like in London?")

// The model returns a Message with `toolCalls` populated.
if (responseMessage.toolCalls.isNotEmpty()) {
    val toolResponses = mutableListOf<Content.ToolResponse>()
    // There can be multiple tool calls in a single response.
    for (toolCall in responseMessage.toolCalls) {
        println("Model wants to call: ${toolCall.name} with arguments: ${toolCall.arguments}")

        // Execute the tool manually with your own logic. `executeTool` is just an example here.
        val toolResponseJson = executeTool(toolCall.name, toolCall.arguments)

        // Collect tool responses.
        toolResponses.add(Content.ToolResponse(toolCall.name, toolResponseJson))
    }

    // Use Message.tool to create the tool response message.
    val toolResponseMessage = Message.tool(Contents.of(toolResponses))

    // Send the tool response message to the model.
    val finalMessage = conversation.sendMessage(toolResponseMessage)
    println("Final answer: ${finalMessage.text}") // e.g., "The weather in London is 25c."
}

উদাহরণ

টুলটির ব্যবহার পরখ করে দেখতে, রিপোটি ক্লোন করুন এবং example/ToolMain.kt দিয়ে চালান:

bazel run -c opt //kotlin/java/com/google/ai/edge/litertlm/example:tool -- <abs_model_path>

ত্রুটি পরিচালনা

এপিআই মেথডগুলো নেটিভ লেয়ারের ত্রুটির জন্য LiteRtLmJniException অথবা লাইফসাইকেল সংক্রান্ত সমস্যার জন্য IllegalStateException মতো স্ট্যান্ডার্ড কোটলিন এক্সেপশন থ্রো করতে পারে। এপিআই কলগুলোকে সবসময় try-catch ব্লকের মধ্যে রাখুন। অ্যাসিঙ্ক্রোনাস অপারেশনের সময় MessageCallback এর onError কলব্যাকটিও ত্রুটি রিপোর্ট করবে।