Skip to main content
Qwen-Audio-ASR-Streaming

Qwen-Audio-ASR-Streaming实时语音识别Java SDK

本文介绍Qwen-Audio-ASR-Streaming实时语音识别Java SDK的参数和接口细节。

前提条件

快速开始

Recognition类提供了非流式调用和双向流式调用等接口。请根据实际需求选择合适的调用方式:
  • 非流式调用:针对本地文件进行识别,并一次性返回完整的处理结果。适合处理录制好的音频。
  • 双向流式调用:可直接对音频流进行识别,并实时输出结果。音频流可以来自外部设备(如麦克风)或从本地文件读取。适合需要即时反馈的场景。
  • 非流式调用
  • 双向流式调用:基于回调
  • 双向流式调用:基于Flowable
提交单个语音实时转写任务,通过传入本地文件的方式同步阻塞地拿到转写结果。实例化Recognition类,调用call方法绑定请求参数和待识别文件,进行识别并最终获取识别结果。
import com.alibaba.dashscope.audio.asr.recognition.Recognition;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionParam;
import com.alibaba.dashscope.utils.Constants;

import java.io.File;

public class Main {
    public static void main(String[] args) {
        // 以下为华北2(北京)地域的配置,调用时请将"{WorkspaceId}"替换为真实的业务空间ID,各地域的配置不同。
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference";
        // 创建Recognition实例
        Recognition recognizer = new Recognition();
        // 创建RecognitionParam
        RecognitionParam param =
                RecognitionParam.builder()
                        .model("qwen-audio-3.1-asr-flash-streaming")
                        // 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
                        // 若没有配置环境变量,请用百炼API Key将下行替换为:.apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .format("wav")
                        .sampleRate(16000)
                        //.parameter("language_hints", new String[]{"zh"})
                        .build();

        try {
            System.out.println("识别结果:" + recognizer.call(param, new File("{YOUR_AUDIO_FILE}")));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 任务结束后关闭 WebSocket 连接
            recognizer.getDuplexApi().close(1000, "bye");
        }
        System.out.println(
                "[Metric] requestId: "
                        + recognizer.getLastRequestId()
                        + ", first package delay ms: "
                        + recognizer.getFirstPackageDelay()
                        + ", last package delay ms: "
                        + recognizer.getLastPackageDelay());
        System.exit(0);
    }
}

高并发调用

在DashScope Java SDK中,采用了OkHttp3的连接池技术,以减少重复建立连接的开销。详情请参见高并发最佳实践。

接口地址

SDK的接口地址需在初始化前设置为下方地址(包含WorkspaceId)。如需切换到其他地域,请修改 Constants.baseWebsocketApiUrl为对应地域的URL。
  • 华北2(北京)
  • 新加坡
wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference调用时请将{WorkspaceId}替换为真实的Workspace ID。
阿里云百炼为华北2(北京)、新加坡地域推出了业务空间专属域名,能够为推理请求提供卓越的性能和更高的稳定性,建议迁移至新域名:
  • 华北2(北京)地域:从 dashscope.aliyuncs.com 迁移至 {WorkspaceId}.cn-beijing.maas.aliyuncs.com
  • 新加坡地域:从 dashscope-intl.aliyuncs.com 迁移至 {WorkspaceId}.ap-southeast-1.maas.aliyuncs.com

请求参数

通过RecognitionParam的链式方法配置模型、采样率、音频格式等参数。配置完成的参数对象传入Recognition类的call/streamCall方法中使用。
RecognitionParam param = RecognitionParam.builder()
  .model("qwen-audio-3.1-asr-flash-streaming")
  .format("pcm")
  .sampleRate(16000)
  //.parameter("language_hints", new String[]{"zh"})
  .build();
参数类型是否必须说明
modelString是模型名称。
sampleRateInteger是采样率(Hz),支持任意采样率。
formatString是音频格式。取值范围:
  • pcm
  • wav
  • mp3
  • opus
  • speex
  • aac
  • amr
