Skip to content

17.2 Skills 專案結構

專案結構概述

良好的專案結構是開發高質量 Skills 的基礎。本節將詳細介紹 Skills 專案的標準結構和最佳實踐。

python
### 1\. 基础结构

    bash


    my-skill/
    ├── src/                      # 源代码目录
    │   └── skills/               # Skills 模块
    │       ├── __init__.py        # 模块初始化
    │       ├── my_skill.py        # 主 Skill 实现
    │       ├── utils/             # 工具函数
    │       │   ├── __init__.py
    │       │   ├── helpers.py     # 辅助函数
    │       │   └── validators.py  # 验证器
    │       └── models/           # 数据模型
    │           ├── __init__.py
    │           └── schemas.py    # 数据模式
    ├── tests/                    # 测试目录
    │   ├── __init__.py
    │   ├── conftest.py           # pytest 配置
    │   ├── test_my_skill.py      # Skill 测试
    │   ├── test_utils.py         # 工具测试
    │   └── fixtures/             # 测试固件
    │       ├── __init__.py
    │       └── data/             # 测试数据
    ├── docs/                     # 文档目录
    │   ├── api.md                # API 文档
    │   ├── usage.md              # 使用文档
    │   └── development.md        # 开发文档
    ├── examples/                 # 示例目录
    │   ├── basic_usage.py        # 基本使用示例
    │   └── advanced_usage.py    # 高级使用示例
    ├── scripts/                  # 脚本目录
    │   ├── build.py              # 构建脚本
    │   ├── deploy.py             # 部署脚本
    │   └── test.sh               # 测试脚本
    ├── configs/                  # 配置目录
    │   ├── development.yaml      # 开发配置
    │   ├── production.yaml       # 生产配置
    │   └── testing.yaml          # 测试配置
    ├── resources/                # 资源目录
    │   ├── templates/            # 模板文件
    │   ├── static/              # 静态文件
    │   └── data/                # 数据文件
    ├── .gitignore               # Git 忽略文件
    ├── .pylintrc               # Pylint 配置
    ├── .mypy.ini               # MyPy 配置
    ├── pyproject.toml           # 项目配置
    ├── setup.py                # 安装脚本
    ├── requirements.txt        # 依赖列表
    ├── requirements-dev.txt    # 开发依赖
    ├── README.md              # 项目说明
    ├── LICENSE                # 许可证
    └── CHANGELOG.md           # 变更日志
    ~~~### 2. 详细说明

    #### 2.1 源代码目录(src/)

    # src/skills/__init__.py
    """
    Skills 模块
    """
    from skills.my_skill import MySkill
    __all__ = ["MySkill"]
    __version__ = "0.1.0"

    ```python

    # src/skills/my_skill.py

```python
    """
    主 Skill 实现
    """
    from typing import Dict, Any
    from claude_code_sdk import Skill, SkillContext, SkillResult

    class MySkill(Skill):
        """自定义 Skill 实现"""

        def __init__(self):
            super().__init__(
                name="my-skill",
                version="0.1.0",
                description="A custom Claude Code skill"
            )

        def get_parameters_schema(self) -> Dict[str, Any]:
            """获取参数模式"""
            return {
                "type": "object",
                "properties": {
                    "input": {
                        "type": "string",
                        "description": "Input text to process"
                    }
                },
                "required": ["input"]
            }

        def execute(self, parameters: Dict[str, Any], context: SkillContext) -> SkillResult:
            """执行 Skill"""
            input_text = parameters["input"]
            output = self.process_input(input_text)

            return SkillResult(
                success=True,
                data={
                    "input": input_text,
                    "output": output
                }
            )

        def process_input(self, input_text: str) -> str:
            """处理输入文本"""
            return input_text.upper()

    python
python
    # src/skills/utils/__init__.py
    """
    工具函数模块
    """
    from skills.utils.helpers import format_output, validate_input
    from skills.utils.validators import validate_parameters
    __all__ = ["format_output", "validate_input", "validate_parameters"]

    python
python
    # src/skills/utils/helpers.py
    """
    辅助函数
    """
    from typing import Any

    def format_output(data: Any, format_type: str = "json") -> str:
        """格式化输出"""
        if format_type == "json":
            import json
            return json.dumps(data, indent=2)
        elif format_type == "yaml":
            import yaml
            return yaml.dump(data)
        else:
            return str(data)

    def validate_input(input_text: str) -> bool:
        """验证输入"""
        return isinstance(input_text, str) and len(input_text) > 0

    python
python
    # src/skills/utils/validators.py
    """
    验证器
    """
    from typing import Dict, Any
    def validate_parameters(parameters: Dict[str, Any], schema: Dict[str, Any]) -> bool:
        """验证参数"""
        required = schema.get("required", [])
        properties = schema.get("properties", {})

        for param in required:
            if param not in parameters:
                return False

        param_schema = properties.get(param, {})
        param_type = param_schema.get("type")
        if param_type:
            if param_type == "string" and not isinstance(parameters[param], str):
                return False
    elif param_type == "number" and not isinstance(parameters[param], (int, float)):
                return False
            elif param_type == "boolean" and not isinstance(parameters[param], bool):
                return False
        return True

    python
python
    # src/skills/models/__init__.py
    """
    数据模型模块
    """
    from skills.models.schemas import InputSchema, OutputSchema

    __all__ = ["InputSchema", "OutputSchema"]

    python
python
    # src/skills/models/schemas.py
    """
    数据模式
    """
    from dataclasses import dataclass
    from typing import Optional
    @dataclass
    class InputSchema:
        """输入模式"""
        input: str
        options: Optional[dict] = None

    @dataclass
    class OutputSchema:
        """输出模式"""
        success: bool
        data: dict
        message: Optional[str] = None

#### 2.2 测试目录(tests/)

    python
# tests/__init__.py
"""
测试模块
"""

python
python
    # tests/conftest.py
    """
    pytest 配置
    """
    import pytest
    from claude_code_sdk import SkillContext
    @pytest.fixture
    def skill_context():
        """Skill 上下文固件"""
        return SkillContext()

    @pytest.fixture
    def sample_parameters():
        """示例参数固件"""
        return {
            "input": "test input"
        }

    @pytest.fixture
    def sample_context():
        """示例上下文固件"""
        return {
            "project": {
                "name": "test-project",
                "path": "/tmp/test-project"
            },
            "user": {
                "id": "user123",
                "name": "Test User"
            }
        }

    ```python

    # tests/test_my_skill.py

    """
    Skill 測試
    """
    import pytest
    from skills.my_skill import MySkill

    class TestMySkill:
        """MySkill 測試類"""

        def setup_method(self):
            """設定方法"""
            self.skill = MySkill()

        def test_skill_initialization(self):
            """測試 Skill 初始化"""
            assert self.skill.name == "my-skill"
            assert self.skill.version == "0.1.0"
            assert self.skill.description == "A custom Claude Code skill"

        def test_get_parameters_schema(self):
            """測試獲取引數模式"""
            schema = self.skill.get_parameters_schema()

            assert "properties" in schema
            assert "input" in schema["properties"]
            assert "required" in schema
            assert "input" in schema["required"]

        def test_execute_success(self, skill_context):
            """測試成功執行"""
            parameters = {"input": "hello"}
            result = self.skill.execute(parameters, skill_context)

            assert result.success
            assert result.data["output"] == "HELLO"

        def test_execute_missing_parameter(self, skill_context):
            """測試缺少引數"""
            parameters = {}

            with pytest.raises(KeyError):
                self.skill.execute(parameters, skill_context)

        def test_process_input(self):
            """測試處理輸入"""
            assert self.skill.process_input("hello") == "HELLO"
            assert self.skill.process_input("world") == "WORLD"
            assert self.skill.process_input("123") == "123"

    ```python
    # tests/test_utils.py
    """
    工具函数测试
    """
    import pytest
    from skills.utils.helpers import format_output, validate_input
    from skills.utils.validators import validate_parameters

    class TestHelpers:
        """辅助函数测试"""

        def test_format_output_json(self):
            """测试 JSON 格式化"""
            data = {"key": "value"}
            result = format_output(data, "json")
            assert '"key": "value"' in result

        def test_format_output_yaml(self):
            """测试 YAML 格式化"""
            data = {"key": "value"}
            result = format_output(data, "yaml")
            assert "key: value" in result

        def test_validate_input_valid(self):
            """测试有效输入"""
            assert validate_input("hello") == True
            assert validate_input("world") == True

        def test_validate_input_invalid(self):
            """测试无效输入"""
            assert validate_input("") == False
            assert validate_input(123) == False

    class TestValidators:
    """验证器测试"""

        def test_validate_parameters_valid(self):
    """测试有效参数"""
            parameters = {"input": "test"}
    schema = {
    "properties": {
    "input": {"type": "string"}
    },
    "required": ["input"]
    }
    assert validate_parameters(parameters, schema) == True

        def test_validate_parameters_missing_required(self):
    """测试缺少必需参数"""
            parameters = {}
    schema = {
    "properties": {
    "input": {"type": "string"}
    },
    "required": ["input"]
    }
    assert validate_parameters(parameters, schema) == False

        def test_validate_parameters_wrong_type(self):
    """测试错误类型"""
            parameters = {"input": 123}
    schema = {
    "properties": {
    "input": {"type": "string"}
    },
    "required": ["input"]
    }
    assert validate_parameters(parameters, schema) == False

