config-conventions

Par nvidia · skills

Conventions de configuration pour NeMo-RL. Le YAML est l'unique source de vérité pour les valeurs par défaut. Couvre l'utilisation des TypedDict, les mises à jour de YAML types et les patterns de valeurs par défaut interdits.

npx skills add https://github.com/nvidia/skills --skill config-conventions

Conventions de configuration

Règle fondamentale

YAML est l'unique source de vérité pour les valeurs par défaut. Ne définissez pas de valeurs par défaut non-None dans le code pour les paramètres de configuration. Le YAML chargé (et les overrides utilisateur) doit fournir les valeurs requises.

Accès direct à la configuration

Pour les attributs obligatoires, écrivez du code comme policy_cfg["precision"] et supposez qu'il est présent. N'introduisez pas de valeurs par défaut cachées au fond du code.

Exprimer l'optionnalité via TypedDict

Utilisez typing.NotRequired pour marquer les attributs optionnels. Les attributs optionnels peuvent être absents/None ; le code peut vérifier leur présence.

Où vivent les valeurs par défaut

  • Les configs exemplaires sous examples/configs/*.yaml incluent les valeurs par défaut documentées.
  • Les YAMLs de recette sous examples/configs/recipes/**/*.yaml sont des snapshots exécutables et peuvent omettre la documentation.

Documenter les nouvelles clés de configuration

Lors de l'ajout d'une nouvelle clé de configuration à une sous-classe TypedDict, documentez :

  • L'objectif de la clé
  • Les valeurs/types valides
  • La valeur par défaut recommandée (le cas échéant)

Reflétez la valeur par défaut dans les YAMLs exemplaires sous examples/configs/*.yaml.

Les YAMLs de recette doivent définir defaults

Les YAMLs de recette sous examples/configs/recipes/**/*.yaml doivent définir defaults: <exemplar>.yaml pour hériter de l'une des configs exemplaires dans examples/configs/*.yaml. Cela garde les recettes minimalistes — elles ne surchargent que ce qui diffère de l'exemplaire.

Si un YAML de recette n'a pas de clé defaults, exécutez :

uv run ./tools/config_cli.py minimize <recipe.yaml>

Cela minimisera la config et assignera la clé defaults appropriée.

Accéder aux champs NotRequired

Quand vous accédez à un champ NotRequired, utilisez une vérification in ou .get(key) / .get(key, None). Ne fournissez jamais une valeur par défaut non-None — cela cache le comportement et annule l'objectif de rendre le champ optionnel.

À faire :

# .get() avec None (pas une valeur par défaut cachée)
stop_properly_penalty_coef = cfg.get("stop_properly_penalty_coef", None)

# Vérification de vérité pour les booléens optionnels
if master_config.grpo.get("skip_reference_policy_logprobs_calculation"):
    ...

# NotRequired imbriqué : vérifier la présence à chaque niveau explicitement
if "megatron_cfg" in policy_config and policy_config["megatron_cfg"]["enabled"]:
    ...

À ne pas faire :

# Valeur par défaut booléenne cachée — devrait venir de YAML
disable_ppo_ratio = cfg.get("disable_ppo_ratio", False)

# Valeur par défaut non-triviale cachée — l'appelant ignore que True est le repli
normalize_rewards = grpo_config.get("normalize_rewards", True)

# .get() enchaîné avec valeurs par défaut cachées à chaque niveau
megatron_enable = config.get("megatron_cfg", {}).get("enabled", False)

Si un champ NotRequired est absent, le code doit gérer cela explicitement — ne le camouflage pas avec une valeur par défaut magique.

Motifs interdits

À ne pas faire :

# Valeur par défaut cachée dans le code
precision = policy_cfg.get("precision", "bfloat16")

# Paramètre de fonction définissant par défaut une valeur de config
def build_policy(policy_cfg, precision: str = "bfloat16"):
    ...

À faire :

# Attribut obligatoire : s'attendre à ce que YAML ou l'override utilisateur le fournisse
precision: str = policy_cfg["precision"]

# Attribut optionnel : vérifier la présence
if "milestones" in scheduler_cfg:
    configure_milestones(scheduler_cfg["milestones"])

Voir aussi : @docs/design-docs/design-and-philosophy.md (section TypedDict and Configuration Defaults).

Skills similaires