Built-ins

asr Plugin

详细说明 asr 内建 plugin 如何安装转写依赖、配置模型、显式转写音频,以及在 chat 入站链路里自动增强语音消息

asr Plugin

asr 是当前最能体现“plugin 不只是 action 集合,还能直接参与运行链路”的内建 plugin 之一。

它的核心目标很直接:

  • 让语音或音频附件能被转成文本
  • 让 agent 能像处理普通文字消息一样处理语音输入

它到底做什么

asr 主要负责三类事情:

  1. 安装和配置语音转写依赖
  2. 提供显式的本地音频转写 action
  3. 在 chat 入站时自动把语音附件增强成文本片段

所以它既是:

  • 显式工具能力
  • 运行时中间层增强能力

它使用了哪些 plugin 能力

asr 用到了:

  • config
  • setup
  • usage
  • availability
  • actions
  • hooks.pipeline
  • system

这里最值得注意的是 hooks.pipeline

这意味着 asr 不只等你手动调用 transcribe,它还可以主动参与消息进入 agent 之前的增强流程。

它为什么是很重要的参考实现

如果你想设计这种能力:

  • 输入先预处理
  • 预处理结果再交给 agent
  • 预处理失败时尽量不要把主链路直接打死

asr 是非常好的参考。

因为它当前就采用了这种策略:

  • 有语音附件时尝试转写
  • 转写成功则把文本追加进消息增强区
  • 转写失败则 best-effort 跳过,不阻塞主流程

典型运行流

在自动增强模式下,一条语音消息通常这样流动:

  1. chat 入站消息带着 voiceaudio 附件进入
  2. asr 的 pipeline hook 检查附件列表
  3. 对每个有效音频文件尝试调用转写依赖
  4. 若成功,把转写文本追加到 pluginSections
  5. 追加后的增强消息继续交给后续 agent 处理

这个链路的关键不是“替代原消息”,而是“在原消息上增加可读文本上下文”。

典型场景

场景一:Telegram 语音消息希望直接让 agent 理解

这是 asr 最典型的使用方式。

用户发来语音,系统先转写,再把文字交给 agent。

这样后面的规划、工具调用和回答逻辑都可以继续以文本心智工作。

场景二:你手上有一个本地音频文件,只想单独拿到转写结果

这时不需要走完整 chat 链路,直接调用 transcribe action 即可。

场景三:你想保留语音能力,但暂时不想自动增强每条消息

这时可以保留 plugin 启用,同时关闭 augmentMessage

这样 transcribe 仍然能显式调用,但入站消息不会自动附加转写文本。

在 SDK 里怎么挂载

import { Agent } from "@downcity/agent";
import { AsrPlugin } from "@downcity/plugins";

const agent = new Agent({
  id: "voice-agent",
  path: "/path/to/project",
  tools: {},
  plugins: [new AsrPlugin()],
});

关键配置项

配置项作用说明
injectPrompt是否注入 ASR 提示词建议大多数语音场景开启
augmentMessage是否自动增强入站消息自动转写链路的关键开关
provider转写 provider当前默认是本地相关 provider
modelId默认模型例如 SenseVoiceSmall
language默认语言提示例如 autozhen
timeoutMs超时时间用于限制转写等待时间

主要动作

Action作用什么时候用
status查看配置与依赖状态想先判断当前环境
install安装转写依赖首次启用语音转写
configure更新 ASR 配置日常调整模型和策略
on启用 plugin,可选顺带安装一步打开语音能力
off关闭 plugin暂停语音能力
use切换当前模型安装多个模型后切换
transcribe转写一个本地音频文件显式调用场景
models查看支持模型给 UI 或控制面做选择器
doctor诊断 plugin 与依赖怀疑环境不完整时

场景化用法示例

查看当前状态

const status = await agent.plugins.runAction({
  plugin: "asr",
  action: "status",
});

安装转写依赖

const result = await agent.plugins.runAction({
  plugin: "asr",
  action: "install",
  payload: {
    modelIds: ["SenseVoiceSmall"],
    activeModel: "SenseVoiceSmall",
    installDeps: true,
  },
});

切换当前模型

const result = await agent.plugins.runAction({
  plugin: "asr",
  action: "use",
  payload: {
    modelId: "SenseVoiceSmall",
  },
});

显式转写一个本地音频文件

const result = await agent.plugins.runAction({
  plugin: "asr",
  action: "transcribe",
  payload: {
    audioPath: "/path/to/message.wav",
    language: "zh",
  },
});

查看支持模型

const models = await agent.plugins.runAction({
  plugin: "asr",
  action: "models",
});

做依赖诊断

const diagnosis = await agent.plugins.runAction({
  plugin: "asr",
  action: "doctor",
});

pipeline 在这里到底起什么作用

这是理解 asr 的关键。

它在 chat 入站增强点上做的事情不是“修改原始渠道消息”,而是:

  • 找出语音附件
  • 做转写
  • 把转写文本附加到增强区

所以它更像在告诉 agent:

  • 原始消息之外,还有一段可读文本上下文

这种设计很适合:

  • 保留原消息语义
  • 补充额外可读信息
  • 不强耦合到某个具体 chat 渠道实现

为什么转写失败不会阻塞主流程

当前实现刻意采用 best-effort 策略。

原因很现实:

  • 语音转写依赖可能偶发失败
  • 某个附件坏掉,不代表整条消息就应该完全失效

所以 asr 更倾向于:

  • 能转就转
  • 转不出来就跳过
  • 让主消息继续进入 agent

这非常适合真实生产环境。

system 在这里为什么也重要

即使 asr 已经能自动增强消息,system prompt 仍然有价值。

因为 agent 需要知道:

  • 当前环境具备语音转写能力
  • 遇到音频相关需求时可以调用 asr action
  • 自动增强文本应该如何理解

它的自然边界

asr 虽然背后要调用模型和依赖,但从架构角色看,它仍然更像 plugin:

  • 暴露 action
  • 参与 pipeline
  • 管理配置

如果你要设计“能力参与消息流水线”的机制,plugin 通常就是最自然的边界。

需要注意的边界

自动增强只针对语音 / 音频附件

它不是任意附件预处理框架。

关闭 augmentMessage 后,显式转写仍然可用

这两件事不要混为一谈。

use 切模型前,最好先确认模型已安装

否则会遇到“配置指向某个模型,但环境实际上没准备好”的问题。

什么时候优先参考它

当你要设计这些能力时,优先参考 asr

  • 入站消息增强
  • best-effort pipeline hook
  • 显式 action 与自动链路并存
  • 语音输入转文本

相关文档