Skip to content

一次 LLM 请求经历了什么?从 Token、上下文到流式响应

一次 LLM 请求不是“把字符串发给模型”这么简单,而是依次经过输入组装、Token 化、排队与推理、增量生成、输出解析和业务提交。生产问题通常出在这些阶段之间的边界:上下文超限、排队变慢、流中断、输出不可解析,或业务已经超时但供应商仍在生成。

先说结论

理解 LLM 请求生命周期的价值,不是记住模型内部细节,而是为每一阶段定义输入、输出、时限、失败类型和可观测信号。应用层至少要区分:

  1. 请求进入应用后的排队与预处理时间;
  2. 模型首个输出片段到达前的等待时间;
  3. 从首个片段到完整响应的生成时间;
  4. Schema 校验、业务校验与结果提交时间。

如果只记录一个总耗时和一个“调用失败”异常,就无法判断该缩短上下文、调整并发、重试,还是修复解析器。

适合谁,不适合谁

本文适合已经能调用模型 API,准备处理延迟、流式响应、超时和错误分类的后端或全栈开发者。

本文不讨论模型训练、注意力机制的数学推导,也不承诺解释某一家供应商的私有推理实现。不同模型、部署形态与 API 能力会变化,本文只描述应用侧可控制和可观测的通用边界。

请求生命周期的七个阶段

1. 接收业务请求

应用先完成身份识别、权限检查、业务幂等键读取和输入大小限制。幂等键必须由调用方在重试间复用,或由服务端根据稳定的业务操作标识生成;不能拿每次请求都会变化的追踪 ID 代替。此时不要把用户原文、密钥或内部文档无差别写入日志。

2. 组装上下文

上下文可能包含系统指令、历史消息、检索片段、工具结果和本轮输入。组装顺序应是确定的,并保留每一类内容的来源标识。超出预算时,应按业务优先级裁剪,而不是从字符串尾部机械截断。

3. Token 化与请求提交

模型服务会把文本转换为 Token。应用不应假设“字符数等于 Token 数”,应使用供应商或模型对应的计数能力做预算;无法精确计数时,必须预留安全余量。提交时同时携带请求 ID、模型路由结果、超时信号和允许的最大输出边界。

4. 排队与推理准备

请求提交后可能经历网络传输、网关排队、容量调度和输入处理。这个阶段主要影响首片段延迟。首片段迟迟不到,不等于模型正在稳定生成,也可能是连接、限流或服务容量问题。

5. 增量生成

流式接口会返回多个事件或文本片段。客户端必须处理半包、断流、重复事件、结束标记和供应商错误事件,不能假设每个网络块就是一个完整 JSON。流式展示只改善用户感知,并不会自动降低完整响应时间或成本。

6. 聚合、解析与校验

文本生成结束不代表请求成功。结构化场景还要执行语法解析、Schema 校验和业务规则校验,例如枚举是否合法、引用是否存在、金额是否越界。解析失败应与网络失败分开统计。

7. 提交业务结果

最后才把结果写入数据库、发送消息或触发工具。涉及副作用时,使用幂等键、事务外盒或人工确认,防止调用方超时重试造成重复执行。

生命周期决策表

现象优先观察常见原因首选动作不应立即做
首片段很慢排队时间、连接时间、输入 Token上下文过长、限流、容量不足缩短输入、限制并发、切换可用路由盲目增加输出上限
首片段快但结束慢输出 Token、片段间隔输出过长、停止条件不清收紧任务和输出上限因生成慢而重试并制造双请求
流式中断已收片段数、结束原因、连接错误网络断开、上游超时标记不完整结果,按幂等策略恢复把残缺内容当完整答案
输出无法解析原始响应摘要、Schema 错误路径提示约束不足、模型偏离格式校验后有限修复或重试直接写入业务系统
总耗时偶发升高分阶段耗时分位、路由、并发排队抖动、依赖变慢按阶段定位并设置预算只看平均总耗时

可执行的请求状态机

下面是语言无关伪代码,重点是状态与副作用边界:

text
traceId = newTraceId()
idempotencyKey = requireStableBusinessIdempotencyKey(input)
state = "received"

authorize(input)
context = buildContext(input, tokenBudget)
state = "submitted"

stream = provider.generate(context, timeoutSignal)
for event in stream:
    if event.type == "delta":
        state = "streaming"
        append(event.text)
    if event.type == "error":
        fail(classify(event))
    if event.type == "done":
        state = "generated"

parsed = parse(fullText)
validated = validateSchemaAndBusinessRules(parsed)
state = "validated"

commitOnce(idempotencyKey, validated)
state = "completed"

traceId 用于链路追踪,idempotencyKey 用于阻止重复副作用,两者职责不同。必须为状态迁移设置终止条件:客户端取消、总超时、最大输出、供应商结束事件和应用关闭。任何一种终止都要取消仍在进行的上游请求。

超时、重试、降级和观测边界

  • 超时:至少区分连接/首片段超时与总请求超时;总超时触发后向上游传播取消信号。
  • 重试:只对短暂网络错误、明确限流或可恢复服务错误做有限重试;已产生副作用或正在持续流式输出时,不自动重试。
  • 降级:可以切换到能力满足最低要求的模型、缩短非关键上下文,或返回“稍后处理”;不能静默删除权限约束和关键业务信息。
  • 观测:记录请求 ID、路由、输入/输出 Token、分阶段耗时、结束原因、重试次数和校验结果;敏感正文默认不落日志。

常见误区与失败边界

  1. 把 HTTP 200 当成功:传输成功不代表输出可用。
  2. 所有错误都重试:无效参数、上下文超限和 Schema 设计错误,重试通常只会重复消耗。
  3. 流式输出直接驱动副作用:模型尚未完成时内容可能改变或缺失。
  4. 客户端取消但上游继续生成:浪费资源,也会让并发统计失真。
  5. 只记录完整 Prompt:既有敏感数据风险,也缺少可聚合的阶段指标。

应用无法控制模型内部调度和采样过程,因此不要根据不可见内部状态设计恢复逻辑;恢复应依赖应用可观测的事件、错误类型与幂等状态。

可执行检查清单

  • [ ] 为请求生成贯穿网关、模型调用和业务提交的 request ID
  • [ ] 给上下文各部分设置来源、优先级和 Token 预算
  • [ ] 分别设置首片段超时和总超时
  • [ ] 客户端取消时能中止上游请求
  • [ ] 流式解析器能处理拆包、错误事件和非正常结束
  • [ ] 将传输成功、生成完成、Schema 通过、业务提交成功分开统计
  • [ ] 重试有错误白名单、次数上限和退避
  • [ ] 有幂等键保护数据库写入和工具调用
  • [ ] 日志默认脱敏,不保存密钥与完整敏感上下文

下一步

先回到 AI 工程化专题 查看完整学习顺序。理解请求生命周期后,下一步是把供应商差异隔离在 可替换模型供应商的 LLM Client 中,让超时、重试和观测策略有统一落点。

AI 应用开发训练营 · 现在开始

别只收藏 AI 文章,今天就做出第一个能上线的项目

文章解决认知,项目才证明能力。把 Agent、RAG、MCP 变成可运行、可展示、可面试表达的成果,现在就从一次岗位准备度自测开始。

立即开始 AI 岗位准备度自测 查看训练营路线
真实学员成果先看成果,再决定是否开始 →
  1. 01选方向
  2. 02做项目
  3. 03出成果
  4. 04拿面试