音频转写出错时,很多人第一反应是换模型或怀疑识别能力,但多数故障其实发生在文件、鉴权、网络和限流这四层。转写接口是 multipart/form-data 上传,链路比纯文本接口长,排查顺序也应该更长:先看 HTTP 状态码和错误类型,再看请求本身,最后才调整音频和提示词。
本文按 401、400 格式错误、413 文件过大、429 限流、超时,以及返回空文本或乱码这几类拆开,给出排查路径和一段可复用的处理代码。文件限制、模型名和错误格式可能随版本调整,以官方文档和站内文档为准,价格以模型价格为准。
说明:OpenAI、Whisper 是其权利人的商标,本文仅作技术接入说明。接口限制、支持格式和模型名称可能调整,请以官方文档与站内文档为准。
一、先建立排查顺序
| 现象 | 常见状态码 | 高频原因 | 处理方向 |
|---|---|---|---|
| 鉴权失败 | 401、403 | Key 错误、未带 Bearer、无音频接口权限 | 修凭证,不要重试 |
| 格式不支持 | 400 | 编码格式不在支持列表、扩展名与实际编码不符 | 转码后重传 |
| 文件过大 | 413 或 400 | 超过单文件大小上限 | 压缩或切分 |
| 请求过频 | 429 | 每分钟请求数、并发或额度超限 | 退避、排队、拆 Key |
| 服务端错误 | 500、502、503 | 上游异常或过载 | 退避后有限重试 |
| 超时 | 无响应或连接中断 | 文件大、上传慢、处理时间长 | 切分、调整超时 |
| 返回空文本 | 200 | 静音、音量低、语言误判、编码异常 | 检查音频而非重试 |
响应头或错误体中如果有 request-id,务必保留。找服务方排查时,一个请求 ID 加一段可复现的最小音频,比十张截图有用。
二、401:先查请求头,再查 Key
401 表示身份验证没有通过,和余额、模型能力通常无关。按下面顺序排查:
- 鉴权头是否为
Authorization: Bearer <key>,不要漏掉Bearer和空格。 - Key 前后是否有空格、换行或引号。从聊天窗口复制时最容易带入。
- 环境变量是否真的加载。可以只打印前缀确认,不要把完整 Key 写进日志。
- Key 是否被吊销、是否属于当前项目,账户是否有音频接口权限。
- Base URL 是否为
https://ai.zhongshangqihang.com/v1,路径是否为/v1/audio/transcriptions。 - 如果是网关,确认该入口是否开放音频转写,不要假设文本接口可用,音频接口就一定可用。
还有一个常见错误:把文件塞进 JSON 请求体。转写接口要求 multipart/form-data,命令行要用 curl -F "file=@meeting.mp3",而不是 -d。请求体格式错了,有时会表现成 400,也可能因为没读到有效凭证而返回 401。
三、400 与 413:格式和大小问题
400 里最常见的是格式不支持。官方文档列出的常见音频格式包括 mp3、mp4、mpeg、mpga、m4a、wav、webm 等,完整列表和编码要求以当前文档为准。改扩展名不等于转码:把 .amr 重命名成 .mp3,服务端读到的仍是原编码,照样报错。
413 通常表示文件超过单文件大小上限。官方常见上限是 25 MB,具体以文档为准。处理方式有两种:
- 压缩:统一转成 16 kHz 单声道,语音场景不需要高码率。可用
ffmpeg -i input.mp3 -ac 1 -ar 16000 -b:a 64k output.mp3。 - 切分:按 10 分钟一段切开,逐段转写后合并。切点尽量选静音处,段间留一点重叠,避免把词切成两半。
长音频不要只靠压缩硬塞。文件越大,上传越慢,超时概率越高,失败后重传的成本也越高。切分并行更稳,但要控制并发,否则会从 413 变成 429。
四、429:限流不等于余额不足
429 表示请求超过了速率、并发或额度限制。同样是 429,错误体里的类型可能不同:有的表示频率超限,有的表示额度不足。先看错误类型,再决定是等待、降并发,还是充值。
常见触发场景包括:批量任务同时开太多并发;多个服务共用一把 Key;失败后立即重试,形成重试风暴;长音频占用连接时间过久;免费或低档位账号的每分钟额度较小。
处理顺序是:先看响应里有没有 Retry-After,再按指数退避加随机抖动重试;把批量任务放进队列,限制同时在跑的请求数;按项目拆 Key,避免互相挤占;给重试设置上限和告警,不要无限循环。转写按音频时长计费,重复提交还可能带来重复计费,重试前先确认上一次是否已经成功。
五、超时:区分上传慢还是处理慢
超时可能发生在三个阶段:连接建立、文件上传、服务端处理。小文件也超时,优先查网络、代理和 Base URL;大文件稳定超时,优先切分和压缩。
客户端要显式设置超时,不要依赖默认值。转写耗时和音频时长、文件大小、排队情况都有关,给一个偏宽松但有限的上限,例如两到三分钟,再用任务记录区分“已提交未返回”和“根本没发出去”。超时后的自动重试要谨慎:如果服务端其实已经处理完成,重试会产生第二次计费和重复结果。
六、200 但空文本或乱码
这两种情况没有 HTTP 错误,排查方向完全不同。
空文本常见于:整段静音或音量过低;语言参数和音频不符;声道异常,主声道没有声音;文件编码能上传但解码异常。先做音量检测,显式传 language=zh,再统一转成 16 kHz 单声道试一次。
乱码或大段错字常见于:语种误判、方言口音重、背景音乐和人声混在一起、多人抢话、录音距离过远。可以在请求里用 prompt 传入人名、产品名和专业术语,转写后用词表做替换。若音频本身不可用,换模型也救不回来,应该回到录音和预处理环节。
七、重试与切分:一段可复用的代码
重试只适用于瞬时错误。401、400、413 改请求才有意义,盲目重试只会放大问题。
import os
import random
import time
from openai import (
OpenAI,
APIConnectionError,
APIStatusError,
APITimeoutError,
RateLimitError,
)
client = OpenAI(
api_key=os.environ["WHISPER_API_KEY"],
base_url="https://ai.zhongshangqihang.com/v1",
timeout=180,
)
def transcribe(path: str, model: str = "whisper-1", retries: int = 4) -> str:
for attempt in range(retries):
try:
with open(path, "rb") as f:
result = client.audio.transcriptions.create(
model=model,
file=f,
language="zh",
response_format="verbose_json",
)
text = (result.text or "").strip()
if not text:
raise ValueError("空转写:先检查音量、语言和声道")
return text
except RateLimitError:
wait = min(2 ** attempt, 30) + random.random()
print(f"429,等待 {wait:.1f}s 后重试")
time.sleep(wait)
except (APITimeoutError, APIConnectionError):
time.sleep(min(2 ** attempt, 30) + random.random())
except APIStatusError as exc:
if exc.status_code >= 500:
time.sleep(min(2 ** attempt, 30) + random.random())
else:
raise # 400/401/413 应该改请求,不要重试
raise RuntimeError("重试次数已用完")
print(transcribe("meeting.mp3"))
模型名以站内文档为准;whisper-1 只是常见示例。超过大小限制的音频,先用 ffmpeg 切分,再对每一段调用这个函数,合并时记得把各段起始时间加回去。
八、日志与找服务方排查的清单
- 记录发生时间、时区、HTTP 状态码和错误类型。
- 记录
request-id,以及请求打的是官方入口还是网关入口。 - 记录文件名、实际编码、时长、大小、采样率和声道数。
- 记录
model、language、response_format等关键参数。 - 记录重试次数、每次等待时间和最终结果。
- 记录是否为共享 Key、当时的并发数和批量任务规模。
- 准备一段 10–30 秒、可公开的最小复现音频,去掉个人信息。
提交给服务方时,不要发送完整 Key,也不要在未获授权的情况下发送客户录音。能稳定复现的最小样本,比“有时候会报错”的描述有效得多。
常见问题
413 和 400 都是文件问题,怎么区分?
413 一般表示体积超过上限,处理方式是压缩或切分;400 更多是格式、参数或编码问题,处理方式是转码和检查字段。先看错误类型和消息,不要只看状态码。
429 一直不恢复怎么办?
先看错误类型是频率超限还是额度不足。频率问题降并发、排队、拆 Key;额度问题需要充值或换入口。持续 429 时不要继续加密重试,否则只会延长恢复时间。
超时该不该直接重试?
先判断请求是否可能已经在服务端完成。转写可能已计费,直接重试会产生重复结果和重复费用。用任务记录或幂等设计确认状态,再决定是否重发。
转写为空是不是模型坏了?
多数不是。优先检查音量、静音段、语言参数、声道和实际编码。用同一段音频换一个入口测试,可以快速区分是音频问题还是服务问题。
网关报错和官方报错怎么区分?
保留 request-id 和错误类型,用同一条请求分别打两个入口。若官方入口正常、网关入口报错,问题多半在网关配置或转发;两边都报错,再查 Key、网络和音频文件。
下一步
先注册中商起航 AI 网关,用一段一分钟音频把 401、413、429 和超时各演练一次,再接入生产监控。模型可用性与价格以模型价格为准。
相关阅读:
