循环
循环和循环控制器是Rivet中最难理解的概念。但它们也非常强大,对于许多使用场景来说是必不可少的。
以下是在Rivet中可以创建的最简单循环:

当前必须连接到Break节点。这为图形提供了一个"起点"以便向后推导。对于基本案例,只需将Graph Output节点连接到Break即可。
循环控制器
循环控制器是Rivet中唯一允许包含节点循环(包括其自身)的节点。其理念是数值会通过循环控制器进行周期性流动。所有在循环中可能变化的数值必须流经循环控制器本身。
输入
循环控制器有一个始终存在的输入Continue。这是一个boolean类型(但传入的值将被强制转换为布尔值)。
如果传入Continue的值为真值(或control-flow-excluded!参见Control Flow),则循环将继续执行。如果值为假值,则循环将停止执行。
接下来,循环控制器具有动态数量的值对。每对包含一个输入和一个默认输入。
默认输入(每对中的第二个!)是可选的。这是通过循环控制器传递的默认值。在大多数情况下,您会将来自循环控制器外部的值传递到循环控制器的默认输入中。这些值充当循环的"初始状态"。
因此,输入端口(每对中的第一个!)的值应该来自循环内部(连接到循环控制器输出端口的节点)。
输出
对于循环控制器的每对输入(不包括Continue端口),循环控制器将有一个额外的输出端口。
在第一次迭代时,此端口的值将是传入循环控制器默认值端口的值。在后续迭代中,此端口的值将是前一次迭代时传入循环控制器输入端口的值。
示例
下图展示了一个循环控制器,其中有两个值在其中流动。初始值为 A 和 B:

A和B的默认值通过循环控制器流向循环控制器的第一个和第二个输出端口。这些值流入两个文本节点,一个追加+ A,另一个追加+ B。然后它们流回循环控制器的相应输入端口。
在第二次迭代时,可以忽略默认值,流程如下所示:

A + A 和 B + B 的值流向循环控制器的输出端口,并返回到文本节点以再次追加 + A 和 + B,然后再次流回循环控制器。
这个循环永远不会中断。如果运行此图表,当循环控制器达到最大迭代次数时将会报错。
使用指南
向列表追加元素
一个常见的用例是在循环过程中不断向某种数组追加内容。由于Array Node默认设置为Flatten,这可以通过使用数组节点将数组的"当前"值与任何附加值连接起来轻松实现。

聊天机器人
假设你想在Rivet中创建一个类似ChatGPT的聊天机器人。对应的流程图看起来会是这样:

循环维护两个状态片段。
- 整个聊天记录减去最后一条机器人消息
- 聊天机器人的最后一条消息
流程大致如下:
- AI的初始消息被传递到第二个输入对的默认值中。这为图表"播种"了向用户展示的初始问题。
- 该值(
Break后的第二个输出端口)被传递到用户输入节点中。这会向用户显示聊天机器人发送的最后一条消息。 - A full message history is constructed, consisting of:
- 之前的完整消息历史记录
- 聊天机器人发送的最后一条消息
- 用户的响应
- This full message history is passed into a Chat Node. This node will return the next message from the chatbot.
- 同时,构建的完整消息历史会被循环回传给循环控制器,形成下一次循环的"完整消息历史"。
- Chat Node 将其响应文本传递到 Prompt Node。该提示节点被标记为"Assistant"作为用户,以便聊天机器人能区分每条消息的发送者。
- AI的这条聊天消息响应被传递到循环控制器节点第二对的值中。
- 循环继续
有时候可能难以理解循环的流程以及如何正确连接它。最好的理解方式是通过实际操作并观察会发生什么!