用 Vue 3 Composables 把第三方 API 集成变成可复用流程

人工智能在物流与供应链By 3L3C

把第三方 SDK 集成写成 Vue 3 composables:可复用、可观测、好维护,适用于物流供应链中的 AI 语音助手与自动化工作流。

Vue 3ComposablesAPI 集成自动化工作流AI 语音助手物流科技
Share:

Featured image for 用 Vue 3 Composables 把第三方 API 集成变成可复用流程

用 Vue 3 Composables 把第三方 API 集成变成可复用流程

物流与供应链团队做 AI 语音助手和自动化工作流时,最容易踩的坑不是模型不准,而是集成方式不可维护:页面里到处 fetch()、到处 setInterval()、到处塞 SDK 初始化,结果一旦要加“语音转写 + 直播监控 + 异常告警 + 工单创建”,代码就变成一团线。

我见过不少“功能能跑”的项目,最后输在交付速度:新需求进来,团队不敢动老代码;第三方 SDK 升级,所有页面都要改;线上偶发加载失败,没人知道该从哪里排查。

这篇文章把 Deepgram 的 Vue 3 composables 教程换一个角度讲:把它当成一个可复制的集成模式,用来管理第三方 SDK(以 Amazon IVS Player 为例)以及后续的 AI 能力(比如语音识别、质检、自动流转)。你会得到的是一套更像“工作流积木”的写法:脚本加载、依赖编排、状态可观测、失败可恢复。

为什么 composables 是“前端自动化工作流”的底座

结论先说:composables 的价值不是语法糖,而是让第三方集成变成可复用、可测试、可监控的模块。

在“人工智能在物流与供应链”这个系列里,我们经常讨论路径规划、仓储自动化、需求预测,但落地时绕不过一个现实:前端/业务端要接很多服务。

  • 语音助手要接:ASR(语音转文字)、TTS(文字转语音)、对话编排、CRM/OMS/WMS。
  • 运营监控要接:直播/视频 SDK、告警平台、事件总线。
  • 自动化工作流要接:审批、工单、通知、报表。

这些都属于“第三方 API 集成”。如果你把初始化逻辑散落在组件里,后期你会付出三倍成本:

  1. 复用成本高:复制粘贴让 bug 复制得更快。
  2. 状态不可控:到底加载成功了没?失败原因是什么?没人说得清。
  3. 依赖难编排:A 依赖 B,B 又依赖 C,最后只能靠“祈祷式 setTimeout”。

composable 的优势在于:它天然鼓励你把“状态 + 行为”封装成一个小模块,就像把一个自动化步骤封装成“可插拔节点”。

模式一:用 composable 管理第三方脚本加载(Promise 化)

答案在第一句:把“脚本注入”写成单例 Promise,让加载过程可等待、可复用、可失败处理。

很多团队在集成第三方 SDK 时,习惯直接把 <script> 放进 index.html。这当然简单,但它有两个明显问题:

  • 全站污染:SDK 在每个页面都加载,首屏变慢。
  • 难以治理:你很难对“加载成功/失败/重试次数”做统一处理。

更可控的做法,是像原文那样,把注入脚本的逻辑写成 composable,并返回一个 Promise:

// useIVSPlayer.js
export default new Promise((res, rej) => {
  const script = document.createElement('script')
  script.src = 'https://player.live-video.net/1.8.0/amazon-ivs-player.min.js'
  document.head.appendChild(script)

  script.onload = () => res(true)
  script.onerror = () => rej(new Error('IVS player script load failed'))
})

这对物流与供应链场景有什么用?

把它映射到“AI 语音助手与自动化工作流”,你会发现它其实是一个通用节点:

  • 加载语音 SDK(WebRTC、音频处理库)
  • 加载地图与路径规划 SDK
  • 加载可视化大屏 SDK

统一 Promise 入口的好处:你的业务代码不再关心“SDK 到底什么时候可用”,它只需要 await.then()

一句话总结:脚本加载本身就是一个工作流步骤,应该被显式建模,而不是隐式发生。

模式二:用“依赖 composable”把异步编排写清楚

答案在第一句:一个 composable 依赖另一个 composable 时,用显式的等待(Promise/async)把顺序固定下来。

