FDE Training · Module 03

03

LLM 推理与大模型调用

模块 03 · LLM 推理与大模型调用

本章目标:掌握 AI 工程的第一站——把大模型"部署起来"和"调起来"。分两块:一是本地/私有化推理部署(vLLM 等),二是通过 API 调用各种大模型并踩平 token、上下文、流式、重试的坑。这是 2026 FDE 的核心分水岭之一。


3.1 先搞懂推理是啥

  • 训练:把海量数据"喂"给模型,让它学会;开满 GPU,跑很久。
  • 推理:模型已经学会,你给它一句话,它给你答案;这就是客户每天都在用的环节。
  • FDE 主要关心推理:怎么让"已经训好的模型"又快又稳地出答案,还能省钱。

关键指标(面试必背):

  • 吞吐量(Throughput):单位时间能出多少 token。
  • 延迟(Latency):一个请求从进去到出第一个字/全部字多久。
  • TTFT(Time To First Token):到第一个字的延迟(流式体验的关键)。
  • 显存占用:模型装不装得下、并发能开多大。

3.2 推理框架:vLLM 是主力(TGI / TensorRT-LLM 了解)

3.2.1 为什么用 vLLM

裸跑大模型慢、占显存。vLLM 做了三件关键的事:

  1. PagedAttention:显存按页管理,能塞下更多并发请求。
  2. Continuous Batching:请求一个接一个批处理,提升吞吐。
  3. 与 OpenAI API 格式兼容:/v1/chat/completions,前端代码零改动。

3.2.2 本地起一个 vLLM(示意)

# 拉一个开源模型权重,然后用 vLLM 起 OpenAI 兼容服务
vllm serve Qwen/Qwen2.5-7B-Instruct \
  --served-model-name my-qwen \
  --port 8000 \
  --max-model-len 16384 \
  --gpu-memory-utilization 0.85

起好后就能用 OpenAI SDK 调:

from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="EMPTY")
r = client.chat.completions.create(
    model="my-qwen",
    messages=[{"role": "user", "content": "你好"}],
    stream=True
)

3.2.3 显存调优 & 吞吐延迟优化(重点)

  • --gpu-memory-utilization:给推理预留显存比例,太高会 OOM,太低浪费。
  • --max-model-len:上下文长度上限。太大挤占并发显存,按实际需要设。
  • PagedAttention + Continuous Batching:默认开着,并发多时吞吐明显提升。
  • 量化(想塞进更小显存):模块 13 细讲(AWQ/GPTQ/FP8)。

一句话人话:显存是钱,上下文长=占得多,并发高=吃吞吐,你要在"够用"和"省钱"之间找平衡。

补一段:量化为什么能"塞进更小显存",连续批处理又为什么快

量化的思路很朴素:模型权重默认用 FP16(16 位浮点)存,7B 参数 ≈ 14GB;把权重从 16 位压到 8 位甚至 4 位整数(INT8/INT4),显存直接减半甚至降到 1/4。代价是精度损失一点点,但推理的瓶颈常常卡在"读显存带宽"而不是"算",所以实测往往又快又省。连续批处理(Continuous Batching)快在"把 GPU 算力用满":传统做法是一个请求算完才接下一个,请求之间 GPU 经常空转;连续批处理让多个请求的 token 在同一批里一起算,谁生成了新 token 就随时插进下一批,显卡几乎不歇。两件事合起来,正是 vLLM 能高并发低延迟的核心。想动手看代码(candle 跑 GGUF 量化模型、连续批处理循环)和量化等级对照表,去 Rust + AI 全栈 页补一补。


3.3 模型 API 调用(OpenAI / 通义 / 文心 / DeepSeek 等)

3.3.1 一套通用的"调 API"姿势

import time, random
from openai import OpenAI

client = OpenAI(api_key=os.environ["LLM_API_KEY"], base_url=os.environ.get("LLM_BASE_URL"))

def complete(messages, *, model="deepseek-chat", temperature=0.2, max_tokens=1024):
    for attempt in range(3):
        try:
            return client.chat.completions.create(
                model=model, messages=messages,
                temperature=temperature, max_tokens=max_tokens,
            ).choices[0].message.content
        except Exception as e:
            if attempt == 2:
                raise
            time.sleep(1.5 ** attempt + random.uniform(0, 0.5))  # 退避重试

要点(面试常考):

  • REST/自定义 base_url:各家模型几乎都兼容 OpenAI 格式,换 base_url + api_key 就能换供应商。
  • temperature:越高越随性、越会发散;审合同这类要确定性,用低 temperature(0~0.2)。
  • max_tokens:限制输出长度,防失控、控制成本。
  • 超时 & 退避重试:网络抖动在客户现场极常见。

3.4 token、上下文窗口、流式输出(天天踩的坑)

3.4.1 Token 是啥、怎么算钱

  • 模型不读"字",读"token"(切分后的最小单元)。中文一般 1~1.5 字 ≈ 1 token。
  • 问一句、答一句、还有长 Prompt(系统词+历史)都要算钱。
  • 成本公式:成本 ≈ (输入 token + 输出 token) × 单价。所以别把一堆无关历史塞进每次请求。

