现在的大语言模型代码写得游刃有余,大语言模型的上下文虽然不长,很多时候也不太聪明,但是我们却可以使用工程手段让大语言模型能够完整理解一个项目。

大语言模型的核心在语言上,自带写小说先天优势,如果将AI写代码的那种工程手段用在写小说上呢?

架构设计

AI写项目时并不是上去就开始硬写的,是先安排任务,然后写。遇到上下文太长不好改的地方还会调用一个小模型去想办法把写的东西插进去。

聊天上下文太长了后会摘要,信息不足时Agent会调用工具。

于是,我们写小说也是重在由上到下,先规划大纲,然后逐步往下,最后才是写小说内容。

但我们不会到Agent调用工具这种程度,因为这对于写小说来说太高级了。

生成小说我们遵循下列流程

  1. 通过与AI聊天的形式,确定小说的各种设定、大概内容方向。

  2. 自动生成主角团。

  3. 生成章级大纲。

  4. 逐章生成节级大纲。

  5. 逐节生成内容。

  6. 摘要内容、提取伏笔。

其中第4步后面是循环的,在循坏时上一节的摘要会被携带到下一节生成时,以便连贯。

每个小说会维护一个全局的伏笔表,每次提取的伏笔会被管理起来,伴随后续的生成。

于是我们发现,生成小说是一个线性过程,也不用用上什么高级的大语言模型架构技巧。

上述的步骤两个技术点就能搞定:

  • 文本输出(最基本的)

  • 单工具调用

单工具调用

在很久以前,Agent的概念还没有的时候,我就想让AI去调用工具,但是成功率比较感人,Json格式都输出不对。

但现在的大语言模型应该都有做过这方面的训练,进行简单Json输出调用工具还是很好做的,模型很聪明。

一定要给示例,这是让大语言模型稳定输出的必要条件。就像我们看库文档时希望能有代码直接复制一样。

如这个提示词,是用于跟用户交互采集信息的:

现在需要与用户交互式交换一些信息,请你正常与用户聊天进行询问,在你认为信息获取的足够了后,与系统交互,结束交互对话。

结束对话前请先总结并询问用户所采集的信息是否正确,得到用户的确定后结束系统交互。

这是一个相当简单的工作,请减少没必要的思考过程,不需要询问要求以外的其他任何东西。


一旦你决定结束交互对话,请输出`{`开头的不包含xml标签的JSON数据与系统交互。


<examples>
    <example>
    好的,我记住你喜欢的动物了。
    {
        "success": true,
        "data": "用户喜欢的动物如下:\n- 小猫\n- 小狗\n- 海豚"
    }
    </example>
    <example>
    明白了。
    {
        "success": true,
        "data": "用户认为应该这样做。"
    }
    </example>
    <example>
    好的,那就不打扰你啦。
    {
        "success": false,
        "data": "用户拒不配合信息采集工作。"
    }
    </example>
    <example>
    提倡和谐语言,共建文明社会。
    {
        "success": false,
        "data": "用户发表不雅言论。"
    }
    </example>
</examples>

先只做一步对话,不要考虑整个流程。

还有纯工具的:

现在你需要帮助系统从用户输入中提取结构化信息。

请不要编造或猜测任何信息,如果需要提取的任一信息不存在或内容无效(如暂无),请直接返回失败。

需要提取的内容有 {keys}

请输出`{`开头的不包含xml标签的JSON数据与系统交互。
提取的结构化信息都作为字符串返回。

<examples>
    <example>
        <input>
        需要提取的内容有 `年龄`、`姓名`、`爱好` 
        </input>
        <output>
        {
            "success": true,
            "data": {
                "年龄": "22",
                "姓名": "孔大王",
                "爱好": "打篮球、跳舞、刷视频、吃甜食"
            }
        }
        </output>
    </example>
    <example>
        <input>
        需要提取的内容有 `最喜欢的人`、`衣服品牌`、`是否对猫过敏`、`年龄` 
        </input>
        <output>
        {
            "success": true,
            "data": {
                "最喜欢的人": "小溪酱",
                "衣服品牌": "耐克",
                "是否对猫过敏": "否",
                "年龄": "13"
            }
        }
        </output>
    </example>
    <example>
        <input>
        需要提取的内容有 `最爱吃的东西`、`姓名`、`讨厌的天气` 
        </input>
        <output>
        {
            "success": false,
            "data": "信息未提及讨厌的天气、姓名"
        }
        </output>
    </example>
