上个星期,我在一台 Ubuntu 服务器上把千问系列模型从零到一完整部署了一遍——先确认显卡驱动和 CUDA 环境,再搭建 Python 虚拟环境,然后是模型文件下载、推理服务启动、最后用接口对外提供对话能力。整个过程走完,最深的感受是:千问的部署本身并不难,难的是动手之前把路线选对,以及在环境问题上少走弯路。这段时间陆陆续续有同事和朋友问我一模一样的流程:怎么选模型、显卡要求多高、vLLM 和 Ollama 到底该用哪个、量化方案怎么选。干脆把整个思路和步骤按实际操作的顺序整理成这篇文章。
这篇文章不是简单的命令清单,只贴命令那种文章你搜一下到处都是。我想重点讲的是每一步背后的选择逻辑,以及踩过之后才明白的坑。如果你手上有一台 Ubuntu 机器,想跑千问系列模型做原型验证,或者想给团队搭一个内网可用的推理服务,又或者单纯想在本地折腾大模型,这篇文章的思路和步骤都适用。7B 级别的单卡部署、更大规模的服务化部署,核心链路是一样的。
1. 动手之前,先想清楚这几件事
1.1 你的显卡能扛多大参数量的模型
部署千问的第一步不是装环境,而是算显存账。千问系列开源模型从 0.5B 一直到 72B,规模跨度非常大,对显存的要求差距是十倍级别的。
先给一个粗略估算公式:模型权重占用的显存,大约等于参数量乘以每个参数占用的字节数,再乘以 1.2 到 1.25 的系数。比如 7B 模型用 FP16(半精度)存储,每个参数占 2 字节,光权重就是 14GB 左右,加上 KV Cache 和中间激活值,单卡要跑得流畅,建议至少 16GB 显存,保险起见直接上 24GB。如果换成 INT4 量化,每个参数只需要 0.5 字节,7B 模型的权重就压到 4GB 上下,显存压力立刻小了一大截,代价是生成速度会有折损,具体损失多少我在后面量化那节细说。
我整理了一个按单卡配置做的参考表,实际部署前可以先拿这个表格对照一下自己手里的卡:
| 模型规模 | FP16 权重占用 | INT4 量化后权重占用 | 推荐至少显存 | 备注 |
|---|---|---|---|---|
| Qwen2.5-1.5B | 3GB | 不到 1GB | 6GB | 纯 CPU 也能跑,速度感人 |
| Qwen2.5-3B | 6GB | 2GB 左右 | 8GB | 入门级显卡可以玩 |
| Qwen2.5-7B | 14GB | 4~5GB | 16GB | 最常见的单卡部署档位 |
| Qwen2.5-14B | 28GB | 8~9GB | 32GB | 量化后 24GB 卡可一战 |
| Qwen2.5-32B | 64GB | 16~18GB | 40GB 以上或多卡 | 单卡建议 4090 这类大显存卡 |
| Qwen2.5-72B | 144GB | 36~40GB | 多卡或大显存 | 基本要上多卡张量并行 |
注意,上面只算了模型权重的占用,实际推理时还要考虑 KV Cache。KV Cache 的大小和上下文长度直接相关,估算方式大约是层数、隐藏维度和序列长度的乘积关系。以 7B 规模的模型为例,32 层、4096 隐藏维度、4096 上下文长度的情况下,KV Cache 大约额外占用 2GB 左右。如果你把 max-model-len 拉到 32K 甚至更长,这部分显存会成倍增长,所以不要以为显存只是用来装权重的。
1.2 三种部署路线怎么选
千问在 Ubuntu 上有三条主流部署路线,我分别说说它们解决问题的场景,你在动手前需要做好选择,因为后面所有步骤都围绕这条路线展开。
第一条是直接用 Transformers 加载模型。这是最灵活的路线,代码直观,方便你定制推理逻辑、接入 RAG 或者做深度调试。缺点是默认实现是逐 token 生成,单请求吞吐偏低,不适合高并发场景。如果只是自己测试效果,或者要做研究和二次开发,这条路线最合适。
第二条是用 vLLM 做服务化部署。vLLM 会把模型封装成一个 OpenAI 兼容的 HTTP 接口,内部用了 continuous batching 和 PagedAttention 技术,可以在并发场景下大幅提高吞吐量。缺点是依赖和环境要求相对高,启动时占用的显存也更大。如果需要给团队搭一个内网推理服务,或者要对接现有系统,直接上 vLLM 是最省心的。
第三条是 Ollama 路线。Ollama 把 llama.cpp 系的运行时、模型管理和命令行交互都封装好了,一行命令就能拉模型、一行命令就能启动对话。它适合个人电脑、快速验证、低并发场景。优点是安装最简单,缺点是你很难深入定制生成逻辑,API 也相对没那么标准。
选型逻辑说白了就三个问题:是不是要对外提供服务?并发量大概多少?愿意花多少时间在环境调试上?如果只是自己玩,Ollama 是最省事的;团队要搭内网服务,直接 vLLM;要做二次开发或者想彻底搞懂推理机制,就从 Transformers 开始。
1.3 量化方案先想好,别到时候再来回折腾
量化这个问题,我建议你在选模型和部署路线之前就想清楚,不要等模型下载完了才发现显存不够,然后又重新下载。
不同部署路线支持的量化格式是不一样的。Ollama 只认 GGUF 格式的量化模型;vLLM 支持 GPTQ、AWQ 量化的模型,也支持部分 GGUF;Transformers 可以用 bitsandbytes 在加载时动态量化,也可以配合 AutoGPTQ 加载 GPTQ 模型。如果选错了路线和格式的搭配,实际上还是能跑,但要走很多弯路。
量化的核心思路是用较少的位宽去近似表示模型权重。比如 FP16 是 2 字节,INT8 是 1 字节,INT4 是 0.5 字节。位宽越低,显存占用越小,但信息损失越大,模型的回答质量可能会下降。不过在实际体验中,对于 7B 以上的模型,合理的 INT4 量化对回答质量的损失通常是可以接受的,尤其对话场景下感官差异不明显。我的建议是:显存紧张就上 INT4,显存宽裕就保持 FP16/FP32,没必要为了极致精度牺牲部署成功率。
2. Ubuntu 环境准备:驱动、CUDA、Python 一条龙
2.1 显卡驱动装对了,后面能少走一半弯路
在 Ubuntu 上部署千问,环境部分最大的坑不在 Python,而在显卡驱动。很多同学装了 PyTorch 之后发现torch.cuda.is_available()返回 False,第一反应是重装 PyTorch,其实是驱动层面的问题。
先跑一条命令看看现状:
nvidia-smi如果这条命令能正常输出 GPU 信息,说明驱动已经装好,右侧显示的 CUDA Version 表示当前驱动支持的最大 CUDA 版本。如果提示找不到命令,说明驱动没装或者没在 PATH 里。
一个很多人不知道的知识点:PyTorch 从 2.x 版本开始,会自带 CUDA runtime,你通过 pip 安装的是 cu121、cu124 这类带 CUDA 的版本,实际上不需要在系统里单独装一套完整 CUDA Toolkit。真正的要求是:显卡驱动的版本足够新,能支撑 PyTorch 自带的 CUDA runtime。简单说,驱动里的 CUDA 版本号只要大于等于 PyTorch 要求的版本号即可。
所以环境规划的思路就清晰了:先把显卡驱动装好,然后直接装带 CUDA 的 PyTorch,其他 CUDA Toolkit 组件可以不装。省了很多事,也少踩很多坑。我在一台以前装过老版本驱动的机器上踩过这么一次:驱动版本太老,PyTorch cu124 装上后调用 CUDA 接口直接报错,最后是把驱动升级到较新的长期支持版本才解决。升级驱动之后一定要重启机器,再用 nvidia-smi 确认。
2.2 Python 虚拟环境与 PyTorch 版本对齐
环境隔离是必须做的。我见过有人直接在系统 Python 里装一堆依赖,结果版本冲突之后,整个系统的包管理直接崩了,最后被迫重装系统。用 conda 或者 venv 创建独立环境,成本极低,收益极高。
我自己的做法是 conda 建环境,Python 版本选 3.10 或 3.11:
conda create -n qwen python=3.11 -y conda activate qwen然后安装 PyTorch。这里注意,不要用默认 pip 源直接装,因为默认源很可能给你装 CPU 版本。从 PyTorch 官方源安装才能拿到 CUDA 版本:
pip install torch --index-url https://download.pytorch.org/whl/cu124装完之后一定要验证 CUDA 是否可用:
python -c "import torch; print(torch.__version__, torch.cuda.is_available())"如果输出是 True,说明 CUDA 环境已经通了。这一步验证很重要,后面所有报错排查都建立在 PyTorch 能正确调用 GPU 的基础上。另外提一句,Python 版本不建议选 3.12 以上的太新版本,虽然 PyTorch 现在支持,但 vLLM、AutoGPTQ 这类依赖包有些版本还没有完全跟上,选 3.10/3.11 是最稳妥的。
2.3 模型下载的两种渠道与断点续传
千问的开源模型权重,可以从两个主流模型托管平台下载:Hugging Face 和 ModelScope。两条渠道下载到的模型文件本质上是一样的,你按自己网络情况选择一条就行。
Hugging Face 用官方命令行工具下载:
pip install huggingface_hub huggingface-cli download Qwen/Qwen2.5-7B-Instruct --local-dir ./qwen-7b-instructModelScope 的下载命令也差不多:
pip install modelscope modelscope download --model Qwen/Qwen2.5-7B-Instruct --local_dir ./qwen-7b-instruct实际下载时注意一点:模型文件通常有好几个 GB,甚至几十 GB,网络波动很容易让下载中断。Hugging Face 的下载工具本身支持断点续传,中断之后重新执行同一命令,会从断点继续,不用从头再来。所以我给你的建议是:下载中途断了不用慌,重新执行命令就行。
另外一个非常容易忽视的问题:下载前先确认磁盘空间。用df -h看看目标磁盘的剩余空间,7B 模型 FP16 版本至少留出 20GB,14B 以上建议留 50GB 以上。我吃过一次亏,下载到一半磁盘满了,整批文件全部作废,白白浪费了几个小时。
3. 用 Transformers 把千问跑起来:最轻的完整方案
3.1 最小加载代码与 Chat Template 的正确用法
如果只是想验证模型能不能跑通,Transformers 是最直接的方式。先装依赖:
pip install transformers accelerate然后写一段最小加载代码:
from transformers import AutoModelForCausalLM, AutoTokenizer model_name = "Qwen/Qwen2.5-7B-Instruct" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForCausalLM.from_pretrained( model_name, torch_dtype="auto", device_map="auto" )这里的device_map="auto"会自动把模型分配到可用的 GPU 上,单卡场景就是全部放到 GPU。torch_dtype="auto"会自动匹配模型原始权重保存时的精度,如果要强制 FP16 可以传torch.float16。
千问的 Instruct 版本必须走 Chat Template,这是很多人容易忽视的地方。如果不套 Chat Template 直接把问题拼接成文给模型,输出格式会完全不对。正确的做法是用 tokenizer 内置的模板转换:
messages = [{"role": "user", "content": "用一句话介绍你自己"}] text = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) inputs = tokenizer([text], return_tensors="pt").to(model.device) response = model.generate( **inputs, max_new_tokens=512, do_sample=True, temperature=0.7, top_p=0.8 ) output = tokenizer.decode(response[0][len(inputs[0]):], skip_special_tokens=True) print(output)注意最后解码时用len(inputs[0])切掉输入部分,只留下模型新生成的 token,再跳过特殊符号,否则输出里会带着一大段对话历史。这段代码我在 24GB 显存的机器上跑 7B FP16 完全没问题,首次加载要预热的等待时间,之后单次生成每秒大约几十个 token,体验不错。
3.2 生成参数实战:max_new_tokens、temperature 怎么设
很多朋友拷了代码就跑,但生成参数不调,效果会差很多。这里分享下我调参的经验。
max_new_tokens控制模型最多生成多少新 token,默认值很小的话回答会被截断。做对话场景建议至少 512,需要长文生成就拉到 1024 或 2048。但要留意,这个值越大会占用越多的 KV Cache 显存,太长可能导致 OOM。
temperature控制随机性,取值 0 到 2,越低越确定,越高越发散。日常对话用 0.7 左右比较自然;做事实性问答可以降到 0.3;想让它有点创意可以调高到 1.0 以上,但太高容易出现胡言乱语。
top_p是核采样参数,控制在累积概率范围内的 token 被采样。保持默认 0.8 到 0.9 一般没问题。如果模型输出明显重复,把 top_p 适当调低,同时把 temperature 调到 0.7 以下,重复问题会缓解很多。
还有一个容易忽略的参数是repetition_penalty。如果遇到模型开始复读,可以把 repetition_penalty 调到 1.05 到 1.2 之间,能有效抑制重复。这个参数在 Transformers 的 generate 接口里直接传就行。
3.3 第一次推理的显存占用实测参考
我在 24GB 显存的单卡上做了一个小实测,用的是 Qwen2.5-7B-Instruct 的 FP16 版本。模型加载后显存占用大约 15GB 左右,也就是权重 14GB 加上一些额外开销。跑单轮对话、max_new_tokens 设为 512 时,峰值显存大约 16GB 以内。如果上下文长度拉到 8192,KV Cache 变大,峰值会接近 18GB 左右。对比 INT4 量化版本,显存占用降到 6~7GB,明显轻了一截,但生成速度从每秒几十个 token 下降到每秒二十个左右。
给一个直接的建议:24GB 显存的单卡,7B FP16 随便跑;16GB 显存的卡建议上 7B 的量化版本或者直接选 3B 模型;8GB 显存的卡就别碰 7B 了,老老实实用 Ollama 的量化版小模型,体验会好很多。
4. vLLM 部署:高并发服务化的正确打开方式
4.1 安装 vLLM 与启动单卡服务
如果目标是给团队或者系统提供推理服务,vLLM 是首选。它做的核心优化是 continuous batching,多个请求的解码可以交错执行,GPU 利用率比 Transformers 的逐请求处理高得多。
安装和启动比较简单。先装依赖,注意 vLLM 对 Python 和 PyTorch 版本有要求,我在 Python 3.11 环境里安装没有遇到问题:
pip install vllm然后一行命令启动服务:
vllm serve Qwen/Qwen2.5-7B-Instruct \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.9 \ --max-model-len 8192命令里的参数含义值得说一下。--tensor-parallel-size 1表示单卡推理,多卡场景把这个值改成显卡数量,vLLM 会自动做张量并行,把模型一层一层切到多张卡上。--gpu-memory-utilization 0.9表示最多使用 90% 的 GPU 显存,留出 10% 余量给 CUDA 上下文和碎片化开销。--max-model-len 8192表示最大上下文长度,这个值会直接影响 KV Cache 的显存占用。
启动成功后,控制台会输出服务地址,默认是http://0.0.0.0:8000。第一次启动会加载模型权重,需要一点时间,之后就可以接受请求了。
4.2 调 OpenAI 兼容接口的正确姿势
vLLM 启动的服务是 OpenAI 兼容的,这意味着你可以直接用 OpenAI SDK、或者任何支持 OpenAI 协议的工具来调用它。我用 curl 验证一下服务是否正常:
curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "Qwen/Qwen2.5-7B-Instruct", "messages": [{"role": "user", "content": "你好,介绍一下自己"}], "temperature": 0.7, "max_tokens": 512 }'返回的是一个 JSON,结构和 OpenAI 接口基本一致,包含 choices、usage 等字段。这里需要注意,请求体里的 model 字段要和你启动服务时传入的模型名称一致,否则会报错找不到模型。
用 Python 调用也很自然:
import requests resp = requests.post( "http://localhost:8000/v1/chat/completions", json={ "model": "Qwen/Qwen2.5-7B-Instruct", "messages": [{"role": "user", "content": "讲个冷笑话"}], "max_tokens": 256, } ) print(resp.json()["choices"][0]["message"]["content"])这种接口风格的好处是生态兼容性极好。我自己搭完服务后,直接改了一个现成项目里的接口地址和模型名就能跑,代码一行都不用改。如果团队里已经有用 OpenAI 接口写好的应用,接千问就是改个 base_url 的事。
4.3 并发能力和显存控制参数
vLLM 的优势在并发场景下才体现得明显。实测同样的 7B FP16 模型,Transformers 单请求每秒大概几十个 token,vLLM 在并发十几个请求时,整体吞吐能跑到几百个 token 每秒,这是连续批处理优化带来的效果,也是服务化部署选 vLLM 的最核心原因。
vLLM 的并发能力受几个参数共同约束。--max-num-seqs控制同时处理的序列数,默认值可能比较保守,可以调高试试,比如 128。--max-model-len控制上下文长度,越长每个序列占用的 KV Cache 越大,能并发的数量就越少。--gpu-memory-utilization控制显存使用上限,调高能容纳更多 KV Cache,但容易触发 OOM。
实际部署时我的调优顺序是:先确认显存够不够加载模型权重,然后按业务需求定 max-model-len,最后再调 gpu-memory-utilization 和 max-num-seqs 找到吞吐和稳定性的平衡点。如果只是内部测试,跑早一点就行,不用一开始就追求最大并发。
5. Ollama 路线:想省事时的备用方案
5.1 安装与拉取模型的一行命令
Ollama 是目前把大模型本地化做到最简单的工具。安装命令很短:
curl -fsSL https://ollama.com/install.sh | sh装完之后拉取模型:
ollama pull qwen2.5:7b启动服务并进入交互式对话:
ollama run qwen2.5:7b就这三条命令,一个能对话的千问就起来了。Ollama 底层用的是 llama.cpp 系的运行时,模型默认以 GGUF 格式加载,显存不够时甚至可以自动把部分层卸载到 CPU 上跑,所以对硬件的要求比 vLLM 和 Transformers 低很多。我自己在只有 8GB 显存的机器上,用qwen2.5:3b照样能跑得动,速度虽然不快但能用。
如果不想进交互模式,也可以用 REST API 调用。Ollama 默认监听 11434 端口,千问的对话接口是/api/chat,用 curl 就能测:
curl http://localhost:11434/api/chat \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5:7b", "messages": [{"role": "user", "content": "你好"}], "stream": false }'5.2 Ollama 与 vLLM 的取舍建议
我的建议很明确:个人电脑、低并发、快速验证,用 Ollama;团队服务化、高并发、需要稳定吞吐,用 vLLM。这两条路线不是替代关系,而是场景不同。
Ollama 的优点是上手简单、资源占用可控、CPU 也能顶一下。缺点是并发能力弱、自定义空间小、API 不是标准的 OpenAI 格式(虽然它也提供一个兼容端点,但功能没那么完整)。vLLM 的优点是吞吐高、接口标准、可控参数多。缺点是对显存要求更苛刻,启动复杂度高一点。
有一个常见场景值得说一下:你如果只是自己的开发机想跑模型,不建议上 vLLM 把显存全占了,用 Ollama 更舒服。如果是要部署一个供同事调用的服务,vLLM 是更负责任的选择,因为它能扛住并发压力。两条路线切换的成本其实不高,模型权重文件可以分别以不同格式存在本地,互不影响。
6. 推理性能调优:上下文、并发与显存的三角关系
6.1 显存分配逻辑:权重、KV Cache 和激活值
跑通模型只是第一步,真正让服务稳定运行,需要理解显存是怎么被消耗掉的。推理时的显存主要分三块:模型权重、KV Cache、中间激活值。模型权重相对固定,加载完就占住了;KV Cache 随上下文长度和并发请求数动态增长;中间激活值在预填充阶段会有一段峰值。
这就是为什么你嗗下gpu-memory-utilization 0.9的时候,vLLM 会把 90% 的显存都纳入自己的管理范围,预留一部分给权重和激活值,剩下的全部用来准备 KV Cache。如果你把max-model-len调得很大,KV Cache 预留就会变多,能并发的请求数就会少;反之亦然。
调优时需要有一个整体视角。举个实际例子:7B FP16,24GB 显存,max-model-len8192,gpu-memory-utilization0.9,max-num-seqs64,vLLM 可以轻松跑起来;同样的配置,把max-model-len拉到 32768,可能就需要把max-num-seqs降到 32 才能不 OOM。如果你既要长上下文又要高并发,唯一的硬性方案就是换更大显存的卡或者用量化模型。
6.2 量化三选一:GGUF、GPTQ、AWQ
量化方案的选择,直接决定你能不能在有限显存下跑起更大的模型。我梳理了主流的三种格式和它们的适用场景:
| 量化格式 | 主要运行时 | 特点 | 推荐场景 |
|---|---|---|---|
| GGUF (Q4_K_M) | Ollama、llama.cpp | 体积小,CPU 也能跑,生态成熟 | 个人电脑、低显存、快速验证 |
| GPTQ (4bit) | vLLM、Transformers | 保真度较高,GPU 推理优化好 | 服务化部署、vLLM 场景 |
| AWQ (4bit) | vLLM(原生支持) | 激活感知量化,权重量化后稳定性好 | 服务化部署,追求低显存高性能 |
GGUF 的 Q4_K_M 是我个人用得最多的一个量化档位。它的 4bit 量化质量在同类里算好的,7B 模型量化后权重约 4GB 出头,24GB 显卡跑完全没问题,甚至 16GB 都能带起来。配合 Ollama,一条命令就能用起来。
GPTQ 和 AWQ 更适合配合 vLLM 使用。vLLM 对这两种格式有原生支持,加载后依然能享受连续批处理带来的高吞吐。在服务化场景里,如果你需要 32B、72B 这种大模型又不想上多卡,量化几乎是唯一解。不过要注意,从 Hugging Face 拉取量化模型时,有些量化版本的权重已经在模型描述里注明了适用框架,动手前看一眼模型卡的说明,别下错了格式。
7. 部署中的高频坑与完整排查链路
7.1 “CUDA out of memory”的完整排查顺序
这个报错我遇到无数次,基本都是同一个原因:显存不够。但显存不够有不同的触发点,排查要按顺序来,不要一上来就改代码。
第一步:先看当前显存被谁占了。
nvidia-smi注意看有没有其他进程占用了显存。我遇到过最离谱的一次是之前跑的 Python 进程没退出,僵尸进程把显存占了 10GB,新模型死活加载不进去。直接杀掉僵尸进程就解决了。
第二步:确认报错发生在加载阶段还是生成阶段。加载阶段 OOM,说明权重放不下,要么换量化模型,要么换小模型;生成阶段 OOM,说明 KV Cache 超了,把 max-model-len 调小,或者把并发数降下来。
第三步:检查是不是 CUDA graph 的额外显存导致。vLLM 默认会为加速请求申请额外显存,在显存很吃紧的情况下可以加--enforce-eager启动参数,关掉 CUDA graph 优化,牺牲一点点速度换显存空间。
第四步:如果上述步骤都不行,退一步用 CPU offload。Transformers 支持device_map="auto"自动把部分层放到 CPU,Ollama 在显存不足时也会自动卸载层。代价是速度明显变慢,但至少能跑。
7.2 模型下载中断的续传方案
下载大模型中断这件事,几乎人人都遇到过。我的一些经验:
Hugging Face 的huggingface-cli download是支持断点续传的,中断后重新执行命令,已下载的分片不会重来。ModelScope 的工具同样支持。关键是中断之后别去手动删文件,直接重新跑命令,下载工具会自己判断哪些分片已经完成。
有时候是某个大文件反复下载失败。一个较有效的方式是用--include参数单独下载失败的分片,比如:
huggingface-cli download Qwen/Qwen2.5-7B-Instruct \ --local-dir ./qwen-7b-instruct \ --include "*.safetensors"这样只拉模型权重文件,其他无关的配置文件不重复下载。分片下载完成之后,整个模型目录就完整了。
还有一个经常被忽略的问题:磁盘空间。下载前用df -h看一下,7B FP16 至少留 20GB,14B 以上至少留 50GB。我见过有人下载到 90%,磁盘满了,整个目录作废,白等几个小时。另外,模型文件多了之后,下载目录的磁盘 I/O 也会成为瓶颈,建议把下载目录放在固态硬盘上。
7.3 模型回答乱码、重复或者空白怎么定位
跑通之后最怕遇到“模型在说话但说不好”的问题。我按出现频率排一下常见原因和解决办法。
第一,乱码或格式完全不对。几乎都是因为没走 Chat Template。直接用原始文本喂给模型,千问 Instruct 版本会输出夹带特殊符号或者格式错乱的内容。解决办法就是参照上文用apply_chat_template转换输入。vLLM 和 Ollama 会默认处理聊天模板,所以这两个路线基本不会遇到这个问题。
第二,输出重复、绕圈。先检查 temperature 是不是太高,太高会导致发散和复读,调到 0.7 以下;再看是不是没有设置 repetition_penalty,加上 1.05 到 1.1 的值,复读通常会缓解。还有一个原因是上下文太长时模型“忘了”之前说了什么,这在长对话场景比较常见,需要配合摘要机制来解决。
第三,输出空白或者非常短。大概率是 max_new_tokens 设置太小,或者模型生成到了结束符。先调大 max_new_tokens 试试。如果一直只输出特殊符号,考虑是 tokenizer 版本和 model 版本不匹配,升级 transformers 和 tokenizers 到最新版再试。
第四,回答质量明显差。可能是量化程度太高造成的损失,比如用 4bit 量化跑 1.5B 模型,效果确实一般。这种时候要么换大模型,要么降低量化强度,用 Q8 或直接半精度。
提示:排查生成质量问题时,有一个高效的验证方法——先用官方提供的 Demo 脚本跑一遍同模型,再看看自己的代码和脚本之间的差异。如果官方脚本输出正常,那问题基本出在输入格式或生成参数上。
最后再分享一个我自己操作时的小习惯:部署完千问之后,不要急着接业务,先把模型拉起来跑一轮比较固定的测试问题集,记录下响应时间、显存占用、回答质量,再调一轮参数。这个基线数据在后面排查问题和评估模型效果时特别有用。毕竟模型部署只是开始,真正让模型稳定可靠地服务,需要你在实际使用中不断调优。