用 Vue + Spring Boot + Python 做一个 AI 双人海龟汤游戏:从出题、联机到自动审稿等核心技术设计与实现

本文记录"蜜码"项目中 AI 双人海龟汤模块的设计与实现,重点介绍题目质量、联机状态同步、自动修订以及开发者测试工具。文中的结构示例经过简化,不是可以直接替换项目接口的完整代码。

一、为什么做这个功能

在"蜜码"这个双人空间项目里,我加入了一个游戏入口,希望两个人即使使用不同电脑,也能一起玩海龟汤。

海龟汤的基本玩法并不复杂:主持人给出一段不完整的故事,玩家通过提问还原背后的真相。将主持人换成 AI 后,可以自动生成新故事、回答问题,并在结束时评估玩家的推理。

真正做起来以后,我发现最难的部分不是聊天界面,而是题目质量。

有些故事看起来很神秘,但关键事实与汤面完全没有联系,玩家只能碰运气;有些故事依赖双胞胎、替身等身份反转,多玩几局就开始重复;还有些题目选择了恐怖风格,实际上只是普通悬疑故事。

所以,这个模块的目标逐渐变得清晰:先生成并锁定一个能解释清楚、也能问出来的故事,再让两位玩家围绕固定真相进行推理。

二、把玩法需求拆成可以实现的规则

目前的游戏支持以下配置:

| 配置 | 可选内容 |
| --- | --- |
| 难度 | 普通、困难、极难 |
| 生死类型 | 红汤、清汤、随机 |
| 世界规则 | 本格、变格、随机 |
| 故事风格 | 悬疑、恐怖、犯罪、心理、情感等 |
| 预设提示 | 自定义数量,范围为 0~10 条 |
| 正式提问额度 | AI 推荐,或玩家自定义 |
| 推理进度查询 | 可开启,全局最多 3 次 |
| 猎奇元素 | 选择恐怖风格时可配置,默认开启 |

红汤表示故事中有人死去,清汤表示故事中没有人死去。本格使用现实规则,变格允许有边界的超自然设定。

这些配置需要参与完整故事的生成与审核。例如,清汤不能只保证汤面没有提到死亡,却在汤底里突然加入一个已经死去的人;本格也不能在揭晓时用鬼魂或轮回解释矛盾。

提问流程经过调整后,采用"先三问热身,再自由提问"的方式:

1. 两位玩家分别有 3 次免费提问。
2. 谁先提问,谁先连续完成自己的免费三问。
3. 再由搭档完成免费三问。
4. 免费提问结束后,两个人都可以继续发送问题。

主持人的回答限制为四种:

是

不是

是也不是

无关

其中,"是也不是"需要故事本身确实存在两种相关状态,不能因为模型不确定就使用这个回答。

两个人还可以单独讨论、整理私人推理草稿,并通过双方确认提交最终答案。正式提交后,本局结束,由 AI 评估还原度并公布汤底。

三、系统架构:游戏状态与 AI 工作分开

这个模块使用三部分协作:

| 层级 | 技术 | 主要职责 |

| --- | --- | --- |

| 前端 | Vue 3、Vite | 房间页面、故事展示、聊天、动画和进度反馈 |

| 业务后端 | Spring Boot | 用户与空间权限、房间状态、额度、记录和联机同步 |

| AI 服务 | Python、FastAPI | 生成题目、盲读、审稿、主持回答和推理评估 |

整体关系可以理解为:

玩家 A 的浏览器 ─┐

├─ Spring Boot ─ 数据库

玩家 B 的浏览器 ─┘ │

WebSocket 通知

│

Python AI 服务

│

模型服务

这里有一个关键选择:房间状态由 Java 后端统一管理。

前端不能自行决定"本次提问已经扣费",Python 也不能直接决定"房间已经进入下一阶段"。AI 返回的是内容或判断结果,是否接纳结果、如何修改状态和扣减额度,由业务后端完成。

这样可以避免两台电脑各自维护一套状态,也方便在模型请求失败时保持原有记录。

当前房间状态包含:

WAITING 等待双方准备

GENERATING 创作与审核

PLAYING 推理进行中

EVALUATING 最终答案评估中

RESULT_ERROR 评估失败,等待重试

FINISHED 已结束并揭晓

CLOSED 房间已关闭

正常流程是等待准备、生成题目、进行推理、评估答案,最后揭晓。取消创作或关闭未开局房间,则进入关闭状态。

