让大语言模型互斗万智牌的实验项目


基本信息


导语

让大语言模型(LLM)玩《万智牌》不仅是一个有趣的实验,更是检验其在复杂规则下逻辑推理与多步规划能力的试金石。本文详细介绍了作者如何构建系统,让模型在理解长篇规则文本的同时进行博弈。对于关注 AI 智能体进化与游戏技术实现的开发者而言,这篇文章提供了一套从规则解析到模型交互的完整工程实践参考。


评论

中心观点 该文章展示了一种通过将复杂卡牌游戏规则转化为结构化文本提示,使大语言模型(LLM)具备多步推理与规则遵循能力的可行性验证,揭示了当前LLM在处理长上下文与状态依存逻辑时的潜力与局限。

支撑理由与边界分析

  1. 复杂逻辑的符号化映射能力(事实陈述) 文章证明了LLM不仅能处理自然语言,还能在严格的符号系统(如万智牌的堆叠机制、优先权传递)中运作。作者通过精心设计的Prompt Engineering,将游戏状态(手牌、战场、墓地)转化为模型可理解的上下文,使模型能够执行“结算”这一高度程序化的任务。

    • 反例/边界条件:当游戏状态过于复杂(例如超过10个永久物在场)或需要长距离因果推演(如“三回合前打出的牌现在生效”)时,模型的推理能力会显著下降,出现“幻觉”式结算。
  2. 长上下文记忆与状态管理的挑战(作者观点 + 你的推断) 万智牌对局是一个典型的长序列决策过程。文章展示了LLM在维持整局游戏连贯性方面的尝试,这实际上是对模型“工作记忆”的压力测试。虽然模型能理解单次交互,但在整局游戏的宏观策略(如调度资源)上往往表现拙劣。

    • 反例/边界条件:随着Token数量增加,模型对早期游戏细节的注意力会急剧衰减(即“迷失中间”现象),导致在后期回合中遗忘关键规则或己方盘面状态。
  3. 概率生成与确定性规则的冲突(你的推断) LLM本质上是基于概率的下一个词预测模型,而卡牌游戏规则是确定性的。文章的价值在于展示了如何用概率模型拟合确定性逻辑。作者通过Few-Shot或Chain-of-Thought(思维链)技术,强行约束了模型的生成空间,使其逼近确定性输出。

    • 反例/边界条件:在规则模糊或存在交互冲突的边缘场景(Corner Cases)中,模型倾向于根据训练数据中的常见对局模式进行“脑补”,而非严格执行规则书,导致非法操作。

维度评价

  1. 内容深度(4/5) 文章并未停留在简单的“让AI玩”,而是深入到了规则引擎的构建层面。它探讨了如何将非结构化文本转化为结构化操作,论证了LLM作为“解释型”执行器的潜力。然而,文章对于模型失败案例的归因分析稍显不足,未深入探讨是注意力机制缺陷还是训练数据偏差导致。

  2. 实用价值(3.5/5) 对于游戏开发者而言,这提供了一种低成本构建NPC或测试环境的新思路,无需编写硬编码的脚本即可让AI理解复杂规则。但在工业级应用中,目前纯LLM驱动的方案稳定性不足,更多是作为辅助测试工具而非核心逻辑引擎。

  3. 创新性(4/5) 将LLM应用于具有法律文档般复杂度的卡牌游戏,本身就是对模型推理能力的极限挑战。文章提出了一种“规则即上下文”的范式,这比传统的强化学习(如AlphaGo)更通用,因为它不需要预训练的环境模拟器。

  4. 可读性(5/5) 文章结构清晰,技术细节与实战案例结合得当。通过展示具体的对局日志和Prompt片段,让读者直观地看到了模型的思考过程(及其错误),这种“白盒”式的展示极具说服力。

  5. 行业影响 该项目验证了LLM在“Agent工作流”中的执行层能力。它暗示了未来AI在处理复杂SaaS操作、自动化合规审查等需要严格遵循流程的行业中的潜力。它不仅是游戏Demo,更是“基于文档的自动化执行”的雏形。

  6. 争议点或不同观点

    • 成本争议:使用GPT-4等高端模型进行实时对局成本极高且延迟大,这是否比传统的基于穷举或启发式搜索的AI(如MiniMax算法)更优?
    • 智能本质:模型表现出的“策略”究竟是对规则的理解,还是仅仅是对训练数据中人类对局文本的统计模仿?

