コンテンツにスキップ

Claude Code 完全ガイド

Claude Sonnet 4×GitHub Copilot実装完全ガイド - 実践的開発手法とコード例【技術深掘り編】

はじめに

本記事は「AIエージェント開発革命2025」の技術深掘り編として、Claude Sonnet 4とGitHub Copilotの実装詳細に焦点を当てます。実際のコード例、詳細な設定手順、パフォーマンス最適化、そして実践的なトラブルシューティングまで包括的に解説します。

この記事のポイント

  • 高度なエージェント実装

    TypeScript/Pythonでの実装例とベストプラクティス

  • :material-settings-box: 詳細設定ガイド

    MCP設定、認証、プロジェクト統合の完全手順

  • トラブルシューティング

    よくある問題と解決策、デバッグ手法

  • パフォーマンス最適化

    レスポンス速度とリソース使用量の最適化技術

Claude Code CLI環境構築

1. 初期セットアップと認証

# Claude Code CLIインストール
npm install -g @anthropic/claude-cli

# 認証設定
claude auth login
# または環境変数設定
export ANTHROPIC_API_KEY="your-api-key-here"

# プロジェクト初期化
claude init --template advanced

2. CLAUDE.mdプロジェクト設定

# CLAUDE.md - プロジェクト設定例

## Project Context
- **Framework**: React + TypeScript + Node.js
- **Database**: PostgreSQL with Prisma ORM
- **Testing**: Jest + React Testing Library
- **CI/CD**: GitHub Actions + Docker

## Development Guidelines
- Use ESLint + Prettier for code formatting
- Follow conventional commits
- Write comprehensive tests for all features
- Document public APIs with TSDoc

## Agent Behaviors
- Always run tests before suggesting code changes
- Prioritize type safety and error handling
- Include comprehensive logging for debugging
- Follow existing code patterns and conventions

## Custom Tools
- `@database-agent`: PostgreSQL optimization and queries
- `@security-agent`: Security audit and vulnerability scanning
- `@test-agent`: Automated test generation and coverage analysis

3. カスタムエージェント設定

{
  "agents": {
    "database-expert": {
      "description": "PostgreSQL最適化エキスパート",
      "context": "@database-schema.md @performance-requirements.md",
      "tools": ["sql_analyzer", "performance_profiler"],
      "personality": "detail-oriented, performance-focused"
    },
    "security-specialist": {
      "description": "セキュリティ監査スペシャリスト", 
      "context": "@security-policies.md @compliance-requirements.md",
      "tools": ["vulnerability_scanner", "code_analyzer"],
      "personality": "security-first, thorough"
    }
  }
}

GitHub Copilot統合実装

1. VS Code拡張設定

// settings.json
{
  "github.copilot.enable": {
    "*": true,
    "yaml": false,
    "plaintext": false
  },
  "github.copilot.advanced": {
    "debug.overrideEngine": "claude-sonnet-4",
    "authProvider": "github"
  },
  "github.copilot.editor.enableAutoCompletions": true,
  "github.copilot.experimental": {
    "chat.codeGeneration": true,
    "chat.multiTurn": true
  }
}

2. カスタムプロンプト設定

// copilot-config.ts
interface CopilotConfiguration {
  model: 'claude-sonnet-4' | 'gpt-4o' | 'gpt-4.1';
  temperature: number;
  maxTokens: number;
  context: {
    codebase: boolean;
    documentation: boolean;
    tests: boolean;
  };
}

const config: CopilotConfiguration = {
  model: 'claude-sonnet-4',
  temperature: 0.2,
  maxTokens: 4096,
  context: {
    codebase: true,
    documentation: true,
    tests: true
  }
};

// プロジェクト固有プロンプト
export const PROJECT_PROMPTS = {
  codeGeneration: `
    Generate TypeScript code following our project conventions:
    - Use strict type checking
    - Include comprehensive error handling
    - Add JSDoc comments for public APIs
    - Follow our naming conventions: camelCase for variables, PascalCase for types
    - Use async/await instead of Promises.then()
  `,
  testGeneration: `
    Generate Jest tests with:
    - Comprehensive test coverage (happy path + edge cases)
    - Proper mocking of external dependencies
    - Clear test descriptions and assertions
    - Setup and teardown for database tests
  `
};

エージェント開発実装例

1. TypeScript実装 - 自律コーディングエージェント

// src/agents/CodingAgent.ts
import { ClaudeCodeClient } from '@anthropic/claude-code';
import { GitHubService } from '../services/GitHubService';
import { TestRunner } from '../services/TestRunner';

