关于 football-betting-analysis
用于分析赛前及进行中足球比赛的技能,可将 FlashScore 数据整理为结构化、基于证据的报告。它会预处理并规范化比赛信息,以谨慎的概率表述代替下注建议或保证。
主要功能
- 01根据球队和日期查询发现比赛
- 02从 FlashScore 数据构建规范化比赛上下文
- 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 的行为:
脚本按两个优先级处理阵容:
-
如果存在
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 |
| 只提到一支球队 | 搜索该球队在 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 场比赛 → 使用该比赛。
- 如果同一支球队有多场比赛 → 优先选择时间上最接近查询日期范围的比赛。 这样可以避免不必要的澄清。
- 否则,必须澄清。
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提取并规范化缺席信息 - 验证实际存在的赔率市场,并屏蔽不存在的市场
- 整合历史中每场比赛的高级统计数据(射门、控球率、xG 等)— 仅用于构建
form.advanced(最终 JSON 中不输出单场数据) - 按球队汇总历史球员统计数据(
player_stats.as_historical_home/away) - 纳入赛事背景(排名、状态、大小球排名)
- 发出一致性警告
- 将所有信息整合到一个 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 中包含缺席球员,请按照下文定义的缺席级别进行报告。
缺席级别(按深度递增):
-
**已观察到的缺席 [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为第三层辅助来源——仅用于描述比赛过程,绝不用于虚构结构性优势。如果没有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]。 - 一律简要说明原因。
强 / 中 / 弱信号:
- 使用项目符号列表呈现,不要写成段落。
分析结尾:
- 必须包含总体置信度。
- 必须区分强信号与弱相关性。
- 结尾不得使用确定性措辞。
保存数据
- 将此分析保存为 txt 文件,路径为 ./claude/skills/football-betting-analysis/football-analysis。
- 创建一个名称对应比赛所属赛事的文件夹,例如 Champions League 25-26。
- 将文件保存为 [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。不得查询额外端点。 |