架构之道 · AI 旅行助手前端
在 AI 浪潮席卷产品设计的前沿,前端架构的内涵早已悄然蜕变。它不再是单纯把 UI 画得漂亮、把组件分得干净,而演变成了一场关乎体验连续性、业务吞吐效率与系统确定性的系统性战役。
本文聊的"AI 场景助手",不是实验室里的理想模型,而是一个在资源受限、需求狂飙、多端环境错综复杂的真实业务泥潭里,连滚带爬摸索出来的实战型架构。我们不谈空中楼阁的"完美设计",只聊如何在"稳定交付、丝滑体验、无限扩展"的既定约束下,跳好一场务实的踢踏舞。
现场:多端场景下的"硬核"挑战
作为一款深度嵌入宿主 App 的 AI 场景助手,它一出生就要面对极其刁钻的生存环境:
三大生存压力
网络波动 · 功能密度 · 宿主环境
| # | 挑战维度 | 场景描述 & 架构要求 |
|---|---|---|
| 1 | 网络极其不稳定 | 用户可能在地铁、机场、甚至是信号微弱的户外。系统必须对网络波动、流式数据断联、UI 频繁重绘有极高的容错率。 |
| 2 | 功能密度高、跨度大 | 实时语音翻译、双向对话翻译、图像场景识别、日程规划推荐……这些功能不是孤立的页面,产品要求它们在同一个会话上下文中无缝流转。 |
| 3 | 宿主环境复杂 | 它既要能作为独立 H5 跑在浏览器里,又要通过 window.HostBridge 原生桥接、稳如泰山地嵌入宿主 App。 |
面对这碗"硬菜",我们团队达成了三点共识作为架构的底色:
流式协议 · 意图驱动 · 多端兼容
面对复杂业务环境,团队达成的架构共识
| 架构支柱 | 设计与实现要点 |
|---|---|
1流式协议 | 以流式协议为交互心脏,SSE 长连接管理连接的建立、维持、中断与异常销毁 |
2意图驱动 | intent + query + files 统一请求契约,所有能力复用同一条聊天通道 |
3多端兼容 | 独立 H5 与宿主 App 原生桥接并存,TTS/埋点双轨降级应对复杂环境 |
务实的底座:不盲从、不包揽
在技术选型上,我们选择了 Vue3 + Vite。这很常规,但足够轻快、生态成熟。
真正让我们纠结过的是状态管理。在很多人眼里,大厂架构就该把所有状态塞进 Pinia 这样的全局 Store 里。但我们偏不。我们选择了一种极具"现实主义"的做法:只把全局通用的基础状态留给 Store,而将聊天主状态、输入态、流式加载态等与交互强相关的逻辑,全部"下沉"到 Composable(组合式函数)和页面局部状态中。
架构师大白话:
在业务一天三变、功能频繁迭代的开荒期,如果把所有交互细节都抽象成全局 Store,很快就会因为模块间盘根错节的依赖,陷入"动一发而动全身"的维护噩梦。通过 Composable 封装诸如"对话流控制"、"语音录制状态机",既实现了逻辑的干净复用,又把变量的生命周期死死掐在组件内部,变更成本极低。
在基础设施层面,我们用 Axios 统一了网络请求管道,并在这个管道上横向切了一刀,把以下硬核能力做成了透明的拦截器:
- •Token 自动注入:业务同学无需手动拼接鉴权头
- •traceId 全链路追踪:一次请求从发起到渲染可串联排查
- •防重复提交:关键写操作在网关层前被拦截
- •请求/响应加解密:安全能力对上层完全透明
业务开发同学只需要关心接口数据,剩下的安全和链路追踪,架构在底层全包了。
对话能力的核心:三层解耦的"内容交响乐"
AI 产品的灵魂在于"对话"。如果把大模型的输出单纯当成一串"蹦字"的文本流,那是把架构做窄了。我们将对话交互抽丝剥茧,拆解为职责泾渭分明的三层结构:
┌─────────────────────────────────────────────────────────────┐
│ 1. 通信层 (fetch-event-source) → SSE 长连接与连接生命周期 │
└─────────────────────────────────────────────────────────────┘
│ (原始数据流)
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. 协议解析层 (Protocol Parser) → META / Chunk 分片协议拆解 │
└─────────────────────────────────────────────────────────────┘
│ (结构化卡片/文本)
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. 呈现层 (UI Render) → Markdown + 动态业务卡片 (行程/景点) │
└─────────────────────────────────────────────────────────────┘3.1 通信层:告别原生的脆弱
我们放弃了原生的 EventSource 和 WebSocket,选用了 fetch-event-source 库通过 SSE(Server-Sent Events)方式接入。它既有流式的实时性,又完全兼容 HTTP 协议的各种配置(比如支持自定义 Header)。通信层只干一件事:管理连接的生死,管它建立、维持、中断(Abort)还是异常销毁,给上层提供一条清爽的数据管道。
3.2 协议解析层:最具有战略眼光的一着
我们把大模型的输出,定义为"可编排的内容流"。前端会显式解析 STREAM_META(元数据)、text_chunk(文本碎片)和 card_chunk(推荐卡片分片)等多种自定义协议。大模型吐出的不仅仅是字,还可能是结构化的指令。这一层完美隔离了模型侧协议的抖动,无论后端大模型怎么换、字段怎么变,在这里都被洗成前端认识的标准化数据。
3.3 呈现层:让表达形式各得其所
在这里,Markdown 语法与我们自定义的业务卡片(如动态行程单、景点推荐小卡片)混合编排、即时渲染。
意图驱动:如何把乱成麻的功能拧成一股绳
同传、翻译、查行程、看场景……如果每个功能开一个页面,用户会迷失在无尽的菜单跳转里,研发也得针对每个功能写一套会话管理。
我们的破局点在于引入了 Intent(意图驱动)机制。在业务视角下,无论用户是在敲字、在说英文、还是在拍一张路牌,在底层都被抽象成统一的请求契约:
{ intent: string; query: string; files?: File[] }intent: live_interpretation用户点「实时语音翻译」
intent: image_scene_recognition用户拍照片,触发图像场景识别
intent: policy_consultation政策咨询等新业务,只需加枚举与卡片组件
所有能力全部复用同一条聊天通道和流式基础设施。新业务上线,前端研发只需要在枚举里加个类型,写一下专属的卡片渲染组件,剩下的会话状态管理、重试逻辑、流式解析全套现成"样板房"直接拎包入住。这才是真正的架构复用效率。
现实主义的防御性设计:多端协同与语音管线
真实的工程世界里没有标准答案,只有"看菜吃饭"。
以语音输出(TTS)为例,我们在架构上同时接入了三种路径:
HTTP 静态 TTS
纯 H5 环境下的基础路径,网络一般时的可靠降级
WebSocket 流式 TTS
网络良好时的实时音频,低延迟体验
原生 App TTS
App 内走 Bridge 桥接,获得最完美的音频权限和底噪控制
这看起来有点冗余,但恰恰是应对复杂环境的"现实主义生存智慧"——在 App 内,走原生桥接能获得最完美的音频权限和底噪控制;在纯 H5 环境下,根据网络好坏动态在流式和静态音频之间降级切换。
同样,埋点与日志也采用了类似的"双轨制":App 内走 Bridge 借宿主能力上报,Web 端降级走常规 Beacon/XHR 方案。做 AI 产品,边缘场景下的稳定性,直接决定了用户是觉得它"真聪明"还是"人工智障"。
架构的自我审视:当下的痛点与明天的路
坦率地说,在业务野蛮生长的阶段,为了快,我们也留下了不少"成长的代价":
聊天页面超 2000 行
核心聊天页面的组件已经突破了 2000 行,代码编排开始变得臃肿
双 UI 库并存
Element Plus 和 Vant 双 UI 库并存,带来了样式冲突和打包体积的负担
i18n 未启用
国际化基础能力虽然铺好了,但运行时为了赶进度依然固定成了中文,属于"枪已擦亮,发令枪未响"
系统已经成功跨越了"从无到有"的草莽期,正站在"从可用走向可治理"的十字路口。基于构建一个"严谨、可信、优雅"的系统,我们下一阶段的目标很明确:
全链路可观测
围绕消息发送、首字节时间(TTFB)、流式渲染完成、用户主动中断等关键节点建立统一事件打点,让 traceId 贯穿到流式渲染层
复杂度外科手术
把那两千多行的聊天页面,精准拆解为会话编排、消息渲染、输入控制、语音管线四个子域,并为协议解析等核心逻辑补齐单元测试
安全与配置收敛
清理通过 URL Query 传递 Token 的野路子,收敛配置文件加载策略;针对大模型和 Markdown 动态渲染构建严格白名单 Sanitize,把 XSS 风险锁死在摇篮里
结语
这个"AI 场景助手"的前端架构,没有什么惊天动地的自研框架,也没有炫技式的复杂概念。它的价值恰恰在于清醒——精准识别了 AI 能力在前端落地时的痛点,然后在流式协议、意图驱动、多端兼容这三个支柱上扎扎实实地做好了防御性设计。
在理想的桃源与残酷的现实之间,找到那条能让业务跑得最稳、最快的路,这就是我们前端工程里的现实主义。
本文属于 无魔法工程流派 的第 8 篇肉身实战。
发表评论
分享你的想法和反馈