首页
/ LlamaFactory 开发工作流详解:make 命令、v0/v1 双架构与训练管线源码解析

LlamaFactory 开发工作流详解:make 命令、v0/v1 双架构与训练管线源码解析

2026-09-03 15:30:43作者:胡唯隽

本文以仓库根目录的 CLAUDE.md 为核心参照,系统讲解 LlamaFactory 的开发者工作流:日常使用的 make 命令与测试规范、由 USE_V1 环境变量控制的 v0/v1 双架构、CLI 入口的分发机制、run_exp() 训练调用链、YAML 配置系统背后的 typed dataclass 参数解析,以及关键模块索引、新增模型支持三步法、分布式训练后端与代码风格约定。读完本文,你可以独立在本地完成 LlamaFactory 的代码检查、测试运行、打包构建,并能顺着源码定位任意一次 llamafactory-cli train 调用背后的完整执行路径。

开发命令总览:make 目标与 uv 集成

CLAUDE.md 开篇列出了仓库的日常开发命令,它们全部封装在根目录 Makefile 中:

# 代码风格(自动修复)
make style

# 代码质量检查(只检查不修改)
make quality

# 运行全部测试
make test

# 运行单个测试文件
WANDB_DISABLED=true pytest -vv --import-mode=importlib tests/path/to/test_file.py

# 运行匹配指定模式的测试
WANDB_DISABLED=true pytest -vv --import-mode=importlib tests/ -k "test_name"

# 检查 License 头
make license

# 构建打包
make build

Makefile 的源码可以看到这些目标的真实实现细节:

  • uv 自动探测Makefile 通过 command -v uv 判断当前环境是否安装了 uv,若存在则自动改写命令前缀——RUN := uv runBUILD := uv buildTOOL := uvxRUFF := uvx ruff@0.15.5;否则回退到原生命令(如 python -m build、裸 ruff)。这与 CLAUDE.md 中"项目首选包管理器为 uv"的说明一致,且锁定了 ruff 版本为 0.15.5 以保证检查行为可复现。
  • 检查范围check_dirs := scripts src tests tests_v1,即 make style / make quality / make license 都会覆盖这四个目录。
  • make style 执行 ruff check --fix + ruff format(自动修复);make quality 执行 ruff check + ruff format --check(只读检查,用于 CI)。
  • make license 运行 tests/check_license.py 对四个目录做 Apache 2.0 License 头检查,对应 tests/check_license.py
  • make test 等价于 WANDB_DISABLED=true uv run pytest -vv --import-mode=importlib tests/ tests_v1/——注意它一次性运行 v0 和 v1 两套测试目录,并且 --import-mode=importlib 是必需的,可避免同名测试文件的导入冲突。

双架构:v0 与 v1 如何切换

