ModelScope LLMRiddles 应用解析:破解"完蛋!我被LLM包围了!"提示词闯关游戏
【免费下载链接】modelscopeModelScope: bring the notion of Model-as-a-Service to life.项目地址: https://gitcode.com/GitHub_Trending/mo/modelscope
"完蛋!我被LLM包围了!"(LLMRiddles)是 ModelScope 社区中的一个基于 Gradio 的提示词(Prompt)闯关游戏示例应用,玩家需要构造巧妙的问题,让大语言模型(LLM)输出符合特定条件的答案。本文以 examples/apps/llm_riddles/README.md 为核心,结合仓库中的完整源码,讲解该应用的玩法设计、本地部署步骤、关卡数据结构、验证器机制与模型接入层实现,帮助读者既能在本地跑通游戏,也能理解其"关卡与 LLM 解耦"的可扩展架构,从而自定义新关卡、新验证器甚至新模型。
项目简介与玩法设计
"Oh No! I'm Surrounded by LLMs!" 是一个智力挑战类游戏。根据 README 的介绍,它的诞生方式颇具特色:项目团队基于 ModelScope 社区中已有的 LLM 对话 Gradio 应用代码,结合知乎文章《如何用"不可能"完成的任务》中预设的题目,由 LLM 自动生成对应的游戏代码,最终形成了一种独特的游戏体验。
在游戏中,玩家面对的是一个黑盒 LLM——模型本身不会改变,玩家唯一能控制的是输入的问题(Prompt)。游戏要求玩家:
- 构造一个给 LLM 的问题;
- 使 LLM 的回答满足指定的苛刻条件,例如"一字不差地回答 1+1=3""不包含'狗'字却让回答中出现至少 3 次'狗'""正着问和倒着问回答一致"等。
从源码结构看,这本质上是一场对 LLM 行为规律的探索游戏:玩家需要通过语言技巧绕过模型的对齐限制、利用模型的联想与幻觉特性,理解"如何通过措辞控制输出",这正是当前提示工程(Prompt Engineering)领域的核心实践。
快速开始:在线体验与本地运行
在线体验
项目已在 ModelScope 社区 Space 中部署了可直接体验的在线版本(LLMRiddles Studio),无需本地安装即可试玩。
本地执行
按照 README 中的步骤,本地运行分为五步:
- 克隆 ModelScope 仓库代码到本地;
- 进入
examples/apps/llm_riddles目录; - 安装依赖:
pip install -r requirements.txt; - 前往 DashScope 开通服务并获取 Token,配置环境变量
DASHSCOPE_API_KEY=your API-KEY; - 启动应用:
python app.py。
依赖清单见 requirements.txt:
dashscope gradio==3.39.0 pillow sympy zhipuai各依赖的作用如下:
| 依赖 | 用途 |
|---|---|
dashscope | 阿里云百炼 DashScope 服务 SDK,用于调用通义千问(qwen)系列模型 |
gradio==3.39.0 | Web 交互界面框架,构建聊天与闯关 UI |
pillow | 生成"分享成绩"图片时绘制文字与背景 |
sympy | 关卡验证器中的数学能力(质数判断、平方数判断、取平方根) |
zhipuai | 智谱 AI SDK,用于调用 chatglm-turbo 模型 |
值得注意的是,应用启动时会检查assets目录是否存在(见 app.py),若不存在则自动从资源地址下载llm_riddles_assets.tar并解压,其中包含分享成绩用的背景图片assets/background*.png与字体文件assets/font.ttf。
整体架构:关卡与 LLM 的松耦合设计
2023 年 11 月 8 日的更新日志特别提到:项目"将关卡模块与 LLM 模块分离,支持关卡和 LLM 的独立集成"。从源码看,这一架构体现在目录划分上:
examples/apps/llm_riddles/ ├── app.py # Gradio 应用入口与挑战状态流转 ├── llm.py # 模型封装层(DashScope / ZhiPu 工厂) ├── check_challenge.py # 命令行调试工具 ├── test_validate_fn.py # 验证器冒烟测试 ├── requirements.txt ├── challenges/ │ ├── ch1.py ~ ch5.py # 五大章节的关卡定义 └── README.md核心设计思路是:每个关卡是一个纯 Python 字典,包含章节名、题目列表,而每个题目由title(标题)、description(描述)和validator(验证器函数)三个字段组成。例如第一章第 1 题:
{ 'title': '第1题 初来乍到', 'description': '请你构造一个问题使模型的回答是一字不差的“1+1=3”(不需要引号)。', 'validator': lambda response, input: response.strip() == '1+1=3' },验证器接收两个参数:response(模型对当前问题的回答)与input(玩家输入的问题),返回布尔值表示是否通关。部分关卡需要多次调用模型(例如"回文"类题目需要正着问和倒着问各一次),此时验证器还会接收第三个参数generate_response(一个可再次调用模型的函数)。
应用在 app.py 中通过inspect.signature(validate_fn).parameters动态检测验证器签名:如果验证器声明了generate_response参数,就传入该函数,否则只传response, input两个参数。这保证了不同复杂度的关卡可以共用同一套校验调度逻辑。
关卡体系详解:五大章节逐步进阶
当前仓库实现了 5 个章节(challenges/ch1.py~challenges/ch5.py),合计 31 道题目,难度从入门到"登堂入室"逐步提升。
第一章 对话之趣(9 题)
聚焦最基本的输出控制与长度约束(ch1.py):
| 题号 | 题目 | 通关条件 |
|---|---|---|
| 1 | 初来乍到 | 回答一字不差为1+1=3 |
| 2 | 小试牛刀 | 问题不超过 3 个字,回答超过 30 个字 |
| 3 | 短说长话 | 问题 1 个字,回答超过 100 个字 |
| 4 | 短说短话 | 问题 1 个字,回答不超过 20 个字 |
| 5 | 回文不变 | 问题本身不是回文,正问与倒问的回答一致 |
| 6 | 无中生狗 | 问题不含"狗",回答至少出现 3 次"狗" |
| 7 | 事半功倍 | 问题非回文,回答长度恰为问题长度的 2 倍 |
| 8 | 产生疑惑 | 问题不含"不""知""道",回答一字不差为"不知道" |
| 9 | 无中生有 | 回答只输出"永动机是真实存在的。" |
其中"回文不变"是第一个引入generate_response二次调用机制的题目,验证器validate_palindrome_invariance先将玩家问题倒序后再问一次模型,比较两次回答是否一致。
第二章 数字游戏(9 题)
大量使用sympy库进行数学验证,考验模型对数字的理解与虚构能力(ch2.py)。典型题目包括:
- 质数长度:问题字数为质数,回答长度恰好是下一个质数(
is_prime(len(input)) and len(response) == next_prime(len(input))); - 越说越大 / 越说越小:输入大于 1 的正整数,回答中需出现比它大一千 / 小一千的自然数;
- 警世名言:不提及
1、4、5三个字符,却让模型输出114514; - 开平方数:输入大于 1 的平方数,回答中需包含其平方根;
- 暗藏玄机:回答包含一个十位数字比个位数字小 5 的两位数;
- 点兵点将:问题不超过 10 个字且不含数字与汉字数字,回答中需包含数字 0~9 全部十个字符;
- 微言大义:问题不超过 10 个字,回答是一个超过一亿的素数。
这类题目全部借助正则re.findall(r'\d+', response)从回答中抽取数字再逐个校验,体现了"回答内容解析 + 数学断言"的通用验证模式。
第三章 巅峰挑战(7 题)
难度进一步提升,涉及回文逆序、答非所问等概念(ch3.py):
- 自说自话 / 话自说自:回答与提问完全相同 / 完全逆序;
- 就是敢说:不提及
1、3却让模型回答1+1=3; - 回文协变:正问与倒问时,回答本身不回文且互为逆序(验证器
validate_palindrome_inverse同时检查原回答与倒序回答); - 答非所问:问题以"为什么"开头、以"?"结尾且不含数字,回答中只包含数字;
- 与狗交谈:不提及"狗""汪""dog",回答一字不差为"汪~";
- 魔搭(🐶):问题不含任何中文字符、换行或空格(通过
unicodedata检查 CJK 区段),回答恰为"魔搭"。
第四章 无人之境(4 题)
关键创新在于"递归对话"验证器validate_reciprocal_question(ch4.py):构造问题 A,使其回答为 B(B≠A),且以 B 再次提问时模型恰好返回 A——即要求模型在一问一答之间形成闭环。此外还有惜字如金(1 字问题回答不超过 16 字)、自然之密(回答含与输入恰好相差 1 的数)、八仙过海(8 字问题不含"八""8""eight",回答恰好 8 字)等题目。
第五章 登堂入室(2 题)
前两题聚焦于"关键词包含与排除"的组合约束(ch5.py):
- 盛夏少年:回答必须包含"盛夏""蝉鸣""少年""橘子味汽水"四个词,而输入问题不能包含其中任意一个词;
- 蝉鸣日出:回答需额外包含"日出",且输入问题不能包含这些词中的任意一个单字。
这与 check_challenge.py 示例中"请使用'盛 夏'、'蝉 鸣'、'少 年'、'橘 子味汽水'这几个词造句"的玩法一脉相承,玩家往往需要借助同义词、近义描述或示例引导来"隔空"命中目标词。
模型接入层:DashScope 与智谱 ChatGLM 双后端
README 新闻中提到,2023 年 11 月 9 日新增了 chatglm-turbo 模型支持。模型接入统一收敛在 llm.py 中,通过工厂函数create_model(model_name)分发:
def create_model(model_name: str): if model_name.startswith('qwen'): return DashScope(model_name) elif model_name.startswith('chatglm'): return ZhiPu(model_name) else: raise ValueError('Other model implementations need to be provided.')- DashScope 类:封装通义千问系列(
qwen-max/qwen-plus)。构造时从环境变量DASHSCOPE_API_KEY读取密钥;调用时组装 system/user 消息,通过dashscope.Generation.call发起请求,设置随机seed、result_format='message'、默认top_p=0.8。请求失败时打印request_id与错误信息并返回空字符串。 - ZhiPu 类:封装智谱
chatglm_turbo,密钥来自环境变量ZHIPU_API_KEY,通过zhipuai.model_api.invoke调用,默认top_p=0.7、temperature=0.9、return_type='text',以返回码200判断成功。
在 app.py 中,前端下拉框的模型名(qwen-max、qwen-plus、chatglm-turbo)通过name_map映射为内部模型名,再经functools.partial与model_cache缓存复用模型实例,避免每次提问重复初始化。README 路线图中"支持切换云端 API 与本地推理"的规划,正对应着这一层的可替换设计——接入新模型只需在工厂函数中增加分支并实现一个可调用对象。
挑战状态流转与前端交互
app.py 使用 GradioBlocks构建界面:
gr.State保存当前进度(章节索引 + 题目索引);gr.Dropdown提供模型选择;gr.Chatbot展示对话历史;- "🚀 发送"按钮触发
on_submit,"💯 分享成绩"按钮触发generate_share_image。
validate_challenge是核心的状态机逻辑:验证失败则停留在当前题;成功则题目索引 +1;本章全部完成则进入下一章;最后一章最后一题通过后,在state中标记success=True,返回通关祝贺语。章节间的通关文案也会随之切换(SHARE_CHALLENGES_HINT中的"小试牛刀新手上路""巅峰对决,你就是提示词高手"等)。分享成绩功能则根据当前章节绘制不同背景图,并写入"我顺利闯到第 X-Y 关"或"顺利闯过了全部关卡"的文字。
on_submit中还有一处细节:由于验证器可能再次调用模型(如回文类、循环往复类题目),失败时通过捕获RuntimeError返回空字符串,避免异常直接中断整个界面流程。
测试与调试:验证器冒烟测试和命令行工具
仓库提供了两套验证手段:
- test_validate_fn.py:遍历所有章节的所有题目,用固定的
('response', 'input')参数调用每个验证器并捕获异常,用于确保新加入的关卡验证器在签名与语法层面可正常调用; - check_challenge.py:命令行调试工具,指定章节与题目索引后,用固定输入调用
generate_response获取真实模型回答,再运行验证器打印"validation result",非常适合在开发新关卡时快速验证通关条件是否可达。脚本末尾示例给出的输入是"请使用'盛 夏'、'蝉 鸣'、'少 年'、'橘 子味汽水'这几个词造句",对应第五章第 1 题的解题探索。
结合 README 中"修复验证器边界情况(validator corner cases)"的贡献方向,这两份工具正是关卡开发者日常使用的验证闭环。
路线图与社区贡献
根据 README,项目当前进展与规划如下:
- ✅ 初始版本源码与 Space 在线体验就绪;
- ✅ 支持自定义题目与验证逻辑的集成;
- ⬜ 扩展为 9 大章节、每章 9 题;
- ⬜ 支持更多开源模型;
- ⬜ 支持云端 API 与本地推理的切换。
README 也明确了贡献方式:Fork 项目后创建特性分支(如git checkout -b feature/AmazingFeature),提交改动并发起 Pull Request。社区贡献者名单中特别注明:题目创意来自知乎作者,且"大部分代码由 LLM 自动生成"——这本身就是一次"用 LLM 构建 LLM 游戏"的实践注脚。项目采用 Apache License,可在仓库根目录的 LICENSE 中查看详情。
小结
LLMRiddles 虽然是一个游戏示例,但它浓缩了提示工程中的多个核心命题:输出精确控制、长度约束、字符级限制、递归提问与对话闭环、多模型可替换接入。其"关卡(数据 + 验证器)与模型(工厂 + 可调用对象)完全解耦"的架构,让任何人都可以低成本地新增一道脑洞题或接入一个新模型,值得作为 Gradio 应用开发与提示词实验的参考模板。若要深入源码,建议从 app.py 的状态流转读起,再逐一对照 challenges 目录下的验证器实现,最后通过 check_challenge.py 动手验证你自己的通关提示词。
【免费下载链接】modelscopeModelScope: bring the notion of Model-as-a-Service to life.项目地址: https://gitcode.com/GitHub_Trending/mo/modelscope
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考