soniqo/FunctionGemma-270M-LiteRT-LM
FunctionGemma 270M — LiteRT-LM (Android)
LiteRT-LM exports of google/functiongemma-270m-it for on-device function calling, plus a separately loadable Control LoRA adapter. The original stock model.litertlm remains unchanged.
Files
The LoRA-enabled base includes 128, 512, and 1024-token prefill graphs, a 1024-token KV cache, the tokenizer, and the FunctionGemma chat template. Base weights use dynamic INT8 quantization with FP32 activations for CPU/XNNPACK.
Control adapter
The adapter routes a compact offline phone-control surface:
call_contact, dial_number, find_contact, find_music, play_music, stop_music, set_volume, and list_capabilities.
It was trained as an attention-only rank-8 MLX LoRA on all 18 layers, targeting Q/K/V/O projections with scale 20. LiteRT-LM 0.14 CPU accepts ranks 16 and 32, so the export losslessly pads rank 8 to rank 16: the additional A columns and B rows are exactly zero. The adapter contains 144 external, 64-KiB-aligned FP32 tensor buffers and lora_rank=16 metadata.
Use the compact prompt format that matches training:
<start_of_turn>developer
You are a model that can do function calling with the following functions
Available functions: call_contact, dial_number, find_contact, find_music, play_music, set_volume, list_capabilities.
Music state: idle.<end_of_turn>
<start_of_turn>user
set volume to five<end_of_turn>
<start_of_turn>modelAdd stop_music to the available-function line only while music is playing. The adapter is not intended for the full declaration prompt used by the stock bundle.
Android Kotlin 0.14
LiteRT-LM 0.14's Kotlin EngineConfig does not expose the engine LoRA-rank setting used by the C and Python APIs. Therefore Kotlin applications should use the adapter-required model-lora16-android.litertlm compatibility bundle and pass the adapter to each conversation:
val engine = Engine(
EngineConfig(
modelPath = "/data/local/tmp/model-lora16-android.litertlm",
backend = Backend.CPU(),
),
)
engine.initialize()
val conversation = engine.createConversation(
ConversationConfig(
samplerConfig = SamplerConfig(topK = 1, topP = 1.0, temperature = 0.0),
loraConfig = LoraConfig(
loraPath = "/data/local/tmp/control-r4-rank16.tflite",
),
),
)Greedy decoding is recommended for deterministic tool syntax. Released Kotlin 0.14.0 also lacks a per-conversation output-token cap; close each one-shot conversation after the command completes.
Validation
The release candidate uses training checkpoint step 400.
The Android engine loaded in 641 ms with an existing XNNPACK cache. Latency is generation-only after engine initialization. The 136-example held-out set contains action, no-action, and music-state cases. Dynamic INT8 loses routing accuracy relative to MLX, so applications should confirm high-impact actions such as dialing and should validate the model against their own command set.
Artifact integrity
The source model revision is google/functiongemma-270m-it@39eccb091651513a5dfb56892d3714c1b5b8276c.
Workflow contract
Function calls use:
<start_function_call>call:name{arg:<escape>value<escape>}<end_function_call>The stock model supports ordinary FunctionGemma declarations and tool-response turns. The Control adapter is designed for one command and one tool call per fresh conversation; multi-step chaining and long multi-turn slot filling were not evaluated.
Links
- speech-android — Android SDK and Control demo
- speech-models — training and export tooling
- soniqo.audio