CLAUDE.md 指出 LlamaFactory 存在两套并行架构,由环境变量 USE_V1 控制:

  • v0(默认)api, webui > chat, eval, train > data, model > hparams > extras
  • v1(实验性,USE_V1=1trainers > core > accelerator, plugins, config > utils,代码位于 src/llamafactory/v1/
  • 当前大部分活跃开发发生在 v0;v1 的实验代码集中在 src/llamafactory/v1/ 目录,其内部已按 acceleratorconfigcorepluginssamplerstrainersutils 等模块组织,与文档描述的依赖链一致。

架构切换的入口在 src/llamafactory/cli.py

def main():
    from .extras.misc import is_env_enabled

    if is_env_enabled("USE_V1"):
        from .v1 import launcher
    else:
        from . import launcher

    launcher.launch()

main() 检查 USE_V1 是否启用,然后分别导入 v1.launcher 或根级 launcher 并调用其 launch()。两套 launcher 的对外子命令保持同一套命名,对使用者透明。

CLI 入口与子命令

pyproject.toml 中注册了两个等价的命令行入口,均指向 llamafactory.cli:main

[project.scripts]
llamafactory-cli = "llamafactory.cli:main"
lmf = "llamafactory.cli:main"

子命令的分发逻辑集中在 src/llamafactory/launcher.pylaunch() 中,按 sys.argv[1] 依次匹配,与 CLAUDE.md 列出的可用子命令完全对应:

子命令 处理函数 说明
train train.tuner.run_exp() 启动训练
chat chat.chat_model.run_chat() CLI 聊天
api api.app.run_api() OpenAI 风格 API 服务
export train.tuner.export_model() 合并 LoRA / 导出模型
webchat webui.interface.run_web_demo() Web 聊天界面
webui webui.interface.run_web_ui() LlamaBoard Web UI
env extras.env.print_env() 打印环境信息
version print(WELCOME) 显示版本信息
help print(USAGE) 显示用法帮助

另外两点值得注意的实现细节:

  • eval 子命令已被弃用launcher.py 中直接 raise NotImplementedError("Evaluation will be deprecated in the future."),评估功能请走 src/llamafactory/eval/ 下的独立评估器。
  • 直接运行 launcher.py 即等价于 train:文件末尾的 __main__ 块直接导入并调用 run_exp(),这也是 torchrun 多卡启动时能被反复拉起的原因(见下文"分布式训练"一节)。

v0 训练流程:从 YAML 到 run_sft 的完整调用链

CLAUDE.md 概括了 v0 的训练流程:

run_exp() [tuner.py]
  → read_args() → 解析 YAML/JSON 配置
  → get_train_args() → 生成 typed 参数 dataclass
  → 路由到: run_sft / run_dpo / run_ppo / run_rm / run_pt / run_kto
  → 可选: export_model()

源码印证如下。src/llamafactory/train/tuner.pyrun_exp() 是入口:

def run_exp(args=None, callbacks=None) -> None:
    args = read_args(args)
    if "-h" in args or "--help" in args:
        get_train_args(args)

    ray_args = get_ray_args(args)
    callbacks = callbacks or []
    if ray_args.use_ray:
        _ray_training_function(ray_args, config={"args": args, "callbacks": callbacks})
    else:
        _training_function(config={"args": args, "callbacks": callbacks})

_training_function()tuner.py)先调用 get_train_args(args) 得到五元组参数,再按 finetuning_args.stage 路由到不同工作流;若启用了可选后端(HyperParallel、Megatron Bridge、MCA),还会优先路由到对应的 run_*_hp / run_*_mb / run_*_mca 变体:

    if finetuning_args.stage == "pt":
        run_pt(...)
    elif finetuning_args.stage == "sft":
        run_sft(...)
    elif finetuning_args.stage == "rm":
        run_rm(...)
    elif finetuning_args.stage == "ppo":
        run_ppo(...)
    elif finetuning_args.stage == "dpo":
        run_dpo(...)
    elif finetuning_args.stage == "kto":
        run_kto(...)

训练通过 YAML 配置发起,例如:

llamafactory-cli train examples/train_lora/qwen3_lora_sft.yaml

以下 examples/train_lora/qwen3_lora_sft.yaml 是一份完整的 LoRA SFT 配置,按 model / method / dataset / output / train / eval 分组组织,可作为新建配置的模板:

### model
model_name_or_path: Qwen/Qwen3-4B-Instruct-2507
trust_remote_code: true

### method
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all

### dataset
dataset: identity,alpaca_en_demo
template: qwen3_nothink
cutoff_len: 2048
max_samples: 1000
preprocessing_num_workers: 16
dataloader_num_workers: 4

### output
output_dir: saves/qwen3-4b/lora/sft
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
save_only_model: false
report_to: none  # choices: [none, wandb, tensorboard, swanlab, mlflow]

### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000
resume_from_checkpoint: null

导出(合并 LoRA 等)走 export_model()tuner.py),由 llamafactory-cli export 触发:它依次加载 tokenizer、应用模板、加载模型,校验"量化模型不可再合并 adapter"等约束,随后保存权重与 tokenizer/processor,并额外生成一份 Ollama Modelfile 便于本地部署。

配置系统:read_args 与 typed dataclass

所有训练参数都来自 YAML/JSON 配置文件。CLAUDE.md 指出 src/llamafactory/hparams/parser.py 中的参数解析会生成四个 typed dataclass:ModelArguments(模型/分词器选择、量化)、DataArguments(数据集、模板、预处理)、FinetuningArguments(LoRA rank/target、训练方法 sft/dpo/ppo/rm/pt/kto)、TrainingArguments(扩展 HuggingFace 的 TrainingArguments)。

