pylolm (LoLm)
Local LLMs on Android, from Python. An Android-friendly take on llama-cpp-python, built on
llama.cpp and designed for Kivy, Flet and Termux.
- Zero Python dependencies: a thin
ctypeslayer over a small C shim. llama-cpp-python-style API:Llama(...),create_chat_completion(...),create_completion(...).- Streaming generators, stop strings, a
stop()button for your UI. - Multi-turn chat that reuses the KV cache, so long conversations stay fast.
- Aimed at small GGUF models (0.5B-2B) on phones.
Status: alpha (0.1.0). Text generation only. TTS / STT / OCR are on the roadmap.
Install
pip install pylolm
pylolm get-libs # downloads the prebuilt native libraries (seconds)
pylolm doctor # checks that everything loads
get-libs fetches the Android arm64 libraries attached to the matching GitHub Release, checks their
SHA-256 checksum, and installs them to ~/.pylolm/lib. These are built by CI to run on a wide range
of phones.
Prefer to compile for your exact device, or get-libs is not available for your setup?
pkg install cmake clang git
pylolm build-native # clones llama.cpp and builds on the device (slow: ~30 min)
Libraries are searched in $PYLOLM_LIB_DIR, then pylolm/lib/, then ~/.pylolm/lib/.
Quick start
from pylolm import Llama
llm = Llama("/sdcard/models/Qwen2.5-0.5B-Instruct-Q4_K_M.gguf", n_ctx=2048)
messages = [{"role": "user", "content": "Explain GGUF in two sentences."}]
# whole answer
out = llm.create_chat_completion(messages, max_tokens=200)
print(out["choices"][0]["message"]["content"])
# streaming
for chunk in llm.create_chat_completion(messages, max_tokens=200, stream=True):
piece = chunk["choices"][0]["delta"].get("content")
if piece:
print(piece, end="", flush=True)
Try it from the terminal: pylolm chat /path/to/model.gguf.
API
| Call | Notes |
|---|---|
Llama(model_path, n_ctx=2048, n_threads=None, verbose=False) |
n_threads defaults to min(4, cpu_count) |
create_chat_completion(messages, max_tokens=256, temperature=0.7, top_p=0.95, top_k=40, min_p=0.05, repeat_penalty=1.0, seed=None, stop=None, stream=False, chat_template=None) |
OpenAI-style dict, or chunk iterator with stream=True |
create_completion(prompt, ...) / llm(prompt, ...) |
raw text completion |
stop() |
stop the running generation from another thread |
reset() |
clear the KV cache (forget the conversation) |
count_tokens(text) |
tokens used by a string |
close() / with Llama(...) as llm: |
free the model |
Errors: LibraryNotFoundError, ModelLoadError, ContextOverflowError, GenerationError
(all subclass PyLoLmError).
usage in a non-streaming result includes cached_prompt_tokens: how many prompt tokens were
reused from the previous turn.
Chat templates. The model's built-in template is applied through llama.cpp's template
support, which covers the common families (ChatML/Qwen, Llama 3, Gemma, ...) but is not a full
Jinja engine. If a newer model's template is rejected, pass chat_template="chatml" (or another
known name) or build the prompt yourself and call create_completion.
Using it in apps
UI threads. Generation blocks, so run it off the UI thread. A streaming generator is easiest:
import threading
def worker():
for chunk in llm.create_chat_completion(messages, stream=True):
text = chunk["choices"][0]["delta"].get("content")
if text:
Clock.schedule_once(lambda dt, t=text: append_to_label(t)) # Kivy
# page.run_thread / page.update(...) for Flet
threading.Thread(target=worker, daemon=True).start()
Call llm.stop() from your Stop button; breaking out of the loop also stops generation.
Flet. flet build apk installs packages from PyPI using the Android platform tag, so the
android_24_arm64_v8a wheel is what ships the native libraries. This path needs on-device
verification for your Flet/Python version.
Kivy / python-for-android. p4a does not consume Android wheels yet. For now, bundle the
.so files with your app and point PYLOLM_LIB_DIR at them before importing pylolm:
import os
os.environ["PYLOLM_LIB_DIR"] = os.path.join(os.path.dirname(__file__), "pylolm_libs")
import pylolm
A proper p4a recipe is on the roadmap.
Building from source
git clone https://github.com/auraway/pylolm && cd pylolm
pip install -e ".[dev]"
python -m pytest # pure-Python tests, no model needed
PYLOLM_MODEL=/path/model.gguf python -m pytest # + integration tests
Native libraries: src/pylolm/native/build_termux.sh (on a phone) or build_android_ndk.sh
(cross-compile). The llama.cpp version is pinned in src/pylolm/native/LLAMA_CPP_REF.
Releasing to PyPI
- Set
LLAMA_CPP_REFto a llama.cpp tag/commit you have tested. - Bump
versioninpyproject.tomland add aCHANGELOG.mdentry. - On PyPI, add a trusted publisher for this repo
(workflow
release.yml, environmentpypi). git tag v0.1.0 && git push --tags. CI builds the sdist, a pure wheel, and the Android arm64 wheel, publishes them to PyPI, and attachespylolm-libs-android-arm64-v8a.tar.gz(+.sha256) to the GitHub Release forpylolm get-libs. The tag must match the version inpyproject.toml.
Roadmap
- p4a recipe for Kivy; verified Flet build
- whisper.cpp (speech-to-text) module
- TTS and OCR modules
- GPU backends (Vulkan/OpenCL) as an opt-in
License
MIT. llama.cpp is MIT-licensed too; model licenses are your responsibility.
Metadata
Release files for pylolm 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pylolm-0.1.0.tar.gz | 25.9 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pylolm-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
| pylolm-0.1.0-py3-none-android_24_arm64_v8a.whl | Python 3 | none | Android API level 24+ ARM64 v8a | Details |
Total release size: 4.8 MB
Release files / pylolm-0.1.0.tar.gz
| Download URL | pylolm-0.1.0.tar.gz |
|---|---|
| Size | 25.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f7c316d39eb2f2a31f66f47289a65e7a31bf8cf9b465111c6099246959985e15
|
|
BLAKE2b-256 checksum How to use checksums |
af6dd7c613eafd01e35ed902468694c6d6336f16ff1aff6b00926789eb5b70e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / pylolm-0.1.0-py3-none-any.whl
| Download URL | pylolm-0.1.0-py3-none-any.whl |
|---|---|
| Size | 24.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
17d9307284aa4f382191d20a28c296b6d56958b398f9d6783db7323b13f7ba46
|
|
BLAKE2b-256 checksum How to use checksums |
b62f692bfea2421180322b163d0fc324aada5728a6febaaaf2a50ab0514ec685
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / pylolm-0.1.0-py3-none-android_24_arm64_v8a.whl
| Download URL | pylolm-0.1.0-py3-none-android_24_arm64_v8a.whl |
|---|---|
| Size | 4.7 MB |
| Tags | Android API level 24+ ARM64 v8a Python 3 |
|
SHA-256 checksum How to use checksums |
70c8f6c7702ef406246c980f14eccd944056090b508042d75d355a9192d6b5cc
|
|
BLAKE2b-256 checksum How to use checksums |
38d539166c9ec7948a640f2cc361378d1abefe3a63f1c86c04ecae29fe8f4955
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency log