コンテンツにスキップ

Claude Code 完全ガイド

Claude Skills API実装ガイド - 本番運用のためのエラーハンドリングとベストプラクティス

この記事は比較記事のフォローアップです

基本概念は Claude Skills vs Projects徹底比較 を参照してください。

ゴール

この記事を読むことで、以下が実現できます:

  • Claude Skills APIの堅牢なエラーハンドリング実装
  • カスタムスキルのアップロード・バージョン管理の自動化
  • トークン消費の監視と最適化
  • 本番環境で発生する失敗パターンの事前回避

アーキテクチャ概要

graph LR
    A[アプリケーション] -->|1. Skills API| B[カスタムスキル管理]
    A -->|2. Messages API| C[チャット実行]
    B -->|スキルID| C
    C -->|3. レスポンス| D[トークン監視]
    D -->|4. ログ| E[運用監視]

    style B fill:#667eea
    style D fill:#764ba2

フロー: 1. カスタムスキルをアップロード(Skills API) 2. スキルIDを取得・保存 3. Messages APIでスキルを指定して実行 4. トークン消費を監視・ログ記録


実装ステップ

ステップ1: 基本的なSkills API呼び出し

まずは最小限の実装から始めます。

import anthropic
from anthropic import Anthropic

client = Anthropic(api_key="YOUR_API_KEY")

# Anthropic管理スキルを使用
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    betas=["skills-2025-01-07", "code-execution-2025-01-07"],
    tools=[{"type": "code_execution"}],
    container={"skills": ["xlsx", "pptx"]},  # container.skills で指定
    messages=[{
        "role": "user",
        "content": "売上データをExcelにまとめて"
    }]
)

print(response.content)

注意点: - betasパラメータでSkills APIを有効化 - code_executionツールはxlsx/pptxスキルに必要 - スキル名は正確に指定(大文字小文字を区別)


ステップ2: エラーハンドリングとリトライロジック

本番環境では、レート制限やネットワークエラーに対応する必要があります。

import time
from anthropic import Anthropic, APIError, RateLimitError

def call_skills_api_with_retry(
    client: Anthropic,
    skills: list[str],
    messages: list[dict],
    max_retries: int = 3,
    base_delay: float = 2.0
) -> dict:
    """
    リトライロジック付きSkills API呼び出し

    Args:
        client: Anthropicクライアント
        skills: 使用するスキルのリスト
        messages: メッセージ履歴
        max_retries: 最大リトライ回数
        base_delay: 基本待機時間(秒)

    Returns:
        APIレスポンス
    """
    for attempt in range(max_retries):
        try:
            response = client.messages.create(
                model="claude-sonnet-4-6",
                max_tokens=1024,
                betas=["skills-2025-01-07", "code-execution-2025-01-07"],
                tools=[{"type": "code_execution"}],
                container={"skills": skills},
                messages=messages
            )
            return response

        except RateLimitError as e:
            if attempt == max_retries - 1:
                raise
            # Exponential backoff
            wait_time = base_delay * (2 ** attempt)
            print(f"Rate limit hit. Retry {attempt+1}/{max_retries} after {wait_time}s")
            time.sleep(wait_time)

        except APIError as e:
            print(f"API Error: {e}")
            if attempt == max_retries - 1:
                raise
            time.sleep(base_delay)

    raise Exception("Max retries exceeded")

実装ポイント: - Exponential backoffでレート制限を回避 - RateLimitErrorと一般的なAPIErrorを区別 - 最終試行時は例外をそのまま上げて上位でハンドリング


ステップ3: カスタムスキルのアップロードと管理

カスタムスキルを動的にアップロード・更新する実装です。

import hashlib
import json
from pathlib import Path
from anthropic import Anthropic

