58d75cc56a
- ars_opd/configs.py: 冻结 dataclass,机器路径无默认强制显式传入; 双预算/enable_thinking/lr 差异均按 §7 规范标注 - __post_init__ 构造即校验,防"completion 预算为零→loss 恒 0"静默空训练 - tests/test_configs.py: 6 个校验测试 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
50 lines
1.3 KiB
Python
50 lines
1.3 KiB
Python
"""SFTConfig 的构造校验测试(层 1 / T1)。
|
|
|
|
只测"配置错误必须在构造时炸"这一条约定;参数语义本身没有逻辑可测。
|
|
"""
|
|
|
|
import dataclasses
|
|
|
|
import pytest
|
|
|
|
from ars_opd.configs import SFTConfig
|
|
|
|
|
|
def make(**overrides):
|
|
"""最小合法配置;单测只关心被覆盖的那个字段。"""
|
|
base = dict(dataset_path="dummy.parquet", output_dir="/tmp/dummy")
|
|
base.update(overrides)
|
|
return SFTConfig(**base)
|
|
|
|
|
|
def test_合法配置可构造():
|
|
cfg = make()
|
|
assert cfg.max_length > cfg.max_prompt_length
|
|
|
|
|
|
def test_prompt预算吞掉总预算时报错():
|
|
# 这是最危险的静默失败:completion 预算为 0 → labels 全 -100 → loss 恒 0
|
|
with pytest.raises(ValueError, match="max_prompt_length"):
|
|
make(max_prompt_length=4096, max_length=4096)
|
|
|
|
|
|
def test_非法学习率报错():
|
|
with pytest.raises(ValueError, match="learning_rate"):
|
|
make(learning_rate=0.0)
|
|
|
|
|
|
def test_非法子集大小报错():
|
|
with pytest.raises(ValueError, match="subset_size"):
|
|
make(subset_size=0)
|
|
|
|
|
|
def test_非法max_steps报错():
|
|
with pytest.raises(ValueError, match="max_steps"):
|
|
make(max_steps=0)
|
|
|
|
|
|
def test_配置冻结不可变():
|
|
cfg = make()
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
cfg.learning_rate = 1e-3
|