Melhores práticas de reconhecimento de fala
Otimize a qualidade ASR por meio de práticas recomendadas de áudio, personalização de vocabulário e correção pós-processamento.
A precisão do reconhecimento de fala depende de três coisas: qualidade de áudio, personalização de vocabulário e pós-processamento. Áudio de baixa qualidade é a causa mais comum de erros. A personalização do vocabulário lida com termos específicos do domínio. O pós-processamento captura o que os outros dois perdem.
Este guia cobre todos os três.
Qualidade de áudio
O melhor modelo ASR do mundo não consegue transcrever áudio e não consegue ouvir com clareza. A qualidade do áudio é o maior fator na precisão do reconhecimento – e o mais barato para consertar.
Ambiente de gravação
| Fator | Recomendação |
|---|---|
| Ruído de fundo | Grave em uma sala silenciosa. Evite zumbidos do ar condicionado, cliques no teclado e conversas próximas. Se o ruído for inevitável, use um microfone direcional. |
| Eco e reverberação | Paredes duras, vidro e grandes salas vazias causam eco. Adicione móveis estofados, use salas menores ou use um microfone para falar próximo. |
| Distância do alto-falante | Mantenha uma distância de 10 a 30 cm do microfone. Muito perto causa distorção plosiva (sons "p" e "b"). Muito longe capta o ruído da sala. |
| Estilo de falar | Fale em um ritmo natural. Evite resmungar, hesitar ou falar sobre os outros. Para cenários com vários alto-falantes, deixe pausas claras entre os alto-falantes. |
Seleção de microfone
Cenários diferentes exigem microfones diferentes. A escolha certa elimina o ruído na fonte.
| Cenário | Microfone recomendado | Por que |
|---|---|---|
| Call Center / ditado | Fone de ouvido com microfone boom (por exemplo, Jabra Evolve2, Plantronics) | O design de fala próxima rejeita o ruído de fundo. Distância consistente da boca ao microfone. Melhor precisão de alto-falante único. |
| Entrevistas/apresentações | Microfone de lapela (lapela) (por exemplo, Rode Wireless GO, DJI Mic) | Clipes para roupas, mãos livres. Bom para um alto-falante se movimentando. |
| Salas de reuniões | Microfone de matriz de conferência (por exemplo, Jabra Speak, Poly Sync, matriz XMOS) | Vários microfones com formação de feixe. Capta alto-falantes de todas as direções enquanto reduz o eco. |
| Aplicativos móveis | Microfone de dispositivo integrado | Aceitável para uso casual. Para aplicativos móveis de precisão crítica, peça aos usuários que usem fones de ouvido com microfone integrado. |
| Telefonia (8kHz) | N/A (áudio da portadora) | Use modelos de 8kHz. A qualidade do áudio é fixada pela rede telefônica. |
Se você controla o hardware de gravação, invista em um fone de ouvido USB com cancelamento de ruído. Um $50 (≈ R$ 251,015*) fone de ouvido melhora a precisão mais do que qualquer otimização de software.
Formato de áudio
| Parâmetro | Recomendação |
|---|---|
| Taxa de amostragem | 16 kHz ou superior. Use 8 kHz apenas para gravações telefônicas. Taxas de amostragem mais altas (44,1 kHz, 48 kHz) são reduzidas automaticamente – funcionam bem, mas custam mais largura de banda. |
| Canais | Mono. Estéreo é aceito, mas o segundo canal é ignorado. |
| Formato | PCM ou WAV (sem perdas). Eles preservam o sinal completo. |
| Compressão | Evite codecs com perdas (MP3, AAC, OGG) para caminhos de precisão crítica. Se precisar compactar, use OPUS a 32 kbps ou superior. |
| Profundidade de bits | 16 bits. |
Não aplique filtros de redução de ruído, AGC (controle automático de ganho) ou aprimoramento de áudio antes de enviar áudio para ASR. Esses filtros podem remover o sinal de fala junto com o ruído, degradando a precisão. Envie o áudio bruto e deixe o modelo ASR lidar com o ruído internamente.
Personalização de vocabulário
Quando sua saída ASR reconhece termos específicos incorretamente – nomes de marcas, nomes de produtos, jargão técnico, nomes próprios – a personalização de vocabulário corrige o problema. A técnica depende de qual família de modelos você usa.
| Técnica | Modelos | Como funciona |
|---|---|---|
| Contexto de prompt | Qwen-Omni | Descreva seu domínio no prompt do sistema. O modelo é um LLM que entende de áudio, por isso se adapta a cada solicitação. Mais flexível, mas com maior latência por solicitação do que o ASR dedicado. |
| Aprimoramento de contexto | Qwen3-ASR | Passe o contexto do domínio como uma mensagem do sistema. O modelo se adapta dinamicamente. |
| Hotwords | Fun-ASR | Crie uma lista de vocabulário com termos ponderados. Passe o ID da lista na chamada ASR. |
Contexto do prompt (Qwen-Omni)
Qwen-Omni não é ASR tradicional - é um LLM que entende de áudio. Descreva o seu domínio no prompt do sistema e o modelo se adapta sem qualquer pré-configuração. Esta é a abordagem mais flexível, mas tem maior latência por solicitação do que os modelos ASR dedicados.
Python
```python
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://maas.qwencloudapi.com/compatible-mode/v1",
)
completion = client.chat.completions.create(
model="qwen3-omni-flash",
messages=[
{
"role": "system",
"content": "You are transcribing investment banking discussions. "
"Key terms: Bulge Bracket, Boutique, Middle Market, LBO, DCF."
},
{
"role": "user",
"content": [
{
"type": "input_audio",
"input_audio": {
"data": "https://example.com/meeting.mp3",
"format": "mp3"
}
},
{"type": "text", "text": "Transcribe this audio."}
]
}
],
stream=True,
modalities=["text"],
)
for chunk in completion:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
```
Node.js
```javascript
import OpenAI from "openai";
const openai = new OpenAI({
apiKey: process.env.DASHSCOPE_API_KEY,
baseURL: "https://maas.qwencloudapi.com/compatible-mode/v1"
});
const completion = await openai.chat.completions.create({
model: "qwen3-omni-flash",
messages: [
{
role: "system",
content: "You are transcribing investment banking discussions. "
+ "Key terms: Bulge Bracket, Boutique, Middle Market, LBO, DCF."
},
{
role: "user",
content: [
{
type: "input_audio",
input_audio: {
data: "https://example.com/meeting.mp3",
format: "mp3"
}
},
{ type: "text", text: "Transcribe this audio." }
]
}
],
stream: true,
modalities: ["text"],
});
for await (const chunk of completion) {
if (chunk.choices?.[0]?.delta?.content) {
process.stdout.write(chunk.choices[0].delta.content);
}
}
```
curl
```bash
curl -X POST https://maas.qwencloudapi.com/compatible-mode/v1/chat/completions \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3-omni-flash",
"messages": [
{
"role": "system",
"content": "You are transcribing investment banking discussions. Key terms: Bulge Bracket, Boutique, Middle Market, LBO, DCF."
},
{
"role": "user",
"content": [
{
"type": "input_audio",
"input_audio": {
"data": "https://example.com/meeting.mp3",
"format": "mp3"
}
},
{
"type": "text",
"text": "Transcribe this audio."
}
]
}
],
"stream": true,
"modalities": ["text"]
}'
```
Use o contexto imediato quando a terminologia do seu domínio muda com frequência ou quando você precisa que o modelo entenda a intenção além da transcrição bruta. Para listas de termos estáveis com áudio previsível, hotwords ou aprimoramento de contexto oferecem menor latência.
Aprimoramento de contexto (Qwen3-ASR)
Passe o contexto específico do domínio no system mensagem. O modelo utiliza esse contexto para melhorar o reconhecimento de termos especializados – sem listas de vocabulário, sem ajuste de peso. Aceita listas de palavras, parágrafos ou uma mistura de ambos.
Antes e depois:
| Conteúdo de áudio | Sem contexto | Com contexto |
|---|---|---|
| Terminologia de banco de investimento | "...os principais bancos, Bird Rock, BB..." | "...os principais bancos, Bulge Bracket, BB..." |
O contexto usado: "Bulge Bracket, Boutique, Middle Market"
Formatos de contexto suportados – todos são igualmente eficazes:
- Lista de palavras:
"Bulge Bracket, Boutique, Middle Market"(vírgula, espaço ou matriz JSON separados) - Parágrafo: uma descrição do domínio em linguagem natural (por exemplo, um parágrafo sobre a terminologia de banco de investimento)
- Misto: Lista de palavras + parágrafo combinados no mesmo contexto
Python
```python
import os
import dashscope
dashscope.base_http_api_url = 'https://maas.qwencloudapi.com/api/v1'
messages = [
{
"role": "system",
"content": [{"text": "Bulge Bracket, Boutique, Middle Market"}]
},
{
"role": "user",
"content": [{"audio": "https://example.com/investment-banking-audio.mp3"}]
}
]
response = dashscope.MultiModalConversation.call(
api_key=os.getenv("DASHSCOPE_API_KEY"),
model="qwen3-asr-flash",
messages=messages,
result_format="message"
)
print(response.output.choices[0].message.content[0]["text"])
```
Java
```java
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.common.Role;
import java.util.*;
public class ContextEnhancementExample {
public static void main(String[] args) {
MultiModalConversation conv = new MultiModalConversation();
// System message with domain context
MultiModalMessage sysMessage = MultiModalMessage.builder()
.role(Role.SYSTEM.getValue())
.content(Arrays.asList(
Collections.singletonMap("text", "Bulge Bracket, Boutique, Middle Market")
))
.build();
// User message with audio
MultiModalMessage userMessage = MultiModalMessage.builder()
.role(Role.USER.getValue())
.content(Arrays.asList(
Collections.singletonMap("audio",
"https://example.com/investment-banking-audio.mp3")
))
.build();
MultiModalConversationParam param = MultiModalConversationParam.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model("qwen3-asr-flash")
.message(sysMessage)
.message(userMessage)
.build();
MultiModalConversationResult result = conv.call(param);
System.out.println(result.getOutput().getChoices().get(0)
.getMessage().getContent().get(0).get("text"));
}
}
```
O contexto é limitado a 10.000 tokens. O modelo é robusto para textos irrelevantes no contexto – incluindo nomes ou descrições não relacionados – com quase nenhum impacto negativo na precisão.
Palavras-chave (Fun-ASR)
Crie uma lista de vocabulário de termos que você want o modelo a ser priorizado e, em seguida, passe o ID da lista ao chamar o ASR. Isso segue um fluxo de trabalho de duas etapas:
- Crie uma lista de hotwords por meio da API Hotwords. Especifique
target_modelpara declarar qual modelo ASR usará esta lista. - Passe o ID da lista na chamada ASR. O modelo deve corresponder ao
target_modeldo passo 1.
Python
```python
import dashscope
from dashscope.audio.asr import *
import os
dashscope.base_http_api_url = 'https://maas.qwencloudapi.com/api/v1'
dashscope.base_websocket_api_url = 'wss://maas.qwencloudapi.com/api-ws/v1/inference'
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
target_model = "fun-asr-realtime"
# Step 1: Create hotword list
service = VocabularyService()
vocabulary_id = service.create_vocabulary(
prefix='my-app',
target_model=target_model,
vocabulary=[
{"text": "Bulge Bracket", "weight": 4},
{"text": "Middle Market", "weight": 4}
]
)
# Step 2: Use hotword list for recognition
if service.query_vocabulary(vocabulary_id)['status'] == 'OK':
recognition = Recognition(
model=target_model,
format='wav',
sample_rate=16000,
callback=None,
vocabulary_id=vocabulary_id
)
result = recognition.call('audio.wav')
print(result.output)
# Clean up when no longer needed
service.delete_vocabulary(vocabulary_id)
```
Java
```java
import com.alibaba.dashscope.audio.asr.recognition.*;
import com.alibaba.dashscope.audio.asr.vocabulary.*;
import com.alibaba.dashscope.utils.Constants;
import com.google.gson.*;
import java.io.File;
public class HotwordExample {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("DASHSCOPE_API_KEY");
Constants.baseHttpApiUrl = "https://maas.qwencloudapi.com/api/v1";
Constants.baseWebsocketApiUrl = "wss://maas.qwencloudapi.com/api-ws/v1/inference";
String targetModel = "fun-asr-realtime";
// Step 1: Create hotword list
JsonArray vocab = new JsonArray();
JsonObject word1 = new JsonObject();
word1.addProperty("text", "Bulge Bracket");
word1.addProperty("weight", 4);
vocab.add(word1);
VocabularyService service = new VocabularyService(apiKey);
Vocabulary vocabulary = service.createVocabulary(targetModel, "my-app", vocab);
// Step 2: Use hotword list for recognition
if ("OK".equals(service.queryVocabulary(vocabulary.getVocabularyId()).getStatus())) {
Recognition recognizer = new Recognition();
RecognitionParam param = RecognitionParam.builder()
.model(targetModel)
.apiKey(apiKey)
.format("wav")
.sampleRate(16000)
.build();
try {
System.out.println(recognizer.call(param, new File("audio.wav")));
} finally {
recognizer.getDuplexApi().close(1000, "bye");
}
}
service.deleteVocabulary(vocabulary.getVocabularyId());
System.exit(0);
}
}
```
Formato da palavra-chave
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
text |
corda | Sim | A palavra-chave. Deve ser uma palavra ou frase real. Veja os limites de comprimento abaixo. |
weight |
interno | Sim | Peso prioritário. Faixa: 1-5. Padrão: 4. |
lang |
corda | Não | Código de idioma (por exemplo, en, zh). Omitir a detecção automática. |
Limites de comprimento do texto:
- Contém caracteres não ASCII: a contagem total de caracteres não deve exceder 15.
- ASCII puro: a contagem de palavras separadas por espaço não deve exceder 7.
Ajuste de peso
-
Comece com peso 4. Isso funciona para a maioria dos termos.
-
Aumente para 5 somente se um período ainda estiver faltando após o teste. Um peso maior pode fazer com que o modelo tenha alucinações com a hotword onde ela não pertence.
-
Não defina todas as hotwords com peso 5. Quando tudo é de alta prioridade, nada é. Diferencie pela importância real.
O
target_modelespecificado ao criar a lista de hotwords deve corresponder ao modelo usado na chamada ASR. Uma incompatibilidade faz com que as hotwords não tenham efeito.
Para obter detalhes completos da API sobre como criar, consultar, atualizar e excluir vocabulários de hotwords, consulte a referência da API Hotwords.
Correção pós-processamento
A personalização do vocabulário lida com termos conhecidos. O pós-processamento captura todo o resto – erros gramaticais, palavras dependentes do contexto e homófonos ambíguos.
Padrão de trilha dupla
Para aplicações críticas de precisão (transcrição médica, processos judiciais, relatórios financeiros), combine ASR em tempo real com pós-correção LLM:
Audio Stream
|
v
+-------------------+ +-------------------+
| Realtime ASR | --> | LLM Post-Correct |
| (low latency) | | (high accuracy) |
+-------------------+ +-------------------+
| |
v v
Display immediately Replace with corrected text
(draft transcript) (final transcript)
- Fast track: Transmita áudio para o endpoint ASR em tempo real (
qwen3-asr-flash-realtimeoufun-asr-realtime). Exiba resultados intermediários imediatamente. - Faixa de correção: Colete resultados ASR em nível de frase. Envie-o para um LLM (por exemplo,
qwen-plus) com um prompt de correção com reconhecimento de domínio:
Fix any speech recognition errors in the following transcript.
Preserve the original meaning. Domain: [medical/legal/financial].
Transcript: "{asr_output}"
- Substitua o texto exibido pela versão corrigida assim que o LLM responder (normalmente de 1 a 2 segundos).
Este padrão é especialmente valioso quando:
- A terminologia específica do domínio é frequentemente mal reconhecida, mesmo com a personalização do vocabulário.
- Os requisitos de precisão excedem 98%.
- Um atraso de correção de 1 a 2 segundos é aceitável para a experiência do usuário.
Precisão de medição
- WER (Taxa de erro de palavras): Mede antes e depois de cada otimização. Compare um conjunto representativo de amostras de áudio com transcrições verificadas por humanos.
- Teste A/B: compare apenas a personalização de vocabulário com a personalização de vocabulário + correção de faixa dupla.
- Acompanhamento por termo: monitore a precisão de cada termo em sua lista de hotwords ou contexto. Alguns termos podem precisar de ajuste de peso ou contexto adicional.
ASR de alta simultaneidade
Ao executar o ASR em escala, use o pool de objetos para gerenciar Recognition instâncias. Isso evita a sobrecarga de criação de uma nova conexão WebSocket por solicitação.
Java: pool de objetos para reconhecimento
Use um pool de objetos Apache Commons Pool2 para gerenciar Recognition instâncias. Requer Java SDK >= 2.16.9.
Variáveis de ambiente:
| Variável | Padrão | Recomendação |
|---|---|---|
DASHSCOPE_CONNECTION_POOL_SIZE |
32 | 2x pico de simultaneidade |
DASHSCOPE_MAXIMUM_ASYNC_REQUESTS |
32 | Corresponder ao tamanho do pool de conexões |
DASHSCOPE_MAXIMUM_ASYNC_REQUESTS_PER_HOST |
32 | Corresponder ao tamanho do pool de conexões |
RECOGNITION_OBJECTPOOL_SIZE |
500 | Simultaneidade de pico de 1,5x-2x |
import com.alibaba.dashscope.audio.asr.recognition.Recognition;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
class RecognitionFactory extends BasePooledObjectFactory<Recognition> {
public Recognition create() { return new Recognition(); }
public PooledObject<Recognition> wrap(Recognition obj) {
return new DefaultPooledObject<>(obj);
}
}
// Create a global singleton pool
GenericObjectPoolConfig<Recognition> config = new GenericObjectPoolConfig<>();
int poolSize = 500; // Or read from RECOGNITION_OBJECTPOOL_SIZE
config.setMaxTotal(poolSize);
config.setMaxIdle(poolSize);
config.setMinIdle(poolSize);
GenericObjectPool<Recognition> recognitionPool =
new GenericObjectPool<>(new RecognitionFactory(), config);
// In each task thread:
Recognition recognizer = recognitionPool.borrowObject();
try {
// ... run recognition task
recognitionPool.returnObject(recognizer);
} catch (Exception e) {
// Do not return failed objects
}
O tamanho do conjunto de objetos deve ser menor ou igual ao tamanho do conjunto de conexões. Caso contrário, os threads serão bloqueados enquanto aguardam conexões disponíveis.
Lista de verificação de produção
- [ ] Áudio capturado com microfone apropriado para o cenário
- [] Formato de áudio sem perdas (PCM/WAV), mono, 16 kHz+
- [] Sem filtros de pré-processamento (redução de ruído, AGC) aplicados ao áudio
- [] Personalização de vocabulário configurada (aprimoramento de contexto ou hotwords, correspondendo à sua família de modelos)
- [ ] Para palavras-chave:
target_modelcorresponde ao modelo ASR em uso - [ ] Para hotwords: pesos ajustados de forma incremental, nem todos definidos no máximo
- [] WER medido em amostras de áudio representativas
- [] Padrão de trilha dupla avaliado para caminhos críticos de precisão
- [] Tamanhos do pool de conexões e do pool de objetos configurados para carga de pico esperada
- [] O tratamento de erros retorna objetos com falha para descarte (não de volta ao pool)
- [] Tratamento de fallback para indisponibilidade do serviço ASR
- [] O monitoramento rastreia a precisão do reconhecimento ao longo do tempo
Modelos suportados
| Técnica | Modelos suportados |
|---|---|
| Contexto de prompt | qwen3.5-omni-plus, qwen3.5-omni-flash, qwen3.5-omni-plus-realtime, qwen3.5-omni-flash-realtime, qwen3-omni-flash |
| Aprimoramento de contexto | qwen3-asr-flash, qwen3-asr-flash-realtime, qwen3-asr-plus, qwen3-asr-plus-realtime |
| Hotwords | fun-asr-realtime, fun-asr (e variantes datadas) |
Para obter a lista completa de modelos, consulte Modelos de fala para texto.
Preços
- Aprimoramento de contexto: Sem custo adicional. Padrão Qwen3-ASR aplica-se o preço por token.
- Hotwords: Gratuito. Não há custo para criar ou usar vocabulários de hotwords.
Limites
- Aprimoramento de contexto: máximo de 10.000 tokens por mensagem do sistema.
- Hotwords: até 10 listas de hotwords por conta (compartilhadas entre modelos). Até 500 hotwords por lista. Solicite um aumento, se necessário.