Modèles de conception et bonnes pratiques des Skills
Les patrons de conception de Skill distillés d'une vaste pratique vous aident à prendre rapidement des décisions judicieuses face à de nouvelles exigences.
Cet article résume les 7 patrons de conception les plus couramment utilisés et leurs scénarios d'application.
Patron 1 : Skill à responsabilité unique
Chaque Skill fait une seule chose et la fait bien.
Plus la fonctionnalité est ciblée, plus la description est précise, plus la précision de déclenchement est élevée et plus la maintenance est facile.
| Approche | Exemple |
|---|---|
| Correct : responsabilité unique | pdf-to-text (ne gère que l'extraction de texte) |
| Incorrect : responsabilités mélangées | pdf-tools (lecture, conversion, fusion, filigrane... le tout au même endroit) |
Si vous constatez que la description d'un Skill doit être très longue pour préciser ce qu'il « ne fait pas », cela signifie généralement qu'il a assumé trop de responsabilités et qu'il devrait être scindé.
Patron 2 : Vérification défensive des entrées
Effectuez toute la validation des entrées de façon centralisée au point d'entrée du script Skill, et n'accédez à la logique métier qu'après réussite de la validation.
Exemple
# Modèle : vérification défensive des entrées - validation centralisée au point d'entrée, libération après validation
import sys
import os
import json
def validate(args) -> list:
"""Valider de manière centralisée toutes les entrées et renvoyer une liste d'erreurs (une liste vide signifie que tout est validé)"""
errors = []
if not args.file:
errors.append("Argument manquant --file")
elif not os.path.exists(args.fichier):
errors.append(f"Le fichier n'existe pas : {args.file}")
elif os.path.getsize(args.file) == 0:
errors.append("Le contenu du fichier est vide")
if args.limit < 1:
errors.append("--limit doit être supérieur à 0")
return errors
def run(args):
"""Point d'entrée de la logique métier, appelé uniquement après réussite de la validation"""
# Effectuer le traitement réel...
return {"status": "success", "file": args.file}
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--file", required=False, default="")
parser.add_argument("--limit", type=int, default=100)
args = parser.parse_args()
# 1. Validation centralisée
errors = validate(args)
if errors:
result = {"status": "input_error", "errors": errors}
print(json.dumps(result, ensure_ascii=False))
sys.exit(1)
# 2. Exécuter la logique métier après validation réussie
result = run(args)
print(json.dumps(result, ensure_ascii=False))
Modèle 3 : Sortie progressive
Pour les compétences qui prennent plus de 5 secondes, la progression doit être affichée par étapes, plutôt que de laisser l'utilisateur face à une attente silencieuse.
## 执行流程(渐进式输出示例) ### 步骤一:读取文件 运行读取脚本后,立即告知用户: > 已读取文件:example_data.csv(1,024 行,8 列)正在进行数据清洗... ### 步骤二:数据清洗 清洗完成后,告知用户: > 数据清洗完成:删除重复行 3 条,空值填充 12 处。正在生成报告... ### 步骤三:生成报告 报告生成后,展示下载链接并说明内容: > 报告已生成,包含统计摘要和数据质量评估。
Modèle 4 : Opérations idempotentes
Les résultats d'exécution d'une compétence doivent être idempotents : pour la même entrée, quel que soit le nombre de fois où elle est exécutée, la sortie doit être cohérente.
Les opérations non idempotentes (comme l'ajout de contenu à chaque exécution) peuvent semer la confusion lorsque les utilisateurs réessaient.
Exemple
import os
from datetime import datetime
OUTPUT_DIR = "/mnt/user-data/outputs"
def get_output_path(base_name: str, suffix: str = ".xlsx") -> str:
"""
Générer un chemin de sortie déterministe
Approche idempotente : écraser le fichier de même nom à chaque exécution (au lieu d'ajouter ou de générer un nouveau fichier)
Garantir que la même entrée correspond toujours au même fichier de sortie
"""
# Méthode A : Nom de fichier fixe (la même entrée écrase toujours)
return os.path.join(OUTPUT_DIR, f"{base_name}_report{suffix}")
# Méthode B (horodatage) : générer un nouveau fichier à chaque fois (non idempotent, mais conserve l'historique)
# ts = datetime.now().strftime("%Y%m%d_%H%M%S")
# return os.path.join(OUTPUT_DIR, f"{base_name}_{ts}{suffix}")
Patron 5 : Signal d'achèvement explicite
Après qu'une Skill a terminé son exécution, elle doit émettre un « signal d'achèvement » clair pour que l'utilisateur sache que la tâche est terminée et qu'il n'a pas besoin de continuer à attendre.
## 任务完成后的输出规范 无论成功还是失败,最后一步必须输出一个明确的状态行: 成功时: > 任务完成:报告已生成,共处理 1,024 行数据,耗时约 3 秒。 失败时: > 任务中断:在"数据清洗"步骤遇到错误(原因:文件编码不是 UTF-8)。 > 建议:将文件另存为 UTF-8 格式后重新上传。
Patron 6 : Déclaration de compatibilité de version
Déclarez les versions de modèle compatibles dans le frontmatter de SKILL.md pour éviter un comportement inattendu dans les environnements non pris en charge.
---
name: data-analyzer
version: 1.2.0
description: 分析 CSV/Excel 数据,生成统计报告。
compatibility:
claude_models:
- claude-sonnet-4-20250514 # 经过验证的模型版本
- claude-opus-4 # 同样支持
python: ">=3.8"
platforms:
- linux # Claude 计算机使用环境
---
Patron 7 : Échec rapide
Dès qu'une erreur qui empêche la poursuite est détectée, arrêtez-vous immédiatement et signalez-le clairement, plutôt que de continuer l'exécution avec l'erreur et de produire une sortie dénuée de sens.
Exemple
import sys
import json
def assert_condition(condition: bool, message: str, hint: str = ""):
"""Si les conditions ne sont pas remplies, afficher immédiatement une erreur et quitter (modèle Fail Fast)"""
if not condition:
result = {
"status": "error",
"message": message,
"hint": hint
}
print(json.dumps(result, ensure_ascii=False))
sys.exit(1)
# Effectuer toutes les vérifications préalables de manière centralisée au début du script
import os
file_path = sys.argv[1] if len(sys.argv) > 1 else ""
assert_condition(bool(file_path),
"Argument de chemin de fichier manquant",
"Utilisation : python script.py <chemin du fichier>")
assert_condition(os.path.exists(file_path),
f"Le fichier n'existe pas : {file_path}",
"Veuillez vérifier si le chemin est correct, ou téléverser à nouveau le fichier")
assert_condition(file_path.endswith(".csv"),
"Format de fichier non pris en charge, .csv attendu",
f"Fichier réel : {file_path}")
# Toutes les vérifications ont réussi, exécuter la logique réelle
print(json.dumps({"status": "ok", "file": file_path}))
Référence rapide des motifs
| Modèle | Principe fondamental | Problème résolu |
|---|---|---|
| Responsabilité unique | Une compétence ne fait qu'une chose | Déclenchement imprécis, difficile à maintenir |
| Vérification défensive des entrées | Validation centralisée au point d'entrée | Erreurs signalées uniquement au milieu de l'exécution |
| Sortie progressive | Signaler la progression par étapes | Les utilisateurs ne savent pas si l'exécution est en cours |
| Opérations idempotentes | Même entrée, même sortie | Les réessais produisent des résultats déroutants |
| Signal d'achèvement explicite | Fournir une notification de l'état final une fois terminé | Les utilisateurs ne savent pas si la tâche est terminée |
| Déclaration de compatibilité de version | Déclarer les environnements d'exécution pris en charge | Comportement anormal lorsque l'environnement ne correspond pas |
| Échouer rapidement | S'arrêter immédiatement en cas d'erreur | Continuer malgré les erreurs produit une sortie invalide |