API-ja Kotlin e LiteRT-LM për Android dhe JVM (Linux, MacOS, Windows) me veçori si përshpejtimi i GPU dhe NPU , multimodaliteti dhe përdorimi i mjeteve .
Hyrje
Ja një shembull i një aplikacioni terminal për biseda i ndërtuar me API-në Kotlin:
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) }
}
}
}
}

Për të provuar shembullin e mësipërm, klononi depon dhe ekzekutoni me example/Main.kt :
bazel run -c opt //kotlin/java/com/google/ai/edge/litertlm/example:main -- <abs_model_path>
Modelet .litertlm të disponueshme janë në Komunitetin HuggingFace LiteRT . Animacioni i mësipërm përdorte Gemma3-1B-IT .
Për një shembull për Android, shikoni aplikacionin Google AI Edge Gallery .
Fillimi me Gradle
Ndërsa LiteRT-LM është zhvilluar me Bazel, ne ofrojmë paketat Maven për përdoruesit e Gradle/Maven.
1. Shtoni varësinë 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")
}
Mund t’i gjeni versionet e disponueshme në Google Maven në litertlm-android dhe litertlm-jvm .
latest.release mund të përdoret për të marrë versionin më të fundit.
2. Inicializoni Motorin
Engine është pika e hyrjes në API. Inicializojeni atë me shtegun e modelit dhe konfigurimin. Mos harroni ta mbyllni motorin për të liruar burimet.
Shënim: Metoda engine.initialize() mund të kërkojë një kohë të konsiderueshme (p.sh., deri në 10 sekonda) për të ngarkuar modelin. Rekomandohet fuqimisht që ta thirrni këtë në një fije në sfond ose korutinë për të shmangur bllokimin e fijes së ndërfaqes së përdoruesit.
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()
Në Android, për të përdorur backend-in e GPU-së, aplikacioni duhet të kërkojë në mënyrë të qartë bibliotekat native të varura duke shtuar sa vijon në AndroidManifest.xml tuaj brenda etiketës <application> :
<application>
<uses-native-library android:name="libvndksupport.so" android:required="false"/>
<uses-native-library android:name="libOpenCL.so" android:required="false"/>
</application>
Për të përdorur backend-in e NPU-së , mund t'ju duhet të specifikoni direktorinë që përmban bibliotekat NPU. Në Android, nëse bibliotekat janë të përfshira me aplikacionin tuaj, caktojeni atë në context.applicationInfo.nativeLibraryDir . Shihni LiteRT-LM NPU për më shumë detaje rreth bibliotekave native të NPU-së.
val engineConfig = EngineConfig(
modelPath = modelPath,
backend = Backend.NPU(nativeLibraryDir = context.applicationInfo.nativeLibraryDir)
)
3. Krijo një bisedë
Pasi motori të jetë inicializuar, krijoni një instancë Conversation . Mund të ofroni një ConversationConfig për të personalizuar sjelljen e tij.
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 zbaton AutoCloseable , kështu që mund të përdorni bllokun use për menaxhimin automatik të burimeve për biseda të njëhershme ose jetëshkurtra:
engine.createConversation(conversationConfig).use { conversation ->
// Interact with the conversation
}
4. Dërgimi i mesazheve
Ekzistojnë tre mënyra për të dërguar mesazhe:
-
sendMessage(contents): Message: Thirrje sinkrone që bllokon derisa modeli të kthejë një përgjigje të plotë. Kjo është më e thjeshtë për ndërveprimet bazë kërkesë/përgjigje. -
sendMessageAsync(contents, callback): Thirrje asinkrone për përgjigje që transmetohen vazhdimisht. Kjo është më e mirë për kërkesa që ekzekutohen për një kohë të gjatë ose kur dëshironi ta shfaqni përgjigjen ndërsa gjenerohet. -
sendMessageAsync(contents): Flow<Message>: Thirrje asinkrone që kthen një Kotlin Flow për përgjigje transmetimi. Kjo është qasja e rekomanduar për përdoruesit e Coroutine.
Shembull Sinkron:
import com.google.ai.edge.litertlm.Content
import com.google.ai.edge.litertlm.Message
print(conversation.sendMessage("What is the capital of France?"))
Shembull asinkron me rikthim thirrjeje:
Përdorni sendMessageAsync për të dërguar një mesazh te modeli dhe për të marrë përgjigje përmes një thirrjeje mbrapsht.
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)
Shembull asinkron me Flow:
Përdorni sendMessageAsync (pa argumentin callback) për të dërguar një mesazh te modeli dhe për të marrë përgjigje përmes një Kotlin Flow.
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. Multimodaliteti
Objektet Message mund të përmbajnë lloje të ndryshme të Content , duke përfshirë Text , ImageBytes , ImageFile dhe 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. Përcaktimi dhe Përdorimi i Mjeteve
Ekzistojnë dy mënyra për të përcaktuar mjetet:
- Me funksionet Kotlin (të rekomanduara për shumicën e rasteve)
- Me specifikimin e Open API (kontroll i plotë i specifikimit dhe ekzekutimit të mjetit)
Përcaktimi i mjeteve me funksionet Kotlin
Ju mund të përcaktoni funksionet e personalizuara të Kotlin si mjete që modeli mund t'i thërrasë për të kryer veprime ose për të marrë informacion.
Krijo një klasë që implementon ToolSet dhe shëno metodat me @Tool dhe parametrat me @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()
}
}
Prapa skenave, API-ja inspekton këto shënime dhe nënshkrimin e funksionit për të gjeneruar një skemë në stilin OpenAPI. Kjo skemë përshkruan funksionalitetin e mjetit, parametrat (duke përfshirë llojet dhe përshkrimet e tyre nga @ToolParam ) dhe llojin e kthimit në modelin e gjuhës.
Llojet e parametrave
Tipet për parametrat e shënuar me @ToolParam mund të jenë String , Int , Boolean , Float , Double ose një List e këtyre tipeve (p.sh., List<String> ). Përdorni tipe të pavlefshme (p.sh., String? ) për të treguar parametrat e pavlefshëm. Vendosni një vlerë të paracaktuar për të treguar që parametri është opsional dhe përmendni vlerën e paracaktuar në përshkrimin në @ToolParam .
Lloji i kthimit
Lloji i kthimit të funksionit tuaj të mjetit mund të jetë çdo lloj Kotlin. Rezultati do të konvertohet në një element JSON përpara se të dërgohet përsëri në model.
- Llojet
Listkonvertohen në vargje JSON. - Llojet e
Mapkonvertohen në objekte JSON. - Tipet primitive (
String,Number,Boolean) konvertohen në primitivin JSON përkatës. - Llojet e tjera konvertohen në vargje me metodën
toString().
Për të dhënat e strukturuara, rekomandohet kthimi i Map ose i një klase të dhënash që do të konvertohet në një objekt JSON.
Përcaktimi i mjeteve me specifikimin OpenAPI
Si alternativë, mund të përcaktoni një mjet duke zbatuar klasën OpenApiTool dhe duke dhënë përshkrimin e mjetit si një varg JSON që përputhet me specifikimin e Open API. Kjo metodë është e dobishme nëse tashmë keni një skemë OpenAPI për mjetin tuaj ose nëse keni nevojë për kontroll të detajuar mbi përkufizimin e mjetit.
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}"""
}
}
Mjetet e Regjistrimit
Përfshini raste të mjeteve tuaja në 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)
Modeli do të vendosë se kur ta thërrasë mjetin bazuar në bisedë. Rezultatet nga ekzekutimi i mjetit dërgohen automatikisht përsëri te modeli për të gjeneruar përgjigjen përfundimtare.
Thirrja manuale e mjeteve
Si parazgjedhje, thirrjet e mjeteve të gjeneruara nga modeli ekzekutohen automatikisht nga LiteRT-LM dhe rezultatet nga ekzekutimi i mjetit dërgohen automatikisht përsëri në model për të gjeneruar përgjigjen tjetër.
Nëse doni të ekzekutoni manualisht mjetet dhe t'i dërgoni rezultatet përsëri modelit, mund ta vendosni automaticToolCalling në ConversationConfig në false .
val conversation = engine.createConversation(
ConversationConfig(
tools = listOf(
tool(SampleOpenApiTool()),
),
automaticToolCalling = false,
)
)
Nëse çaktivizoni thirrjen automatike të mjeteve, do t'ju duhet të ekzekutoni manualisht mjetet dhe t'i dërgoni rezultatet përsëri modelit në kodin e aplikacionit tuaj. Metoda execute të OpenApiTool nuk do të thirret automatikisht kur automaticToolCalling është vendosur në false .
// 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."
}
Shembull
Për të provuar përdorimin e mjetit, klononi depon dhe ekzekutoni me example/ToolMain.kt :
bazel run -c opt //kotlin/java/com/google/ai/edge/litertlm/example:tool -- <abs_model_path>
Trajtimi i Gabimeve
Metodat API mund të hedhin LiteRtLmJniException për gabime nga shtresa vendase ose përjashtime standarde të Kotlin si IllegalStateException për probleme të ciklit jetësor. Gjithmonë mbështjellni thirrjet API në blloqe try-catch. Thirrja mbrapsht onError në MessageCallback do të raportojë gjithashtu gabime gjatë operacioneve asinkrone.