API Kotlin của LiteRT-LM cho Android và JVM (Linux, MacOS, Windows) với các tính năng như tăng tốc GPU và NPU, đa phương thức và sử dụng công cụ.
Giới thiệu
Dưới đây là một ứng dụng trò chuyện trên thiết bị đầu cuối mẫu được xây dựng bằng 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) }
}
}
}
}

Để dùng thử mẫu ở trên, hãy sao chép kho lưu trữ và chạy bằng example/Main.kt:
bazel run -c opt //kotlin/java/com/google/ai/edge/litertlm/example:main -- <abs_model_path>
Các mô hình .litertlm hiện có nằm trong Cộng đồng HuggingFace LiteRT. Ảnh động ở trên sử dụng Gemma3-1B-IT.
Đối với mẫu Android, hãy xem ứng dụng Google AI Edge Gallery.
Bắt đầu với Gradle
Mặc dù LiteRT-LM được phát triển bằng Bazel, nhưng chúng tôi cung cấp các gói Maven cho người dùng Gradle/Maven.
1. Thêm phần phụ thuộc vào 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")
}
Bạn có thể tìm thấy các phiên bản có sẵn trên Google Maven trong litertlm-android và litertlm-jvm.
Bạn có thể dùng latest.release để tải bản phát hành mới nhất.
2. Khởi chạy Công cụ
Engine là điểm truy cập vào API. Khởi chạy bằng đường dẫn mô hình và cấu hình. Hãy nhớ đóng công cụ này để giải phóng tài nguyên.
Lưu ý: Phương thức engine.initialize() có thể mất một khoảng thời gian đáng kể (ví dụ: tối đa 10 giây) để tải mô hình. Bạn nên gọi phương thức này trên một luồng hoặc coroutine trong nền để tránh chặn luồng giao diện người dùng.
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()
Trên Android, để sử dụng phần phụ trợ GPU, ứng dụng cần yêu cầu các thư viện gốc phụ thuộc một cách rõ ràng bằng cách thêm nội dung sau vào AndroidManifest.xml bên trong thẻ <application>:
<application>
<uses-native-library android:name="libvndksupport.so" android:required="false"/>
<uses-native-library android:name="libOpenCL.so" android:required="false"/>
</application>
Để sử dụng phần phụ trợ NPU, bạn có thể cần chỉ định thư mục chứa các thư viện NPU. Trên Android, nếu các thư viện được đi kèm với ứng dụng của bạn, hãy đặt thành context.applicationInfo.nativeLibraryDir. Hãy xem LiteRT-LM NPU để biết thêm thông tin chi tiết về các thư viện gốc NPU.
val engineConfig = EngineConfig(
modelPath = modelPath,
backend = Backend.NPU(nativeLibraryDir = context.applicationInfo.nativeLibraryDir)
)
3. Tạo cuộc trò chuyện
Sau khi khởi động công cụ, hãy tạo một thực thể Conversation. Bạn có thể cung cấp một ConversationConfig để tuỳ chỉnh hành vi của 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 triển khai AutoCloseable, vì vậy, bạn có thể sử dụng khối use để quản lý tài nguyên tự động cho các cuộc trò chuyện một lần hoặc ngắn hạn:
engine.createConversation(conversationConfig).use { conversation ->
// Interact with the conversation
}
4. Gửi tin nhắn
Có 3 cách để gửi tin nhắn:
sendMessage(contents): Message: Lệnh gọi đồng bộ chặn cho đến khi mô hình trả về một phản hồi hoàn chỉnh. Điều này đơn giản hơn đối với các hoạt động tương tác cơ bản theo yêu cầu/phản hồi.sendMessageAsync(contents, callback): Lệnh gọi không đồng bộ để truyền trực tuyến các phản hồi. Phương thức này phù hợp hơn cho các yêu cầu chạy trong thời gian dài hoặc khi bạn muốn hiển thị phản hồi trong khi phản hồi đang được tạo.sendMessageAsync(contents): Flow<Message>: Lệnh gọi không đồng bộ trả về một Kotlin Flow để truyền phát trực tuyến các phản hồi. Đây là phương pháp được đề xuất cho người dùng Coroutine.
Ví dụ đồng bộ:
import com.google.ai.edge.litertlm.Content
import com.google.ai.edge.litertlm.Message
print(conversation.sendMessage("What is the capital of France?"))
Ví dụ không đồng bộ có lệnh gọi lại:
Sử dụng sendMessageAsync để gửi thông báo đến mô hình và nhận phản hồi thông qua một lệnh gọi lại.
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)
Ví dụ không đồng bộ với Flow:
Sử dụng sendMessageAsync (không có đối số gọi lại) để gửi thông báo đến mô hình và nhận phản hồi thông qua Luồng Kotlin.
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. Đa phương thức
Các đối tượng Message có thể chứa nhiều loại Content, bao gồm Text, ImageBytes, ImageFile và 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. Xác định và sử dụng công cụ
Có hai cách để xác định công cụ:
- Với các hàm Kotlin (nên dùng trong hầu hết các trường hợp)
- Với quy cách Open API (kiểm soát hoàn toàn quy cách và quá trình thực thi công cụ)
Xác định các công cụ bằng hàm Kotlin
Bạn có thể xác định các hàm Kotlin tuỳ chỉnh làm công cụ mà mô hình có thể gọi để thực hiện các hành động hoặc tìm nạp thông tin.
Tạo một lớp triển khai ToolSet và chú thích các phương thức bằng @Tool và các tham số bằng @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()
}
}
Ở phía sau, API sẽ kiểm tra các chú thích này và chữ ký hàm để tạo một giản đồ theo kiểu OpenAPI. Lược đồ này mô tả chức năng, các tham số (bao gồm cả loại và nội dung mô tả của tham số từ @ToolParam) và loại dữ liệu trả về của công cụ cho mô hình ngôn ngữ.
Các loại thông số
Các loại tham số được chú thích bằng @ToolParam có thể là String, Int, Boolean, Float, Double hoặc List của các loại này (ví dụ: List<String>).
Sử dụng các kiểu có thể có giá trị rỗng (ví dụ: String?) để cho biết các tham số có thể rỗng. Đặt giá trị mặc định để cho biết rằng tham số là không bắt buộc và đề cập đến giá trị mặc định trong phần mô tả trong @ToolParam.
Loại trả về
Loại dữ liệu trả về của hàm công cụ có thể là bất kỳ loại nào trong Kotlin. Kết quả sẽ được chuyển đổi thành một phần tử JSON trước khi được gửi lại cho mô hình.
- Các loại
Listđược chuyển đổi thành mảng JSON. - Các loại
Mapđược chuyển đổi thành các đối tượng JSON. - Các kiểu dữ liệu nguyên thuỷ (
String,Number,Boolean) được chuyển đổi thành kiểu dữ liệu nguyên thuỷ JSON tương ứng. - Các loại khác được chuyển đổi thành chuỗi bằng phương thức
toString().
Đối với dữ liệu có cấu trúc, bạn nên trả về Map hoặc một lớp dữ liệu sẽ được chuyển đổi thành đối tượng JSON.
Xác định các công cụ bằng Quy cách OpenAPI
Ngoài ra, bạn có thể xác định một công cụ bằng cách triển khai lớp OpenApiTool và cung cấp nội dung mô tả của công cụ dưới dạng một chuỗi JSON tuân thủ quy cách Open API. Phương thức này sẽ hữu ích nếu bạn đã có một giản đồ OpenAPI cho công cụ của mình hoặc nếu bạn cần kiểm soát chi tiết định nghĩa của công cụ.
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}"""
}
}
Đăng ký công cụ
Đưa các phiên bản công cụ của bạn vào 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)
Mô hình sẽ quyết định thời điểm gọi công cụ dựa trên cuộc trò chuyện. Kết quả từ quá trình thực thi công cụ sẽ tự động được gửi lại cho mô hình để tạo phản hồi cuối cùng.
Gọi công cụ theo cách thủ công
Theo mặc định, các lệnh gọi công cụ do mô hình tạo sẽ được LiteRT-LM tự động thực thi và kết quả từ quá trình thực thi công cụ sẽ tự động được gửi lại cho mô hình để tạo phản hồi tiếp theo.
Nếu muốn thực thi các công cụ theo cách thủ công và gửi kết quả về cho mô hình, bạn có thể đặt automaticToolCalling trong ConversationConfig thành false.
val conversation = engine.createConversation(
ConversationConfig(
tools = listOf(
tool(SampleOpenApiTool()),
),
automaticToolCalling = false,
)
)
Nếu tắt tính năng gọi công cụ tự động, bạn sẽ cần thực thi công cụ theo cách thủ công và gửi kết quả trở lại mô hình trong mã ứng dụng của mình. Phương thức execute của OpenApiTool sẽ không được gọi tự động khi automaticToolCalling được đặt thành 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."
}
Ví dụ:
Để dùng thử tính năng sử dụng công cụ, hãy sao chép kho lưu trữ và chạy bằng example/ToolMain.kt:
bazel run -c opt //kotlin/java/com/google/ai/edge/litertlm/example:tool -- <abs_model_path>
Xử lý lỗi
Các phương thức API có thể truyền LiteRtLmJniException cho các lỗi từ lớp gốc hoặc các trường hợp ngoại lệ Kotlin tiêu chuẩn như IllegalStateException cho các vấn đề về vòng đời.
Luôn bao bọc các lệnh gọi API trong các khối try-catch. Lệnh gọi lại onError trong MessageCallback cũng sẽ báo cáo lỗi trong các thao tác không đồng bộ.