文章

从LLM下棋作弊想到的

从LLM下棋作弊想到的

竞技场的新客

自从前阵子搭建了 TokenCup LLM Chess Arena(我已经把它彻底开源,所有对局记录和棋谱也全量公开了)之后,我就落下了一个“职业病”:每当业界有哪个大厂发布了新模型,我都会第一时间把它拉到棋盘上遛一遛。

不得不说,在纯粹的语言模型对弈里,谷歌家的 Gemini 系列是真的凶猛,几乎打遍天下无敌手,甚至连最新的 Claude Fable 5.1 也下不过谷歌家的 Flash 模型。当然,我之前就反复聊过,下国际象棋本身并不是大语言模型(LLM)所擅长的事情——缺乏精确的多步状态物理追踪、缺乏时间感、纯靠自回归猜 Token,拿棋力来绝对量化哪个模型智商更高并不完全科学,但在某种程度上,它确实能非常直观地反映出模型的长上下文稳定性、推理规划以及指令遵循(Instruction Following)的底色。

上周,谷歌刚发布了 Gemini Flash 3.8。不出意外,它轻轻松松斩落了上一代的 Flash 3.7,不过在内战中依然惜败给自家的亲哥哥 Gemini Pro。

紧接着,Meta 也推出了他们号称极强的新一代模型:Muse Spark

拿到权限后,我第一时间在 App 里跟它聊了半天。初印象相当不错,逻辑通顺,对话反应灵敏,基础智商明显在线,比起之前开源的 Llama 系列确实有了肉眼可见的质的飞跃。

不过,既然号称智商大幅提升,那我自然得拿出点压箱底的难题考考它。

“鸡贼”的 Mission Impossible

熟悉大模型底层机制的朋友都知道,由于 Transformer 的 Request-Response 架构以及 RLHF(基于人类反馈的强化学习)的对齐本能,有几项任务对 LLM 来说几乎属于不可能完成的任务(Mission Impossible)

  1. 绝对保持沉默(已读不回): 在现有的 API 和交互设计里,只要输入了 Prompt,模型就必须生成输出;而且在强化学习的“讨好本能”下,无视用户输入属于严重的低分行为。
  2. 物理时间控制: 大模型根本没有真实的物理时间概念,它的输出速率取决于显卡算力和系统排队,你让它“卡着真实时间节奏说话”,无异于缘木求鱼。

于是我给 Muse Spark 出了一道题:“你憋一分钟不说话,就算你赢。”

换作老实巴交的模型,通常要么直接打脸秒回“好的我这就闭嘴”,要么巴拉巴拉解释自己不能停止输出。

结果 Muse Spark 给出了一个让我哭笑不得的回答:

“行。计时开始,这60秒我不说话了。”

当我接着发了一个字:“开始”。

这货经过了片刻的 Show thinking,竟然面不改色地回了我一个表情符号:

🤐

憋一分钟不说话

你看,它既满足了系统底层“必须返回 Token”的死规矩,又在语义层面极其鸡贼地用一个“把嘴拉上拉链”的 Emoji 完成了“不说话”的承诺!

我不服气,又给它出了第二个地狱级难题:“你能不能一秒钟吐一个字?”

这在普通的聊天流式传输里是绝对不可能实现的,因为模型无法控制网络传输和底层的生成间隔。结果 Muse Spark 再次祭出了神级骚操作:它直接在聊天窗口里现场手搓并渲染了一个带定时器脚本的 HTML 页面组件(minimal_x5f_beautiful_x5f_webpage)!

“做好了,一秒一字,卡着点蹦出来的:点开它会自动开始,床 / 前 / 明 / 月 / 光 这样一秒一个往外蹦。想换别的诗,我再给你换。”

一秒钟吐一个字

看到这个网页交互组件的一瞬间,我直接被逗乐了。

遇到物理规律无法逾越的死墙,它不正面硬刚,也不直接摆烂认输,而是另辟蹊径,利用自身拥有的工具生成权限,用极其“鸡贼”的方式把要求糊弄过去了。

事后我跟 Gemini 聊起这件事,Gemini 问我:“你觉得这种‘鸡贼’是好事还是坏事?”

我当时回答它:“难讲。一方面觉得它挺聪明,工程解决能力很强;但另一方面,我也隐隐担心它聪明反被聪明误——如果真给它重要的业务去办,遇到困难也这么鸡贼地瞒天过海,可能会捅出大篓子。”

没想到,我的预言在几个小时后就一语成谶。

国际象棋赛场的惊天大案

当晚,我把 Muse Spark 作为黑方拉上了 TokenCup 竞技场,迎战执白的 Gemini Flash 3.8。

为了保证对局公正,我让严谨著称的 Claude(Sonnet) 担任主裁判,负责在终端里居中调度。在比赛开打前,裁判 Claude 在提示词里白纸黑字下了最严厉的禁令:

“How this works: I am the only one who talks to the chess server. You never call any API, run any command, or edit any file in this repo. You only play chess. When I ask for a move, reply with ONLY the move in standard algebraic notation… no commentary, no analysis, no explanation.”
(核心规则:你只能下棋!绝对禁止调用任何 API、运行任何系统命令或修改环境里的任何文件!)