export class AutonomousCodingAgent {
  private claude: ClaudeCodeClient;
  private github: GitHubService;
  private testRunner: TestRunner;

  constructor(apiKey: string, githubToken: string) {
    this.claude = new ClaudeCodeClient({ apiKey });
    this.github = new GitHubService(githubToken);
    this.testRunner = new TestRunner();
  }

  async resolveIssue(issueNumber: number): Promise<{
    success: boolean;
    prUrl?: string;
    error?: string;
  }> {
    try {
      // 1. Issue内容を取得・分析
      const issue = await this.github.getIssue(issueNumber);
      const analysis = await this.claude.analyze({
        prompt: `
          Analyze this GitHub issue and create an implementation plan:

          Title: ${issue.title}
          Description: ${issue.body}
          Labels: ${issue.labels.map(l => l.name).join(', ')}

          Provide:
          1. Problem analysis
          2. Implementation approach
          3. File changes required
          4. Test strategy
        `,
        model: 'claude-sonnet-4',
        extendedThinking: true
      });

      // 2. 実装コード生成
      const implementation = await this.generateImplementation(analysis);

      // 3. テスト生成・実行
      const tests = await this.generateTests(implementation);
      const testResults = await this.testRunner.run(tests);

      if (!testResults.success) {
        throw new Error(`Tests failed: ${testResults.errors.join(', ')}`);
      }

      // 4. Pull Request作成
      const prUrl = await this.createPullRequest(
        issueNumber,
        implementation,
        tests,
        analysis.summary
      );

      return { success: true, prUrl };

    } catch (error) {
      return { 
        success: false, 
        error: error instanceof Error ? error.message : 'Unknown error'
      };
    }
  }

  private async generateImplementation(analysis: any): Promise<CodeImplementation[]> {
    const implementations: CodeImplementation[] = [];

    for (const fileChange of analysis.fileChanges) {
      const code = await this.claude.generate({
        prompt: `
          Generate ${fileChange.language} code for:

          File: ${fileChange.path}
          Purpose: ${fileChange.purpose}
          Requirements: ${fileChange.requirements.join(', ')}

          Follow project conventions and include:
          - Comprehensive error handling
          - Type safety (if TypeScript)
          - Proper logging
          - Performance optimization
        `,
        context: {
          files: await this.getRelatedFiles(fileChange.path),
          codebase: true
        }
      });

      implementations.push({
        path: fileChange.path,
        content: code,
        language: fileChange.language
      });
    }

    return implementations;
  }

  private async generateTests(implementations: CodeImplementation[]): Promise<TestSuite[]> {
    const testSuites: TestSuite[] = [];

    for (const impl of implementations) {
      if (impl.language === 'typescript' || impl.language === 'javascript') {
        const testCode = await this.claude.generate({
          prompt: `
            Generate comprehensive Jest tests for this code:

            ${impl.content}

            Include:
            - Unit tests for all public methods
            - Integration tests for complex workflows
            - Edge case testing
            - Mock external dependencies
            - 90%+ code coverage
          `
        });

        testSuites.push({
          path: impl.path.replace(/\.(ts|js)$/, '.test.$1'),
          content: testCode,
          type: 'jest'
        });
      }
    }

    return testSuites;
  }