opus/speex:必须使用Ogg封装;wav:必须为PCM编码;amr:仅支持AMR-NB类型。
keep_dialectboolean否仅 qwen-audio-3.1-asr-flash-streaming 支持。默认 false,将方言转写为普通话;设为 true 时保留方言表达。通过 .parameter("keep_dialect", value) 设置。完整参数说明请参见客户端事件。
vad_modelString否仅 qwen-audio-3.1-asr-flash-streaming 支持。可选 near_meeting_16k(近场)或 far_field_meeting_16k(远场,默认值)。通过 .parameter("vad_model", value) 设置。完整参数说明请参见客户端事件。
vocabularyIdString否预编译热词列表 ID。需预先调用创建热词列表接口生成,识别时传入该 ID 即可使用列表中的热词。适用于词汇已知且相对稳定、需要跨请求复用同一词表的场景。使用方法请参见预编译热词。
vocabularyMap<String, Integer>否即时热词。以键值对形式传入,键为热词文本(string),值为热词权重(integer),无需预先创建热词列表。权重取值范围为 [1, 5] 或 50:取 [1, 5] 时值越大模型越倾向输出该词;取 50 时为超级热词,召回率大幅提升,但超级热词数量最多不超过 50 个。适用于临时性、会话级别的热词优化。与预编译热词同时配置时,系统会合并两类热词;合并后超过 2000 个时,随机选择 2000 个使用。使用方法请参见即时热词。vocabulary需要通过 RecognitionParam 实例的 parameter 方法或者 parameters 方法进行设置:
Map<String, Integer> vocab = new HashMap<>();
vocab.put("张三", 5);
vocab.put("李四", 5);

RecognitionParam param = RecognitionParam.builder()
        .model("qwen-audio-3.1-asr-flash-streaming")
        .format("pcm")
        .sampleRate(16000)
        .parameter("vocabulary", vocab)
        .build();
semantic_punctuation_enabledboolean否是否启用语义断句。默认值:false。
  • true:开启语义断句,关闭 VAD 断句。
  • false(默认):开启 VAD 断句,关闭语义断句。
语义断句准确性更高,适合会议转写场景;VAD(Voice Activity Detection,语音活动检测)断句延迟较低,适合交互场景。semantic_punctuation_enabled需要通过RecognitionParam实例的parameter方法或者parameters方法进行设置:
RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.1-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("semantic_punctuation_enabled", true)
 .build();
max_sentence_silenceInteger否VAD 断句静音阈值(ms)。当一段语音后的静音时长超过该阈值时,系统会判定该句子已结束。当semantic_punctuation_enabled为true时,不作为sentence_end返回依据,但设置过小可能会影响识别效果。默认值:1300。取值范围:[200, 6000]。max_sentence_silence需要通过RecognitionParam实例的parameter方法或者parameters方法进行设置:
RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.1-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("max_sentence_silence", 800)
 .build();
multi_threshold_mode_enabledboolean否
仅在semantic_punctuation_enabled参数为false时生效。
是否启用多阈值模式。启用后可防止 VAD 断句切割过长。默认值:false。multi_threshold_mode_enabled需要通过RecognitionParam实例的parameter方法或者parameters方法进行设置:
RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.1-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("multi_threshold_mode_enabled", true)
 .build();
punctuation_prediction_enabledboolean否设置是否在识别结果中自动添加标点:
  • true(默认):是,不支持修改。
punctuation_prediction_enabled需要通过RecognitionParam实例的parameter方法或者parameters方法进行设置:
RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.1-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("punctuation_prediction_enabled", false)
 .build();
heartbeatboolean否是否启用心跳包。默认值:false。
  • true:在持续发送静音音频的情况下,可保持与服务端的连接不中断。
  • false(默认):即使持续发送静音音频,连接也将在一定时间后因超时而断开。
静音音频指的是在音频文件或数据流中没有声音信号的内容。静音音频可以通过多种方法生成,例如使用音频编辑软件如Audacity或Adobe Audition,或者通过命令行工具如FFmpeg。
使用该字段时,SDK版本不能低于2.19.1。
heartbeat需要通过RecognitionParam实例的parameter方法或者parameters方法进行设置:
RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.1-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("heartbeat", true)
 .build();
language_hintsString[]否待识别音频语种。无默认值,不设置时模型自动识别。最多支持设置 4 个值,超出时仅前 4 个生效。
  • zh: 中文
  • en: 英文
  • ja: 日语
  • ko:韩语
  • vi:越南语
  • th:泰语
  • id:印尼语
  • ms:马来语
  • tl:菲律宾语
  • hi:印地语
  • ar:阿拉伯语
  • fr:法语
  • de:德语
  • es:西班牙语
  • pt:葡萄牙语
  • ru:俄语
  • it:意大利语
  • nl:荷兰语
  • sv:瑞典语
  • da:丹麦语
  • fi:芬兰语
  • no:挪威语
  • el:希腊语
  • pl:波兰语
  • cs:捷克语
  • hu:匈牙利语
  • ro:罗马尼亚语
  • bg:保加利亚语
  • hr:克罗地亚语
  • sk:斯洛伐克语