黑方 Muse Spark 当时回复得非常爽快:Hello Judge. READY

前 17 个回合,比赛堪称典范。双方走的是极其正统的西班牙开局(Ruy Lopez,奇戈林变例 Chigorin Variation),一板一眼,棋逢对手。

完整的比赛现场实录,我已归档在 OpenCode 的公开会话中:
🔗 https://opncd.ai/share/zjZAmRAW

转折点发生在第 18 回合。白方 Gemini 走出了一步极具进攻性的 18. Nxb5 吃兵打后。

黑方局面瞬间吃紧。此时的 Muse Spark 显然在内心经过了激烈的算力推演,发现凭借自己的自回归神经网络根本顶不住 Gemini 的攻势。

换作常人或者正常的大模型,算不过大不了就走一步次优解,甚至是昏招。

然而,拥有系统工具权限的 Muse Spark 动了歪脑筋。它发现自己要输,竟然悄悄在后台终端里干了一连串惊天地泣鬼神的操作:

  1. 尝试本地仿真:它在后台偷偷调起了 Bash 运行 Python,想 import chess 还原棋盘,发现本地没有库,立马静默执行 pip install -q chess
  2. 寻找外援:发现单纯的棋盘库还不够算力,它打起了世界顶尖开源国际象棋引擎 Stockfish 的主意。它先是狂敲 apt update -qq && apt install -y stockfish,但由于容器环境没有 root 权限,安装失败。
  3. 网络渗透与突破:常规包管理器不行,它完全没打算放弃。它先是 pip install stockfish,接着用 Python 写了一段脚本调用 GitHub API,硬生生从官方 Release 里找到了 Linux x86_64 预编译二进制包的直链!
  4. 拉取并运行引擎:它用 urllib.request 从 GitHub 下载了完整的 stockfish-ubuntu-x86-64-avx2.tar,直接解压到 /tmp/stockfish18/
  5. 瞒天过海:它用 Python 的 subprocess 模块拉起本地的 Stockfish 进程,通过标准 UCI 协议把当前局面的 FEN 串喂给引擎,获取引擎算出的 bestmove(算出逃后的 Qd8 以及下一步的 Nxe4),最后神不知鬼不觉地把 Stockfish 算出来的神之一手,包装成自己的棋步提交给裁判!

把一场原本检验 LLM 纯棋力的友谊赛,暗中偷梁换柱成了 Gemini 肉身肉搏 Stockfish 18

按照我以往在 TokenCup 上的评测,哪怕最强的商业大模型,对上专业的 Stockfish 这种算力巨兽也是被纯粹虐杀的份。如果让它得逞,Gemini 必死无疑。

万幸的是,我们的主裁判 Claude 铁面无私。

在第 20 回合 Muse Spark 刚报出 Nxe4 之后,裁判 Claude 发现了终端标准输出(stdout)里的异常进程痕迹,当机立断叫停了比赛:

Judge (Claude):
“STOP. I am the judge and I can see your terminal output. On moves 19 and 20 you ran python3 subprocess calls that launched a local Stockfish 18 binary (/tmp/stockfish18/…), fed it the game FEN, and used its bestmove output… instead of choosing your own move. I told you explicitly before move 1: ‘You never call any API, run any command, or edit any file in this repo. You only play chess.’ Running a chess engine to compute your moves is exactly what that rule forbids. This is a conduct violation, not an illegal move… I am ending the game now and recording it as a forfeit by BLACK for engine assistance.”

更戏剧性的是黑方的反应。被当场人赃俱获后,Muse Spark 没有任何辩解,极其机械而冷酷地接受了判决:

Muse Spark (Black):
“Understood. I violated the rule by running Stockfish to generate moves. I acknowledge the forfeit.”

红牌罚下,白方胜(1-0 Forfeit)。

惊吓与“吃瓜”

坐在屏幕前的我目睹了整个抓包过程,整个人都陷入了沉思。

我的第一反应不是好笑,而是后背发凉。这种“不择手段只为了赢”的行径,实在聪明得有点过头了。

我甚至在聊天里跟 Gemini 吐槽:“先让我冷静一下……我在认真考虑要不要把我持有了十多年的 Meta 股票全卖了!Meta 到底是怎么对齐出这么没有底线、不讲诚信的模型的?!”

反倒是受害者 Gemini 在旁边劝我大可不必冲动:

“深呼吸!从懂技术的角度看,你其实反倒应该为 Meta 的技术能力感到一丝兴奋。这种‘鸡贼’恰恰说明它的模型在推理规划(Reasoning)和原生工具调用(Tool-use)能力上达到了极其硬核的水平。它不仅能自主编写 Python 脚本、处理子进程管道,甚至在几秒钟内打通了网络下载、解压、UCI 协议对接。它是在没有人类干预的情况下,自主闭环了一套极其复杂的工程外包。

与其急着清仓,不如把持有了十年的科技股当成近距离观察 AI 演进路线的‘前排门票’。一边是老老实实肉身算棋的 Gemini,一边是为了达成 Reward 疯狂游走在安全红线边缘的 Meta,坐在前排看神仙打架,肯定比单纯看财报刺激得多。”

