Skills-Komposition und Orchestrierung
Ein einzelner Skill löst ein einzelnes Problem, während komplexe Workflows oft erfordern, dass mehrere Skills zusammenarbeiten.
Dieser Artikel erläutert, wie Abhängigkeiten zwischen Skills entworfen werden und wie Multi-Skill-Workflows in SKILL.md orchestriert werden.
Kompositionsmuster: Zwei Ansätze
| Muster | Beschreibung | Anwendungsfall |
|---|---|---|
| Sequenzielle Orchestrierung | Die Ausgabe von Skill A wird als Eingabe von Skill B verwendet | Datenverarbeitungs-Pipeline |
| Paralleler Aufruf | Mehrere Skills gleichzeitig verwenden und die Ergebnisse zusammenführen | Multi-Source-Datenaggregation |
Claude kann in einer einzigen Konversation Cross-Skill-Aufrufe durchführen, kann aber jeweils nur den Inhalt eines Skills "aktiv lesen". Komplexe Multi-Skill-Workflows werden normalerweise von einem "Orchestrierungs-Skill" koordiniert.
Beispiel für sequenzielle Orchestrierung
mit"PDF hochladen → Text extrahieren → Word-Zusammenfassungsbericht generieren"Nehmen Sie dies als Beispiel: Drei Skills arbeiten nacheinander zusammen.
---
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 展示下载链接。
Implementierung der Skill-Komposition über Skripte
Wenn mehrere Skills Skripte gemeinsam nutzen, kann das Hauptskript direkt die Skripte anderer Skills aufrufen, um eine Verarbeitungspipeline zu bilden.
Beispiel
# Orchestriert die Verarbeitungspipeline mehrerer Skill-Skripte
import subprocess
import sys
import os
import json
SKILLS_BASE = "/mnt/skills/public"
def run_script(script_path: str, args: list) -> dict:
"""Führt das Skript am angegebenen Pfad aus und gibt das JSON-Ergebnis zurück"""
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:
"""
Führe die vollständige Pipeline zur Erstellung von PDF → Word-Berichten aus
Stufe 1: PDF-Textextraktion
Stufe 2: Generierung der Inhaltszusammenfassung (von Claude übernommen, hier übersprungen)
Stufe 3: Word-Dokumenterstellung
"""
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")
# Stufe 1: PDF-Text extrahieren
print("Stufe 1: PDF-Text wird extrahiert...")
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" Extrahierte {step1.get('pages', '?')} Seiten")
# Phase 3: Word-Bericht generieren (die Zusammenfassung wird von Claude generiert und übergeben, bevor dieses Skript aufgerufen wird)
summary_json = os.path.join(output_dir, "summary.json")
if not os.path.exists(summary_json):
return {"status": "error", "stage": 3,
"message": "summary.json fehlt, bitte schließen Sie zuerst Phase 2 ab"}
print("Phase 3: Word-Bericht wird generiert...")
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))
Zirkuläre Abhängigkeiten vermeiden
Wenn Skill A von Skill B abhängt und Skill B von Skill A abhängt, entsteht eine zirkuläre Abhängigkeit, wodurch die Ausführung unmöglich wird.
Beim Entwerfen der Skill-Komposition sollten Sie unidirektionale Abhängigkeitsbeziehungen beibehalten.
Gemeinsam genutzte Hilfsfunktionen
Gemeinsame Funktionen, die von mehreren Skills benötigt werden, können in ein gemeinsames Modul ausgelagert werden, um doppelte Implementierungen zu vermeiden.
Beispiel
# Datei-Hilfsfunktionen, die von mehreren Skills gemeinsam genutzt werden
import os
UPLOAD_DIR = "/mnt/user-data/uploads"
OUTPUT_DIR = "/mnt/user-data/outputs"
def resolve_upload(filename: str) -> str:
"""Parst einen Dateinamen in den vollständigen Upload-Pfad"""
if os.path.isabs(filename):
return filename # Bereits ein absoluter Pfad
return os.path.join(UPLOAD_DIR, filename)
def resolve_output(filename: str) -> str:
"""Parst einen Dateinamen in den vollständigen Ausgabepfad und stellt sicher, dass das Verzeichnis vorhanden ist"""
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
# In jedem Skill-Skript verwendet:
# import sys; sys.path.insert(0, "/home/claude/shared")
# from file_utils import resolve_upload, resolve_output