#### 2.3 配置文件

    yaml
python

    ```yaml

    # configs/development.yaml

    # 開發環境配置

    version: "1.0"

    skills:
      my-skill:
        enabled: true
        debug: true
        log_level: DEBUG

    logging:
      level: DEBUG
      format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
      output: console

    cache:
      enabled: true
      ttl: 3600
      storage: memory

    ```> # configs/production.yaml
    # 生产环境配置
    version: "1.0"
    skills:
    my-skill:
    enabled: true
    debug: false
    log_level: INFO
    logging:
    level: INFO
    format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    output: file
    file_path: /var/log/my-skill.log
    cache:
    enabled: true
    ttl: 7200
    storage: redis
    redis_host: localhost
    redis_port: 6379

    ```

    ~~~yaml

    ```yaml

    ```

    # configs/testing.yaml

    # 測試環境配置

    version: "1.0"

    skills:
      my-skill:
        enabled: true
        debug: true
        log_level: DEBUG

    logging:
      level: DEBUG
      format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
      output: console

    cache:
      enabled: false

    testing:
      mock_external_calls: true
      use_test_data: true

    ```## 项目组织原则

    ### 1. 模块化设计

    ## 模块化原则
    ### 单一职责
    每个模块只负责一个功能
    - my_skill.py: 主 Skill 逻辑
    - helpers.py: 辅助函数
    - validators.py: 验证逻辑
    ### 高内聚低耦合
    模块内部紧密相关,模块之间松散耦合
    - 使用接口定义
    - 依赖注入
    - 事件驱动
    ### 可复用性
    设计可复用的组件
    - 工具函数独立
    - 数据模型通用
    - 配置灵活

    ```

    ### 2. 命名規範

    ~~~markdown

    ```markdown

    ## 命名规范

    ### 文件命名
    - 使用小写字母和下划线
    - 描述性名称
    - 避免缩写

    示例:
    - my_skill.py ✓
    - helpers.py ✓
    - validators.py ✓
    - MySkill.py ✗
    - helper.py ✗

    ### 类命名
    - 使用大驼峰命名法
    - 名词或名词短语
    - 描述性名称

    示例:
    - MySkill ✓
    - SkillContext ✓
    - InputSchema ✓
    - mySkill ✗
    - skill_context ✗

    ### 函数命名
    - 使用小写字母和下划线
    - 动词或动词短语
    - 描述性名称

    示例:
    - execute() ✓
    - process_input() ✓
    - validate_parameters() ✓
    - Execute() ✗
    - processInput() ✗

    ### 变量命名
    - 使用小写字母和下划线
    - 描述性名称
    - 避免单字母变量

    示例:
    - input_text ✓
    - result_data ✓
    - skill_context ✓
    - txt ✗
    - data ✗

    ```### 3. 目錄組織

    ## 目錄組織原則

    ### 按功能組織

    將相關功能放在同一目錄

    - utils/: 工具函式
    - models/: 資料模型
    - tests/: 測試程式碼

    ### 按層次組織

    保持清晰的層次結構

    - src/: 原始碼
    - tests/: 測試程式碼
    - docs/: 文件

    ### 避免過深巢狀

    目錄層次不超過 3

    - src/skills/my_skill.py ✓
    - src/skills/utils/helpers.py ✓
    - src/skills/utils/data/processors/helpers.py ✗

    ```
    ## 文档组织

    ### 1. API 文档

    ~~~markdown

    ```markdown

    # docs/api.md

    # MySkill API 文件

    ## 概述

    MySkill 是一個自定義的 Claude Code Skill,用於處理文字輸入。

    ## 引數

    ### input (必需)


    - 型別: string
    - 描述: 要處理的輸入文字
    - 示例: "hello world"

    ### options (可選)


    - 型別: object
    - 描述: 附加選項
    - 屬性:
      - format: 輸出格式 (json, yaml, text)
      - case: 大小寫轉換 (upper, lower, title)

    ## 返回值

    ### success


    - 型別: boolean
    - 描述: 操作是否成功

    ### data


    - 型別: object
    - 描述: 返回的資料
    - 屬性:
      - input: 原始輸入
      - output: 處理後的輸出

    ### message


    - 型別: string (可選)
    - 描述: 附加訊息

    ## 示例

    ### 基本使用

    ```python

    ```python

    from skills.my_skill import MySkill

    skill = MySkill()
    result = skill.execute(
        {"input": "hello world"},
        context
    )

    print(result.data["output"])  # "HELLO WORLD"

    ### 高階使用

    ```python

    result = skill.execute(
    {
    "input": "hello world",
    "options": {
    "format": "json",
    "case": "upper"
    }
    },
    context
    )

    ### 2. 使用文档

    # docs/usage.md
    # MySkill 使用指南
    ## 安装
    ~~~`bash
    `bash

    pip install my-skill

    ## 基本使用

    ### 命令行

    ~~~bash
    bash

    claude --skill my-skill --input "hello world"

    ### Python API

    ```python

    from skills.my_skill import MySkill
    from claude_code_sdk import SkillContext

    skill = MySkill()
    context = SkillContext()

    result = skill.execute(
    {"input": "hello world"},
    context
    )

    print(result.data["output"])

    ## 高階用法

    ### 自定義選項

    ```python
    python

    result = skill.execute(
        {
            "input": "hello world",
            "options": {
                "format": "yaml",
                "case": "title"
            }
        },
        context
    )

    ### 批量处理

    ```python

    inputs = ["hello", "world", "test"]

    results = []
    for input_text in inputs:
    result = skill.execute(
    {"input": input_text},
    context
    )
    results.append(result)

    ## 錯誤處理

    ### 缺少引數

    ```python
    python

    try:
        result = skill.execute({}, context)
    except KeyError as e:
        print(f"Missing parameter: {e}")

    ### 无效输入

    ```python

    from skills.utils.validators import validate_parameters

    parameters = {"input": 123}
    schema = skill.get_parameters_schema()

    if not validate_parameters(parameters, schema):
    print("Invalid parameters")

    ### 3. 開發文件

    ```
    # docs/development.md
    # MySkill 开发指南
    ## 开发环境设置
    ### 安装依赖
    ~~~`bash
    `bash

    pip install -e ".[dev]"

    ### 运行测试

    ~~~bash
    bash

    pytest

    ### 代码格式化

    ```bash

    black src/skills

    ### 程式碼檢查

    ~~~bash
    bash

    pylint src/skills

    ## 新增新功能

    ### 1. 建立新方法

    ```python

    def new_feature(self, data: str) -> str:
    """新功能"""
     # 实现逻辑
    return data

    ### 2. 添加测试

    ```python

    python

    def test_new_feature(self):
        """測試新功能"""
        result = self.skill.new_feature("test")
        assert result == "expected"

    ### 3. 更新文件

    更新 API 文件和使用文件。

    ## 釋出流程

    ### 1. 更新版本號

    ```python

    # setup.py
    version="0.2.0"

    ### 2. 更新变更日志

    ~~~markdown
    markdown

    # CHANGELOG.md

    ## [0.2.0] - 2024-01-15

    ### Added
    - 新功能描述

    ### Changed
    - 变更描述

    ### Fixed
    - 修复描述

    ### 3. 创建发布

    ```bash

    git tag v0.2.0
    git push origin v0.2.0

    ### 4. 釋出到 PyPI

    ~~~bash
    bash

    python setup.py sdist bdist_wheel
    twine upload dist/*

    ```

    ```

基于 MIT 许可发布 | 永久导航