mcpField
F
football-betting-analysis

football-betting-analysis

github.com/josearroyave数据与数据库0268 次安装28 周前更新
代码仓库

关于 football-betting-analysis

用于分析赛前及进行中足球比赛的技能,可将 FlashScore 数据整理为结构化、基于证据的报告。它会预处理并规范化比赛信息,以谨慎的概率表述代替下注建议或保证。

主要功能

  1. 01根据球队和日期查询发现比赛
  2. 02从 FlashScore 数据构建规范化比赛上下文
  3. 03结合赔率、状态、阵容和赛事信息
  4. 04按数据来源标记证据
  5. 05生成概率式结构化分析

适用场景

  1. 01评估特定的即将开赛足球比赛
  2. 02分析正在进行的比赛
  3. 03对照赔率、状态和比赛背景
  4. 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.md
data/
all_tournaments.csv
main_leagues.csv
main_teams.csv
scripts/
build_match_context.py
generate_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 的行为:

脚本按两个优先级处理阵容:

  1. 如果存在 startingLineups(已确认的官方阵容):

    • starting_lineups — 已确认的首发阵容 [API]
    • missing_players — 缺席球员及原因 [API]
    • substitutes — 可用替补 [API]
    • predicted_lineups → 空
    • unsure_missing — 空
  2. 如果不存在 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
只提到一支球队搜索该球队在 7 天范围内的下一场比赛
带重音符号的名称(“Atletico”、“Inter”)搜索前去除重音符号进行规范化
部分名称(“Barça”、“Atleti”)对结果中的 home_team/away_team 进行模糊匹配
提到赛事(“la league”、“champions”)搜索后按 league_id 筛选

| status = "notstarted" | analysis_mode = "prematch" → 继续 | | status = "inprogress" | → 继续进行实时分析。 | | status = "finished" | → 不适用。通知用户。 |

如果只匹配到一支球队,但对手有多个候选项: → 必须澄清。询问:“你想查 [球队] 对阵 [候选 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."

推荐相近候选项:

  • 相似度阈值:比率 ≥ 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. 如果用户提到了联赛 → 优先选择该联赛。
  2. 如果用户提到了确切日期 → 只考虑该日期。
  3. 如果两支球队组合起来恰好有 1 场比赛 → 使用该比赛。
  4. 如果同一支球队有多场比赛 → 优先选择时间上最接近查询日期范围的比赛。 这样可以避免不必要的澄清。
  5. 否则,必须澄清。
4.3 预处理(阶段 2 — build_match_context.py)

这是获取分析数据的唯一方式。不要直接使用 MCP 端点获取比赛数据。

python scripts/build_match_context.py <event_id> <home_team_id> <away_team_id>

脚本的作用:

  1. 在内部调用所有 FlashScore 端点
  2. 根据两支球队的结果历史构建 H2H
  3. 汇总状态历史(GF、GC、Over、BTTS、主场/客场拆分)— form.basic
  4. 从 Get_Match_Lineups 提取并规范化缺席信息
  5. 验证实际存在的赔率市场,并屏蔽不存在的市场
  6. 整合历史中每场比赛的高级统计数据(射门、控球率、xG 等)— 仅用于构建 form.advanced(最终 JSON 中不输出单场数据)
  7. 按球队汇总历史球员统计数据(player_stats.as_historical_home/away)
  8. 纳入赛事背景(排名、状态、大小球排名)
  9. 发出一致性警告
  10. 将所有信息整合到一个 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]

降级处理:

  • 如果没有赔率 → 不比较市场与指标的差异。仅在有赔率时使用。
  • 如果两者都没有 → 层面 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":加入结果与赛前状态及赛前赔率的比较。

层面 3 — 关键人物

通用规则(新增): 层面 3 = 仅包含事实 + 最少背景信息。不作解读、不赋予权重、不下结论、不使用因果性措辞。

Capa 3 NO puede contener:
- conclusiones
- inferencias
- lenguaje causal ("porque", "esto implica", "esto sugiere")

Solo descripción estructurada de datos.

唯一问题: 有什么?(不是:这意味着什么?)

双路径逻辑(始终尝试两条路径):

  • 通道 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

每队 Top 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]”
  • 如果某队超过 50% 的产出来自单一球员 → 发出提醒。

通道 B — Get_Match_Lineups 的数据来源:

