调用大模型失败时,报错怎么翻译给用户?哪些错误重试也没用?
简化版
模型服务的报错是英文 JSON 或框架包装过的异常,直接弹到页面上没人看得懂。统一出口要把它翻译成「该去哪里改什么」:欠费去充值,Key 无效去模型配置页检查密钥,模型名不存在去核对名称,输入太长去精简正文,429 限流稍后重试,超时检查网络和接口地址。翻译的同时按可重试性分类:欠费、Key 无效、模型名写错属于账户和配置问题,重试多少次都不会好,批量任务遇到就应该立即停;限流、超时、服务端 5xx 可以退避后重试;输入超长和输出被截断要改输入或上限,原样重试没有意义。框架自带的自动重试次数要设小,避免 Key 填错时把额度浪费在反复重试上。
详细版
| 报错 | 典型特征 | 翻译成 | 重试有没有用 |
|---|---|---|---|
| 欠费、额度用完 | 平台欠费码、insufficient_quota | 去平台充值 | 没用 |
| Key 无效 | HTTP 401、invalid_api_key | 去模型配置页检查密钥 | 没用 |
| 模型名不存在 | model_not_found、HTTP 404 | 核对模型名称 | 没用 |
| 输入超长 | context_length_exceeded | 精简输入 | 原样重试没用 |
| 输出被截断 | HTTP 200,结束原因 length | 调大最大输出或精简输入 | 原样重试没用 |
| 限流 | HTTP 429 | 稍后重试 | 退避后有用 |
| 超时、连不上 | 超时异常、连接异常 | 检查网络和接口地址 | 偶发时有用 |
落地要点:
- 翻译规则只写一份,放在统一调用出口里,对话、向量、Agent 三种调用共用。
- 没匹配上的报错不丢,截断原文后返回,保留排查线索。
- 翻译后的原因写进调用日志,页面、日志看到的是同一句话。
- 批量任务按可重试性决定去留:单条偶发失败记下来继续,遇到重试无用的错误立即停。
完整版教学
一、报错长什么样
模型调用失败时,调用方拿到的东西有三种形态:
HTTP 错误响应 状态码 401 / 404 / 429 / 500,响应体是服务商自己的 JSON:
{"error": {"code": "invalid_api_key", "message": "Incorrect API key ..."}}
框架包装的异常 SDK 把 HTTP 错误包成运行时异常,信息在 message 里,
网络问题的真实原因常常藏在 getCause() 里
看起来成功的失败 HTTP 200,但结束原因是 length,正文只有半截
第三种最容易漏掉:它不算报错,框架不会抛异常,只有主动检查结束原因才能发现。前两种直接抛给页面,用户看到的是一大段英文加状态码,既看不懂,也不知道该去改哪里。
二、按「该去哪里改」翻译
翻译的目标不是把英文换成中文,而是告诉看到提示的人下一步做什么:
| 翻译前 | 翻译后 |
|---|---|
Incorrect API key provided | API Key 无效,请到【AI 模型配置】检查密钥是否填错或已失效 |
The model xxx does not exist | 模型名不存在,请到【AI 模型配置】核对模型名称 |
This model's maximum context length is ... | 输入正文太长,超出了模型单次能处理的上限,请精简后重试 |
Rate limit reached | 请求太频繁被平台限流,请稍后重试 |
Read timed out | 连不上模型服务或等待超时,请检查网络和接口地址 |
识别时优先看稳定的错误码和状态码,其次再看错误信息里的关键字。不同服务商用词不同,比如欠费有的叫 insufficient_quota,有的叫 Arrearage,关键字要按实际接入的服务商补全。一条都没匹配上时,把原文截断到一两百字返回,保留排查线索。
记忆钩子:好的报错提示回答三个问题:出了什么问题、去哪里改、改完要不要重试。
三、按可重试性分三类
翻译之外,更重要的是判断「再试一次有没有用」:
| 类别 | 例子 | 处理 |
|---|---|---|
| 重试无用 | 欠费、Key 无效、模型名不存在、没有模型权限 | 不重试,立即报错,批量任务立即停 |
| 改了再试 | 输入超长、输出被截断、参数不合法 | 不原样重试,提示改输入或调上限 |
| 稍后可能好 | 限流、超时、服务端 5xx | 有限次数退避重试 |
第一类的本质是账户或配置问题,只有人去改了配置才会好。把它和第三类混在一起统一重试,Key 填错一次,每个请求都要白试好几遍。
四、框架自动重试设多少
很多 SDK 自带失败重试,默认可能是两三次。重试次数直接影响两件事:
最坏耗时 = 单次超时 × (重试次数 + 1)
单次超时 90 秒、重试 1 次:最坏 180 秒
单次超时 90 秒、重试 3 次:最坏 360 秒
Key 填错时的无效请求数 = 调用次数 × (重试次数 + 1)
100 次调用、重试 3 次:400 次注定失败的请求
100 次调用、重试 1 次:200 次
所以自动重试设成 1 次左右就够:能扛住偶发的网络抖动,又不会在配置错误时把等待时间和请求数成倍放大。更精细的做法是只对第三类错误重试,但这要在框架的重试机制之外自己写判断。
五、批量任务:遇到重试无用的错误立即停
批量向量化、批量生成这类任务一次要调几百上千次模型。按单条处理失败的常见写法是「记下原因,继续下一条」,这对偶发失败是对的,对配置错误却是灾难:
500 个片段,API Key 填错:
逐条继续:500 次调用全部失败,最后得到一句「500 条失败」
识别到重试无用立即停:第 1 条失败就停,提示「API Key 无效,请到模型配置检查密钥」
判断依据就是第三节的分类:翻译后的原因如果属于「重试无用」,立即结束整个任务,并把原因和已经成功的条数一起告诉用户。
六、翻译规则只写一份
项目里调用模型的地方很多:普通对话、流式对话、向量化、带工具的 Agent。每处各写一套 try-catch 和翻译,很快就会不一致:同一个 Key 错误,这个页面说「密钥无效」,那个页面说「调用失败:401」。正确的做法是把翻译放进统一调用出口的一个函数里,各处失败都调它;重试无用的判断也基于同一个函数的翻译结果,而不是另写一套关键字匹配。
翻译后的原因同时写进调用日志的失败原因列。这样管理员在日志页看到的,和用户在页面上看到的是同一句话,排查时对得上。
七、常见误区与追问
- 误区:把服务商的报错原样返回给页面,信息最全。 用户看不懂、不知道去哪改,翻译成可操作的中文,原文留在日志里。
- 误区:所有失败都重试几次更稳。 欠费、Key 无效、模型名错误重试多少次都一样,只会放大等待时间和请求数。
- 误区:HTTP 200 就是调用成功。 输出撞上最大长度时照样返回 200,正文只有半截,要检查结束原因。
- 误区:批量任务单条失败就记下来继续,总没错。 配置类错误会让每一条都失败,应该识别出来立即停。
- 追问:翻译规则按错误码匹配还是按文字匹配? 优先错误码和状态码,文字关键字作为补充,并按实际接入的服务商补全。
- 追问:没匹配上任何规则的报错怎么办? 截断原文后返回,保留排查线索,同时写进日志。
八、加强记忆
模型报错先翻译、再分类。翻译按「去哪里改」写:欠费去充值、Key 和模型名去配置页、输入太长去精简、限流稍后试、超时查网络,没匹配上的截断原文保留线索。分类按可重试性:账户和配置问题重试无用,批量任务遇到立即停;输入超长和输出截断改了再试;限流、超时、5xx 有限退避重试。框架自动重试设小,最坏耗时是单次超时乘以重试次数加一。翻译规则只写一份放在统一出口,结果写进调用日志,页面和日志看到的是同一句话。
项目实战落地
项目里怎么做的
《AI Agent旅游行程智能规划平台》的统一出口 AiChatService 里只有一个翻译函数 describeModelError,调用对话模型、向量模型、行程编排三处失败都用它:
| 识别关键字 | 翻译成 |
|---|---|
Arrearage、insufficient_quota、overdue | 模型平台账户欠费或免费额度已用完,请先到平台充值 |
Invalid API-key、invalid_api_key、401 | API Key 无效,请到【AI模型配置】检查密钥 |
model_not_found、Model not exist | 模型名不存在,请到【AI模型配置】核对模型名称 |
context_length_exceeded 等 | 输入正文太长,超出了模型单次能处理的上限 |
| JSON 解析异常的特征文字 | 工具参数不完整(输出被截断),请调大该用途的最大输出 |
429、rate_limit、Throttling | 请求太频繁被平台限流,请稍后重试 |
timed out、timeout、Connection | 连不上模型服务或等待超时,请检查网络和接口地址 |
没匹配上时截断到 200 字返回原文。欠费、Key 无效、模型名不存在这三句提示定义成常量,isFatalModelError 按「翻译后的原因里含这三句之一」判断重试也没用,批量向量化靠它决定是否提前停。模型工厂的自动重试 MAX_RETRIES = 1,单次超时 90 秒。
《AI Agentic RAG高级企业知识库平台》有两个翻译函数,按调用方式分工:走 httpx 的重排接口拿得到响应对象,按状态码翻译(401 Key 无效、403 没有该模型权限、404 地址或模型名不存在、429 太频繁或额度用尽);走 LangChain SDK 的对话和向量模型拿到的是异常,按异常文本翻译。
为什么这样取舍
- 重试只设 1 次。 失败后只再试一次,避免 Key 填错时把额度浪费在反复重试上。
- 重试无用的判断基于翻译结果。 三句提示是常量,翻译和判断用同一份规则,不会出现「翻译成 Key 无效却被当成可重试」的情况。
- 两种翻译入口。 状态码只有直接拿到 HTTP 响应时才有;SDK 把错误包成异常之后,只能看异常文本。
翻译后的原因会写进调用日志的失败原因列,日志字段见「大模型应用日志应该记录哪些字段?」。
面试官还会追问
- 旅游项目批量向量化一篇文档时遇到重试无用的错误中断了,已经成功的片段怎么处理?中断提示里会写什么?
- 一篇文档的片段全部向量化失败时,页面上看到的是哪一次失败的原因?
学完《AI Agent旅游行程智能规划平台》,上面这些追问你都会迎刃而解。