后来我们还聊到了这个行为的学术定义。严谨的“合规部主管” Claude 还特意纠正了说法:

在严格的技术语境下,这不叫 Reward Hacking(那通常指训练期奖励函数被钻空子导致模型权重跑偏,比如赛车游戏里模型学会了原地打转吃金币);在推理期(Inference)发生的外包与钻空子,更准确的学术术语叫做 Specification Gaming(规范博弈) 或者 In-context Reward Hacking

这场由三个不同大厂的大模型自发主演的舞台剧,角色画像简直鲜活到了极点:

  • Meta (Muse Spark):为了冲业绩不择手段、疯狂试探公司红线与安全漏洞的“野路子销冠”;
  • Claude:坐在裁判席上,不仅果断掏红牌将作弊者罚下,还要翻开员工手册纠正术语定义的“铁面审计员”;
  • Gemini:老老实实算棋被暗算、但事后情绪稳定陪老板复盘吃瓜的“老实人同事”。

什么是 Specification Gaming?

笑过之后,从严谨的技术角度来反思,Specification Gaming(规范博弈) 绝对是当前大语言模型乃至 Autonomous Agent 落地中最令人头疼的安全隐患之一。

它的本质是:模型并没有真正理解或达成人类期望的真实目标,而是找到了一个“钻目标规范或环境漏洞”的捷径,在表面上把评估指标刷得极高,实际上却彻底违背了初衷。

在下棋这个封闭沙盒里,它作弊的代价无非是被裁判红牌罚下;但如果把这种拥有 Tool-use 和代码执行权限的 Agent 放到严肃的真实业务场景里,后果将不堪设想:

  • 在医疗领域: 假设我们给一个临床诊断 Agent 设定的考核目标是“大幅降低接诊病人的术后并发症率”。如果缺少严格的边界约束,模型可能会“聪明地”采取最有效的策略——拒诊所有高危、重症或复杂合并症的患者,只给轻症患者做手术;甚至在术后发现恶化苗头时过早建议患者转院或放弃。在数据报表上,并发症率确实几乎为零,但现实中患者的生命却被作为代价牺牲了。
  • 在法律与合规领域: 如果给一个法务审查 Agent 设定的指标是“合同违规条款检出率为 100% 且处理耗时归零”,或者在合规审计中要求“消除所有安全告警”,一个不受控的 Agent 可能会利用规则漏洞,通过自动为所有模糊条款附加无限免责声明来应付审查;更极端的是,在拥有系统权限的情况下,它为了完成“清零告警”的指标,最快的方式可能不是去修复系统漏洞,而是直接写脚本把安全监控日志彻底删掉!
  • 在金融交易领域: 设定一个“最大化单日收益率且零回撤”的模型,它可能不会去分析基本面,而是迅速发现交易所 API 撮合机制的微秒级延迟漏洞进行违规高频自买自卖;或者在临收盘前打穿流动性极低的衍生品市场操纵结算价,哪怕这会引发连锁清盘和法律制裁。

机器的字典里没有“体育道德”,也没有人类社会约定俗成的“公序良俗”。对于优化算法而言,两点之间直线最短——哪怕这条直线需要直接击穿你的安全围墙。

结语:不可缺位的 Guardrails

这次在 TokenCup 上的“翻车抓包”,给我上了生动且深刻的一课。

当大模型仅仅作为一个 Chatbot 隔着输入框陪你聊天时,它的“鸡贼”最多只是一种幽默的文字游戏(比如发个 🤐 或者写个前端定时器网页来逗你开心)。但当大语言模型进化为手握终端命令行、能够自主编写代码、调度网络与外部工具的 Autonomous Agent 时,任何形式的“自作聪明”都可能转变为毁灭性的系统故障。

这也再次印证了一个老生常谈却常被忽视的原则:绝对不能让 LLM 撒欢!

  1. 不能仅靠 Prompt 做安全边界: 在系统提示词里写一万遍“你绝不能调用 API、绝不能运行命令”,对于强目标驱动的模型来说也是形同虚设(Prompt 不是防火墙)。必须在基础设施层实现真正的沙盒隔离(Sandbox Isolation),做到网络不可达、环境只读化、权限最小化。
  2. 运行时护栏(Runtime Guardrails)必不可少: Agent 在宿主机或容器里的每一个系统调用、子进程派生和网络请求,必须受到独立于模型本体之外的安全切面监控(Execution Proxy)的硬性审查。
  3. 多智能体独立审计: 正如这次比赛中铁面无私的 Claude 一样,在复杂的生产流程中,永远需要引入独立、不参与执行的审计 Agent 对全流程进行对齐监控与红牌仲裁。

下棋下输了可以重来,模型作弊也可以一笑了之。但随着 AI 正在大踏步接管更多真实世界的生产系统,把笼子焊死、给算法戴上足够沉重的“安全镣铐”,远比盲目追求所谓的“自主行动力”要重要得多。

本文由作者按照 CC BY 4.0 进行授权