LlamaFactory 开发工作流详解:make 命令、v0/v1 双架构与训练管线源码解析
本文以仓库根目录的 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 run、BUILD := uv build、TOOL := uvx、RUFF := 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=1):trainers > core > accelerator, plugins, config > utils,代码位于src/llamafactory/v1/ - 当前大部分活跃开发发生在 v0;v1 的实验代码集中在 src/llamafactory/v1/ 目录,其内部已按
accelerator、config、core、plugins、samplers、trainers、utils等模块组织,与文档描述的依赖链一致。
架构切换的入口在 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.py 的 launch() 中,按 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.py 的 run_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)。
结合源码可以补充两点实现细节:
-
YAML 加载与 CLI 覆盖合并。parser.py 的
read_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),便于尽早发现拼写错误或已废弃参数。 -
实际返回的是五元组。parser.py 定义的
_TRAIN_ARGS包含五个 dataclass:_TRAIN_ARGS = [ ModelArguments, DataArguments, TrainingArguments, FinetuningArguments, GeneratingArguments, ]即
get_train_args()除了文档列出的四个,还会产出用于生成式任务的GeneratingArguments(对应src/llamafactory/hparams/下的 model_args.py、data_args.py、training_args.py、finetuning_args.py、generating_args.py)。
get_train_args() 内部还承担了大量参数合法性校验,例如:量化模型仅兼容 LoRA/OFT(_verify_model_args)、非 SFT 阶段禁止 predict_with_generate 与 neat_packing、streaming 模式必须指定 max_steps、DeepSpeed 训练需通过 FORCE_TORCHRUN=1 启动等(见 parser.py 的 ValueError 分支)。这些检查是"配置写错时立刻报错、而不是跑到训练中途才崩"的关键,排查配置问题时可以直接对照这一段。
关键模块索引
CLAUDE.md 给出的模块速查表是理解代码库导航价值的核心,结合仓库实际文件整理如下:
| 模块 | 职责 | 备注 |
|---|---|---|
| src/llamafactory/model/loader.py | 加载模型 + tokenizer,应用量化、LoRA、patch | load_model / load_tokenizer 是 tuner.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.py、pairwise.py、pretrain.py、feedback.py、unsupervised.py |
| src/llamafactory/train/sft/ | SFT trainer | dpo / kto / ppo / rm / pt 各阶段目录结构相同 |
| src/llamafactory/chat/ | 推理引擎 | 含 base_engine.py、hf_engine.py、vllm_engine.py、sglang_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 给出的新增模型流程是:
- 添加提示词模板:在 src/llamafactory/data/template.py 的
TEMPLATES字典中注册新模板。模板对象负责定义模型家族的消息格式、system 前缀、stop token 等行为;训练配置中通过template: xxx引用(如示例配置中的template: qwen3_nothink),解析器会校验data_args.template是否存在于TEMPLATES中(见 template.py)。 - 添加模型补丁:如该模型需要兼容处理(如
use_cache兼容、视觉编码器适配、embedding 修正等),在 src/llamafactory/model/patcher.py 中补充对应补丁,由模型加载流程统一应用。 - 添加多模态支持(如需要):在 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 中,当子命令为
train且get_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,多卡/多机的进程编排由框架代劳。 - Ray:tuner.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 FSDP2:
run_exp在stage 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=true(Makefile 的test目标已内置该环境变量),避免测试触发 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 = 119、target-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)会检查scripts、src、tests、tests_v1四个目录。
小结
CLAUDE.md 作为面向 AI 编码助手的仓库指南,实际上完整勾勒出 LlamaFactory 的工程骨架:Makefile 定义的七类开发命令、cli.py 中由 USE_V1 控制的双架构分发、launcher.py 的子命令路由与 torchrun 自动编排、tuner.py 中 run_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 架构——即可高效地在当前仓库内定位、验证与扩展功能。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00