现在位置: 首页 > Skills 教程 > 正文

Skills 错误处理与容错

一个只能在理想情况下运行的 Skill 是脆弱的。

健壮的 Skill 需要预见常见错误,给出清晰的反馈,并尽可能自动恢复。


错误处理的三个层次

层次 发生位置 处理方式
输入验证错误 执行前 检查输入,若不合法直接拒绝并说明原因
运行时错误 脚本执行中 捕获异常,输出结构化错误信息
结果异常 执行完成后 验证输出是否符合预期,若不符合触发补救流程

在 SKILL.md 中定义错误处理策略

SKILL.md 中应当包含一个明确的错误处理章节,告诉 Claude 遇到问题时该怎么做。

实例

## 错误处理

### 输入问题
- 文件不存在:告知用户文件路径有误,请重新上传
- 文件格式不支持:列出支持的格式(pdf、docx、txt),请用户转换后重试
- 文件为空:告知文件内容为空,无法处理

### 执行问题
- 脚本运行失败:将完整错误信息展示给用户,不要隐藏
- 依赖未安装:先尝试自动安装(pip install),若失败则告知用户手动安装
- 超时:若超过 60 秒未完成,输出当前进度并询问用户是否继续等待

### 结果问题
- 输出文件为空:重新检查处理逻辑,向用户说明可能原因
- 输出格式不符合预期:展示实际输出,询问用户是否满意

脚本中的标准错误处理模式

Python 脚本应使用 try-except 结构,并统一返回包含 status 字段的 JSON。

实例

# 文件路径:scripts/error_handling_demo.py
import json
import sys
import os

class SkillError(Exception):
    """Skill 自定义异常基类"""
    def __init__(self, message: str, code: str):
        self.message = message
        self.code    = code     # 错误码,便于程序判断错误类型
        super().__init__(message)

class InputError(SkillError):
    """输入验证错误"""
    pass

class ProcessError(SkillError):
    """处理过程错误"""
    pass

def validate_input(file_path: str) -> None:
    """验证输入,出错时抛出 InputError"""
    if not file_path:
        raise InputError("未提供文件路径", "MISSING_FILE")
    if not os.path.exists(file_path):
        raise InputError(f"文件不存在:{file_path}", "FILE_NOT_FOUND")
    if os.path.getsize(file_path) == 0:
        raise InputError(f"文件内容为空:{file_path}", "EMPTY_FILE")

def process(file_path: str) -> dict:
    """主处理逻辑"""
    try:
        validate_input(file_path)

        with open(file_path, "r", encoding="utf-8") as f:
            content = f.read()

        # 实际处理逻辑(此处简化为行数统计)
        lines = content.split("\n")
        return {
            "status": "success",
            "data": {
                "file":  file_path,
                "lines": len(lines),
                "chars": len(content)
            }
        }

    except InputError as e:
        # 输入错误:用户可以修正后重试
        return {
            "status":  "input_error",
            "code":    e.code,
            "message": e.message,
            "hint":    "请检查文件路径是否正确,文件是否存在且非空"
        }
    except UnicodeDecodeError:
        # 编码错误:给出具体的修复建议
        return {
            "status":  "process_error",
            "code":    "ENCODING_ERROR",
            "message": "文件编码不是 UTF-8,无法读取",
            "hint":    "请将文件另存为 UTF-8 编码后重试"
        }
    except Exception as e:
        # 未预期的错误:完整记录,便于调试
        return {
            "status":  "unexpected_error",
            "code":    "UNKNOWN",
            "message": str(e),
            "hint":    "请将上述错误信息反馈给开发者"
        }

if __name__ == "__main__":
    file_path = sys.argv[1] if len(sys.argv) > 1 else ""
    result    = process(file_path)
    print(json.dumps(result, ensure_ascii=False, indent=2))
# 文件存在时的成功输出:
{
  "status": "success",
  "data": {
    "file": "/mnt/user-data/uploads/runoob.txt",
    "lines": 128,
    "chars": 5432
  }
}

# 文件不存在时的错误输出:
{
  "status": "input_error",
  "code": "FILE_NOT_FOUND",
  "message": "文件不存在:/mnt/user-data/uploads/missing.txt",
  "hint": "请检查文件路径是否正确,文件是否存在且非空"
}

依赖自动安装的容错模式

当脚本依赖的 Python 包未安装时,可以在脚本中自动尝试安装。

实例

# 文件路径:scripts/auto_install_demo.py
import subprocess
import sys

def ensure_package(package_name: str, import_name: str = None) -> bool:
    """
    确保 Python 包已安装,若未安装则自动安装

    参数:
        package_name: pip 安装时使用的包名(如 "python-docx")
        import_name:  import 时使用的名称(如 "docx"),默认与 package_name 相同
    """

    import_name = import_name or package_name
    try:
        __import__(import_name)
        return True  # 已安装
    except ImportError:
        print(f"正在安装依赖:{package_name}...")
        result = subprocess.run(
            [sys.executable, "-m", "pip", "install", package_name,
             "--break-system-packages", "--quiet"],
            capture_output=True, text=True
        )
        if result.returncode == 0:
            print(f"安装成功:{package_name}")
            return True
        else:
            print(f"安装失败:{package_name}")
            print(result.stderr)
            return False

# 使用示例:在脚本开头确保所有依赖已就绪
if not ensure_package("pandas"):
    sys.exit(1)
if not ensure_package("openpyxl"):
    sys.exit(1)

# 依赖就绪后,正常 import
import pandas as pd
print("所有依赖已就绪,开始执行...")

自动安装只适用于开发和轻量级场景。在生产环境的 Skill 中,应将依赖写入文档,由用户预先安装,而不是在运行时自动安装。


错误信息的书写规范

好的错误信息能帮助用户快速定位问题,差的错误信息只会让人困惑。

维度 差的写法 好的写法
描述问题 "出错了" "文件 report.csv 不存在于上传目录"
说明原因 (无) "可能是文件名拼写有误,或文件尚未上传"
提供行动 (无) "请重新上传文件,或检查文件名是否正确"

实例

# 差的错误信息
raise Exception("Error")

# 好的错误信息
raise InputError(
    "文件 runoob_data.csv 未在上传目录中找到。"
    "可能原因:文件名拼写有误,或文件尚未上传。"
    "请重新上传文件后再试。",
    code="FILE_NOT_FOUND"
)