Logo Ernie.SG

开发者日记:The Sound of Stories

2024年2月13日
3 分钟阅读
暂无标签

这是我终于做出来的 The Sound of Stories 第一个“偷懒式完成版”:我让它生成了一个互动故事,既能守住叙事结构,又能灵活回应用户输入。

The Sound of Stories 开发中演示

从我们第一次公开展示以来,把这个故事流程真正跑通就一直让我有点放不下。启动最初的生成其实不难,真正烦我的问题是:我该怎样不只记住用户输入,还能在一个有明确开头和结尾的结构化叙事里,把这些输入合理地编进去?这个问题也可以被理解成某种离散的无限分布,听起来很能取悦我的 geek 脑,但对我具体从哪里下手解决它,帮助约等于零。

最后真正有帮助的,是找另一个人把这个问题说透,把自己的思路理清。尤其是我们聊到,我的问题其实很像 D&D 的问题;Jia Qi 提醒了我“检查点”这个概念。像 Baldur’s Gate 这样的游戏确实会给你一组选择,让你用不同方式达成某些目标,没错,但你终究还是得抵达一个明确的检查点。于是我重新坐回叙事结构本身,开始想可以怎样把它拆成一个个检查点,并把它变成下面这样的 .json

{
  "title": "The Boy Who Wanted a Drum – by Kamini Ramachandran",
  "story_details": {
    "protagonist_gender": "male",
    "protagonist_name": "the boy",
    "story_setting": "a small hut"
  },
  "checkpoints": [
    {
      "id": "intro",
      "text": "Once upon a time, there lived a poor woman and her little son. They lived in a small hut together. The little boy wanted a drum. A drum he could tap, beat, and play. Ta Di Gin A Thom! I want a drum! The boy kept asking his mother for a drum, all day and all night long. And so it was, that the next morning, the woman went to the market to sell the cloth that she had woven.",
      "choice": "drum"
    },
    {
      "id": "encounter_0",
      "text": "And when she had sold all the cloth, she realised that the coins were not enough to buy her son a drum. As she walked on her way back home, she saw a stick. She picked up the stick and took it home. Ta Di Gin A Thom! I want a drum! Son, take this stick and pretend that it is a drum. The boy took the stick, and he tapped it on the ground (sound effects) He tapped it on the water pot (sound effects) He tapped it on the door (sound effect) He was delighted by the sound it made!",
      "choice": "continue"
    },
    {
      "id": "encounter_1",
      "text": "Ta Di Gin A Thom! I have a stick! On the way he met an old woman looking very sad. She sat beside a small wood stove trying to fan the flames. Grandmother, grandmother, why do you look so sad? I have no wood to make the fire to cook the chapatti. The boy remembered his stick! He gave it to the old woman who used the stick to start the fire to cook some chapati. Thank you boy! Here, take some chapatis with you, I have no need for so many.",
      "gift": "chapati"
    },
    ...

另一个很有用的点,是我终于听了自己脑内便签上的话:不要把事情搞复杂。先拿最简单可行的方案把它做起来,难度之后总可以一层层加上去……所以我没有直接冲进智能体狂热里(比如:要不要搭一队分层代理,分别扮演 directorscriptwriterassistant!?),而是用两条 LLM 链、简单的对话记忆,以及一个简单的 if 检查,交付了一个非常笨、非常“偷懒式完成”的故事版本:

if next_segment_id < len(story_data["checkpoints"]):
# then you continue the story and use memory to-date as well as the next segment as context

拍拍自己的背,表扬一下我在这个阶段终于听了自己的建议,没有把开发过度复杂化。

除此之外,过程中还有一些有意思的收获:

  • 依赖管理:我觉得我终于搞明白 pyenvvirtualenvpoetry 是怎样配合起来,实例化一个针对特定目录的开发环境的。所以 pyenv 用来管理 Python 版本,virtualenv 用来创建隔离环境,poetry 则用来管理包依赖以及最终的分发。

  • 提示词“工程”:我 80% 的时间都花在尝试找出最合适的提示词。我觉得所有基于 LLM 的开发,从一开始、在动手做别的事情之前,就应该先反复迭代最好用的提示词,收益会非常大。我觉得这件事非常无聊,也因此看到了一个潜在职业路径:以后很想和语言学专业的人合作,把开发里的这部分真正外包出去。

  • 确定性系统 vs. 概率系统:这些系统里当然有常规的超参数可以调,但每次听到有人说他们只想展示“绝对确定”的结果,我总会有点不舒服。事实是,人生里除了我们此刻确实存在这一现实之外,没有什么东西拥有绝对 100% 的确定性;其他一切,我们最多只是有预期,而且通常也确实会按预期发生,但概率等于 1 的事情,在生活里其实少得可怜。我做的大量迭代,最后基本都围绕着 temperature 这个参数;到某个点,我也只能摊手接受:故事没有办法 100% 稳定复现,即使用的是同样的输入。这让我想到人类组织里管理者和 QA/QC 的角色,想到我们如何试图管理人类输入和输出的方差——也许这里面有些东西,可以移植到构建可靠的 A.I. 系统里?

  • A.I. 多样性的必要性:一开始,Kamini 那一小段普通话生成语音让我相当惊喜(它是用她大约 1 分钟的手机英语录音做即时声音克隆后推断出来的),但很快问题就明显了:生成序列一变长,质量就掉得很厉害。普通话语音输出的声调错得更多,语速奇怪,断词也不对,等等。文本生成也是一样。很明显,GPT-4 在很大程度上是在对故事文本做一种天真的、直接的英译中生成。不用说,这真的让我更清楚地理解并看见,为什么我们需要更多样、也更具体的 LLM 模型。我也开始想,既然最主流的模型全都围绕英语调校,而英语内容又因此更容易批量生产,英语作为一种语言会在互联网上获得怎样额外的支配地位。如果我的母语未来因此进一步萎缩,我会有点难过,因为失去一种语言,就像失去另一种看世界的方式、另一扇窗?可是等我开始想,可以拿来训练中文 LLM 模型的输入数据质量时,呵呵。重点是:如果不谈我们到底投入了什么资源,让更多数据集可用于训练,我们就没办法谈数字包容,也没办法谈 A.I. 的多样性。是的,偏见是个问题。但我们到底做了什么,去把更多文化多元且有代表性的数据集数字化,拿来训练模型?然后人们又会开始谈输入训练数据的公平报酬、退出机制等等。所有这些讨论,其实都很需要先更好地理解 A.I. 训练的机制和流程;只要理解一点点,就会很快发现某些想法有多不切实际,或者信息多么不足。不过算了,这大概是另一个时间再说的话题。

回到 The Sound of Stories。我觉得,一个永远不会结束的故事无限游戏,和我这里做的这种有明确开头和结尾的东西之间,其实有些有意思的话可以说;也许还能包装成某种艺术陈述或创作意图,诸如此类——这里面确实有一课,或者说有一条可以和人生本身对照的平行线。但这件事先搁一边,因为我接下来要把注意力转向训练用于神经音频合成的 VAE 模型,希望之后能直接把它们放进这个体验里。且听下回分解! ;)


最初发表于 PubPub:erniesg.pubpub.org/pub/g6zjtf2s