版权与内容来源声明
本文为原创整理。文中涉及官方文档、开源仓库、论文与公开报道的内容,均在附表 A 中标注来源;引用官方原文保持原样,不作改写。文中命令、版本号与界面截图以本文成文时的实测/核验结果为准,标注「待验证」的部分请以你本地环境实际输出为判断依据。本文不推荐任何不合规的软件获取方式,也不对任何收益结果作承诺。转载请注明出处。
第 1 章 三种超时,对应三种完全不同的状态
1.1 先把分层超时观搬过来
网络工程里,超时不是一个数而是一组数。连接超时管「对端在不在、路通不通」,握手没完成就放弃;读超时管「对端接下了活却不吭声」;总超时管「这次调用整体允许占我多少时间」。亚马逊官方工程文集强调:任何跨进程调用都该设超时,且连接超时与请求超时是两件事,前者不宜用操作系统的套接字接收超时顶替,因为它未必覆盖域名解析和安全握手。
1.2 大模型调用把这件事搅乱了
普通接口短连接、短计算、无副作用,几毫秒就返回;大模型调用三项全反——长连接、单次可能算几十秒到几分钟、而且常带副作用。副作用指的是这次调用在结果之外还改了别处状态,比如扣费、写库、触发下游工具。
同一个读超时背后可能是三件完全不同的事:
- 状态一:请求根本没发出去。连接阶段就超时,服务端连你的请求头都没看见。
- 状态二:发出了,但没等到响应。可能还在算,可能算完而响应在回程丢了,也可能失败了而错误响应也丢了。
- 状态三:副作用已经发生,只是响应丢了。计费已产生、记录已写入、下游工具已被触发。
亚马逊那篇官方文章提醒:超时或失败并不等于副作用没有发生;副作用重复执行不可接受时,最佳实践是把接口设计成幂等的。
1.3 硬规则:重试前先按请求标识查状态
三种状态在客户端看起来一样,只能靠外部信息把它们分开。OpenAI 的接口说明给了两条路:响应里回一个唯一的服务端请求标识响应头;你也可以自带一个客户端请求标识(只允许 ASCII 字符、不超过 512 个字符)。官方还点明:超时或网络异常、拿不到服务端标识时,可以拿自己生成的那个值去查平台是否收到过这个请求。
⚠️代码待验证
{"ts":"2026-10-13T06:00:00Z","client_request_id":"调用前生成的 UUID,重试时必须复用同一个值","server_request_id":"从响应头里取到的服务端请求标识,收到时才补写","attempt":1,"connect_timeout_ms":2000,"first_byte_timeout_ms":30000,"total_timeout_ms":120000,"tool_side_effect":false,"outcome":"sent_no_response"}关键是client_request_id必须在调用之前生成、并且跨重试保持不变;每次重试都换一个新值的话,三次重试在日志里就是三条互不相干的记录。
| 你观察到的现象 | 更可能是哪种状态 | 重试前必须先做什么 |
|---|---|---|
| 连接阶段就超时,一个字节都没送出去 | 状态一:根本没发出去 | 可以直接重试,风险最低 |
| 连接已建立、请求已发出,首字节之前就读超时 | 状态二:发了,但没响应 | 先按请求标识查一次,再决定是否重试 |
| 已收到部分内容,或计费已发生、下游工具已被触发,连接随后断开 | 状态三:副作用可能已落地 | 禁止无脑重试,先查副作用是否已生效 |
第 2 章 把「能不能重试」做成一张白名单
2.1 别只用「是不是 5 开头」来分
很多人的直觉规则是:4 开头是我的错,不重试;5 开头是服务端的错,重试。这条在大模型接口上只能算半个答案:亚马逊官方文章提醒过,最终一致性会让这条线变模糊——此刻看起来是客户端错误的返回,下一刻可能就该成功;而有些 5 开头的返回,重试多少次都不会变好。
可靠的依据是两个维度:错误是不是暂时性的,以及这次调用是不是已经产生了副作用;后者最容易被漏掉,因为你过去处理的请求大多是只读的。
2.2 白名单
| 你看到的返回 | 性质 | 能不能重试 | 依据与注意点 |
|---|---|---|---|
| 网络层失败:连接被重置或超时,请求尚未送出 | 传输失败 | 可以 | 请求大概率没到服务端,偏安全 |
| HTTP 408 | 请求超时 | 可以 | 官方客户端默认在重试范围内 |
| HTTP 409 | 资源状态冲突 | 有限度地可以 | 官方客户端默认可重试 |
| HTTP 429,且带 Retry-After | 临时限流 | 可以,按该头部的值等 | 服务端已告诉你要等多久 |
| HTTP 429,但原因是配额、余额或用量上限 | 配额类 | 不可以 | 重试不会恢复访问权限 |
| HTTP 500 | 服务端内部错误 | 可以 | 官方建议短暂等待后重试 |
| HTTP 503,模型临时过载 | 服务端过载 | 可以,按 Retry-After,否则加大间隔 | 官方明确可重试 |
| HTTP 529,服务端过载 | 服务端过载 | 可以 | 官方客户端默认自动重试两次 |
| HTTP 400 / 401 / 402 / 403 / 404 / 413 | 请求、账号或账单问题 | 不可以 | 同样的请求重试还是同样的结果 |
| HTTP 504,服务端处理超时 | 处理超时 | 谨慎 | 官方建议改用流式接口规避长请求超时 |
要单独强调那一行「配额类 429」:它和其他 429 长得一样,处理方式却相反。官方错误码说明里,429 至少还混着余额耗尽、组织与项目支出上限、组织用量上限,并明确写了重试账单、支出或配额类错误不会恢复访问权限。
2.3 重试只在链条里的一层做
亚马逊官方文章给了个算术:五层深的调用链、每层各重试三次,最底层数据库开始失败时,压到它身上的负载会放大 243 倍,几乎不可能恢复。
大模型应用的层数往往更多:前端一层、你封装的服务一层、官方 SDK 再自动一层。文档写明,部分错误默认会自动重试两次左右;Anthropic 也写明其 SDK 对连接错误、限流和 5 开头错误自动重试、默认两次并遵守 Retry-After。也就是说,你什么都不写,链条里已经有一层在重试;你再套一层就是乘出来的。规矩是:指定唯一一层重试,通常是最外层那个拥有整体时间预算的调用方;其余层只给紧凑超时、不自己重试。
第 3 章 指数退避必须带抖动,固定间隔为什么一定失败
3.1 固定间隔的病灶是同步,不是间隔太短
很多人把固定间隔重试的失败归因于「等得不够久」。真正的病灶是同步:一百个并发请求在同一毫秒撞上限流、都等 1 秒,1 秒后它们仍然会同时到达。改成指数增长(1 秒、2 秒、4 秒……)能降低频率,但仍然同步——尖峰只是被推迟。亚马逊架构博客那篇被反复引用的实验文章,结论就是:不带抖动的指数退避是明显的输家。
3.2 抖动就是往等待里掺随机数
抖动的本质是给定时器加一点随机偏移,避免一批设备在同一时刻做同一件事。搬到重试上,就是把「等多久」从确定值换成随机值。三种主流写法,官方定义得很清楚。
| 写法 | 等待时长怎么取 | 特点 | 什么时候用 |
|---|---|---|---|
| 无抖动 | 固定值,或按底数乘 2 的幂次增长 | 所有客户端同步重试,尖峰只是被推迟 | 不建议单独使用 |
| 全抖动 | 在 0 到封顶值之间均匀取一个随机数 | 打散最彻底,整体完成的工作量最低 | 大量独立客户端共享一个上游 |
| 等量抖动 | 封顶值的一半固定,另一半随机 | 保留了一个最低等待下限 | 你希望至少等够一段恢复时间 |
| 去相关抖动 | 在上一次等待的 1 倍到 3 倍之间随机、再封顶 | 不断游走,不依赖尝试次数 | 客户端状态不精确、想更温和地施压 |
对「很多客户端、一个上游」的场景,全抖动是性价比最高的默认。
⚠️代码待验证
importrandomdefnext_wait_ms(base_ms,attempt,cap_ms):# attempt 从 1 开始计数ceiling=min(cap_ms,base_ms*(2**(attempt-1)))returnrandom.uniform(0,ceiling)# 全抖动:0 到封顶值之间均匀取3.3 封顶、次数上限,再加一个重试配额
抖动解决「何时重试」,还要解决「重试到什么时候停」。指数退避不封顶,十几轮后等待会膨胀到以小时计,所以要封顶;封顶后又回到固定间隔、又会同步,所以封顶必须和抖动一起用。次数也要有上限:连续失败五次的请求,第六次通常也不会成功。
更关键的是重试配额。亚马逊官方文章的比喻很形象:重试是「自私的」,客户端在用服务端更多时间换自己更高的成功可能;于是客户端放一个令牌桶,只要有令牌就能重试,令牌耗尽就退到固定低速率。它限的是重试流量,每次都失败的客户端会把自己的额度耗干,从而停止放大。
第 4 章 收到 HTTP 429 之后,到底该等多久
4.1 先看响应头,那是权威值
标准答案一句话:服务端给了等待指示就以它为准,没给才用自己算的退避值。OpenAI 的限流文档写明,因临时限流返回 429、因模型过载返回 503 时,响应里可能带 Retry-After,并明确说明这个头不意味着配额、账单类错误重试就能成功——这既说明它只对临时类错误有效,也让它成为判断当前 429 属于临时限流还是配额类的旁证。
Anthropic 的限流说明同样写明,超出速率限制会收到 429 并附带指示等待时长的响应头。所以优先级是:服务端给的等待值 > 自己算的带抖动退避值,两者都要被次数上限和重试配额约束。
⚠️代码待验证
defwait_seconds_from_response(resp,fallback_ms):header=resp.headers.get("Retry-After")ifheaderisnotNone:try:returnfloat(header)# 常见形式是「等多少秒」exceptValueError:returnfallback_ms/1000.0# 另一种是日期形式,这里保守回退returnfallback_ms/1000.04.2 同一个 429 内部还要再分一次类
同为 429,官方至少区分出速率限制被触发、预付余额耗尽、组织用量上限、组织支出上限、项目支出上限。对纯粹的速率限制,官方建议放慢节奏、遵循 Retry-After;对后几类,重试不会恢复访问权限。可以按这条规则分诊:
- 429 带 Retry-After,且用量曲线确实在往上冲——按临时限流处理,等待后重试,同时把整体发送速率降下来。
- 429 不带 Retry-After,或错误详情指向余额、支出、用量上限——按配额类处理,不重试,去处理账务或限额,并告警。
- 429 反复出现且重试后立刻再撞——这是长期超载。官方文章的判断很直白:退避只能短期救火,负载不是暂时性的时候把负载往后推没有用,这时该降速或削峰。
4.3 长请求更容易踩超时,流式是官方给的解法
官方文档直接建议:对处理超时类错误改用流式接口,也不要在不用流式的情况下把最大输出长度设得过大,因为一些网络会丢弃长时间空闲的连接。对通信背景的人来说这是老朋友——长连接怕静默,静默久了中间设备就要动手。
第 5 章 流式输出吐到一半断了,能不能接着写
5.1 流式带来的两种新失败
改成流式之后,成功状态在生成开始时就已经返回了,后面的错误不再以状态码出现,而是作为流里的错误事件发过来。Anthropic 的流式文档写明:高峰期你可能在事件流里收到一个过载类错误事件,它通常对应 429 那一档的服务过载。OpenAI 的限流文档把它写成一条操作纪律:流式请求开始之后出现的错误可能以流事件的形式到达,不要在已经消费了输出之后自动重放一个请求。所以流式除了总超时,还需要一个空闲超时——相邻两个事件间隔超过阈值就主动断开。
5.2 判断:是重放,还是续写
分界点是:在断开之前,你有没有已经开始消费输出。什么都没收到,就和普通请求失败一样,退避后重试即可;已经收到一部分就复杂了,因为你对是否已产生副作用并不确定。
| 中断发生的时机 | 能不能续 | 正确动作 |
|---|---|---|
| 连接建立阶段就失败,一个片段都没吐 | 不用续,直接重试 | 退避后重试整个请求 |
| 已经吐了一部分普通文本,中途断开 | 可以续写 | 保存已收到的部分,发新请求让它接着写 |
| 已吐出的部分里包含工具调用块 | 工具调用块不能部分恢复 | 回退到最近一个完整文本块的粒度再续写 |
| 已吐出的部分里包含思考块 | 思考块同样不能部分恢复 | 同上,或退回「先查副作用再决定」 |
| 流已正常开始之后收到错误事件 | 不属于自动重试范围 | 按官方纪律:不要自动重放已消费输出的请求 |
「怎么续」也有版本差异:较早的模型版本可以把半截回答当作助手消息前缀发回去续写;较新的模型版本改为要求发一条用户消息,内容是半截回答加一句「请从这里接着写」。工具调用块与思考块都无法部分恢复。
5.3 请求标识在流式场景里更值钱
流式里请求标识更值钱:非流式至少还有成功与失败两个结局,流式却可能是「成功了一半」。官方还给「后台模式」提供了断点续读,连接中断后可从上次收到的序号接着读。
文中反复用到的那几张判断表:第 1 章的三态判断表、第 3 章的抖动对照表和第 5 章的流式中断处置表,我另外整理成了一份可以直接贴进值班手册的清单版本。放在资料包里,扫码即可获取:
第 6 章 工具调用场景:幂等键该怎么设计
6.1 工具调用是最容易重复副作用的地方
让模型去执行动作——发通知、写工单、扣费——把两件危险的事凑到了一起:长耗时(模型要先想再调)和明确的副作用(工具真的改了外部状态)。一旦中间那一步超时,你面对的就是状态三:工具可能已经执行了,只是结果没回来。
更麻烦的是,重试往往不发生在你的代码里,而发生在模型那一层:它看到工具返回失败,很可能自己决定再调一次。所以幂等键必须一路传到工具执行的那一端。
6.2 三条设计规则
第一条,键由「这次业务动作」决定,而不是由「这次尝试」决定:同一个动作无论被调多少次,算出的键必须一模一样。Stripe 的官方幂等文档说得很清楚:键由客户端生成、服务端用它识别同一请求的后续重试,并保存第一次请求的结果、对同一键返回同样结果;它还提醒不要拿邮箱、个人标识这类敏感信息当键。
第二条,键的粒度要恰好等于一个业务动作。官方文档里有一句针对常见误用的话值得引用其意:一个键应该唯一标识某一个具体动作,比如「为订单号某某创建一笔支付」,而不是标识一个会话或一次接口调用。键太粗,第二次真实业务会被当成重复丢掉。
第三条,服务端要真的支持它——幂等键不是通用的魔法头。社区里数据管道的通行做法是把键随数据往下游传、在写入端用唯一约束去重,思路同样适用:去重动作发生在真正产生副作用的那一端,中间的转发环节只原样传递键。
⚠️代码待验证
importhashlibimportjsondeftool_idempotency_key(tool_name:str,args:dict,session_id:str)->str:# 规则:同一个业务动作,在任意次重试里都必须算出同一个键payload=json.dumps({"tool":tool_name,"args":args},sort_keys=True,ensure_ascii=False,)digest=hashlib.sha256(payload.encode("utf-8")).hexdigest()[:32]returnf"{session_id}:{digest}"6.3 不同工具,键的取法不同
| 工具动作 | 天然幂等吗 | 幂等键怎么取 |
|---|---|---|
| 只读查询 | 是 | 不需要键 |
| 按唯一标识写一条记录 | 取决于实现 | 用这条记录自身的业务标识 |
| 发通知、发邮件 | 否 | 用「内容摘要 + 会话标识」 |
| 下单、扣款 | 否 | 调用前生成随机标识,随请求一起带上 |
| 触发下游工作流 | 否 | 用工作流实例标识 |
| 计数器自增 | 否 | 先落幂等键再计数,或改成「设为某个值」 |
判断一个工具要不要幂等键,有个一秒钟就能做完的测试:把这次操作原样执行两遍,结果和只执行一遍一样吗?不一样就必须有键。这和网络上区分「覆盖写」与「增量改」是同一个思维动作。
第 7 章 重试风暴:一次重试怎么会把上游打垮
7.1 放大是乘出来的
| 调用链上各自重试的层数 | 每层重试次数 | 一次用户请求最多放大成 | 后果 |
|---|---|---|---|
| 1 层 | 3 | 3 次 | 可控,属于正常容错 |
| 3 层 | 3 | 27 次 | 已经明显放大,故障期会很痛 |
| 5 层 | 3 | 243 次 | 上游几乎不可能自愈 |
大模型应用里这条链通常是:业务代码 → 服务封装 → 官方 SDK,而 SDK 默认也会自动重试两次左右——所以「我代码里没写重试」不等于「没有重试」。
7.2 三个刹车
第一个刹车是只在链路的一层重试,其余层快速失败——直接把乘法变成了加法。
第二个刹车是重试配额(重试令牌桶):客户端持有一个桶,只要有令牌就能重试,令牌耗尽后重试降到固定低速率,把「单请求次数上限」提升成「全局重试量上限」。
第三个刹车是熔断:下游错误超过阈值时就停止调用一段时间。官方文章对它态度微妙——它被广泛推荐,但会引入难以测试的模式切换,还可能显著延长恢复时间,所以他们更偏向用重试令牌桶缓解。稳妥次序是:先「只在一层重试」,再加「重试令牌桶」,最后才考虑熔断。
⚠️代码待验证
llm_call:timeouts:connect_ms:2000# 连接超时:对端在不在、路通不通first_byte_ms:30000# 首字节超时:流式下等价于空闲超时total_ms:120000# 总超时:整体时间预算retry:max_attempts:3# 次数上限,绝不能无限base_ms:500# 退避底数cap_ms:20000# 退避封顶jitter:full# 全抖动respect_retry_after:true# 服务端给了等待指示就以它为准retry_token_bucket:enabled# 重试流量也走令牌桶,容量按上游承受力定only_one_layer:true# 只在链路的一层做重试idempotency:client_request_id:required# 调用前生成,跨重试保持不变log_server_request_id:true# 收到响应头后补写服务端请求标识7.3 从网络工程搬过来的七条
你现有的经验里能直接平移的不少,但每条都要换一次判据:
- 分层超时:连接超时、首字节超时(流式里就是空闲超时)、总超时都要设,分工不能混。
- 幂等判断:过去只对读、覆盖写、删除放心重放;现在有副作用的默认不许重放。
- 错误分类:过去只看状态码决定重发;现在还要看错误类型字段,把临时限流和配额耗尽分开——它们可能共用同一个 429。
- 退避带抖动:过去给轮询定时器加随机偏移;现在退避必须带抖动。
- 重试令牌桶:过去令牌桶限正常流量;现在要额外给重试流量配一个桶。
- 只在单层重传:过去网络设备只在一处重传;现在重试只在调用链的一层做,其余层快速失败。
- 请求标识串链路:过去你用请求标识核对两端;现在要落客户端请求标识(调用前生成、跨重试不变),重试前先按它查状态。
这七条里如果只能先做一件事,就做第七条:三种状态靠的正是这个标识才能分辨,没有它,白名单和退避策略都建立在分不清的假设上。
本章那份重试与超时的配置模板:把第 7 章的三层超时、抖动退避、重试令牌桶和幂等要求合成了一份可直接改的配置骨架,字段旁都写了用途。放在资料包里,扫码即可获取:
附表 A:本文引用事实与出处对照表
- 跨进程调用应设超时,连接超时与请求超时分开;五层各重试三次放大到 243 倍,宜只在一层重试;带副作用的接口无幂等保证不安全;重试量用令牌桶限制。出处:亚马逊 Builders’ Library《Timeouts, retries, and backoff with jitter》 https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/本文位置:第 1.1、2.3、3.3、7.1、7.2 节。
- 全抖动、等量抖动、去相关抖动三种写法;「不带抖动的指数退避是明显的输家」的模拟结论。出处:亚马逊架构博客《Exponential Backoff and Jitter》 https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/本文位置:第 3.1、3.2 节。
- 临时限流返回 429、模型过载返回 503 时可能带 Retry-After,该头部不适用于配额与账单类错误;流式开始后的错误可能以流事件到达,不要在已消费输出后自动重放。出处:OpenAI《Rate limits》 https://platform.openai.com/docs/guides/rate-limits本文位置:第 4.1、5.1 节。
- 429 至少区分速率限制、余额耗尽、组织与项目支出上限、组织用量上限;重试配额类错误不恢复访问权限。出处:OpenAI《Error codes》 https://platform.openai.com/docs/guides/error-codes/本文位置:第 2.2、4.2 节。
- 请求标识响应头用于排障并被建议记录;可自行提供客户端请求标识,仅 ASCII、不超过 512 个字符,超时或网络异常时可用它查证请求是否被收到。出处:OpenAI《API Overview》 https://platform.openai.com/docs/api-reference/introduction本文位置:第 1.3 节。
- 默认对部分错误自动重试两次并带指数退避(含连接类错误、408、409、429、5 开头)。出处:OpenAI《Python API library》 https://developers.openai.com/api/reference/python/本文位置:第 2.3、7.1 节。
- 后台模式的响应在连接中断后可从上次收到的序号续读。出处:OpenAI《Background mode》 https://platform.openai.com/docs/guides/background本文位置:第 5.3 节。
- 各状态码含义(400、401、402、403、404、409、413、429、500、504、529);529 为服务临时过载,官方 SDK 自动重试连接错误、限流与 5 开头错误并遵守 Retry-After;每个响应带请求标识;504 建议考虑改用流式。出处:Anthropic《Claude API errors》 https://platform.claude.com/docs/en/api/errors本文位置:第 1.3、2.2、4.3 节。
- 流式采用事件流,高峰期可能在流内收到过载类错误事件;恢复办法是保存已收内容并构造接续请求继续;较早模型用助手消息前缀续写,较新模型改用一条用户消息;工具调用块与思考块无法部分恢复。出处:Anthropic《Streaming messages》 https://platform.claude.com/docs/en/build-with-claude/streaming本文位置:第 5.1、5.2 节。
- 超出速率限制会收到 429,并附带一个指示需要等待多久的响应头。出处:Anthropic《Our approach to rate limits for the Claude API》 https://support.claude.com/en/articles/8243635本文位置:第 4.1 节。
- 幂等键由客户端生成、服务端保存首次请求的结果并对同一键返回相同结果,键应唯一标识一个具体动作、不得用敏感信息。出处:Stripe《Idempotent requests》 https://stripe.com/docs/idempotency本文位置:第 6.2 节。
(说明:本文参数与建议值均以成文时核验的官方文档为准,截至 2026-10-13。厂商接口参数与默认行为会变动,使用前请回官方 reference 复核。)
附表 B:术语速查表
| 术语 | 一句话解释 | 在本文哪里用到 |
|---|---|---|
| 连接超时 | 从发起连接到握上手最多等多久,判断对端是否可达 | 第 1.1 节 |
| 读超时 / 首字节超时 | 连接建立后,两次收到数据之间允许的最长空闲 | 第 1.1、5.1 节 |
| 总超时 | 一次调用的整体时间预算 | 第 1.1 节 |
| 副作用 | 调用在结果之外还改了别处状态,如计费、写库 | 第 1.2 节 |
| 幂等 | 同一个操作执行一次和执行多次,结果相同 | 第 2.1、6.2 节 |
| 幂等键 | 客户端生成、让服务端识别「这是同一个请求的重试」的标识 | 第 6.2 节 |
| 请求标识 | 为一次请求分配的唯一样式字符串,用于事后查证 | 第 1.3 节 |
| 指数退避 | 每次重试把等待时间按倍数拉长 | 第 3.1 节 |
| 抖动 | 给等待时间掺入随机量,打散同步重试的尖峰 | 第 3.2 节 |
| 重试令牌桶 | 给重试流量封顶,令牌耗尽后重试降到固定低速率 | 第 3.3 节 |
写在最后:这篇用到的资料
写这篇文章时,把相关的官方文档和源码又翻了一遍,顺手也整理了几份配套的东西:
- 大模型学习路线图:从零基础到能自己动手做 Agent,按阶段说明每一步该学什么、哪些可以先跳过
- 《LangChain + LangGraph + MCP 智能体开发实战》视频课:7 个模块,从私有化部署、Embedding+RAG 到 MCP+Agent 全流程
- AI 大模型知识库(在线可查):Agent Skills 从入门到落地、Claude Skills 完全指南等专题,按目录浏览即可
- 640 套 AI 大模型行业报告 + 经典 PDF 书籍:看行业落地案例和别人怎么做的时候用得上
- 大模型零基础到精通教学视频:跟着敲一遍,比只读文档快得多
资料是我自己整理的,放在下面这个码上,扫码即可获取:
添加时备注「AI」,优先通过。
资料按「先路线、再动手、最后查漏」的顺序整理好了,建议先看学习路线那一份,照着它挑一条适合自己当前基础的路径再往下看。