Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/docs/advanced/inference-time-scaling.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,17 @@ print(f"Attempts: {len(result.sample_generations)}")
The `ValidationResult.reason` string is passed to both S1 and S2 as repair guidance —
write specific, actionable failure reasons for best results.

Pass `judge_backend` to have an LLM judge validate any requirement that has no
`validation_fn`. `feedback_strategy` sets how much detail the judge returns to S1 as
repair feedback. It has no effect without `judge_backend`, or for requirements that
have their own `validation_fn`:

| Strategy | Feedback to S1 |
| -------- | -------------- |
| `"simple"` (default) | Pass/fail only; the judge answers yes or no |
| `"first_error"` | The first mistake the judge finds |
| `"all_errors"` | Every mistake the judge finds |

> **Full example:** [`docs/examples/sofai/sofai_graph_coloring.py`](https://github.com/generative-computing/mellea/blob/main/docs/examples/sofai/sofai_graph_coloring.py)

## Budget forcing
Expand Down
9 changes: 9 additions & 0 deletions docs/examples/aLora/101_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
`stembolts_intrinsic.py` in this directory — it has no standalone entry point of
its own; `102_example.py` drives it interactively (reads from stdin, so it isn't
runnable as an automated example).

Runs the model locally, so it needs a GPU or Apple Silicon Mac; the model and
adapter are downloaded from Hugging Face on first run.

Prerequisites:
uv sync --extra hf

Usage:
uv run python docs/examples/aLora/101_example.py
"""

import time
Expand Down
21 changes: 21 additions & 0 deletions docs/examples/aLora/102_example.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# pytest: skip, huggingface, e2e
# SKIP REASON: Requires user input (blocks on stdin in an infinite loop).
"""Interactive diagnosis loop using a fully custom, non-catalog aLoRA adapter.

Demonstrates loading and calling the custom `stembolts` adapter (Hugging Face:
`nfulton/stembolts`) through the helpers in `stembolts_intrinsic.py`. Each turn
runs the adapter-backed intrinsic with a fresh `ChatContext` and prints the raw
JSON result (`defective_part` and `diag_likelihood`). The loop never exits on its
own; stop it with Ctrl+C.

The example uses Granite 3.3 2B because that is the available `stembolts`
adapter variant; Granite 4.0 and 4.1 variants are not currently available. To
train and upload your own variant, see `README.md` in this directory.

Runs the model locally, so it needs a GPU or Apple Silicon Mac; the model and
adapter are downloaded from Hugging Face on first run.

Prerequisites:
uv sync --extra hf

Usage:
uv run python docs/examples/aLora/102_example.py
"""

from stembolts_intrinsic import (
async_stembolt_failure_analysis,
Expand Down
147 changes: 45 additions & 102 deletions docs/examples/aLora/README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,42 @@
# aLoRA Examples

This directory contains examples demonstrating how to tune and use your own (Adaptive) Low-Rank Adapters.
This directory contains examples demonstrating how to tune and use your own (Activated)
Low-Rank Adapters. For the full CLI reference and a conceptual overview, see
[LoRA and aLoRA adapters](../../docs/advanced/lora-and-alora-adapters.md),
[`m alora` CLI reference](../../docs/reference/cli.md), and the
[custom adapter function tutorial](../../docs/tutorials/07-custom-adapter-function.md).
For the built-in catalog adapters, see [`intrinsics/`](../intrinsics/README.md).

## Examples

| File | Description |
| :--- | :--- |
| [`101_example.py`](./101_example.py) | Comparing aLoRA-backed requirement validation against LLM-as-a-judge, using the catalog-native `requirement-check` adapter (not a custom one — see `stembolts_intrinsic.py` for loading your own). |
| [`102_example.py`](./102_example.py) | Interactive loop that exercises the custom `stembolts` adapter — skip-marked because it blocks on stdin in an infinite loop. |
| [`stembolts_intrinsic.py`](./stembolts_intrinsic.py) | Helper module for loading and calling the fully custom `stembolts` adapter (no standalone entry point — `102_example.py` consumes it). |
| [`make_training_data.py`](./make_training_data.py) | Converts raw JSONL into `{item, label}` training data, validating labels against a JSON schema (`jsonschema`). |
| [`example_readme_generator.py`](./example_readme_generator.py) | Programmatic README generation for adapters. |
| [`stembolt_failure_dataset.jsonl`](./stembolt_failure_dataset.jsonl) | Training data in the `{item, label}` format that `m alora train` expects. |
| [`stembolt_customer_data.jsonl`](./stembolt_customer_data.jsonl) | Raw data used as input to `make_training_data.py`. |
| [`io.yaml`](./io.yaml) | Output contract for the `stembolts` adapter, passed to `m alora upload --io-yaml`. |
| [`hints.txt`](./hints.txt) | Domain hints passed to `m alora add-readme --hints`. |

## Training Models

First, we need to clone Mellea and put ourselves into this directory:

```bash
git clone github.com/generative-computing/mellea;
cd mellea;
uv venv .venv;
source .venv/bin/activate;
uv pip install -e .[all];
pushd docs/examples/aLora/;
git clone https://github.com/generative-computing/mellea
cd mellea
uv venv .venv
source .venv/bin/activate
uv pip install -e ".[all]"
pushd docs/examples/aLora/
```

Now let's train a model:

```
```bash
m alora train \
--basemodel ibm-granite/granite-4.1-3b \
--outfile stembolts_model \
Expand All @@ -32,38 +51,39 @@ m alora train \

## Upload Models

If model training succeeds, you will need to upload your model as an adapter function:
If model training succeeds, you will need to upload your model as an adapter function.
Uploading requires a Hugging Face account; run `huggingface-cli login` first.

```bash
# WARNING: running this command will upload your model weights to huggingface.co !!!
# The model will be private.
# replace $HF_USERNAME with your Hugging Face username.
m alora upload \
--intrinsic \
--name "$HF_USERNAME/stembolts" \
--io-yaml io.yaml \
--intrinsic \
--name "$HF_USERNAME/stembolts" \
--io-yaml io.yaml \
stembolts_model
```

You can also train and upload the same adapter for multiple model families:

```
```bash
# CHANGE $HF_USERNAME to your username, or set envvar.
m alora train \
--basemodel ibm-granite/granite-3.3-2b-instruct \
--outfile stembolts_model_3.3_2b \
--adapter alora \
stembolt_failure_dataset.jsonl &&
m alora upload \
--intrinsic \
--name "$HF_USERNAME/stembolts" \
--io-yaml io.yaml \
--intrinsic \
--name "$HF_USERNAME/stembolts" \
--io-yaml io.yaml \
stembolts_model_3.3_2b
```

## Generate a README

After uploading your adapter, you can auto-generate a README for the Hugging Face model repository using `m alora add-readme`. This command uses Mellea to analyze your training dataset and produce documentation with a description, data examples, and integration code:
After uploading your adapter, you can auto-generate a README for the Hugging Face model repository using `m alora add-readme`. This command uses Mellea to analyze your training dataset and produce documentation with a description, data examples, and integration code. It needs a running model backend (the default session backend, so `ollama serve`):

```bash
m alora add-readme \
Expand All @@ -80,95 +100,18 @@ m alora add-readme \
--name $HF_USERNAME/stembolts \
--io-yaml io.yaml \
--basemodel granite-4.1-3b \
--hints hints.txt
--hints hints.txt \
stembolt_failure_dataset.jsonl
```

The generator will display the README and ask for confirmation before uploading it to your Hugging Face repo. You can also call the generator programmatically from Python — see `example_readme_generator.py` for an example.

## Using Adapter Functions

Compose the adapter directly from an `Identity`, an output contract, and a
weights binding — no dedicated adapter class needed:

```python
from mellea.backends.adapters import Adapter, Identity, LocalFileBinding, get_io_contract
from mellea.backends.adapters.catalog import AdapterType

def stembolt_adapter(base_model_name: str = "granite-4.1-3b") -> Adapter:
return Adapter(
identity=Identity(name="stembolts", adapter_type="alora"),
# get_io_contract falls back to a permissive dict contract for names
# outside the built-in catalog.
io_contract=get_io_contract("stembolts"),
weights=LocalFileBinding(
name="stembolts",
adapter_type=AdapterType.ALORA,
repo_id="$USERNAME/stembolts", # REPLACE $USERNAME WITH YOUR HUGGING FACE USERNAME
# A custom, non-catalog adapter has no catalog entry to resolve
# revision=None from — pin it explicitly.
revision="main",
),
)
```

Registering it with a backend downloads and loads the weights:

```python
from mellea.backends.cache import SimpleLRUCache
from mellea.backends.huggingface import LocalHFBackend

backend = LocalHFBackend(
model_id="ibm-granite/granite-4.1-3b", cache=SimpleLRUCache(5)
)

backend.add_adapter(stembolt_adapter(base_model_name="granite-4.1-3b"))
```

## Example Files

### [101_example.py](./101_example.py)
Comparing aLoRA-backed requirement validation against LLM-as-a-judge, using the
catalog-native `requirement-check` adapter (not a custom one — see
`stembolts_intrinsic.py` for loading your own).

Demonstrates:
- Registering a catalog adapter as an aLoRA
- `ALoraRequirement` vs `LLMaJRequirement` routing
- Timing both validation paths

### [102_example.py](./102_example.py)
Interactive loop that exercises the custom `stembolts` adapter — skip-marked
because it blocks on stdin in an infinite loop.

The example uses Granite 3.3 2B because that is the available `stembolts`
adapter variant; Granite 4.0 and 4.1 variants are not currently available.

Demonstrates:
- Loading a fully custom, non-catalog adapter via `stembolts_intrinsic.py`
- Running the adapter-backed intrinsic repeatedly with a fresh `ChatContext`

### [make_training_data.py](./make_training_data.py)
Utility for preparing training datasets for adapter training.

Demonstrates:
- Dataset format preparation
- Data validation
- Preprocessing for training

### [stembolts_intrinsic.py](./stembolts_intrinsic.py)
Helper module for loading and calling the fully custom `stembolts` adapter
(no standalone entry point — `102_example.py` consumes it).

Demonstrates:
- Custom adapter composition (`_stembolt_adapter()`) and intrinsic definition (`StemboltIntrinsic`)
- Registering the adapter on a backend, guarded by qualified name
- Calling the intrinsic directly via `mfuncs.act`

### [example_readme_generator.py](./example_readme_generator.py)
Programmatic README generation for adapters.

Demonstrates:
- Auto-generating adapter documentation
- Using the `m alora add-readme` command programmatically
- Documenting custom adapters
Compose the adapter from an `Identity`, an output contract, and a `LocalFileBinding`,
then register it on a `LocalHFBackend` with `backend.add_adapter()`. The code is in
[LoRA and aLoRA adapters](../../docs/advanced/lora-and-alora-adapters.md), and
`stembolts_intrinsic.py` is the helper module `102_example.py` imports to load the
`stembolts` adapter; replace its `repo_id` (`nfulton/stembolts`) with `$HF_USERNAME/stembolts` to use your
own upload. A custom, non-catalog adapter has no catalog entry to resolve `revision`
from, so pin it explicitly (`revision="main"`).
16 changes: 16 additions & 0 deletions docs/examples/aLora/example_readme_generator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# pytest: skip, huggingface, e2e
# SKIP REASON: documentation only.
"""Generating a Hugging Face README for a trained adapter programmatically.

Demonstrates calling `generate_readme()` directly, which is the same code path as
the `m alora add-readme` command. A `MelleaSession` analyzes the training dataset
and writes a model README (description, data examples, integration code) to
`stembolts_model_readme.md`. Replace the placeholder `name` with your own
`<hf-username>/<adapter-name>`; `hints` and `prompt_file` are optional.

Prerequisites:
uv sync --extra cli
ollama serve
ollama pull granite4.2:3b

Usage:
cd docs/examples/aLora && uv run python example_readme_generator.py
"""

from cli.alora.readme_generator import generate_readme, make_readme_jinja_dict

Expand Down
13 changes: 13 additions & 0 deletions docs/examples/aLora/make_training_data.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# pytest: skip, huggingface, e2e
# SKIP REASON: documentation only.
r"""Converting raw JSONL into the `{item, label}` training format for aLoRA training.

Reads a JSONL file whose rows carry `item`, `defective_part`, and `diag_likelihood`
(such as `stembolt_customer_data.jsonl`), validates each label against the
stembolt response schema, and writes rows of the form
`{"item": ..., "label": "<json string>"}` — the format `m alora train` expects (see
`stembolt_failure_dataset.jsonl`). Output goes to stdout unless `-o` is given.

Usage:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the trailing \ sits inside a regular (non-raw) docstring, so Python treats it as a line continuation and joins the two lines. ast.get_docstring gives you the command on one line with a stretch of spaces before the file name. It's cosmetic, since it only shows in help() or generated docs, but making it r""" or putting the command on one line avoids it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used r""" here and in a couple of others too where the command is long.

uv run python docs/examples/aLora/make_training_data.py \
docs/examples/aLora/stembolt_customer_data.jsonl -o training_data.jsonl
"""

import argparse
import json
import sys
Expand Down
9 changes: 9 additions & 0 deletions docs/examples/aLora/stembolts_intrinsic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
most catalog adapters use. It is invoked directly via `Intrinsic`/`mfuncs.act()`
and the raw JSON is returned to the caller — it is not a pass/fail
`ALoraRequirement` validator. Consumed by `102_example.py` in this directory.

This module has no standalone entry point and is not run directly.

Prerequisites:
uv sync --extra hf

Usage:
See `102_example.py`, which imports `stembolt_failure_analysis()` and
`async_stembolt_failure_analysis()` from this module.
"""

import mellea.stdlib.functional as mfuncs
Expand Down
Loading
Loading