实时AI文本工作流核心:RelayRouter消息路由与低延迟流式架构 1. 题外话别把实时AI想成“带画面的聊天”这两年被“实时AI”这个词轰炸得有点麻木大部分宣传片里都是用户在跟一个虚拟人脸视频通话助手不仅听得懂还能实时生成表情回话。看得多了很多人下意识觉得“实时AI”就等于“把聊天变成视频”。但我在实际折腾后台工作流时越来越确信实时AI的核心不是画面而是低延迟的请求-响应循环。视频、语音、AR面具都是这个循环的不同出口可在文本工作流里实时AI同样成立而且更有工程味道。我为什么会关注到这一点因为手里正在做的一套文本生成服务要求做到“用户敲完半句话模型就开始补全下一位”整套链路不需要任何视频也不需要语音合成只需要极快地接收流式token、做路由判断、再把结果回灌到上游。这里面真正卡脖子的不是模型本身而是消息路由。一次不合理的路由可能让整个实时体验从“跟真人对话”退化成“发帖等审核”。这也是我研究Gemini Live Avatar那套交互逻辑之后回过头来把重心放在RelayRouter上的原因。这套经验适合谁适合正在做聊天机器人、实时写作助手、自动化文本代理的开发者也适合对“流式AI架构”感兴趣、想搞清楚实时AI到底吃什么硬件、拼什么软件的同学。今天我尽量把架构、路由、流式链路、坑位一次讲透不绕弯。2. 从Gemini Live Avatar看“实时”到底实时在哪2.1 真人级对话体验的四道关卡Gemini Live Avatar最惊艳的地方是它把“电视新闻主播式”的互动搬到手机上。但拆开看它跟普通ChatGPT语音模式没有本质区别都是在解决四件事听到、听懂、想好、说出。听到麦克风低延迟采集噪声抑制断句切分。听懂流式ASR自动语音识别在说话过程中就出中间结果而不是等你说完。想好LLM边收边出以token流的形态预测回复。说出TTS流式合成第一个音节在LLM输出第一个完整词后就能合并。这四步之间任何一步出现超过200毫秒的延迟人就会觉得“卡”。实测里Avatar能稳定压在1秒内出首字靠的不只是模型快更多是靠每个环节都在流式工作。这提醒我一件事实时AI从来不是一个模型的事而是一整条流水线的协同。2.2 视频只是其中一种输出模态Gemini Live Avatar之所以给人一种“颠覆感”是因为它把输出从声音扩展到视频。但它的输入输出通道设计和文本聊天其实是共用的同样的思维链、同样的记忆管理、同样的上下文拼接只是最后把token渲染成表情和音频。打个比方实时AI是一台发动机视频是跑车外壳语音是喇叭文本则是仪表盘。你不能因为外壳最抢眼就以为发动机是给外壳造的。放到工程语境里如果我只需要文本通道我完全可以用那套“实时”的内核把输出模态换成一个Markdown流这正好是RelayRouter的机会它负责在正确的时间把文本token送到正确的处理节点。2.3 文本工作流才是实时AI最普及的场景视频对话听着酷可真正每天被调用几千次的实时AI场景反而是文本代码补全、会议纪要实时润色、客服实时推荐回复、写作助手边写边补。这些场景对画面没有需求对“延迟”和“路由正确性”却极其敏感。举个例子我用过一个内部的知识库问答助手用户提问后如果路由层先去调一堆不相干的插件再返回答案整体体验会特别“笨”。后来我把路由策略改成“先做意图分类再做工具挑选”首token时间从1400毫秒降到600毫秒。这个优化对视频场景无所谓对文本工作流却是生死线。3. RelayRouter到底是个什么层3.1 我们得先承认LLM本身不擅长“决定下一步该干嘛”纯LLM擅长的是续写也擅长根据指令输出结构化内容但让它自己决定该调用哪个工具、该跳过哪些插件、该把哪段上下文先送入窗口它经常犹豫或出错。现实中我们要么用Agent框架要么在代码里写硬路由可两者都有问题Agent框架太黑盒硬路由太僵硬。RelayRouter的定位刚好落在这两者之间一个显式的、可观测的、面向流式消息的路由层。它不替代模型也不替代业务逻辑它只回答三个问题这条消息要去哪它需要带哪些上下文它要优先被谁消费在文本工作流里回答完这三个问题实时性就有了骨架。3.2 RelayRouter的四大核心能力我基于自己搭过的路由层把RelayRouter的核心能力拆成四块这也是你在选型或自建时最重要的参考维度消息归一化把不同来源WebSocket、HTTP回调、Message Queue进来的文本统一成一个内部消息结构。策略路由基于规则、意图识别结果、context变量把消息派发到不同处理器。流式转发不缓存完整响应而是在接收模型token的同时转发下游实现端到端流式。回退与熔断下游处理器超时或报错时自动走备用路径而不是让整个请求失败。这四块能力听起来不难但拼在一起要稳、要低延迟、要可观测工作量非常大。RelayRouter的价值在于它把这个层做成标准件让我不用每次重写。3.3 为什么不是“直接用消息队列”有人会问Kafka、RabbitMQ不也能路由吗确实能但那是为异步持久化设计的。实时文本工作流的特征是消息生命周期短、延迟敏感、需要感知流式增量。传统MQ先落盘、再消费的模式在首token延迟上就输了。RelayRouter这类轻量路由层更适合直接嵌在应用进程或旁路进程里优先保证毫秒级转发而不是保证“消息永不丢失”。在实时场景偶尔丢一条中间态消息远好过让用户多等半秒。4. 手把手搭一套基于RelayRouter的实时文本工作流4.1 目标场景设计为了把话题落地我设计了一个具体场景做一个“实时技术文章助手”用户在编辑器里敲一句titel系统自动把标题补全成摘要和关键词列表并在用户继续输入时增量修正。整个工作流的步骤是前端把用户敲击的文本通过WebSocket推给中继服务。中继服务用RelayRouter接收消息。RelayRouter做意图判断决定是调用标题生成模型、摘要模型还是关键词提取模型。每个模型结果统一从RelayRouter流式返回前端。这个场景不需要视频不需要语音但你能清清楚楚看到“实时AI”的芯。4.2 消息结构定义所有进入RelayRouter的消息我先定义一套统一的Schema。不要小看这一步混乱的消息结构是路由层最大的敌人。{ messageId: uuid-v4, sessionId: session-123, timestamp: 1699999999999, source: editor:main, channel: text/stream, payload: { text: 实时 AI 不只是把聊天变成视频, cursor: 12, meta: { userId: user-07, docId: doc-99 } } }统一结构的好处是路由规则不用关心上游协议处理器也不用关心消息来自WebSocket还是HTTP。只要schema统一后面加新类型的输入源只需要写适配器。4.3 路由规则配置RelayRouter支持配置文件定义路由规则。下面是一段伪配置但基本逻辑跟实际配置一致routes: - name: title_enrich_route match: intent: enrich_title sessionLength: 3 to: enricher-service contextPolicy: includeLast: 5 maxTokens: 800 streaming: true - name: keyword_extract_route match: intent: extract_keywords confidence: 0.7 to: keyword-service streaming: true - name: fallback_route match: catchAll: true to: fallback-llm streaming: false每个路由都绑定了一个“意图”这个意图可以由小模型在线分类产出也可以由前端直接传入。第一版建议前端传入跑通后再升级为模型判断这样排障方便。4.4 流式转发的实现要点路由层转发LLM的流式响应时最怕的是“缓存积累”。很多初学者会把LLM的完整响应存进一个Buffer然后一次性转发给前端。这等于把流式交互变成了“等全文生成完再发”实时性瞬间归零。正确做法是拿到增量就转发增量。以Python为例核心伪代码如下async def forward_stream(route, message): async with httpx.AsyncClient(timeoutNone) as client: async with client.stream( POST, route.upstream_url, json{prompt: message.payload[text]} ) as resp: async for chunk in resp.aiter_bytes(): # 解析chunk通常是SSE格式 tokens parse_sse_tokens(chunk) await relay_to_websocket(message.session_id, tokens)注意keep-alive。如果上游模型长时间没有输出token连接可能被中间代理掐断需要在路由层维护心跳。4.5 上下文管理策略实时文本工作流里的上下文管理比离线场景更“抠”。因为用户还在打字历史上下文可能还在变路由层必须决定“快照哪一段上下文”。我目前的策略是三层核心上下文系统提示词、用户当前输入永不截断。短期上下文最近几轮对话尽量保留但超长时按窗口比例压缩。长期记忆从向量库里检索的片段只把与当前输入相似度最高的前三条注入。RelayRouter允许在路由规则中指定contextPolicy目的就是不让每个处理器各自管理上下文由路由层统一装配避免上下文漂移。4.6 连接管理与背压实时WebSocket连接成千上万时背压问题就会出现处理器能力不足但路由层还在拼命转发最终导致内存暴涨。我这里有一个必须强调的血泪教训流式系统一定要做背压控制。我在RelayRouter里设置了一个简单信号量机制from asyncio import Semaphore, Queue, TaskGroup class StreamBridge: def __init__(self, max_concurrent: int): self._sem Semaphore(max_concurrent) async def dispatch(self, message, route): async with self._sem: await forward_stream(route, message)当并发超过阈值时新请求进入等待队列而不是直接涌向上游。这会导致个别请求的首token变慢但能保住整体服务的稳定不会出现“连环超时”。体验上偶发变慢可以忍全盘崩溃不能忍。4.7 可观测性设计追踪一条消息的一生路由层能不能做好最终看可观测性。我每次排查线上问题都靠“消息轨迹”一个messageId从进来到离开经过了哪些路由节点每一跳耗时多少。RelayRouter给我提供了这样一个表格视图节点耗时(ms)状态备注ingress_ws12ok收到用户输入intent_classifier38okintentenrich_titlerouter_rule_match4ok命中title_enrich_routeupstream_llm_first_token520ok流式开始upstream_llm_complete1930ok全部token发完relay_to_frontend16ok推送结束有了这张表任何“哪一段慢了”都一目了然。我建议你在设计阶段就要求路由层导出这些trace数据别等服务出事再补。5. 踩坑实录实时文本工作流最容易翻车的5个问题5.1 流式响应的“断句”导致下游拼接混乱LLM流式返回的token经常是半截比如一个词的拼音被拆成几片。如果你在下游处理器里做“关键词提取”或“拼写检查”拿半截词去处理就会误报。我踩过真实的坑标题生成器连续收到“实”“时”“AI”三个token把它当三个词结果输出的扩展标题完全跑偏。解决思路在路由层为上向下游 NER命名实体识别场景引入“延迟窗口”等语义完整的片段比如句子边界或空格出现后再投递而不是每个token都投。实时性损失极小但准确性大幅提升。5.2 模型等待队列导致“假实时”只优化单次推理延迟不够。多个用户同时触发请求时如果模型服务排队很严重实时体验照样崩。关键指标不是P50而是P95。P50看着200毫秒P95跑到5秒用户感知就是“时快时慢”。应对办法是容量预估和限流。我习惯按P95倒推如果目标P95是800毫秒模型单次推理300毫秒那么每实例可用并发约2-3然后根据在线峰值算好实例数。RelayRouter的并发信号量在这里正好充当“网关限流器”。5.3 重试风暴让下游雪崩某个模型服务不稳定时路由层很容易触发重试逻辑。如果没有退避机制一旦同时重试几十条消息下游瞬间被打死。我在RelayRouter里对重试做了两层约束单条消息最多重试2次。两次重试之间至少间隔800毫秒。这两条看似简单实际能避免80%的雪崩场景。5.4 前端断连后路由层还在继续转发用户关闭浏览器WebSocket断开但上游LLM还在生成。如果我们不取消上游调用那些无用token会继续占用带宽和算力。正确的做法是在路由层监听WebSocket断开信号并调用上游的cancel接口终止生成。如果上游不支持cancel至少丢弃后续token并释放信号量避免连接资源被无用请求占着。5.5 上下文被重复注入导致费用爆炸在流式场景用户每敲一个字符如果都把全部历史消息塞进提示词token消耗会随时间二次方增长。我见过月度成本飙到原来20倍的案例纯粹是上下文管理太粗糙。建议按会话状态做“动态截断”只有用户停顿超过600毫秒时才触发一次完整上下文组装否则只把增量部分发给模型。RelayRouter的会话级缓冲在这里很管用。6. 在文本工作流之外的扩展思路6.1 从文本到多模态RelayRouter并没有被束缚虽然我们聊的是文本工作流但RelayRouter这套路由逻辑天然不绑定模态。你可以把“识别图片中的文字”也看成一个文本增强步骤把TTS合成看成另一个下游服务。路由层只负责把消息送达不关心下游是文本模型还是多模态模型。6.2 实时工作流的下一个试点人机协同写作我最近在试验一个更有意思的场景写作协作者未必是“后台全自动”而是“人类AI轮流接力”。RelayRouter把一段草稿路由给“人类审阅”回调人类修改完后消息再次进入工作流由AI继续补全。这类人机循环在传统REST接口里特别别扭但在流式路由层里显得非常自然。6.3 路由即策略把AI产品当管道而非单点很多团队的AI架构是一堆模型直接对前端改一个模型就要动前端。引入路由层后模型变成后端的可替换节点前端只跟RelayRouter通信。这个位置的真正价值是你有机会在不改业务代码的前提下持续调优AI策略。今天用大模型明天换更快的模型都只是路由配置的变化。7. 最后说几句实在的从Gemini Live Avatar聊到文本工作流再落到RelayRouter我真正的体会是实时AI最性感的从来不是那张会动的嘴而是背后那套能在几百毫秒内完成“接收-理解-路由-生成-转发”的管道架构。视频只是把管道终端做得更华丽文本工作流才是检验管道是否扎实的训练场。如果你现在准备搭建一个实时文本助手我的建议是先别急着炼丹调模型把路由层设计好把消息结构定清楚把背压和可观测性做完整。只要这几根柱子立住了后面无论换成什么模型、加什么功能都不会太狼狈。我也还在边做边踩坑特别是动态上下文预算和人机协同路由这两个方向坑比想象中多。但如果你的项目也正好卡在这些问题上欢迎沿着这条思路先搭一个最小闭环出来跑几天数据再回来对照优化。毕竟“实时”这种东西光看架构图永远感觉不到真跑起来才知道哪里疼。