  private async createPullRequest(
    issueNumber: number,
    implementations: CodeImplementation[],
    tests: TestSuite[],
    summary: string
  ): Promise<string> {
    // 新しいブランチ作成
    const branchName = `fix/issue-${issueNumber}-${Date.now()}`;
    await this.github.createBranch(branchName);

    // ファイル変更をコミット
    for (const impl of implementations) {
      await this.github.updateFile(impl.path, impl.content, `Implement ${impl.path}`);
    }

    for (const test of tests) {
      await this.github.updateFile(test.path, test.content, `Add tests for ${test.path}`);
    }

    // Pull Request作成
    const prUrl = await this.github.createPullRequest({
      title: `Fix #${issueNumber}: ${summary}`,
      body: `
        ## 概要
        ${summary}

        ## 変更内容
        ${implementations.map(i => `- \`${i.path}\`: ${i.purpose || '実装追加'}`).join('\n')}

        ## テスト
        ${tests.map(t => `- \`${t.path}\`: ${t.type}テスト追加`).join('\n')}

        ## 確認事項
        - [ ] 全テストが通過
        - [ ] コードレビュー完了
        - [ ] ドキュメント更新(必要な場合)

        Closes #${issueNumber}
      `,
      base: 'main',
      head: branchName
    });

    return prUrl;
  }
}

// 使用例
const agent = new AutonomousCodingAgent(
  process.env.ANTHROPIC_API_KEY!,
  process.env.GITHUB_TOKEN!
);

// GitHub Issue #123を自動解決
agent.resolveIssue(123).then(result => {
  if (result.success) {
    console.log(`Pull Request created: ${result.prUrl}`);
  } else {
    console.error(`Failed to resolve issue: ${result.error}`);
  }
});

2. Python実装 - MCP統合エージェント

# agents/mcp_integration_agent.py
import asyncio
import json
from typing import Dict, List, Any, Optional
from dataclasses import dataclass
from pathlib import Path

import anthropic
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

@dataclass
class MCPServer:
    name: str
    command: str
    args: List[str]
    env: Dict[str, str] = None

class MCPIntegrationAgent:
    def __init__(self, anthropic_api_key: str):
        self.client = anthropic.Anthropic(api_key=anthropic_api_key)
        self.mcp_servers: Dict[str, ClientSession] = {}

    async def initialize_mcp_servers(self, servers: List[MCPServer]):
        """MCP サーバーを初期化して接続"""
        for server in servers:
            try:
                server_params = StdioServerParameters(
                    command=server.command,
                    args=server.args,
                    env=server.env or {}
                )

                async with stdio_client(server_params) as (read, write):
                    async with ClientSession(read, write) as session:
                        await session.initialize()
                        self.mcp_servers[server.name] = session

                        # サーバーの利用可能なツールを確認
                        tools = await session.list_tools()
                        print(f"Connected to {server.name}: {len(tools.tools)} tools available")

            except Exception as e:
                print(f"Failed to connect to {server.name}: {e}")

    async def execute_with_mcp_tools(self, prompt: str, server_names: List[str] = None) -> str:
        """MCP ツールを使用してタスクを実行"""

        # 利用可能なツールを収集
        available_tools = {}
        target_servers = server_names or list(self.mcp_servers.keys())

        for server_name in target_servers:
            if server_name in self.mcp_servers:
                session = self.mcp_servers[server_name]
                tools = await session.list_tools()
                available_tools[server_name] = tools.tools

        # Claude に利用可能なツールと共にプロンプトを送信
        tools_description = self._format_tools_for_claude(available_tools)

        enhanced_prompt = f"""
        {prompt}

        利用可能なMCPツール:
        {tools_description}

        必要に応じてこれらのツールを使用してタスクを完了してください。
        ツールを使用する場合は、JSON形式で以下のように指定してください:
        {{"tool_call": {{"server": "server_name", "tool": "tool_name", "arguments": {{...}}}}}}
        """

        # Claude APIを呼び出し
        response = self.client.messages.create(
            model="claude-3-sonnet-20241022",
            max_tokens=4096,
            messages=[{"role": "user", "content": enhanced_prompt}]
        )

        response_text = response.content[0].text

        # ツール呼び出しを解析・実行
        updated_response = await self._process_tool_calls(response_text)

        return updated_response

    async def _process_tool_calls(self, response: str) -> str:
        """レスポンス内のツール呼び出しを処理"""
        import re

        # JSON形式のツール呼び出しを検索
        tool_call_pattern = r'\{"tool_call":\s*\{[^}]+\}\}'
        tool_calls = re.findall(tool_call_pattern, response)

        updated_response = response

        for call_json in tool_calls:
            try:
                call_data = json.loads(call_json)
                tool_call = call_data["tool_call"]

                server_name = tool_call["server"]
                tool_name = tool_call["tool"]
                arguments = tool_call.get("arguments", {})

                if server_name in self.mcp_servers:
                    session = self.mcp_servers[server_name]
                    result = await session.call_tool(tool_name, arguments)

                    # ツール呼び出し結果でレスポンスを更新
                    result_text = f"ツール実行結果 ({server_name}/{tool_name}): {result.content}"
                    updated_response = updated_response.replace(call_json, result_text)

            except Exception as e:
                error_text = f"ツール実行エラー: {e}"
                updated_response = updated_response.replace(call_json, error_text)

        return updated_response

    def _format_tools_for_claude(self, tools_by_server: Dict[str, List]) -> str:
        """ツール情報をClaude用にフォーマット"""
        formatted = []

        for server_name, tools in tools_by_server.items():
            formatted.append(f"**{server_name}:**")
            for tool in tools:
                formatted.append(f"  - {tool.name}: {tool.description}")
                if hasattr(tool, 'inputSchema'):
                    formatted.append(f"    引数: {json.dumps(tool.inputSchema, ensure_ascii=False)}")

        return "\n".join(formatted)

# 使用例
async def main():
    # MCP サーバー設定
    servers = [
        MCPServer(
            name="filesystem",
            command="python",
            args=["-m", "mcp_server_filesystem"],
            env={"PYTHONPATH": "."}
        ),
        MCPServer(
            name="database",
            command="node",
            args=["mcp-server-postgres.js"],
            env={"DB_CONNECTION_STRING": "postgresql://localhost/mydb"}
        ),
        MCPServer(
            name="web_search",
            command="python",
            args=["-m", "mcp_server_web_search"],
            env={"SEARCH_API_KEY": "your-search-api-key"}
        )
    ]

    # エージェント初期化
    agent = MCPIntegrationAgent(
        anthropic_api_key="your-anthropic-api-key"
    )

    # MCP サーバー接続
    await agent.initialize_mcp_servers(servers)

    # タスク実行例
    result = await agent.execute_with_mcp_tools(
        "プロジェクトのREADME.mdファイルを読み取り、データベースから関連する統計情報を取得して、最新の市場動向を検索してレポートを作成してください。",
        server_names=["filesystem", "database", "web_search"]
    )

    print("実行結果:")
    print(result)

if __name__ == "__main__":
    asyncio.run(main())

高度な設定とカスタマイズ

1. GitHub Actions統合

# .github/workflows/ai-agent-ci.yml
name: AI Agent CI/CD

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  ai-code-review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Claude Code CLI
        run: |
          npm install -g @anthropic/claude-cli
          claude auth login --api-key "${{ secrets.ANTHROPIC_API_KEY }}"

      - name: AI Code Review
        run: |
          claude review --format json --output review-results.json

      - name: Upload Review Results
        uses: actions/upload-artifact@v4
        with:
          name: ai-review-results
          path: review-results.json

  automated-testing:
    runs-on: ubuntu-latest
    needs: ai-code-review
    steps:
      - uses: actions/checkout@v4

      - name: Generate AI Tests
        env:
          ANTHROPIC_API_KEY: "${{ secrets.ANTHROPIC_API_KEY }}"
        run: |
          claude generate-tests --coverage 90 --output tests/generated/

      - name: Run Generated Tests
        run: |
          npm test -- tests/generated/

      - name: Coverage Report
        run: |
          npm run coverage -- --coverageDirectory=coverage/ai-generated

  auto-deploy:
    runs-on: ubuntu-latest
    needs: [ai-code-review, automated-testing]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: AI Deployment Validation
        env:
          ANTHROPIC_API_KEY: "${{ secrets.ANTHROPIC_API_KEY }}"
        run: |
          claude validate-deployment --environment production

      - name: Deploy with AI Monitoring
        run: |
          # デプロイ処理...
          claude monitor-deployment --duration 300 --alerts-webhook "${{ secrets.SLACK_WEBHOOK }}"

2. 詳細パフォーマンス設定

{
  "claude_code_config": {
    "performance": {
      "cache": {
        "enabled": true,
        "ttl": 3600,
        "max_size": "500MB",
        "strategy": "lru"
      },
      "concurrency": {
        "max_parallel_requests": 5,
        "request_queue_size": 50,
        "timeout": 30000
      },
      "optimization": {
        "context_compression": true,
        "incremental_updates": true,
        "smart_batching": true
      }
    },
    "quality": {
      "code_standards": {
        "eslint_config": ".eslintrc.js",
        "prettier_config": ".prettierrc",
        "typescript_strict": true
      },
      "testing": {
        "min_coverage": 85,
        "auto_generate_tests": true,
        "test_frameworks": ["jest", "vitest", "playwright"]
      }
    },
    "security": {
      "scan_dependencies": true,
      "check_secrets": true,
      "validate_inputs": true,
      "audit_logs": true
    }
  }
}

トラブルシューティング

1. よくある問題と解決策

// troubleshooting/DiagnosticTools.ts
export class ClaudeCodeDiagnostics {

  async diagnoseConnection(): Promise<DiagnosticResult> {
    const results: DiagnosticResult = {
      apiConnection: false,
      modelAccess: false,
      mcpServers: {},
      githubIntegration: false,
      recommendations: []
    };

    try {
      // API接続テスト
      const client = new ClaudeCodeClient();
      await client.ping();
      results.apiConnection = true;

      // モデルアクセステスト
      const response = await client.complete({
        prompt: "Test connection",
        model: "claude-sonnet-4",
        maxTokens: 10
      });
      results.modelAccess = !!response;

    } catch (error) {
      results.recommendations.push({
        issue: "API接続エラー",
        solution: "ANTHROPIC_API_KEYを確認し、ネットワーク接続をチェックしてください",
        error: error.message
      });
    }

    // MCP サーバー診断
    for (const serverName of this.getConfiguredMCPServers()) {
      try {
        const isHealthy = await this.checkMCPServerHealth(serverName);
        results.mcpServers[serverName] = isHealthy;

        if (!isHealthy) {
          results.recommendations.push({
            issue: `MCP サーバー "${serverName}" が応答しません`,
            solution: `サーバーを再起動するか、設定を確認してください`,
            command: `claude mcp restart ${serverName}`
          });
        }
      } catch (error) {
        results.mcpServers[serverName] = false;
        results.recommendations.push({
          issue: `MCP サーバー "${serverName}" エラー`,
          solution: `設定ファイルとログを確認してください`,
          error: error.message
        });
      }
    }

    return results;
  }

  async optimizePerformance(): Promise<OptimizationResult> {
    const analysis = await this.analyzePerformance();
    const optimizations: Optimization[] = [];

    // レスポンス時間が遅い場合
    if (analysis.averageResponseTime > 5000) {
      optimizations.push({
        type: "cache",
        description: "レスポンスキャッシュを有効化",
        impact: "50-70%高速化",
        implementation: "config.cache.enabled = true"
      });
    }

    // メモリ使用量が多い場合
    if (analysis.memoryUsage > 1000) {
      optimizations.push({
        type: "memory",
        description: "コンテキスト圧縮を有効化",
        impact: "30-40%メモリ削減",
        implementation: "config.optimization.context_compression = true"
      });
    }

    // 同時リクエスト数の最適化
    if (analysis.concurrentRequests > 10) {
      optimizations.push({
        type: "concurrency",
        description: "並行処理数を調整",
        impact: "安定性向上",
        implementation: `config.concurrency.max_parallel_requests = ${Math.ceil(analysis.concurrentRequests * 0.7)}`
      });
    }

    return {
      current_performance: analysis,
      optimizations,
      estimated_improvement: this.calculateEstimatedImprovement(optimizations)
    };
  }

  async generateDebugReport(): Promise<string> {
    const diagnostic = await this.diagnoseConnection();
    const performance = await this.optimizePerformance();
    const logs = await this.collectRecentLogs();

    return `
# Claude Code Debug Report
Generated: ${new Date().toISOString()}

## Connection Status
- API Connection: ${diagnostic.apiConnection ? '✅' : '❌'}
- Model Access: ${diagnostic.modelAccess ? '✅' : '❌'}
- GitHub Integration: ${diagnostic.githubIntegration ? '✅' : '❌'}

## MCP Servers
${Object.entries(diagnostic.mcpServers)
  .map(([name, status]) => `- ${name}: ${status ? '✅' : '❌'}`)
  .join('\n')}

## Performance Analysis
- Average Response Time: ${performance.current_performance.averageResponseTime}ms
- Memory Usage: ${performance.current_performance.memoryUsage}MB
- Cache Hit Rate: ${performance.current_performance.cacheHitRate}%

## Recommendations
${diagnostic.recommendations
  .map(rec => `- **${rec.issue}**: ${rec.solution}`)
  .join('\n')}

## Recent Errors
${logs.errors.slice(0, 5).map(error => `- ${error.timestamp}: ${error.message}`).join('\n')}

## Optimization Suggestions
${performance.optimizations
  .map(opt => `- ${opt.description} (${opt.impact})`)
  .join('\n')}
    `;
  }
}

// 使用例
const diagnostics = new ClaudeCodeDiagnostics();

// 問題診断
diagnostics.diagnoseConnection().then(result => {
  console.log('Diagnostic Results:', result);

  if (result.recommendations.length > 0) {
    console.log('\n推奨アクション:');
    result.recommendations.forEach(rec => {
      console.log(`- ${rec.solution}`);
      if (rec.command) {
        console.log(`  実行: ${rec.command}`);
      }
    });
  }
});

// デバッグレポート生成
diagnostics.generateDebugReport().then(report => {
  console.log(report);
});

2. ログ解析と監視

# monitoring/claude_monitor.py
import asyncio
import json
import logging
from datetime import datetime, timedelta
from typing import List, Dict, Any
from dataclasses import dataclass, asdict
import aiofiles
import psutil

@dataclass
class PerformanceMetric:
    timestamp: datetime
    response_time: float
    memory_usage: float
    cpu_usage: float
    cache_hit_rate: float
    error_rate: float

class ClaudeCodeMonitor:
    def __init__(self, log_file: str = "claude_code.log"):
        self.log_file = log_file
        self.metrics: List[PerformanceMetric] = []
        self.alerts: List[Dict[str, Any]] = []

        # ログ設定
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_file),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger('ClaudeCodeMonitor')

    async def collect_metrics(self) -> PerformanceMetric:
        """現在のパフォーマンスメトリクスを収集"""

        # システムメトリクス
        cpu_usage = psutil.cpu_percent(interval=1)
        memory = psutil.virtual_memory()
        memory_usage = memory.percent

        # Claude Code固有メトリクス(ログから解析)
        response_time = await self._calculate_avg_response_time()
        cache_hit_rate = await self._calculate_cache_hit_rate()
        error_rate = await self._calculate_error_rate()

        metric = PerformanceMetric(
            timestamp=datetime.now(),
            response_time=response_time,
            memory_usage=memory_usage,
            cpu_usage=cpu_usage,
            cache_hit_rate=cache_hit_rate,
            error_rate=error_rate
        )

        self.metrics.append(metric)

        # 古いメトリクスを削除(24時間以上前)
        cutoff_time = datetime.now() - timedelta(hours=24)
        self.metrics = [m for m in self.metrics if m.timestamp > cutoff_time]

        return metric

    async def _calculate_avg_response_time(self) -> float:
        """過去1時間の平均レスポンス時間を計算"""
        try:
            async with aiofiles.open(self.log_file, 'r') as f:
                content = await f.read()

            # レスポンス時間のログエントリを解析
            import re
            response_time_pattern = r'response_time:(\d+\.?\d*)ms'
            matches = re.findall(response_time_pattern, content)

            if matches:
                times = [float(match) for match in matches[-100:]]  # 最新100件
                return sum(times) / len(times)

            return 0.0
        except Exception:
            return 0.0

    async def _calculate_cache_hit_rate(self) -> float:
        """キャッシュヒット率を計算"""
        try:
            async with aiofiles.open(self.log_file, 'r') as f:
                content = await f.read()

            cache_hits = content.count('cache:hit')
            cache_misses = content.count('cache:miss')
            total = cache_hits + cache_misses

            return (cache_hits / total * 100) if total > 0 else 0.0
        except Exception:
            return 0.0

    async def _calculate_error_rate(self) -> float:
        """エラー率を計算"""
        try:
            async with aiofiles.open(self.log_file, 'r') as f:
                content = await f.read()

            error_count = content.count('ERROR')
            total_requests = content.count('REQUEST')

            return (error_count / total_requests * 100) if total_requests > 0 else 0.0
        except Exception:
            return 0.0

    async def check_alerts(self, metric: PerformanceMetric):
        """アラート条件をチェック"""
        alerts = []

        # レスポンス時間アラート
        if metric.response_time > 10000:  # 10秒以上
            alerts.append({
                'type': 'performance',
                'severity': 'critical',
                'message': f'レスポンス時間が異常に長い: {metric.response_time}ms',
                'recommendation': 'キャッシュ設定を確認し、不要なコンテキストを削減してください'
            })

        # メモリ使用量アラート
        if metric.memory_usage > 90:
            alerts.append({
                'type': 'resource',
                'severity': 'warning',
                'message': f'メモリ使用量が高い: {metric.memory_usage}%',
                'recommendation': 'コンテキスト圧縮を有効化するか、並行処理数を削減してください'
            })

        # エラー率アラート
        if metric.error_rate > 5:  # 5%以上
            alerts.append({
                'type': 'error',
                'severity': 'critical',
                'message': f'エラー率が高い: {metric.error_rate}%',
                'recommendation': 'ログを確認し、根本原因を特定してください'
            })

        # キャッシュヒット率アラート
        if metric.cache_hit_rate < 50:  # 50%未満
            alerts.append({
                'type': 'cache',
                'severity': 'info',
                'message': f'キャッシュヒット率が低い: {metric.cache_hit_rate}%',
                'recommendation': 'キャッシュTTLを調整するか、キャッシュサイズを増やしてください'
            })

        for alert in alerts:
            alert['timestamp'] = datetime.now().isoformat()
            self.alerts.append(alert)
            self.logger.warning(f"ALERT: {alert['message']}")

        return alerts

    async def generate_report(self) -> Dict[str, Any]:
        """パフォーマンスレポートを生成"""
        if not self.metrics:
            return {"error": "メトリクスデータがありません"}

        recent_metrics = self.metrics[-100:]  # 最新100件

        avg_response_time = sum(m.response_time for m in recent_metrics) / len(recent_metrics)
        avg_memory_usage = sum(m.memory_usage for m in recent_metrics) / len(recent_metrics)
        avg_cache_hit_rate = sum(m.cache_hit_rate for m in recent_metrics) / len(recent_metrics)
        avg_error_rate = sum(m.error_rate for m in recent_metrics) / len(recent_metrics)

        return {
            "report_generated": datetime.now().isoformat(),
            "period": "過去24時間",
            "summary": {
                "average_response_time": f"{avg_response_time:.2f}ms",
                "average_memory_usage": f"{avg_memory_usage:.1f}%",
                "average_cache_hit_rate": f"{avg_cache_hit_rate:.1f}%",
                "average_error_rate": f"{avg_error_rate:.2f}%"
            },
            "recent_alerts": len([a for a in self.alerts if 
                datetime.fromisoformat(a['timestamp']) > datetime.now() - timedelta(hours=1)]),
            "recommendations": self._generate_recommendations(recent_metrics),
            "detailed_metrics": [asdict(m) for m in recent_metrics[-20:]]  # 最新20件の詳細
        }

    def _generate_recommendations(self, metrics: List[PerformanceMetric]) -> List[str]:
        """メトリクスに基づく推奨事項を生成"""
        recommendations = []

        avg_response = sum(m.response_time for m in metrics) / len(metrics)
        avg_cache_hit = sum(m.cache_hit_rate for m in metrics) / len(metrics)
        avg_error = sum(m.error_rate for m in metrics) / len(metrics)

        if avg_response > 5000:
            recommendations.append("レスポンス時間が長いため、コンテキスト圧縮またはキャッシュの有効化を検討してください")

        if avg_cache_hit < 70:
            recommendations.append("キャッシュヒット率が低いため、キャッシュ戦略の見直しを推奨します")

        if avg_error > 2:
            recommendations.append("エラー率が高いため、入力検証とエラーハンドリングの強化が必要です")

        return recommendations

# 使用例
async def main():
    monitor = ClaudeCodeMonitor()

    # 監視ループ
    while True:
        try:
            # メトリクス収集
            metric = await monitor.collect_metrics()

            # アラートチェック
            alerts = await monitor.check_alerts(metric)

            # 1時間ごとにレポート生成
            if datetime.now().minute == 0:
                report = await monitor.generate_report()
                print(json.dumps(report, indent=2, ensure_ascii=False))

            # 5分間待機
            await asyncio.sleep(300)

        except KeyboardInterrupt:
            print("監視を停止します...")
            break
        except Exception as e:
            monitor.logger.error(f"監視エラー: {e}")
            await asyncio.sleep(60)  # エラー時は1分待機

if __name__ == "__main__":
    asyncio.run(main())

パフォーマンス最適化

1. コンテキスト管理最適化

// optimization/ContextManager.ts
export class SmartContextManager {
  private contextCache: Map<string, CachedContext> = new Map();
  private compressionRatio: number = 0.7;

  async optimizeContext(context: string, maxTokens: number): Promise<string> {
    const contextHash = this.hashContext(context);

    // キャッシュチェック
    if (this.contextCache.has(contextHash)) {
      const cached = this.contextCache.get(contextHash)!;
      if (Date.now() - cached.timestamp < 3600000) { // 1時間有効
        return cached.optimizedContext;
      }
    }

    let optimizedContext = context;

    // トークン数が上限を超える場合は圧縮
    const tokenCount = this.countTokens(context);
    if (tokenCount > maxTokens) {
      optimizedContext = await this.compressContext(context, maxTokens);
    }

    // 関連性の低い情報を除去
    optimizedContext = await this.removeIrrelevantInfo(optimizedContext);

    // 重要な情報を強調
    optimizedContext = this.highlightImportantInfo(optimizedContext);

    // キャッシュに保存
    this.contextCache.set(contextHash, {
      originalContext: context,
      optimizedContext,
      timestamp: Date.now(),
      compressionRatio: context.length / optimizedContext.length
    });

    return optimizedContext;
  }

  private async compressContext(context: string, maxTokens: number): Promise<string> {
    // セクション別に重要度を分析
    const sections = this.parseIntoSections(context);
    const scoredSections = await this.scoreRelevance(sections);

    // 重要度順にソートして必要な分だけ選択
    scoredSections.sort((a, b) => b.score - a.score);

    let compressedContext = "";
    let currentTokens = 0;

    for (const section of scoredSections) {
      const sectionTokens = this.countTokens(section.content);
      if (currentTokens + sectionTokens <= maxTokens * this.compressionRatio) {
        compressedContext += section.content + "\n";
        currentTokens += sectionTokens;
      }
    }

    return compressedContext;
  }

  private parseIntoSections(context: string): Section[] {
    // コンテキストを論理的なセクションに分割
    const sections: Section[] = [];
    const lines = context.split('\n');

    let currentSection: Section = { type: 'general', content: '', startLine: 0 };

    for (let i = 0; i < lines.length; i++) {
      const line = lines[i];

      // コードブロックの検出
      if (line.startsWith('```')) {
        if (currentSection.content) {
          sections.push(currentSection);
        }
        currentSection = { type: 'code', content: line + '\n', startLine: i };
      }
      // 見出しの検出
      else if (line.startsWith('#')) {
        if (currentSection.content) {
          sections.push(currentSection);
        }
        currentSection = { type: 'heading', content: line + '\n', startLine: i };
      }
      // エラーメッセージの検出
      else if (line.includes('Error') || line.includes('Exception')) {
        if (currentSection.content) {
          sections.push(currentSection);
        }
        currentSection = { type: 'error', content: line + '\n', startLine: i };
      }
      else {
        currentSection.content += line + '\n';
      }
    }

    if (currentSection.content) {
      sections.push(currentSection);
    }

    return sections;
  }

  private async scoreRelevance(sections: Section[]): Promise<ScoredSection[]> {
    // セクションの重要度スコアリング
    return sections.map(section => {
      let score = 0;

      // タイプ別基本スコア
      switch (section.type) {
        case 'error': score += 10; break;
        case 'code': score += 8; break;
        case 'heading': score += 6; break;
        case 'general': score += 3; break;
      }

      // キーワードボーナス
      const importantKeywords = ['error', 'bug', 'fix', 'implement', 'TODO', 'FIXME'];
      for (const keyword of importantKeywords) {
        if (section.content.toLowerCase().includes(keyword.toLowerCase())) {
          score += 2;
        }
      }

      // 長さペナルティ(長すぎるセクションは重要度を下げる)
      if (section.content.length > 1000) {
        score -= Math.floor(section.content.length / 1000);
      }

      return { ...section, score };
    });
  }
}

