> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mellea.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# LoRA and aLoRA adapters

> Train lightweight adapters on your own labeled data and use them as requirement validators in Mellea programs.

Off-the-shelf language models sometimes fail on domain-specific tasks — particularly
requirement validation over proprietary terminology or specialized classification
schemes not well-represented in general training data. Mellea lets you train a
[LoRA](https://arxiv.org/abs/2106.09685) or
[aLoRA](https://github.com/IBM/activated-lora) adapter on your own labeled dataset
and use it as a requirement validator in any Mellea program.

**Prerequisites:** `pip install "mellea[cli]"`. Training requires a GPU or
Apple Silicon Mac with sufficient VRAM for the chosen base model. Uploading requires a
Hugging Face account.

> **Backend note:** Custom-trained adapters can only be loaded into `LocalHFBackend`.
> They do not work with Ollama, OpenAI, or other remote backends.
>
> Granite Switch models ship with pre-trained intrinsic adapters embedded in the
> model weights, which can be used via `OpenAIBackend` with
> `load_embedded_adapters=True`. See [Intrinsics](./intrinsics) for details.

## LoRA vs aLoRA

Both adapter types fine-tune a base model on your data. The difference is inference cost:

|                    | LoRA                             | aLoRA                                          |
| ------------------ | -------------------------------- | ---------------------------------------------- |
| Inference overhead | Processes full context each call | Activated at a single token — minimal overhead |
| Best for           | General fine-tuning              | Fast inner-loop checks, requirement validation |
| Training time      | Similar                          | Similar                                        |

For requirement validation in Mellea (short binary checks inside a generation loop),
aLoRA is the better choice. Use `--adapter lora` if you need a more general fine-tune
and can absorb the inference cost.

## Data format

Training data is a `.jsonl` file with one JSON object per line. Each object must have:

* `item` — the input text to classify
* `label` — the string classification label

```json theme={null}
{"item": "Observed black soot on intake. Seal seems compromised under thermal load.", "label": "piston_rings"}
{"item": "Rotor misalignment caused torsion on connecting rod. High vibration at 3100 RPM.", "label": "connecting_rod"}
{"item": "Combustion misfire traced to a cracked mini-carburetor flange.", "label": "mini_carburetor"}
{"item": "Stembolt makes a whistling sound and does not complete the sealing process.", "label": "no_failure"}
```

Labels can be any strings. The adapter learns to predict the label from the item text.

## Train an adapter

```bash theme={null}
m alora train data.jsonl \
  --basemodel ibm-granite/granite-3.2-8b-instruct \
  --outfile ./checkpoints/my_adapter \
  --adapter alora \
  --epochs 6 \
  --learning-rate 6e-6 \
  --batch-size 2 \
  --max-length 1024 \
  --grad-accum 4
```

The trained adapter weights are saved to `./checkpoints/my_adapter/`.

### Parameters

| Flag              | Type    | Default  | Description                                |
| ----------------- | ------- | -------- | ------------------------------------------ |
| `datafile`        | `str`   | required | Path to `.jsonl` training file             |
| `--basemodel`     | `str`   | required | Hugging Face model ID or local path        |
| `--outfile`       | `str`   | required | Directory to save adapter weights          |
| `--adapter`       | `str`   | `alora`  | Adapter type: `alora` or `lora`            |
| `--device`        | `str`   | `auto`   | Device: `auto`, `cpu`, `cuda`, or `mps`    |
| `--epochs`        | `int`   | `6`      | Number of training epochs                  |
| `--learning-rate` | `float` | `6e-6`   | Learning rate                              |
| `--batch-size`    | `int`   | `2`      | Per-device batch size                      |
| `--max-length`    | `int`   | `1024`   | Max tokenized sequence length              |
| `--grad-accum`    | `int`   | `4`      | Gradient accumulation steps                |
| `--promptfile`    | `str`   | None     | JSON file overriding the invocation prompt |

The default invocation prompt is `<|start_of_role|>check_requirement<|end_of_role|>`.
Provide `--promptfile` only if your adapter needs a different prompt format. The file
must contain `{"invocation_prompt": "..."}`.

## Upload to Hugging Face

```bash theme={null}
huggingface-cli login  # one-time setup

m alora upload ./checkpoints/my_adapter \
  --name your-org/my-adapter
```

This creates the Hugging Face repository if it does not exist and uploads the adapter
weights. Requires `HF_TOKEN` set or a prior `huggingface-cli login`.

> **Warning:** Before uploading to a public repository, review whether your training
> data includes proprietary, confidential, or personal information. Language models can
> memorize details from small domain-specific datasets.

If you intend to use the adapter as a Mellea intrinsic (so that it can be loaded by
model ID rather than local path), pass `--intrinsic` and provide an `io.yaml` file:

```bash theme={null}
m alora upload ./checkpoints/my_adapter \
  --name your-org/my-adapter \
  --intrinsic \
  --io-yaml ./io.yaml
```

## Use the adapter in Mellea

Load the trained adapter into a `LocalHFBackend` using `CustomIntrinsicAdapter`:

```python theme={null}
from mellea.backends.huggingface import LocalHFBackend
from mellea.backends.adapters.adapter import CustomIntrinsicAdapter
from mellea.stdlib.context import ChatContext
from mellea import MelleaSession
from mellea.stdlib.requirements import req

backend = LocalHFBackend(model_id="ibm-granite/granite-3.2-8b-instruct")

adapter = CustomIntrinsicAdapter(
    model_id="your-org/my-adapter",       # HF repo ID or local checkpoint path
    base_model_name="granite-3.2-8b-instruct",
)
backend.add_adapter(adapter)

m = MelleaSession(backend, ctx=ChatContext())

failure_check = req("The failure mode must not be 'no_failure'.")
result = m.instruct(
    "Write a triage summary based on this technician note: {{note}}",
    user_variables={"note": "High vibration at 3100 RPM, connecting rod suspected."},
    requirements=[failure_check],
)
print(str(result))
# Output will vary — LLM responses depend on model and temperature.
```

When `backend.add_adapter()` is called, Mellea automatically routes requirement
validation through the adapter for any `req()` calls on that session. The adapter
runs at the `check_requirement` prompt position — fast, with minimal context overhead.

## Disable adapter validation

To run without adapter validation (for benchmarking or debugging):

```python theme={null}
backend.default_to_constraint_checking_alora = False
```

Set it back to `True` to re-enable. This flag is per-backend instance and does not
affect other sessions.

**See also:** [Intrinsics](./intrinsics) |
[The Requirements System](../concepts/requirements-system) |
[Write Custom Verifiers](../how-to/write-custom-verifiers) |
[CLI Reference](../reference/cli)