</examples>

伏笔管理

伏笔直接存储在一个非结构化的markdown文件中了,用一次读一次。

每次生成完一节,会提取伏笔,提取新的伏笔、根据已有的伏笔提取收回的伏笔,生成一个结构化的数据,描述哪些伏笔收回了,哪些伏笔是新增的。

{
    "新伏笔": [
        {
            "原句": "你的‘锚点’理论,我略有耳闻。",
            "类型": "暗示性台词",
            "等级": "强",
            "指向": "魔法派系拥有获取科技联盟机密情报的渠道,可能存在间谍或魔法侦测手段。"
        },
        {
            "原句": "魔法是世界的意志,科技是世界的规律。意志与规律,从来都不是对立的。它们只是同一位神明左手与右手罢了。",
            "类型": "暗示性台词",
            "等级": "强",
            "指向": "魔法与科技的本质是统一的,它们源于同一个更高层次的存在或法则,这可能是解决两大阵营冲突的关键。"
        },
        {
            "原句": "评议会想把她当成变量来研究,雷哲那样的激进派想把她当成威胁来消除,他们都错了。",
            "类型": "暗示性台词",
            "等级": "中",
            "指向": "科技联盟内部存在不同派系(评议会、雷哲派系),他们对星璃的态度和目的各不相同,主角将同时面对来自内部的复杂压力。"
        }
    ],
    "回收伏笔": [
        {
            "content": "星璃就是那片海,而你,林诺,就是她的岸。",
            "potential_future": "月婵的到来是一个催化剂,旨在促成林诺与魔法派系之间,或科技与魔法之间一次必要的、命中注定的融合或理解。“窗”是林诺封闭的世界观,“风”是星璃和月婵的影响。"
        },
        {
            "content": "然后转身,再次像一滴墨水融入清水般,悄无声息地消失在门口。",
            "potential_future": "星璃拥有空间传送或维度穿越的能力,其来源和原理是关键谜题。"
        },
        {
            "content": "星璃的力量太纯粹,也太强大,她需要被引导,而不是被禁锢。",
            "potential_future": "星璃的魔法力量与她的情感状态或周围环境的情感状态存在直接关联,这可能是她力量的核心机制。"
        },
        {
            "content": "在狂暴的能量场中,投入一个与之频率完全相反的、绝对稳定的‘锚点’,就能平息风暴。你以为,这个理论只能用在你的机器上吗?",
            "potential_future": "“普罗米修斯”计划的核心存在巨大的失控风险,星璃的介入可能成为引爆点,导致一场科技与魔法冲突的灾难。"
        }
    ]
}

我原本是想用一个程序管理的,但是感觉设计上有点儿困难。

于是,我选择将上面生成的数据再丢给另一个AI,让它去根据这段信息重新生成一次非结构化伏笔文件,同时提供给他小说全局信息,让他安排一下计划回收的章节。

因为我并没有系统学过写小说而且也没有正式写过小说,我发现生成小说的时候记录的伏笔数量能达到30个。感觉里面包含的信息是比我预料的丰富的。

角色/团体管理

重要的角色应该有角色设定,我认为各个小配角也应该给他们设定的,于是除了最开始生成角色档案,生成大纲时,如果里面的出场角色包含了没有的角色,也会执行生成角色的过程。

由于章/节大纲里面包含了出场角色,所以在生成内容之前可以简单地将里面的角色信息提取出来作为上下文。

成本

10万字的小说,用了1.4M Token,12.5元。

发布

我发现一个问题,各个平台严格限制发布数量。

于是,任凭AI写的快,我也不能快快地发···

总结

大的安排依赖于从上到下的大纲生成。

小的细节依赖于伏笔的传递。

但我认为还有一些问题。

  • 伏笔传递的信息有限,可能会有割裂感。

  • 伏笔管理成本有点高。

后续我希望可以做到:

  • 角色设定会随着故事发展变化,添加一些额外信息。

  • 出现的每一个实体(角色/团体...)都有自己的设定,并且会像上一条一样处理。

  • 多模型,降本增效。

我能想到的,最大的成功就是无愧于自己的心。