2. リクエスト最適化

// optimization/RequestOptimizer.ts
export class RequestOptimizer {
  private requestQueue: RequestQueue = new RequestQueue();
  private batchProcessor: BatchProcessor = new BatchProcessor();

  async optimizeRequest(request: ClaudeRequest): Promise<ClaudeResponse> {
    // リクエストの種類を分析
    const requestType = this.analyzeRequestType(request);

    switch (requestType) {
      case 'batch_suitable':
        return this.batchProcessor.addToBatch(request);

      case 'high_priority':
        return this.executeImmediate(request);

      case 'cacheable':
        return this.executeWithCaching(request);

      default:
        return this.requestQueue.enqueue(request);
    }
  }

  private analyzeRequestType(request: ClaudeRequest): RequestType {
    // コード生成系は並列処理可能
    if (request.prompt.includes('generate') && request.prompt.includes('code')) {
      return 'batch_suitable';
    }

    // エラー修正は高優先度
    if (request.prompt.includes('error') || request.prompt.includes('fix')) {
      return 'high_priority';
    }

    // 説明系はキャッシュ可能
    if (request.prompt.includes('explain') || request.prompt.includes('what is')) {
      return 'cacheable';
    }

    return 'standard';
  }

  async executeWithCaching(request: ClaudeRequest): Promise<ClaudeResponse> {
    const cacheKey = this.generateCacheKey(request);

    // キャッシュチェック
    const cached = await this.cache.get(cacheKey);
    if (cached && !this.isCacheExpired(cached)) {
      return cached.response;
    }

    // 新しいリクエスト実行
    const response = await this.executeRequest(request);

    // キャッシュに保存
    await this.cache.set(cacheKey, {
      response,
      timestamp: Date.now(),
      ttl: this.calculateTTL(request)
    });

    return response;
  }
}

パフォーマンス最適化のポイント

  • コンテキスト圧縮: 不要な情報を除去し、重要な情報のみを保持
  • リクエストバッチング: 類似したリクエストをまとめて処理
  • インテリジェントキャッシング: リクエストの種類に応じたキャッシュ戦略
  • 並列処理最適化: I/Oバウンドなタスクの効率的な並列実行

まとめ

  • 実装レベルの深掘り - TypeScript/Pythonでの具体的な実装例を提供
  • 詳細設定ガイド - MCP統合、GitHub Actions、パフォーマンス設定の完全手順
  • 実践的トラブルシューティング - 診断ツール、監視システム、最適化手法
  • プロダクションレディ - セキュリティ、品質管理、監視を含む本格運用対応

Claude Sonnet 4×GitHub Copilotの真の実力を引き出すには、これらの実装詳細と最適化技術の理解が不可欠です。本記事の技術を活用して、次世代のAIエージェント開発を実現してください。

関連記事