等级 L3 · 每天 40 分钟 · 场景:调API→一、调用链路的工程问题,控成本→五、成本控制落地

一句话:把 LLM 接进业务系统,难点不在「怎么调通」——那是十行代码的事——而在超时、重试、并发、成本、可观测这些老本行。Demo 到生产之间隔的全是你熟悉的东西。

学习地图

你的问题看哪一节
「调通了但一上量就出问题」一、调用链路的工程问题
「超时怎么设、能不能重试」二、超时与重试
「首字延迟太长用户等不了」三、流式返回
「返回的 JSON 解析老是失败」四、结构化输出
「账单比预估高一个数量级」五、成本控制落地
「线上出问题查不出来」六、可观测

前置:大模型基础概念里的 token、上下文窗口、成本三节。

一、调用链路的工程问题

LLM 调用和你熟悉的 RPC 调用,差异在这几处:

维度普通 RPCLLM 调用
延迟几十毫秒几秒到几分钟
响应大小可预期不可预期(取决于生成多少)
失败模式超时 / 5xx超时 / 限流 / 内容不符合预期
幂等通常可重试重试结果不一定相同
成本忽略不计按量计费,是主要成本项

这五条差异决定了后面每一节。最反直觉的是延迟量级——按 RPC 的思路设 3 秒超时,会发现几乎全部超时。

别把 LLM 调用放在同步主链路里

如果一次调用要几秒到几十秒,放在用户请求的同步路径上会拖垮整条链路。常见的三种处理:

  • 流式返回:用户能立刻看到内容在生成(见第三节)
  • 异步 + 轮询/推送:提交任务返回 taskId,前端轮询或走 WebSocket
  • 离线批处理:不要求实时的场景(内容审核、批量打标)走批量接口,通常有大幅折扣

选哪个取决于用户要不要立刻看到结果,不取决于技术偏好。

二、超时与重试

超时要按分钟设,不是按秒

各家 SDK 的默认超时通常在 10 分钟量级。你要根据场景收紧,但别收到秒级

一个容易踩的坑:不同 SDK 的时间单位不一样。Python、Ruby 用秒,TypeScript 用毫秒。写 timeout: 30 在 TS 里是 30 毫秒,不是 30 秒——请求还没发出去就超时了。

重试的三个坑

坑 1:超时也会被重试,实际耗时是乘法关系

SDK 通常默认重试 2 次,且超时本身也在重试范围内。这意味着最坏情况的墙钟时间是:

最坏耗时 = 超时时间 × (重试次数 + 1)

设 10 分钟超时 + 默认 2 次重试 = 最坏 30 分钟才返回。上游的超时必须大于这个值,否则上游先断,你这边还在重试。

坑 2:不是所有错误都该重试

状态码含义该不该重试
400请求格式/参数错❌ 重试多少次都一样
401 / 403认证/权限
404模型 ID 写错了
413请求太大❌ 要减小输入
429限流按响应里的 retry-after 等待
500 / 529服务端错误 / 过载✅ 指数退避

SDK 一般已经内置了对 429/5xx 的自动重试。先确认默认行为,别重复造一层——两层重试叠加会把重试次数放大成乘积。

坑 3:重试不幂等

同样的输入,重试后的输出不保证相同。所以:

  • 别用「重试直到解析成功」来兜底格式问题——该用结构化输出(第四节)
  • 有副作用的场景(重试会重复扣款、重复发消息),要在你这层做幂等控制,不能指望模型

限流要自己扛一层

各家都有 RPM(每分钟请求数)和 TPM(每分钟 token 数)限制。TPM 比 RPM 更容易先撞上——一个长上下文请求可能顶几十个短请求。

生产上建议在自己这侧加一层限流/排队,理由和你给下游服务加限流一样:让排队发生在你能控制的地方,而不是把 429 直接透传给用户。

三、流式返回

长输出必须用流式。这不只是体验问题——非流式请求在输出量大时会撞上 HTTP 超时,直接失败。

一个经验值:输出预期超过一万多 token 就该流式;流式下可以把上限放得更宽。

流式的工程代价

流式解决了首字延迟,但引入三个新问题:

  1. 错误可能发生在中途——已经吐了一半内容才失败。你的前端和落库逻辑要能处理「不完整的结果」
  2. 网关/代理要支持——Nginx 的缓冲要关(proxy_buffering off),否则它会攒完再一次性吐给客户端,流式白做
  3. 取消要能传递——用户关掉页面时,要能把取消传到上游,否则你还在为没人看的内容付费

落库时机

流式场景下常见的做法是:边推给前端,边在内存里拼完整结果,结束时一次落库。不要每个分片都写一次库——那是自找的写放大。

四、结构化输出

要用程序解析模型输出时,「在提示词里请求返回 JSON」是最弱的方案。三个层次:

