很多团队拿到 Key 跑通一条 curl 就以为接完了,真进项目才发现超时该设多少、并发一上来就限流、流式断在半路、日志里啥也复盘不了。这篇不讲协议兼容层,只讲工程怎么做:云端和本地两种调用路径怎么选、参数怎么定档、失败怎么降级、上线前拿什么评测。每一步都给可执行动作。
拿到 Key 跑通一条 curl,和把模型接进一个真项目,中间差着好几天的活儿。真进项目才会撞上的问题很具体:超时该设几个值、并发一上来就限流、流式响应断在半路、日志里只有一句报错啥也复盘不了。这篇只讲工程落地:云端和本地两条调用路径怎么选、参数怎么分档、失败怎么降级、上线前拿什么评测。
先把态度摆正:接入不是「调通一次」,而是「长期稳定地调」。所以下面每个小节都按「先定标准,再给动作」来写,你能直接抄进技术方案里。凡是涉及延迟、限流阈值、可用性这类会变的数字,都别写死在文档里,去站内对应页面核对当时的数值再填。
先定调用形态:云端接口还是本地起服务
这一步别急着写代码,先按团队现状分档。只有一两个人在做功能验证、数据不敏感,用云端接口最快,当天就能出结果。数据不能出内网,或者有稳定且持续的大流量、需要压成本,才轮到考虑本地起推理服务。选错了不是改几行代码的事,是整套部署和运维方式都要换。
- 先问数据:输入输出能不能出内网?不能出就直接进本地路线,别再纠结云端快不快
- 再问人:本地路线有没有人能维护服务进程、做量化选型、处理升级回滚?没人别硬上
- 再问量:调用量是不是长期稳定?偶尔冲一波高峰的团队,云端更合算也更省心
- 再问切换成本:两条路线的调用代码尽量收敛到同一层封装,切换只改配置不改业务逻辑
- 本地还要提前确认三件事:机器有没有卡、显存够不够放目标量化、有没有监控手段看服务是否活着
如果暂时定不下来,就按「先云端跑通业务、把调用层抽干净、本地只作为一个后端备选」来做,后面真要迁本地,业务代码不用动,这是最省事的路径。
请求层怎么写:一次封装,处处复用
接入做得好不好,九成看请求层封得干不干净。把 base url、鉴权信息、模型名、超时、重试这些全部集中到一个客户端模块,业务侧只传消息体和业务参数。这样做的直接好处是:换地址、换模型、调超时,只改一处,不用满仓库搜关键字。
- 建一个客户端模块对外只暴露 send 和 sendStream 两个方法,内部负责拼请求、加头、计时、重试。业务代码不 import 任何 HTTP 库。
- 收敛配置来源地址、鉴权、模型名、超时值统一从配置对象读,环境变量注入,禁止在业务文件里硬编码。改完在测试环境验证一次切换是否只动配置。
- 给每次调用打本地 request id在客户端入口生成一个唯一 id,贯穿日志、重试和回执。排查时顺着它就能串起一整条链路,不用靠时间戳猜。
- 请求体只放确定要用的字段多余字段一律不传。不同上游对字段的支持范围不一样,多传容易静默失效——请求成功了但参数根本没生效。
超时怎么分档:连接、首包、整体分开设
只设一个总超时,是接入期最常见的坑。请求慢了你分不清是连不上、还是排队久、还是模型输出长,只能干瞪眼。正确做法是拆成三个值:连接超时管握手,首包超时管从发出请求到收到第一个字节,整体超时管从发起到结束。三者各司其职,报错信息一眼能定位问题在哪一段。
| 超时类型 | 管什么 | 调大调的判断依据 |
|---|---|---|
| 连接超时 | 能否建立连接,网络或地址问题 | 频繁连接失败才调,通常不用动 |
| 首包超时 | 排队、路由、冷启动等前置耗时 | 首包长期偏慢,去站内测速页看自己的延迟基线再定 |
| 整体超时 | 本次请求从发起到结束的上限 | 和业务能容忍的最长等待对齐,不要大于上游本身的上限 |
流式场景重点盯首包时间。首包久,绝大多数情况是排队或路由问题,而不是模型本身慢,所以先看自己的延迟基线,再决定是把首包超时调大还是换时段、换通道。到站内测速页量一组自己的数据,比照搬别人的经验值靠谱得多。
- 超时后不要立刻换模型重试:先判断是偶发抖动还是持续劣化,抖动的等下一轮,持续劣化才走降级
- 重试要带上限,并且加抖动退避,别让所有失败请求同时回冲
- 离线批处理可以放宽整体超时,但必须配任务级截止时间,避免单个请求拖死整批
- 不适用的情况:强交互的对话场景不要为了成功率把整体超时拉太长,用户等不起
并发与限流:从串行起步,按档位放开
并发不要按理论值配,先串行跑通,再一档一档往上加,记录下什么时候开始出现限流报错。这个「在哪一档开始报错」才是你账号当前的稳定水位,比任何别人的经验值都准。批量任务尤其要注意,用固定大小的并发池加队列,不要无脑把所有请求一次铺开。
| 现象 | 大概率原因 | 先做什么 |
|---|---|---|
| 零星限流报错 | 瞬时并发超过水位 | 降并发数,加退避抖动 |
| 持续限流 | 额度或渠道层面受限 | 停重试,转人工核对站内渠道状态 |
| 延迟整体抬高 | 队列堆积或通道劣化 | 减少批量大小,看测速基线 |
- 并发数、分批大小、失败重投做成可配置项,别写死在代码里
- 命中限流用指数退避加重试上限,不是无限重试
- 退避一定加抖动,否则所有请求会在同一时刻一起回冲,越重试越糟
- 重试次数到顶仍失败,说明不是偶发问题,继续重试只是烧额度,应立即转人工
- 到站内价格与渠道追踪页核对当时的档位和状态,别凭记忆判断
什么情况下该果断停手:退避之后仍然持续失败,基本可以判定是额度、渠道或鉴权层面的问题,再重试没有意义。这时候正确的动作是发告警、查状态,而不是把重试次数调得更大。
降级怎么做:分级而不是一刀切
降级最怕写成「全都降」或者「都不降」两种极端。按业务容忍度分三档更实际:核心链路允许切备用模型或备用通道;一般链路允许从流式退回非流式,用户感知是慢一点但还能用;非核心链路允许直接返回兜底文案,先保住主流程不崩。
- 列出链路清单把项目里所有调模型的地方列成一张表,逐个标注它对业务的重要程度,落到上面三档里。
- 为每档写触发和恢复条件触发条件写清楚是连续失败几次、还是错误码命中;恢复条件同样要写,否则降级之后没人知道什么时候能切回来。
- 把策略放到配置里显式声明别藏在 if 分支里。配置化之后,值班的人不看代码也知道当前是怎么兜底的。
- 每次降级打点上报降级次数、降级到哪一档、持续时长都要记。不然月底发现成本异常,说不清是哪条链路在兜底。
还有一条边界:降级只能保证可用性,不能保证质量。如果业务对输出准确度要求很高,降级就该往「提示用户稍后再试」走,而不是塞一个能力不够的备选模型糊弄过去。
日志记什么:让慢和贵都能复盘
日志的目标只有一个:出问题时不用重跑就能复盘。最常缺的两个信息是「这次请求花了多久」和「这次请求用掉了多少额度」,缺了它们,慢和贵都说不清原因。所以必记字段要固定下来,形成规范,而不是谁想加就加。
- 请求时间、总耗时,最好再拆出首包耗时
- 使用的模型与通道
- 输入输出 token 数
- 状态码与错误类型
- 是否走了重试或降级,重试了几次
- 本地 request id,用于串联一次业务请求背后的多次模型调用
记的时候对输入输出做长度截断或脱敏,别把用户原文整体落盘,本地调用场景尤其要注意这点——日志文件躺在自己机器上,反而更容易被忽略。另外把日志按链路聚合,让你一眼看出一次业务请求背后到底打了几次模型调用、各花了多少时间,这样优化才有靶子。
上线前的评测:小样本跑通再放量
上线前不要只看「能不能调通」,要跑一组固定用例。用例覆盖四类:正常输入、边界输入、超长输入、异常参数。这组用例固定下来,每次改配置或换模型都重跑一遍,就能看出这次改动到底带来了什么差异。
| 用例类型 | 验证什么 | 不通过时的动作 |
|---|---|---|
| 正常输入 | 主流程是否跑通、输出是否符合业务要求 | 查请求层封装与提示词 |
| 边界输入 | 空值、超短、特殊字符是否处理住 | 补参数校验与兜底 |
| 超长输入 | 长度上限、截断策略是否生效 | 调分批或截断逻辑 |
| 异常参数 | 错误码是否被正确识别 | 补错误映射与日志字段 |
评测只盯三件事:能不能跑通、延迟是否可接受、输出是否符合业务要求。不要去做绝对化排名,那对工程接入没有指导意义;模型和价格的对比数字,到站内模型资料库和价格追踪页核对当时的版本就行,别抄进你的技术方案里。
- 固定用例集把四类用例写成一个可重复执行的脚本,输出结果和耗时。每次改动都跑。
- 结果和日志挂到一起形成「改了配置 → 跑一遍用例 → 看差异」的固定节奏,而不是拍脑袋判断好坏。
- 选低峰发布先放小流量观察一轮,重点看错误率和延迟分位,没问题再逐步放开。
- 留回滚开关降级策略和模型配置都要能一键切回上一版,放量出问题时不用临时改代码。
接入完成的标志不是「跑通了一次」,而是「慢和贵都能说清原因,坏了能一键退回」。下一步把你的延迟基线和渠道状态核一遍,再照着评测清单跑一轮,比闷头调参有用得多。→
常见问题
云端接口和本地起服务,怎么决定用哪个?
先看两条硬约束:数据能不能出内网,团队有没有人能维护推理服务。数据不敏感、团队小、要快速验证,云端接口更省事;数据必须留内网或有稳定大流量且能长期养服务,再考虑本地。多数团队的实际做法是先云端跑通业务,把调用层封装好,后续需要时再切本地。
调用总是超时,先查哪里?
按顺序排查:先用站内测速页量出基础延迟,确认是网络慢还是模型慢;再看是不是并发开太大导致排队;然后确认超时三个值是否只设了总超时,导致无法区分连接失败和读取慢。找到是哪一段慢之后再调参数,不要直接盲目加大超时。
被限流了应该怎么处理?
先降并发而不是加并发,用固定大小的并发池加队列消化任务。命中限流后走指数退避加重试上限,退避带抖动。如果退避后仍持续失败,一般不是瞬时抖动而是额度或通道问题,这时候该停下来检查账号档位和通道健康度,继续重试只是烧钱。
本地调用接进项目,和云端写法要分开吗?
不要分开。把 base url、鉴权、模型名、超时都收进同一个客户端模块,本地和云端只是配置不同的两个实例。这样切换、双跑、灰度对比都只改配置。唯一的差别通常是本地没有公网鉴权的那些限制,但接口形状保持一致,业务代码就不用动。
怎么判断接入是不是真的做完了?
跑一遍固定用例集,覆盖正常、边界、超长输入和异常参数;确认日志能复盘出每次请求的耗时、token 和是否降级;确认限流时能自动退避而不是雪崩。这三件事都过了,才算工程上接完,只跑通一条 curl 不算。