language_hints需要通过RecognitionParam实例的parameter方法或者parameters方法进行设置:
RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.1-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("language_hints", new String[]{"zh"})
 .build();
speech_noise_thresholdfloat否语音与噪音的判定阈值,用于调整语音活动检测(VAD)的灵敏度。取值范围:[-1.0, 1.0]。取值说明:
  • 取值越接近 -1:降低噪音判定阈值,噪音被识别为语音的概率增大,可能导致更多噪音被转写
  • 取值越接近 +1:提高噪音判定阈值,语音被误判为噪音的概率增大,可能导致部分语音被过滤
此参数为高级配置参数,调整可能显著影响识别效果,建议:
  • 调整前充分测试验证效果
  • 根据实际音频环境小幅度调整(建议步长 0.1)
speech_noise_threshold需要通过RecognitionParam实例的parameter方法或者parameters方法进行设置:
RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.1-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("speech_noise_threshold", -0.5)
 .build();
special_word_filterString否指定在语音识别过程中需要处理的敏感词,并支持对不同敏感词设置不同的处理方式。详情请参见敏感词过滤。special_word_filter需要通过RecognitionParam实例的parameter方法或者parameters方法进行设置:
// 1. 构建最外层对象
JSONObject root = new JSONObject();
root.put("system_reserved_filter", true);

// 2. 构建“从结果中完全移除”的配置
JSONObject root1 = new JSONObject();
JSONArray array1 = new JSONArray();
array1.put("开始");
array1.put("进行");
root1.put("word_list", array1);

// 3. 构建“替换为等长 *”的配置
JSONObject root2 = new JSONObject();
JSONArray array2 = new JSONArray();
array2.put("测试");
root2.put("word_list", array2);

// 4. 组装
root.put("filter_with_empty", root1);
root.put("filter_with_signed", root2);

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.1-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("special_word_filter", root.toString())
 .build();
inputMap<String, Object>否输入对象,用于传入对话上下文(context)。上下文用于辅助识别、提升专有词汇的识别准确率。使用方法详见提升识别准确率。Map 中需包含 context 键,值为 List<Map<String, Object>> 类型的消息数组,每条消息包含以下字段:
  • role(String,必选):消息角色。user 表示前几轮用户语音的识别结果或领域相关的词表;assistant 表示前几轮大语言模型的回复内容。
  • content(List<Map>,必选):消息内容列表。每个元素包含 type(String,role 为 user 时填 input_text,role 为 assistant 时填 text)和 text(String,文本内容)。
上下文消息(input_text 和 text 类型)各最多 5 条,超出时保留最近的 5 条。每轮上下文文本总长度不超过 400 个字符,超出部分从末尾截断。
携带上下文时,context 中的消息顺序有要求:上下文消息必须按对话轮次排列,每轮中 user(input_text 类型)必须在对应的 assistant(text 类型)之前。
使用该字段时,SDK版本不能低于2.22.23。
input通过RecognitionParam实例的input方法进行设置:
// 1. 构建 input 结构体
Map<String, Object> userContent = new HashMap<>();
userContent.put("type", "input_text");
userContent.put("text", "你好啊");

Map<String, Object> assistantContent = new HashMap<>();
assistantContent.put("type", "text");
assistantContent.put("text", "你好啊,我是通义千问,有什么可以帮助你的?");

Map<String, Object> userMessage = new HashMap<>();
userMessage.put("role", "user");
userMessage.put("content", Arrays.asList(userContent));

Map<String, Object> assistantMessage = new HashMap<>();
assistantMessage.put("role", "assistant");
assistantMessage.put("content", Arrays.asList(assistantContent));

Map<String, Object> input = new HashMap<>();
input.put("context", Arrays.asList(userMessage, assistantMessage));

// 2. 通过 input 方法传入
RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.1-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .input(input)
 .build();
apiKeyString否用户API Key。

关键接口

Recognition类

Recognition通过import com.alibaba.dashscope.audio.asr.recognition.Recognition;方式引入。它的关键接口如下:
接口/方法参数返回值描述
public void call(RecognitionParam param, final ResultCallback<RecognitionResult> callback)
  • param:请求参数
  • callback:回调接口(ResultCallback)
无基于回调形式的流式实时识别,该方法不会阻塞当前线程。
public String call(RecognitionParam param, File file)
  • param:请求参数
  • file:待识别音频文件
识别结果基于本地文件的非流式调用,该方法会阻塞当前线程直到全部音频读完,该方法要求所识别文件具有可读权限。
public Flowable<RecognitionResult> streamCall(RecognitionParam param, Flowable<ByteBuffer> audioFrame)
  • param:请求参数
  • audioFrame:Flowable<ByteBuffer>实例
