LLaMA Factory is a unified framework for efficiently fine-tuning 100+ large language models. This guide covers architecture, configuration, deployment, security, and developer internals for administrators, operators, and contributors working with the system at a production level.
For everyday usage, CLI commands, and getting-started workflows, see the User Guide.
1. Architecture Overview
1.1 Dual-Engine Design
LLaMA Factory ships two complete training engines selectable at runtime. Both share the same CLI entry point (llamafactory-cli / lmf) and configuration surface, but differ fundamentally in extensibility and internal design.
| Aspect | Legacy Engine (default) | V1 Engine (USE_V1=1) |
|---|---|---|
| Entry point | cli.py → launcher.py |
cli.py → v1/launcher.py |
| Training loop | HuggingFace Trainer subclasses | Custom BaseTrainer.fit() with micro-batching |
| Extensibility | Monolithic, modify source | Plugin registry (BasePlugin pattern) |
| Distributed | Accelerate / DeepSpeed via HF | Native DeepSpeed, FSDP2, DDP |
| Supported stages | SFT, DPO, KTO, PPO, RM, PT | SFT, DPO, RM |
| Maturity | Production-proven | Newer, plugin-oriented |
Important
The V1 engine is activated exclusively via the
USE_V1=1environment variable. There is no YAML flag or CLI switch. All V1-specific configuration (plugin configs, batching strategies) is ignored when V1 is not active.
1.2 Legacy Engine Module Map
src/llamafactory/
├── cli.py # Entry point, dispatches commands
├── launcher.py # Command dispatch, torchrun auto-launch
├── train/
│ └── tuner.py # Stage router → per-stage workflows
│ ├── sft/ # Supervised fine-tuning
│ ├── dpo/ # Direct preference optimization
│ ├── kto/ # KTO training
│ ├── ppo/ # Proximal policy optimization
│ ├── rm/ # Reward modeling
│ └── pt/ # Pretraining / continued pretraining
├── model/ # Model loading, adapter mgmt, quantization
├── data/ # Data loading, template system, multimodal, tool formatting
├── hparams/ # Argument dataclasses
├── chat/ # ChatModel (HF, vLLM, SGLang, KTransformers engines)
├── webui/ # Gradio-based LlamaBoard
├── api/ # FastAPI OpenAI-compatible server
├── eval/ # Evaluation (deprecated)
└── extras/ # Constants, env detection, logging, misc, package checks
1.3 V1 Engine Module Map
src/llamafactory/v1/
├── launcher.py # V1 command dispatch
├── core/
│ ├── data_engine.py # torch Dataset from YAML/HF Hub/local
│ ├── model_engine.py # Model init, PEFT, quantization, kernels
│ ├── base_trainer.py # Training loop with micro-batch accumulation
│ ├── base_sampler.py # Inference engine
│ └── utils/
│ ├── batching.py # BatchGenerator with strategies
│ ├── checkpoint.py # Distributed checkpoint save/resume
│ └── rendering.py # ChatML message rendering
├── config/ # OmegaConf + HfArgumentParser arg parsing
├── plugins/
│ ├── data_plugins/ # Data loading + conversion (alpaca, pair)
│ ├── model_plugins/ # Init, PEFT (LoRA), quant, kernels, templates, parallelization
│ ├── trainer_plugins/ # Optimizer, LR scheduler, distributed (DeepSpeed, FSDP2, Hub)
│ └── sampler_plugins/ # vLLM sampler
├── trainers/ # SFTTrainer, DPOTrainer, RMTrainer
├── samplers/ # CLISampler
├── accelerator/ # DistributedInterface, profiler
└── utils/ # Types, logging, plugin system, helpers, constants
1.4 Command Dispatch Flow
llamafactory-cli <command>
│
▼
cli.py ─── USE_V1=1? ───► v1/launcher.py
│ no │
▼ ▼
launcher.py V1 dispatch
│ (train/chat)
▼
Dispatch table:
train → train/tuner.py → stage-specific workflow
api → api/app.py (FastAPI + Uvicorn)
chat → chat/ChatModel (interactive CLI)
export → model export pipeline
webchat → Gradio chat interface
webui → LlamaBoard (full Gradio UI)
env → print environment info
version → print version
When the command is train and multiple GPUs are detected (or FORCE_TORCHRUN=1), launcher.py automatically re-launches the process under torchrun with appropriate distributed arguments.
1.5 Data Flow — Training Pipeline
YAML config ──► hparams parsing ──► DataEngine/DataLoader
│
Model loading ◄──────────┘
│
▼
Trainer.fit() / HF Trainer.train()
│
├── Forward pass (micro-batch)
├── Loss computation (stage-specific)
├── Backward + gradient accumulation
├── Optimizer step + LR schedule
└── Checkpoint save (every N steps)
│
▼
Output: adapter weights / merged model / checkpoints
2. System Requirements
2.1 Software Dependencies
| Dependency | Minimum Version | Purpose |
|---|---|---|
| Python | 3.9+ | Runtime |
| PyTorch | 2.x | Training framework |
| Transformers | 5.x+ | Model loading, tokenizers |
| PEFT | latest | LoRA and adapter methods |
| DeepSpeed | 0.14+ | ZeRO optimization, offloading |
| Accelerate | latest | Distributed training orchestration |
| Gradio | 4.x | WebUI (LlamaBoard) |
| FastAPI | latest | API server |
| Uvicorn | latest | ASGI server |
| OmegaConf | latest | V1 config parsing |
| Pydantic | 2.x | API protocol models |
2.2 Hardware Guidelines
| Scenario | GPU Memory | Recommended Setup |
|---|---|---|
| QLoRA 7B model | 8-16 GB | Single consumer GPU (RTX 3090/4090) |
| LoRA 7B model | 16-24 GB | Single A100/H100 or RTX 4090/5090 |
| Full fine-tune 7B | 80+ GB | Multi-GPU (2-4x A100 80GB) |
| Full fine-tune 70B | 320+ GB | 4-8x A100/H100, ZeRO-3 offload |
| LoRA 70B model | 40-80 GB | 1-2x A100 80GB with 4-bit quantization |
Note
VRAM usage varies significantly with
cutoff_len,micro_batch_size, and quantization settings. UseRECORD_VRAM=1to profile actual consumption during a short test run before committing to long training jobs.
2.3 Docker Images
Three official Docker images target different accelerator stacks:
| Image | Path | Base | Target Hardware |
|---|---|---|---|
| CUDA | docker/docker-cuda/ |
NVIDIA CUDA | NVIDIA GPUs |
| ROCm | docker/docker-rocm/ |
AMD ROCm | AMD GPUs |
| NPU | docker/docker-npu/ |
Ascend CANN | Huawei Ascend NPUs |
Each includes a Dockerfile with all dependencies pre-installed. Build with standard Docker commands from the respective directory.
3. Configuration Reference
3.1 Legacy Engine Arguments
The legacy engine uses six argument dataclasses parsed from YAML config files:
| Dataclass | Key Fields |
|---|---|
ModelArguments |
model_name_or_path, adapter_name_or_path, quantization_bit, quantization_method |
DataArguments |
dataset, dataset_dir, template, cutoff_len, max_samples, streaming |
TrainingArguments |
Extends HF Seq2SeqTrainingArguments — output_dir, per_device_train_batch_size, learning_rate, num_train_epochs, bf16, deepspeed |
FinetuningArgs |
stage (sft/dpo/kto/ppo/rm/pt), finetuning_type (lora/full/freeze), lora_rank, lora_target |
GeneratingArgs |
temperature, top_p, top_k, max_new_tokens, repetition_penalty |
EvaluationArgs |
task, n_shot, batch_size |
Configuration is YAML-based. Example skeleton:
### model
model_name_or_path: meta-llama/Llama-2-7b-hf
### method
stage: sft
finetuning_type: lora
lora_rank: 8
lora_target: all
### dataset
dataset: alpaca_en
template: llama2
cutoff_len: 1024
### output
output_dir: saves/llama2-7b/lora/sft
logging_steps: 10
save_steps: 500
### train
per_device_train_batch_size: 2
gradient_accumulation_steps: 4
learning_rate: 1.0e-4
num_train_epochs: 3.0
bf16: true
3.2 V1 Engine Arguments
The V1 engine uses OmegaConf combined with HfArgumentParser, providing a cleaner configuration surface:
ModelArguments:
| Field | Default | Description |
|---|---|---|
model |
Qwen/Qwen3-4B-Instruct-2507 |
Model name or path |
template |
qwen3_nothink |
Chat template name |
trust_remote_code |
(False) | Allow remote code execution |
model_class |
llm |
Model class: llm, cls, or other |
init_config |
(PluginConfig) | Initialization plugin config |
peft_config |
(PluginConfig) | PEFT plugin config (LoRA, etc.) |
kernel_config |
(PluginConfig) | Kernel plugin config (NPU ops) |
quant_config |
(PluginConfig) | Quantization plugin config |
TrainingArguments:
| Field | Default | Description |
|---|---|---|
output_dir |
auto-generated UUID | Output directory |
micro_batch_size |
1 |
Per-device micro-batch size |
global_batch_size |
None (auto) |
Total batch across all devices |
cutoff_len |
2048 |
Maximum sequence length |
learning_rate |
1e-4 |
Initial learning rate |
num_train_epochs |
3 |
Number of training epochs |
max_steps |
None |
Override epoch-based with step count |
max_grad_norm |
1.0 |
Gradient clipping threshold |
bf16 |
True |
Use bfloat16 precision |
batching_strategy |
normal |
One of: normal, padding_free, dynamic_batching, dynamic_padding_free |
batching_workers |
16 |
Data loading workers |
enable_activation_checkpointing |
True |
Gradient checkpointing |
dist_config |
(PluginConfig) | Distributed training plugin |
optim_config |
(PluginConfig) | Optimizer plugin |
lr_scheduler_config |
(PluginConfig) | LR scheduler plugin |
seed |
42 |
Random seed |
resume_from_checkpoint |
None |
Path or "auto" for latest |
save_steps |
(None) | Save every N steps |
save_epochs |
(None) | Save every N epochs |
save_ckpt_as_hf |
False |
Convert checkpoints to HF format |
save_total_limit |
None |
Max checkpoints to keep |
logging_steps |
1 |
Log every N steps |
DataArguments:
| Field | Default | Description |
|---|---|---|
train_dataset |
(required) | Training dataset specification |
eval_dataset |
None |
Evaluation dataset specification |
SampleArguments:
| Field | Default | Description |
|---|---|---|
sample_backend |
hf |
Inference backend: hf or vllm |
max_new_tokens |
128 |
Max generation length |
Tip
V1 plugin configs use a nested structure with a mandatory
namefield. For example, to configure LoRA in V1:peft_config: name: lora r: 16 lora_alpha: 32 target_modules: all
3.3 V1 Batching Strategies
| Strategy | Description | Use Case |
|---|---|---|
normal |
Standard padding to max length in batch | Default, simplest |
padding_free |
No padding, sequences concatenated | Memory-efficient for variable-length data |
dynamic_batching |
Batches adjusted by token budget | Best throughput for diverse sequence lengths |
dynamic_padding_free |
Dynamic batching + no padding | Maximum memory efficiency |
3.4 Environment Variable Reference
Complete list of environment variables that control runtime behavior:
Engine Selection:
| Variable | Default | Description |
|---|---|---|
USE_V1 |
0 |
Enable V1 engine (1 to activate) |
API Server:
| Variable | Default | Description |
|---|---|---|
API_KEY |
None |
Bearer token for API authentication |
API_PORT |
8000 |
Server port |
API_HOST |
0.0.0.0 |
Server bind address |
API_MODEL_NAME |
gpt-3.5-turbo |
Model name returned in API responses |
FASTAPI_ROOT_PATH |
"" |
Root path prefix (for reverse proxies) |
SAFE_MEDIA_PATH |
api/safe_media |
Allowed local file access path |
ALLOW_LOCAL_FILES |
1 |
Enable local file access in API |
API_VERBOSE |
1 |
Verbose request logging |
MAX_CONCURRENT |
1 |
Maximum concurrent inference requests |
Logging & Debugging:
| Variable | Default | Description |
|---|---|---|
LLAMAFACTORY_VERBOSITY |
INFO |
Log level |
DISABLE_VERSION_CHECK |
0 |
Skip dependency version checks |
RECORD_VRAM |
0 |
Record VRAM usage during training |
ALLOW_EXTRA_KEYS |
0 |
Allow unknown keys in YAML configs |
Distributed Training:
| Variable | Default | Description |
|---|---|---|
FORCE_TORCHRUN |
0 |
Force torchrun launch even for single GPU |
USE_MCA |
0 |
Enable MCA (forces torchrun) |
OPTIM_TORCH |
1 |
Enable DDP optimizations (expandable_segments, NCCL) |
NNODES |
1 |
Number of training nodes |
NODE_RANK |
0 |
Current node rank in multi-node setup |
NPROC_PER_NODE |
auto-detect | GPUs per node |
MASTER_ADDR |
127.0.0.1 |
Master node address |
MASTER_PORT |
auto | Master node port |
Elastic Training:
| Variable | Default | Description |
|---|---|---|
RDZV_ID |
None |
Rendezvous ID for elastic launch |
MIN_NNODES |
None |
Minimum nodes for elastic training |
MAX_NNODES |
None |
Maximum nodes for elastic training |
MAX_RESTARTS |
0 |
Maximum worker restarts |
Model Hubs:
| Variable | Default | Description |
|---|---|---|
USE_MODELSCOPE_HUB |
0 |
Download models from ModelScope |
USE_OPENMIND_HUB |
0 |
Download models from OpenMind |
WebUI:
| Variable | Default | Description |
|---|---|---|
GRADIO_SERVER_NAME |
0.0.0.0 |
Gradio server bind address |
Warning
Setting
ALLOW_EXTRA_KEYS=1suppresses errors for unrecognized YAML keys. This is dangerous in production because typos in configuration fields will be silently ignored rather than caught at startup. Use only during development or migration.
4. Deployment & Scaling
4.1 Single-GPU Deployment
The simplest deployment for inference serving:
# Start API server with a LoRA adapter
llamafactory-cli api \
--model_name_or_path meta-llama/Llama-2-7b-hf \
--adapter_name_or_path saves/llama2-7b/lora/sft \
--template llama2 \
--finetuning_type lora
Or equivalently with a YAML config:
llamafactory-cli api path/to/config.yaml
4.2 Multi-GPU Training
LLaMA Factory auto-detects available GPUs and launches torchrun automatically. Manual control is available via environment variables:
# 4 GPUs on a single node
NPROC_PER_NODE=4 llamafactory-cli train config.yaml
# Force torchrun even on single GPU (useful for debugging distributed code)
FORCE_TORCHRUN=1 llamafactory-cli train config.yaml
4.3 Multi-Node Training
# Node 0 (master)
NNODES=2 NODE_RANK=0 MASTER_ADDR=10.0.0.1 MASTER_PORT=29500 \
NPROC_PER_NODE=8 llamafactory-cli train config.yaml
# Node 1
NNODES=2 NODE_RANK=1 MASTER_ADDR=10.0.0.1 MASTER_PORT=29500 \
NPROC_PER_NODE=8 llamafactory-cli train config.yaml
4.4 Elastic Training
For fault-tolerant training that can scale nodes dynamically:
RDZV_ID=my_job MIN_NNODES=2 MAX_NNODES=4 MAX_RESTARTS=3 \
NPROC_PER_NODE=8 llamafactory-cli train config.yaml
4.5 DeepSpeed Configurations
Pre-built DeepSpeed configs are provided in examples/deepspeed/:
| Config File | ZeRO Stage | Features |
|---|---|---|
ds_z0_config.json |
0 | No sharding (baseline) |
ds_z2_config.json |
2 | Optimizer + gradient sharding with auto tensor parallelism |
ds_z2_offload_config.json |
2 | Stage 2 + CPU offloading |
ds_z3_config.json |
3 | Full parameter sharding |
ds_z3_offload_config.json |
3 | Stage 3 + CPU offloading |
ds_z3_fp8_config.json |
3 | Stage 3 + FP8 precision |
Usage in legacy engine YAML:
deepspeed: examples/deepspeed/ds_z3_config.json
Usage in V1 engine:
dist_config:
name: deepspeed
config_file: examples/deepspeed/ds_z3_config.json
4.6 FSDP Configurations
Available FSDP configs in examples/accelerate/:
| Config | Description |
|---|---|
fsdp_config.yaml |
Standard FSDP |
fsdp2_config.yaml |
FSDP2 (newer PyTorch native) |
fsdp_config_offload.yaml |
FSDP with CPU offloading |
fsdp_config_multiple_nodes.yaml |
Multi-node FSDP |
4.7 Docker Deployment
# Build CUDA image
cd docker/docker-cuda
docker build -t llamafactory:cuda .
# Run training
docker run --gpus all -v /data/models:/models -v /data/output:/output \
llamafactory:cuda llamafactory-cli train /config/train.yaml
# Run API server
docker run --gpus all -p 8000:8000 \
-e API_KEY=your-secret-key \
-e API_MODEL_NAME=my-fine-tuned-model \
llamafactory:cuda llamafactory-cli api /config/api.yaml
Important
When running the API server in Docker, always set
API_KEYto a strong secret. The default configuration has no authentication, and CORS allows all origins.
4.8 Reverse Proxy Setup
When deploying behind a reverse proxy (nginx, Traefik), set the FASTAPI_ROOT_PATH environment variable to match the proxy's path prefix:
# If proxied at /llm/v1/
FASTAPI_ROOT_PATH=/llm API_PORT=8000 llamafactory-cli api config.yaml
5. Operations
5.1 Checkpoint Management
Legacy engine: Uses HuggingFace Trainer checkpointing. Checkpoints are saved to output_dir/checkpoint-{step}/.
V1 engine: Uses TrainingCheckpointCoordinator for distributed-safe checkpointing:
- Saves model state, optimizer state, LR scheduler state, batch generator state, and RNG states
resume_from_checkpoint: "auto"scansoutput_dirfor the latest checkpointsave_total_limitrotates old checkpoints to control disk usagesave_ckpt_as_hf: trueconverts distributed checkpoints to HuggingFace format (requires approximately 2x memory during save)
# V1 checkpoint config example
output_dir: /output/my-training-run
save_steps: 500
save_total_limit: 3
resume_from_checkpoint: auto
save_ckpt_as_hf: false
Caution
Setting
save_ckpt_as_hf: trueroughly doubles memory usage during checkpoint saves because the full model must be materialized in HuggingFace format. On memory-constrained setups, save in native format and convert post-training using the checkpoint conversion scripts.
5.2 Checkpoint Conversion Scripts
Located in scripts/convert_ckpt/:
| Script | Purpose |
|---|---|
llamafy_baichuan2.py |
Convert Baichuan2 to LLaMA format |
llamafy_qwen.py |
Convert Qwen to LLaMA format |
tiny_llama4.py |
Create tiny LLaMA4 for testing |
tiny_qwen3.py |
Create tiny Qwen3 for testing |
5.3 Dataset Registry
Datasets are registered in data/dataset_info.json. Each entry specifies:
{
"dataset_name": {
"file_name": "path/to/data.json",
"formatting": "alpaca",
"columns": {
"prompt": "instruction",
"query": "input",
"response": "output"
}
}
}
The V1 engine uses YAML-based dataset definitions with DatasetInfo objects supporting:
| Field | Description |
|---|---|
path |
Local path or HF Hub dataset ID |
source |
hf_hub, ms_hub, or local |
split |
Dataset split name |
converter |
Data converter plugin (alpaca, pair) |
size |
Dataset size hint |
weight |
Sampling weight for dataset mixing |
streaming |
Enable streaming mode |
Note
In the V1 engine, all datasets in a training run must be either all streaming or all non-streaming. Mixing modes produces the error: "All datasets must be streaming or non-streaming."
5.4 Monitoring & Logging
Log levels: Controlled via LLAMAFACTORY_VERBOSITY (values: DEBUG, INFO, WARNING, ERROR, CRITICAL).
VRAM profiling: Set RECORD_VRAM=1 to track GPU memory allocation throughout training.
Training metrics: Both engines log loss, learning rate, and throughput at intervals set by logging_steps.
External loggers: The legacy engine supports integration with MLflow, WandB, and TensorBoard via HuggingFace Trainer's reporting infrastructure.
5.5 Utility Scripts
Located in scripts/stat_utils/:
| Script | Purpose | Usage |
|---|---|---|
cal_flops.py |
Calculate model FLOPs | Pre-training capacity planning |
cal_mfu.py |
Calculate model FLU utilization | Measure hardware efficiency |
cal_ppl.py |
Calculate perplexity | Evaluate model quality |
cal_lr.py |
Calculate learning rate schedule | Visualize LR warmup/decay |
length_cdf.py |
Dataset length CDF | Choose appropriate cutoff_len |
5.6 Batch Size Constraints
The V1 engine enforces strict batch size relationships:
global_batch_size must be divisible by (data_parallel_size × micro_batch_size)
If global_batch_size is not set, it is computed automatically as micro_batch_size × data_parallel_size. Violations produce: "Global batch size must be divisible by DP size and micro batch size."
6. Performance
6.1 Memory Optimization Ladder
Listed from least to most aggressive, apply cumulatively as needed:
| Technique | Memory Savings | Config |
|---|---|---|
| BF16 training | ~50% vs FP32 | bf16: true |
| Gradient checkpointing | ~30-50% activation memory | V1: enable_activation_checkpointing: true; Legacy: gradient_checkpointing: true |
| LoRA | ~90% trainable params | finetuning_type: lora / V1: peft_config.name: lora |
| QLoRA (4-bit) | ~75% model memory | quantization_bit: 4 + LoRA |
| DeepSpeed ZeRO-2 | Shard optimizer + gradients | deepspeed: ds_z2_config.json |
| DeepSpeed ZeRO-3 | Shard everything | deepspeed: ds_z3_config.json |
| ZeRO-3 + CPU offload | Offload to system RAM | deepspeed: ds_z3_offload_config.json |
| Padding-free batching | Eliminate padding waste | V1: batching_strategy: padding_free |
6.2 Throughput Optimization
Batching strategy selection (V1):
normal: Safe default. Pads all sequences to the longest in the batch.padding_free: Concatenates sequences without padding. Best for datasets with high length variance. No wasted compute on pad tokens.dynamic_batching: Groups sequences by similar length into token-budget batches. Maximizes GPU utilization.dynamic_padding_free: Combines both strategies for maximum efficiency.
Data loading: batching_workers: 16 (V1 default) controls parallel data preprocessing. Increase on CPU-rich nodes; decrease if CPU is the bottleneck.
DDP optimization: OPTIM_TORCH=1 (default) enables PyTorch DDP optimizations including CUDA expandable memory segments and NCCL optimizations.
6.3 V1 Training Loop Internals
The BaseTrainer.fit() loop operates as follows:
- BatchGenerator initialization — creates batches according to the configured
batching_strategy - Optimizer creation — default AdamW, overridable via
optim_configplugin - LR scheduler creation — configurable via
lr_scheduler_configplugin - Training loop per step:
- Accumulate
Nmicro-batches (whereN = global_batch_size / (micro_batch_size × dp_size)) - Each micro-batch: forward → loss → backward
- Loss scaling uses valid-token weighting (not naive averaging)
- If DeepSpeed: engine handles backward pass and optimizer step
- If FSDP2/DDP: manual
clip_grad_norm_→optimizer.step()→scheduler.step()
- Accumulate
- Checkpoint save at configured intervals
- Callbacks fire at each logging step (LoggingCallback built-in, custom TrainerCallback supported)
6.4 Sequence Parallelism
The V1 engine supports Ulysses sequence parallelism for extremely long sequences via the model plugin system. Note the limitation: "Sequence parallel is not supported for qwen3.5 model."
6.5 NPU Kernel Optimizations
For Huawei Ascend NPUs, the V1 kernel plugin provides fused operations:
| Kernel | Operation |
|---|---|
fused_moe |
Fused Mixture-of-Experts |
swiglu |
Fused SwiGLU activation |
rms_norm |
Fused RMS normalization |
rope |
Fused rotary position embedding |
Configure via:
kernel_config:
name: npu
7. Security
7.1 API Authentication
The API server authenticates requests via Bearer token:
Authorization: Bearer <API_KEY>
Set via the API_KEY environment variable. When API_KEY is not set, the API operates without authentication.
Caution
Running the API server without
API_KEYset exposes the model to unauthenticated access. Always set a strong API key in production deployments.
7.2 CORS Policy
The API server allows all origins (*) by default. For production deployments behind a reverse proxy, configure CORS restrictions at the proxy level.
7.3 Local File Injection (LFI) Protection
The check_lfi_path() function in api/common.py restricts local file access to the directory specified by SAFE_MEDIA_PATH. Any request attempting to access files outside this boundary is rejected.
- Default
SAFE_MEDIA_PATH:api/safe_media(relative to working directory) ALLOW_LOCAL_FILES=0disables all local file access through the API
7.4 Server-Side Request Forgery (SSRF) Protection
The check_ssrf_url() function in api/common.py prevents the API from making requests to internal network resources:
- Blocks private IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, etc.)
- Blocks reserved/link-local addresses
- Validates HTTP and HTTPS schemes only
- Rejects URLs targeting internal services
7.5 Remote Code Execution
The trust_remote_code parameter (both engines) allows execution of arbitrary Python code bundled with model repositories. This is required by some models but represents a significant security risk.
Warning
Only enable
trust_remote_codefor models from trusted sources. Malicious model repositories can execute arbitrary code during model loading. In production, prefer models that do not require remote code.
7.6 Security Hardening Checklist
| Item | Action |
|---|---|
| API authentication | Set API_KEY to a strong random secret |
| Local file access | Set ALLOW_LOCAL_FILES=0 unless required |
| SAFE_MEDIA_PATH | Restrict to a dedicated media directory |
| Remote code | Set trust_remote_code: false unless model requires it |
| CORS | Restrict at reverse proxy level |
| Network exposure | Bind API to localhost (API_HOST=127.0.0.1) behind reverse proxy |
| Container isolation | Run containers with --read-only filesystem where possible |
| GPU isolation | Use NVIDIA_VISIBLE_DEVICES to restrict GPU access |
8. Developer Internals
8.1 V1 Plugin System
The V1 engine's extensibility is built on the BasePlugin registry pattern in v1/utils/plugin.py.
Registration:
@InitPlugin("custom_init").register("load_model")
def custom_load_model(model_args, ...):
# Custom model loading logic
pass
Invocation:
InitPlugin("custom_init")() # Calls the registered method
Plugin hierarchy:
| Plugin Base Class | Purpose | Methods |
|---|---|---|
InitPlugin |
Model initialization | load_model, load_tokenizer |
PeftPlugin |
Parameter-efficient fine-tuning | apply_peft, save_peft |
QuantizationPlugin |
Model quantization | quantize_model |
KernelPlugin |
Custom compute kernels | apply_kernels |
DataLoaderPlugin |
Data loading customization | load_data |
DataConverterPlugin |
Data format conversion | convert (alpaca, pair formats) |
OptimizerPlugin |
Custom optimizers | create_optimizer |
LRSchedulerPlugin |
Learning rate schedules | create_scheduler |
DistributedPlugin |
Distributed training backends | setup, teardown |
Plugin configs use PluginConfig — a dict-like object requiring a name field that maps to the registered plugin. Missing the name field produces: "Plugin configuration must have a 'name' field."
8.2 V1 DataEngine Internals
DataEngine (v1/core/data_engine.py) implements a torch.utils.data.Dataset:
- Parses dataset YAML config into
DatasetInfoobjects - Each dataset can come from HuggingFace Hub, ModelScope, OpenMind, or local files
- Data converters transform raw records into the internal message format (ChatML)
- Builds a flat
data_indexfor efficient random access across multiple datasets - Supports dataset mixing via
weightfield - Streaming mode for datasets too large to fit in memory (disables random access — "Streaming dataset does not support index access.")
8.3 V1 ModelEngine Internals
ModelEngine (v1/core/model_engine.py) orchestrates model setup:
- Load base model via
InitPlugin - Apply quantization via
QuantizationPlugin(if configured) - Apply PEFT via
PeftPlugin(if configured) - Apply custom kernels via
KernelPlugin(if configured) - Apply distributed wrapping (DDP, FSDP2, or DeepSpeed)
Note
When using LoRA with the V1 engine, loading the model by meta device (lazy initialization) is not supported. Attempting this produces: "Currently lora stage does not support loading model by meta."
8.4 V1 Distributed Training
The DistributedInterface in v1/accelerator/ abstracts distributed backends:
DeepSpeed: Uses the DeepSpeed engine to manage backward pass, optimizer step, and gradient accumulation. Configured via JSON config files (ZeRO stages 0/2/3).
FSDP2: Uses PyTorch's native FSDP2. Manages parameter sharding and gradient synchronization. Configured via YAML accelerate configs.
DDP: Standard PyTorch DistributedDataParallel. The default when no distributed config is specified with multiple GPUs.
The V1 engine requires drop_last=True for distributed training to ensure even batch distribution across ranks. Violating this produces: "Drop last must be True."
8.5 Legacy Engine ChatModel
The ChatModel class in chat/ supports four inference backends:
| Backend | Engine | Use Case |
|---|---|---|
| HuggingFace | transformers generate |
Default, broadest compatibility |
| vLLM | vllm |
High-throughput serving |
| SGLang | sglang |
Structured generation |
| KTransformers | ktransformers |
Specialized inference |
8.6 API Server Internals
The FastAPI server (api/app.py) exposes three endpoints:
| Method | Path | Handler | Description |
|---|---|---|---|
| GET | /v1/models |
list_models |
Returns loaded model info |
| POST | /v1/chat/completions |
create_chat_completion |
OpenAI-compatible chat completion |
| POST | /v1/score/evaluation |
create_score_evaluation |
Score/evaluate responses |
Request/response models are defined in api/protocol.py using Pydantic v2. The API follows the OpenAI chat completions specification for maximum compatibility with existing client libraries.
Concurrency is controlled by MAX_CONCURRENT (default 1), which limits simultaneous inference requests to prevent GPU OOM.
8.7 Template System
Both engines use a template system to format conversations for different model families. Templates define:
- System message handling
- Turn delimiters and role tokens
- Tool/function call formatting
- Stop sequences
The V1 engine ships with built-in templates including qwen3 and qwen3_nothink (the default, which suppresses chain-of-thought tokens).
8.8 Test Infrastructure
Two independent test suites:
| Suite | Path | Coverage |
|---|---|---|
| Legacy tests | tests/ |
Data processing, model loading, templates, training, evaluation |
| V1 tests | tests_v1/ |
V1 data engine, model engine, training, plugins |
Run with pytest:
# All legacy tests
pytest tests/
# All V1 tests
pytest tests_v1/
# Specific test
pytest tests_v1/test_data_engine.py -v
8.9 Project File Structure
hiyouga/LlamaFactory/
├── src/llamafactory/ # Main package
│ ├── cli.py # Entry point
│ ├── launcher.py # Legacy command dispatch
│ ├── train/ # Training stages (sft, dpo, kto, ppo, rm, pt)
│ ├── model/ # Model loading & adapters
│ ├── data/ # Data loading & templates
│ ├── hparams/ # Argument dataclasses
│ ├── chat/ # Interactive chat (multi-backend)
│ ├── api/ # FastAPI server
│ ├── webui/ # LlamaBoard (Gradio)
│ ├── eval/ # Evaluation (deprecated)
│ ├── extras/ # Utilities
│ └── v1/ # V1 plugin-based engine
│ ├── core/ # DataEngine, ModelEngine, BaseTrainer
│ ├── config/ # OmegaConf argument parsing
│ ├── plugins/ # All plugin implementations
│ ├── trainers/ # SFT, DPO, RM trainers
│ ├── samplers/ # CLI sampler
│ ├── accelerator/ # Distributed interface
│ └── utils/ # Plugin system, helpers
├── data/ # Demo datasets + dataset_info.json
├── examples/ # YAML configs for all scenarios
│ ├── deepspeed/ # DeepSpeed JSON configs
│ ├── accelerate/ # FSDP YAML configs
│ └── ... # Per-stage example configs
├── docker/ # Dockerfiles (CUDA, ROCm, NPU)
├── scripts/ # Utilities (FLOPs, MFU, PPL, checkpoint conversion)
├── tests/ # Legacy test suite
└── tests_v1/ # V1 test suite
9. Integration Points
9.1 OpenAI API Compatibility
The API server implements the OpenAI chat completions protocol, making it a drop-in replacement for applications using the OpenAI client library:
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="your-api-key"
)
response = client.chat.completions.create(
model="my-model",
messages=[{"role": "user", "content": "Hello!"}]
)
The API_MODEL_NAME environment variable controls what model name the server reports. Clients can use any model name in their requests; the server always uses the loaded model.
9.2 HuggingFace Hub Integration
- Models: Loaded directly from HuggingFace Hub via
model_name_or_path/model - Datasets: Referenced by Hub ID in dataset configs
- Adapters: Saved to and loaded from Hub-compatible format
- Checkpoints:
save_ckpt_as_hfconverts to Hub format
9.3 ModelScope and OpenMind Hubs
Alternative model/dataset sources activated via environment variables:
# Use ModelScope for model downloads
USE_MODELSCOPE_HUB=1 llamafactory-cli train config.yaml
# Use OpenMind for model downloads
USE_OPENMIND_HUB=1 llamafactory-cli train config.yaml
9.4 Gradio WebUI (LlamaBoard)
The WebUI provides a browser-based interface for:
- Training configuration and launch
- Model chat/evaluation
- Dataset preview
# Start WebUI
llamafactory-cli webui
# Or with custom binding
GRADIO_SERVER_NAME=0.0.0.0 llamafactory-cli webui
9.5 Tool Calling
The API supports tool/function calling in the OpenAI format. Example scripts are provided in scripts/api_example/ demonstrating tool calling and image input.
Appendix A: Troubleshooting
A.1 "can't start new thread" (RuntimeError)
Error: RuntimeError: can't start new thread
Cause: System thread limit reached, commonly when batching_workers is too high or the system ulimit for threads is restrictive.
Solution: Reduce batching_workers in training config. Increase the system thread limit: ulimit -u 65536.
Prevention: Set batching_workers proportional to available CPU cores, not arbitrarily high.
A.2 "backward through graph twice" with Unsloth + ZeRO-3
Error: RuntimeError about backward through the graph a second time, occurring with unsloth_gc enabled alongside Gemma4 and DeepSpeed ZeRO-3.
Cause: Incompatibility between Unsloth's gradient checkpointing and ZeRO-3's parameter partitioning for certain model architectures.
Solution: Disable unsloth_gc when using ZeRO-3 with affected models (Gemma4). Use standard gradient checkpointing instead.
Prevention: Test new model + optimizer + distributed combinations on small datasets before committing to full training runs.
A.3 "ignore_mismatched_sizes" breaking model loading
Error: Model loading fails or produces incorrect results when ignore_mismatched_sizes is enabled in the loader.
Cause: Silently loading mismatched tensor shapes corrupts the model rather than failing loudly.
Solution: Remove ignore_mismatched_sizes and fix the root cause (wrong model path, incompatible adapter, architecture mismatch).
Prevention: Always verify model and adapter compatibility before loading.
A.4 MLflow external logger failing
Error: MLflow integration produces errors or fails to log metrics.
Cause: MLflow configuration or connectivity issues with the tracking server.
Solution: Verify MLflow tracking URI is accessible. Check MLflow version compatibility with the HuggingFace Trainer version in use.
Prevention: Test MLflow connectivity independently before integrating with training.
A.5 GPU 0 barrier warning in distributed training
Error: Warning about GPU 0 waiting at a barrier during distributed training.
Cause: Uneven workload distribution or a process on one rank taking significantly longer.
Solution: Ensure all ranks have equal data. Check for CPU bottlenecks on specific nodes. Verify network connectivity between nodes.
Prevention: Use drop_last=True (mandatory in V1) to ensure even batch distribution.
A.6 Data packing error in SFT with multimodal models
Error: Data packing fails during SFT with models like Qwen3VL.
Cause: Packing (concatenating multiple examples into one sequence) conflicts with multimodal token handling.
Solution: Disable packing when training multimodal models.
Prevention: Review model-specific documentation for known training limitations.
A.7 "Plugin configuration must have a 'name' field"
Error: Raised during V1 engine config parsing.
Cause: A plugin config block (e.g., peft_config, dist_config) is specified without the required name field.
Solution: Add the name field identifying which plugin implementation to use:
peft_config:
name: lora # This field is mandatory
r: 16
A.8 "Global batch size must be divisible by DP size and micro batch size"
Error: Raised at training start in V1 engine.
Cause: The global_batch_size is not evenly divisible by the product of data parallel size and micro_batch_size.
Solution: Either remove global_batch_size (let it auto-compute) or set it to a valid multiple. For example, with 4 GPUs and micro_batch_size: 2, valid global_batch_size values are 8, 16, 24, etc.
Tip
When troubleshooting distributed training issues, set
LLAMAFACTORY_VERBOSITY=DEBUGandNPROC_PER_NODE=1to isolate whether the issue is distributed-specific or a general training problem.