四、先锁定汤底,再展示汤面

我没有采用**"先让 AI 写汤面,之后一边回答一边补汤底"**的方式。

这种方式很容易出现一个问题:玩家提出某种猜测后,模型顺着猜测临时补充故事。最终看似每个问题都有回答,但真相一直在变化。

目前的流程是:

生成完整题目

↓

检查结构与线索

↓

独立读者盲读

↓

审稿与问题探针

↓

通过后保存完整题目

↓

只向玩家公开汤面

完整题目不仅包含汤面和汤底,还包含人物关系、时间线、因果链、核心事实、提示和线索路径。

下面是简化后的结构示意:

{

"title": "题目名称",

"surface_story": "玩家可以看到的故事",

"death_type": "clear",

"world_type": "realistic",

"solution": {

"summary": "完整真相",

"characters": \[\],

"world_rules": "无"

},

"timeline": \[\],

"cause_chain": \[\],

"core_facts": [

{

"id": "F1",

"fact": "需要推理出的关键事实",

"weight": 100

}

],

"clue_map": [

{

"surface_detail": "汤面中的一个具体异常",

"question_path": "围绕异常可以提出的问题",

"fact_ids": "F1"

}

],

"hints": \[\]

}

其中,核心事实用于约束主持回答和推理评估,线索路径用于检查"这个事实能否从公开故事中逐步问出来"。

完整题目保存在后端,正常游戏接口不会提前返回汤底。生成通过后,才向两位玩家展示汤面。

五、让题目有深度,但仍然能推理

难度高不应该意味着必须猜中一个毫无铺垫的隐藏设定。

例如,汤面只写"一个人打开门后哭了",汤底却突然补充十年前的经历、罕见疾病和复杂身份关系。这个故事即使能自圆其说,也不适合用来推理。

我主要从三个方向约束生成。

1. 关键事实必须有公开入口

一个重要隐藏事实,至少应该有一个可追问的汤面细节与它关联。

玩家不必直接从汤面读出答案,但需要知道可以从哪里开始问。异常物件、行为顺序、人物反应和空间关系,都可以成为入口。

2. 增加因果层次,而不是堆积秘密

普通题强调一条主要行动链。更高难度可以增加关联机制和推理层次,但仍然需要围绕同一组因果展开。

如果每解释一个异常,都需要新增一项互不相关的隐情,玩家就很难判断自己是否接近真相。

3. 避免廉价的身份捷径

项目加入了创作机制规划与历史避重。

生成时会参考同空间近期的题目,尽量选择较少出现的方向,例如物件用途、时间顺序、观察条件、行动目的、信息差和空间关系。

同时,对双胞胎、克隆复制、相同长相替身、多重人格等作为核心反转的套路进行限制,减少连续出现相似题目的情况。

这类语义去重仍然依赖模型判断,不能保证每一道题都完全新颖,但比单纯要求"不要重复"更容易检查。

六、参考优秀案例,具体是怎么参考的

为了改善故事设计,项目引入了海龟汤参考案例库。

这里的"学习"是将案例材料作为出题时的参考输入,没有训练或微调模型。

参考案例主要帮助作者理解:

  • 汤面怎样留下有效异常;

  • 隐藏事实怎样与公开线索关联;

  • 反转怎样回收前面的细节;

  • 提问怎样逐步推进因果链。

当前创作方向、玩家配置、参考案例与近期历史避重材料,会共同参与提示词构建。

开发面板还保留了本局实际生成提示词的快照,可以检查这一次使用了哪些参考材料,以及作者、读者和审稿分别收到了什么要求。

这样遇到坏题时,就有材料可以分析,而不是只能反复修改一句"请生成更好的故事"。

七、独立盲读与审稿,分别检查什么

如果只让作者模型评价自己的题目,很容易得到过于乐观的结果。

因此,我把检查拆成了两个阶段。

独立读者:只看公开汤面

独立读者只能看到玩家可见的故事,不会收到汤底和核心事实。

它需要判断:哪些地方反常、有哪些自然的提问入口,以及玩家读完之后能获得什么信息。

选择恐怖风格时,读者还要指出具体的恐怖证据,而不是因为配置写着"恐怖"就默认认可。

这一阶段主要观察玩家视角,减少"已经知道答案,所以觉得线索很明显"的偏差。

审稿:对照完整真相检查

审稿阶段可以看到完整题目,检查因果、类型约束、线索覆盖和推理公平性,并用关键问题探针验证主持人应该如何回答。