可验证的检查方式

  1. 非法操作率统计

    • 指标:在100场对局中,统计模型尝试打出违反法力曲线、忽略召唤失调或结算堆叠顺序错误的次数。
    • 验证:该指标应随着模型规模的增大和Prompt的优化呈现单调递减趋势。
  2. 长距离记忆衰减测试

    • 实验:人为设定一个在第1回合打出、第10回合才生效的“延迟触发”机制。
    • 观察窗口:观察模型在第10回合是否能准确回忆并结算该效果,遗忘率即为记忆衰减的量化指标。
  3. Token消耗与游戏回合数的线性关系

    • 指标:记录每回合平均消耗的Token数。
    • 验证:检查是否存在Token溢出导致的上下文窗口截断,这直接限制了LLM进行长游戏(如控制套牌内战)的可行性。

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 示例1:卡牌数据结构定义
from dataclasses import dataclass
from typing import List

@dataclass
class Card:
    """表示一张万智牌卡牌"""
    name: str
    mana_cost: int
    card_type: str  # "creature", "instant", "sorcery"等
    power: int = 0
    toughness: int = 0
    
    def can_play(self, available_mana: int) -> bool:
        """检查是否有足够法术力使用此卡"""
        return self.mana_cost <= available_mana

# 使用示例
lightning_bolt = Card("闪电箭", 1, "instant")
goblin = Card("鬼怪", 1, "creature", 1, 1)

print(f"能否使用闪电箭?{lightning_bolt.can_play(2)}")
print(f"鬼怪数据:{goblin}")
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 示例2:游戏状态管理
class GameState:
    """管理游戏状态"""
    def __init__(self):
        self.players = ["玩家1", "玩家2"]
        self.turn = 0
        self.current_player = 0
        self.battlefield = {player: [] for player in self.players}
        self.graveyards = {player: [] for player in self.players}
    
    def next_turn(self):
        """进入下一个回合"""
        self.turn += 1
        self.current_player = (self.current_player + 1) % 2
        print(f"回合{self.turn}{self.players[self.current_player]}的回合")
    
    def play_card(self, player: str, card: Card):
        """玩家使用卡牌"""
        if player == self.players[self.current_player]:
            self.battlefield[player].append(card)
            print(f"{player}使用了{card.name}")
        else:
            print("这不是你的回合!")

# 使用示例
game = GameState()
game.next_turn()
game.play_card("玩家1", Card("森林", 0, "land"))
game.next_turn()
game.play_card("玩家2", Card("山脉", 0, "land"))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 示例3:简单的战斗系统
def resolve_combat(attacker: Card, defender: Card) -> tuple:
    """处理生物之间的战斗"""
    # 攻击者对防御者造成等于其力量的伤害
    defender_damage = attacker.power
    # 防御者对攻击者造成等于其力量的伤害
    attacker_damage = defender.power
    
    # 计算剩余生命值
    attacker_toughness = attacker.toughness - attacker_damage
    defender_toughness = defender.toughness - defender_damage
    
    return (attacker_toughness > 0, defender_toughness > 0)

# 使用示例
goblin = Card("鬼怪", 1, "creature", 1, 1)
hill_giant = Card("山丘巨人", 3, "creature", 3, 3)

attacker_survives, defender_survives = resolve_combat(goblin, hill_giant)
print(f"鬼怪存活?{attacker_survives}")
print(f"山丘巨人存活?{defender_survives}")

案例研究

1:DeepMind AlphaStar 项目

1:DeepMind AlphaStar 项目