结合源码可以补充两点实现细节:

  1. YAML 加载与 CLI 覆盖合并parser.pyread_args() 用 OmegaConf 加载配置文件,并把命令行上的剩余参数作为 override 合并进来:

    if len(sys.argv) > 1 and (sys.argv[1].endswith(".yaml") or sys.argv[1].endswith(".yml")):
        override_config = OmegaConf.from_cli(sys.argv[2:])
        dict_config = OmegaConf.load(Path(sys.argv[1]).absolute())
        return OmegaConf.to_container(OmegaConf.merge(dict_config, override_config))
    

    这意味着可以 llamafactory-cli train config.yaml --learning_rate 5e-5 临时覆盖 YAML 中的字段而不改动文件;命令行中出现的未知参数会触发 ValueError(除非设置 ALLOW_EXTRA_ARGS=1),便于尽早发现拼写错误或已废弃参数。

  2. 实际返回的是五元组parser.py 定义的 _TRAIN_ARGS 包含五个 dataclass:

    _TRAIN_ARGS = [
        ModelArguments,
        DataArguments,
        TrainingArguments,
        FinetuningArguments,
        GeneratingArguments,
    ]
    

    get_train_args() 除了文档列出的四个,还会产出用于生成式任务的 GeneratingArguments(对应 src/llamafactory/hparams/ 下的 model_args.pydata_args.pytraining_args.pyfinetuning_args.pygenerating_args.py)。

get_train_args() 内部还承担了大量参数合法性校验,例如:量化模型仅兼容 LoRA/OFT(_verify_model_args)、非 SFT 阶段禁止 predict_with_generateneat_packing、streaming 模式必须指定 max_steps、DeepSpeed 训练需通过 FORCE_TORCHRUN=1 启动等(见 parser.pyValueError 分支)。这些检查是"配置写错时立刻报错、而不是跑到训练中途才崩"的关键,排查配置问题时可以直接对照这一段。

关键模块索引

CLAUDE.md 给出的模块速查表是理解代码库导航价值的核心,结合仓库实际文件整理如下:

模块 职责 备注
src/llamafactory/model/loader.py 加载模型 + tokenizer,应用量化、LoRA、patch load_model / load_tokenizertuner.py 的直接依赖
src/llamafactory/model/patcher.py 模型特定的兼容性补丁 新增模型时通常在这里加补丁
src/llamafactory/data/template.py 提示词模板;TEMPLATES 字典映射模型家族 → 格式 TEMPLATES: dict[str, "Template"] = {} 定义于 template.py
src/llamafactory/data/mm_plugin.py 多模态(图像/视频/音频)数据处理 需要多模态支持时在此扩展
src/llamafactory/data/processor/ 各训练阶段的数据处理器 supervised.pypairwise.pypretrain.pyfeedback.pyunsupervised.py
src/llamafactory/train/sft/ SFT trainer dpo / kto / ppo / rm / pt 各阶段目录结构相同
src/llamafactory/chat/ 推理引擎 base_engine.pyhf_engine.pyvllm_engine.pysglang_engine.py,KTransformers 推理通过 model_args.use_kt 路径启用
src/llamafactory/extras/constants.py 全项目共享的枚举与常量 EngineName

各训练阶段的统一目录结构(workflow.py + trainer.py + metric.py)可以从 src/llamafactory/train/ 下的 dpo/kto/ppo/rm/pt/sft/ 子目录确认;train/hyper_parallel/train/mca/train/megatron_bridge/ 则分别承载下文所述的分布式后端。

为新模型添加支持的三步法

CLAUDE.md 给出的新增模型流程是:

  1. 添加提示词模板:在 src/llamafactory/data/template.pyTEMPLATES 字典中注册新模板。模板对象负责定义模型家族的消息格式、system 前缀、stop token 等行为;训练配置中通过 template: xxx 引用(如示例配置中的 template: qwen3_nothink),解析器会校验 data_args.template 是否存在于 TEMPLATES 中(见 template.py)。
  2. 添加模型补丁:如该模型需要兼容处理(如 use_cache 兼容、视觉编码器适配、embedding 修正等),在 src/llamafactory/model/patcher.py 中补充对应补丁,由模型加载流程统一应用。
  3. 添加多模态支持(如需要):在 src/llamafactory/data/mm_plugin.py 中为新模型家族注册 multimodal plugin,处理图像/视频/音频的编码与占位符替换。

这三步覆盖了"模板 → 模型加载 → 数据管道"三个层面,完成后该模型即可走完整的 train / export / chat / api 流程。

分布式训练:torchrun 自动拉起与可选后端

