Skills: Fortgeschrittenes Logging und Debugging
Einfaches Debugging stützt sich auf print, fortgeschrittenes Debugging auf systematische Logging-Mechanismen.
Dieser Artikel stellt vor, wie man strukturiertes Logging für Skill-Skripte einrichtet, sowie fortgeschrittene Techniken zur Lokalisierung von Problemen in komplexen Ausführungsabläufen.
Ersetze print durch logging
printGeeignet für schnelles Debugging, aber in Produktions-Skills sollte man auf daslogging-Modul der Python-Standardbibliothek umsteigen.
Der Vorteil der Protokollierung besteht darin, dass Sie die Ausgabestufe steuern können – während der Entwicklung DEBUG-Informationen ausgeben und in der Produktion nur WARNING und höher.
Beispiel
import logging
import sys
from datetime import datetime
def get_logger(name: str, level: str = "INFO") -> logging.Logger:
"""
Erstellen Sie einen strukturierten Logger
Parameter:
name: Logger-Name, normalerweise der Modulname (__name__)
level: Log-Level, DEBUG / INFO / WARNING / ERROR
"""
logger = logging.getLogger(name)
logger.setLevel(getattr(logging, level.upper(), logging.INFO))
# Wiederholtes Hinzufügen von Handlern vermeiden
if logger.handlers:
return logger
# Konsolenausgabe: menschenlesbares Format
console = logging.StreamHandler(sys.stdout)
console.setFormatter(logging.Formatter(
"[%(asctime)s] [%(levelname)s] %(name)s - %(message)s",
datefmt="%H:%M:%S"
))
logger.addHandler(console)
# Dateiausgabe: in Logdatei schreiben (optional)
log_file = f"/home/claude/skill_{datetime.now().strftime('%Y%m%d')}.log"
file_handler = logging.FileHandler(log_file, encoding="utf-8")
file_handler.setFormatter(logging.Formatter(
"%(asctime)s [%(levelname)s] %(name)s:%(lineno)d - %(message)s"
))
logger.addHandler(file_handler)
return logger
# Verwendungsbeispiel
if __name__ == "__main__":
log = get_logger(__name__, level="DEBUG")
log.debug("Debug-Info: Dateipfad = /mnt/user-data/uploads/example.csv")
log.info("Dateiverarbeitung starten")
log.warning("Dateigröße überschreitet 50MB, die Verarbeitung könnte langsam sein")
log.error("Datei konnte nicht gelesen werden: FileNotFoundError")
[10:23:01] [DEBUG] __main__ - 调试信息:文件路径 = /mnt/user-data/uploads/example.csv [10:23:01] [INFO] __main__ - 开始处理文件 [10:23:01] [WARNING] __main__ - 文件大小超过 50MB,处理可能较慢 [10:23:01] [ERROR] __main__ - 文件读取失败:FileNotFoundError
Verfolgung der Ausführungszeit
Wenn ein Skill langsam ausgeführt wird, müssen Sie die zeitintensiven Engpass-Schritte identifizieren.
Beispiel
import time
import functools
import logging
log = logging.getLogger(__name__)
def timeit(func):
"""Dekorator: erfasst automatisch die Ausführungszeit einer Funktion"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
log.info(f"{func.__name__} dauerte {elapsed:.3f} Sekunden")
return result
return wrapper
# Verwendung: Fügen Sie den @timeit-Dekorator zu der Funktion hinzu, die Sie messen möchten
@timeit
def load_csv(file_path: str):
import pandas as pd
return pd.read_csv(file_path)
@timeit
def calculate_stats(df):
return df.describe()
# Sie können auch einen Kontextmanager zur manuellen Zeitmessung verwenden
class Timer:
def __init__(self, label: str):
self.label = label
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, *args):
elapsed = time.perf_counter() - self.start
log.info(f"{self.label} dauerte {elapsed:.3f} Sekunden")
# Verwende den Timer-Kontextmanager
if __name__ == "__main__":
with Timer("Daten lesen und bereinigen"):
import pandas as pd
df = pd.read_csv("/mnt/user-data/uploads/example_data.csv")
df = df.dropna()
[10:23:05] [INFO] load_csv 耗时 0.342 秒 [10:23:05] [INFO] calculate_stats 耗时 0.018 秒 [10:23:05] [INFO] 读取并清洗数据 耗时 0.361 秒
Strukturiertes Logging: JSON-Format ausgeben
Wenn Logs von Programmen geparst werden müssen (anstatt von Menschen gelesen zu werden), ist das JSON-Format besser geeignet.
Beispiel
import json
import sys
from datetime import datetime
def log_event(level: str, event: str, **context):
"""
Strukturierte JSON-Logs ausgeben
Parameter:
level: Log-Level (info / warning / error)
event: Ereignisname
context: Zusätzliche Kontext-Schlüssel-Wert-Paare
"""
entry = {
"timestamp": datetime.now().isoformat(),
"level": level,
"event": event,
**context
}
# stderr für die Log-Ausgabe verwenden, um eine Vermischung mit der normalen Ausgabe des Skripts zu vermeiden
print(json.dumps(entry, ensure_ascii=False), file=sys.stderr)
# Verwendungsbeispiel
log_event("info", "file_loaded", file="/mnt/user-data/uploads/example.csv", rows=1024)
log_event("warning", "null_detected", column="score", count=12)
log_event("error", "parse_failed", reason="Kodierung ist nicht UTF-8")
{"timestamp": "2026-05-18T10:23:05", "level": "info", "event": "file_loaded", "file": "/mnt/user-data/uploads/example.csv", "rows": 1024}
{"timestamp": "2026-05-18T10:23:05", "level": "warning", "event": "null_detected", "column": "score", "count": 12}
{"timestamp": "2026-05-18T10:23:05", "level": "error", "event": "parse_failed", "reason": "编码不是 UTF-8"}
Debugging der SKILL.md-Anweisungsausführung
Wenn Claude nicht gemäß den Anweisungen in SKILL.md handelt, können Sie das Problem lokalisieren, indem Sie „Kontrollpunkte“ in SKILL.md einfügen.
## 调试检查点(开发模式,发布前删除)
在执行每个步骤前,先以以下格式输出一行状态确认:
`[STEP N] 开始:{步骤名称},输入:{关键参数}`
示例:
`[STEP 1] 开始:读取文件,输入:/mnt/user-data/uploads/example.csv`
`[STEP 2] 开始:数据清洗,输入:1024 行`
这样可以在出错时快速定位到哪个步骤失败。
Debugging-Kontrollpunkte sind temporär. Nach Abschluss des Debuggings müssen diese Anweisungen unbedingt aus SKILL.md entfernt werden, sonst sehen Benutzer bei normaler Nutzung überflüssige Debug-Ausgaben.
Schnellreferenz für häufige Debugging-Szenarien
| Szenario | Debugging-Methode |
|---|---|
| Skill wird nicht ausgelöst | Beschreibung prüfen, mit komplexen Prompts testen, run_loop.py zum Optimieren ausführen |
| Skript meldet ImportError | pip install ausführen, prüfen, ob der Paketname mit dem Importnamen übereinstimmt |
| Dateipfadfehler | Zuerst ls /mnt/user-data/uploads/ ausführen, um den Dateinamen zu bestätigen |
| Verstümmelte Ausgabe | Beim Lesen von Dateien explizit encoding="utf-8" angeben |
| Falsche Ausführungsreihenfolge der Schritte | Verwende eine nummerierte Liste in SKILL.md, um die Reihenfolge der Schritte zu verdeutlichen |
| Leeres Ergebnis | Füge print an Schlüsselstellen im Skript hinzu, um zu bestätigen, bei welchem Schritt die Daten leer werden |