返回博客2026年5月14日2 分钟阅读

用 AI 玩转英超 - 我把自己玩 FPL 的工作流写成了一个 Agent Skill

摘要

Fantasy Premier League 每周一次决策,每次都要看一堆分散在不同网站上的数据:球员状态、对手赛程难度、转会成本、队长候选人。我把这套工作流整理成了一个 skill,叫 fpl-copilot - 数据本地 SQLite,阵容用 Markdown 文件持久化,每个 GW 的分析输出成自包含的 HTML 报告。Claude Code 和 Codex 都能装。

我是 Fantasy Premier League 多年的玩家,每个 gameweek 截止前都要做一连串决策 - 这周谁首发、谁上替补、队长选谁、要不要用一张转会、要不要触发某张 chip。决策的输入很分散:

  • fpl.com 看自己的阵容、看其他玩家的 ownership
  • fplreview 看 projected points
  • LiveFPL 看 fixture difficulty rating
  • Twitter / news 看 injury 状态
  • ......

每个工具都做对一件事,但放在一起就是切来切去。我用 Claude CodeCodex 的时间越来越长,自然就在想 - 能不能把这套工作流写成一个 skill,让 LLM 帮我把数据汇聚到本地,每次问一个问题(“这周队长选谁”、“M. Salah 这五个 GW 的 xG 怎么样”),直接出答案,不用切窗口?

这个 skill 我自己用了几个 GW,稳定之后顺手开源了,叫 fpl-copilot。这篇会聊聊它的几个设计选择,期望对大家有所帮助。

为什么是 Skill 不是 webapp

Skill 的定义很简单 - 一个 SKILL.md 文件 + 若干 reference / script / template,让 Claude 在合适的时机自动调用。它不是独立程序,也不是 chrome extension,是 LLM 的一个"上下文模块"。

我之前也想过做一个 webapp 把这些数据可视化出来。但仔细想 - FPL 的核心动作不是看仪表盘,而是回答一些带条件的问题

  • “Wolves 接下来 5 个 GW 的赛程难度是多少”
  • “我现在有 £8.3m 预算,性价比最高的中场是谁”
  • “如果我把 Maddison 换成 Palmer,未来 5 个 GW 期望多多少分”

这些问题的形式高度灵活,再好的仪表盘都覆盖不了所有组合。但如果数据在一个本地 SQLite 里,把 schema 告诉 LLM,让它自己写 SQL 查 - 答案就自由了。LLM 不擅长可视化大量数据,但很擅长在结构化数据上做 ad-hoc 查询

所以 skill 的定位是:让 LLM 充当一个会查 SQL 又懂 FPL 的助手,而我充当那个提问的人。

数据层用 SQLite + 一个同步脚本

第一层是数据。FPL 没有官方文档化的 API - 但 fantasy.premierleague.com 自己用的几个 JSON 端点公开可访问、不需要 auth,社区已经把它们当 API 用了多年(fplreview、LiveFPL、各类开源库都靠它)。需要注意的是 FPL 从未对这些端点做过承诺,赛季间偶尔会改格式。

  • bootstrap-static.json - 所有球员、所有球队、所有 gameweek 的基础信息(一次 ~600 球员)
  • fixtures.json - 全部 380 场赛程
  • element-summary/{player_id}.json - 单个球员的每场比赛历史

skill 自带一个 sync.sh,把这些 endpoint 拉下来塞进 ~/.fplcopilot/fplcopilot.db。schema 大概长这样:

players (id, web_name, team_id, position, now_cost, form, total_points, status, ...)
teams (id, name, short_name, strength_home, strength_away, ...)
fixtures (id, gameweek, team_h, team_a, difficulty_h, difficulty_a, kickoff_time, ...)
player_history (player_id, gameweek, minutes, goals, assists, xg, xa, bps, ...)
sync_metadata (key, value, updated_at)

sync.sh bootstrap 跑一次拿球员和球队,约 5 秒。sync.sh fixtures 拿全部赛程,约 2 秒。sync.sh player 328 单独拉某个球员的完整历史(比如 Salah 的 GW-by-GW 数据)。sync_metadata 表存上次同步时间,skill 在回答数据问题前会先检查 - 超过 6 小时就建议先同步。

数据全部在本地,不依赖任何第三方服务。即使断网也能拿历史数据做分析。

每个阵容存成一个 Markdown 文件

第二层是用户状态 - 我的阵容、转会决定、用过哪些 chip。这部分没有塞进 SQLite。原因是这种状态是叙事性的:

  • 阵容是动态的:每个 GW 都可能换人、换队长
  • 上下文很重要:为什么这个 GW 用 Triple Captain、为什么留着 Maddison 还没卖
  • 我可能同时管理几个 squad - 自己的、朋友的、Wildcard 草稿

塞进数据库做起来不舒服。每个 squad 一个独立的 Markdown 文件反而清爽 - 内容人类可读、可以 git 管理、可以手改、可以 diff 出 GW 之间的变化。文件长这样:

---
name: MyFplTeam
owner: me
updated: 2026-05-13
gameweek: 36
formation: 3-4-3
captain: Salah
vice_captain: Saka
bench: [Mamardashvili, Senesi, Kroupi Jr., Salmon]
chips_used: [TC@GW32]
---

