football-betting-analysis について
サッカーの試合前および進行中の分析を行い、FlashScore のデータから根拠に基づく構造化レポートを作成するスキルです。試合情報を正規化し、断定や予想の保証ではなく確率的な表現を用います。
主な機能
- 01チームと日付から試合を検索
- 02FlashScore データから正規化した試合コンテキストを作成
- 03オッズ、調子、ラインアップ、大会情報を統合
- 04データソースごとに根拠を表示
- 05確率表現による構造化分析を生成
活用シーン
- 01特定の開催前サッカー試合の確認
- 02進行中の試合の分析
- 03オッズと調子、試合背景の比較
- 04分析前に利用できないデータを確認
MCP 対応
試合の検索とデータ取得に FlashScore MCP を使用し、前処理スクリプトを介して情報をまとめます。このスキル自体は MCP ツールを提供しません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ josearroyave/ agent-skills --skill football-betting-analysisインストール後、Claude Code で/football-betting-analysisを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mddata/all_tournaments.csvmain_leagues.csvmain_teams.csvscripts/build_match_context.pygenerate_teams_csv.py詳細
サッカー賭博分析
1. 概要
サッカーの試合前分析です。自然言語での問い合わせを受け取り、FlashScore MCP で
試合を検索し、前処理スクリプト
build_match_context.py を実行して正規化された JSON コンテキストを取得し、確率的な表現を用いた
構造化レポートを作成します。
notstarted および inprogress の試合のみ対象です。 finished の試合には、このスキルは適用されません。
モデルは、試合の検索を除き、エンドポイントを直接呼び出しません。
すでにクリーンアップ、正規化、統合されたデータを final_context で受け取ります。
分析は、利用可能なエビデンスの解釈です。ベットの推奨ではありません。 結果を保証するものでもありません。「可能性があります」「兆候」「示唆しています」のような表現を常に使います。 「勝ちます」「確実です」「オーバーは間違いなく成立します」といった表現は使いません。
2. 使用する場合/使用しない場合
使用する場合:
- ユーザーが特定のサッカーの試合について試合前分析を求めている場合。
- 試合の状態が
notstartedの場合。
使用しない場合:
- 試合がすでに
finishedの場合 → このスキルは適用されません。 - 特定の試合ではなく、トーナメントやチームについての問い合わせの場合 → 対応できません。そのチームの今後の試合を検索することを提案できます。
final_contextを生成できなかった場合。
アーキテクチャ上の注記: このバージョンでは、機械学習モデルに基づく予測を利用できません。 設計上、予測レイヤーはオッズ主導です。数値確率はオッズからのみ得られます。 指標は信頼度を調整するだけで、パーセンテージは算出しません。
3. データソース — FlashScore MCP
使用するエンドポイント
| エンドポイント | 用途 |
|---|---|
Get_Match_Details | イベント全体+オッズ |
Get_Match_H2H | 直接対戦 |
Get_Match_Stats | 履歴内の各試合(matches[i])に対して並列で呼び出し — 集計済みの form.advanced を構築する場合のみ使用 |
Get_Match_Lineups | 存在する場合はラインナップ+欠場者の名前と欠場理由を含む missingPlayers |
Get_Team_Results | 試合検索(フォールバック)+チームの試合結果履歴 |
Get_Team_Fixtures | 試合検索(優先)— チームの今後の試合 |
Get_Tournament_Standings | トーナメント内の調子/順位のコンテキスト |
Get_Match_Standings_OverUnder | オーバー/アンダー順位表 |
Get_Tournament_Top_Scorers | トーナメントの得点王 |
Get_Match_Standings_Form | 試合内での最近の調子 |
FlashScore に存在しないもの(決して捏造してはいけません)
| 存在しないもの | 影響 |
|---|---|
| 試合前に確認済みのラインアップ | エンドポイント Get_Match_Lineups は存在しますが、確認済みのラインアップがまだ利用できない場合があります。空の場合もあります。ラインアップを捏造してはいけません。利用可能であれば predictedLineups を使用してください — スクリプトが自動的に処理します。 |
| 既往の負傷履歴 | API には存在しません。捏造してはいけません。 |
Get_Match_Lineups にデータがない場合の missingPlayers | エンドポイントに含まれていない場合 → 理由や選手を捏造してはいけません。 |
build_match_context.py における normalize_lineups の動作:
スクリプトは、優先度の異なる 2 つの段階でラインアップを処理します。
-
startingLineupsが存在する場合(公式に確認済みのラインアップ):starting_lineups— 確認済みの先発ラインアップ [API]missing_players— 欠場選手とその理由 [API]substitutes— 出場可能な交代選手 [API]predicted_lineups→ 空unsure_missing— 空
-
startingLineupsは存在しないが、predictedLineupsが存在する場合(予測/未確認のラインアップ):unsure_missing— 欠場が確認されていない選手 [API]missing_players→ 欠場選手とその理由 [API]predicted_lineups— 予測ラインアップ [API]starting_lineups→ 空substitutes→ 空
注: ラインアップが確認済みでなくても、Get_Match_Lineups に missingPlayers(名前+理由)が含まれる場合があります。利用可能であれば、そのデータを使用してください。
分析における各シグナルのソース:
| タグ | 意味 |
|---|---|
[API] | FlashScore MCP のエンドポイントから直接取得したデータ |
[ODDS] | 市場オッズから算出 |
[IND] | API データをもとに算出した指標 |
[N/A] | API で利用できないデータ |
4. 分析パイプライン
4.1 クエリの解析
自然言語のクエリから抽出します:
{
home_team: string, // equipo mencionado primero
away_team: string, // equipo mencionado segundo (o null si solo uno)
date_from: ISO 8601, // fecha inicio del rango
date_to: ISO 8601, // fecha fin del rango
league: string|null, // competición mencionada (o null)
analysis_mode: "prematch" // único modo soportado
}
解析ルール:
| 状況 | ルール |
|---|---|
| ユーザーが「今日」と言った場合 | date_from = hoy、date_to = hoy |
| ユーザーが「明日」と言った場合 | date_from = mañana、date_to = mañana |
| ユーザーが「今週末」と言った場合 | date_from = viernes、date_to = domingo |
| ユーザーが曜日を指定せずに「今週」と言った場合 | date_from = lunes、date_to = domingo |
| チームが1つだけ挙げられた場合 | 7日間の範囲で、そのチームの次の試合を検索します |
| アクセント付きの名前(「Atletico」、「Inter」) | 検索前にアクセントを除去して正規化します |
| 部分的な名前(「Barça」、「Atleti」) | 結果の home_team/away_team とファジーマッチングします |
| 大会名が挙げられた場合(「la league」、「champions」) | 検索後に league_id で絞り込みます |
| status = "notstarted" | analysis_mode = "prematch" → 続行 |
| status = "inprogress" | → ライブ分析を続行します。 |
| status = "finished" | → 該当しません。ユーザーに通知します。 |
チームは1つだけ一致し、相手チームの候補が複数ある場合: → 必ず確認します。「[チーム] 対 [候補 A] と [候補 B] のどちらをお探しですか?」
4.2 試合の検索(フェーズ 1 — MCP を直接使用するのはこのフェーズのみ)
ステップ 1 — チーム検索 API で検索:
1. Normalizar nombres de ambos equipos (minúsculas, sin acentos, sin puntos)
2. Usar la API de búsqueda:
GET https://s.livesport.services/api/v2/search/?q=<query>&lang-id=13&type-ids=1,2,3,4&project-id=202&project-type-id=1
3. Filtrar resultados: sport.id=1 (fútbol), type.id=2 (Team)
4. Retorna: team_id, name, url, country, country_id
→ Si 1 resultado: proceed con ese team_id
→ Si >1 resultado: clarificación obligatoria ("¿Buscás [equipo A] o [equipo B]?")
→ Si 0 resultados: ir a paso 5 (fallback a /data/main_teams.csv)
検索 API 用の正規化:
- 小文字にする
- アクセントを除去する:á→a、é→e、í→i、ó→o、ú→u
- ピリオドを除去する:「Atl.」→「Atl」
- 余分なスペースを除去する
ステップ 2 — /data/main_teams.csv でチームを検索(フォールバック):
5. Si no se encontró el equipo en la API, buscar en /data/main_teams.csv:
Normalizar nombres (mismas reglas que arriba)
6. Buscar match exacto en /data/main_teams.csv después de normalizar
→ Si 1 resultado: proceed
→ Si >1 resultado: clarificación obligatoria
7. Si 0 resultados exactos: intentar substring match
→ Si 1 resultado: proceed
→ Si >1 resultado: clarificación obligatoria
8. Si 0 resultados: buscar coincidencias cercanas (similitud string)
→ Calcular similaridad entre nombre buscado y todos los nombres en /data/main_teams.csv
→ Si hay candidatos con similitud ≥ umbral (ej: Levenshtein ratio ≥ 0.6):
→ Si 1 candidato cercano: "¿Quisiste decir [nombre]?"
→ Si >1 candidatos: mostrar top 3: "¿Buscás alguno de estos? [A], [B], [C]"
→ Si ningún candidato cercano: "No encontré '[equipo]'. Verificá el nombre."
類似する候補の提示:
- 類似度のしきい値:ratio ≥ 0.6(Levenshtein など)
- 類似度の高い順に最大 3 件の候補を表示する
- 候補には CSV の元の名前(正規化前)を含める
ステップ 3 — fixtures の重複範囲を検索:
9. Get_Team_Fixtures(team_id_home, page=1)
10. Get_Team_Fixtures(team_id_away, page=1)
11. Filtrar fixtures del rango date_from..date_to
12. Buscar partido donde home_team_id o away_team_id de un fixture
coincida con el team_id del otro equipo (overlap)
→ Si 1 resultado: proceed
→ Si >1 resultado: priorizar por fecha más cercana al rango solicitado
→ Si 0: ir a paso 4
ステップ 4 — results にフォールバック:
13. Get_Team_Results(team_id_home, page=1)
14. Get_Team_Results(team_id_away, page=1)
15. Buscar overlap (misma lógica que fixtures)
→ Si 1 resultado: proceed
→ Si >1: priorizar por fecha más cercana
→ Si 0: "No encontré el partido [Home] vs [Away] en las fechas indicadas."
ステップ 5 — 確認と抽出:
16. Verificar estado del evento:
→ status = "notstarted" → proceed con análisis pre-partido
→ status = "inprogress" → proceed con análisis en vivo
→ status = "finished" → "El partido ya finalizó. Esta skill es solo pre-partido y en vivo."
17. Extraer IDs:
→ event_id = del evento encontrado
→ home_team_id = del equipo local
→ away_team_id = del equipo visitante
候補が複数ある場合の優先順位:
- ユーザーがリーグを指定した場合は、そのリーグを優先します。
- ユーザーが正確な日付を指定した場合は、その日付のみを対象とします。
- 該当するチームの組み合わせの試合がちょうど 1 件の場合は、その試合を使用します。
- 同じチームの試合が複数ある場合は、クエリの日付範囲に最も近い試合を優先します。 これにより、不要な確認を避けられます。
- それ以外の場合は、必ず確認します。
4.3 前処理(フェーズ 2 — build_match_context.py)
分析用データを取得する唯一の方法です。試合データの取得に MCP エンドポイントを直接使用しないでください。
python scripts/build_match_context.py <event_id> <home_team_id> <away_team_id>
スクリプトの処理内容:
- FlashScore のエンドポイントへの呼び出しをすべて内部で実行します
- 両チームの結果履歴から H2H を構築します
- 直近の状況を集計します(GF、GC、over、BTTS、ホーム/アウェイ別) —
form.basic Get_Match_Lineupsから欠場情報を抽出し、正規化します- 実際に存在する odds マーケットを検証し、存在しないものをブロックします
- 履歴内の各試合の高度な統計(シュート、ポゼッション、xG など)を統合します —
form.advancedの構築にのみ使用します(個々のデータは最終 JSON に出力されません) - チームごとの過去の選手統計を集計します(
player_stats.as_historical_home/away) - トーナメントのコンテキスト(順位、直近の状況、over/under の順位表)を取り込みます
- 整合性に関する警告を出力します
- すべての情報を 1 つの JSON(
final_context)にまとめます
スクリプトの出力 — final_context:
{
"meta": {
event_id, home_team_id, away_team_id, generated_at
},
"match": {
event_id,
home_team: { id, name, event_participant_id },
away_team: { id, name, event_participant_id },
tournament: { id, stage_id, name },
country, referee, timestamp, datetime, status,
scores: {
home, away,
home_total, away_total,
home_1st_half, away_1st_half,
home_2nd_half, away_2nd_half,
home_extra_time, away_extra_time,
home_penalties, away_penalties
},
"lineups": {
home: {
formation, // formación reportada (de predictedFormation)
lineup_count, // cantidad de jugadores en alineación
// -- Si hay alineaciones oficiales (startingLineups existe): --
starting_lineups: [...], // alineación titular oficial [API]
missing_players: [...], // jugadores ausentes con motivo [API]
substitutes: [...], // sustitutos disponibles [API]
predicted_lineups: [], // vacío
unsure_missing: [], // vacío
// -- Si NO hay oficiales pero hay predicción (predictedLineups): --
starting_lineups: [], // vacío
missing_players: [], // vacío
substitutes: [], // vacío
predicted_lineups: [...], // alineación predicha [API]
unsure_missing: [...], // ausencias no confirmadas [API]
},
away: { formation, lineup_count, starting_lineups, missing_players, substitutes, predicted_lineups, unsure_missing },
warnings: string[] | null
},
"preview": string | null, // texto de previa del partido — web scraping de FlashScore (DOM o contentParsed embebido)
// --- inprogress or finished only ---
"summary": object | null, // eventos clave del partido (goles, tarjetas, etc.) [API]
"commentary": object | null, // narración minuto a minuto [API]
"match_stats": object | null, // estadísticas del partido (posesión, tiros, xG, etc.) [API]
"player_stats": object | null, // stats de jugadores del partido actual [API]
"live_analysis": { // solo para status = "inprogress"
total_goals_over_25: { probability, signal, confidence },
total_goals_under_25: { ... },
btts_yes: { ... },
btts_no: { ... },
next_goal_home: { ... },
next_goal_away: { ... },
next_goal_no_more: { ... }, // explicit class — no more goals in the match
next_corner: { lean, signal, confidence, mode: "signal_only" },
total_cards: { lean, signal, confidence, mode: "signal_only" },
1x2_final: { probabilities: { home, draw, away }, model_version, calibrated, inputs_quality, top_factors, prematch_source, confidence, warnings },
match_minute: int,
current_score: { home: int, away: int },
warnings: []
} | null,
warnings: string[] | null
},
"odds": {
available_markets: string[],
odds_home, odds_draw, odds_away,
odds_over_25, odds_under_25,
odds_btts_yes, odds_btts_no,
warnings: string[]
},
"implied_probs": {
prob_home, prob_draw, prob_away,
prob_over_25, prob_btts_yes
},
"h2h": {
total_matches,
home_team_wins, // partidos ganados por el equipo local del análisis
away_team_wins, // partidos ganados por el equipo visitante del análisis
draws,
home_team_goals_for, // goles anotados por el equipo local del análisis en H2H
away_team_goals_for, // goles anotados por el equipo visitante del análisis en H2H
total_goals, both_teams_scored,
matches: [{
match_id, timestamp,
home_score, away_score,
home_team, away_team,
tournament_id, tournament_name,
team_is_home, opponent
}],
basic_stats: { // stats básicos del historial H2H
// home_team = stats of the team that IS home in the CURRENT match (Bayern)
// away_team = stats of the team that IS away in the CURRENT match (Real Madrid)
// form_string/points/home_ppg/away_ppg excluded — not meaningful in h2h context
home_team: {
wins, losses, draws,
gf_avg, gc_avg, total_goals
},
away_team: {
wins, losses, draws,
gf_avg, gc_avg, total_goals
},
both_teams_scored,
over_25_freq, btts_freq,
total_matches,
total_goals
},
advanced_stats: { // stats agregadas del historial (de advanced_stats de cada match)
// For home_team_results / away_team_results: same flat structure
// For h2h: split by current-match home/away identity
// Each sub-dict has: { overall: {...}, first_half: {...}, second_half: {...} }
home_team: {
overall: { attack: {...}, defense: {...}, control: {...}, set_pieces_and_territory: {...}, discipline: {...}, duels_and_defending: {...}, efficiency: {...}, derived: {...} },
first_half: { /* mismo formato que overall */ },
second_half: { /* mismo formato que overall */ }
},
away_team: {
overall: { attack: {...}, defense: {...}, control: {...}, set_pieces_and_territory: {...}, discipline: {...}, duels_and_defending: {...}, efficiency: {...}, derived: {...} },
first_half: { /* mismo formato que overall */ },
second_half: { /* mismo formato que overall */ }
}
},
home_team_player_stats: {
general: { minutes_total, goals_total, assists_total, shots_total, shots_on_target_total, key_passes_total, tackles_won_total, interceptions_total, ball_recoveries_total, yellow_cards_total, red_cards_total, goals_per_90, assists_per_90, shots_per_90, position_distribution, in_base_lineup_count, substitute_count },
individual: {
[player_name]: {
"position": "Goalkeeper" | "Defender" | "Midfielder" | "Forward" | "Unknown",
offense: { GOALS, EXPECTED_GOALS, ASSISTS_GOAL, EXPECTED_ASSISTS, SHOTS_TOTAL, SHOTS_ON_TARGET, BIG_CHANCES_CREATED, BIG_CHANCES_MISSED },
creation: { KEY_PASSES, FINAL_THIRD_ENTRIES_TOTAL, BOX_ENTRIES, THROUGH_BALLS },
possession: { TOUCHES_TOTAL, MATCH_MINUTES_PLAYED, PASSES_TOTAL },
defense: { DUELS_WON, DUELS_TOTAL, DUELS_EFFICIENCY, TACKLES_WON, INTERCEPTIONS, BALL_RECOVERIES },
efficiency: { PASSES_ACCURACY, LONG_BALLS_ACCURACY, CROSSES_ACCURACY, DRIBBLES_EFFICIENCY },
discipline: { FOULS_COMMITTED, FOULS_SUFFERED, CARDS_YELLOW, CARDS_RED, TURNOVERS, ERRORS_LEAD_TO_SHOT, ERRORS_LEAD_TO_GOAL },
goalkeeping:{ SAVES_TOTAL, GOALS_CONCEDED, GOALS_PREVENTED, EXPECTED_GOALS_ON_TARGET_FACED, BIG_CHANCES_SAVED },
derived: { xg_per_shot, goals_minus_xg, xa_minus_assists, duels_win_pct, actions_per_90 }
}, ...
}
},
away_team_player_stats: { /* misma estructura */ },
warnings: string[]
},
"home_team_results": {
matches: [{
match_id, timestamp,
goals_for, goals_against, total_goals, both_teams_scored,
tournament_id, tournament_name,
team_is_home, opponent
}],
basic_stats: { // stats básicos del historial
all_matches, form_string, points,
home_gf_avg, home_gc_avg,
over_25_freq, btts_freq,
home_ppg, home_gf_avg, home_gc_avg,
away_ppg, away_team_gf_avg, away_team_gc_avg,
total_matches, wins, draws, losses,
goals_for, goals_against, total_goals, both_teams_scored
},
advanced_stats: { // stats agregadas del historial (de advanced_stats de cada match)
overall: {
attack: {
goals_for_avg, xg_for_avg, xgot_for_avg, xa_for_avg,
shots_for_avg, shots_on_target_for_avg, shots_off_target_for_avg,
blocked_shots_for_avg, shots_inside_box_for_avg, shots_outside_box_for_avg,
big_chances_for_avg, touches_in_opposition_box_avg, hit_woodwork_avg
},
defense: {
goals_against_avg, xg_against_avg, xgot_faced_avg,
shots_against_avg, shots_on_target_against_avg, shots_off_target_against_avg,
blocked_shots_against_avg, shots_inside_box_against_avg, shots_outside_box_against_avg,
big_chances_against_avg, touches_in_opposition_box_against_avg,
goalkeeper_saves_avg, errors_leading_to_shot_avg, errors_leading_to_goal_avg, goals_prevented_avg
},
control: {
possession_avg, passes_accuracy_avg, passes_completed_avg, passes_attempted_avg,
long_pass_accuracy_avg, long_passes_completed_avg, long_passes_attempted_avg,
final_third_pass_accuracy_avg, final_third_passes_completed_avg, final_third_passes_attempted_avg,
accurate_through_passes_avg
},
set_pieces_and_territory: {
corners_for_avg, corners_against_avg, offsides_for_avg, offsides_against_avg,
free_kicks_for_avg, free_kicks_against_avg, throw_ins_for_avg, throw_ins_against_avg,
cross_accuracy_avg, crosses_completed_avg, crosses_attempted_avg
},
discipline: {
yellow_cards_avg, red_cards_avg, cards_total_avg, fouls_committed_avg
},
duels_and_defending: {
tackles_success_pct_avg, tackles_won_avg, tackles_attempted_avg,
duels_won_avg, clearances_avg, interceptions_avg
},
efficiency: {
shot_accuracy_pct, goal_conversion_pct, big_chance_conversion_pct,
xg_per_shot, shots_on_target_faced_per_goal_against, save_pct,
finishing_overperformance, conceding_overperformance
},
derived: {
xg_balance_avg, xg_ratio, shots_share, shots_on_target_share,
big_chances_balance_avg, corners_balance_avg, discipline_balance_avg
}
},
first_half: { /* mismo formato que overall */ },
second_half: { /* mismo formato que overall */ },
warnings: []
},
player_stats_as_home: {
general: { minutes_total, goals_total, assists_total, shots_total, shots_on_target_total, key_passes_total, tackles_won_total, interceptions_total, ball_recoveries_total, yellow_cards_total, red_cards_total, goals_per_90, assists_per_90, shots_per_90, position_distribution, in_base_lineup_count, substitute_count },
individual: {
[player_name]: {
"position": "Goalkeeper" | "Defender" | "Midfielder" | "Forward" | "Unknown",
offense: { GOALS, EXPECTED_GOALS, ASSISTS_GOAL, EXPECTED_ASSISTS, SHOTS_TOTAL, SHOTS_ON_TARGET, BIG_CHANCES_CREATED, BIG_CHANCES_MISSED },
creation: { KEY_PASSES, FINAL_THIRD_ENTRIES_TOTAL, BOX_ENTRIES, THROUGH_BALLS },
possession: { TOUCHES_TOTAL, MATCH_MINUTES_PLAYED, PASSES_TOTAL },
defense: { DUELS_WON, DUELS_TOTAL, DUELS_EFFICIENCY, TACKLES_WON, INTERCEPTIONS, BALL_RECOVERIES },
efficiency: { PASSES_ACCURACY, LONG_BALLS_ACCURACY, CROSSES_ACCURACY, DRIBBLES_EFFICIENCY },
discipline: { FOULS_COMMITTED, FOULS_SUFFERED, CARDS_YELLOW, CARDS_RED, TURNOVERS, ERRORS_LEAD_TO_SHOT, ERRORS_LEAD_TO_GOAL },
goalkeeping:{ SAVES_TOTAL, GOALS_CONCEDED, GOALS_PREVENTED, EXPECTED_GOALS_ON_TARGET_FACED, BIG_CHANCES_SAVED },
derived: { xg_per_shot, goals_minus_xg, xa_minus_assists, duels_win_pct, actions_per_90 }
}, ...
}
},
player_stats_as_away: { /* misma estructura */ },
warnings: string[] | null
},
"away_team_results": {
matches: [{
match_id, timestamp,
goals_for, goals_against, total_goals, both_teams_scored,
tournament_id, tournament_name,
team_is_home, opponent
}],
basic_stats: { // stats básicos del historial
all_matches, form_string, points,
home_gf_avg, home_gc_avg,
over_25_freq, btts_freq,
home_ppg, home_gf_avg, home_gc_avg,
away_ppg, away_team_gf_avg, away_team_gc_avg,
total_matches, wins, draws, losses,
goals_for, goals_against, total_goals, both_teams_scored
},
advanced_stats: { // stats agregadas del historial (de advanced_stats de cada match)
overall: { /* mismo formato que en home_team_results */ },
first_half: { /* mismo formato */ },
second_half: { /* mismo formato */ },
warnings: []
},
player_stats_as_home: {
general: { minutes_total, goals_total, assists_total, shots_total, shots_on_target_total, key_passes_total, tackles_won_total, interceptions_total, ball_recoveries_total, yellow_cards_total, red_cards_total, goals_per_90, assists_per_90, shots_per_90, position_distribution, in_base_lineup_count, substitute_count },
individual: {
[player_name]: {
"position": "Goalkeeper" | "Defender" | "Midfielder" | "Forward" | "Unknown",
offense: { GOALS, EXPECTED_GOALS, ASSISTS_GOAL, EXPECTED_ASSISTS, SHOTS_TOTAL, SHOTS_ON_TARGET, BIG_CHANCES_CREATED, BIG_CHANCES_MISSED },
creation: { KEY_PASSES, FINAL_THIRD_ENTRIES_TOTAL, BOX_ENTRIES, THROUGH_BALLS },
possession: { TOUCHES_TOTAL, MATCH_MINUTES_PLAYED, PASSES_TOTAL },
defense: { DUELS_WON, DUELS_TOTAL, DUELS_EFFICIENCY, TACKLES_WON, INTERCEPTIONS, BALL_RECOVERIES },
efficiency: { PASSES_ACCURACY, LONG_BALLS_ACCURACY, CROSSES_ACCURACY, DRIBBLES_EFFICIENCY },
discipline: { FOULS_COMMITTED, FOULS_SUFFERED, CARDS_YELLOW, CARDS_RED, TURNOVERS, ERRORS_LEAD_TO_SHOT, ERRORS_LEAD_TO_GOAL },
goalkeeping:{ SAVES_TOTAL, GOALS_CONCEDED, GOALS_PREVENTED, EXPECTED_GOALS_ON_TARGET_FACED, BIG_CHANCES_SAVED },
derived: { xg_per_shot, goals_minus_xg, xa_minus_assists, duels_win_pct, actions_per_90 }
}, ...
}
},
player_stats_as_away: { /* misma estructura */ },
warnings: string[] | null
},
"standings": {
teams: { [team_id]: { position, name, points, wins, draws, losses, goals, goal_difference } },
warnings: string[] | null
},
"overunder_standings": {
teams: { [team_id]: { over, under, average_goals } },
warnings: string[] | null
},
"form_standings": {
teams: { [team_id]: { points, form_string } },
warnings: string[] | null
},
"top_scorers": {
home_scorers: [{ name, player_id, team, goals, assists }],
away_scorers: [...],
warnings: string[] | null
},
"tournament_top_scorers": {
home_scorers: [...],
away_scorers: [...],
warnings: string[] | null
}
}
スクリプトの使用ルール:
final_contextを受け取った後、モデルは MCP エンドポイントを再度呼び出しません。- 分析に使用するすべてのデータは JSON から取得します。
- スクリプトが警告を出力した場合 → モデルはその内容を考慮し、矛盾する内容を述べてはなりません。
- JSON 内で
[N/A]と示されている場合 → モデルはそのまま[N/A]として使用し、データを推測しません。 - スクリプトは決定論的です。同じ入力に対して、常に同じ出力を生成します。
- モデルは、正規化済みのデータについて、その意味を説明する場合を除き、再計算や再解釈を行いません。
スクリプトが失敗した場合、または実行できない場合: → 「試合のコンテキストを生成できませんでした。分析を実行できません。」
5. 8 つのレイヤー — 正確な定義
各レイヤーには、入力、計算、必須の出力、縮退時の処理があります。
レイヤー 1 — 基本コンテキスト
入力: odds_home、odds_draw、odds_away、odds_over_25、
odds_btts_yes。
計算:
- 市場の暗黙の確率:
1 / odds - Over 2.5 の暗黙の確率:
1 / odds_over_25 - BTTS の暗黙の確率:
1 / odds_btts_yes - バイアス:明確な本命(>60%)、やや有利な本命(50-60%)、拮抗(<50%)
必須の出力:
## 1. Contexto del Partido
- Partido: [Home] vs [Away]
- Competición: [Liga]
- Fecha/hora: [ISO 8601]
- Estado: [notstarted/inprogress]
---
Mercado dice [ODDS]:
- [Home]: [prob]% | Draw: [prob]% | [Away]: [prob]%
- Over 2.5: [cuota] → prob implícita [prob]%
- BTTS: [cuota] → prob implícita [prob]%
---
Indicadores históricos [IND]:
- Indicadores favorecen: [Home/Away/Equilibrado]
- Soporte histórico: [bajo/medio/alto]
Mercado vs datos: [alineados/parcialmente alineados/en conflicto] — [explicación breve]
縮退時の処理:
- odds がない場合 → 市場と指標の差は使用しません。利用可能な場合に限り、odds のみを使用します。
- どちらもない場合 → レイヤー 1 は大幅に縮退します。
postmatch 用の出力:
Mercado esperaba [ODDS]:
- [Home]: [prob]% | Draw: [prob]% | [Away]: [prob]%
- Over 2.5: [cuota] → prob implícita [prob]%
- BTTS: [cuota] → prob implícita [prob]%
Resultado vs expectativa [ODDS]/[IND]:
- El resultado [fue alineado / parcialmente alineado / sorpresivo] con las probabilidades del mercado
レイヤー 2 — チームの記述
入力: Get_Team_Results(履歴)、Get_Match_H2H、Get_Tournament_Standings(該当する場合)、final["preview"](ウェブスクレイピング — FlashScore の試合プレビュー文)。
計算:
- 直近 N 試合のポイント:チームの結果から取得
- 直近の状況:最近の結果(W/D/L)
- 平均得点:
goals_scored / matches_playedおよびgoals_conceded / matches_played - Over 2.5 の頻度:直近 N 試合のうち、合計得点が 2.5 を超えた試合を数えます
- BTTS の頻度:直近 N 試合のうち、両チームが得点した試合を数えます
- プロフィール:生成したゴールと実際のゴールに基づきます(期待値を上回る/下回る)
- H2H:
Get_Match_H2Hが存在する場合に使用します
必須の出力:
## 2. [Qué Viene Pasando / Lo Que Está Pasando]
[Adaptar según estado del partido:]
- status = notstarted → "Qué Viene Pasando"
- status = inprogress → "Lo Que Está Pasando" + marcador actual + minuto
- status = finished → "Lo Que Pasó"
[Home] [IND] [marcador si inprogress]:
Forma: [form_string] — [pts] pts / [N] pts posibles
Goles: [home_gf_avg]/[home_gc_avg]
Over 2.5: [X/N] | BTTS: [X/N] (si hay datos)
En casa: [home_ppg] ppg | [home_goals]GF / [home_goals]GC
Perfil: [ofensivo/conservador/equilibrado/inestable]
[ away ] [IND]:
[mismo formato]
H2H [IND]: [X]PJ — [home_team_wins]V-local [draws]E [away_team_wins]V-visitante | goles local [home_team_goals_for] / visitante [away_team_goals_for]
[score reciente 1]
[score reciente 2]
Nota: [si la forma se extrajo solo del evento actual (N=1), indicarlo]
[Para notstarted]: Previa del partido [IND]: [texto de previa de FlashScore — si no disponible: "Previa no disponible [N/A]"]
[Para inprogress]: Eventos recientes: [resumen de últimos eventos del partido — de summary.events]
[Para finished]: Resultado final: [home] [H] - [A] [away] | [marcador final]
[Para postmatch — analysis_mode = "postmatch"]:
El resultado [confirma/rompe] la tendencia reciente de cada equipo
Resultado vs forma: [el partido fue consistente/inconsistente con la forma previa]
**Nota:** La previa del partido debe ser concisa. Si excede 3-4 oraciones, resumir los puntos más relevantes para el análisis.
縮退時の処理:
home_formが空の場合 → 利用可能な H2H のみを列挙します。直近の状況は N/A とします。- H2H がない場合 → H2H セクションを省略します。
- サンプル数が N < 5 の場合は、必ず注記を含めます。
previewが利用できない場合 → テキスト「プレビューを利用できません [N/A]」を使用します。- status = inprogress の場合 → 現在のスコアと分数を含む「現在の状況」を使用します。
- status = finished の場合 → 最終結果を含む「試合の結果」を使用します。
analysis_mode = "postmatch"の場合:結果と試合前の直近の状況、および試合前の odds を比較します。
レイヤー 3 — 主な選手
全体ルール(新規): レイヤー 3 は事実と最小限のコンテキストのみを扱います。解釈、重み付け、結論、因果関係を示す表現は含めません。
Capa 3 NO puede contener:
- conclusiones
- inferencias
- lenguaje causal ("porque", "esto implica", "esto sugiere")
Solo descripción estructurada de datos.
唯一の問い: 何があるか?(「それは何を意味するか?」ではありません)
2 つの経路を使うロジック(常に両方を試みる):
- レーン A:
Get_Match_Player_Stats→ 個人成績(ゴール、アシスト、シュートなど) - レーン B:
Get_Match_Lineups→missingPlayers(名前+欠場理由)
レーン A が失敗しても、レーン B が missingPlayers を返す場合は、レーン B を使用します。
両方とも失敗した場合は、[N/A] を付けて縮退レイヤーに切り替えます。
レーン A — Get_Match_Player_Stats からの直接入力:
goals、assists、shots、shots_on_target、key_passes、
tackles_won、interceptions、ball_recoveries、yellow_cards、
red_cards、minutes。
ルール — ヒューリスティックな数式は使用しない:
- 重み(0.3、0.5 など)や、独自に考案した正規化は使用しないでください。
- 「インパクトスコア」、「攻撃面の影響」など、複合指標を計算しないでください。
- 許可されるもの: 個別の指標による直接的なランキング(ゴール数、キーパス数など)。
- 依存度: 選手のゴール/生産量とチーム全体の直接的な比率。
ルール(新規): レイヤー 3 の出力は純粋に事実を記述するものとします。「チームに影響します」、「重要な戦力を欠きます」、「攻撃力が低下します」などの表現は含めないでください。解釈はすべてレイヤー 5 で行います。
選手ごとの出力(直接データ、数式なし):
[Jugador X] ([pos]):
Producción:
- Goles: X
- Asistencias: X
Volumen ofensivo:
- Tiros: X (X a puerta)
Creación:
- Pases clave: X
Disciplina:
- Amarillas: X | Rojas: X
チームごとの上位 N 人(指標による直接的なランキング — 複合スコアなし):
Top generadores de gol [IND]:
1. [Jugador A] — [X] goles
2. [Jugador B] — [X] goles
Top creadores [IND]:
1. [Jugador A] — [X] pases clave
2. [Jugador B] — [X] pases clave
攻撃面の依存度:
- 計算式:
(選手のゴール数 / チームの総ゴール数) * 100 - しきい値:40% 超 → 「攻撃面の依存度が高い [IND]」
- 1 人の選手がチームの生産量の 50% 超を占める場合は、アラートを出します。
レーン B — Get_Match_Lineups からの情報源:
スクリプト build_match_context.py は、優先度が 2 段階に定義されたラインナップを処理します(normalize_lineups で定義)。
-
レベル 1 — 公式ラインナップ(
startingLineupsが存在する場合):missing_players:name、player_id、reason、countryを含む欠場選手のリスト [API]substitutes:出場可能な交代選手 [API]starting_lineups:公式の先発ラインナップ [API]predicted_lineups:空unsure_missing:空
-
レベル 2 — 予想ラインナップ(
startingLineupsが存在せず、predictedLineupsが存在する場合):unsure_missing:欠場が確定していない選手 [API]predicted_lineups:予想ラインナップ [API]missing_players:空substitutes:空starting_lineups:空
missing_players に欠場選手が含まれている場合は、以下で定義する欠場レベルに従って報告します。
欠場レベル(詳細度の高い順):
-
確認された欠場 [API]: API が返す名前と理由(Injury、Inactive、Leg Injury など)。API に示された情報のみを報告します。
-
文脈情報を付加した欠場 [IND]: その選手が
Get_Tournament_Top_Scorersに登場する、または過去の試合のGet_Team_ResultsやGet_Match_Player_Statsで重要な得点者/チャンスメーカーとして記録されている場合 → 「[選手名] は欠場 — トップスコアラー/大会の上位選手として記録 [IND]」と示します。事実としてのみ報告し、影響を解釈しないでください。 -
影響度不明 [N/A/IND]: 選手が欠場しているものの、その影響度を推定するのに十分な根拠がない場合 → 「影響度を正確に定量化できません [N/A]」と示します。影響を決して推測しないでください。
レーン B のみを使用する場合のルール:
- 追加の文脈がない欠場(重要な得点者としての記録がなく、裏付けとなるランキングもない場合)→ 観察された事実としてのみ報告します [API]。
- 欠場選手ごとにチームの戦力がどの程度低下するかを計算しないでください。
- 失われるゴール数や、ゴールの確率への影響を推定しないでください。
- 同じチームに欠場選手が重なっていることは、文脈上の観察事項として述べてもかまいません(チームのパフォーマンス上限に関する確実性が下がります)。ただし、根拠のない数値は示さないでください。
必須の出力:
## 3. Protagonistas
[Carril A — Si hay player-stats:]
[Jugador] ([pos]):
Producción:
- Goles: X
- Asistencias: X
Volumen ofensivo:
- Tiros: X (X a puerta)
Creación:
- Pases clave: X
Disciplina:
- Amarillas: X | Rojas: X
[Top del partido]
Dependencia ofensiva:
- [Equipo]: [jugador] → [X]% de los goles del equipo [IND]
[Carril B — Si hay missingPlayers sin player-stats:]
Ausencias observadas [API]:
- [Equipo]: [Jugador] — [motivo de la API]
- [Equipo]: [Jugador] — [motivo de la API]
[Si hay ausencia contextualizada:]
- [Equipo]: [Jugador] — ausente [IND] — [goleador/top scorer del torneo / pieza habitual]
Lectura contextual [IND]:
- [Equipo] llega con [X] bajas registradas en la API.
- La influencia de las ausencias se considera [alta/moderada/baja] solo si coincide con
otras señales disponibles (producción en排行榜, dependencia ofensiva, ranking histórico, etc.).
- Influencia no cuantificable con precisión [N/A]: [jugador(es)].
[Si commentary disponible Y coincide con indicadores:]
Patrón de estilo observado: [descripción]
[Si commentary disponible pero NO coincide con indicadores:]
Patrón de estilo: [N/A] — dato observacional no respaldado por stats.
縮退:
- player-stats と missingPlayers のどちらもない場合 → 「主役のデータなし [N/A] — 劣化レイヤー。」選手や欠場者を捏造しないでください。
- missingPlayers だけがある場合(レーン B)→ レーン A は N/A、レーン B は上記で定義した欠場レベルに従います。
- 両方ある場合 → レーン A を使用し、レーン B を補足情報として追加します。
analysis_mode = "postmatch"の場合:player_statsを主な情報源、summary.eventsを二次情報源、commentaryを三次的な補助情報として使用します。commentaryは展開の描写にのみ使用し、構造的な優位性を捏造してはいけません。player_statsはないもののsummary.eventsがある場合 → 展開の描写はイベントに基づきます。
レイヤー 4 — 複合指標
ルール(新規): レイヤー 4 では指標名を示せますが、なぜ重要なのかは説明しません。
| レイヤー | 役割 |
|---|---|
| 4 | 測定する |
| 5 | 説明する |
唯一の問い: どれくらいか?(「なぜ重要なのか?」ではありません)
Capa 4 NO puede contener:
- conclusiones
- inferencias
- lenguaje causal ("porque", "esto implica", "esto sugiere")
- "esto favorece a X"
- "esto indica partido abierto"
Solo descripción estructurada de datos comparables entre equipos.
入力: チームの履歴(home_team_results、away_team_results、h2h)、オッズ。
計算:
- 攻撃力の優位性:両チームの平均ゴール数の差
- 守備の脆弱性:アウェイチームの失点数/試合数
- 好調度の差:各チームの直近 N 試合の勝ち点
- ホーム/アウェイの差:ホーム時の PPG とアウェイ時の PPG
- Over 2.5 のリスク:両チームの Over 頻度の平均
- BTTS のリスク:両チームの BTTS 頻度の平均
- 規律:両チームのカード数の平均(
Get_Match_Statsによる) - 変動性:各チームの直近 5 試合のゴール数の標準偏差
- サンプルの安定性:利用可能な試合数 N と最低 5 試合との比較
市場とデータの整合性 [IND]:
- 高い: 市場と過去のデータが同じ側を支持し、かつその度合いも同程度です。
- 中程度: 同じ側を支持していますが、強度が異なります。
- 低い: 異なる側を支持しているか、一方が均衡と見なし、もう一方がそう見なしていません。
(整合性の測定 — その理由の解釈ではありません。)
必須出力:
## 4. Indicadores Compuestos
Ventaja ofensiva: [Home] por [+/-X.XX] goles [IND]
Fragilidad: [Away] recibe [X.XX] goles/partido [IND]
Gap forma (últimos [N]): [Home] [+/-X pts] sobre [Away] [IND]
Gap casa/fuera: [Home] [+/-X.X] ppg [IND]
Riesgo Over 2.5: [X%] [IND]
Riesgo BTTS: [X%] [IND]
Volatilidad: [baja/media/alta] [IND]
Índice disciplina: [bajo (<1.0 yc/pp) / medio (1.0-1.5) / alto (>1.5)] [IND]
Mercado vs datos: [alta/moderada/baja]
Estabilidad muestra: [N] partidos / mínimo 5 — [suficiente/limitado]
劣化時の処理:
- 好調度のデータがない場合(N<3)→ 好調度の差と変動性を N/A とします。
4.5 全体的な冗長性回避ルール
各レイヤーは新しい情報を提供する必要があります。 すでに前のレイヤーで表現された考えは、別の形に変換されない限り 繰り返してはいけません(例:データ → 解釈)。
禁止事項:
- レイヤー 5 でレイヤー 2 の好調度、オッズ、連勝・連敗を再説明すること
- レイヤー 6 でレイヤー 5 の診断を再度行うこと
- レイヤー 8 でレイヤー 6 のシグナルを要約すること
許可事項:
- レイヤー 5 でレイヤー 2 のデータを使い、因果関係に基づいて解釈すること
- レイヤー 6 でレイヤー 5 のシグナルを使い、重要度に応じて重み付けすること
- レイヤー 8 でレイヤー 6 の優先順位付けを使い、最終的な見解に反映すること
正しい流れ:
datos (capa 2) → medición (capa 4) → interpretación (capa 5) → priorización (capa 6) → predicción (capa 7) → síntesis (capa 8)
レイヤー 5 — 診断
唯一の問い: それらのシグナルが重要なのはなぜか?
範囲: 原因 + 矛盾 + 持続可能性
入力: レイヤー 1、2、4 の出力。
因果関係のルール(新規): 原因を数値データの直接的な言い換えにしてはいけません。指標を繰り返すのではなく、そのメカニズムを説明する必要があります。
❌ 悪い例: 「Madrid がホームで優位に立つのは、PPG が 2.25 だからです」
✅ 良い例: 「Madrid がホームで優位に立つのは、トランジション時の強度とハイプレスによるものです。Bernabéu は単なる勝ち点の平均ではなく、そのダイナミクスを増幅します」
必須出力:
## 5. [Por Qué Pasa / Qué Está Pasando]
[Adaptar según estado:]
- notstarted: "Por Qué Pasa" — análisis de tendencias pre-partido
- inprogress: "Qué Está Pasando" — evaluación de lo que ocurre vs lo esperado + comparación con pre-match
Causas [IND]:
- [Causa real derivada de datos — explicar el MECANISMO, no reformular la métrica]
- [Causa 2]
Contradicciones:
- [contradicción 1 — mercado vs stats, forma vs contexto]
- [contradicción 2]
¿Sostenible?
- sí/no — [razón basada en evidencia]
[Para inprogress: usando `live_analysis` y `summary.events`]
Análisis en vivo: El marcador [X-X] [refleja/no refleja] lo que muestran las stats (xG: [xg_home]-[xg_away], posesión: [pos_home]%-[pos_away]%).
[¿El equipo [X] domina aunque no esté ganando?]
[¿Los últimos eventos cambiaron la dinámica?]
[`live_analysis` proporciona probabilidades actualizadas para cada mercado.]
劣化時の処理:
- stats がない場合 → 原因や持続可能性の分析は生成できません。
- 好調度のデータがない場合 → 「傾向を診断するにはデータが不十分です [N/A]。」
analysis_mode = "postmatch"の場合:焦点は「何が起こるか」から「何が起こり、その理由は何か」に変わります。事前の予想と実際の展開の矛盾を含めてください。
レイヤー 6 — シグナルの重み付け
重み付けルール:
| 重み | 対象となるもの | 対象とならないもの |
|---|---|---|
| 強い | シュート、一貫性(N≥5)、市場と指標の一致、主要選手のパフォーマンス | 裏付けのない短い連勝、単発のスコア |
| 中程度 | N=3-4のフォーム、ホーム/アウェイの文脈を考慮していないH2H、市場と過去データの中程度の差、他のレイヤーで裏付けられた複数の欠場者 | |
| 弱い | N<3、市場と過去データの大きな差、指標で裏付けられていない市場、他のレイヤーで裏付けられていない欠場者 |
役割のルール(新規): レイヤー 6 は優先順位付けを行う唯一のレイヤーです。レイヤー 8 では繰り返しません。
レイヤー 6 で行ってはならないこと:
- 新たな因果関係の解釈(これはレイヤー 5 の役割です)
- 市場の推奨(これはレイヤー 8 の役割です)
- すでに述べたシグナルの繰り返し
行うのは、ソースを示しながら重みに基づいて優先順位を付けること(強い/中程度/弱い/利用不可)だけです。
Get_Match_Lineups.missingPlayers に記録された複数の欠場者:
- 他のレイヤー(チームのパフォーマンス、ランキング、攻撃への依存度、フォーム)と一致する場合に限り、中程度のシグナルとして扱えます。
- それだけで強いシグナルとして扱うことはできません。欠場者のリストだけで分析を左右してはなりません。
- 欠場が統計データやランキングで裏付けられていない場合は、弱いシグナルです。
必須の出力:
## 6. Qué Señales Pesan Más
Fuertes [fuente]:
- [señal + razón]
Moderadas [fuente]:
- [señal + razón]
Débiles [razón]:
- [señal]
No utilizables [razón]:
- [señal]
Outliers:
- [partido + razón]
劣化時の対応:
- レイヤー 4 が利用できない場合 → シグナルは利用不可です。
analysis_mode = "postmatch"の場合、焦点を「何が起こる可能性があるか」から「何が起きたか、そしてその理由」へと切り替えます。事前の予想と実際の展開の矛盾を含めてください。
レイヤー 7 — 予測(オッズ主導)
組み合わせルール:
| 条件 | 対応 |
|---|---|
| オッズを利用できる | オッズを確率の基本ソースとして使用する |
| 指標を利用できる | 信頼度の引き上げ/引き下げのみに使用し、パーセンテージを作り出さない |
| オッズも指標も利用できない | 予測を出さない。信頼度は非常に低い。 |
| 市場と過去データが一致する | シグナルを強める |
| 市場と過去データが矛盾する | 弱める。「不確実」と明記する。 |
数値で示す確率は、オッズからのみ算出できます。指標からパーセンテージを作り出してはなりません。
必須の出力:
## 7. [Qué Podría Pasar / Qué Se Espera]
[Adaptar según estado:]
- notstarted: "Qué Podría Pasar" — predicción pre-partido
- inprogress: "Qué Se Espera" — predicción actualizada con marcador actual y stats en vivo
[Para notstarted:]
Resultado: [Home] [X]% | Empate [Y]% | [Away] [Z]%
Goles esperados: [Home] [X.XX] | [Away] [Y.XX] (basado en avg histórico)
Over 1.5: [X]% | Over 2.5: [Y]% | BTTS: [Z]%
Tipo: [cerrado/abierto/defensivo/competido]
Confianza: [muy baja/baja/media/media-alta/alta] — [motivo de la calificación]
[Para inprogress: usando `live_analysis`]
Marcador actual: [Home] [X] - [Y] [Away] — [minuto]'
xG acumulado: [Home] [X.XX] | [Away] [Y.XX]
Señales en vivo [live_analysis]:
- Over 2.5: [probability]% | BTTS: [probability]%
- Próximo gol — Home: [probability]% | Away: [probability]% | No más goles: [probability]%
- Esquinas próximo: [lean] | Señal: [signal]
- 1X2 final — Home: [probability]% | Empate: [probability]% | Away: [probability]%
Resultado esperado al final: [Home] [X] - [Y] [Away] (basado en xG y tiempo restante)
Tipo de partido: [cerrado/abierto/defensivo/competido]
Confianza: [muy baja/baja/media/media-alta/alta] — [motivo de la calificación]
[¿El equipo que está perdiendo merece estar abajo?]
Nota: "Predictiva basada en `live_analysis` + odds históricas."
劣化時の対応:
- オッズも指標もない場合 → 「予測は利用できません [N/A] — データが不十分です。」
- 市場と過去データが矛盾する場合 → 次を追加します:「⚠ 市場と過去データが一致していません。 不確実性が高まっています。」
第8層 — 最終的な読み取り
唯一の質問: 最終的にどのような見方をすればよいですか?
範囲: 人間による解釈+十分な根拠のある1〜2市場(概念的であり、数値は用いない)
ルール(新規): 第8層は概念レベルで扱います。シナリオ、リスク、読み取りを示します。第7層の確率や数値指標を繰り返さず、データを用いて再度根拠を説明せず、第6層のシグナルを要約しません。
第8層では、以下を行ってはいけません。
- 最も強いシグナルの一覧(第6層ですでに提示済み)
- アラートの一覧(第5層ですでに提示済み)
- 根拠のある市場の一覧(第7層ですでに提示済み)
- 確率や数値指標
次の内容だけを読み解きます:最も妥当なシナリオ、隠れたリスク、買うべきでないもの。
必須の出力:
## 8. Lectura Final
- Qué escenario tiene más sentido
- Qué escenario tiene riesgo oculto
- Qué NO comprar del partido
Opcional:
- 1-2 mercados bien justificados (no lista — solo decisión final bien fundamentada)
Nota: "Las lecturas anteriores son las mejor soportadas por la evidencia disponible."
品質低下時:
- 第7層の信頼度が非常に低い場合 → 第8層は「市場の推奨を伴わないシナリオの読み取り」に縮小します。
analysis_mode = "postmatch"の場合:焦点を「何が起こる可能性があるか」から「何が起きたか、そしてなぜ起きたか」に切り替えます。事前の予想と実際の展開との矛盾を含めてください。
9. 信頼度ポリシー
全体的な信頼度
| データの状態 | 最大信頼度 |
|---|---|
| 試合+オッズ+統計+選手統計+履歴 | 高 |
| 試合+オッズ+統計(選手統計なし) | 中〜高 |
| 試合+オッズ(統計なし) | 中 |
| 試合のみ | 低 |
| 試合なし | 非常に低い/分析不可能 |
層ごとの調整
| 不足しているデータ | 影響を受ける層 | 低下内容 |
|---|---|---|
| オッズなし | 第1層、第7層 | 最大で中 |
| 統計なし(シュート、コーナー、xG) | 第4層、第5層 | ゴールのシグナルが弱まる |
| 選手統計なし | 第3層 | N/A のテキストのみ |
| 履歴なし(N<3) | 第2層、第4層 | 過去のデータを利用できない |
| H2H なし | 第2層 | H2H = N/A |
層ごと
各層には、次のいずれかを指定できます。
- 完全 — すべての入力データを利用できます。
- 部分的 — 一部の入力データが不足しているため、該当する
[N/A]テキストを使用します。 - 利用不可 — 必要な入力データが不足しており、計算できません。
11. 不当な合理化の禁止
ここはガードレールのセクションです。以下の内容は必ず遵守してください。 以下の行為は、例外なく禁止です。
データを捏造しない
[N/A]→ 捏造しないでください。 選手統計がない場合 → 第3層は「十分なデータがありません」とします。- ラインナップ、負傷者、出場停止選手、監督を捏造しないでください。
Get_Match_H2Hが空または null の場合、H2H を捏造しないでください。
外部ソースを使用しない
- 分析中に、Bzzoiro、SofaScore、Transfermarkt、Wikipedia、その他のソースを参照しないでください。
- 有効な唯一の情報源は FlashScore MCP です(セクション3に記載のエンドポイント経由)。
モデルを即興で作らない
- 学習モデルに基づく予測の代わりとなるヒューリスティックモデルを構築しないでください。
- このバージョンは設計上、オッズ主導です。独自のモデルを即興で作らないでください。
- 第7層の数値確率は、オッズのみを根拠とします。独自の計算は使用しません。
- 第3層で重み(0.3、0.5 など)や複合指標を使用しないでください。
確実性を誇張しない
- 「勝つ」「確実だ」「オーバーは必ず成立する」と言わないでください。
- 必ず「可能性がある」「シグナル」「示唆している」「証拠は〜を示している」と表現してください。
- 必ず信頼度を示してください。
矛盾を省略しない
- 市場と指標が異なる方向を示す場合は、明確に述べてください。
- あるシグナルが傾向ではなくノイズである場合は、その旨を述べてください。
中身のない文で埋めない
- 各セクションには、必須フィールドを含む定義済みの出力があります。
- フィールドのデータがない場合 → 「[N/A]」+簡潔な理由。
- セクションを「空白」のままにしたり、何も伝えない一般的な文で埋めたりしないでください。
FlashScore MCP を誤解しない
Get_Team_Fixtures/Get_Team_Resultsが試合を見つける手段です。/api/events/?team=Xは存在しません。inprogressの試合:ライブ分析が可能です — 試合の最新データを使用してください。finishedの試合:analysis_mode = "postmatch"→ 試合後分析を進めてください。
postmatch のルール:
- 原因を捏造しないでください。Commentary は一連のプレーや局面を描写するためのものであり、構造的な優位性を作り上げるためのものではありません。
match_statsがない場合 → 結果+イベント+直近の調子+試合前オッズに限定してください。summary.eventsがない場合 → 「転換点」について述べないでください(出力形式ですでにフィルタリングされています:「summary.eventsまたは commentary に根拠がある場合のみ」)。- 完全な読み解きにデータが不十分な場合 → 「展開の部分的な分析」というラベルを使い、利用できなかったデータを列挙してください。
- Commentary は観察データであり、主要なシグナルではありません。他のレイヤーの指標と一致する場合にのみ有効です。
12. 分析の出力形式
必須の構成(以下の順序を厳守):
# [Home] vs [Away] — [Competición] ([Fecha])
[8 capas completas]
---
Confianza global: [muy baja/baja/media/media-alta/alta]
セクションごとの目安の長さ:
- レイヤー 1~2:各 8~15 行。
- レイヤー 3~6:各 5~12 行。
- レイヤー 7~8:各 8~15 行。
利用できないデータ:
- 欠損データには常に
[N/A]を使用してください。 - 理由を常に簡潔に説明してください。
強い/中程度/弱いシグナル:
- 散文ではなく、箇条書きで示してください。
分析の締めくくり:
- 全体的な信頼度を必ず含めてください。
- 強いシグナルと弱い相関を必ず区別してください。
- 断定的な文で締めくくらないでください。
データの保存
- この分析を
./claude/skills/football-betting-analysis/football-analysisにある txt ファイルに保存します。 - 大会名に対応する名前のフォルダーを作成します。例:Champions League 25-26。
- ファイル名を [DD_MM_AAAA] [EQUIPO LOCAL] vs [EQUIPO VISITANTE] [JORNADA_X].txt として保存します。[JORNADA_X] の X には、開催される節の番号、または該当する場合は準々決勝やラウンド 16 を指定します。
13. クイックリファレンス
CONSULTA NL → parsing → { home, away, date_from, date_to, league? }
Fase 1 (MCP directo):
Match discovery: livesport search API → /data/main_teams.csv (fallback) → Get_Team_Fixtures → Get_Team_Results
→ analysis_mode = prematch | live | postmatch
→ Extraer: event_id, home_team_id, away_team_id
Fase 2 (build_match_context.py):
python scripts/build_match_context.py <event_id> <home_team_id> <away_team_id>
→ Devuelve final_context JSON con todos los datos normalizados
NO LLAMAR ENDPOINTS MCP DIRECTAMENTE PARA DATOS DEL PARTIDO.
Solo Get_Team_Fixtures / Get_Team_Results para match discovery.
信頼度のしきい値:
| データ | 最大信頼度 |
|---|---|
| イベント + オッズ + 統計 + 選手統計 + 履歴 | 高 |
| イベント + オッズ + 統計(選手統計なし) | 中~高 |
| イベント + オッズ(統計なし) | 中 |
| イベントのみ | 低 |
| イベントなし | 実行不可能 |
分析全体で必須の情報源ラベル:
[API] [ODDS] [IND] [N/A]
重複を避けるルール(クイックリファレンス)
| レイヤー | 固有の質問 | してはいけないこと |
|---|---|---|
| 3 | 何があるか? | 解釈しない、結論を出さない |
| 4 | どのくらいか? | なぜ重要かを説明しない |
| 5 | なぜか? | 数値データを言い換えず、仕組みを説明する |
| 6 | 何が重要か? | レイヤー 5 の診断を繰り返さない |
| 8 | 何を結論として持ち帰るか? | レイヤー 6 のシグナルを要約しない、レイヤー 7 の数値を繰り返さない |
14. 解消済みの不備
| 合理化 | 対策 |
|---|---|
| 「FlashScore になかったので Bzzoiro/SofaScore/別のソースを使った」 | 禁止です。 FlashScore MCP のみを使用してください。例外はありません。 |
| 「player-stats がなかったので、ラインナップをでっち上げた」 | 禁止です。 レイヤー 3 のレーン B:Get_Match_Lineups に missingPlayers があれば使用してください。何もなければ → [N/A]。 |
| 「学習モデルベースの予測の代わりに、ヒューリスティックモデルを構築した」 | 禁止です。 レイヤー 7 = オッズ主導です。確率をでっち上げないでください。 |
| 「入力として架空の xG を使った」 | 禁止です。 FlashScore が Get_Match_Stats で xG を返さない場合、でっち上げないでください。API が提供するデータを使用してください。 |
| 「試合はすでに始まっているが、それでも分析したい」 | 該当しません。 このスキルは notstarted の試合のみを対象とします。inprogress または finished の試合については、処理を進めないでください。 |
| 「injuries data がなかったので、負傷者をでっち上げた」 | 禁止です。 missingPlayers が利用できない場合、欠場者やその理由をでっち上げないでください。 |
| 「欠場者ごとにチームの戦力がどれだけ低下するか計算した」 | 禁止です。 欠場の数値的な影響を推定しないでください。API が提供する情報と、定義済みの欠場レベルのみを使用してください。 |
| 「missingPlayers を単独で強いシグナルとして使った」 | 禁止です。 他のレイヤーで裏付けられていない欠場情報は弱いシグナルです。強いシグナルとして扱ってはいけません。 |
| 「H2H が返されなかったので、記憶を頼りに書いた」 | 禁止です。 Get_Match_H2H = null の場合は「H2H は利用できません [N/A]。」としてください。 |
| 「イベントしかなかったのに『高』とした」 | 禁止です。 イベントのみの場合、信頼度は「低」です。しきい値テーブルに従う必要があります。 |
| 「オーバーは確実に入る」 | 禁止です。 常に確率的な表現を使用してください。 |
| 「レイヤー 3 を記憶に頼った名前で埋めた」 | 禁止です。 各レイヤーには定義済みの出力があります。データがなければ → [N/A]。 |
| 「2 試合のサンプルは代表性がある」 | 禁止です。 N<5 の場合は「サンプル数が限られています。」としてください。指標の重みは小さくなります。 |
| 「0.3/0.5 の重みで impact score を計算した」 | 禁止です。 レイヤー 3 では、ヒューリスティックな数式ではなく、直接データとランキングを使用します。 |
| 「モデルから直接 Get_Match_Details/H2H/Stats を呼び出した」 | 禁止です。 試合データの収集はすべて build_match_context.py を経由します。試合の発見には Get_Team_Fixtures/Get_Team_Results のみを使用してください。 |
| 「スクリプトが警告を出したが、データは正しいと思った」 | 禁止です。 スクリプトの警告は指示です。スクリプトがデータを疑わしいと判定した場合は、それに従い、異議を唱えないでください。 |
| 「JSON は [N/A] だったが、記憶ではデータを知っていた」 | 禁止です。 JSON は利用可能なデータを正規化し、印を付けています。[N/A] とマークされたデータを再びでっち上げないでください。 |
| 「JSON を受け取った後、追加の MCP エンドポイントを実行した」 | 禁止です。 final_context を受け取った後は、分析に使うすべてのデータを JSON から取得してください。追加のエンドポイントを照会しないでください。 |