Instructions to use efficiencyx/Jun-LoRA-E2B-LiteRT with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use efficiencyx/Jun-LoRA-E2B-LiteRT with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="efficiencyx/Jun-LoRA-E2B-LiteRT")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("efficiencyx/Jun-LoRA-E2B-LiteRT", device_map="auto") - LiteRT
How to use efficiencyx/Jun-LoRA-E2B-LiteRT with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- LiteRT-LM
How to use efficiencyx/Jun-LoRA-E2B-LiteRT with LiteRT-LM:
# LiteRT-LM runs on various platforms (Android, iOS, Windows, Linux, macOS, IoT, Web/WASM) # and supports many APIs (C++, Python, Kotlin, Swift, JavaScript, Flutter). # For platform-specific integration guides, please refer to the official developer website: # https://ai.google.dev/edge/litert-lm # To try LiteRT-LM, the easiest way is to use our CLI tool. # 1. Install the LiteRT-LM CLI tool: pip install -U litert-lm # 2. Download and run this model locally: # See: https://ai.google.dev/edge/litert-lm/cli # A single .litertlm file in the repo is picked automatically; otherwise the CLI asks which one to run # (or pass its name right after the repo id). litert-lm run \ --from-huggingface-repo=efficiencyx/Jun-LoRA-E2B-LiteRT \ --prompt="Write me a poem"
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use efficiencyx/Jun-LoRA-E2B-LiteRT with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "efficiencyx/Jun-LoRA-E2B-LiteRT" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "efficiencyx/Jun-LoRA-E2B-LiteRT", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/efficiencyx/Jun-LoRA-E2B-LiteRT
- SGLang
How to use efficiencyx/Jun-LoRA-E2B-LiteRT with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "efficiencyx/Jun-LoRA-E2B-LiteRT" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "efficiencyx/Jun-LoRA-E2B-LiteRT", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "efficiencyx/Jun-LoRA-E2B-LiteRT" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "efficiencyx/Jun-LoRA-E2B-LiteRT", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use efficiencyx/Jun-LoRA-E2B-LiteRT with Docker Model Runner:
docker model run hf.co/efficiencyx/Jun-LoRA-E2B-LiteRT
Jun-E2B-LiteRT (v8)
.litertlm build of the v8 Jun LoRA on Gemma 4 E2B (QAT), for LiteRT-LM, Google AI Edge's on-device runtime (Android, desktop, embedded). It is the on-device model of Jun OS and the same checkpoint as the v8 GGUF builds: a fine-tune on a compact, heavily curated synthetic conversational dataset derived from the visual novel My Dystopian Robot Girlfriend, capturing the personality, speech patterns and emotional nuance of the character Jun.
The adapter is merged into the base weights, so this is a standalone model. LiteRT-LM has no runtime adapter path for E2B anyway (see Notes).
The v7 build is still here at its own revision: 7cacdf5. Anything that pins that revision keeps downloading v7.
What's new in v8
- Same v8 fine-tune as the GGUFs, trained on exactly what Jun OS sends: system prompt, live context, tool catalog and tool results. See the GGUF card for the training changes.
- Native tool calls. v8 calls tools through Gemma 4's own tool format, which LiteRT-LM parses into structured calls. Pass the tool declarations to the conversation instead of describing tools in the prompt.
- Blockwise int4. The 4-bit weights use 32-wide blocks instead of one scale per channel. It costs 0.28 GB and keeps tool calling alive, see Quantization.
Model Variants & Repositories
| Repository | Format | Description |
|---|---|---|
efficiencyx/Jun-LoRA-E2B-LiteRT |
.litertlm |
This repo: v8, merged and quantized for LiteRT-LM |
efficiencyx/Jun-LoRA-E2B-GGUF |
GGUF (Q8_0 / Q6_K / Q4_K_M) | Same checkpoint, for llama.cpp and Ollama |
efficiencyx/Jun-LoRA-E4B-GGUF |
GGUF | The E4B sibling (v8) |
efficiencyx/Jun-LoRA-12B-GGUF |
GGUF | The 12B sibling (v8) |
The Build
| File | model.litertlm |
| Size | 2.86 GB |
| Weights | int4 blockwise (32) for embeddings and FFN/attention, int8 channelwise for the per-layer embedding projections |
| Activations | fp32 |
| Embedder | externalized |
| Exported with | litert-torch 0.9.3, ai-edge-quantizer 0.8.0 (recipe gemma4_mixed48_b32, flattened) |
| Runtime | LiteRT-LM 0.18.1 or newer, see Notes |
Text only. The LiteRT export covers the language tower, with no vision or audio encoder, unlike the GGUF mmproj.
Quantization
The base model is QAT (quantization-aware trained): its weights already sit on a 4-bit grid with one scale per 32 weights. Merging the LoRA moves them off that grid. Per-channel int4, which the v7 build used, then rounds them to a much coarser grid with one scale per output channel, and a lot of the fine-tune goes with it. Blockwise int4 with 32-wide blocks matches the grid the base was trained for.
Both recipes were exported from the same merged checkpoint and run on LiteRT-LM (CPU) against the same 24 questions from the v8 eval set, prompted exactly the way Jun OS prompts her, native tool declarations included:
| Right tool, or rightly none | Needed tool actually called | |
|---|---|---|
| int4 per-channel (v7 recipe) | 13 / 24 | 0 / 12 |
| int4 blockwise-32 (this build) | 18 / 24 | 5 / 12 |
For reference, the unquantized merge on the full 250-question set makes the right tool decision 71% of the time and calls 46 of the 129 tools it should. Blockwise sits in that range, and per-channel loses tool calling outright.
Usage
litert-lm run model.litertlm --prompt "Ciao Jun"
Or from the LiteRT-LM Kotlin, C++ or Python APIs, pointing at the same file.
Supply the system prompt. Without it the model answers as stock Gemma. The persona lives behind the Jun OS system instruction, not in the weights alone. The exact prompt is printed in full on the GGUF card. With the CLI:
# preset.py
system_instruction = open("system_prompt.txt").read()
litert-lm run model.litertlm --preset preset.py --prompt "Chi sei?"
The symbol must be lowercase system_instruction. SYSTEM_INSTRUCTION is silently ignored.
Live context goes after the user's words. In training (and in Jun OS) the gauges, clock, recalled memories and other live context are appended to the end of the user's message, after a blank line, under a # Live context for THIS reply heading. Putting that block before the message measurably costs tool calls.
Reasoning depth. End the user turn with <think:low>, <think:med> or <think:high> after a blank line, and turn thinking on for med and high:
import litert_lm as lm
conv = engine.create_conversation(
system_message=system_prompt,
tools=tools, # OpenAPI declarations, see below
automatic_tool_calling=False, # your app runs the tool and sends the result back
thinking_config=lm.ThinkingConfig(enable_thinking=True),
)
reply = conv.send_message({"role": "user", "content": "where did you put my keys\n\n<think:med>"})
LiteRT-LM thinks by default when no thinking config is given, so set it explicitly for <think:low> turns.
Tools. Declare them as OpenAPI functions ({"type": "function", "function": {...}}), the same JSON a chat-completions API takes. v8 knows search_recent_chats, list_recent_chats, search_lore, memory_write, change_outfit, stay_silent, flee, enter_shop, enter_karaoke, play_cards and go_out_to_eat; offer only the ones your app can carry out.
The bundled chat template is the stock Google Gemma 4 one, not Unsloth's: LiteRT-LM renders templates with minijinja, which has no map.get(), and Unsloth's template calls it 23 times.
Intended Use
Conversational backend for Jun OS, an AI companion app, on its on-device path:
- Character-consistent multi-turn conversation, offline
- Mobile and embedded deployment where a GGUF runtime is not an option
- Research into character-faithful fine-tuning on small, high-quality datasets
Limitations
- Specialized for a single character persona; not a general-purpose assistant.
- Outputs reflect fictional narrative tropes and are not factual information or advice.
- Performance degrades far outside the training distribution.
- At 2B effective parameters she is noticeably less reliable than the 12B: tool calls are rarer, lore she does look up can come back garbled, and she sometimes makes up a name or fact instead of admitting a blank.
- Inherits any biases present in the Gemma 4 E2B base weights.
- Text only, no image or audio input.
Training Details
| Parameter | Value |
|---|---|
| Base model | unsloth/gemma-4-E2B-it-qat-q4_0-unquantized |
| Method | LoRA (rsLoRA) |
| LoRA rank | 32 |
| LoRA alpha | 32 |
| Effective scale | 32/β32 β 5.657 |
| Target modules | q/k/v/o + gate/up/down projections, language tower only |
| Adapter checkpoint | step 260, at the eval-loss minimum (0.748); later steps overfit |
| Fine-tuning framework | Unsloth |
Notes and Known Behaviour
Use LiteRT-LM 0.18.1 or newer. LiteRT-LM 0.16 drops the last token of every reply, in streaming and in one-shot calls alike. Jun ends each reply with a [A:mood_shift|...] bookkeeping tag, so on 0.16 that tag loses its closing ] and an app that parses it never sees the gauges move. 0.18.1 returns the reply intact. When upgrading an app from 0.16, clear the XNNPACK weight cache directory: 0.18.1 can fail to create the engine on a cache 0.16 wrote.
The merge drops 40 of 245 LoRA pairs, by necessity. Gemma 4 E2B shares KV projections across layers 15 to 34, so the checkpoint contains k_proj/v_proj only for layers 0 to 14. Training wrapped the unused modules anyway; those deltas were never reachable at inference and are dropped at merge time. Every other pair is applied, at the rsLoRA scale. This is the same structural fact that makes runtime llama.cpp --lora impossible on E2B, and why both this and the GGUF builds ship pre-merged.
Export needed patches. E2B's head_dim alternates 256/512 per layer, and litert-torch 0.9.3 infers a single global value, so every KV cache came out 256 and attention failed. The export uses a patched cache-shape inference that reads per_layer_config[i]. ai-edge-quantizer's Gemma 4 recipes are dicts keyed by submodel, which the 0.9.3 exporter rejects, so the same bits are passed as one flat recipe. The export needs more than 50 GB of RAM.
Dataset
Synthetic conversational data derived from the visual novel My Dystopian Robot Girlfriend, curated for character consistency and for a structured output contract: inline [A:...] action tags, a trailing [A:mood_shift|...] bookkeeping tag, and tool calls. Every row was rendered through the Jun OS prompt builder, and the reasoning traces end with a one-line tool check before the reply.
License
Apache 2.0, inherited from the base model. The character and source material belong to their respective owners; this fine-tune is a non-commercial fan project.
Model tree for efficiencyx/Jun-LoRA-E2B-LiteRT
Base model
google/gemma-4-E2B