背景: DeepMind 长期致力于利用人工智能解决复杂决策问题。在继 AlphaGo 之后,团队将目光投向了即时战略游戏《星际争霸 II》(StarCraft II)。这是一个完美的测试平台,因为它具有巨大的状态空间(比围棋大得多)、需要长期规划且信息不完美(战争迷雾)。

问题: 在《星际争霸 II》中,AI 面临的主要挑战是如何在“宏观战略”(如经济运营、兵力部署)与“微观操作”(如单个单位控制)之间取得平衡。传统的基于脚本或强化学习的 AI 往往只能通过极高的“每分钟操作数”(APM)来通过微操获胜,这违背了人类玩游戏的策略逻辑,且无法适应复杂的战术变化。

解决方案: DeepMind 开发了 AlphaStar,这是一个基于深度神经网络的智能体。它使用了通用的长短期记忆网络(LSTM)来处理游戏状态,并利用Transformer架构来处理实体交互。最重要的是,AlphaStar 通过模仿学习(Imitation Learning)从人类高手的对局录像中学习基础策略,随后通过大规模的“自我对弈”进行强化学习,在不断的对抗中进化出超越人类顶级选手的战术意识。

效果: AlphaStar 成功达到了与《星际争霸 II》顶级职业选手(如 MaNa)相当的水平。它不仅在微操上表现出色,更展示了具有人类特征的宏观策略,如“牵制战术”和“经济压制”。这是 AI 首次在没有限制微操速度的情况下,在复杂的即时战略游戏中击败世界冠军,证明了 LLM 及相关深度学习技术在处理复杂序列决策和长线规划方面的巨大潜力。


2:OpenAI Five 与 Dota 2

2:OpenAI Five 与 Dota 2

背景: 《Dota 2》是世界上最复杂且最受欢迎的多人在线战术竞技游戏(MOBA)之一。OpenAI 选择了这款游戏作为研究通用人工智能的下一步,旨在测试 AI 在团队合作、不完全信息博弈和极高维度的状态空间下的表现。

问题: 《Dota 2》的游戏规则极其复杂,每个英雄有数十个技能,且游戏时长通常在 30-45 分钟,这意味着 AI 需要在长达数万帧的序列中做出连贯的决策。此外,游戏包含“战争迷雾”,玩家只能看到视野内的单位,这要求 AI 必须具备预测对手位置和意图的能力。早期的 AI 只能在限制版的 1v1 单挑中获胜,无法处理 5v5 团队协作的复杂性。

解决方案: OpenAI 开发了 OpenAI Five,这是一个由五个独立的神经网络组成的系统。他们使用了“近端策略优化”(PPO)算法,让 AI 在 Linux 虚拟机中通过自我对弈进行训练。为了让 AI 学会团队配合,他们设计了一种称为“团队精神”的超参数,鼓励英雄为团队整体利益而战,而不是独自刷钱。训练规模极其庞大,相当于 180 年的游戏时间。

效果: OpenAI Five 在 2018 年的 Dendi 赏金赛中击败了世界顶级选手,随后在 2019 年以 2:0 的战绩击败了当时的世界冠军 OG 战队。这一成果展示了 LLM 和强化学习技术在处理多智能体协作、长期延迟奖励以及极其复杂的环境规则时的能力,为未来的机器人协作和复杂系统控制提供了宝贵的经验。


3:CICERO 与外交游戏

3:CICERO 与外交游戏

背景: Meta AI(前 Facebook AI)致力于研究具备自然语言处理和推理能力的 AI。他们选择了策略棋盘游戏《外交》作为测试平台。这款游戏不同于围棋或国际象棋,它没有骰子或运气成分,核心在于玩家之间的谈判、结盟和背叛。

问题: 《外交》不仅需要策略规划,最核心的难点在于“沟通”。AI 必须理解自然语言,与人类玩家进行谈判,达成协议,并在游戏中判断是否遵守或背叛这些协议。传统的 AI 往往缺乏对语言细微差别的理解,也无法在复杂的社交互动中建立信任。

