Android और JVM (Linux, MacOS, Windows) के लिए LiteRT-LM का Kotlin API. इसमें GPU और NPU ऐक्सलरेशन, मल्टी-मोडैलिटी, और टूल का इस्तेमाल जैसी सुविधाएं हैं.
परिचय
यहां Kotlin API की मदद से बनाया गया एक सैंपल टर्मिनल चैट ऐप्लिकेशन दिया गया है:
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) }
}
}
}
}

ऊपर दिए गए सैंपल को आज़माने के लिए, repo को क्लोन करें और example/Main.kt के साथ चलाएँ:
bazel run -c opt //kotlin/java/com/google/ai/edge/litertlm/example:main -- <abs_model_path>
उपलब्ध .litertlm मॉडल, HuggingFace LiteRT Community पर मौजूद हैं. ऊपर दिए गए ऐनिमेशन में, Gemma3-1B-IT का इस्तेमाल किया गया था.
Android के सैंपल के लिए, Google AI Edge Gallery ऐप्लिकेशन देखें.
Gradle का इस्तेमाल शुरू करना
LiteRT-LM को Bazel की मदद से डेवलप किया गया है. हालांकि, हम Gradle/Maven का इस्तेमाल करने वाले लोगों के लिए Maven पैकेज उपलब्ध कराते हैं.
1. Gradle डिपेंडेंसी जोड़ना
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 का इस्तेमाल करके, नई रिलीज़ को ऐक्सेस किया जा सकता है.
2. इंजन को शुरू करना
Engine, एपीआई का एंट्री पॉइंट है. इसे मॉडल पाथ और कॉन्फ़िगरेशन के साथ शुरू करें. संसाधन रिलीज़ करने के लिए, इंजन बंद करना न भूलें.
ध्यान दें: engine.initialize() तरीके से मॉडल को लोड होने में काफ़ी समय लग सकता है. उदाहरण के लिए, 10 सेकंड तक. हमारा सुझाव है कि यूज़र इंटरफ़ेस (यूआई) थ्रेड को ब्लॉक होने से बचाने के लिए, इस फ़ंक्शन को बैकग्राउंड थ्रेड या कोरूटीन पर कॉल करें.
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()
Android पर, जीपीयू बैकएंड का इस्तेमाल करने के लिए, ऐप्लिकेशन को डिपेंडेंट नेटिव लाइब्रेरी का अनुरोध साफ़ तौर पर करना होगा. इसके लिए, आपको <application> टैग में मौजूद AndroidManifest.xml में यह कोड जोड़ना होगा:
<application>
<uses-native-library android:name="libvndksupport.so" android:required="false"/>
<uses-native-library android:name="libOpenCL.so" android:required="false"/>
</application>
एनपीयू बैकएंड का इस्तेमाल करने के लिए, आपको एनपीयू लाइब्रेरी वाली डायरेक्ट्री के बारे में बताना पड़ सकता है. Android पर, अगर लाइब्रेरी आपके ऐप्लिकेशन के साथ बंडल की गई हैं, तो इसे context.applicationInfo.nativeLibraryDir पर सेट करें. एनपीयू की नेटिव लाइब्रेरी के बारे में ज़्यादा जानने के लिए, LiteRT-LM
NPU देखें.
val engineConfig = EngineConfig(
modelPath = modelPath,
backend = Backend.NPU(nativeLibraryDir = context.applicationInfo.nativeLibraryDir)
)
3. बातचीत शुरू करना
इंजन शुरू होने के बाद, 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 लागू करता है, इसलिए एक बार या कम समय के लिए होने वाली बातचीत के लिए, अपने-आप संसाधन मैनेज करने की सुविधा के लिए use ब्लॉक का इस्तेमाल किया जा सकता है:AutoCloseable
engine.createConversation(conversationConfig).use { conversation ->
// Interact with the conversation
}
4. मैसेज भेजना
मैसेज भेजने के तीन तरीके हैं:
sendMessage(contents): Message: सिंक्रोनस कॉल, जो तब तक ब्लॉक रहता है, जब तक मॉडल पूरा जवाब नहीं दे देता. यह बुनियादी अनुरोध/जवाब इंटरैक्शन के लिए ज़्यादा आसान है.sendMessageAsync(contents, callback): स्ट्रीमिंग के जवाबों के लिए एसिंक्रोनस कॉल. यह लंबे समय तक चलने वाले अनुरोधों के लिए बेहतर है. इसके अलावा, इसका इस्तेमाल तब भी किया जा सकता है, जब आपको जवाब जनरेट होने के दौरान ही उसे दिखाना हो.sendMessageAsync(contents): Flow<Message>: एसिंक्रोनस कॉल, जो स्ट्रीमिंग रिस्पॉन्स के लिए Kotlin फ़्लो दिखाता है. कोरूटीन का इस्तेमाल करने वाले लोगों के लिए, यह तरीका अपनाने का सुझाव दिया जाता है.
सिंक्रोनस का उदाहरण:
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)
फ़्लो के साथ एसिंक्रोनस का उदाहरण:
मॉडल को मैसेज भेजने और Kotlin Flow के ज़रिए जवाब पाने के लिए, sendMessageAsync (बिना कॉलबैक आर्ग के) का इस्तेमाल करें.
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()) }
5. मल्टी-मोडैलिटी
Message ऑब्जेक्ट में अलग-अलग तरह के Content शामिल हो सकते हैं. जैसे, Text, ImageBytes, ImageFile, AudioBytes, और AudioFile.
// Initialize the `visionBackend` and/or the `audioBackend`
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."),
))
6. टूल तय करना और उनका इस्तेमाल करना
टूल तय करने के दो तरीके हैं:
- Kotlin फ़ंक्शन का इस्तेमाल करके (ज़्यादातर मामलों में इसका सुझाव दिया जाता है)
- Open API स्पेसिफ़िकेशन के साथ (टूल स्पेसिफ़िकेशन और एक्ज़ीक्यूशन पर पूरा कंट्रोल)
Kotlin फ़ंक्शन की मदद से टूल तय करना
आपके पास Kotlin के कस्टम फ़ंक्शन को ऐसे टूल के तौर पर तय करने का विकल्प होता है जिन्हें मॉडल, कार्रवाइयां करने या जानकारी पाने के लिए कॉल कर सकता है.
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()
}
}
बैकग्राउंड में, एपीआई इन एनोटेशन और फ़ंक्शन सिग्नेचर की जांच करता है, ताकि OpenAPI स्टाइल वाला स्कीमा जनरेट किया जा सके. इस स्कीमा में, टूल की सुविधाओं, पैरामीटर (इसमें @ToolParam से लिए गए उनके टाइप और ब्यौरे शामिल हैं), और भाषा मॉडल को मिलने वाले रिटर्न टाइप के बारे में बताया गया है.
पैरामीटर के टाइप
@ToolParam से एनोटेट किए गए पैरामीटर के टाइप, String, Int, Boolean, Float, Double या इन टाइप का List हो सकते हैं. उदाहरण के लिए, List<String>).
नल हो सकने वाले टाइप का इस्तेमाल करें (जैसे, String?) का इस्तेमाल किया जाता है. डिफ़ॉल्ट वैल्यू सेट करें, ताकि यह पता चले कि पैरामीटर वैकल्पिक है. साथ ही, @ToolParam में मौजूद ब्यौरे में डिफ़ॉल्ट वैल्यू के बारे में बताएं.
रिटर्न टाइप
आपके टूल फ़ंक्शन का रिटर्न टाइप, कोई भी Kotlin टाइप हो सकता है. नतीजे को मॉडल को वापस भेजने से पहले, JSON एलिमेंट में बदल दिया जाएगा.
Listटाइप को JSON ऐरे में बदल दिया जाता है.Mapटाइप को JSON ऑब्जेक्ट में बदल दिया जाता है.- प्रिमिटिव टाइप (
String,Number,Boolean) को JSON प्रिमिटिव में बदल दिया जाता है. - अन्य टाइप को
toString()तरीके से स्ट्रिंग में बदला जाता है.
स्ट्रक्चर्ड डेटा के लिए, Map या किसी ऐसी डेटा क्लास को वापस लाने का सुझाव दिया जाता है जिसे JSON ऑब्जेक्ट में बदला जाएगा.
OpenAPI स्पेसिफ़िकेशन की मदद से टूल तय करना
इसके अलावा, OpenApiTool क्लास को लागू करके टूल को तय किया जा सकता है. साथ ही, टूल की जानकारी को JSON स्ट्रिंग के तौर पर दिया जा सकता है. यह स्ट्रिंग, Open API स्पेसिफ़िकेशन के मुताबिक होनी चाहिए. यह तरीका तब मददगार होता है, जब आपके पास अपने टूल के लिए पहले से ही OpenAPI स्कीमा हो या आपको टूल की परिभाषा पर ज़्यादा कंट्रोल चाहिए हो.
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/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 अपने-आप लागू करता है. साथ ही, टूल के इस्तेमाल से मिले नतीजे, मॉडल को अपने-आप वापस भेज दिए जाते हैं, ताकि वह अगला जवाब जनरेट कर सके.
अगर आपको टूल को मैन्युअल तरीके से इस्तेमाल करना है और नतीजों को मॉडल को वापस भेजना है, तो ConversationConfig में automaticToolCalling को 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."
}
उदाहरण
टूल इस्तेमाल करने की सुविधा आज़माने के लिए, repo को क्लोन करें और example/ToolMain.kt के साथ चलाएं:
bazel run -c opt //kotlin/java/com/google/ai/edge/litertlm/example:tool -- <abs_model_path>
गड़बड़ी ठीक करना
एपीआई के तरीके, नेटिव लेयर से गड़बड़ियों के लिए LiteRtLmJniException या लाइफ़साइकल से जुड़ी समस्याओं के लिए IllegalStateException जैसे स्टैंडर्ड Kotlin अपवादों को थ्रो कर सकते हैं.
एपीआई कॉल को हमेशा try-catch ब्लॉक में रैप करें. onError में मौजूद MessageCallback कॉलबैक, एसिंक्रोनस कार्रवाइयों के दौरान गड़बड़ियों की जानकारी भी देगा.