Composition et orchestration des compétences
Une seule compétence résout un seul problème, tandis que les flux de travail complexes nécessitent souvent plusieurs compétences pour travailler ensemble.
Cet article présente comment concevoir des dépendances entre les compétences et comment orchestrer des flux de travail multi-compétences dans SKILL.md.
Modèles de composition : deux approches
| Modèle | Description | Scénario applicable |
|---|---|---|
| Orchestration séquentielle | La sortie de la compétence A est utilisée comme entrée de la compétence B | Pipeline de traitement de données |
| Invocation parallèle | Utiliser plusieurs Skills simultanément et fusionner les résultats | Agrégation de données multi-sources |
Claude peut effectuer des appels inter-Skills dans une seule conversation, mais ne peut « lire activement » le corps que d'un seul Skill à la fois. Les workflows complexes multi-Skills sont généralement coordonnés par un « Skill d'orchestration ».
Exemple d'orchestration séquentielle
avec« Téléverser un PDF → Extraire le texte → Générer un rapport de synthèse Word »Prenons ceci comme exemple : trois Skills collaborent en séquence.
---
name: pdf-to-word-report
description: >
将 PDF 文档转换为 Word 格式的摘要报告,包含文字提取、
内容分析和格式化输出三个阶段。当用户需要从 PDF 生成报告、
提取 PDF 内容并整理为 Word 文档时触发。
---
# PDF 转 Word 摘要报告
## 工作流程
本 Skill 协调三个处理阶段,最终生成 .docx 报告。
### 阶段一:提取 PDF 文字
使用 pdf-reading Skill(位于 /mnt/skills/public/pdf-reading/)的处理逻辑:
```bash
python /mnt/skills/public/pdf-reading/scripts/extract.py \
--input <PDF路径> \
--output /home/claude/extracted_text.txt
```
完成后告知用户:已提取 {N} 页内容,共 {字数} 字。
### 阶段二:生成摘要内容
对提取的文字进行内容分析,生成:
- 文档主题(1句话)
- 关键章节摘要(每章 2-3 句)
- 重要数据与结论
将摘要内容写入 /home/claude/summary.json
### 阶段三:生成 Word 报告
使用 docx Skill 的规范,调用:
```bash
python /mnt/skills/public/docx/scripts/generate.py \
--template /mnt/skills/public/docx/assets/report_template.docx \
--data /home/claude/summary.json \
--output /mnt/user-data/outputs/report.docx
```
完成后调用 present_files 展示下载链接。
Implémentation de la composition de Skills via des scripts
Lorsque plusieurs Skills partagent des scripts, le script principal peut directement appeler les scripts d'autres Skills pour former un pipeline de traitement.
Exemple
# Orchestre le pipeline de traitement de plusieurs scripts de Skill
import subprocess
import sys
import os
import json
SKILLS_BASE = "/mnt/skills/public"
def run_script(script_path: str, args: list) -> dict:
"""Exécute le script au chemin spécifié et renvoie le résultat JSON"""
cmd = [sys.executable, script_path] + args
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
if result.returncode != 0:
return {"status": "error", "message": result.stderr}
try:
return json.loads(result.stdout)
except json.JSONDecodeError:
return {"status": "success", "raw_output": result.stdout}
def run_pipeline(pdf_path: str, output_dir: str) -> dict:
"""
Exécuter le pipeline complet de génération de rapport PDF → Word
Étape 1 : extraction de texte PDF
Étape 2 : génération du résumé de contenu (gérée par Claude, ignorée ici)
Étape 3 : Génération de document Word
"""
os.makedirs(output_dir, exist_ok=True)
extracted_txt = os.path.join(output_dir, "extracted.txt")
final_docx = os.path.join(output_dir, "report.docx")
# Étape 1 : Extraire le texte PDF
print("Étape 1 : Extraction du texte PDF...")
step1 = run_script(
f"{SKILLS_BASE}/pdf-reading/scripts/extract.py",
["--input", pdf_path, "--output", extracted_txt]
)
if step1.get("status") == "error":
return {"status": "error", "stage": 1, "message": step1["message"]}
print(f" {step1.get('pages', '?')} pages extraites")
# Étape 3 : Générer un rapport Word (le résumé est généré et transmis par Claude avant que ce script soit appelé)
summary_json = os.path.join(output_dir, "summary.json")
if not os.path.exists(summary_json):
return {"status": "error", "stage": 3,
"message": "summary.json manquant, veuillez d'abord terminer l'étape 2"}
print("Étape 3 : Génération du rapport Word...")
step3 = run_script(
f"{SKILLS_BASE}/docx/scripts/generate.py",
["--data", summary_json, "--output", final_docx]
)
if step3.get("status") == "error":
return {"status": "error", "stage": 3, "message": step3["message"]}
return {"status": "success", "output": final_docx}
if __name__ == "__main__":
pdf_path = sys.argv[1] if len(sys.argv) > 1 else ""
output_dir = sys.argv[2] if len(sys.argv) > 2 else "/home/claude/pipeline_output"
result = run_pipeline(pdf_path, output_dir)
print(json.dumps(result, ensure_ascii=False, indent=2))
Éviter les dépendances circulaires
Lorsque la compétence A dépend de la compétence B et que la compétence B dépend de la compétence A, une dépendance circulaire se forme, rendant l’exécution impossible.
Lors de la conception de la composition des compétences, vous devez maintenir des relations de dépendance unidirectionnelles.
Fonctions utilitaires partagées
Les fonctions communes nécessaires à plusieurs compétences peuvent être extraites dans un module partagé afin d’éviter une implémentation en double.
Exemple
# Fonctions utilitaires de fichiers partagées par plusieurs Skills
import os
UPLOAD_DIR = "/mnt/user-data/uploads"
OUTPUT_DIR = "/mnt/user-data/outputs"
def resolve_upload(filename: str) -> str:
"""Analyse un nom de fichier pour obtenir le chemin de téléversement complet"""
if os.path.isabs(filename):
return filename # Déjà un chemin absolu
return os.path.join(UPLOAD_DIR, filename)
def resolve_output(filename: str) -> str:
"""Analyse un nom de fichier pour obtenir le chemin de sortie complet et s'assure que le répertoire existe"""
if os.path.isabs(filename):
path = filename
else:
path = os.path.join(OUTPUT_DIR, filename)
os.makedirs(os.path.dirname(path), exist_ok=True)
return path
# Utilisé dans chaque script Skill :
# import sys; sys.path.insert(0, "/home/claude/shared")
# from file_utils import resolve_upload, resolve_output