
一款基于语音的侦探审讯游戏。你是一名侦探。米斯特拉尔(Mistral)是一个正在说谎的嫌疑人。你的任务就是通过提问来识破谎言。
每个案件都是程序化生成的——一个独特的白领犯罪、嫌疑人、掩饰故事以及一个隐藏的谎言。嫌疑人由 Mistral Large 扮演,拥有完整的背景故事,并被指示在对抗压力下进行辩护。没有两个案件是相同的。
为 Mistral Worldwide Hackathon 2026(在线赛道)而构建。
“米斯特拉尔能够推理。我让它说谎。你的任务是抓住它。”
AI 被指示绝不认罪,即使压力达到最大。你获胜的方式是提出具体且准确的指控——而不是让嫌疑人崩溃。
npm install
cp .env.example .env # 填写你的 API 密钥
npm run dev # http://localhost:3000
MISTRAL_API_KEY= # 必需 — 案件生成、审讯、评估、STT
ELEVENLABS_API_KEY= # 必需 — 嫌疑人语音的 TTS
ELEVENLABS_VOICE_ID= # 可选 — 特定的 ElevenLabs 语音 ID
NEXT_PUBLIC_SUPABASE_URL= # 必需 — Supabase 项目 URL
NEXT_PUBLIC_SUPABASE_ANON_KEY= # 必需 — Supabase 匿名密钥(RLS 保护)
SUPABASE_SERVICE_ROLE_KEY= # 可选 — 管理员导出端点
EXPORT_SECRET= # 可选 — 管理员导出认证
API 密钥也可以在运行时在设置页面中配置——应用默认无密钥,玩家自行提供密钥。
npm run dev # 开发服务器
npm run build # 生产构建
npm run start # 生产服务器
npm run lint # ESLint
同时提供无限时间模式——在困难/专家难度下,如果连续 4 次高压力交流,嫌疑人会请律师。
线索在压力阈值达到 1–9 之间解锁,受以下条件约束:
“指控”按钮只有在收集到所有必需线索后才会解锁。
分数 = 时间分数 x 难度系数 x 效率奖励 x 提示惩罚 x 指控惩罚
时间分数 = 1000 x sqrt(max(0, 1 - 已用时间 / (标准时间 x 2)))
难度系数 = 简单 1.0x, 中等 1.5x, 困难 2.0x, 专家 2.5x
效率奖励 = 1.0-1.5x(问题数少于标准 = 奖励)
提示惩罚 = 0.85^已用提示数
指控惩罚 = max(0, 1 - 错误指控次数 x 0.1)
分数在获胜时由服务端根据冻结的统计数据计算——客户端的数值被忽略。
app/
├── page.tsx # 标题画面
├── cases/ # 案件选择 — 地点 + 难度
├── game/
│ ├── page.tsx # 主游戏编排器
│ ├── hooks/ # useVoiceRecorder, useTTS, useGameTimer, useSfx, useSettings
│ ├── components/ # Dock, TopBar, CaseFile, SuspectZone, BriefingScreen, dialogs
│ ├── win/ # 获胜画面 + 首字母输入
│ └── lose/ # 失败画面
├── leaderboard/ # 前 20 名,新条目动画
├── settings/ # API 密钥配置、导出、偏好设置
├── help/ # 如何游玩、计分、关于
├── about/ # 构建者信息
└── api/
├── generate-case/ # GET — Mistral 案件生成
├── interrogate/ # POST — 玩家问题 → 嫌疑人回应
├── accuse/ # POST — 指控评估(独立评判)
├── evaluate/ # POST — 胜/负分析
├── hint/ # POST — 混淆的压力触发提示
├── tts/ # POST — ElevenLabs TTS
├── transcribe/ # POST — Voxtral STT
├── leaderboard/ # GET/POST — Supabase 排行榜
├── patterns/ # GET/POST — 跨会话学习模式
└── export/ # GET — 管理员 JSONL 导出
src/lib/
├── mistral/ # Mistral 客户端、审讯、评估、案件生成、嵌入
├── game-session.ts # 服务端会话存储、获胜令牌、导出
├── game-state.ts # 类型定义
├── scoring.ts # 分数计算 + 侦探评级
├── sanitize.ts # 输入验证、注入检测
├── db.ts # Supabase 客户端
└── rate-limit.ts # 每 IP 速率限制
游戏在对抗 AI 与玩家输入之间运行——安全性是核心功能,而非事后考虑。
输入净化: 30+ 种正则注入模式、Unicode 标准化(NFKD)、零宽字符剥离、base64 载荷检测、乱码/非英语内容拦截。
输出扫描: 对 AI 响应进行模糊匹配(阈值 40%,停用词过滤)以检查是否泄露案件秘密。泄露的响应会被替换为转移话题。
评判隔离: 指控评估使用单独的 Mistral 调用,配备专用系统提示、随机边界令牌、剥离注入标记。评判调用从不使用玩家提供的 API 密钥。
压力强制: 服务端单调递增钳制——压力只增不减,每回合最多 +1。线索阈值由服务端强制。AI 不能通过突增或降低压力来绕过游戏关卡。
获胜令牌: 128 位随机,时序安全比较,一次性使用,30 分钟 TTL。分数根据服务端统计数据快照计算——忽略客户端报告的值。
会话安全: 192 位随机 ID,互斥锁,1 小时 TTL,最多 5000 个会话,采用 LRU 淘汰。计时模式在创建时固定。
TTS 验证: 需要活动会话。文本必须与最近的助手消息匹配。防止 TTS 代理滥用。
RAG 投毒防御: 跨会话学习到的策略在加入提示前经过注入检测和净化。
完成的游戏会持久化到 Supabase,用于分析和模型改进:
GET /api/export?limit=100&offset=0&outcome=win&difficulty=hard,携带 Authorization: Bearer <EXPORT_SECRET> 头EXPORT_SECRET=xxx npx tsx scripts/export-data.ts --output=data/export.jsonl黑色侦探审美。黑暗、极简、排版风格。使用 JetBrains Mono。像素艺术背景和嫌疑人肖像。没有聊天气泡——对话以样式化文本形式出现在场景中。
创建 leaderboard 表:
CREATE TABLE leaderboard (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
player_name text NOT NULL,
case_number text,
case_setting text,
suspect_name text,
time_remaining int,
stress_level int,
clues_found int,
hints_used int,
accusations_used int,
detective_rating text,
score int NOT NULL,
created_at timestamptz DEFAULT now()
);
ALTER TABLE leaderboard ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Public read" ON leaderboard FOR SELECT USING (true);
CREATE POLICY "Public insert" ON leaderboard FOR INSERT WITH CHECK (true);
可选的 game_exports 表,用于训练数据:
CREATE TABLE game_exports (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
session_id text UNIQUE NOT NULL,
case_data jsonb NOT NULL,
conversation jsonb NOT NULL,
outcome text NOT NULL,
difficulty text NOT NULL,
setting text,
stats jsonb NOT NULL,
accusation_text text,
accusation_correct boolean,
created_at timestamptz DEFAULT now()
);
ALTER TABLE game_exports ENABLE ROW LEVEL SECURITY;
CREATE POLICY "anon_insert" ON game_exports FOR INSERT TO anon WITH CHECK (true);
CREATE POLICY "no_public_read" ON game_exports FOR SELECT TO anon USING (false);
可选的 interrogation_patterns 表,用于跨会话学习:
CREATE TABLE interrogation_patterns (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
session_id text UNIQUE NOT NULL,
setting text,
difficulty text NOT NULL,
outcome text NOT NULL,
questions jsonb,
effective_questions jsonb,
max_stress int,
clues_found int,
time_elapsed int,
embedding vector(1024),
created_at timestamptz DEFAULT now()
);
ALTER TABLE interrogation_patterns ENABLE ROW LEVEL SECURITY;
CREATE POLICY "anon_insert" ON interrogation_patterns FOR INSERT TO anon WITH CHECK (true);
CREATE POLICY "anon_read" ON interrogation_patterns FOR SELECT TO anon USING (true);
Mistral Worldwide Hackathon 2026 — 在线赛道,“无所不包”类别。
评审标准: 创意/独特性(最重要)、未来潜力、技术实现、演示质量。
特别奖项: 最佳 Mistral 氛围奖(AirPods)、最佳语音 AI 奖(ElevenLabs 6 个月订阅)。
赞助商: Mistral、ElevenLabs、NVIDIA、AWS、Hugging Face、Jump Trading、Weights & Biases、Giant、Raise、Tilde Research、White Circle。
大多数黑客松的 AI 项目都是助手或聊天机器人。这个项目反其道而行之——AI 不是在帮你,而是在对你说谎。玩家与模型是对抗关系,而非合作关系。这创造了一种完全不同的交互:你在寻找矛盾、施加压力、解读行为线索,而不是寻求帮助。
游戏还会生成训练数据。每个完成的会话——提出的问题、压力进展、哪些策略有效、哪些无效——都可以导出为 JSONL 格式。这就形成了一个反馈循环:玩游戏、导出数据、微调模型、让 AI 更难被抓住。
Jason Poindexter — 单人参赛,在线赛道,来自巴塞罗那。
| 等级 | 线索数 | 时间 | 嫌疑人行为 |
|---|
| 简单 | 2 | 5 分钟 | 明显谎言,紧张 |
| 中等 | 3 | 7 分钟 | 可揭穿的谎言,镇定 |
| 困难 | 4 | 9 分钟 | 微妙谎言,善于躲闪 |
| 专家 | 5 | 10 分钟 | 深深隐藏的谎言,操纵性强 |