大模型上线没那么难!手把手教你搭一个高并发推理服务,再给它打个分

0 阅读9分钟

你是不是也有这种感觉:明明花了大价钱买了GPU,跑起大模型来却慢得像蜗牛?别人能同时接100个请求,你接10个就开始报错?别急,今天这篇文章就是给你“抄作业”的——从部署到压测,再到给模型的能力打分,一条龙全讲明白。


一、为什么你的大模型跑得慢?—— 显存里藏着的“浪费”

我们先想一个问题:大模型在回答你问题的时候,它在做什么?

简单说,它是一个字一个字往外蹦的。每次生成下一个字,都要回头看一眼之前说过的所有字(这叫“注意力机制”)。为了让模型不用每次重新算一遍,它会把这些“记忆”存下来,放到一块叫 KV Cache 的区域。

问题来了:传统方法(比如Hugging Face自带的生成方式)给每个请求提前占好一整块连续的内存。就好比你一个人去电影院,非要把一整排座位都占上,说“万一我朋友来了呢”。结果大部分座位空着,别人想坐也坐不了。

这就造成了两个后果:

  • 显存利用率低

    :可能只用了30%,剩下的都浪费了。

  • 并发能力差

    :来几个请求就把显存占满了,后面的只能排队。

所以,你需要的不是更贵的显卡,而是一个更聪明的“调度员”——vLLM


二、vLLM:一个能让你的GPU“物尽其用”的推理引擎

vLLM 是加州大学伯克利分校团队开发的开源项目,现在已经是大模型推理的标配之一。它的核心思想就两个,特别容易理解。

2.1 PagedAttention:像拼积木一样管理显存

vLLM 不再给每个请求预留一大块连续显存,而是把显存切成很多小块(就像一页一页的纸)。一个请求来了,它需要几页就分配几页,而且这些页可以不连续存放,通过一张“目录”(页表)来找到它们。

打个比方:传统方法像你租房子,必须整租一套,哪怕你只住一间;vLLM像按天住青旅,来一个人开一个床位,走了立刻腾出来给别人。

结果就是:同样的显存,能同时服务更多请求。官方数据说,最高能让吞吐量(每秒处理的请求数)提升24倍。这不是玄学,是实实在在的工程优化。

2.2 Continuous Batching:让GPU永远不闲着

你有没有遇到过这种情况:食堂打饭,必须等一整个班的人到齐了才开饭,结果有人慢吞吞,全班都得等。

传统批处理就是这个毛病:必须攒够一批请求才一起算,一旦有个请求特别长(比如要写2000个字的回答),整个批次就被它拖慢了,GPU在那干等。

vLLM的连续批处理,就像流水线:每个请求独立处理,哪个完成了就立刻从队列里拉一个新的进来。GPU永远有活干,利用率自然就上去了。


三、动手部署:一行命令跑起一个OpenAI风格的API

很多教程让你配一堆环境、写一堆代码,vLLM不用。你只要装好,然后一行命令就能启动一个和OpenAI完全兼容的API服务。

第一步:装环境

conda create -n vllm_env python=3.11
conda activate vllm_env
pip install vllm

第二步:启动服务

假设你已经有一个训练好的模型(比如Qwen3-8B),放在 /root/autodl-tmp/models/Qwen3-8B-sft-all 目录下。执行:

vllm serve /root/autodl-tmp/models/Qwen3-8B-sft-all \
  --served-model-name Qwen3-8B-sft-all \
  --max-model-len 32K

解释一下:

  • serve:告诉vLLM我要起一个API服务。

  • 第一个路径:你的模型文件夹。

  • --served-model-name:对外暴露的模型名字,调用的时候要用这个。

  • --max-model-len 32K:允许最大上下文长度(32K就是32768个token,约2万多汉字)。

启动成功后,你会看到类似 Uvicorn running on http://localhost:8000 的提示。这就说明服务已经就绪了。

第三步:后台运行(生产环境必用)

nohup vllm serve /root/autodl-tmp/models/Qwen3-8B-sft-all \
  --served-model-name Qwen3-8B-sft-all \
  --max-model-len 32K > vllm.log 2>&1 &

nohup 让它不会因为你关掉终端而停止,日志输出到 vllm.log 文件。


四、调用服务:三种方式,任你挑选

服务跑起来了,怎么用呢?很简单,vLLM提供了和OpenAI一模一样的接口,所以你用任何支持OpenAI的客户端都能调。

4.1 用curl快速测试

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen3-8B-sft-all",
    "messages": [
      {"role": "system", "content": "你是个乐于助人的助理。"},
      {"role": "user", "content": "我的猫死了,我很难过。"}
    ]
  }'

你会看到模型返回一段安慰你的话。

4.2 用Python的OpenAI库

from openai import OpenAI
 
client = OpenAI(
    base_url="http://localhost:8000/v1/",
    api_key="none"   # vLLM默认不校验key,占个位就行
)
 
response = client.chat.completions.create(
    model="Qwen3-8B-sft-all",
    messages=[
        {"role": "user", "content": "量子计算会威胁比特币吗?"}
    ]
)
 
print(response.choices[0].message.content)

是不是和调用真正的OpenAI一模一样?无缝切换。

4.3 用LangChain

很多做AI应用的人喜欢用LangChain,vLLM也完美支持。