class SkillManager:
    """カスタムスキルのアップロード・バージョン管理"""

    def __init__(self, client: Anthropic, cache_file: str = ".skill_cache.json"):
        self.client = client
        self.cache_file = Path(cache_file)
        self.cache = self._load_cache()

    def _load_cache(self) -> dict:
        """キャッシュファイルからスキルID情報を読み込み"""
        if self.cache_file.exists():
            return json.loads(self.cache_file.read_text())
        return {}

    def _save_cache(self):
        """キャッシュファイルに保存"""
        self.cache_file.write_text(json.dumps(self.cache, indent=2))

    def _calc_hash(self, content: str) -> str:
        """スキル内容のハッシュ計算(変更検知用)"""
        return hashlib.sha256(content.encode()).hexdigest()[:16]

    def upload_skill(self, skill_path: Path, force_update: bool = False) -> str:
        """
        カスタムスキルをアップロード

        Args:
            skill_path: スキルファイルのパス
            force_update: 強制更新フラグ

        Returns:
            スキルID
        """
        content = skill_path.read_text()
        content_hash = self._calc_hash(content)
        cache_key = str(skill_path)

        # キャッシュヒット判定
        if not force_update and cache_key in self.cache:
            cached = self.cache[cache_key]
            if cached["hash"] == content_hash:
                print(f"Using cached skill: {cached['skill_id']}")
                return cached["skill_id"]

        # Skills APIでアップロード
        # 注: 実際のアップロードAPIは未公開のため、疑似コード
        skill_id = self._upload_to_api(content)

        # キャッシュ更新
        self.cache[cache_key] = {
            "skill_id": skill_id,
            "hash": content_hash,
            "uploaded_at": time.time()
        }
        self._save_cache()

        print(f"Uploaded skill: {skill_id}")
        return skill_id

    def _upload_to_api(self, content: str) -> str:
        """
        実際のアップロード処理(疑似実装)

        注: カスタムスキルアップロードAPIはBetaステージです。
        公式ガイドでは /v1/skills エンドポイントが存在し、
        Skills API QuickstartやCreate Custom skillsのドキュメントが
        提供されています。詳細仕様は変更される可能性があります
        """
        # 実際の実装例(仕様確定後):
        # response = self.client.skills.create(
        #     content=content,
        #     name="custom-skill",
        #     version="1.0"
        # )
        # return response.skill_id

        return f"skill_{hashlib.sha256(content.encode()).hexdigest()[:12]}"

設計上の工夫: - ハッシュ計算で変更検知→不要なアップロード回避 - キャッシュファイルでスキルID永続化 - force_updateフラグで強制更新可能


トークン消費の特性理解

Progressive Disclosure(段階的開示)の仕組み

Claude Skillsは、必要な情報だけを必要な時にロードするアーキテクチャを採用しています。

動作フロー

1. 起動時: スキルの名前と説明(メタデータ)のみロード
            ↓
2. タスク判定: ユーザーリクエストに関連するスキルを特定
            ↓
3. 詳細ロード: 関連スキルの完全な指示とリソースを読み込み
            ↓
4. 実行: スキルを使用してタスクを処理

トークン効率性の特徴

公式ドキュメントによると、以下の特性があります:

スキル登録時: - 各スキルのメタデータは「数十トークン程度」(公式表現: "a few dozen tokens") - 複数スキルを登録しても、メタデータ分のみでベースラインへの影響は軽微

スキル実行時: - タスクに関連するスキルの詳細のみをロード - 無関係なスキルは詳細ロードされないため、登録数が多くても効率的

Projectsとの比較: - Projectsは全ドキュメント(最大200Kトークン)を常時ロード - Skillsは必要な部分のみの読み込みのため、大幅に軽量

注意:具体的な数値データについて

Claude Skillsのトークン消費に関する公式ベンチマークは公開されていません。上記は公式ドキュメントの定性的な説明に基づいています。

トークン監視の実装

実際のトークン消費は、APIレスポンスから確認できます:

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    betas=["skills-2025-01-07"],
    container={"skills": ["your-skill-id"]},
    messages=[{"role": "user", "content": "タスク"}]
)

# トークン消費の確認
usage = response.usage
print(f"入力トークン: {usage.input_tokens}")
print(f"出力トークン: {usage.output_tokens}")

失敗パターンと回避策

症状原因回避策
429 Rate Limit Error1分間のリクエスト過多Exponential backoff実装(ステップ2参照)
スキルが適用されないbeta headerの未指定betas=["skills-2025-01-07"]を必ず含める
Invalid skill nameスキル名のタイポ定数化 or 事前検証ロジック追加
トークン超過エラー大量スキル登録必要最小限に絞る(5個以下推奨)
キャッシュ不整合手動削除後の再実行force_update=Trueで強制再アップロード

自動化・拡張案

実装後の発展的な改善アイデア:

  1. CI/CDパイプライン統合
  2. スキルファイル変更検知→自動アップロード
  3. GitHub Actionsでバージョン管理

  4. トークン監視ダッシュボード

  5. リアルタイムコスト追跡
  6. アラート設定(日次予算超過時)

  7. A/Bテスト基盤

  8. スキルバージョンごとの性能比較
  9. ユーザーフィードバック収集

  10. マルチテナント対応

  11. ワークスペースごとのスキル分離
  12. 権限管理(read-only/admin)

  13. フォールバック戦略

  14. スキル実行失敗時の通常モード自動切替
  15. デグレード防止

次のステップ


参考リンク