skill-logger について
skill-loggerは、スキルの品質を記録・評価するためのスキルで、利用データをもとに改善したい開発者向けです。呼び出しログ、品質シグナル、スコアリング、傾向分析、改善のフィードバックループを扱います。
主な機能
- 01スキル呼び出しとコンテキストの記録
- 02品質シグナルの収集
- 03多面的な品質スコアリング
- 04SQLiteとJSONのログ形式
- 05傾向分析と改善の手がかり
活用シーン
- 01スキル利用ログの設定
- 02スキルのバリエーション間で性能を比較
- 03品質低下やエラー増加の特定
- 04データに基づくスキル改善
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ curiositech/ some_claude_skills --skill skill-loggerインストール後、Claude Code で/skill-loggerを入力して読み込まれたか確認します。
同梱ファイル.claude-plugin/plugin.jsonreferences/scoring-rubric.md
詳細
スキルロガー
体系的なログ記録とスコアリングによって、スキルの品質を追跡、測定し、改善します。
このスキルを使用するタイミング
次の場合に使用します:
- スキルの使用状況をログに記録する仕組みを設定する
- スキルの出力に対する品質指標を定義する
- スキルのパフォーマンスを長期的に分析する
- 改善が必要なスキルを特定する
- スキル強化のためのフィードバックループを構築する
- スキルのバリエーションを A/B テストする
次の場合には使用しません:
- 新しいスキルを作成する場合 → agent-creator を使用します
- スキルのドキュメントを作成する場合 → skill-coach を使用します
- 実行時のデバッグを行う場合 → 適切なデバッガースキルを使用します
- 一般的なログ記録やモニタリングを行う場合 → devops-automator を使用します
ログ記録の中核となるアーキテクチャ
┌────────────────────────────────────────────────────────────────┐
│ SKILL LOGGING PIPELINE │
├────────────────────────────────────────────────────────────────┤
│ │
│ 1. CAPTURE 2. ANALYZE 3. SCORE │
│ ├─ Invocation ├─ Output parse ├─ Quality metrics │
│ ├─ Input context ├─ Token usage ├─ User satisfaction │
│ ├─ Output ├─ Tool calls ├─ Goal completion │
│ └─ Timing └─ Error patterns └─ Efficiency │
│ │
│ 4. AGGREGATE 5. ALERT 6. IMPROVE │
│ ├─ Per-skill stats ├─ Quality drops ├─ Identify patterns │
│ ├─ Trend analysis ├─ Error spikes ├─ Suggest changes │
│ └─ Comparisons └─ Underuse └─ Track experiments │
│ │
└────────────────────────────────────────────────────────────────┘
ログに記録する内容
呼び出しデータ
{
"invocation_id": "uuid",
"timestamp": "ISO8601",
"skill_name": "wedding-immortalist",
"skill_version": "1.2.0",
"input": {
"user_query": "Create a 3D model from my wedding photos",
"context_tokens": 1500,
"files_referenced": ["photos/", "config.json"]
},
"execution": {
"duration_ms": 45000,
"tool_calls": [
{"tool": "Bash", "count": 5},
{"tool": "Write", "count": 3}
],
"tokens_used": {
"input": 8500,
"output": 3200
},
"errors": []
},
"output": {
"type": "code_generation",
"artifacts_created": ["pipeline.py", "config.yaml"],
"response_length": 3200
}
}
品質シグナル
QUALITY_SIGNALS = {
# Implicit signals (automated)
'completion': 'Did the skill complete without errors?',
'token_efficiency': 'Output quality per token used',
'tool_success_rate': 'Tool calls that succeeded',
'retry_count': 'How many retries needed?',
# Explicit signals (user feedback)
'user_edit_ratio': 'How much did user modify output?',
'user_accepted': 'Did user accept/use the output?',
'follow_up_needed': 'Did user need to ask for fixes?',
'explicit_rating': 'Thumbs up/down if available',
# Outcome signals (delayed)
'code_ran_successfully': 'Did generated code work?',
'tests_passed': 'Did it pass tests?',
'reverted': 'Was the output later reverted?',
}
スコアリングフレームワーク
多次元品質スコア
def calculate_skill_score(invocation_log):
"""Score a skill invocation 0-100."""
scores = {
# Completion (25%)
'completion': (
25 if invocation_log['errors'] == [] else
15 if invocation_log['recovered'] else
0
),
# Efficiency (20%)
'efficiency': min(20, 20 * (
BASELINE_TOKENS / invocation_log['tokens_used']
)),
# Output Quality (30%)
'quality': (
30 if invocation_log['user_accepted'] else
20 if invocation_log['user_edit_ratio'] < 0.2 else
10 if invocation_log['user_edit_ratio'] < 0.5 else
0
),
# User Satisfaction (25%)
'satisfaction': (
25 if invocation_log['explicit_rating'] == 'positive' else
15 if invocation_log['no_follow_up'] else
5 if invocation_log['follow_up_resolved'] else
0
),
}
return sum(scores.values())
スコアの解釈
| スコア範囲 | 品質レベル | 対応 |
|---|---|---|
| 90-100 | 優秀 | 模範例として記録する |
| 75-89 | 良好 | 一貫性を監視する |
| 50-74 | 許容範囲 | 改善点を確認する |
| 25-49 | 低品質 | 修正を優先する |
| 0-24 | 不合格 | 直ちに対応する |
ログの保存スキーマ
SQLite スキーマ(ローカル)
CREATE TABLE skill_invocations (
id TEXT PRIMARY KEY,
skill_name TEXT NOT NULL,
skill_version TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
-- Input
user_query TEXT,
context_tokens INTEGER,
-- Execution
duration_ms INTEGER,
tokens_input INTEGER,
tokens_output INTEGER,
tool_calls_json TEXT,
errors_json TEXT,
-- Output
output_type TEXT,
artifacts_json TEXT,
response_length INTEGER,
-- Quality signals
user_accepted BOOLEAN,
user_edit_ratio REAL,
follow_up_needed BOOLEAN,
explicit_rating TEXT,
-- Computed
quality_score REAL,
INDEX idx_skill_name (skill_name),
INDEX idx_timestamp (timestamp),
INDEX idx_quality (quality_score)
);
CREATE TABLE skill_aggregates (
skill_name TEXT,
period TEXT, -- 'daily', 'weekly', 'monthly'
period_start DATE,
invocation_count INTEGER,
avg_quality_score REAL,
error_rate REAL,
avg_tokens_used INTEGER,
avg_duration_ms INTEGER,
PRIMARY KEY (skill_name, period, period_start)
);
JSON ログ形式(ポータブル)
{
"logs_version": "1.0",
"skill_name": "wedding-immortalist",
"entries": [
{
"id": "uuid",
"timestamp": "2025-01-15T14:30:00Z",
"input": {...},
"execution": {...},
"output": {...},
"quality": {
"signals": {...},
"score": 85,
"computed_at": "2025-01-15T14:35:00Z"
}
}
]
}
分析クエリ
スキルパフォーマンスダッシュボード
-- Overall skill rankings
SELECT
skill_name,
COUNT(*) as uses,
AVG(quality_score) as avg_quality,
AVG(tokens_output) as avg_tokens,
SUM(CASE WHEN errors_json != '[]' THEN 1 ELSE 0 END) * 100.0 / COUNT(*) as error_rate
FROM skill_invocations
WHERE timestamp > datetime('now', '-30 days')
GROUP BY skill_name
ORDER BY avg_quality DESC;
-- Quality trend (weekly)
SELECT
skill_name,
strftime('%Y-%W', timestamp) as week,
AVG(quality_score) as avg_quality,
COUNT(*) as uses
FROM skill_invocations
GROUP BY skill_name, week
ORDER BY skill_name, week;
-- Problem detection
SELECT skill_name, COUNT(*) as failures
FROM skill_invocations
WHERE quality_score < 50
AND timestamp > datetime('now', '-7 days')
GROUP BY skill_name
HAVING failures >= 3
ORDER BY failures DESC;
改善の機会
def identify_improvement_opportunities(skill_name, logs):
"""Analyze logs to suggest skill improvements."""
opportunities = []
# Pattern 1: Common follow-up questions
follow_ups = extract_follow_up_patterns(logs)
if follow_ups:
opportunities.append({
'type': 'missing_capability',
'description': f'Users frequently ask: {follow_ups[0]}',
'suggestion': 'Add guidance for this common need'
})
# Pattern 2: High edit ratio in specific output types
edit_patterns = analyze_edit_patterns(logs)
if edit_patterns['code'] > 0.4:
opportunities.append({
'type': 'code_quality',
'description': 'Users frequently edit generated code',
'suggestion': 'Review code examples and templates'
})
# Pattern 3: Repeated errors
error_patterns = cluster_errors(logs)
for error_type, count in error_patterns:
if count >= 3:
opportunities.append({
'type': 'recurring_error',
'description': f'{error_type} occurred {count} times',
'suggestion': 'Add error handling or documentation'
})
return opportunities
実装ガイド
基本的なロガーフック
# hooks/skill_logger.py
import json
import sqlite3
from datetime import datetime
from pathlib import Path
LOG_DB = Path.home() / '.claude' / 'skill_logs.db'
def log_skill_invocation(
skill_name: str,
user_query: str,
output: str,
tool_calls: list,
duration_ms: int,
tokens: dict,
errors: list = None
):
"""Log a skill invocation to the database."""
conn = sqlite3.connect(LOG_DB)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO skill_invocations
(id, skill_name, timestamp, user_query, duration_ms,
tokens_input, tokens_output, tool_calls_json, errors_json,
response_length)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
str(uuid.uuid4()),
skill_name,
datetime.utcnow().isoformat(),
user_query,
duration_ms,
tokens.get('input', 0),
tokens.get('output', 0),
json.dumps(tool_calls),
json.dumps(errors or []),
len(output)
))
conn.commit()
conn.close()
品質シグナルの収集
def collect_quality_signals(invocation_id: str, signals: dict):
"""Update an invocation with quality signals."""
conn = sqlite3.connect(LOG_DB)
cursor = conn.cursor()
# Update with user feedback
cursor.execute('''
UPDATE skill_invocations
SET user_accepted = ?,
user_edit_ratio = ?,
follow_up_needed = ?,
explicit_rating = ?,
quality_score = ?
WHERE id = ?
''', (
signals.get('accepted'),
signals.get('edit_ratio'),
signals.get('follow_up'),
signals.get('rating'),
calculate_score(signals),
invocation_id
))
conn.commit()
conn.close()
アラートと通知
アラート条件
ALERT_CONDITIONS = {
'quality_drop': {
'condition': 'avg_quality_7d < avg_quality_30d * 0.8',
'message': 'Skill {skill} quality dropped 20%+ in past week',
'severity': 'warning'
},
'error_spike': {
'condition': 'error_rate_24h > error_rate_7d * 2',
'message': 'Skill {skill} error rate doubled in past 24h',
'severity': 'critical'
},
'underused': {
'condition': 'uses_7d < uses_30d_avg * 0.5',
'message': 'Skill {skill} usage down 50%+ this week',
'severity': 'info'
},
'high_performer': {
'condition': 'avg_quality_7d > 90 AND uses_7d > 10',
'message': 'Skill {skill} performing excellently',
'severity': 'positive'
}
}
アンチパターン
「すべてをログに記録する」
誤り:すべての呼び出しについて、入力と出力を完全にログに記録します。 理由:プライバシー上の懸念、ストレージの急増、ノイズにつながります。 適切な方法:メタデータと要約を記録し、詳細なログ記録はオプトイン方式にします。
「一度採点したら、そのままにする」
誤り:完了直後に品質スコアを計算します。 理由:遅れて現れるシグナル(コードが動作したか、取り消されたかなど)を見逃します。 適切な方法:一定期間シグナルを収集し、定期的に再計算します。
「平均値だけを見る」
誤り:品質スコアの平均値だけを追跡します。 理由:分布が見えず、障害のパターンを見逃します。 適切な方法:パーセンタイル、失敗率、パターンを追跡します。
「ベースラインがない」
誤り:ベースラインを設定せずに品質を測定します。 理由:改善や悪化を検出できません。 適切な方法:スキルごとにベースラインを設定し、推移を比較します。
出力レポート
スキルの週次ヘルスレポート
# Skill Health Report - Week of 2025-01-13
## Overview
- Total invocations: 247
- Average quality: 78.3 (up 2.1 from last week)
- Error rate: 4.2% (down 1.8%)
## Top Performers
1. **wedding-immortalist** - 92.1 avg quality, 18 uses
2. **skill-coach** - 89.4 avg quality, 34 uses
3. **api-architect** - 87.2 avg quality, 22 uses
## Needs Attention
1. **legacy-code-converter** - 52.3 avg quality (down 15%)
- Common issue: Missing dependency detection
- Suggested fix: Add dependency scanning step
## Improvement Opportunities
- `partner-text-coach`: Users frequently ask for tone adjustment
- `yard-landscaper`: High edit ratio on plant recommendations
連携ポイント
- skill-coach:品質データをスキルの改善に活用します
- agent-creator:新しいスキルの設計時に指標を活用します
- automatic-stateful-prompt-improver:プロンプト最適化に品質シグナルを活用します
中核となる考え方:測定すれば改善できます。スキルのログ記録によって、スキルの品質に関する直感を実行可能なデータに変え、スキルエコシステム全体の継続的な改善を可能にします。
コメント
Markdown 対応