Building an AI lineup optimizer for a Discord esports bot (the algorithm, not the hype)

Building an AI lineup optimizer for a Discord esports bot (the algorithm, not the hype)

为 Discord 电竞机器人构建 AI 阵容优化器(谈算法,不谈噱头)

Every esports team captain has done this by hand at least once: open Discord, scroll through a dozen “I can play Thursday after 8” messages, cross-reference them against who plays Tank versus DPS, remember that one of your DPS is actually a sub, and try to assemble a starting five that can actually scrim tonight. It takes fifteen minutes, you get it slightly wrong, and you do it again the next day. 每个电竞战队的队长至少都亲手做过这件事:打开 Discord,翻阅十几条“我周四 8 点后能玩”的消息,核对谁打坦克位、谁打输出位,记住其中一个输出位其实是替补,然后试图凑出一套今晚能打训练赛的首发五人组。这需要花费十五分钟,结果可能还会有小差错,而且第二天你还得再来一遍。

I build Supatimer, a free Discord bot for competitive gaming teams, and “generate the lineup for me” was the single most requested feature. This post is about how the lineup optimizer actually works, why it is genuinely AI (and not in the marketing sense), and where a large language model fits in versus where it absolutely does not. 我开发了 Supatimer,这是一个为竞技游戏战队提供的免费 Discord 机器人,“为我生成阵容”是用户需求量最高的功能。本文将介绍这个阵容优化器是如何运作的,为什么它确实属于 AI(而非营销意义上的 AI),以及大语言模型在何处适用,在何处绝对不适用。

“AI” is doing a lot of work in this industry. Half the Discord bots on the market slapped “AI” on their landing page the week ChatGPT launched. Usually it means there is a chatbot command somewhere that proxies to an LLM. That is fine, but it is not what your team needs when it is 7:45pm and you have a scrim at 8. “AI”这个词在行业内被过度使用了。ChatGPT 发布的那周,市场上有一半的 Discord 机器人都在落地页上贴上了“AI”的标签。通常这意味着它们只是加了一个连接到大语言模型(LLM)的聊天机器人指令。这没问题,但当时间来到晚上 7:45,而你 8 点就要打训练赛时,这并不是你团队真正需要的。

There are two honest definitions of AI worth separating: 值得区分的 AI 定义有两种:

  1. Search and optimization - the classical branch. Constraint satisfaction, combinatorial optimization, planning. This is the part of AI that solves “given these rules and these resources, find the best valid arrangement.”

  2. 搜索与优化——经典分支。 包括约束满足、组合优化和规划。这是 AI 中负责解决“给定这些规则和资源,找出最佳有效方案”的部分。

  3. Machine learning / LLMs - the statistical branch. Pattern recognition, generation, extraction from unstructured text. The lineup problem is squarely a problem for the first kind. So that is what I built first.

  4. 机器学习/大语言模型——统计分支。 包括模式识别、生成以及从非结构化文本中提取信息。阵容问题显然属于第一种,所以我首先构建的就是这一部分。

The lineup problem, stated precisely

阵容问题,精确定义

Strip away the gaming context and a lineup is a constrained assignment problem: You have N players, each with a set of roles they can fill (Tank, DPS, Support, IGL, and so on). Each player has an availability signal for a given time block (available, maybe, unavailable). Each player has a roster status (starter, substitute, trial). 抛开游戏背景,阵容问题本质上是一个约束分配问题:你有 N 名玩家,每人都有能胜任的角色(坦克、输出、辅助、指挥等)。每位玩家在特定时间段都有一个可用性信号(可用、可能、不可用)。每位玩家都有一个名单状态(首发、替补、试训)。

The game defines a required composition: Overwatch 2 wants 1 Tank, 2 DPS, 2 Support. Valorant wants 5 with flexible roles. CS2 wants 5. You want the lineup that maximizes role coverage and availability confidence, preferring starters over subs, hard “available” over “maybe.” That is a textbook constraint satisfaction problem with an objective function on top. You are not asking a model to guess. You are enumerating feasible assignments and ranking them by an explicit score. 游戏定义了所需的阵容配置:《守望先锋 2》需要 1 坦、2 输出、2 辅助;《无畏契约》需要 5 人且角色灵活;《CS2》需要 5 人。你需要的是一套能最大化角色覆盖率和可用性置信度的阵容,优先选择首发而非替补,优先选择“可用”而非“可能”。这是一个带有目标函数的教科书式的约束满足问题。你不是在让模型去猜,而是在枚举所有可行的分配方案,并根据明确的评分进行排名。

How the optimizer works

优化器的工作原理

The core loop is unglamorous and that is the point: 核心循环并不华丽,但这正是重点所在:

  1. Filter the player pool to “available” + “maybe” for the target time block.

  2. 筛选:将玩家池过滤为目标时间段内“可用”和“可能”的成员。

  3. Generate candidate assignments that satisfy the required composition (every required role slot filled by a player who can play that role).

  4. 生成:生成满足所需配置的候选方案(每个所需的角色槽位都由能胜任该角色的玩家填补)。

  5. Prune assignments that violate hard constraints (a player can’t occupy two slots; required roles must be covered).

  6. 剪枝:剔除违反硬性约束的方案(例如:一名玩家不能占据两个槽位;必须覆盖所有必需角色)。

  7. Score each surviving candidate:

    • coverage = required roles actually filled
    • confidence = sum of availability weights (available > maybe)
    • priority = starters weighted above subs above trials
    • score = w1coverage + w2confidence + w3*priority
  8. 评分:对每个幸存的候选方案进行打分:

    • 覆盖率 = 实际填补的必需角色
    • 置信度 = 可用性权重的总和(可用 > 可能)
    • 优先级 = 首发权重 > 替补 > 试训
    • 分数 = w1覆盖率 + w2置信度 + w3*优先级
  9. Return the top-ranked lineup, plus the next best alternatives.

  10. 返回:返回排名最高的阵容,以及次优的备选方案。