当前审核要求包含总体质量门槛、六项公平性检查以及至少三个不同的关键问题探针。

程序也会检查一些能明确验证的内容,例如引用是否来自汤面、结构字段是否完整、线索是否关联核心事实。

但这些流程不等于数学证明。模型可能漏掉语义矛盾,多个角色也可能产生相似判断,仍然需要实际试玩和坏题回归材料补充验证。

八、恐怖与猎奇怎样服务于推理

最初的恐怖要求比较笼统,模型经常生成"有怪声""被人跟踪"之类的故事。它们有悬疑气氛,但压迫感不足。

后来我把要求改得更加具体:

  1. 危险要贴近人物的生活与身体边界。

  2. 汤面至少有两处可以观察到的反常细节。

  3. 这些细节需要与同一条主要因果链相连。

  4. 揭晓后,玩家重新理解之前的细节,并产生后怕。

开启猎奇元素后,可以加入异常习惯、令人不适的身体感受、扭曲的物件用途等细节,但它们仍然必须参与故事的核心解释。

本格恐怖可以来自现实中的控制、侵害或异常行为。变格恐怖可以来自超自然规则,但规则必须有边界、有代价,并且能通过故事中的异常逐步发现。

清汤仍然需要保证无人死亡,不能为了增强恐怖而绕过类型限制。

当前恐怖审核除了总体要求,还增加了独立盲读至少 80 分、审稿至少 85 分的门槛,要求引用公开证据,并确认揭底后的威胁解释成立。开启猎奇时,两个检查阶段都需要指出汤面中的猎奇证据。

分数只是模型对风格的判断。具体证据和可追问的因果,比一个高分本身更有价值。

九、一次点击后自动修订,怎样处理失败

早期的生成流程会在审核失败后直接报错,让玩家重新点击开始。

从玩家的角度看,这相当于把内部创作失败变成了额外操作。所以现在的流程会自动继续修订,审核通过后才发布题目。

每一轮失败都会把具体问题交回作者,例如:

某个关键事实缺少汤面入口。
时间线中两次行为的顺序互相冲突。
清汤的汤底出现了死亡事实。
恐怖证据不足,读者只能感到普通悬疑。

如果一个恐怖方案连续修订三版仍然没有通过,就自动换新的核心机制和场景继续创作,避免始终围绕失败方案打补丁。

前端展示创作阶段、修订次数和等待时间。这些信息来自实际进度事件,没有把未知的生成时间伪装成一个精确完成百分比。

业务后端还对暂时性服务失败安排重试,玩家也可以取消创作。取消后,旧任务即使稍后返回,也不能把已经关闭的房间重新打开。

自动修订改善了操作体验,但无法保证任意模型配置下都能在固定时间内产出合格题目。质量门槛越严格,等待时间也可能越长。

十、双人联机:通知变化,再读取房间

两个人通过各自账号加入同一个空间后,可以在不同电脑上进入同一个游戏房间。

房间发生变化时,后端保存记录,再通过 WebSocket 通知客户端。前端收到通知后读取最新房间状态,并通过轮询与重新连接作为补充。

更新操作包括:

**- 加入和准备;

  • 生成阶段变化;
  • 玩家提问与主持回答;
  • 讨论和提示使用;
  • 提交、确认最终答案;
  • 开发者直接结束对局。**

房间数据带有递增的 revision。前端在同一房间中忽略更旧的响应,减少并发请求返回顺序不同造成的状态回退。

AI 工作也不会一直占用房间状态修改锁。请求在后台执行,结果返回后再检查当前状态,确认仍然有效才保存。

如果 AI 回答失败,不会消耗对应的提问或进度额度;成功接纳结果后才修改记录。

这一实现以单个 Java 服务实例中的协调器为基础。如果以后要部署多个业务实例,还需要把并发互斥和任务归属扩展到数据库或其他共享协调机制。

十一、前端:用聊天承载提问,减少无关重绘

玩家提问采用聊天界面,两位玩家的消息都显示在右侧,AI 回答显示在左侧。

发送与回答加入了接近 Telegram 风格的气泡弹出动画,让消息出现时更自然。

页面切换则需要另一种处理。项目中曾经出现过"看起来不算卡,但切换很生硬"的问题。

调整时,一个重要原则是只让真正的页面或场景变化触发进入、离开动画。房间轮询、准备状态更新和新消息到达,不应该让整个页面重新播放过渡。