from langchain_openai import ChatOpenAI
 
llm = ChatOpenAI(
    model="Qwen3-8B-sft-all",
    base_url="http://localhost:8000/v1/",
    api_key="none",
    temperature=0
)
 
response = llm.invoke("用一句话解释什么是PagedAttention")
print(response.content)

五、光跑起来还不够:你的模型到底能扛多大压力?

服务跑通了,但你肯定想知道:它能同时服务多少人?首字响应快不快?每秒能吐多少个字?

这就需要做压力测试。别一听“压测”就觉得复杂,用阿里魔搭社区的 EvalScope 工具,一行命令全搞定。

安装压测模块

pip install 'evalscope[perf]'

发起压测

evalscope perf \
  --url "http://127.0.0.1:8000/v1/chat/completions" \
  --parallel 5 \
  --model Qwen3-8B-sft-all \
  --number 20 \
  --api openai \
  --dataset openqa \
  --stream

参数说明,我用人话翻译一下:

参数

意思

--parallel 5

同时开5个“虚拟用户”去问模型

--number 20

总共问20次(5个用户,每人问4轮)

--dataset openqa

用一套现成的问答集当考题

--stream

模拟打字机效果,一个字一个字返回

跑完之后,你会看到一张结果表。我帮你解读最重要的几个指标:

指标

白话解释

Output token throughput (tok/s)

模型每秒能吐出多少个字。越高说明回答越快。

Time to first token (s)

你问完问题,模型多久才蹦出第一个字。这是体验的关键——如果超过1秒,用户就会觉得“卡”。

Average latency (s)

从你发问到拿到完整回答的总耗时。

Succeed requests

成功多少个。如果失败率很高,说明服务扛不住这个并发。

举个例子,如果你跑出来 Time to first token 是0.2秒,Output token throughput 是100 tok/s,那就相当不错了。


六、模型“智商”够不够?—— 用EvalScope给它打个分

压测测的是速度并发能力。但你的模型回答得准不准、逻辑强不强、会不会胡说八道,那是另一个维度的问题,需要能力评估

EvalScope 内置了海量考试题,比如:

  • MMLU

    :考模型的综合知识(像高考文综)

  • GSM8K

    :小学数学应用题

  • HumanEval

    :写代码的能力

  • IFEval

    :能不能听明白复杂指令

专门针对Qwen3模型,魔搭社区还整理了一个 modelscope/EvalScope-Qwen3-Test 数据集,把这些考题打包好了。

跑评估只需要几行Python代码

from evalscope import TaskConfig, run_task
 
task_cfg = TaskConfig(
    model='Qwen3-8B-sft-all',
    api_url='http://127.0.0.1:8000/v1/chat/completions',
    eval_type='service',
    datasets=['data_collection'],
    dataset_args={
        'data_collection': {
            'dataset_id': 'modelscope/EvalScope-Qwen3-Test',
            'filters': {'remove_until': '</think>'}  # 过滤掉模型内部的思考过程
        }
    },
    generation_config={
        'max_tokens': 30000,   # 允许模型输出很长(比如复杂推理)
        'temperature': 0.6,    # 采样温度,Qwen官方推荐值
        'top_p': 0.95,
    },
    limit=200   # 先测200条,省时间
)
 
run_task(task_cfg=task_cfg)

跑完后,EvalScope会给出每个科目的得分,比如MMLU 85分、GSM8K 92分……你就能清楚地知道模型哪里强、哪里弱。

想看漂亮的可视化报告? 安装可视化模块:

pip install 'evalscope[app]'
evalscope_app

如果是远程服务器(比如云主机),用SSH隧道把端口映射到本地:

ssh -CNg -L 7860:127.0.0.1:7860 root@你的服务器地址 -p 你的端口

然后浏览器打开 http://localhost:7860,就能看到一个酷炫的看板,所有成绩一目了然。


七、一个小窍门:专门测“思考型”模型的效率

最近很多模型(比如DeepSeek-R1、QwQ)会先输出一大段思考过程,然后再给答案。这种模式虽然准确率高了,但有时候会“过度思考”——明明10个字能说清,非要绕2000个字。

EvalScope 专门为这种模型设计了一个思考效率指标:

  • 推理Token数

    :模型在 标签内写了多少字。

  • 首次正确Token位置

    :正确答案最早出现在第几个字。

  • Token效率

    :正确答案出现得越早,效率越高。

这样你就能判断:你的模型是不是在“装模作样地思考”,还是真的在高效推理。


八、总结:一套组合拳,让大模型又快又准

我们来回顾一下今天的“三板斧”:

  1. 用vLLM部署

    :一行命令启动高并发、高吞吐的推理服务,解决“跑得慢”的问题。

  2. 用EvalScope压测

    :量化服务的并发能力、首字延迟、吞吐量,解决“能不能扛住”的问题。

  3. 用EvalScope评估

    :用标准考题给模型智商打分,解决“回答得好不好”的问题。

这三步做完,你的大模型应用就具备了生产可用的基础。无论是做AI客服、代码助手,还是内容生成,你都能自信地说:我知道它能跑多快,也知道它有多聪明。

希望这篇文章能帮你少踩一些坑。如果你在实操中遇到问题,欢迎留言讨论,我会尽量解答。