## XI
- GKP: Donnarumma
- DEF: Virgil, Saliba, Van Hecke
......

## Notes
- GW36: 用 Wildcard 重组,主力中场集中在英超头部对阵中下游的轮次
- GW32 用了 TC on Semenyo(away to Spurs,contrarian captain)

skill 在每次涉及阵容的对话之后自动更新这个文件。问“M. Salah 这周首发吗”,它会去读这个文件而不是回头问我。做完一次转会建议,它会把新决定写回去。

决策类输出全部走 HTML

这一层是另一篇博客论证过的方向 - Agent 输出 HTML 的时代到了fpl-copilot 就是那个论点的一个工作实例:输出之后我要看着它做下一步决策的工件,全部走 HTML。

具体哪类问题走 HTML,写在 SKILL.md 的 Agent Rule #11 里:

问题类型输出模板
"我的阵容长什么样" / "next gameweek team"HTMLsquad-view.html
"未来 5 个 GW 的 FDR matrix"HTMLfixture-matrix.html
"Maddison 换 Palmer 划不划算"HTMLtransfer-comparison.html
"这周队长选谁"HTMLcaptain-ranking.html
"GW 36 整体策略"HTMLgameweek-report.html
"Salah 的 form 是多少"Markdown-
"Wolves 的 short name 是什么"Markdown-

报告输出在 ~/.fplcopilot/reports/{YYYY-MM-DD}-{slug}.html,本地双击就开。每个模板都是单文件,inline CSS,必要的 JS 也直接 inline(比如按 FDR 颜色排序的小逻辑),mobile responsive。

实际跑出来的样子:左边是 Claude Code 里的简短对话回答("Solomon out,建议 Dewsbury-Hall / Hinshelwood / Ampadu 替换"),右边是同一个问题生成出来的 GW37 Strategy HTML 报告 - TL;DR、Squad Health、Lineup、FDR Matrix、Captain、Transfers、Chips 一页全有。

为什么这条规则要写得这么硬 - 我之前的版本是把它写在 SKILL.md 中段。模型经常忽略它,每次问 GW 策略都给我返回一堆 Markdown 表格,我得手工说"再做一个 HTML 版"。把它升级成 Agent Rule(加上一张问题类型 → 模板的硬映射表)之后,模型基本不再漏调用 HTML 模板了。

这也是 skill 跟 prompt template 的区别之一 - prompt 里的软提示模型说忘就忘,但 skill 里 Agent Rule 是结构化、有编号的硬约束,模型识别度高很多。

装一个试试

skill 在我自己的 marketplace 里。Claude CodeCodex 都能装:

/plugin marketplace add sugarforever/01coder-agent-skills
/plugin install 01coder-skills@01coder-agent-skills

装完,问它“帮我看看 Wolves 接下来 5 个 GW 的赛程难度”,它会先建议同步数据,然后开始回答。第一次同步约 5 秒。

第一次问到阵容相关的问题,它会让你提供当前 squad(截图也行,或者文字粘)。识别完之后写入 ~/.fplcopilot/squads/my-fpl-team.md,之后所有对话都基于这个文件继续。

做不到的事

这个 Skill 也有做不到的事情:

  • 没有 LiveFPL 的 EO / Effective Ownership 数据。FPL 官方 API 不出这个。如果需要,自己复制一份贴进对话即可
  • 没有 transfer planner 那种"未来 5 个 GW 同时优化"的 ILP 求解。我试过让 LLM 直接用 SQL 模拟,结果对中等复杂度的方案能给合理答案,但严格意义上的最优不保证
  • 不抓 injury news。injury 这种状态太动态、文本来源太杂,让 LLM 看 RSS 或者直接做 web search 比在阵容数据这个域里做规则匹配合适,所以这部分留给别的 skill / 别的对话
  • 数据准确性依赖 FPL 官方 API。官方什么时候出问题,skill 就跟着出问题

相关文章

2026年5月13日

Agent 输出 HTML 的时代到了

Anthropic 工程师 Thariq Shihipar 5 月初发了一条“HTML is the new markdown”,附了 20 个由 Claude Code 产出的单文件 HTML 示例。Simon Willison 第二天宣布放弃用了三年的 Markdown 默认值。这件事值得跟一跟 - 不是 HTML 全面胜出,而是 agent 输出三年前和现在已经是两回事。

最近一封 · Sample

Agent 输出 HTML 的时代到了

Anthropic 工程师 Thariq Shihipar 5 月初发了一条“HTML is the new markdown”,附了 20 个由 Claude Code 产出的单文件 HTML 示例。Simon Willison 第二天宣布放弃用了三年的 Markdown 默认值。这件事值得跟一跟 - 不是 HTML 全面胜出,而是 agent 输出三年前和现在已经是两回事。

—— william

Letters

来信

里面装的是

  • 新文章 — 写完一篇就寄一封,不攒货
  • 这周读到的、看到的、好用的工具
  • 正在折腾的实验,附带翻车记录

约莫 1–2 周一封 · 随时退订

合作伙伴

CompeteMap — 英国及爱尔兰学生竞赛一站式搜索

数学、编程、科学、写作等各类竞赛信息汇总,支持按年龄和科目筛选,再也不错过报名截止日。

准备开始了吗?

先简单说明目标,我会给出最合适的沟通方式。