用Skill File实现贴近真实规则的League Mock Draft
2026/9/4 20:35:35 网站建设 项目流程

mock draft 要真实,最后都得回答同一个问题:它是按照你自己的 league 规则跑出来的,还是套了一个通用默认流程?在带 skill 机制的开发场景里,这类需求越来越多:开发者把规则说明、数据文件和处理脚本打包成一个轻量 skill file,让助手或本地脚本读取后生成贴近实际业务的 mock 结果。看 Hacker News 上“Realer Mock Draft”这类展示项目时,最先被问到的往往不是“它能模拟几轮”,而是“它怎么知道我的 league 长什么样”。

下面这套做法会沿着结构到排错的思路,完整拆解一个可以长期维护的 league mock skill:先理解为什么要用 skill file,再准备 league 配置和球员池两份数据文件,然后搭出 SKILL.md、Node 脚本、校验脚本的最小骨架,最后重点处理最容易卡住的两个实际问题:独立 JS 脚本的 export default 怎么写,以及在线 mock 平台不可用时如何用本地 fixture 兜底。整个过程不需要复杂的工程框架,Node 18 以上环境就可以直接跑通。先把核心认知理清:mock draft 不是随机抽签,而是一套输入、决策、输出和校验机制。

1. 为什么需要 skill file:把“模拟选秀”焊死在你的 league 上

1.1 通用 mock 与基于 league 的 mock 差异很大

很多在线模拟器打开就能用,但它背后是一套写死的默认 league。默认可能是 12 支队伍、15 轮选秀、标准阵容槽位、固定计分。真实 league 通常比这复杂:

  • 队伍数量可能是 10 支、12 支,也可能是 14 支。
  • 选秀轮次需要匹配 roster 槽位,而不是随便设一个整数。
  • 计分可能是 PPR、半 PPR、标准分,或自定义的上场人数限制。
  • 部分球员已经作为 keeper 被锁定,不应进入可选中池。
  • 每个 manager 的 pick 顺序、蛇形方向、交易后的轮次错位都可能不同。

这些信息如果只写在自然语言里,靠人类逐条执行,容易漏;如果只写进可视化界面的下拉框里,团队每次要花时间维护配置项。skill file 解决的是同一个问题:把规则、数据和算法集中到一个可复用单元里,让不同 league 可以通过替换数据文件和参数来使用同一套 mock 逻辑。

下表能看出两类方案的关键差异:

对比维度通用 mock 模拟器基于 skill file 的 league mock
队伍数量通常写死默认值从 league.json 读取
轮次数量脚本内置固定值根据 roster 需求计算或配置
阵容槽位默认 QB/RB/WR/TE/FLEX按 roster_slots 驱动
计分权重界面提供少量模式league.json 自由定义
球员池平台维护的大名单替换 JSON 即可适配不同联赛
keeper 锁定状态需要单独管理写入球员字段即可排除
本地离线运行依赖在线服务数据文件加 Node 脚本即可运行

1.2 skill file 在技术上是什么

skill file 并不是一门新技术,它只是把“技能描述 + 数据 + 处理脚本”放在一个约定目录里。常见结构类似:

<skill-name>/ ├─ SKILL.md ├─ data/ └─ scripts/

其中 SKILL.md 描述这个技能什么时候启用、需要哪些输入、处理步骤是什么、输出格式是什么。真正负责计算和处理结果的是 scripts 目录里的脚本。以 Agent Skills 这类形态为例,运行器通过读取 SKILL.md 决定是否启用该技能;启用后,模型或脚本引擎再调用 Node、Python 等本地程序完成计算,而不是在提示词里硬推理。

这样设计的核心原因很直接:

  • 语言模型擅长理解意图,但不擅长稳定执行重复的中长尾规则。
  • 脚本擅长计算、遍历、排序、校验,但不擅长理解“用户说的第 1 轮第 7 顺位是什么意思”。
  • 把两者结合:SKILL.md 负责理解意图,脚本负责稳定输出。

1.3 容易误解的地方

误区一:skill file 是一份给人看的文档。现实中它是运行时读取的程序单元,SKILL.md 里写的 description 会直接决定某个助手能否在合适时刻想起这个技能。

误区二:mock 既然是模拟,就允许随机。实际上没有可控随机种子和固定规则哈希的 mock,很难排查问题。你无法向同事解释为什么两次生成结果不同,是因为真的模拟了“策略变化”,还是脚本状态污染。

误区三:把算法写在提示词里也没问题。简单的五个球员可以,但一旦 league 有 300 人池、15 轮、蛇形顺位、keeper 锁定,提示词里的描述很容易出现矛盾,而脚本不会。