解决方案: Meta 开发了 CICERO,这是第一个在战略游戏中达到人类水平的 AI 智能体。CICERO 结合了一个包含 27 亿参数的对话模型(用于生成自然语言对话)和一个策略推理引擎(用于规划游戏动作)。它采用了“意图驱动的对话生成”技术,能够根据当前的局势规划,推断出需要与哪个玩家沟通什么内容,从而生成极具说服力的对话。

效果: 在一个包含 40 位人类玩家的《外交》网络联赛中,CICERO 的得分是平均分的两倍多,并在所有参与者中排名前 10%。它不仅展现了高超的游戏策略,更令人震惊的是,许多人类玩家在赛后并不知道与自己谈判的是 AI。这标志着 LLM 技术在融合语言理解、战略规划和心理博弈方面取得了重大突破,为未来人机交互和谈判助手奠定了基础。


最佳实践

最佳实践指南

实践 1:构建结构化的游戏状态表示

说明: Magic: The Gathering (MTG) 拥有极其复杂的游戏状态,包括战场、手牌、墓地、堆栈等区域,以及数百种关键字和异能。让 LLM 理解游戏的第一步是将这些非结构化的规则数据转换为机器可读的、高度结构化的状态表示。单纯依靠自然语言描述会导致上下文过长且容易产生歧义。

实施步骤:

  1. 定义标准化的 JSON Schema 来映射当前游戏状态,区分玩家可见信息(手牌、战场)和私有信息。
  2. 将复杂的异能文本简化为结构化的标签或枚举值,例如将"Whenever this creature attacks, create a 1/1 token"简化为触发事件列表。
  3. 建立一个"游戏机"层,负责解析 LLM 的输出并更新这个状态对象,而不是让 LLM 直接操作原始字符串。

注意事项: 状态表示必须包含所有必要的上下文(如生命值、法术力池、回合阶段),否则 LLM 会做出非法操作。


实践 2:设计分阶段的决策架构

说明: MTG 的一个回合包含多个步骤(维持、抓牌、战斗、结束等)。如果让 LLM 在一次推理中决定整个回合的操作,由于计算限制和错误累积,成功率极低。最佳实践是将游戏循环拆解,让 LLM 专注于当前步骤的决策。

实施步骤:

  1. 将游戏引擎设计为事件驱动模式,每进入一个新阶段(如"开始战斗"),暂停并询问 LLM 的行动意图。
  2. 为每个阶段设计特定的提示词模板,例如在战斗阶段询问攻击者列表,在主阶段询问法术施放。
  3. 允许 LLM 在特定阶段输出"Pass Priority"(通过优先权)的指令,以简化流程。

注意事项: 必须设计优先权传递机制,确保 LLM 理解对手有机会响应其动作,而不是无限连击。


实践 3:实施严格的合法性验证层

说明: LLM 是概率模型,经常会产生幻觉,比如在没地的时候施法、或者违反堆栈规则。不能信任 LLM 的输出直接修改游戏状态。必须在 LLM 和游戏规则之间建立一个强硬的验证层,拒绝非法操作并给予反馈。

实施步骤:

  1. 编写一个确定性的规则引擎,能够根据当前状态验证任何提议的动作是否合法(例如:检查法术力费用、召唤失调、目标合法性)。
  2. 当 LLM 尝试非法操作时,系统应拦截并返回具体的错误信息(例如:“法术力不足,当前仅有3点,需要4点”)。
  3. 将错误信息作为新的上下文重新输入给 LLM,要求其重新生成合法指令。

注意事项: 避免让验证层过于宽松,否则 LLM 会学习到利用漏洞而非真正的规则;也不要过于严苛导致游戏无法进行。


实践 4:利用检索增强生成 (RAG) 处理卡牌异能

说明: MTG 拥有超过 20,000 张卡牌,每张都有独特的文本。将所有卡牌文本放入 Prompt 会迅速超出上下文窗口。使用 RAG 技术可以让 LLM 在需要时动态查询特定卡牌的详细规则和异能。