原文的链路很典型:

  1. 先加载 IVS Player SDK(useIVSPlayer
  2. 再创建播放器并连接直播流(useIVSChannel
  3. 最后把“连接状态”反馈到 UI

在组件里大概是这样:

useIVSPlayer.then(() => {
  const { playerIsLoaded } = useIVSChannel()
  watch(playerIsLoaded, () => {
    if (playerIsLoaded.value) IVSStatus.value = 'Is Connected'
  })
})

我更推荐的写法:把“依赖”收敛到一个入口

当你的集成越来越多(IVS + Deepgram + 工单系统 + 通知系统),组件里一层层 .then() 会变得难读。更稳妥的是把编排也封装成 composable:

// useStreamWorkflow.js
import useIVSPlayer from './useIVSPlayer'
import useIVSChannel from './useIVSChannel'

export async function useStreamWorkflow() { await useIVSPlayer return useIVSChannel() }


组件只做 UI:

```js
const { playerIsLoaded } = await useStreamWorkflow()

这在供应链系统里特别关键,因为 UI 往往只是“工作台”,真正复杂的是背后的流程编排

模式三:用“可观测状态”替代“静默成功”

答案在第一句:第三方集成一定要暴露状态机,而不是只暴露一个函数。

原文用 ref(false)playerIsLoaded 来表示加载完成,这是个好起点。但如果你把它用于生产级物流系统,还需要更清晰的状态:

  • idle:尚未开始
  • loading:脚本加载中
  • ready:SDK 可用
  • connecting:连接频道/服务中
  • connected:已连接
  • error:失败(带错误码与可重试信息)

建议的状态结构:

const status = ref({
  phase: 'idle',
  error: null,
  retries: 0,
})

为什么这对“AI 语音助手”尤其重要?

语音链路比视频更“脆”:

  • 麦克风权限
  • 音频设备切换
  • WebSocket 抖动
  • Token 过期
  • 后端限流

如果你没有可观测状态,客服工作台或调度工作台会出现最糟糕的体验:按钮能点,但没反应;偶尔恢复,但不知道为什么。

而一旦状态机标准化,你就能:

  • 在 UI 上提示“正在重连(第 2 次)”
  • 上报埋点:phase=connecting 超过 5 秒即告警
  • 在自动化工作流里触发降级:切换到文本输入或离线转写

模式四:用事件监听替代 setInterval(更省、更准)

答案在第一句:优先用 SDK 事件回调判断连接成功,setInterval 只作为兜底。

原文用 setInterval 每 500ms 检查 player.core.isLoaded。这在教程里 OK,但在生产里我更倾向:

  1. 优先订阅 SDK 的事件(例如播放状态、错误事件)
  2. 设置一个超时兜底(比如 10 秒)

原因很直接:轮询会带来不必要的开销,也会让“到底哪里慢”变得不清楚。

一个更像“自动化工作流”的思路是:

  • 事件驱动:成功事件触发下一步(比如自动开启语音转写)
  • 超时中断:超时触发告警/重试/降级

在物流场景里,这种事件驱动尤其有价值:比如“直播连接成功 → 自动开始 Deepgram 转写 → 触发质检规则 → 异常自动创建工单”。每一步都应该由事件来推进,而不是靠轮询猜测。

把这个模式迁移到“AI 语音助手 + 供应链工作流”

答案在第一句:把每个外部能力封装成 composable 节点,再用一个 workflow composable 把它们串起来。

举个更贴近业务的例子:仓库现场有一个“语音报修助手”,流程可能是:

  1. 加载音频 SDK 与权限检查
  2. 连接语音识别服务(ASR)
  3. 识别到关键字段(设备编号/故障类型)
  4. 调用 WMS/工单 API 创建工单
  5. 推送到维修群与值班看板

用 composables 的方式,你可以拆成:

  • useAudioInput():麦克风、采样率、静音检测
  • useASRClient():token、连接、重连、状态
  • useIntentParser():把文本解析成结构化字段
  • useWorkOrderApi():创建/查询/更新工单
  • useNotification():钉钉/企业微信/邮件

然后用 useRepairWorkflow() 串起来。这样做的收益非常实在:

  • 新增渠道(比如从网页扩展到手持 PDA WebView)时,大部分逻辑原封不动
  • 出现故障时,你能定位是“脚本没加载”还是“token 过期”还是“网络抖动”
  • 需求迭代时,只改一个节点,不动整条链

常见问题(你大概率会遇到)

composable 里直接访问 document 会不会有问题?

会。在 SSR 或单元测试环境中,document 不存在。解决办法是:

  • 把 DOM 相关逻辑放到 onMounted() 后执行
  • 或在 composable 中做环境判断(仅在浏览器运行)

多次进入页面会不会重复注入脚本?

会,所以脚本加载 composable 推荐做成单例 Promise(原文就是这个思路),并在注入前检查是否已存在同 src 的 script。

Token/权限/重连逻辑放哪里?

不要放组件里。把它们放到对应的 composable,并把状态(phase、error、retries)暴露出来。组件只负责展示与触发。

你可以从今天开始做的三件事

如果你正在做“AI 提升物流效率”的项目(无论是语音助手、仓储自动化看板,还是跨境物流监控),我建议立刻做这三件事:

  1. 把所有第三方 SDK 初始化搬进 composables,组件只保留 UI。
  2. 为每个集成定义状态机(至少:loading/ready/error)。没有状态机的集成,迟早会成为线上事故源。
  3. 把依赖关系写成 workflow composable,别让 .then()setTimeout 把业务逻辑搅浑。

这套写法并不“更复杂”,它只是把复杂度从“隐式的偶发问题”变成“显式的可治理模块”。而对想要把 AI 语音助手真正接入供应链工作流的团队来说,可治理性往往比功能更重要。

你下一步要做的,是把同样的模式用到语音链路上:脚本/SDK 加载、token 获取、WebSocket 连接、转写事件、自动化流转。等这些模块稳定了,你会发现“加一个新业务流程”,真的就像搭积木。你现在的项目里,哪一段第三方集成最让你头疼?