CLAUDE.md 说明多卡训练自动使用 torchrun,并提供三个额外后端:Ray、HyperParallel FSDP2(src/llamafactory/train/hyper_parallel/)、Megatron-core(src/llamafactory/train/mca/)。源码中每条都有对应证据:

  • torchrun 自动拉起launcher.py 中,当子命令为 trainget_device_count() > 1(或未显式用 Ray/KTransformers)时,会以 subprocess.run 启动 torchrun --nnodes ... --nproc_per_node ... --master_addr ... --master_port ... launcher.py <原参数>,并支持 NNODES/NODE_RANK/NPROC_PER_NODE/MASTER_ADDR/MASTER_PORT 环境变量与 c10d rendezvous(RDZV_ID)弹性启动。因此用户只需要一条 llamafactory-cli train xxx.yaml,多卡/多机的进程编排由框架代劳。
  • Raytuner.py_ray_training_function() 负责 ray.init()、资源校验、placement group 创建与 rank 排序,随后用 ray.remote(Worker) 按 bundle 启动等量 worker 执行同一个 _training_function;配合示例配置 examples/train_lora/qwen3_lora_sft_ray.yaml 使用。
  • HyperParallel FSDP2run_expstage in [pt, sft] and use_hyper_parallel 时路由到 train/hyper_parallel/(如 train/hyper_parallel/workflow.py),依赖 hyper_parallel 包。
  • Megatron-core(MCA)use_mca 时路由到 train/mca/,依赖 mcore-adapter;此外 USE_MCA / USE_MEGATRON_BRIDGE 环境变量会在 launcher.py 中强制 FORCE_TORCHRUN=1,保证这类后端始终走 torchrun 启动。

测试规范:tests 与 tests_v1

CLAUDE.md 的测试约定如下,且均与仓库现状一致:

  • 目录划分tests/ 是 v0 测试(含 data/model/train/eval/e2e/ 等子目录),tests_v1/ 是 v1 测试(core/plugins/trainers/ 等),make test 会同时跑两者。
  • GPU 依赖:大部分训练类测试需要 GPU 硬件;pytest marker 包括 @pytest.mark.slow@pytest.mark.runs_on(["cuda"]),可据此筛选 CPU 上可运行的子集。
  • WANDB 必须禁用:任何手动 pytest 命令都要带上 WANDB_DISABLED=trueMakefiletest 目标已内置该环境变量),避免测试触发 wandb 初始化。
  • import-mode--import-mode=importlib 为推荐方式,防止不同子目录下同名测试模块相互冲突。
# 运行单个测试文件
WANDB_DISABLED=true pytest -vv --import-mode=importlib tests/path/to/test_file.py

# 按名称模式筛选
WANDB_DISABLED=true pytest -vv --import-mode=importlib tests/ -k "test_name"

代码风格与 License 约定

CLAUDE.md 列出的风格规则可在 pyproject.toml 的 ruff 配置中得到逐条印证:

  • Ruff 负责 lint 与格式化line-length = 119target-version = "py311"
  • Google 风格 docstring[tool.ruff.lint.pydocstyle] convention = "google"
  • 字符串用双引号[tool.ruff.format] quote-style = "double"
  • Python 3.11+ 语法requires-python = ">=3.11.0"pyproject.toml),classifiers 覆盖 3.11/3.12/3.13;
  • License 头强制:所有新增文件必须包含 Apache 2.0 License 头,make license(即 tests/check_license.py)会检查 scriptssrcteststests_v1 四个目录。

小结

CLAUDE.md 作为面向 AI 编码助手的仓库指南,实际上完整勾勒出 LlamaFactory 的工程骨架:Makefile 定义的七类开发命令、cli.py 中由 USE_V1 控制的双架构分发、launcher.py 的子命令路由与 torchrun 自动编排、tuner.pyrun_exp → read_args → get_train_args → run_* 的训练调用链、hparams/parser.py 中 OmegaConf + HfArgumentParser 的配置解析与校验、以及模板/patcher/mm_plugin 三层的新增模型路径。日常开发只需记住三条主线——make style / quality / test 保证代码质量,llamafactory-cli train <yaml> 走 v0 训练管线,USE_V1=1 切到实验性 v1 架构——即可高效地在当前仓库内定位、验证与扩展功能。

登录后查看全文
热门项目推荐
相关项目推荐