2. 先定输入模型:league 配置和球员池怎么组织

2.1 league.json 是 mock 的第一输入源

先创建一份最小但完整的 league 配置示例。这份文件回答的问题是:这次 mock 要模拟什么环境。

{ "league_name": "demo-league", "league_id": "demo-2025", "team_count": 12, "snake": true, "rounds": 15, "roster_slots": { "QB": 1, "RB": 2, "WR": 2, "TE": 1, "FLEX": 1, "BENCH": 8 }, "scoring": { "pass_td": 4, "rush_rec_td": 6, "interception": -2, "reception_points": 1 } }

字段含义如下:

  • league_id:用于区分不同 league 的唯一标识,后续输出文件建议带上它。
  • team_count:参与模拟的经理人数,直接决定每一轮生成多少个 pick。
  • snake:是否采用蛇形选秀。设为 true 时,第 2 轮顺序会反过来。
  • rounds:总共进行多少轮。生产环境建议根据 roster_slots 的总需求计算,而不是手写一个容易和阵容不匹配的数字。
  • roster_slots:每个位置槽位的数量。示例配置中每队需要 1 个 QB、2 个 RB、2 个 WR、1 个 TE、1 个 FLEX、8 个替补。
  • scoring:计分权重。同一个球员在不同 ppr 设置下得分不同,排序结果也会不同。

这里有一个值得注意的设计选择:roundsroster_slots应该保持一致。比如阵容槽位加起来是 15,那么一轮 mock 应该也是 15 轮,否则会出现多选或漏选。

2.2 player_pool.json 保存球员池快照

球员池不需要在每次 mock 时动态抓取。更稳妥的做法是先拉取一份快照,写入 data 目录,让 mock 过程可以重复执行。示例结构如下:

{ "snapshot_time": "2025-05-01T08:00:00Z", "players": [ { "id": "RB-001", "name": "Demo RB 1", "positions": ["RB"], "adp": 4, "bye": 10, "keeper_team_index": null, "projections": { "rush_yards": 1150, "rush_td": 9, "receiving_yards": 220, "receptions": 45 } }, { "id": "WR-001", "name": "Demo WR 1", "positions": ["WR"], "adp": 8, "bye": 11, "keeper_team_index": null, "projections": { "receiving_yards": 1280, "rush_rec_td": 7, "receptions": 95 } } ] }

说明几个字段:

  • id:球员唯一标识,mock 输出里只存这个 id 会比反复拼接名字更可靠。
  • positions:球员可打的位置。双位置球员写成数组,如["RB", "WR"]
  • adp:平均被选中位置。主要用于同分排序,也可以作为纯 mock 时的默认策略信号。
  • keeper_team_index:如果某球员已经被某队锁定,就不会出现在可选中候选池。
  • projections:预测数据,由积分函数计算得到综合分。不同 scoring 配置会改变最终得分。

player_pool 不需要真实球星数据才能演示流程,用占位 ID 跑通后,把 JSON 换成真实数据源即可。这里不建议在 skill 内直接携带整份付费数据或比赛日内部数据,能放 schema 和样例,就不要放原始全量内容。

2.3 输入模型独立带来的收益

一旦 league 配置和球员池变成独立 JSON,mock skill 就拥有了第一个可复用能力:换 league 时只需要替换数据文件。比如同时存在league-2024.jsonleague-2025.json,同一套脚本无需改动就能输出两套不同结果。这也让“你的 league”不再是 UI 里的临时表单,而成为文件、Git 历史和审计记录的一部分。

3. 搭出最小可运行骨架:目录、SKILL.md 和 package.json

3.1 目录结构先行

在进入代码前,先约定一个稳定的目录。这样后续脚本里不会出现散落的相对路径。

league-mock-skill/ ├─ SKILL.md ├─ package.json ├─ data/ │ ├─ league.example.json │ └─ player_pool.example.json ├─ scripts/ │ ├─ generate-mock.mjs │ └─ validate-mock.mjs └─ output/

目录中每个元素的职责:

  • SKILL.md:技能声明文件,给外部运行器或协作者判断入口。
  • package.json:定义项目依赖和 npm scripts。
  • data/:存放所有输入数据文件;league.example.jsonplayer_pool.example.json是示例文件。
  • scripts/generate-mock.mjs:真正执行 mock 的生成脚本。
  • scripts/validate-mock.mjs:对生成结果做约束校验。
  • output/:存放每次生成结果,便于 diff。

3.2 SKILL.md 的内容怎么写

SKILL.md 不负责计算,它负责告诉外部运行器“什么时候该调用这个技能”。示例:

--- name: demo-league-mock-draft description: 根据用户自己的 league 配置

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询