LlamaFactory 魔改模型注册走不通?让 Codex 走 TaoToken 查 load_class
1. load_class 注册报错from_pretrained 翻车前先看懂 loader.py在 LlamaFactory 里魔改模型通常是继承 Transformers 的类重写 forward()再在 loader.py 用 load_class.register() 挂载。报错多在注册那一步。排查时让 Codex 走 TaoToken 统一通道核类签名Key 先在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建。很多人以为魔改最难的是 forward() 怎么写真正卡人的反而是 load_class 这张注册表你继承了 Qwen2VLForConditionalGeneration重写了 forward()类也填进去了from_pretrained 却要么报 already used要么报 KeyError甚至悄悄加载成官方原版模型。定位到 LLaMA-Factory-main/src/llamafactory/model/loader.py 约 169 行模型初始化就落在model load_class.from_pretrained(**init_kwargs)这一句上。自定义模型要生效必须在这一句执行之前把映射写进 load_class。本文按「先看懂注册表 → 准备 Codex 的 TaoToken 通道 → 对照报错修参数 → 最小脚本验证」的顺序排障把原文强调的 exist_ok 和 Config 类型匹配两个注意点拆开讲。1.1 loader.py 第 169 行附近发生了什么再往前看一段注册代码load_class.register(type(config), YourCustomModelClass, exist_okTrue)。register 是这张表的写入方法负责把「config 类型 → 模型类」的映射写进 load_class随后 from_pretrained 根据传入的 config 实例自动取类、构造模型。这里有个容易漏掉的细节查表键不是 config 的字符串名字而是type(config)返回的类型对象本身。你注册时用的键和 from_pretrained 查询时用的键必须是同一个对象差一点都不行。这也是为什么很多人改了 forward() 却依然走不通forward() 属于模型内部逻辑而 register 属于接入层逻辑。接入层不认你的类模型写得再正确也不会被加载。原文把这层关系讲得很清楚——load_class 本质上是一张可有序遍历的查表结构registor 就是把你的类塞进表里。任何绕过这张表的尝试都会在 from_pretrained 这一步原形毕露。1.2 load_class 的本质一张按 config 类型查模型的表load_class 是 OrderedDict 的子类官方预置了大量映射Qwen2VLConfig 对应 Qwen2VLForConditionalGenerationLlamaConfig 对应 LlamaForCausalLM其他模型也是同一套模式。它的工作方式和字典几乎一样给我一个 config 类型我还你一个模型类。魔改模型要做的就是把某个键对应的官方类替换成你自己的类。替换过程会撞上两个坑。第一同一个键默认不允许重复注册想覆盖官方映射必须显式声明exist_okTrue第二from_pretrained 内部只会按type(config)取类如果你的 config 是自定义子类而这个子类类型没注册过直接 KeyError。这两个坑正好对应原文末尾的提醒也正是下文排障时 Codex 要核对的核心内容。2. 准备排障通道Key 从 TaoToken 拿Base URL 写进 Codex 的 config.toml2.1 打开 TaoToken 创建 API Key排障需要 Codex 能稳定发起对话。先去 TaoToken 注册并创建一把 API Key创建后你会拿到YOUR_API_KEY格式的密钥。TaoToken 提供的是统一 API 兼容通道Base URL 填一次就能接 Codex、Claude Code 这类工具不必为每个工具单独维护密钥。创建完顺手在模型广场确认你要用的模型 ID——以广场当时列表为准不要凭记忆填什么带日期的旧名字。这一步对应原文里「准备环境」的隐性前提代码写得再对总要有一个能跑通对话的渠道让 AI 帮你查签名。用官网创建 Key 而不是在模型配置文件里手写密钥是为了让后续所有工具都从同一个 Key 体系取数排查时也好在控制台对账。2.2 Codex 的 config.toml 指向 https://taotoken.net/apiCodex 的全局配置在~/.codex/config.toml。为 TaoToken 单独声明一个 model_provider再把默认模型指过去codex 命令就会走统一通道model YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chat注意 base_url 填到https://taotoken.net/api就结束末尾不要加 /v1也不要带任何查询参数。模型 ID 以 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 模型广场当时列表为准把占位符替换成真实 ID。保存后导出环境变量export TAOTOKEN_API_KEYYOUR_API_KEY。之后启动 codex 随便问一句若返回 401多半是 Key 复制多了空格或写错正常回复就说明通道已经通了可以进入正题。3. 把 loader.py 和 traceback 一起交给 Codex 核签名3.1 给 Codex 的上下文至少包含三样东西让 Codex 排这种错上下文要给足。最少需要三样loader.py 第 160 到 175 行之间的代码、你写的 register 语句、from_pretrained 的完整 traceback。不要只贴最后一行红字——load_class 的报错里真正有用的是「哪个键冲突」和「哪个类不存在」这些信息分散在堆栈中段贴全了才有核对依据。另外要说清楚边界Codex 只负责按 Transformers 原类签名给出核对结论和修改建议不会直接去动你本地的工程文件。你把代码贴过去它把结论还给你实际改动由你在本地完成。这样既利用了 AI 的排查能力又不会让它稀里糊涂改坏 loader.py 里的其他逻辑。3.2 提问模板按 Transformers 原类签名核对我在 LlamaFactory 里注册自定义模型from_pretrained 加载报错。 文件 src/llamafactory/model/loader.py 的相关代码 [粘贴第 160 到 175 行] 注册语句 load_class.register(type(config), YourCustomModelClass, exist_okTrue) 报错 traceback [粘贴完整报错] 请按 Transformers 对应模型类的 __init__ 签名核对 1. 注册键 type(config) 是否与 load_class 内部查表用的键一致 2. exist_ok 是否必须为 True 才能覆盖官方映射 3. YourCustomModelClass 是否继承了正确的基类from_pretrained 传入的 init_kwargs 能否被 __init__ 接受。 只给结论和修改建议不要改我的其他业务代码。这个模板把原文的三个关键点都覆盖了注册键、exist_ok、自定义类与基类的关系。Codex 会沿着 Transformers 的 modeling 文件逐条比对类签名而不是凭空猜测因此给出的结论能直接对应到报错行。3.3 拿到结论后改哪里Codex 的核对结果一般落在三个位置。第一是 register 参数exist_ok 明确写成 True不要省略第二是注册键如果type(config)和查表键不一致改用同一个类型对象第三是自定义类本身基类没继承对就回头改继承关系不要在 loader.py 里硬凑。改完先不要急着起训练用下面的最小脚本验证注册是否真正生效。4. 对照三种报错修注册参数exist_ok / 键不匹配 / 基类签名4.1 exist_ok 没设 True键冲突直接抛错最直白的一种报错里出现 already used by a Transformers model 字样说明你注册的type(config)在 load_class 里已有官方类而 register 默认不允许覆盖。把exist_okTrue加上即可。但加之前想清楚一件事你真的要覆盖这个映射吗如果只是新增一个模型分支更稳妥的做法是自定义一个 Config 子类并注册新键避免日后官方升级时你的注册把原映射挤掉。提示exist_ok 的语义是「允许覆盖」不是「自动忽略」。它只会放行写入不会管你之前注册的类是否还生效所以覆盖前后最好打印一次表内容确认。4.2 type(config) 查不到自定义 Config 带来的 KeyError如果你为了让模型带上新的配置项新建了 Qwen2VLCustomConfig 这样的类那么type(config)返回的是自定义类型load_class 里没有任何一个键和它相等from_pretrained 取类时直接 KeyError报错信息里往往能看见你的 Config 类名。解决方法是把注册键写成type(config)本身确保键和实例类型是同一个对象。如果自定义 Config 只是想在原字段基础上加几个参数也可以沿用官方 Config 类型注册时用官方类型当键额外字段走 init_kwargs 传进去。前提是自定义模型类的init能接受这些字段否则问题会从 KeyError 变成 TypeError走到下一节。4.3 类签名不匹配报错不在注册行在构造行第三种最隐蔽register 没报错from_pretrained 也查到了类却在构造阶段抛 TypeError比如缺失某个模块参数或位置参数对不上。这通常是因为自定义类没有继承对应的官方模型类而是直接继承了 PreTrainedModel导致init的参数表和 init_kwargs 对不上。这类问题不要试图改 loader 绕过。正确做法是按 Transformers 原类签名重写自定义类的init或者先继承官方模型类、只重写 forward()让父类处理大部分参数。Codex 排查这一步的优势在于它会拿原类签名逐项对比你自定义类的参数表把缺参数的位置直接标出来。5. 验证最小加载脚本并在控制台回看这次调用5.1 最小加载脚本先于业务代码from transformers import AutoConfig # load_class 沿用 loader.py 顶部已有的定义 config AutoConfig.from_pretrained(your/checkpoint/path) load_class.register(type(config), YourCustomModelClass, exist_okTrue) model load_class.from_pretrained(your/checkpoint/path, configconfig) print(实际加载类:, type(model).__name__)先跑这个脚本确认两件事一是 register 不抛错二是打印出来的类名是 YourCustomModelClass 而不是官方类。如果打印出来还是官方类说明注册语句没被执行到或者 exist_ok 覆盖之后又被别处的注册写回去了。这一关过了再回 LlamaFactory 正常起训练或推理魔改后的 forward() 才会真正生效。5.2 回控制台对账这次 load_class 排查排障过程中 Codex 的每次提问都通过 TaoToken 的 API 通道记账用量记录可以在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的控制台里查到。顺手确认模型 ID 和 config.toml 里填的一致相当于给这次排查留个底。后续继续做模型改造时可以在 TaoToken 模型对话 里用同一把 Key 先验证思路日常高频写代码可以看 Coding Plan 是否更划算Key 需要轮换就在 控制台 API Keys 重新创建保证排障和后续开发走的是同一套统一通道。