土耳其机械人; 图片来源: https://commons.wikimedia.org/wiki/File:Racknitz_-_The_Turk_1.jpg (公共领域作品)
这是啥?上周,谷歌发布了 Gemini 2.5 Pro。它在各项基准测试中表现出色,据说特别擅长编码和逻辑推理。那么,没有什么比用它来开发一个象棋应用,并用这个应用与AI对战更好的方法来验证这些说法了。
在这篇博客里,我将分享使用Gemini 2.5 Pro制作一个国际象棋应用的过程。虽然可以把它作为代码助手集成到IDE里,但我主要使用Google的AI Studio来完成这个项目以展示其简便。核心想法是制作一个可以使用的国际象棋应用,让人类用户可以和这个模型对战。
我已经把这个应用程序上传到这个链接了:https://github.com/heiko-hotz/gemini-chess
为什么我们应该在意?自它们诞生以来,大型语言模型(LLMs)就被应用于编码任务。这早已不是秘密,这是它们的主要应用场景之一。我经常在合作的公司中看到这种情况。如今,几乎每家公司的代码开发工作流都以某种形式集成了大型语言模型。像这样的实际编码项目中测试Gemini 2.5 Pro提供了超出标准基准的见解。
此外,与大型语言模型下棋已成为检验其推理能力甚至作为一种娱乐手段的流行方式,正如这个视频所展示的,一位Youtuber让大型语言模型们进行了一场锦标赛(当时Gemini的表现不太好 ☹️)。
这个项目关乎AI辅助的软件开发的未来方向,并提供了一扇了解当前的大型语言模型推理能力展示的窗口。这种结合使其成为一个相关且值得探索的内容,值得我们关注。
做个计划首先,我想了解一下借助Gemini开发这样一个应用程序实际上会是什么样子。我的背景主要是Python,前端开发的知识不多。所以保持架构简单是非常重要的,这样我能自己理解、阅读,并且自己也能调试代码。
我最初的提议旨在与Gemini一起制定一个合作计划:
我想从零开始构建一个与LLM连接的国际象棋应用。
用户可以用鼠标下棋,当轮到电脑走棋时,会调用LLM获取下一步棋。
我前端开发经验不多,希望能保持简单。
我对AI工程很熟悉,要使用的LLM有一个Python SDK,我也很熟悉怎么用。
但如果更简单一些,我们也可以只用REST API。
请给些建议,关于构建这个应用的架构和技术栈。
我希望能在浏览器上运行。
对我来说,最看重的是简洁和代码量最少。
双子建议如下所示:
我们将使用Python后端(Flask)来处理游戏逻辑和状态管理,同时也会与大语言模型进行通信。前端主要使用HTML,并使用少量的JavaScript(chessboard.js)和htmx来处理棋盘界面,以简化前端JavaScript逻辑,并实现与后端的通信。
这听起来像个合理的计划。由于前端涉及的技术我不太熟悉,我想先从这个开始,确保它行得通,然后再开始做后端。
建议的架构如下:
作者供图
设计用户界面我的下一步是让Gemini来构建一个非常简单的独立网页应用。目标是创建一个功能性的棋盘界面,让用户可以为双方下棋,暂时不连接任何后端或LLM。
好的,我们就用JS和HTML吧。
好的,我们开始吧。你可以先做前端界面吗?
我想看看它是什么样的,也想试用一下(没有大模型,只是每次
用户的操作)来看看它怎么运作。
同时告诉我怎么运行它。我用vs code作为我的IDE。
双子回复了所需的HTML、CSS和JavaScript代码如下,如下解释和设置说明:
好的,让我们先构建静态前端。这个版本将让你能在浏览器中本地下棋,操作黑白双方的棋子,使用chessboard.js库来展示棋盘界面,并使用chess.js库在前端进行基本的走子验证。
这一步不涉及任何后端或大语言模型的交互。
项目结构:
为你的项目创建一个文件夹,例如 chess-llm-app。
在该文件夹中创建以下三个文件:
1. index.html
2. style.css
3. script.js
它还建议安装 VS Code Live Server 插件,便于在浏览器中轻松预览本地文件。
他/她/他们解释了这个初始界面的操作机制:
第一次打嗝chessboard.js 负责绘制棋盘、放置棋子以及管理拖放交互。当棋子被放下的时候(onDrop 函数):
script.js 捕获移动(起始方格和目标方格)。
它使用 chess.js 库(在客户端运行的库)来验证移动是否合法(game.move(…))。
如果合法,chess.js 更新其内部游戏状态。script.js 然后更新显示状态(如 FEN、PGN)。
chessboard.js 更新棋盘位置的显示(board.position(game.fen())),以反映新的状态。
如果不合法,chess.js 返回 null,棋子会回到原来的位置。
由于 onDragStart 函数仅仅根据本地 chess.js 的状态来判断谁该走棋,因此在这个版本中,你可以为白方和黑方手动进行走棋。
运行Gemini生成的代码后,应用加载了,但有些部分不见了。
作者供图
双子座提出建议,可能是暂时的网络问题、CDN问题,或者浏览器扩展阻止了访问外部资源——这些都是合理的解释,确实如此。它建议下载这些图片并在本地提供服务。这样感觉更可靠,尤其是对于可部署的应用程序而言。
作者的图片
不过,提供的GitHub链接不对,出现了404错误。链接指向了…/img/chesspieces/wikipedia,而正确的路径应该是…/website/img/chesspieces/wikipedia。手动修正并下载后,棋子就显示出来了!
作者提供图片
后端
在基本用户界面完成后,是时候开始构建后端了——一个用于管理游戏状态并与Gemini通信的Flask应用程序。
首先,我想确认前端结构能否支持由LLM生成的操作,而不仅仅是用户拖拽产生的操作。
问题:如果大模型不是通过拖拽而是回应一步棋,这个UI会工作吗?例如,如果我走e4,而大模型回应e5,我们该如何让棋盘执行这步e5?
双子座的解释真是清楚又让人放心。
作者供图
这意味着我们可以根据LLM的反馈通过编程更新板状态。
然后,Gemini指导我如何为Flask后端搭建项目结构,建议将前端资源放在静态文件夹里,并使用一个主要的app.py文件。
作者供图
它还提出了一项重要的架构转变:不再是由前端的 script.js
通过 chess.js
来验证用户的走棋,前端应该将用户的走棋发送到 Flask 后端。然后后端 (app.py
) 将成为游戏状态的唯一可信来源,负责验证走棋、更新棋盘,并最终触发 LLM 调用以处理。这正好符合我保持前端简洁并集中逻辑处理的目标。
在添加LLM集成之前,我测试了更新的UI与基本的Flask后端(现在处理移动验证)之间的连接。立刻就遇到了一个bug:白方走了一步后,尝试移动黑方棋子时会显示“不是你的回合”的错误,但实际上轮到黑方走了。
作者供图
我把错误信息和描述反馈给了Gemini,它的建议一开始并没有解决问题。有一次,它给出的回复完美地反映了我调试烦恼。
这张图片来自作者
确实如此!查错的时候真的会让人觉得莫名其妙 😅
双子座仍然愿意帮忙,这点还是很不错的。
作者的图片
在添加了更多的日志信息后,Gemini 最终锁定了问题,并找到了正确的解决办法。
作者的这张图片
说实话,这个阶段我没有深入探究根本原因。我们已经接近终点,我急于完成最后一步:双子座整合以生成动作。
连接 Gemini 卫星将 Gemini 的调用集成起来相对简单得多。关键在于设计一个好提示。为了减少 LLM 产生非法操作的可能性,我决定不仅提供当前棋盘状态(用 FEN 表示)和走法记录,还提供了所有合法操作的明确清单。
legal_moves_uci = [move.uci() for move in board.legal_moves]
legal_moves_str = " ".join(legal_moves_uci)
prompt = (
"你作为一个象棋引擎正在为黑方走棋。\n"
"当前棋盘状态的FEN表示为:\n"
f"{current_fen}\n"
"历史走法记录在UCI格式: " + " ".join([m.uci() for m in board.move_stack]) + "\n"
f"可走的合法棋步: {legal_moves_str}\n" # 添加了合法走法
"你的任务是从提供的合法走法列表中选择最佳走法。\n"
"请仅用UCI格式(如 'g8f6','e7e5')回复你的走法,不要添加其他任何文字。"
)
print(f"LLM 提示示例:\n{prompt}")
# 使用全局初始化的客户端对象
if not client:
print("LLM 客户端不可用,无法生成走步。")
llm_response_text = None # 表示失败
else:
try:
response = client.models.generate_content(
model=model_id, contents=prompt
)
print(response.text)
llm_response_text = response.text # 确保在没有LLM调用的情况下初始化为None
except Exception as e:
print(f"LLM API 调用出错: {e}")
llm_response_text = None
这基本上就是核心LLM集成的主要内容了。我最初将Gemini 2.0 Flash模型设为默认模型,后来我在界面上增加了一个下拉菜单,让用户能从不同的模型中选择,其中包括Gemini 2.5 Pro。
应用程序安装完毕后,是时候开始玩了!我开始和 Gemini 2.0 Flash 下棋。作为一个初学至中级玩家,在 chess.com 上的快棋等级大约是 1200 分,我觉得我有机会获胜。
作者拍摄的视频
和2.0 Flash的比赛相对简单。该模型经常未能识别简单的威胁,比如悬劫和明显的将军威胁。
接下来,我切换模型到Gemini 2.5 Pro。差别立刻显现,游戏感觉难度大增。
这是作者拍的视频
直到中盘 Gemini 才开始失误丢子,我挺高兴它犯了错——我觉得我当时也不占优势 😅
再来一个特点注意:因为下午响应时间变长了(可能是美国那边使用量增加的缘故),我在Gemini再出了几招错着后就停了视频。“帮帮忙,我们的TPU都要融化了” 🤣),所以你只能相信我后来把这盘棋下完了 😆
为了更深入了解大型语言模型的“思考”过程,我增加了一个额外的功能:我修改了提示,要求Gemini不仅给出一步棋,还要在提供棋步之前阐述它对当前棋局的思考过程或想法。这非常有用,偶尔,Gemini还会展示出一些个性:
作者的图片
你可以在这里找到它: https://github.com/heiko-hotz/gemini-chess/tree/feat/thoughts
总结用Gemini 2.5 Pro构建这个棋盘游戏应用程序是一次令人惊讶的实验,关于AI辅助开发。尽管一开始前端经验有限,我能够依赖Gemini进行架构设计的建议、代码生成,甚至在一些棘手的调试过程中——包括我们共同经历的那些“诡异”时刻!
生成的应用程序,可以直接与大模型对战,是一个具体成果。也许更重要的是,这一过程突显了AI工具如Gemini如何大幅降低门槛,让开发者能够挑战他们舒适区外的项目,并可能弥补技能差距。这种体验提供了一个对未来软件创作可能如何演变的展望。
海科·霍茨👋 在 Medium 和 LinkedIn 关注我,了解更多关于生成式AI、机器学习和自然语言处理的内容。
作者提供这张图片