脚本 build_match_context.py 按两个优先级处理阵容(定义于 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 中包含缺席球员,请按照下文定义的缺席级别进行报告。

缺席级别(按深度递增):

  1. **已观察到的缺席 [API]:**姓名 + API 返回的原因(Injury、Inactive、Leg Injury 等)。仅报告 API 指明的内容。

  2. **有背景信息的缺席 [IND]:**如果该球员还出现在 Get_Tournament_Top_Scorers 中,或在此前比赛的 Get_Team_Results 或 Get_Match_Player_Stats 中被列为相关得分手/进攻组织者 → 标注为:“[球员] 缺席 — 已记录为本届赛事的得分手/顶尖球员 [IND]。”仅报告事实,不解读影响。

  3. **影响力不确定 [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 为第三层辅助来源——仅用于描述比赛过程,绝不用于虚构结构性优势。如果没有 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 主场占优,源于其在攻防转换中施加的强度和高位逼抢——伯纳乌球场会放大这种态势,而不仅仅是平均积分”

必需输出:

## 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.]

降级处理:

  • 如果没有统计数据 → 无法生成原因或可持续性分析。
  • 如果没有状态数据 → “趋势诊断数据不足 [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 层的数值概率只能来自赔率,不得使用自行计算的结果。
  • 不得使用权重(0.3、0.5 等)或第 3 层的综合指标。
不得夸大确定性
  • 不得说“必胜”“稳了”“大球稳进”。
  • 始终使用“可能”“信号”“表明”“证据指向”等表述。
  • 始终注明置信度。
不得遗漏矛盾
  • 如果市场和指标分别看好不同方向 → 必须明确指出。
  • 如果某个信号只是噪声而非趋势 → 必须说明。
不要用空话填充
  • 每个章节都有包含必填字段的明确输出要求。
  • 如果某个字段没有数据 → 使用 "[N/A]" + 简短原因。
  • 不要让章节“空白”,也不要使用没有实际内容的泛泛措辞。
不要误解 FlashScore MCP
  • Get_Team_Fixtures / Get_Team_Results 是比赛发现途径。 不存在 /api/events/?team=X。
  • 对于 inprogress 比赛:可进行实时分析——使用当前比赛数据。
  • 对于 finished 比赛:analysis_mode = "postmatch" → 继续进行赛后分析。

postmatch 规则:

  • 不要臆造原因。解说内容用于描述比赛过程和关键时刻,而不是臆造结构性优势。
  • 如果没有 match_stats → 仅限于结果 + 事件 + 状态 + 赛前赔率。
  • 如果没有 summary.events → 不要谈论“转折点”(输出格式已作筛选:“仅在 summary.events 或解说内容中存在证据时才提及”)。
  • 如果数据不足以进行完整解读 → 使用“比赛过程的部分解读”标签,并列出缺少哪些数据。
  • 解说内容是观察数据,不是主要信号。只有在与其他层的数据指标相符时才有效。

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]。
  • 一律简要说明原因。

强 / 中 / 弱信号:

  • 使用项目符号列表呈现,不要写成段落。

分析结尾:

  • 必须包含总体置信度。
  • 必须区分强信号与弱相关性。
  • 结尾不得使用确定性措辞。
保存数据
  1. 将此分析保存为 txt 文件,路径为 ./claude/skills/football-betting-analysis/football-analysis。
  2. 创建一个名称对应比赛所属赛事的文件夹,例如 Champions League 25-26。
  3. 将文件保存为 [DD_MM_AAAA] [EQUIPO LOCAL] vs [EQUIPO VISITANTE] [JORNADA_X].txt,其中 [JORNADA_X] 中的 X 是当前轮次编号,或对应的四分之一决赛、八分之一决赛等阶段。

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. 已解决的问题

自我辩解应对措施
“我用了 Bzzoiro/SofaScore/其他来源,因为 FlashScore 没有”禁止。 只能使用 FlashScore MCP。没有例外。
“没有 player-stats,所以我编造了阵容”禁止。 第 3 层 B 轨道:如果 Get_Match_Lineups 中有 missingPlayers,就使用它。如果没有任何数据 → [N/A]。
“我构建了一个启发式模型,来替代基于机器学习模型的预测”禁止。 第 7 层 = 由 odds 驱动。不得编造概率。
“我把编造的 xG 用作输入”禁止。 如果 FlashScore 的 Get_Match_Stats 没有提供 xG → 不得编造。使用 API 提供的数据。
“比赛已经开始了,但我还是想做分析”不适用。 此 skill 仅适用于 notstarted 比赛。对于 inprogress 或 finished 比赛,不得继续。
“没有伤病数据,所以我编造了伤员”禁止。 如果 missingPlayers 不可用 → 不得编造缺席情况或原因。
“我计算了每名缺席球员会让球队实力下降多少”禁止。 不得估算缺席造成的数值影响。只能使用 API 提供的数据和已定义的缺席等级。
“我单独把 missingPlayers 当作强信号使用”禁止。 未经其他层面佐证的缺席信息 = 弱信号。绝不是强信号。
“没有 H2H 数据,所以我凭记忆填了自己知道的内容”禁止。 如果 Get_Match_H2H = null → “H2H 不可用 [N/A]。”
“虽然只有事件数据,但我还是标了‘高’”禁止。 只有事件数据 = 低置信度。阈值表为必填项。
“大球肯定能打出”禁止。 始终使用概率性措辞。
“我凭记忆填充了第 3 层的球员姓名”禁止。 每一层都有定义好的输出。没有数据 → [N/A]。
“2 场比赛的样本具有代表性”禁止。 N<5 = “样本有限。”指标的权重更低。
“我用 0.3/0.5 的权重计算了影响评分”禁止。 第 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。不得查询额外端点。

评论

支持 Markdown