3.4.2 上下文窗口 = 一次最多能塞多少

  • 窗口是上限,你塞进的所有内容(系统词 + 用户问题 + 历史 + RAG 检索片段)的和不能超。
  • 人话:窗口是箱子,装太满要么被截断,要么报错,要么效果变差。
  • 管理手段:
    1. 只带最近 N 轮历史(滑动窗口)。
    2. 压缩长文档(模块 04 RAG 负责检索,而不是全塞进去)。
    3. 监控 token 用量(模块 08 成本观测)。

3.4.3 流式输出(Streaming)怎么接

大模型一个字一个字吐,体验更好、TTFT 更低。后端把流透传给前端:

from fastapi.responses import StreamingResponse

def stream_chat(messages):
    r = client.chat.completions.create(model=..., messages=messages, stream=True)
    for chunk in r:
        if chunk.choices and chunk.choices[0].delta.content:
            yield chunk.choices[0].delta.content

@app.post("/api/chat/stream")
def chat(req):
    gen = stream_chat([{"role":"user","content": req.query}])
    return StreamingResponse(gen, media_type="text/plain")

千万别忘了:流式也要做超时、重试(幂等)、限流,否则客户一句长话前端会卡死。


3.5 一条能上生产的私有化部署路线

客户机密数据不想出内网的场景,落地红旗如下:

客户内网 GPU 机
  └─ vLLM 服务 (/v1/chat/completions)
       ├─ 模型权重(私有化/开源)
       └─ 你的后端服务(鉴权/限流/RAG/Agent)
            └─ 客户业务前端

关键决策点(面试/方案常用):

  1. 模型选型:开源小模型(如 Qwen 系列)还是调通义/文心 API?看数据是否出网、预算、效果要求。
  2. 推理框架:vLLM 几乎是标配;显存紧张再上量化。
  3. 环境适配:客户可能是国产服务器/国产 OS(模块 13),提前确认 CUDA/驱动/依赖。
  4. 并发 & 容量:预估 QPS 和并发,决定几张卡(一张 A100/H 级大概能扛多少并发,要做压测)。

3.6 模块练习

  1. 本地用 vLLM 起一个开源模型的 OpenAI 兼容服务,用 Python 调通非流式 + 流式两种。
  2. 给你后端加一个"调模型"封装:温度、超时、指数退避重试、token 用量记录。
  3. 写一个幂等 + 限流 + 流式的 /api/chat/stream 接口,前端用 fetch 读流。
  4. 做一次简单压测:并发 1/5/10,记录延迟和吞吐,说出"瓶颈在模型还是后端"。
  5. 画一张"客户机密数据不出内网的私有化部署拓扑图",标出鉴权限流和各层边界。

3.7 本章面试题

  1. "vLLM 为什么快?" → 答:PagedAttention 提高显存利用率、Continuous Batching 把多个请求合并批处理、并提供 OpenAI 兼容接口。核心是"把显存用得更足、把计算用得更满"。
  2. "一个 7B 模型跑起来大概要多少显存?" → 答:约 14GB 左右(FP16 权重 ≈ 2×参数量字节),加 KV cache 和量化会更省;具体看量化方式和上下文长度。重点是给面试官展示你的估算逻辑。
  3. "你怎么控制 token 成本?" → 答:压缩 Prompt、只带必要历史、RAG 只检索最相关片段、限制 max_tokens、用量统计与限流告警、必要时换更小/更便宜的模型。
  4. "流式输出要注意什么?" → 答:TTFT 低体验好;但要处理超时、断流重连、错误返回;流式同样要限流和幂等,防止并发打爆和重复计费。
  5. "客户说数据不能出内网,你怎么大概率满足?" → 答:私有化部署:客户内网 GPU 机用 vLLM 起开源/私有模型,后端和 RAG 全在内网,只暴露内网接口并做鉴权限流;评估是否满足效果要求,必要时折中(本地小模型 + 关键场景人工)。

3.8 小结

  • 推理 vs 训练:FDE 主要管"推理"——快、稳、便宜。
  • vLLM 是私有化部署标配;讲清 PagedAttention 和 batching。
  • 调 API:统一 OpenAI 姿势、低 temperature、超时退避重试。
  • token/上下文/流式是日常三坑,会管 token 和窗口就是省钱。
  • 下一章:怎么把客户文档"喂进"模型——RAG 全链路。

延伸阅读 · 去本站教学页补齐基础

  • Rust + AI 全栈——看 GGUF 量化等级怎么选、连续批处理推理服务的完整代码。
  • Python AI 数据科学——从 PyTorch 到 FastAPI 推理接口,补齐 Python 侧调模型的地基。
  • Spring AI——Java 项目里用一种 ChatClient 姿势接大模型的完整套路。
  • 算法与 AI——从 token、上下文窗口到 Transformer 与量化,理解大模型推理的底层原理。
本页由 FDE 培养课程文档生成,完整课程见 FDE 培养 · 课程总览。