Flowable<RecognitionResult>基于Flowable的流式实时识别。
public void sendAudioFrame(ByteBuffer audioFrame)
  • audioFrame:二进制音频流,为ByteBuffer类型
无推送音频,每次推送的音频流不宜过大或过小,建议每包音频时长为100ms左右,大小在1KB~16KB之间。识别结果通过回调接口(ResultCallback)的onEvent方法获取。
public void stop()
无无停止实时识别。该方法会阻塞当前线程,直到回调实例ResultCallback的onComplete或者onError被调用之后才会解除对当前线程的阻塞。
boolean getDuplexApi().close(int code, String reason)
code: WebSocket关闭码(Close Code)reason:关闭原因这两个参数可参考The WebSocket Protocol文档进行配置true在任务结束后,无论是否出现异常都需要关闭WebSocket连接,避免造成连接泄漏。关于如何复用连接提升效率请参考高并发最佳实践。
public String getLastRequestId()
无requestId获取当前任务的requestId,在调用call、streamingCall开始新任务之后可以使用。
该方法自2.18.0版本及以后的SDK中才开始提供。
public long getFirstPackageDelay()
无首包延迟获取首包延迟,从发送第一包音频到收到首包识别结果延迟,在任务完成后使用。
该方法自2.18.0版本及以后的SDK中才开始提供。
public long getLastPackageDelay()
无尾包延迟获得尾包延迟,发送stop指令到最后一包识别结果下发耗时,在任务完成后使用。
该方法自2.18.0版本及以后的SDK中才开始提供。

更新对话上下文

调用 updateContext 在识别任务运行过程中更新对话上下文,用于辅助后续音频的识别。该方法要求 DashScope Java SDK 2.23.0 及以上版本。
public void updateContext(Map<String, Object> payloadInput)
  • 调用时机:调用 call(param, callback) 启动流式识别后、调用 stop 前。
  • 参数:payloadInput 为Map<String, Object>,传入 continue-task 事件的 payload.input 对象,包含 context 字段,不要额外包装 payload 或 input 层级。
  • 支持范围与参数约束:请参见 continue-task。
以下示例复用已启动的 recognizer 实例,Java 集合类型通过 import java.util.*; 导入。
Map<String, Object> userContent = new HashMap<>();
userContent.put("type", "input_text");
userContent.put("text", "这是第 1 轮语音识别测试");
Map<String, Object> userMessage = new HashMap<>();
userMessage.put("role", "user");
userMessage.put("content", Collections.singletonList(userContent));

Map<String, Object> assistantContent = new HashMap<>();
assistantContent.put("type", "text");
assistantContent.put("text", "好的,请开始第 1 轮测试");
Map<String, Object> assistantMessage = new HashMap<>();
assistantMessage.put("role", "assistant");
assistantMessage.put("content", Collections.singletonList(assistantContent));

Map<String, Object> payloadInput = new HashMap<>();
payloadInput.put("context", Arrays.asList(userMessage, assistantMessage));
recognizer.updateContext(payloadInput);

回调接口(ResultCallback)

双向流式调用时,服务端会通过回调的方式,将关键流程信息和数据返回给客户端。您需要实现回调方法,处理服务端返回的信息或者数据。 回调方法的实现,通过继承抽象类ResultCallback完成,继承该抽象类时,您可以指定泛型为RecognitionResult。RecognitionResult封装了服务器返回的数据结构。 由于Java支持连接复用,因此没有onClose和onOpen。
ResultCallback<RecognitionResult> callback = new ResultCallback<RecognitionResult>() {
    @Override
    public void onEvent(RecognitionResult result) {
        System.out.println("RequestId为:" + result.getRequestId());
        // 在此实现处理语音识别结果的逻辑
    }

    @Override
    public void onComplete() {
        System.out.println("任务完成");
    }

    @Override
    public void onError(Exception e) {
        System.out.println("任务失败:" + e.getMessage());
    }
};
接口/方法参数返回值描述
public void onEvent(RecognitionResult result)
result:实时识别结果(RecognitionResult)无当服务有回复时会被回调。
public void onComplete()
无无任务完成后该接口被回调。
public void onError(Exception e)
e:异常信息无发生异常时该接口被回调。

响应结果

实时识别结果(RecognitionResult)

RecognitionResult代表一次实时识别的结果。
接口/方法参数返回值描述
public String getRequestId()
无requestId获取requestId。
public boolean isSentenceEnd()
无是否是完整句子,即产生断句判断给定句子是否已经结束。
public Sentence getSentence()
无单句信息(Sentence)获取单句信息,包括时间戳和文本信息等。