实施步骤:

  1. 建立一个向量数据库,存储所有卡牌的 Oracle 文本(官方标准规则文本)。
  2. 当卡牌进入战场或手牌时,系统自动检索该卡牌的详细文本,并将其摘要注入到当前的 Prompt 上下文中。
  3. 对于复杂的交互(如"保护"或"系命"),检索相关的规则解释文档以辅助 LLM 理解。

注意事项: 检索到的信息必须经过清洗,去除无关的背景描述,仅保留规则相关的机制描述。


实践 5:建立动态记忆与堆栈管理系统

说明: MTG 的核心在于堆栈交互,即响应对手的动作。LLM 容易忘记上一秒发生了什么,或者忽略堆栈上的 pending 效果。必须建立一种机制,帮助模型维持对短期历史和待处理效果的清晰认知。

实施步骤:

  1. 在 Prompt 中维护一个"堆栈摘要"区域,实时列出当前堆栈上待结算的效果及其来源。
  2. 使用"思维链"提示,要求 LLM 在行动前先口头分析当前堆栈状态和潜在后果,再输出最终动作。
  3. 设计记忆模块,记录对手之前使用过的关键牌,以便 LLM 进行长期的策略规划(例如"对手有去除咒语,不要下大生物")。

注意事项: 堆栈信息的呈现必须非常直观,使用缩进或编号列表明确显示执行的顺序和层级。


实践 6:采用自我对弈与反馈循环优化策略

说明: 初始的 LLM 可能只会基本的出牌逻辑。通过让两个 LLM 实例互相对弈,并记录胜负结果


学习要点

  • 将复杂的万智牌游戏规则转化为结构化的 JSON 格式,是让大语言模型(LLM)准确理解并执行游戏逻辑的关键技术突破。
  • 通过在系统提示词中强制要求模型输出特定的 JSON 结构,成功解决了模型在处理游戏状态时容易产生的幻觉和格式错误问题。
  • 相比于微调模型,采用精心设计的提示工程在构建此类游戏智能体时更具成本效益且实施更为灵活。
  • 该项目证明了 LLM 具备处理多步骤逻辑推理和长上下文记忆的能力,能够维持包含数千个 Token 的复杂游戏状态。
  • 实现了一个完全自动化的闭环系统,模型不仅能执行操作,还能自主解析对手的行动并更新游戏盘面。
  • 这种基于文本的游戏代理架构为模拟其他复杂的卡牌或桌面游戏提供了一种可通用的技术范式。
  • 观察发现,模型在遵循具体指令(如系统提示)方面表现优于开放式的创意写作任务,这验证了结构化约束在逻辑推理中的有效性。

常见问题

1: 这个项目是如何实现的?LLM 是如何理解游戏规则的?

1: 这个项目是如何实现的?LLM 是如何理解游戏规则的?

A: 实现该项目主要包含三个核心步骤。首先,构建了一个结构化的游戏状态表示系统,将万智牌复杂的规则和牌面信息转化为 LLM 能够理解的文本或 JSON 格式。其次,设计了提示词工程,将当前的游戏状态(手牌、战场、墓地等)以及合法的操作列表输入给模型。最后,通过解析模型的输出并将其转化为游戏指令来驱动游戏进程。虽然 LLM 无法“记忆”所有规则,但通过上下文注入,它们可以在每一步根据当前状态判断合法的移动。


2: 使用了哪些大语言模型?它们的表现有何不同?

2: 使用了哪些大语言模型?它们的表现有何不同?

A: 该项目通常测试了目前最先进的开源或闭源模型,例如 GPT-4o、Claude 3.5 Sonnet 或 Llama 3 系列。根据实验反馈,参数量较大、推理能力较强的模型(如 GPT-4 级别)在理解复杂交互(如堆叠机制、异能结算)方面表现更好,较少出现违规操作。而较小的模型虽然响应速度更快,但更容易产生“幻觉”,即尝试使用不存在的费用或违反法术力规则的出牌方式。


