01. 一个大模型应用的后端架构通常怎么设计?

整理大模型应用后端分层、推理链路与架构设计要点。

简单回答

一个典型的大模型应用后端由 API Gateway、业务服务层、模型推理层、上下文/状态管理、异步任务队列和可观测性体系组成。核心设计原则是:推理层和业务层解耦、请求异步化、流式输出、以及完善的监控和兜底机制。和传统后端的最大区别在于推理延迟高(秒级)、资源消耗大(GPU)、且输出不确定。

详细解释

整体分层

一个生产级的大模型应用后端通常分为以下几层:

最外层是 API Gateway / 负载均衡,负责鉴权、限流、路由、协议转换。如果是 toC 产品还要处理 WebSocket 或 SSE 的长连接。常用的方案是 Nginx、Kong、或云厂商的 API Gateway。

第二层是业务服务层(BFF / Application Layer),处理用户请求的业务逻辑:会话管理、Prompt 组装、上下文拼接、工具调用编排、结果后处理等。这一层通常是无状态的,可以水平扩展。会话状态和历史消息存在 Redis 或数据库里。

第三层是模型推理层,负责实际的 LLM 推理。可以是自建的推理服务(vLLM、TGI、SGLang),也可以是调用外部 API(OpenAI、Claude 等)。这一层的核心挑战是资源管理——GPU 是稀缺资源,需要做好队列调度、并发控制和负载均衡。

第四层是数据层,包括向量数据库(RAG 场景)、关系型数据库(用户信息、会话记录)、缓存(Redis,存 session、KV Cache 等)、对象存储(文件上传)。

贯穿所有层的是可观测性体系:日志、指标、Tracing。大模型应用的调试比传统应用难得多(输出不确定、中间过程不透明),可观测性是生产稳定性的基础。

和传统后端的关键区别

第一是延迟模型不同。传统 API 调用通常毫秒级返回,LLM 推理是秒级到十秒级。所以大模型应用几乎必须用流式输出(SSE/WebSocket),不能让用户等到全部生成完才看到结果。这对前后端的交互模式有根本性的影响。

第二是成本结构不同。传统后端的主要成本在 CPU 和带宽,大模型后端的主要成本在 GPU 算力或 API 调用费用。每个请求的成本比传统 API 高两到三个数量级,所以 token 计费、用量控制、缓存复用(Prompt Caching)都需要专门设计。

第三是输出不确定性。同一个输入可能产生不同的输出,而且可能有幻觉、格式错误、安全风险。所以需要在输出层加 Guardrails——格式校验、内容审核、敏感词过滤等。

第四是超时和重试策略更复杂。LLM 推理可能因为序列长、并发高而超时。重试时要考虑幂等性(同一个请求重试是否产生不同结果)、是否已经消耗了 token(调外部 API 的情况)。

一个简化的请求流程

用户发送消息 → API Gateway 鉴权限流 → 业务层组装 Prompt(拼接 system prompt、历史消息、RAG 检索结果)→ 调用推理层(自建或外部 API)→ 流式返回 token → 业务层做后处理(格式化、审核、工具调用)→ 流式推送给前端 → 异步存储会话记录和日志。

如果涉及 Agent / Tool Calling,业务层还需要在中间做循环:模型输出工具调用请求 → 执行工具 → 把结果拼回 Prompt → 再次调用模型 → 直到模型输出最终回答。这个循环需要有步数上限和超时控制,防止 Agent 进入死循环。

面试时可以这样答

大模型应用后端的分层和传统后端类似:Gateway、业务层、推理层、数据层,加上贯穿全链路的可观测性。但有几个核心区别需要特别设计。

第一是推理延迟高,秒级到十秒级,所以流式输出几乎是必须的,用 SSE 或 WebSocket 逐 token 推送。第二是成本高,每个请求的 GPU 算力或 API 费用比传统 API 高几个数量级,需要做 token 计费、用量控制和 Prompt Caching。第三是输出不确定,必须在输出层加 Guardrails 做格式校验和内容审核。

业务层的核心职责是 Prompt 组装——把 system prompt、历史消息、RAG 检索结果等拼接成完整的 context。如果是 Agent 场景,还要处理工具调用的循环,需要有步数上限和超时控制。

推理层和业务层解耦很重要,这样可以灵活切换自建推理和外部 API,做 fallback 和负载均衡。整个架构要特别强调可观测性,因为大模型的输出不确定性导致问题排查比传统应用困难得多。

常见追问

  1. 流式输出的中间过程如果出错了怎么处理?已经推送出去的 token 怎么办?
  2. Agent 场景下的工具调用超时和重试怎么设计?
  3. 自建推理和调用外部 API 的架构有什么不同?怎么做平滑切换?