LLM Finetuning Toolkit: YAML-Driven Fine-Tuning, Ablation and QA for Open-Source Models
Toolkit for fine-tuning, ablating and unit-testing open-source LLMs.
At a glance
- What is it?
- georgian-io's llm-toolkit wraps data ingestion, LoRA or QLoRA training, inference and rule-based QA into a single YAML config, then hashes that config so runs resume instead of restarting. It is built for ablation studies, not for production training pipelines.
- Who is it for?
- Adopt llm-toolkit if you are running comparative experiments across prompt templates, base checkpoints and LoRA ranks, and you want the run bookkeeping and QA CSVs handled for you. Do not adopt it if you need a maintained training stack, a serving path, or evaluation beyond string-length and word-overlap checks.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 134 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The ablation bookkeeping problem this toolkit targets
Fine-tuning an open-source LLM is not one training run. It is a grid: several prompt templates, several base checkpoints, a couple of LoRA ranks, quantization on or off. Each cell produces a dataset split, a set of adapter weights, a prediction file and some measure of whether the output is any good. Doing that by hand means either copying a training script N times or writing a loop that quietly loses track of which directory belongs to which hyperparameter combination. The README frames the tool as a "config-based CLI tool for launching a series of LLM fine-tuning experiments on your data and gathering their results," and that framing is the actual product. The training loop itself is a thin layer over Hugging Face Transformers, PEFT and bitsandbytes. The value is in the outer loop: one YAML file describes the sweep, and the tool fans it out. The audience is an ML engineer or researcher who already knows how to fine-tune a model and does not want to rewrite the plumbing every time the experiment matrix changes. It is not aimed at someone who has never run a Trainer before, and the README assumes familiarity with concepts like LoRA rank, 4-bit quantization types and train/test splits.
What the YAML config actually controls
The configuration is split into sections that map onto pipeline stages: data ingestion, model definition, LoRA parameters, training, inference and quality assurance. Data ingestion takes a file_type of huggingface, json or csv plus a path. For Hugging Face datasets the README's example uses yahma/alpaca-cleaned. The prompt block is a template string with {column_name} placeholders, and the README states plainly that it "reads data from specific columns, mentioned in {} brackets, that are present in your dataset." A detail worth flagging: prompt and prompt_stub are both used during fine-tuning, but during testing only the prompt section is fed to the model. That asymmetry is deliberate (the stub usually holds the target output, which you obviously cannot pass at inference), but it means a malformed stub will degrade training data without any obvious error at test time. The model section takes hf_model_ckpt, and the README gives Mistral-7B-v0.1, falcon-7b and Llama-2-7b-hf as examples, with the caveat that "in theory, any open-source LLM supported by Hugging Face can be used." Quantization is configured through a bitsandbytes block with load_in_4bit, bnb_4bit_compute_dtype and bnb_4bit_quant_type, and LoRA through task_type, r, lora_dropout and an explicit target_modules list. That list matters: the README's example enumerates q_proj, v_proj, k_proj, o_proj, up_proj, down_proj and gate_proj, which is a Llama-family attention and MLP layout. Point the same list at a checkpoint with differently named projections and you get a silent no-op or an error, and the README does not document a fallback.
Install, first run, and the two commands that matter
Installation is a single package. The README recommends pipx because it "installs the package and dependencies in a separate virtual environment": pipx install llm-toolkit. Plain pip install llm-toolkit is the alternative. From there the basic path is two commands: llmtune generate config writes a starter config.yml into the current working directory, and llmtune run ./config.yml executes it. The README also shows a direct invocation, python toolkit.py --config-path <path to custom YAML file>, which suggests the CLI is a wrapper around a script rather than the only entry point. Flash Attention 2 requires an extra step, because the package is not a normal wheel: pipx inject llm-toolkit flash-attn --pip-args=--no-build-isolation, or pip install flash-attn --no-build-isolation. Only then do you add attn_implementation: "flash_attention_2" under model, alongside torch_dtype set to bfloat16 or float16 "if using older GPU." The --no-build-isolation flag is a real constraint, not a stylistic choice: flash-attn compiles against the installed torch, so it needs to see the environment rather than a clean build sandbox. If your CUDA toolkit and torch build disagree, that install is where the run dies, before any config is parsed.
Artifacts, config hashing, and how resume works
Every run writes to ./experiment/[unique_hash]. The README states that "each unique configuration will generate a unique hash, so that our tool can automatically pick up where it left off," and gives the concrete case: if you exit mid-training and relaunch, the program loads the existing generated dataset from that directory instead of regenerating it. The artifacts are four directories. /dataset holds a generated pkl file in Hugging Face datasets format. /model holds PEFT adapter weights in HF format. /results is a CSV of prompt, ground truth and predicted values. /qa is a CSV of test results, described in the README as "e.g. vector similarity between ground truth and prediction." The hash keyed on config is the design decision that makes or breaks this tool in practice. It gives you free caching and a natural experiment index. It also means that editing anything in the config, including something cosmetic like a comment-adjacent string, produces a new hash and a fresh run, while editing the code that consumes the config does not. There is no documented migration or invalidation story for stale experiment directories, and no documented way to force a rerun of a cached stage short of changing the config or deleting the directory.
The QA layer is assertion checks, not evaluation
The qa section takes a list of llm_metrics, with length_test and word_overlap_test as the documented options. The README's own framing is a unit-testing analogy: "to ensure that the fine-tuned LLM behaves as expected, you can add tests that check if the desired behaviour is being attained." The summarization example is explicit. You might check that the generated summary is shorter than the input, and measure word overlap between source and summary. These are cheap, deterministic, and useful as regression guards when you change a prompt template or bump LoRA rank. They are also not quality metrics. A summary can be shorter than its input and share half its vocabulary while being useless. Nothing in the supplied material mentions perplexity, ROUGE, BERTScore, an LLM-as-judge, or any human review workflow. If your ablation study's conclusion depends on output quality rather than output shape, this QA layer will not produce the number you need, and the /results CSV is the raw material you would have to score yourself.
Where the toolkit is the wrong tool
Three failure modes are visible from the material. First, scope creep into production. The output is a PEFT adapter in HF format plus a results CSV. There is no serving component, no adapter merging step, no quantization-for-inference path documented here. Treating a run directory as a deployable artifact skips work the toolkit does not do. Second, the dependency surface. The stack is Transformers, PEFT, bitsandbytes, datasets and optionally flash-attn, all of which move quickly and have historically been sensitive to exact version pairings. The latest release listed is v0.2.3 from July 2024, while the repository's last push is dated 2026. That gap between release cadence and repository activity is the thing to check before you build on it: it may mean the project is maintained on main without tagged releases, or it may mean the release artifacts lag well behind. The supplied material does not resolve which. Third, model coverage claims. "Any open-source LLM supported by Hugging Face" is the README's phrasing, but the LoRA target_modules list and the CAUSAL_LM task type are the only ones shown, and no classification or seq2seq config example appears in the material despite the repository topics listing classification and flan-t5. Verify your architecture against a working config before assuming it is covered.
How it differs from Axolotl and raw PEFT scripts
The closest comparison is Axolotl, another YAML-configured fine-tuning tool. The difference is in what the YAML is for. Axolotl's config describes one training run in depth: dataset formats, sequence packing, optimizer schedules, DeepSpeed and FSDP settings, and it scales to multi-GPU. llm-toolkit's config describes a sweep. The README's advanced section shows a prompt field that is a YAML list of templates to "iterate over," and an hf_model_ckpt that is a list of checkpoints. That list-valued config is the whole point, and Axolotl does not express it in the same file. The trade is depth for breadth. You get the ablation matrix, the config hash and the QA CSVs; you give up the distributed-training knobs and the long tail of dataset format handling. Against a hand-rolled PEFT script, the difference is the artifact layout and the resume behavior. Anyone can write the training loop in fifty lines. Getting consistent experiment directories, cached dataset pickles and a results CSV per run without writing that bookkeeping is the reason to take on a dependency here.
Maintenance cost, licence, and what to check before adopting
The licence is Apache-2.0, which permits commercial use, modification and redistribution provided you keep the licence and notice files and state significant changes. That is a permissive baseline and it does not, on its own, settle anything about the models you fine-tune with it: Llama 2, Mistral and Falcon each carry their own licences and acceptable-use terms, and the toolkit does not mediate those. On maintenance, the concrete facts are a v0.2.x release line last tagged in July 2024 and a repository last pushed in 2026. Before adopting, do three things. Install into a throwaway environment with pipx install llm-toolkit and confirm the dependency set resolves against your torch and CUDA versions, since that is the most likely point of breakage. Run llmtune generate config and read the generated file end to end, because the README's config examples are truncated and the generated file is the authoritative schema. Then run one small experiment on a checkpoint you actually intend to use, checking that the /model directory contains adapter weights and that /qa contains rows, before you scale the config into a multi-prompt, multi-checkpoint sweep.
Editorial conclusion
Adopt llm-toolkit if you are running comparative experiments across prompt templates, base checkpoints and LoRA ranks, and you want the run bookkeeping and QA CSVs handled for you. Do not adopt it if you need a maintained training stack, a serving path, or evaluation beyond string-length and word-overlap checks. Before committing, verify that the pinned dependencies in the current release still resolve against your PyTorch and CUDA versions, and read the config schema in the generated config.yml rather than trusting the README snippets, which are truncated mid-example.
Community notes