在Jetson上通过持久流服务本地AI
作者使用NVIDIA Jetson Orin Nano Super和Kokoro-82M模型构建了一个本地文本转语音应用StreamTTS,利用持久流(S2)而非传统请求-响应架构,实现了可共享、可重放的实时音频生成,并解决了慢推理、多用户公平调度和去重等问题。
随着本地AI变得越来越实用,作者希望自托管模型并独立运行工作负载,无需第三方提供商。NVIDIA的Jetson系列是一个很好的起点,作者选择了Jetson Orin Nano Super套件,它拥有1024个CUDA核心和32个张量核心,算力达67 TOPS,足以运行一个由Kokoro-82M模型驱动的小型文本转语音(TTS)应用——StreamTTS。
传统架构通常采用请求-响应模式,但推理速度较慢,且输出是增量式的。如果采用阻塞式请求,多个用户同时提交时会导致排队。作者希望输出结果可分享,用户能立即获得一个链接,并能在生成过程中实时收听。因此,作者选择了持久流(durable streams)作为核心架构。持久流是一种有序的记录序列,每条记录被持久化保存,读者可以随时从头开始回放,或从当前位置跟踪最新产出。
具体实现中,作者使用了开源的S2 Lite作为流存储服务,运行在本地。系统模型通过一系列命名流进行通信:jobs流接收推理请求,pub/casts/流存储每个生成任务的音频输出。工作进程(worker)从jobs流读取任务,运行Kokoro模型生成音频,并将结果追加到对应的输出流中。前端浏览器通过Web Audio API解码并播放每个句子大小的MP3块,支持从任意位置开始播放或实时跟踪。
为了解决多用户公平性问题,工作者进程维护了每个流的播放领先时间(lead),并优先为领先时间最小的流生成下一句音频,确保所有用户都能获得流畅体验。此外,任务ID通过文本和语音的SHA-256哈希生成,结合条件追加操作实现自动去重:相同内容只会被处理一次,后续请求直接返回已有结果。
工作进程还实现了持久消费者模式,通过jobs/_cursor流记录已处理任务的偏移量,支持崩溃后恢复。如果生成过程中工作进程崩溃,重启后会从最近提交的偏移量继续处理,已经完成的任务通过检查输出流中的eos标记跳过。这种设计提供了至少一次交付语义,并通过尝试边界标记处理部分写入的音频。
最终,作者构建的StreamTTS应用托管在streamtts.dev,完全运行在自己的Jetson设备上。整个架构展示了如何用持久流优雅地解决本地AI推理中的慢响应、可重放性和并发调度问题,为类似应用提供了一个简洁的参考方案。