这次我们来看的不是又一个通用 mock draft 模拟器而是一个把“基于你自己联赛的 mock draft”打包成 skill file 的项目思路。项目标题来自 Show HN 上的 “Realer Mock Draft”它想解决的问题很直接大多数选秀模拟工具用的是通用球员池、通用计分规则和通用阵容位置和你真实加入的 fantasy 联盟根本对不上。你按默认规则模拟十轮回到自己联盟一看sleeper 球员、keeper 规则、阵容位置和积分设置全都不一样模拟结果只能看图不能辅助决策。这个项目的思路是把“你的 league”变成 skill 执行前必须加载的上下文而不是让 skill 凭记忆瞎猜。所谓 skill file就是一套可以被 AI Agent 识别的技能定义文件通常包含一个SKILL.md、若干结构化配置和数据文件必要时还能带脚本。只要你的运行环境支持“skills 目录约定”模型就能在用户提到 mock draft 时自动读取这份技能再结合你 league 的真实规则、真实参赛名单和选秀签位输出一份更贴近本联盟的模拟选秀。本文会把这种思路拆成一套可复用的工程模板先看 skill file 的核心能力与适用边界再给目录结构、SKILL.md写法和league_profile.yaml配置示例然后演示如何把 league 数据加载成模型上下文、如何跑一次完整 mock draft、如何批量生成多组策略结果最后补上常见的触发失败、数据错乱和隐私合规问题。适合 fantasy league 的管理者、对 draft 策略感兴趣的内容作者以及想写 skill file 但不知道怎么组织的开发者。先从核心能力速览开始。1. Realer Mock Draft 思路与核心能力速览这个项目的核心不是“教你哪一轮选谁”而是提供一种技能文件的设计规范把 league 规则结构化让 mock draft 在模拟时只基于你 league 的数据。能力项说明项目类型面向 AI Agent 的 skill file 配置与工具链解决的核心问题通用 mock draft 与真实联盟规则不一致关键输入league 规则、阵容结构、参赛经理名单、keeper、历史球员数据模拟依据你 league 的定制计分与选秀设置运行载体支持 skills 目录约定的 AI 客户端或开发框架核心文件SKILL.md、league_profile.yaml、球员池数据、执行脚本批量能力可通过多次调用或脚本循环生成不同策略的多份模拟结果是否依赖 GPU通常不需要消耗主要来自大模型推理 token 与外部 API 请求是否提供 API取决于你运行的 skill 宿主环境上手门槛需要了解 YAML 结构和自己 league 的真实规则从材料看项目没有复杂的前后端它的价值集中在“如何进行结构化表达”。官方没有给出完整的通用引擎更稳妥的判断是把它当成一个范式而不是一个安装即用的 app。下面所有配置都不能保证在所有宿主环境直接运行需要按你实际的 skill 运行器和你的 league 平台做调整。2. 适用场景与使用边界2.1 适合什么场景skill file 最适合的场景有三个。第一个是“预演而非预测”。你可以在真实选秀开始前把联盟的计分规则、每队可上场位置、总轮次和 keepers 写进 skill让它在约束条件下跑几轮看自己在第 3 轮、第 6 轮、第 10 轮分别能拿到什么位置的球员。这种用途比通用 mock 有价值因为它尊重你 league 的 roster slots 和 scoring。第二个是“策略比较”。你可以让 skill 分别模拟“强补 RB”“优先抢 TE”“全部选年轻潜力”等策略输出多套模拟结果对比你的决策边界在哪里。第三个是“规则设计验证”。如果你正在设计一个新 league还没正式开局可以用 skill file 把候选规则先跑一遍看看这套规则下选秀是否会失衡。这比直接在 Excel 里手工推演快很多。2.2 不适合什么场景它不适合做实时交易执行不适合替代真实联盟平台的管理后台。skill 的输出是文本和表格不是自动 pick 工具。如果真有人想把 skill 接到外部平台自动提交选秀操作必须先确认平台是否允许脚本操作并取得 league 成员的明确同意。未经授权自动操作轻则违反平台条款重则影响整个联盟的公平性。2.3 数据与合规边界涉及 fantasy league 数据时必须注意三点。第一联盟成员名、keeper 保留球员、交易明细都可能包含个人信息或平台非公开数据不要随意上传到没有隐私保障的公开环境。第二从平台拉取数据时应使用官方提供的导出或开放接口并控制请求频率不要写绕过访问限制的抓取脚本。第三skill 的模拟结果不等于真实选秀结果更不能把基于模拟的决策包装成稳赚建议。Fantasy 涉及投入成本与竞技对抗任何输出都只能当参考。3. 环境准备与前置条件3.1 运行时环境检查skill file 需要的是一个支持“Agent Skills”或类似机制的宿主。常见结构是宿主客户端会扫描某个skills目录找到里面的SKILL.md并通过 front-matter 描述匹配用户意图。不同宿主对目录名称、加载机制和工具调用权限定义不同所以在开始前先确认三件事。当前客户端是否支持 skills 目录约定支持哪一种。SKILL.md的 front-matter 字段是否需要name、description之外的额外字段。宿主是否允许 skill 执行本地 Python 脚本是否允许访问外部数据源。不需要 GPU也不需要单独的推理服务。普通笔记本只要能跑文本编辑器和目标 Agent 客户端即可。3.2 Python 与依赖本文里的脚本主要是做数据整理不是训练模型。建议环境具备 Python 3.10 以上并安装requests和pyyaml。python -m venv .venv source .venv/bin/activate # Windows 下使用 .venv\Scripts\activate pip install requests pyyaml如果你的宿主不允许执行外部脚本也可以把数据准备环节放到本地完成只把处理好的 YAML/CSV 交给 skill 加载。3.3 推荐目录结构一个最小可运行的 skill file 可以这样组织skills/realer-mock-draft/ ├── SKILL.md ├── league_profile.yaml ├── data/ │ ├── players.csv │ ├── keepers.csv │ └── picks.csv └── scripts/ └── import_league_data.py目录名会直接作为 skill 的标识之一建议用项目名realer-mock-draft便于宿主编排。数据目录放输入脚本目录放只做“读取-转换-输出”的轻量工具。4. SKILL.md 编写与 skill file 结构说明4.1 front-matter 决定模型何时触发SKILL.md的 front-matter 是最容易被忽略但最关键的部分。模型并不是每次都把所有 skill 读一遍而是先读 description判断当前对话是否匹配该 skill。description 必须写清楚触发条件、领域和输入要求。--- name: realer-mock-draft description: 当用户要求基于自己的 fantasy league 规则进行 mock draft、选秀预演、阵容位置策略分析或需要按 league_profile.yaml 里的计分与阵容设置生成模拟选秀结果时使用。不要在缺少 league_profile.yaml 的情况下使用默认球员池做通用 mock。 ---description 里加一句“不要在缺少 league_profile.yaml 的情况下使用通用规则”能显著减少模型在不该触发时胡乱用默认数据。4.2 body 指令要写成执行步骤SKILL.md正文不要写长篇说明要写成模型可以直接执行的步骤式指令。下面是一段可运行的模板。# Realer Mock Draft ## 目标 根据当前仓库中的 league_profile.yaml模拟一次只针对该 league 的 mock draft。 ## 约束 1. 只使用 league_profile.yaml 中存在的球队和经理不新增队伍。 2. roster_slots 是必须被遵守的阵容结构例如 QB/RB/WR/TE/flex。 3. 计分规则按 league_profile.yaml 的 scoring 字段不一致时以 profile 为准。 4. 名单中的 keeper 球员在相应轮次被预先占用不能再被重复选择。 5. 输出时给出每一轮的完整 pick、选择依据和该球员在对应积分规则下的适配度。 ## 执行步骤 1. 读取 league_profile.yaml提取联赛 ID、球队数、轮次数、阵容位置、计分方式。 2. 读取 data/keepers.csv确定已被占用的球员和轮次。 3. 读取 data/players.csv按球员位置和最近表现排序生成候选池。 4. 模拟逐轮选秀记录每个 manager 的已选球员。 5. 输出最终结果表并标注哪些选择是受 keeper 约束影响产生的。 ## 输出格式 使用表格输出每一列依次为轮次、pick 序号、经理、球员、位置、选择依据。这套指令的关键点在于“结构化限制”。模型在生成时容易自由发挥所以必须把“只能从哪些队伍选”“哪些球员已经保留”“阵容位置上限是什么”写清楚。4.3 league_profile.yaml 设计league_profile 是整个 skill 的事实来源。字段设计没有必要一开始就做得很完整但至少要覆盖球队、阵容、轮次、keepers、scoring 五类信息。league_name: Demo League league_id: your_league_id_from_platform platform: your_platform_name scoring: passing_td: 4 passing_yard: 0.04 per yard rushing_td: 6 reception_point: 1 roster_slots: QB: 1 RB: 2 WR: 3 TE: 1 FLEX: 1 K: 1 DEF: 1 BENCH: 6 total_rounds: 12 teams: - manager: Alice - manager: Bob keepers: - manager: Alice player: Player A round: 2这段配置里最重要的是roster_slots和keepers。如果缺这两项skill 和通用 mock 就没有区别。计分方式则影响模型对球员价值的判断特别是在 PPR、half-PPR、0.5 TE premium 这类规则下同一个球员的优先级会完全不同。5. 把 YOUR league 数据变成可加载上下文5.1 手工维护配置如果你的 league 经理人数少规则相对固定手工维护league_profile.yaml足够。推荐第一次只维护当前赛季的设置避免把往年的 roster 变动混进来。配置文件的字段名要尽量稳定不要同时使用TEAM和tm这类同义字段模型解析时容易困惑。5.2 从平台导出 CSV 再转换多数 fantasy 平台都允许导出当前赛季的球员与选秀数据。你可以把导出的 CSV 放到data/再写一个小脚本转换成模型更容易读取的结构。下面是一个通用转换脚本模版真实使用时需要按平台字段名调整。import csv import yaml def load_players_csv(path): players [] with open(path, newline, encodingutf-8) as f: reader csv.DictReader(f) for row in reader: players.append({ name: row.get(player_name) or row.get(name), position: row.get(pos) or row.get(position), team: row.get(team), adp: row.get(adp), projection: row.get(projection), }) return players if __name__ __main__: players load_players_csv(../data/players_raw.csv) safe_players [p for p in players if p[name] and p[position]] with open(../data/players_clean.yaml, w, encodingutf-8) as f: yaml.safe_dump({players: safe_players}, f, allow_unicodeTrue) print(fcleaned {len(safe_players)} players)转换时重点做一件事去掉空行、字段名不一致的行、明显缺失位置的记录。模型看到的数据越干净输出越稳定。5.3 通过公开接口拉数据的注意事项如果你的平台开放官方 API可以把拉取逻辑写进脚本。下面的示例只作为结构参考API_URL和请求头需要替换成你实际使用的平台说明。import requests import yaml API_URL https://example-platform.example/api/v1/league/{league_id} HEADERS {Authorization: Bearer YOUR_ACCESS_TOKEN} def fetch_league(league_id): resp requests.get(API_URL.format(league_idleague_id), headersHEADERS, timeout10) resp.raise_for_status() return resp.json() def to_profile(league_json): profile { league_id: league_json.get(id), teams: league_json.get(teams, []), roster_slots: league_json.get(roster_slots, {}), scoring: league_json.get(scoring, {}), } return profile if __name__ __main__: data fetch_league(12345678) profile to_profile(data) with open(../league_profile.yaml, w, encodingutf-8) as f: yaml.safe_dump(profile, f, allow_unicodeTrue, sort_keysFalse) print(profile updated)这段代码里YOUR_ACCESS_TOKEN是明显的占位符。真实使用时必须把 token 放到环境变量不要提交到 git 仓库。另外请求频率要控制在平台合理范围不要为了批量生成而高频轮询接口。6. 用 SKILL 完成一次“基于本联盟”的 mock draft6.1 触发与启动在支持 skill file 的客户端里你不需要手动指定要加载哪个文件。直接在对话中描述需求即可。推荐采用的触发方式请调用 realer-mock-draft按我 league_profile.yaml 里的规则模拟一次 12 轮 mock draft。假设我从第 5 顺位开始。如果客户端支持也可以在输入中补充“只看前 6 轮”或“请把防守组选秀放到最后三轮”。这类限制条件会覆盖 skill 里的默认输出顺序。6.2 预期执行流程一个正常的执行流程应该包含以下步骤。读取league_profile.yaml确认球队数量。根据roster_slots计算每轮需要的总 pick 数。读取 keepers把保留球员放到指定轮次并标记。从data/players_clean.yaml生成候选池。按蛇形顺序逐轮模拟每选一人检查位置是否达到上限。输出带选秀依据的结果表。6.3 判断成功的标准模拟是否成功不能只看“有没有输出表格”。要检查以下硬性条件。每轮 pick 总数等于联盟球队数。每个经理最终阵容的位置数没有超过roster_slots。每个球员没有被两个经理同时选中。keepers 球员出现在正确轮次且已占用位置后后续选秀不会重复选同一位置超出上限。输出中能看到“为什么选这位球员”的判断依据而不是只给一个名字。满足这些条件skill 才算真正基于你的 league 完成了模拟。7. 批量运行与脚本化策略组合skill 的天然优势是可以反复调用。批量生成多组策略结果时不需要改SKILL.md只要把输入场景参数化即可。7.1 多策略场景文件可以准备一份scenarios.yaml把想比较的策略全部列出来。scenarios: - name: zero_rb description: 前两轮不选 RB优先囤积 WR 和 TE 高分球员 pick_round_bias: { 1: [WR, TE], 2: [WR, TE] } - name: hero_rb description: 第一轮强选顶级 RB第二轮之后开始补 WR pick_round_bias: { 1: [RB] } - name: best_player_available description: 每轮严格按球员总积分优先不用位置策略干预 use_bpa: true模型读到这样的场景配置后会在同一联盟规则下做三次模拟。通过对比同一经理在不同策略下能拿到的阵容比只跑一次更接近真实决策。7.2 调用多次模拟的注意点批量跑的时候最容易出现的问题是“前一次输出污染后一次结果”。模型有时会参照上一轮对话继续生成导致同一位球员出现在多份结果里。建议每次模拟都重新声明“这是新一轮独立模拟不允许引用上一轮结果”或分开多个会话执行。如果 skill 支持脚本执行你也可以写一个简单的循环脚本按场景逐次请求。这里不讨论具体宿主 API只给出伪代码思路。import subprocess scenarios [zero_rb, hero_rb, best_player_available] for scene in scenarios: prompt ( 请开始一次全新的 mock draft不要参考之前对话。 f当前场景{scene}。完成后输出为 Markdown 表格。 ) # 调用宿主 API 或 CLI这里替换为你实际的运行方式 # result client.chat(prompt) print(ffinished {scene})真实接入时你需要把脚本里的client.chat替换成宿主提供的 API 封装。更稳妥的做法是先手动验证单个场景再批量。8. 资源占用与性能观察方法这一类 skill 不消耗 GPU 显存真正的资源瓶颈是大模型推理时间和 token 预算。8.1 token 消耗观察skill 每次被触发模型都需要读取SKILL.md、league_profile.yaml和至少一部分球员数据。联盟越大球员数据文件越大token 消耗越高。建议观察以下指标。资源项观察方式优化方向模型单次输入 token宿主工具或日志查看精简球员字段去掉无用列模型单次输出 token宿主工具查看设置输出格式为简短表格每次模拟耗时从发起请求到返回结果计时减少总轮次、限制候选池外部 API 请求次数日志统计控制拉取频率避免重复全量同步8.2 降低资源消耗的实践第一次测试不要全量灌入几千条球员数据。比如你 league 是 12 队、每队 16 人阵容总需求约为 192 名球员。可以先只保留每个位置前 50 名让 skill 在一个干净的小候选池里完成验证。功能跑通后再扩大数据量。对候选池字段也要做减法。不需要把球员的每一周历史数据都放进去。保留姓名、位置、队伍、近三年平均分、ADP、伤病状态就足够支撑一轮模拟字段过多反而会干扰模型判断。9. 常见问题与排查方法问题现象可能原因排查方式解决方案对话中不触发 skilldescription 描述与用户输入不匹配检查 front-matter 里的触发词把“mock draft”“选秀预演”“fantasy 选秀”加入 description模拟时使用了通用数据未加载 league_profile.yaml查看执行日志确认读了哪个文件把 profile 文件名写死在指令里缺失时报错退出两个经理选中同一球员未做候选池去重检查 players.yaml 中是否存在重复记录选秀前按姓名加位置去重选后记录已选名单keeper 轮次错乱keepers.csv 缺失或 round 字段不对检查 keeper 文件重新整理 keeper 数据让模型先读取该文件位置人数超过 roster_slots每轮后没有校验位置上限检查输出阵容指令里加入“每轮选择后必须校验当前经理位置数量”外部数据拉取失败token 过期或接口地址失效查看脚本异常输出刷新 token确认接口地址与平台文档一致输出结果明显冗长没有限定输出格式查看请求提示词在 SKILL.md 中指定“表格输出不要写长段分析”球员数据涉隐私配置中包含未脱敏成员信息检查 league_profile.yaml用昵称替代真实姓名不在公开仓库保留联盟 ID10. 最佳实践与合规使用建议10.1 目录与版本管理建议把 skill file 放进 git 仓库管理但必须把data/下的原始导出文件或含个人身份信息的版本加入.gitignore。league_profile.yaml如果包含联盟成员真实信息也应该脱敏后再提交。# .gitignore 示例 .venv/ __pycache__/ *.csv data/raw/ .env保留一份脱敏后的 demo profile 作为示例其他真实配置只放在本地环境。10.2 安全与授权提示第一任何需要 token 的脚本都要从环境变量读取密钥。第二不要在公开对话里粘贴带联盟 ID、成员账号的完整数据。第三如果 skill 需要访问第三方平台先阅读该平台的服务条款确认个人用途是否允许 API 访问。第四涉及交易模拟、选秀策略分析时要在结果中标注“模拟不构成真实决策建议”避免读者误解。10.3 从最小案例开始验证建议按“最小可用”顺序推进先用 4 队、3 轮的小规模样例验证 skill 能跑通再加入 keepers再加入完整 scoring最后再接入外部数据平台。这样每一步出现问题时都能快速定位是数据问题还是 skill 指令问题。11. 总结与下一步Realer Mock Draft 这类项目最有价值的地方不是它生成了哪份选秀名单而是它示范了 skill file 应该如何“绑定真实环境”。真正让 mock draft 变得 real 的是把 league 的球队、阵容结构、计分方式、keeper 和队内顺位做成结构化输入强制模型只在约束范围内做选择。这个思路可以平移到你自己的 league也可以推广到其他需要“基于专有上下文做推演”的场景。第一次上手时不要急着写一堆脚本。先把SKILL.md和最小版league_profile.yaml用文本编辑器搭好把规模降到 4 队 3 轮验证它是否真的按你的规则输出。跑通后最值得扩展的是批量场景比较也就是把不同策略参数化通过多次独立模拟找到适合自己 picks 的相对最优路径。最容易踩的坑不是语法问题而是“模型悄悄回退到默认常识”。只要你在指令里把“只使用 profile 中的队伍”、位置上限、keeper 占位轮次这三件事写死这个 skill 就比大多数通用 mock 更接近你的真实 league。