这是关于什么的?
上周,谷歌发布了Gemini 2.5 Pro。它在各处的基准测试中都名列前茅,据报道,它在编码和推理方面尤为出色。那么,还有什么比让它开发一个国际象棋应用程序,然后用这个应用程序与人工智能对弈更好的方法来检验这些说法呢?
在这篇文章中,我将分享我使用Gemini 2.5 Pro开发一个国际象棋应用程序的过程。虽然可以将它作为代码助手集成到集成开发环境(IDE)中,但在这个项目里我主要使用了谷歌的AI Studio,以此来展示其操作的简便性。核心思路是创建一个能连接到LLM的功能完备的国际象棋应用程序,让人类用户能够与该模型对弈。
我们为什么要关注这件事?
自大型语言模型(LLM)诞生以来,它们就一直被应用于编码任务。这是它们的主要应用场景之一,这已经不是什么秘密了;我在与合作的机构中经常看到这种情况。如今,几乎每家公司似乎都有某种形式的集成了大型语言模型的代码开发工作流程。在像这样的实际编码项目中对Gemini 2.5 Pro进行测试,能提供超越标准基准测试的深刻见解。
此外,与LLM下国际象棋已经成为一种流行的方式,既可以探究它们的推理能力,甚至还能作为一种娱乐方式。
这个项目涉及到人工智能辅助软件开发的未来,并且为了解当前大型语言模型的推理能力提供了一个窗口。这种结合使得它成为了一项值得关注的相关探索。
制定计划
首先,我想感受一下用Gemini开发这样一个应用程序实际会是什么样子。我的专业背景主要是Python,而且我的前端开发知识有限。因此,保持架构简单至关重要,这样我才能自己理解、阅读代码,并有可能进行调试。
我最初的提示是为了与Gemini合作制定一个计划:
I want to build a chess app from scratch that connects with an LLM.
The user can use the mouse to play their moves and when it is the
computer's move a call to the LLM is made to get the next move.
I dont have much experience in frontend development and would want
to keep it as simple as possible. i'm very familiar with AI engineering
and the LLM i want to use has a python sdk which i know well how to use.
But if it's easier/simpler, we can also just use the REST API.
Suggest an architecture and tech stacks to build this.
I want to play it on the browser and simplicity and fewest line of code
are the most important to me.
Gemini提出了如下建议:
We'll use a Python backend (Flask) to handle game logic, state management,
and LLM communication. The frontend will be primarily HTML, enhanced with
a minimal amount of JavaScript for the chessboard interface (chessboard.js)
and htmx to handle communication with the backend without writing complex
frontend JavaScript logic.
这听起来是个合理的计划。由于前端涉及到我不太熟悉的技术,我想先攻克前端部分,以确保在构建后端逻辑之前,前端是可行的。
以下是所建议的架构:
设计用户界面
我的下一步是让Gemini构建一个非常基础的、独立的网络应用程序。目标是打造一个具备基本功能的棋盘用户界面,在这个界面中用户能够为双方下棋,此时暂不涉及任何后端程序或与LLM的连接。
Got it, lets stick with js + html.
Ok, let's get started. can you build the frontend/UI first?
I want to see it and also use it (without LLM, just every
move done by the user) to see how it works.
Tell me how to run it as well. I use vs code as my IDE.
Gemini回复了所需的HTML、CSS和JavaScript代码,以及以下的解释和设置说明:
Okay, let's build the static frontend first. This version will allow you
to play chess locally in your browser, making moves for both White and
Black, using the chessboard.js library for the UI and the chess.js library
for basic move validation on the frontend.
No backend or LLM interaction is included in this step.
Project Structure:
Create a folder for your project (e.g., chess-llm-app).
Inside that folder, create these three files:
1. index.html
2. style.css
3. script.js
它还建议安装Visual Studio Code的“实时服务器扩展”,以便在浏览器中轻松进行本地预览。
Gemini解释了这个初始用户界面的工作原理:
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生成的代码后,应用程序加载了,但棋子却不见了:
Gemini认为原因可能是暂时的网络问题、内容分发网络(CDN)问题,或者是浏览器扩展程序阻止了外部资源——这些都是合理的解释。它建议下载棋子图片并在本地提供这些图片。不管怎么说,这感觉是一个更可靠的解决方案,尤其是对于一个可部署的应用程序而言。
然而,提供的用于获取棋子图片的GitHub链接是错误的(出现了404错误)。它指向的是 …/img/chesspieces/wikipedia,而正确的路径应该是 …/website/img/chesspieces/wikipedia。快速手动修正并下载之后,棋子终于显示出来了!
后端
随着基础用户界面能够正常运行,接下来就该构建后端了——也就是使用Flask框架开发的应用程序,它将负责管理游戏状态并与Gemini进行通信。
首先,我想确认前端结构不仅能够处理用户的拖放操作,还能够适应由LLM生成的走棋步骤。
Question: Will this UI work if the LLM responds back with a move instead of
dragging it? e.g. if I play e4 and the LLM responds with e5, how will we
make it so that the chessboard will execute e5?
Gemini的解释清晰明了,让人安心:
它确认了我们能够根据LLM的回复,通过编程的方式来更新棋盘状态。
接下来,Gemini指导我如何为Flask后端构建项目结构,建议创建一个存放前端资源的静态文件夹,以及一个主应用文件app.py。
它还提出了一项重要的架构调整:前端的script.js不应再使用chess.js来验证走棋步骤,而应该将用户的走棋操作发送到Flask后端。而后端(app.py)将成为游戏状态的唯一真实数据源,负责验证走棋步骤、更新棋盘,最终触发对LLM的调用。这与我简化前端并将逻辑集中化的目标完美契合。
第二个小问题
在集成LLM之前,我测试了更新后的用户界面与基础Flask后端(现在负责处理走棋验证)之间的连接。很快,我就遇到了一个错误:白方走棋后,尝试移动黑方棋子时会出现“不是你的回合”的错误提示,即便此时确实该黑方走棋了。
我把错误信息和相关描述反馈给了Gemini。起初,它给出的建议并没有解决这个问题。有一次,它给出的回复简直完美地反映出了我在调试过程中的沮丧心情:
“这可真奇怪”,确实如此!有时候调试工作就是会让人有这种感觉
不过,Gemini 仍然很有帮助:
在根据Gemini的建议添加了更多的日志记录后,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 = (
"You are a chess engine playing as Black.\n"
"The current board state in FEN notation is:\n"
f"{current_fen}\n"
"History of moves in UCI format: " + " ".join([m.uci() for m in board.move_stack]) + "\n"
f"LEGAL MOVES available: {legal_moves_str}\n" # Added legal moves
"Your task is to select the best legal move for Black from the list provided.\n"
"Respond *only* with the chosen move in UCI notation (e.g., 'g8f6', 'e7e5'). Do not add any other text."
)
print(f"LLM Prompt (example):\n{prompt}")
# Use the globally initialized client
if not client:
print("LLM Client is not available. Cannot generate move.")
llm_response_text = None # Indicate failure
else:
try:
response = client.models.generate_content(
model=model_id, contents=prompt
)
print(response.text)
llm_response_text = response.text # Ensure it starts as None if LLM call isn't active
except Exception as e:
print(f"Error during LLM API call: {e}")
llm_response_text = None
这基本上就是LLM核心集成的主要内容了。我最初使用Gemini 2.0 Flash作为默认模型,但后来在用户界面中添加了一个下拉菜单,这样就可以在不同的模型之间进行选择,其中包括Gemini 2.5 Pro。
又一项功能
为了能更深入了解LLM的 “思考” 过程,我添加了最后一项功能:我修改了提示内容,要求Gemini不仅给出一步棋的走法,还要在给出走法之前阐述它对当前游戏局面的推理或想法。事实证明,这很有启发性,而且有时候,Gemini还展现出了一点个性:
结论
使用Gemini 2.5 Pro开发这款国际象棋应用程序是一次颇具启发性的人工智能辅助开发实验。尽管我在前端方面的专业知识有限,但我在很大程度上可以依赖Gemini来提供架构建议、生成代码,甚至在棘手的调试过程中也能依靠它——期间还不乏一起经历的那些“离奇”时刻!