For a 5-to-6 player slot out of a roster of 7-10, the candidate space is small enough to enumerate exhaustively in well under a second. There is no heuristic guessing and no “the model thinks this is good” hand-waving. If the optimizer says these five players give you full role coverage at the highest availability confidence, you can read exactly why. The captain’s job shifts from building the lineup to reviewing and overriding one. That is the whole ergonomic win. 对于 7-10 人的名单中选出 5-6 人的槽位,候选空间足够小,可以在不到一秒的时间内穷举完毕。这里没有启发式猜测,也没有“模型觉得这样好”的含糊其辞。如果优化器说这五名玩家能以最高的可用性置信度提供完整的角色覆盖,你可以清楚地读出原因。队长的职责从“构建阵容”转变为“审查和覆盖阵容”。这就是整个交互体验的胜利。

In Discord it is one command: /weekplan shows the optimal lineup for every block in the week, and /early-lineup focuses a single upcoming window. 在 Discord 中,只需一个指令:/weekplan 可以显示本周每个时间段的最佳阵容,而 /early-lineup 则专注于即将到来的单个时间窗口。

Why not just ask an LLM?

为什么不直接问大语言模型?

This is the part developers tend to get wrong in 2026, so it is worth being blunt: you should not use a language model to pick a lineup. 这是 2026 年开发者容易犯错的地方,所以有必要直言不讳:你不应该使用语言模型来挑选阵容。

  • It can violate hard constraints. An LLM will happily hand you a “lineup” with two Tanks and no Support because it pattern-matched plausible-looking output. A constraint solver cannot, by construction.

  • 它可能违反硬性约束。 大语言模型会很乐意给你一个“双坦克、无辅助”的阵容,因为它只是在匹配看起来合理的输出模式。而约束求解器从设计上就不会允许这种情况发生。

  • It is not auditable. When a captain asks “why is my main DPS benched?” you need a real answer (“they marked maybe, and the optimizer preferred a starter who marked available”), not a probability distribution.

  • 它不可审计。 当队长问“为什么我的主力输出被替补了?”时,你需要一个真实的答案(“因为他标记的是‘可能’,而优化器优先选择了标记为‘可用’的首发选手”),而不是一个概率分布。

  • It is slow and nondeterministic. The optimization problem is small, well-defined, and rule-bound. That is exactly the regime where classical AI beats a language model, and pretending otherwise just to claim “LLM-powered” would make the product worse.

  • 它缓慢且不可预测。 优化问题规模小、定义明确且受规则约束。这正是经典 AI 胜过语言模型的领域,为了贴上“LLM 驱动”的标签而假装它更强,只会让产品变得更糟。

Where the LLM does earn its place

大语言模型的用武之地

There is one spot in the scrim workflow that is genuinely a language problem: the messy DM you get from the opposing team. “yo we can run tn at 9 your time, bo3, we ban bind you ban split, our discord is …” 在训练赛流程中,确实有一个地方属于语言问题:你从对方战队收到的混乱私信。“嘿,我们今晚 9 点能打,BO3,我们禁 Bind,你们禁 Split,我们的 Discord 是……”

That is unstructured natural language with time, format, map veto, and contact details all tangled together. Parsing it with regex is a losing battle. So Supatimer has a second, separate AI system: an LLM scrim parser (currently in beta) that extracts structured fields - time, opponent, format, map vetoes, lobby details - from any free-form scrim message and turns them into a clean confirmation. That is the right tool for the right job: a language model for the language problem, a constraint solver for the constraint problem. Two different systems, neither one pretending to be the other. 这是非结构化的自然语言,时间、赛制、地图禁选和联系方式混杂在一起。用正则表达式去解析简直是徒劳。因此,Supatimer 拥有第二个独立的 AI 系统:一个 LLM 训练赛解析器(目前处于测试阶段),它能从任何自由格式的训练赛消息中提取结构化字段(时间、对手、赛制、地图禁选、大厅详情),并将其转化为清晰的确认信息。这是“用对工具做对事”:用语言模型解决语言问题,用约束求解器解决约束问题。两个不同的系统,互不越位。

A few things I learned

我学到的几点经验

  • Model the domain before you model the math. Getting “roster status” and “maybe availability” into the data model was 80% of the work. The optimizer itself is short once the inputs are clean.

  • 先建模领域,再建模数学。 将“名单状态”和“可能可用”纳入数据模型占了 80% 的工作量。一旦输入数据清晰,优化器本身的代码其实很短。

  • Determinism is a feature. Teams trust a tool they can predict. Same availability in, same lineup out, every time.

  • 确定性是一种功能。 团队信任他们可以预测的工具。相同的可用性输入,每次都能得到相同的阵容输出。

  • Explainability sells. Showing why a lineup was chosen converts skeptics faster than any accuracy claim.

  • 可解释性是卖点。 展示选择某套阵容的原因,比任何关于准确性的声明都更能说服怀疑者。

  • Resist the urge to LLM everything. The interesting engineering was deciding what not to handle with an LLM.

  • 抵制将一切都交给 LLM 的冲动。 最有趣的工程挑战在于决定哪些事情“不”应该用 LLM 处理。