Preserve standalone model chat templates
This commit is contained in:
@@ -16,7 +16,8 @@
|
|||||||
- 对明确写成 `TokenizersBackend` 且带 `tokenizer.json` 的仓库,改用
|
- 对明确写成 `TokenizersBackend` 且带 `tokenizer.json` 的仓库,改用
|
||||||
`PreTrainedTokenizerFast`。
|
`PreTrainedTokenizerFast`。
|
||||||
- 对 `model_type=qwen2`、`eos_token=<|im_end|>` 且缺少聊天模板的模型,补充
|
- 对 `model_type=qwen2`、`eos_token=<|im_end|>` 且缺少聊天模板的模型,补充
|
||||||
简单的 Qwen ChatML 模板,避免 `/v1/chat/completions` 返回 400。
|
简单的 Qwen ChatML 模板,避免 `/v1/chat/completions` 返回 400;已有独立
|
||||||
|
`chat_template.jinja` 或 `chat_template.json` 的模型不补写。
|
||||||
|
|
||||||
启动时在 `/tmp` 建立新模型视图,只重写 `tokenizer_config.json`。权重、模型代码和
|
启动时在 `/tmp` 建立新模型视图,只重写 `tokenizer_config.json`。权重、模型代码和
|
||||||
其他文件以符号链接指回只读 `/model`;源模型不变。没有命中上述问题时直接调用原始
|
其他文件以符号链接指回只读 `/model`;源模型不变。没有命中上述问题时直接调用原始
|
||||||
|
|||||||
@@ -81,7 +81,14 @@ def repair_tokenizer_config(
|
|||||||
patched["tokenizer_class"] = "PreTrainedTokenizerFast"
|
patched["tokenizer_class"] = "PreTrainedTokenizerFast"
|
||||||
repairs.append("TokenizersBackend -> PreTrainedTokenizerFast")
|
repairs.append("TokenizersBackend -> PreTrainedTokenizerFast")
|
||||||
|
|
||||||
if not patched.get("chat_template"):
|
# Transformers can load a standalone template with higher precedence than
|
||||||
|
# tokenizer_config.json. Do not synthesize one when the repository already
|
||||||
|
# supplies a template in that format.
|
||||||
|
has_standalone_template = any(
|
||||||
|
(model_dir / name).is_file()
|
||||||
|
for name in ("chat_template.jinja", "chat_template.json")
|
||||||
|
)
|
||||||
|
if not patched.get("chat_template") and not has_standalone_template:
|
||||||
config_path = model_dir / "config.json"
|
config_path = model_dir / "config.json"
|
||||||
if config_path.is_file():
|
if config_path.is_file():
|
||||||
model_config = _json_object(config_path)
|
model_config = _json_object(config_path)
|
||||||
|
|||||||
@@ -53,6 +53,14 @@ class EngineCompatTests(unittest.TestCase):
|
|||||||
self.assertIsNone(prepare_model(source, work_root=root))
|
self.assertIsNone(prepare_model(source, work_root=root))
|
||||||
self.assertEqual([p.name for p in root.iterdir()], ["model"])
|
self.assertEqual([p.name for p in root.iterdir()], ["model"])
|
||||||
|
|
||||||
|
def test_standalone_chat_template_is_preserved(self):
|
||||||
|
for filename in ("chat_template.jinja", "chat_template.json"):
|
||||||
|
with self.subTest(filename=filename), tempfile.TemporaryDirectory() as directory:
|
||||||
|
root = Path(directory)
|
||||||
|
source = self._model(root, {"eos_token": "<|im_end|>"})
|
||||||
|
(source / filename).write_text("{{ messages }}", encoding="utf-8")
|
||||||
|
self.assertIsNone(prepare_model(source, work_root=root))
|
||||||
|
|
||||||
def test_known_tokenizer_class_is_replaced_only_with_tokenizer_json(self):
|
def test_known_tokenizer_class_is_replaced_only_with_tokenizer_json(self):
|
||||||
with tempfile.TemporaryDirectory() as directory:
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
root = Path(directory)
|
root = Path(directory)
|
||||||
|
|||||||
Reference in New Issue
Block a user