lora-easy
A tiny, object-oriented wrapper around 🤗 PEFT for LoRA fine-tuning of causal
language models. One LoraModel class hides the from_pretrained boilerplate,
and Agent adds web / file search capabilities on top.
This project is primarily developed by Hermes Agent, an AI coding agent by Nous Research, through iterative human-machine pairing.
Key concepts
- LoRA (Low-Rank Adaptation) — instead of updating all of a model's weights,
LoRA freezes the base model and trains two small low-rank matrices (
AandB) injected into the attention layers. Typically ~0.1% of parameters are trainable, so a checkpoint is a few MB instead of GB. - Base vs. adapter — the large pretrained weights never change. The tiny
adapter carries the new personality you trained.
enable_lora()/disable_lora()just switch which oneself.modelpoints at, so toggling never loses your trained weights. - Chat template — training and inference must format text the same way.
Training data is rendered with
add_generation_prompt=False; inference usesTrueso the model knows to start generating. - Label masking —
labelsmirrorinput_ids, but padding positions are set to-100so they are ignored in the loss. - System prompt — set
system_prompt=onLoraModelorAgent(description=…)to give the model a persona. Change it at runtime with/system-promptin an interactive session. - Slash commands — register your own with
@command("/name")and use them duringchat_session().run().
Requirements
torch>=2.0
peft>=0.19
transformers>=4.45
pip install lora-easy
Runs on CUDA, Apple Silicon (MPS), or CPU.
Quick start
LoraModel
from lora_ez import LoraModel
m = LoraModel("Qwen/Qwen2.5-0.5B-Instruct", name="cat",
system_prompt="you are a sassy house cat")
# ----- fine-tune -----
m.enable_lora(r=8, alpha=16)
m.train(data, epochs=30)
m.save() # -> ./lora-cat/
# ----- single-turn chat -----
print(m.chat("hello!"))
# ----- multi-turn with memory -----
with m.chat_session("./chat.json", auto_save=True) as s:
s > "I'm back" # shorthand for s.chat("I'm back")
s > "how are you?"
s.run() # interactive REPL, /exit to quit
Agent (web + file search)
from lora_ez import Agent
m = LoraModel("Qwen/Qwen2.5-0.5B-Instruct")
a = Agent(m, description="you are a data analyst",
web_enabled=True, file_enabled=True)
a.chat("what Python packages are installed?")
a.web_fetch("https://example.com")
a.disable_web()
API
LoraModel
| Method | What it does |
|---|---|
LoraModel(model_id, name, system_prompt, device) |
Load base model + tokenizer |
enable_lora(r, alpha, dropout) |
Attach a LoRA adapter |
disable_lora() |
Point back to the frozen base model |
train(conversations, **kwargs) |
Fine-tune on ShareGPT-format data |
chat(prompt, history, system_prompt) |
Generate a reply |
chat_session(save_path, auto_save, system_prompt) |
Multi-turn session context manager |
save(path) / load(path) |
Persist / restore the adapter |
Agent — wraps a LoraModel with tools
| Method | What it does |
|---|---|
Agent(model, description, web_enabled, …) |
Wrap a model with search tools |
chat(prompt) |
Auto-injects web / file context, then delegates to model |
enable_web() / disable_web() |
Toggle web search |
enable_files() / disable_files() |
Toggle local file search |
web_fetch(url) |
Fetch a URL, respecting allowlists / blocklists |
file_read(path) |
Read a file inside allowed directories |
chat_session(…) |
Multi-turn session (delegated to the model) |
Slash commands — build your own with the @command decorator
from lora_ez import command
@command("/greet")
def greet(session, *args):
return f"Hello, {' '.join(args)}!" if args else "Hello!"
Built-in: /exit, /help, /system-prompt.
Demo
Two demo folders show end-to-end LoRA persona training:
demo/trainsQwen2.5-0.5B-Instructto talk like a sassy house cat usingcat-chat.json(YAML-driven viamodel.yml).demo2/trainsQwen2.5-1.5B-Instructas a high-EQ girlfriend persona "Ivanka" (ivanka-chat.json), showing multi-turn dialogues and long-reply handling viamax_length.
cd demo && python3 run.py # cat persona
cd demo2 && python3 run.py # Ivanka persona (train ~1-2 min on MPS)
cd demo2 && python3 run_session.py # interactive REPL chat with Ivanka
cd demo2 && python3 test_session.py # quick multi-turn + command test
Links
License
MIT
Metadata
Release files for lora-easy 2.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| lora_easy-2.3.tar.gz | 13.7 kB | Without provenance | Details for lora_easy-2.3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| lora_easy-2.3-py3-none-any.whl | Python 3 | none | any | Details for lora_easy-2.3-py3-none-any.whl |
Total release size: 29.6 kB
Release files / lora_easy-2.3.tar.gz
| Download URL | lora_easy-2.3.tar.gz |
|---|---|
| Size | 13.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f9dc70071e80e533c83d6d059c2b9d19a21f4269539ccf23cc91cf005c7c3226
|
|
BLAKE2b-256 checksum How to use checksums |
1901a10e07c28f99f52b52a1dc55ae43c9073c47b7d8cf19e3d63adddf6829cb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / lora_easy-2.3-py3-none-any.whl
| Download URL | lora_easy-2.3-py3-none-any.whl |
|---|---|
| Size | 15.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
205c82a958fedf39bffea59f8ff77d69dbeda45c153a09cadd1aa211ac4c66ad
|
|
BLAKE2b-256 checksum How to use checksums |
7e11b905737d170c7cd3223371c9a08445d761086c620676515ba25998fd8f90
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for lora-easy 2.3
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.