# NEXS LoRA Adapters — Serving & Evaluation Guide
Rank-128 LoRA adapters extracted with
[mergekit](https://github.com/arcee-ai/mergekit) from domain fine-tunes and
sanitized for vLLM serving (pure `lora_A`/`lora_B` weights only;
`modules_to_save` tensors stripped, `modules_to_save: null` in configs; no
`resize_token_embeddings()` needed). Two families:
- **Llama-3.1-8B** — five adapters (finance, legal, medical, toxicity,
truthfulness), 224 A/B pairs each (32 layers × q/k/v/o/gate/up/down).
- **Qwen3-32B** — six adapters (instruction-following, medical ×2,
theorem proving, Russian ×2), 448 A/B pairs each (64 layers × 7 projections).
## Llama-3.1-8B adapters on the Hub
| Domain | HF repo | Extracted from |
|---|---|---|
| finance | [anjohn0077/NEXS-finance-lora](https://huggingface.co/anjohn0077/NEXS-finance-lora) | mukaj/Llama-3.1-Hawkish-8B |
| legal | [anjohn0077/NEXS-legal-lora](https://huggingface.co/anjohn0077/NEXS-legal-lora) | MaziyarPanahi/calme-2.3-legalkit-8b |
| medical | [anjohn0077/NEXS-medical-lora](https://huggingface.co/anjohn0077/NEXS-medical-lora) | TsinghuaC3I/Llama-3.1-8B-UltraMedical |
| toxicity | [anjohn0077/NEXS-toxicity-lora](https://huggingface.co/anjohn0077/NEXS-toxicity-lora) | K-intelligence/Llama-SafetyGuard-Content-Binary |
| truthfulness | [anjohn0077/NEXS-truthfulness-lora](https://huggingface.co/anjohn0077/NEXS-truthfulness-lora) | HiTZ/Llama-3.1-8B-Instruct-multi-truth-judge |
Index/manifest repo: [anjohn0077/NEXS-lora-adapters](https://huggingface.co/anjohn0077/NEXS-lora-adapters)
## Qwen3-32B adapters on the Hub
| Name | HF repo | Extracted from | Notes |
|---|---|---|---|
| IF | [anjohn0077/NEXS-qwen3-32b-IF-lora](https://huggingface.co/anjohn0077/NEXS-qwen3-32b-IF-lora) | qihoo360/Light-IF-32B | instruction following |
| medical-openmedzoo | [anjohn0077/NEXS-qwen3-32b-medical-openmedzoo-lora](https://huggingface.co/anjohn0077/NEXS-qwen3-32b-medical-openmedzoo-lora) | OpenMedZoo/MedGo | |
| medical-tachyhealth | [anjohn0077/NEXS-qwen3-32b-medical-tachyhealth-lora](https://huggingface.co/anjohn0077/NEXS-qwen3-32b-medical-tachyhealth-lora) | TachyHealth/Gazal-R1-32B-sft-merged-preview | fp32 tensors (4.3 GB) |
| prover | [anjohn0077/NEXS-qwen3-32b-prover-lora](https://huggingface.co/anjohn0077/NEXS-qwen3-32b-prover-lora) | Goedel-LM/Goedel-Prover-V2-32B | not yet benchmarked |
| russian-refalmachine | [anjohn0077/NEXS-qwen3-32b-russian-refalmachine-lora](https://huggingface.co/anjohn0077/NEXS-qwen3-32b-russian-refalmachine-lora) | RefalMachine/RuadaptQwen3-32B-Instruct | |
| russian-t-tech | [anjohn0077/NEXS-qwen3-32b-russian-t-tech-lora](https://huggingface.co/anjohn0077/NEXS-qwen3-32b-russian-t-tech-lora) | t-tech/T-pro-it-2.0 | |
## Serve the five Llama adapters with vLLM
Directly from the Hub (vLLM downloads the adapters itself; requires
`hf auth login` or `HF_TOKEN` for the gated base model):
```bash
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-8B \
--enable-lora \
--lora-modules \
finance=anjohn0077/NEXS-finance-lora \
legal=anjohn0077/NEXS-legal-lora \
medical=anjohn0077/NEXS-medical-lora \
toxicity=anjohn0077/NEXS-toxicity-lora \
truthfulness=anjohn0077/NEXS-truthfulness-lora \
--port 8000 \
--max-loras 5 \
--max-lora-rank 128 \
--gpu-memory-utilization 0.85
```
Or from the local sanitized copies (on this cluster):
```bash
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-8B \
--enable-lora \
--lora-modules \
finance=/scratch/shared_dir/lora/llama/finance_sanitized \
legal=/scratch/shared_dir/lora/llama/legal_sanitized \
medical=/scratch/shared_dir/lora/llama/medical_sanitized \
toxicity=/scratch/shared_dir/lora/llama/toxicity_sanitized \
truthfulness=/scratch/shared_dir/lora/llama/truthfulness_sanitized \
--port 8000 \
--max-loras 5 \
--max-lora-rank 128 \
--gpu-memory-utilization 0.85
```
To fetch the Hub copies to a local directory instead:
```bash
for d in finance legal medical toxicity truthfulness; do
hf download "anjohn0077/NEXS-${d}-lora" --local-dir "./adapters/${d}"
done
```
## Serve the six Qwen3-32B adapters with vLLM
The base model is ~65 GB in bf16; one 141 GB H200 fits the model, all six
adapters, and KV cache at `--gpu-memory-utilization 0.85`.
```bash
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen3-32B \
--enable-lora \
--lora-modules \
IF=anjohn0077/NEXS-qwen3-32b-IF-lora \
medical_openmedzoo=anjohn0077/NEXS-qwen3-32b-medical-openmedzoo-lora \
medical_tachyhealth=anjohn0077/NEXS-qwen3-32b-medical-tachyhealth-lora \
prover=anjohn0077/NEXS-qwen3-32b-prover-lora \
russian_refalmachine=anjohn0077/NEXS-qwen3-32b-russian-refalmachine-lora \
russian_t_tech=anjohn0077/NEXS-qwen3-32b-russian-t-tech-lora \
--port 8000 \
--max-loras 6 \
--max-lora-rank 128 \
--gpu-memory-utilization 0.85
```
Or from the local sanitized copies (on this cluster), replace each repo id
with `/scratch/shared_dir/lora/qwen/
_sanitized` (dirs: `IF_sanitized`,
`medical_OpenMedZoo_sanitized`, `medical_TachyHealth_sanitized`,
`prover_sanitized`, `russian_RefalMachine_sanitized`,
`russian_t-tech_sanitized`).
## Evaluate with lm-evaluation-harness
With a server running on port 8000, each adapter is addressed by the name
given in `--lora-modules`. Llama family:
```bash
lm_eval --model local-completions \
--model_args model=finance,base_url=http://localhost:8000/v1/completions,tokenizer=meta-llama/Llama-3.1-8B,num_concurrent=10 \
--tasks mmlu_econometrics \
--output_path results/vllm_finance
lm_eval --model local-completions \
--model_args model=legal,base_url=http://localhost:8000/v1/completions,tokenizer=meta-llama/Llama-3.1-8B,num_concurrent=10 \
--tasks mmlu_professional_law \
--output_path results/vllm_legal
lm_eval --model local-completions \
--model_args model=medical,base_url=http://localhost:8000/v1/completions,tokenizer=meta-llama/Llama-3.1-8B,num_concurrent=10 \
--tasks mmlu_professional_medicine \
--output_path results/vllm_medical
lm_eval --model local-completions \
--model_args model=toxicity,base_url=http://localhost:8000/v1/completions,tokenizer=meta-llama/Llama-3.1-8B,num_concurrent=10 \
--tasks sst2 \
--output_path results/vllm_toxicity_sst2
lm_eval --model local-completions \
--model_args model=truthfulness,base_url=http://localhost:8000/v1/completions,tokenizer=meta-llama/Llama-3.1-8B,num_concurrent=10 \
--tasks truthfulqa_mc2 \
--output_path results/vllm_truthfulness
```
Qwen3-32B family (note `tokenizer=Qwen/Qwen3-32B`):
```bash
lm_eval --model local-completions \
--model_args model=IF,base_url=http://localhost:8000/v1/completions,tokenizer=Qwen/Qwen3-32B,num_concurrent=10 \
--tasks ifeval \
--output_path results/vllm_qwen_IF
lm_eval --model local-completions \
--model_args model=medical_openmedzoo,base_url=http://localhost:8000/v1/completions,tokenizer=Qwen/Qwen3-32B,num_concurrent=10 \
--tasks medqa_4options \
--output_path results/vllm_qwen_medical_openmedzoo
lm_eval --model local-completions \
--model_args model=medical_tachyhealth,base_url=http://localhost:8000/v1/completions,tokenizer=Qwen/Qwen3-32B,num_concurrent=10 \
--tasks medqa_4options \
--output_path results/vllm_qwen_medical_tachyhealth
lm_eval --model local-completions \
--model_args model=russian_refalmachine,base_url=http://localhost:8000/v1/completions,tokenizer=Qwen/Qwen3-32B,num_concurrent=10 \
--tasks m_mmlu_ru \
--output_path results/vllm_qwen_russian_refalmachine
lm_eval --model local-completions \
--model_args model=russian_t_tech,base_url=http://localhost:8000/v1/completions,tokenizer=Qwen/Qwen3-32B,num_concurrent=10 \
--tasks m_mmlu_ru \
--output_path results/vllm_qwen_russian_t_tech
```
(The prover adapter's intended minif2f evaluation has not produced results
yet, so it ships unbenchmarked.)
## Benchmark results
Accuracy of each LoRA served on the base model via vLLM, compared against the
plain base model and the original full fine-tune it was extracted from.
Llama-3.1-8B family:
| Domain | Benchmark | Base | LoRA (vLLM) | Full fine-tune |
|---|---|---|---|---|
| finance | mmlu_econometrics | 0.4825 | 0.4561 | 0.5526 |
| legal | mmlu_professional_law | 0.4941 | 0.4915 | 0.4948 |
| medical | mmlu_professional_medicine | 0.7169 | 0.7059 | 0.7721 |
| toxicity | sst2 | 0.6732 | 0.8991 | 0.8899 |
| truthfulness | truthfulqa_mc2 | 0.4416 | 0.7164 | 0.7307 |
Note: toxicity and truthfulness recover nearly all (or more than) the
fine-tune's gains; finance/medical/legal LoRAs land close to base — most of
those fine-tunes' improvement lived in the full-rank embedding/head deltas
that vLLM cannot serve and were stripped during sanitization.
Qwen3-32B family (from `qwen32b_adapter_acc.csv`):
| Adapter | Benchmark | Base | LoRA (vLLM) | Full fine-tune |
|---|---|---|---|---|
| IF | ifeval | 0.8336 | 0.2737 | 0.8669 |
| medical-openmedzoo | medqa_4options | 0.7494 | 0.7604 | 0.7596 |
| medical-tachyhealth | medqa_4options | 0.7494 | 0.7455 | 0.7478 |
| russian-refalmachine | m_mmlu_ru | 0.7517 | 0.7524 | 0.7370 |
| russian-t-tech | m_mmlu_ru | 0.7517 | 0.7542 | 0.7679 |
| prover | minif2f | — | — | — |
Notes: the IF LoRA scores far below base on ifeval (0.2737 vs 0.8336) — the
low-rank approximation appears to break the fine-tune's instruction-following
behavior rather than approximate it; it is published for completeness with
these honest numbers. The medical and russian adapters track their full
fine-tunes closely. prover has not been benchmarked (its minif2f run produced
no results), but it passes structural validation and serves through vLLM.
## Dependencies (for replication)
All extraction, sanitization, serving, and evaluation ran in a single Python
virtualenv on Linux with NVIDIA H200 GPUs (driver 595.71.05). Exact versions:
| Component | Version | Notes |
|---|---|---|
| Python | 3.12.3 | |
| torch | 2.9.1 | CUDA 12.8 build (`2.9.1+cu128`) |
| mergekit | 0.1.4 | **fork**: [ikhyunAn/mergekit](https://github.com/ikhyunAn/mergekit) @ `e85a454`, editable install — not upstream arcee-ai/mergekit |
| vllm | 0.15.1 | |
| transformers | 4.57.1 | |
| peft | 0.15.2 | |
| huggingface-hub | 0.35.3 | pinned `<1.0` (required by transformers 4.57.1) |
| safetensors | 0.5.3 | |
| accelerate | 1.6.0 | |
| tokenizers | 0.22.1 | |
| xformers | 0.0.32.post1 | |
| numpy | 2.2.6 | |
| lm_eval | 0.4.9.1 | [EleutherAI/lm-evaluation-harness](https://github.com/EleutherAI/lm-evaluation-harness) @ `ad3f4d0c`, editable install |
To recreate the core environment:
```bash
python3.12 -m venv lora-env && source lora-env/bin/activate
pip install torch==2.9.1 --index-url https://download.pytorch.org/whl/cu128
pip install vllm==0.15.1 transformers==4.57.1 peft==0.15.2 \
"huggingface_hub==0.35.3" safetensors==0.5.3 accelerate==1.6.0
pip install -e "git+https://github.com/ikhyunAn/mergekit.git@e85a454#egg=mergekit"
pip install -e "git+https://github.com/EleutherAI/lm-evaluation-harness.git@ad3f4d0c#egg=lm_eval"
```
Caveats:
- Do **not** upgrade `huggingface_hub` past 1.0 in this environment —
transformers 4.57.1 pins `huggingface-hub<1.0` and both transformers and
mergekit break at import time with 1.x.
- Extraction used a single GPU (`CUDA_VISIBLE_DEVICES=` with
`mergekit-extract-lora --cuda`); each 8B extraction takes ~4 minutes on an
H200 and peaks around 2×16 GB of downloaded weights in the HF cache.
## Provenance / pipeline
1. Extraction: `mergekit-extract-lora --model --base-model
--out-path --cuda` with base `meta-llama/Llama-3.1-8B` for the
llama family (see `extract_and_upload_loras.sh`; raw outputs in
`/scratch/shared_dir/lora/llama//`) and `Qwen/Qwen3-32B` for the
qwen family (raw outputs in `/scratch/shared_dir/lora/qwen/`).
2. Sanitization (same script set in `/scratch/shared_dir/lora/llama/` and
`/scratch/shared_dir/lora/qwen/`): `fix_adapters.py` (drop norm layers) →
`fix_vllm_weights.py` / `final_clean.py` (drop all non-`lora_*` keys, null
out `modules_to_save`) → `verify_all_clean.py`. For llama, toxicity's
extended vocab (128258) was truncated to the base 128256 first via
`fix_toxicity_vocab.py`.
3. Upload: `upload_sanitized_loras.py` (llama) and `upload_qwen_loras.py`
(qwen), both in this directory, push each sanitized adapter to its Hub
repo with an updated README.