方案可靠性说明
提示词里写「只返回 JSON」可能带前言、带 ```json 包裹、字段名漂移
结构化输出(传 JSON Schema)服务端保证输出符合 schema,首选
工具调用 / Function Calling本来就要触发动作的场景更自然

用 schema 时要知道的限制

各家对 JSON Schema 的支持都是子集,常见限制:

  • 不支持递归 schema
  • 不支持数值范围(minimum/maximum)、字符串长度(minLength)这类约束
  • 对象通常要求显式写 additionalProperties: false

这些约束要在你代码里补校验——schema 只保证结构合法,不保证值合理。模型完全可以返回一个结构完美但年龄是 -5 的对象。

另外,新 schema 第一次请求会有编译开销(后续会被缓存一段时间)。压测时注意区分冷启动和稳态。

无论用哪种,解析都要容错

生成有随机性,不要假设两次调用返回完全相同的字符串。留好解析失败的降级路径和告警,别让一次解析异常打挂整个接口。

五、成本控制落地

成本的算法在大模型基础概念讲过,这里讲怎么落地。

按投入产出排序,依次做

① Prompt caching(性价比最高,优先做)

共享的长前缀(系统提示、文档、few-shot)缓存后按约 0.1 倍计价。要点:

  • 缓存是前缀匹配:稳定内容放前面,易变内容放后面。时间戳、请求 ID、用户 ID 拼在系统提示开头 = 缓存 100% 失效
  • 有最小长度门槛,太短的前缀静默不缓存(既不报错也不生效)。门槛值各模型不同,而且不随代际单调下降——换模型后要重新确认,别沿用旧假设
  • 断点数量有限(通常 4 个),要放在稳定性的分界处
  • 并发请求第一次都吃不到缓存:缓存要等第一个响应开始返回后才可读。扇出场景先发 1 个,等它开始返回再发其余的

② 按任务分流模型

分类、抽取、格式化这类高频简单任务用轻量档,能省下数倍成本。别一律用旗舰档。

③ 用批量接口

不要求实时的场景走批量接口,通常有 50% 左右折扣。适合:离线打标、批量摘要、数据清洗。

④ 压缩输入

删掉提示词里的冗余说明、长文档先摘要、多轮对话定期压缩历史。放在最后做——收益不如前三项,改动却更大。

一个必须设的东西:预算熔断

按 token 计费意味着一个 bug 可能烧掉一个月预算——死循环调用、异常输入导致超长上下文、被恶意刷接口。

至少要有:单请求 token 上限(max_tokens 别设太大)、单用户/单租户配额、总量告警 + 自动熔断。这和你给下游服务设限流是同一个道理,只是这次超了要付钱。

六、可观测

没有 token 账本,前面所有优化都是盲调。 这是接 LLM 时最该先建的东西,很多团队上线几个月才想起来。

每次调用至少记这些:

字段为什么记
输入 token / 输出 token成本核算的基础
缓存命中 token / 缓存写入 token判断 caching 有没有真生效
模型 ID分流策略的效果对比
耗时(首字 + 总时长)流式体验的关键指标
stop_reason / 结束原因见下
业务标识(场景、租户、traceId)出问题能定位到是哪个功能

两个最值得盯的指标

缓存命中率:如果重复请求下缓存命中 token 一直是 0,说明有东西在破坏前缀——时间戳、随机 ID、没排序的 JSON 序列化、每次都变的工具列表。这是上线后第一个该加的监控。

注意统计口径:响应里的「输入 token」通常只是未命中缓存的那部分,不是总输入量。总量要三项相加,否则你会以为成本降了其实只是统计漏了。

结束原因分布:模型停止生成的原因通常有几类——正常结束、达到 token 上限、要调用工具、内容被拒。「达到 token 上限」的占比是个健康度指标:占比高说明你的输出被截断了,用户看到的是半句话。

常见追问

  • 该用哪家的 API? 先看三个硬条件:数据能不能出境/出内网、有没有企业合同和 SLA、账单能不能按部门拆分。技术差异通常不是决定因素——能力有差距但都在快速变化,合规和采购流程才是真门槛

  • 要不要做多厂商适配层? 看你有没有真实的切换需求。没有需求就别做——各家的能力差异(工具调用格式、结构化输出、缓存机制)没法完全抹平,抽象层会退化成最小公倍数,把各家的优势都磨掉。真要做,抽象在「业务能力」层(如”意图识别”),不要抽象在「API 调用」层。

  • 本地部署的开源模型呢? 数据不能出内网时是唯一选择。代价:能力通常落后一代、要自己搞 GPU 和推理服务、要自己做扩缩容和高可用。先用商用 API 验证需求成立,再评估自建——反过来容易在基建上耗几个月然后发现需求不成立。

  • 多轮对话的历史怎么存? API 是无状态的,会话状态由你维护。存 Redis 就行,和普通会话没区别。要注意的是历史会无限增长——必须有截断或压缩策略,否则迟早撑爆上下文窗口,而且每轮都在为越来越长的历史付费。

  • 怎么做压测? 三个和普通压测不同的点:要按 token 而不是按 QPS 算容量(TPM 通常先于 RPM 撞限);要区分缓存冷热(冷启动的成本和延迟完全不同);要压长输入长输出的极端场景,那才是最容易暴露超时问题的地方。

相关