单句信息(Sentence)

接口/方法参数返回值描述
public Long getBeginTime()
无句子开始时间,单位为ms返回句子开始时间。
public Long getEndTime()
无句子结束时间,单位为ms返回句子结束时间。
public String getText()
无识别文本返回识别文本。
public List<Word> getWords()
无字时间戳信息(Word)的List集合返回字时间戳信息。

字时间戳信息(Word)

接口/方法参数返回值描述
public long getBeginTime()
无字开始时间,单位为ms返回字开始时间。
public long getEndTime()
无字结束时间,单位为ms返回字结束时间。
public String getText()
无字返回识别的字。
public String getPunctuation()
无标点返回标点。

错误码

如遇报错问题,请参见错误码进行排查。 若问题仍未解决,可加入语音 SDK 示例仓库中列出的开发者群反馈问题,并提供Request ID,以便进一步排查问题。

常见问题

功能特性

Q:在长时间静默的情况下,如何保持与服务端长连接?

将请求参数heartbeat设置为true,并持续向服务端发送静音音频。 静音音频指的是在音频文件或数据流中没有声音信号的内容。静音音频可以通过多种方法生成,例如使用音频编辑软件如Audacity或Adobe Audition,或者通过命令行工具如FFmpeg。

Q:如何将音频格式转换为满足要求的格式?

可使用FFmpeg工具,更多用法请参见FFmpeg官网。
# 基础转换命令(万能模板)
# -i,作用:输入文件路径,常用值示例:audio.wav
# -c:a,作用:音频编码器,常用值示例:aac, libmp3lame, pcm_s16le
# -b:a,作用:比特率(音质控制),常用值示例:192k, 320k
# -ar,作用:采样率,常用值示例:44100 (CD), 48000, 16000
# -ac,作用:声道数,常用值示例:1(单声道), 2(立体声)
# -y,作用:覆盖已存在文件(无需值)
ffmpeg -i input_audio.ext -c:a 编码器名 -b:a 比特率 -ar 采样率 -ac 声道数 output.ext

# 例如:WAV → MP3(保持原始质量)
ffmpeg -i input.wav -c:a libmp3lame -q:a 0 output.mp3
# 例如:MP3 → WAV(16bit PCM标准格式)
ffmpeg -i input.mp3 -c:a pcm_s16le -ar 44100 -ac 2 output.wav
# 例如:M4A → AAC(提取/转换苹果音频)
ffmpeg -i input.m4a -c:a copy output.aac  # 直接提取不重编码
ffmpeg -i input.m4a -c:a aac -b:a 256k output.aac  # 重编码提高质量
# 例如:FLAC无损 → Opus(高压缩)
ffmpeg -i input.flac -c:a libopus -b:a 128k -vbr on output.opus

Q:如何识别本地文件(录音文件)?

识别本地文件有两种方式:
  • 直接传入本地文件路径:此种方式在最终识别结束后获取完整识别结果,不适合即时反馈的场景。 参见非流式调用,在Recognition类的call方法中传入文件路径对录音文件直接进行识别。
  • 将本地文件转成二进制流进行识别:此种方式一边识别文件一边流式获取识别结果,适合即时反馈的场景。
    • 参见双向流式调用:基于回调,通过Recognition类的sendAudioFrame方法向服务端发送二进制流对其进行识别。
    • 参见双向流式调用:基于Flowable,通过Recognition类的streamCall方法向服务端发送二进制流对其进行识别。

故障排查

Q:无法识别语音(无识别结果)是什么原因?

  1. 请检查请求参数中的音频格式(format)和采样率(sampleRate/sample_rate)设置是否正确且符合参数约束。以下为常见错误示例:
    • 音频文件扩展名为 .wav,但实际为 MP3 格式,而请求参数 format 设置为 mp3(参数设置错误)。
    • 音频采样率为 3600Hz,但请求参数 sampleRate/sample_rate 设置为 48000(参数设置错误)。
    可以使用ffprobe工具获取音频的容器、编码、采样率、声道等信息:
    ffprobe -v error -show_entries format=format_name -show_entries stream=codec_name,sample_rate,channels -of default=noprint_wrappers=1 input.xxx
    
  2. 请检查language_hints设置的语言是否与音频实际语言一致。 例如:音频实际为中文,但language_hints设置为en(英文)。
  3. 若以上检查均无问题,可通过定制热词提升对特定词语的识别效果。
文本生成
图像生成
视频生成
世界模型
3D模型生成
音频
  • 音频生成
Realtime API
向量与排序
决策模型
TokenPlan
模型生产