因此,场景键主要由房间 ID 和游戏阶段决定。进入游戏后,普通问答更新会保留当前页面结构,让聊天组件处理消息动画。

另外,汤面支持按人物为明确归属的说话或行为标色,并提供图例和开关。无法可靠判断归属的内容保持中性色,避免颜色本身误导推理。

这些变化不是单纯增加动画,而是让页面变化与用户正在进行的动作保持对应。

十二、开发者工具:让一次测试更快结束

海龟汤生成涉及多轮模型调用。如果测试时必须完整玩完一局,再由两个人确认提交,验证成本会比较高。

因此,项目加入了开发者面板。

它可以查看锁定汤底、时间线、因果链、提示、核心事实、线索路径、审稿结果和提示词快照。提前查看汤底会给本局加上开发测试标记,双方都能看到。

最新加入的"结束本场游戏"用于快速结束测试:

| 当前情况 | 直接结束后的行为 |
| --- | --- |
| 等待准备、创作中 | 关闭房间 |
| 推理中,或已有题目正在等待评分 | 立即结束,向双方展示汤底 |
| 已经结束或关闭 | 保持原有结果 |

直接结束不需要搭档确认,也不调用 AI 评分。已有问答记录会保留,页面显示"本场测试已结束",不会生成一份虚假的推理得分。

实现时需要注意的不只是状态改为 FINISHED,还要清除 busy、待处理提问、待确认方案和错误状态。生成中的进度也需要停止。

现有异步回调会检查任务是否仍有效,因此结束之后,迟到的 AI 回答、评分或生成结果不会再改写这局。

开发者接口复用现有权限限制:仅在启用开发工具的 dev 环境,由房主调用。普通玩家即使直接请求接口,也不能使用这个功能。

按钮隐藏只是界面行为,真正的权限判断仍在后端。

十三、验证范围与后续改进

本次开发者结束功能完成时,后端针对开发权限、提问规则、结束状态以及迟到的 AI 回调进行了测试;相关两组测试共 26 项通过。前端生产构建也通过,页面使用模拟房间响应验证了直接结束后的汤底展示。

这里要区分三种验证:

| 验证方式 | 能覆盖什么 |
| --- | --- |
| 后端自动化测试 | 权限、状态变化、额度和异步回调边界 |
| 前端构建与页面验证 | 编译、事件绑定和结果展示 |
| 真实模型试玩 | 题目逻辑、推理体验、风格与重复程度 |

真实模型测试中,有本格红汤样本通过了加强后的恐怖审核;变格清汤仍出现过逻辑问题,随后继续收紧了创作约束。因此,自动化测试通过不能直接等同于所有生成题目都好玩。

后续值得继续完善的是坏题回归集、取消与超时体验、题目多样性评估,以及多实例部署时的并发协调。

结语

这个项目让我意识到,把 AI 接到一个聊天框,只是海龟汤玩法的起点。

真正影响体验的是:汤底是否固定、线索是否有入口、主持判断是否一致,以及两位玩家看到的状态是否可靠。

通过完整题目锁定、独立盲读、审稿探针、自动修订和开发者工具,至少可以让这些问题更容易检查、定位和改进。AI 负责创作与判断,游戏规则和状态边界则由程序明确执行。

相关推荐
猪猪拆迁队1 小时前
跨电脑复制共享-WebRTC 打洞踩坑
前端·后端·go
ServBay1 小时前
如何用 AI Agent 构建全栈应用(2026版)
后端·ai编程
黎燃2 小时前
我给自己写了一个 mini OpenRouter:基于蓝耘 MaaS 的多模型路由网关实战
后端
leobertlan2 小时前
痛苦系列 | DSP-01 从连续到离散:DSP基础与采样
android·后端
高频因子挖掘机2 小时前
同一只股票前复权和不复权价格对不上?先检查这几个口径
后端·github·api
Bazingga2 小时前
Harness学习笔记:从马具到工程外壳
后端
法欧特斯卡雷特2 小时前
Kotlin 新特性抢先看:伴生扩展与伴生块
后端·面试·开源
桃李醉春风3 小时前
被微信拒审那天,我才真正学会 Vibecoding:一个人 + AI,3 万行代码、1.8 万张素材的小程序全复盘
后端
她的男孩3 小时前
打印模板草稿能保存,一点发布就报主从关系:我们把校验拆成了两档
java·spring boot·后端