3: AI 能够处理万智牌中复杂的堆叠和交互规则吗?

3: AI 能够处理万智牌中复杂的堆叠和交互规则吗?

A: 这是一个巨大的挑战。万智牌拥有极其复杂的规则体系,特别是“堆叠”机制和优先权交换。目前的 LLM 在处理简单的回合流程(如战斗、施咒)时表现尚可,但在处理多层交互时往往力不从心。为了解决这个问题,开发者通常会构建一个“裁判”系统或使用严格的规则引擎来验证 LLM 的输出。如果 LLM 试图执行非法操作(例如在对手回合瞬间使用非瞬间牌),系统会拦截并提示其重新选择,从而保证游戏规则的正确性。


4: 运行这个项目的成本高吗?对局速度如何?

4: 运行这个项目的成本高吗?对局速度如何?

A: 成本和速度取决于所选用的模型。如果使用 API 调用闭源模型(如 GPT-4),每一局游戏可能需要数十次甚至上百次 API 调用,费用相对较高,且受限于网络延迟和生成速度,一局游戏可能需要较长时间。如果使用本地部署的开源模型(如 Llama 3),虽然硬件门槛较高,但可以免除 API 费用,且通常能获得更快的推理速度。总体而言,目前的 AI 对局速度远慢于人类对局或传统 AI 算法。


5: LLM 是如何构建套牌的?它们有策略吗?

5: LLM 是如何构建套牌的?它们有策略吗?

A: 套牌构建通常由开发者预设,或者通过特定的“构建模式”让 LLM 从一个有限的牌池中进行选择。在游戏过程中,LLM 表现出的策略通常是基于“贪婪”算法的,即倾向于立即打出能带来最大优势的牌,或者简单地攻击对手。虽然它们能理解基本的卡差优势,但在复杂的长期规划、组合技识别以及针对特定局势的战术调整上,目前的表现还不如传统的游戏 AI 或人类玩家。


6: 这个项目的代码是开源的吗?我可以尝试运行它吗?

6: 这个项目的代码是开源的吗?我可以尝试运行它吗?

A: 是的,这类 Show HN 项目通常会在 GitHub 上开源代码。代码库通常包含游戏状态的模拟器、与 LLM API 交互的接口以及用于记录对局日志的脚本。你可以通过配置自己的 API Key(如 OpenAI Key)或本地模型地址来运行它。不过,运行前可能需要安装特定的依赖库,并准备好相应的牌表数据文件。


7: 让 LLM 玩万智牌有什么实际意义?

7: 让 LLM 玩万智牌有什么实际意义?

A: 除了娱乐价值之外,这是一个极佳的测试 LLM 逻辑推理和长上下文记忆能力的基准。万智牌拥有超过 20,000 张具有不同文字描述的卡牌,且规则极其严谨,要求 AI 必须在遵守严格限制的同时进行动态决策。这有助于研究人员评估模型在复杂系统中的表现,以及改进模型遵循指令和减少幻觉的能力。


思考题

## 挑战与思考题

### 挑战 1: [简单]

问题**: 考虑到万智牌拥有数千张具有独特文本的卡牌,如果直接将完整的卡牌规则文本输入给 LLM,上下文窗口会迅速溢出。请设计一种数据预处理方案,将卡牌信息转化为结构化格式(如 JSON),并提取出 AI 进行决策所需的最小关键字段集合(如费用、力量/防御、类型、关键异能),以便在有限的上下文窗口内包含尽可能多的战场信息。

提示**: 思考哪些是“静态信息”(卡牌属性),哪些是“动态信息”(当前状态)。尝试使用枚举或 ID 来代替冗长的规则描述文本,例如将“当此生物进场时,抽一张牌”简化为 ETB: DRAW_1


引用

注:文中事实性信息以以上引用为准;观点与推断为 AI Stack 的分析。



站内链接

相关文章