运行时架构
了解分层的 Convai Unity SDK 运行时——每一层负责什么、单个角色的具身层,以及运行时生命周期状态如何管理。
Convai Unity SDK 分层构建。每一层都有明确的职责,并向内通信——外层依赖内层,绝不相反。理解这种结构能让你知道 SDK 的哪些部分面向开发者、哪些可以替换,以及哪些是你无需触碰的内部实现细节。
系统层
下图展示了主要层级及其相互关系。 ConvaiRuntime 在第二层持有四个直接子系统—— IRoomRuntime, IEventHub, IAgentRegistry,以及模块列表。角色和玩家显示在 IRoomRuntime 和 IAgentRegistry之下。运行时级功能模块共享一个公共模块上下文;携带具身模块的角色还会获得自己专属的按角色组成根。
ConvaiRuntime (顶层) ——拥有所有子系统并协调完整生命周期。通过以下方式在应用生命周期内仅创建一次: ConvaiRuntimeBuilder。公开启动、暂停、恢复和停止操作,并将其传播到所有已注册模块。它持有四个直接子系统:
IRoomRuntime——管理实时会话:连接、断开、音频路由、角色所有权和诊断。角色和本地玩家在此层之下显示。IEventHub——用于整个 SDK 中跨系统通信的解耦发布/订阅总线。IAgentRegistry——所有处于活动状态的ConvaiCharacter和ConvaiPlayer实例的注册表。IReadOnlyList<IConvaiModule>——已注册功能模块的集合。
角色 / 玩家层 — ConvaiCharacter 和 ConvaiPlayer 注册到 IAgentRegistry 并通过 IRoomRuntime接收其按会话上下文。每个角色维护自己的会话状态。携带具身模块——注视、身体动画、肢体语言、对话流程或情绪——的角色还会获得自己的 EmbodimentContext;见下方具身层。
模块上下文层 ——运行时级功能模块(IConvaiModule,例如 LipSync、Vision 和 Narrative)共享一个 IModuleContext ,该上下文提供对运行时服务的访问。模块可以声明彼此模块 ID 和服务之间的依赖,但通过 IEventHub 或注册在 IModuleContext 上的服务进行交互,而不是持有彼此具体类型的直接引用。
运行时接口清单
IConvaiRuntime 公开以下子系统作为属性。每个属性都是特定功能领域的入口点。
State
运行时状态
运行时当前生命周期状态
房间
IRoomRuntime
连接、音频、所有权和诊断
事件
IEventHub
解耦的发布/订阅通信
智能体
IAgentRegistry
所有活动角色和玩家的注册表
模块
IReadOnlyList<IConvaiModule>
所有已注册的功能模块
传输
ITransportProvider
平台特定的实时传输
对话
IConversationProvider
与 Convai 的通信
配置
ConvaiBootstrapConfigSnapshot
不可变的启动配置
运行时偏好设置
IRuntimePreferences
可变的运行时偏好设置
功能变体
IFeatureVariantProvider
功能变体 / A-B 选择
持久化
IPersistenceProvider
运行时拥有的数据存储
遥测
ITelemetryProvider
可观测性和分析
开发者最常与 房间, 智能体,以及 事件 交互。 传输, 对话, 持久化, 遥测,以及 功能变体 可通过 ConvaiRuntimeBuilder.
你可以替换的内容
ConvaiRuntimeBuilder 是运行时在启动前用于组合的流畅 API。每个方法都会返回 this,因此可以链式调用。
下表列出了哪些可替换、哪些仅限内部使用。
传输提供程序
UseTransport()
平台默认值(WebSocket / LiveKit)
会话提供程序
UseConversation()
Convai RTVI 会话提供程序
持久化提供程序
UsePersistence()
PlayerPrefs支持的键值存储
遥测提供程序
UseTelemetry()
无操作遥测
功能变体提供程序
WithFeatureVariants()
静态功能标志
运行时偏好设置
WithRuntimePreferences()
默认值来自 ConvaiSettings
事件总线
UseEventHub()
默认的内存内事件总线
代理注册表
UseAgentRegistry()
默认注册表
最终用户身份
WithEndUserIdentityProvider()
设备 ID 提供程序
终端用户元数据
WithEndUserMetadataProvider()
无
模块
AddModule() / AddModule<T>()
仅限 SDK 功能模块
房间运行时
UseRoomRuntime()
内部的、由 LiveKit 支持的房间
IRoomRuntime 子结构
房间层本身由四个协调器组成,都可通过 IConvaiRuntime.Room.
连接
IRoomConnectionCoordinator
连接、断开、会话状态
音频
IRoomAudioCoordinator
麦克风采集、远程音频播放
所有权
IRoomOwnershipCoordinator
此客户端拥有哪些角色以及焦点在哪些角色上
诊断
IRoomDiagnostics
会话指标、健康监控
在脚本中,你最可能调用的是连接和音频协调器。当场景中有多个角色时,所有权会自动管理。诊断用于性能监控和调试。
模块层
模块是在运行时生命周期内运行的功能扩展。它们接收一个共享的 IModuleContext ,并且可以注册其他模块或呈现层使用的服务。
在 Build() 调用之前,通过构建器添加模块:
模块会随着运行时一起启动、暂停、恢复和停止。 IConvaiModule 接口定义了这些生命周期钩子。使用 RequiredModules声明依赖,运行时会按依赖顺序启动模块,并按相反顺序停止——但模块仍通过 IEventHub 或 IModuleContext.TryGetModuleService访问另一个模块的数据,而绝不会直接引用另一个模块的具体类型。请参阅 扩展 SDK 以获取完整的模块编写参考。
具身层
某个 ConvaiCharacter 携带具身模块——注视、身体动画、肢体语言、对话流程或情绪——的角色都会获得自己的 EmbodimentContext。Convai 在某个具身模块首次在该角色上解析到它时,会自动添加此组件;你永远不会从“添加组件”菜单中手动添加它,而且它自身也没有菜单项。
EmbodimentContext 是按角色的组成根,而不是注册到 ConvaiRuntimeBuilder的功能模块。它公开了所有具身模块接入的共享基础设施:
CharacterRoot
Transform
角色的根变换
EventHub
IEventHub
由 IConvaiRuntime.Events
日志记录器
ILogger
供具身模块使用的结构化诊断
RigBinding
IStandardRigBinding
用于检测到的骨架的语义骨骼和 BlendShape 查找
Character
ConvaiCharacter
所属角色
具身模块—— ConvaiGazeController, ConvaiBodyAnimationController, ConvaiBodyLanguageController, ConvaiConversationFlowController,以及 ConvaiEmotionController ——在 OnEnable 上解析上下文,并向其发布自己的契约,而不是彼此持有直接引用。 EmbodimentContext 触发 RigBindingChanged, EmbodimentConfigurationChanged,以及 DependenciesPopulated ,以便模块在骨架重建、预设切换或运行时依赖首次可用时作出响应。项目自身的组件可以通过 RegisterTickable/UnregisterTickable.
确定性 Tick
具身模块不运行于 Unity 的按组件 Update() 顺序。每个模块都向上下文的 Tick 调度器注册,该调度器会在每一帧中按声明的 认知 → 表达 → 完成 顺序精确地对每个已注册模块 Tick 一次——同一阶段内的先后由注册顺序决定,而不是由层级位置或哪个模块先启用决定。调度器本身从 Update开始 Tick;消费其输出的动画器指挥者和面部合成器随后从 LateUpdate进行,前提是 Animator 已为该帧摆好骨架姿态。
单写入 Animator 和面部 BlendShape
两个基础设施组件通过强制单写入访问,确保两个具身模块永远不会争夺同一输出:
该 动画器指挥者 是唯一调用
Animator.SetFloat及相关方法来处理由具身驱动参数的组件。模块通过它提交命名参数写入,而不是直接触碰Animator;当第二个模块注册一个已经被占用的参数时,会被拒绝,而不是静默覆盖第一个。该 面部 BlendShape 合成器 是唯一向
SkinnedMeshRenderer为具身输出写入 BlendShape 的组件。模块在帧内提交各区域的层权重,而合成器只会在LateUpdate.
这两个组件都会由 EmbodimentContext Convai 与其一同自动提供——将它们以及 EmbodimentContext 它本身视为 Convai 为角色添加的基础设施,而不是你直接配置的内容。
运行时状态 生命周期
运行时会从创建到释放经历以下状态。
已创建
已构建运行时,但尚未启动
Starting
StartAsync() 进行中
运行中
完全运行
暂停中
PauseAsync() 进行中
已暂停
已暂停;可恢复
恢复中
ResumeAsync() 进行中
停止中
StopAsync() 进行中
Stopped
已关闭;无法重启
已释放
DisposeAsync() 已调用;所有资源已释放
所有状态转换都是包装在 IConvaiOperation<Unit>失败。调用前请检查 Status 中的异步操作,并在继续之前在返回的操作上进行确认,以确保转换已完成。
下一步
现在你已经了解 Convai 运行时如何组成,以及每一层中哪些部分可以替换。接下来阅读“会话生命周期”,了解每个角色的会话如何创建、持久化和恢复,然后继续阅读“轮替模式”和“事件系统”。
最后更新于
这有帮助吗?