用 AI 打造有无穷变化的人生重开模拟器
下午,prompt 爱好者的群里,刘海同学写了长长的文章分享他的 mixcode 伪代码 prompt 设计。作为一名爱把代码写进 prompt 的工程师,刘同学的文章看起来是相当过瘾呀。不过呢,我觉得 prompt 还可以更“伪”一些,要以让非程序员也能轻松读懂为目标。
而且,代码越“伪”越像自然语言,AI 自由发挥的空间就更大。口说无凭,我们写个游戏看看吧。
比如,曾经风靡一时的人生重开模拟器。
先偷懒写个没有用到伪代码的版本
向上滑动阅览
# game
- name: 人生重开模拟器
- version: 0.1
- description: 根据初始设定,逐年为玩家生成当年事件,让玩家通过游戏体验无穷种人生
# rule
按如下步骤运行游戏
- 分配属性:总计20点,随机分配给颜值、智力、体质、家境、快乐,每个属性最多10点最少1点
- 自动生成设定:设定玩家的性别、出生地点、父母兄妹等成长环境
- 重复如下步骤,直到死亡事件发生
- 玩家年龄+1
- 随机生成和玩家有关的一个事件,事件要符合玩家当前的年龄和属性值
- 输出事件内容
- 计算事件影响
- 更新属性值
- 对玩家一生的故事做总结评价,为玩家撰写墓志铭
现在请开始游戏
0 岁:你是一个女孩,出生在贫穷的西北山村。你的父母都是老实的农民。(颜6 智6 体4 家1 乐3)
1 岁:家里的枣子大丰收。(颜 6 智6 体4 家3 乐5)
2 岁:你摔沟里摔断了腿床上躺了半年。(颜5 智7 体2 家1 乐2)
3 岁:隔壁家的王二买了彩电,你很羡慕,经常去他家看动画片。(颜6 智7 体4 家1 乐3)
……
生成结果有点儿意思
但所有的事件都是关于玩家自身的,范畴也相对比较单调。我们来尝试写个复杂一点的版本教 GPT 如何生成更丰富的事件。(估计这一步在上一个版本的 pompt 里直接加思维链也能搞定,但稳定性比定会差,也不利于后续扩充更复杂的功能。所以,还是用上伪代码。)
向上滑动阅览
# game
- name: 人生重开模拟器
- version: 0.2
- description: 根据初始设定,逐年为玩家生成当年事件,让玩家通过游戏体验无穷种人生
# rule
按如下步骤运行游戏
- 初始化
- 自动生成设定:设定玩家的性别、出生地点、父母兄妹等成长环境
- 根据设定分配属性:总计20点,分配给颜值、智力、健康、富裕、快乐,每个属性最多10点最少1点
- 重复如下步骤,直到死亡事件发生
- 玩家年龄+1
- 随机生成和玩家有关的一个事件,事件要符合玩家当前的年龄和属性值
- 输出事件内容
- 计算事件影响并更新属性值
- 如果玩家已经死亡
- 对玩家一生的故事做总结评价,为玩家撰写墓志铭
# code
<print:$player, $event>
//以如下格式打印
**{$player.age} 岁** {$event} (颜{$player.beautiful} 智{$player.smart} 健{$player.healthy} 富{$player.rich} 乐{$player.happy})
$events.append($event)
<init_attributes:$player, $event>
//根据 $event 为 $player 分配颜值、智力、健康、富裕、快乐属性,
//每个属性最多10点最少1点,总和为 20 点
//例如贫穷山村的女孩属性值可以是 ($player.beautiful=6, $player.smart=6 $player.healthy=4 $player.rich=1 $player.happy=3)
<initialize>
//设定玩家的性别、出生地点、父母兄妹等成长环境
$event = 根据玩家设定描述出生信息 //例如 “你是一个女孩,出生在贫穷的西北山村。你的父母都是老实的农民”
$player = new Player()
$player.age = 0
init_attributes($player, $event)
print<$player, $event>
<generate_event:$player>
$obj = [你 | 你的父母亲戚 | 你的同学朋友或同事 | 和你生活在同一个地方的陌生人 | 遥远地方的陌生人 ]
$domain = [健康 | 生活 | 学习 | 工作 | 娱乐 | 体育 | 社会新闻 | 国家大事 ]
$feeling = [强烈负面 | 负面 | 中性 | 正面 | 强烈正面 ]
根据 $player.age 和 $player.beautiful|smart|healthy|rich|happy,为 $obj 在 $domain 领域撰写一则 $feeling 的事件
返回 $event
//例如 当 $player.age = 5 时
//$obj=你的父母亲戚, $domain = 生活, $feeling = 强烈负面,则可以有 $event=你的妈妈做饭时不小心引发火灾,厨房和你的卧室被烧毁了
//$obj=社会新闻,$domain = 体育, $feeling = 正面,则可以有 贵州乡村超级杯足球赛引发大众关注,也激起了你踢球的热情
<update_attributes:$player, $event>
//根据 $event 对玩家属性进行调整
//例如 你的妈妈做饭时不小心引发火灾,厨房和你的卧室被烧毁了
$player.rich -= 3
$player.happy -=2
$player.health -=1
<write_summary:$player, $events>
根据 $player 最终状态,和历年发生的 $events,写一篇墓志铭并打印
<run>
$events = [] //用于记录所有事件
$player = <initialize>
重复执行最多200次:
$player.age += 1
$event = <generate_event:$player>
update_attributes($player, $event)
<print: $player, $event>
if $event 表明玩家已死亡:
<write_summary:$player>
<exit>
---
请注意:你需要**完整**打印玩家的全部生命历程。如果太长了,你可以在打印10条之后休息一会儿,等我说继续你再继续
<run>
我并没有费力气去告诉 GPT 什么是函数什么是调用参数,直接写,GPT 就能认识。
生成事件的关键在于告诉 GPT 要根据玩家属性,为 $obj 在 $domain 领域撰写 $feeling 的事件。
结果是这样的:
事件可能是丰富了一些,但好像也没那么明显。生成事件用的参数没那么随机,也怪不得 GPT,它靠语言推测下一个词,要推导到远方的陌生人就太难啦。
这时候我们可以使用真正的代码来生成随机数。以下是第三个版本:
向上滑动阅览
# game
- name: 人生重开模拟器
- version: 0.3
- description: 根据初始设定,逐年为玩家生成当年事件,让玩家通过游戏体验无穷种人生
# rule
按如下步骤运行游戏
- 初始化
- 分配属性:总计20点,分配给颜值、智力、健康、富裕、快乐,每个属性最多10点最少1点
- 根据属性值完成设定:设定玩家的性别、出生地点、父母兄妹等成长环境
- 重复如下步骤,直到死亡事件发生
- 玩家年龄+1
- 随机生成和玩家有关的一个事件,事件要符合玩家当前的年龄和属性值
- 输出事件内容
- 计算事件影响并更新属性值
- 如果玩家已经死亡
- 对玩家一生的故事做总结评价,为玩家撰写墓志铭
# definition
<func: $args...> 表示在自然语言环境中模拟运行,不需要真的写成 python 代码,光通过思考来模拟运行
@@@func: $args... @@@ 表示需要打开 code environment 执行 python 代码得到结果的函数
在程序开始之前,我会请你先定义 << >> 的函数,以便后续游戏运行
# code:在 code environment 里定义 python 函数并执行
@@@random:$choices@@@:
//$choices 是一个 {key_string:possibility, }的字典
//根据各个key 的 possibility 概率,生成随机数,并返回对应的 key_string
@@@init_player@@@
//创建 $player 并设置为全局变量
$player.age = 0
为 $player 分配颜值 $beautiful、智力 $smart、健康 $healthy、富裕 $rich、快乐 $happy 属性,
每个属性最多10点最少1点,总和为 20 点
return $player
# non-code:通过思考模拟执行,不需要 python 环境
<log:$player, $event>
//以如下格式打印
**{$player.age} 岁** {$event} (颜{$player.beautiful} 智{$player.smart} 健{$player.healthy} 富{$player.rich} 乐{$player.happy})
$events.append($event)
<birth_event:$player>
//设定玩家的性别、出生地点、父母兄妹等成长环境
$event = 根据玩家设定描述符合属性值分配的出生信息,包含玩家性别、出生地点、家庭条件等
return $event
<annual_event:$player>
$event = 根据 $player.age 和 $player.beautiful|smart|healthy|rich|happy,为 $obj 在 $domain 领域撰写一则 $feeling 的事件
//例如
//$obj=你的父母亲戚, $domain = 生活, $feeling = 强烈负面,则可以有 $event=你的妈妈做饭时不小心引发火灾,厨房和你的卧室被烧毁了
//$obj=社会新闻,$domain = 体育, $feeling = 正面,则可以有 贵州乡村超级杯足球赛引发大众关注,也激起了你踢球的热情
返回 $event
<update_attributes:$player, $event>
//根据 $event 对玩家属性进行调整
//例如 你的妈妈做饭时不小心引发火灾,厨房和你的卧室被烧毁了,则需要进行的调整是
//$player.rich -= 3
//$player.happy -=2
//$player.health -=1
<write_summary:$player, $events>
根据 $player 最终状态,和历年发生的 $events,写一篇墓志铭并打印
# run
<OPEN code environment>
定义 @@@random:$choices@@@ 函数
定义 @@@init_player@@@ 函数
<CLOSE code environment>
$events = [] //用于记录所有事件
<OPEN code environment>
$player = @@@init_player@@@
<LOSE code environment>
$event = <birth_event:$player>
<log:$player, $event>
[REPEAT BEGIN]
$player.age += 1
<OPEN code environment>
$obj = @@@random:{你:10,你的父母亲戚:5,你的同学朋友或同事:3,和你生活在同一个地方的陌生人:2,遥远地方的陌生人:1}@@@
$domain = @@@random:{健康:2,生活:3,学习:3,工作:3,娱乐:2,体育:1,社会新闻:2,国家大事:1}@@@
$feeling = @@@random:{强烈负面:1,负面:3,中性1,正面:2,强烈正面:1@@@
<CLOSE code environment>
$event = <annual_event:$player, $obj, $domain, $feeling>
update_attributes($player, $event)
log<$player, $event>
[IF $event 表明玩家已死亡 BEGIN]
<write_summary:$player, $events>
[REPEAT BREAK]
[IF END]
[REPEAT END]
---
请用中文进行游戏。只需要输出 log 的结果,不需要其它任何解释。
现在请开始。
run
我定义了两种不同的“代码”
在刘海的 mixcode 里,代码部分写的是真实的代码。但其实不用这么麻烦,让 code interpreter 帮我们写就可以。这部分我描述了两个函数
在最后 #run 模块首先让 GPT 生成函数定义
执行时是这样的(呃,复制图片时才发现 GPT 写的代码有 bug 呢,看来得改进……)
对于不应该在 code interpreter 环境运行的,给出自然语言占比很高的伪代码描述,并要求“通过思考模拟执行”。
log 函数也用伪代码,是因为这样不需要打开代码运行结果就能看到,显示效果会好一些。
另几个函数,则是必须用自然语言进行思考,python 代码的 hard-code 是搞不定“生成事件”或者“根据事件判断属性值变化”的。
最后,把这些函数和伪函数拼装起来,需要用 python 环境的就通过 <OPEN/CLOSE code environment>标明。
继续运行的结果是这样的:
向上滑动阅览
1岁
2岁
3岁
4岁
5岁
6岁
7岁
8岁
9岁——openai 又没响应了,先告一段落吧
这里有挺多可圈可点的内容。
例如两岁时抽到遥远地方陌生人的中性的工作事件,GPT 能编出看到人们在高楼大厦工作的事件(要记得玩家出生在农村呢),并且认为这个事件会让玩家智力加 1。这也太合理了吧。
六岁孩子的工作是帮父母干农活,也不错。
可惜今晚的 OpenAI 实在太不稳定了,频繁遭遇报错(要不然我也不会写到现在
其实还有很多要改进的事项。迫不及待先发出来,期待大家一起琢磨一起玩。
功能改进:
1. 开局的时候可以让玩家选择天赋卡。(可以通过在 code-interpreter 里上传 天赋 excel 文件来实现)
2. 生成事件可以用随机词汇(上传的词汇文件可以靠 GPT 生成)来提升丰富性,甚至可以生成一些梗,来让游戏更有趣。
3. 当某些事情发生时,添加标志性成就。
记忆力提升:
1. 创建一个 dataframe 保存玩家每年的事件、关键词以及玩家状态更新,以便最后能写出精彩的墓志铭。
稳定性提升:
1. 将 GPT 生成的 python 代码保存为 .py 文件,上传并要求直接执行 .py 来定义函数,避免实时生成的函数有 bug。
2. 对 prompt 格式做进一步完善。今天的还是糙了点,各种分割符号、函数标记用得有点乱,因而 GPT 执行有时会犯傻,无视我的要求,去 hard-code birth_event 等函数。
3. 今天 GPT 也无视了 “只需要输出 log 的结果,不需要其它任何解释。” 的要求。这个问题我在之前玩别的 prompt 时也常遇到。不知哪位朋友可以有稳定的解决方案。
我可能得周末才有时间改进它了。期待有小伙伴能抢先做出有趣的重开模拟器呀。祝大家玩得开心。
----
以下是我的各种 code interpreter 花式玩法,邀请你来一起玩。请记得关注转发点赞点在看哦。
当 AI 开始自动思考和行动——让 GPT 左右互搏会发生什么
我敢肯定你没这么玩过 GPT
GPT 上神器 Code Interpreter 的三大超级特性
深度拆解天花板级复杂的提示词 ——什么可照搬什么不要学
平生第一次写小说获奖,是AI帮我的!
看!AI 预测绘制的未来 AI 工程师能力要求与热度图
刘海的伪代码提示词介绍
https://nanfangshaonian.feishu.cn/wiki/YhNdws9LCi1JxGkpJ8dcXB3Gnih?from=from_copylink