一个做了8年React/TypeScript前端的人,最近在公开学习应用AI,目标是先做AI工程师,再做AI解决方案架构师,最后成为AI Forward Deployed Engineer。在碰token、RAG或agent之前,他先画了一张图:用户点下"Summarize"按钮的那一刻,到底发生了什么?

打开网易新闻 查看精彩图片

答案被拆成了9个步骤。有意思的是,其中只有两步真正发生在模型内部,剩下七步都是工程师自己要把控的环节。

调用之前:第1到4步

第1步,客户端发请求。从浏览器这一侧看,一个LLM功能就是一次发往后端的HTTP调用:POST /summarize,带上用户的文本,如果是聊天再加一个会话id。OpenAI的文档明确说,绝不能在客户端代码里暴露API key,所以key放在服务器上,只有服务器去和模型提供方对话。

第2步,API校验输入。FastAPI拿Pydantic模型检查请求体,不合法的数据根本到不了处理函数:FastAPI会抛出RequestValidationError,默认处理器返回HTTP 422。校验通过后,Pydantic保证字段符合声明的类型。这是拦截坏输入最便宜的地方。

第3步,拼装prompt。模型只能看到你发给它的东西。Anthropic的Messages API是无状态的,所以每次都要把完整历史重新发一遍。OpenAI同样把每个请求视为独立、无状态,虽然提供可选的服务器端会话状态,但也指出链条中较早的输入token在每一轮仍会被计费。检索到的文档(RAG)也是在这一步加入prompt。

第4步,数token、查预算。模型读的是token不是字符,而分词器与模型绑定,所以不同模型之间的计数并不相同。系统prompt、工具定义、历史记录和输出全都共享同一个上下文窗口。如果光是输入就超了限制,请求会失败——Anthropic会返回400,"prompt is too long"。发送前先估算token,并设定最大输出长度。

模型内部:第5到6步

第5步,prefill,模型一次性读完所有输入。推理分两个阶段,prefill阶段模型并行处理每一个输入token,计算量大,也是模型侧决定首token时间(TTFT)的主要因素。网络时间和提供方的排队还会让这段等待更长。

第6步,decode,一次一个token。模型自回归地生成:给词表里每个token打分,选一个,追加,重复。KV cache保留之前的计算,让每一步不用从头再来,每一步的节奏就是每个输出token的时间。生成会在遇到结束符、停止序列或token上限时停下。

怎么选下一个token属于采样设置:贪心,或者用temperature、top-k、top-p采样。别假设每个模型都有这些设置——Anthropic的文档说,Claude 4.7及以后版本如果把这些参数设成非默认值,会返回400。

调用之后:第7到9步

第7步,把token流式传回。OpenAI和Anthropic都在decode还在进行时以服务器发送事件(SSE)的形式流式返回token,所以第6步和第7步是重叠的。文档里有两个坑:错误可能在流中途到达,而且是在200状态之后;部分输出比完整响应更难审核。

第8步,输出也要校验。结构化输出会把模型约束到你提供的JSON Schema(OpenAI支持其中一个子集),但OpenAI的指南说它们仍可能包含错误,并列出两种要处理的情况:拒答,以及因token上限被截断的响应。如果用了流式,就在流结束后再校验。FastAPI的response_model是第二道检查:不匹配会变成服务器错误,而不是错误的数据。形状合法不等于答案正确,正确性要靠后续的评测来覆盖。

第9步,安全重试,然后记录。同样的状态码可能含义不同:429可能是限流,但Anthropic在你触达月度支出上限时也会用它,所以重试前先读错误体。配额或计费错误永远不要重试。对临时错误,有Retry-After就照做,否则用带抖动的指数退避,并给尝试次数和总时长设上限。官方SDK本身已经会重试部分错误(Anthropic默认重试两次),所以要把这算进你的限制里,而不是嵌套循环。最后记录输入/输出token用量、延迟和提供方的request id,这些记录会喂给调试、成本追踪,最终还有评测。

这位前端工程师的结论是:这其实就是一个请求生命周期,只是中间换了个不寻常的后端。9步里只有2步是模型,另外7步是契约、预算、流和失败处理,都是工程师自己的活。他给自己定的工作规则是:把模型当成一个不可靠、按量计费、远程的依赖,在它两边都放上校验。

下一步,他打算先补Python类型与异步、FastAPI和Pydantic,以及LLM机制(token、上下文、推理)。他留给读者的问题是:你做的第一个LLM功能里,这9步中哪一步最先出问题?