ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

大模型工程落地实战:vLLM+LoRA生产级部署全链路解析

大模型工程落地实战:vLLM+LoRA生产级部署全链路解析 1. 项目概述这不是又一个“大模型入门课”而是一份从实验室代码到生产环境的实战手记“SGG-大模型从算法优化到工程落地的双重范式”——这个标题里没有“零基础”“速成”“保姆级”也没有“爆火”“风口”“躺赢”。它直白得近乎冷酷SGG是项目代号也是我们团队内部对这套技术栈的简称大模型不是泛指LLaMA或Qwen而是特指我们在真实业务场景中反复打磨、最终跑通全链路的7B级中文对话模型算法优化与工程落地不是并列的两个模块而是同一枚硬币的两面你调参时没考虑显存碎片推理服务就必然OOM你设计API时忽略请求队列积压再好的微调结果也卡在网关。我带过三支不同行业的AI落地团队见过太多项目死在“模型指标漂亮上线即崩盘”的断崖上。这次SGG项目我们用142天把37次模型迭代、21轮服务压测、8次架构重构的原始日志、监控截图和失败回滚记录全部沉淀为可复现、可审计、可交接的技术路径。它不教你怎么写prompt但会告诉你为什么在batch_size4时GPU利用率只有32%它不讲transformer原理但会拆解如何把一个12GB的LoRA权重在不重启服务的前提下热加载进正在响应用户请求的vLLM实例。如果你正卡在“训完模型不知道下一步该部署到哪”“部署后QPS上不去还老超时”“微调效果好但一上生产就变智障”这些具体而真实的困境里这篇就是为你写的。它适合两类人一类是刚跑通Lora微调的算法同学想真正理解自己写的那几行peft_config.py背后发生了什么另一类是运维或后端工程师被临时拉来“支持下AI服务”面对一堆陌生的CUDA_VISIBLE_DEVICES和--tp-size参数一头雾水。我们不用“范式”这种词装点门面只说人话怎么让大模型在你公司的服务器上老老实实、稳稳当当地干活。2. SGG项目整体设计与思路拆解为什么放弃“标准流程”选择一条更笨但更稳的路2.1 核心矛盾识别算法指标与工程指标的天然撕裂很多团队启动大模型项目时第一张PPT永远是“准确率提升X%”“BLEU分数提高Y点”。这本身没错但问题在于这些指标是在理想数据集、固定batch、无并发压力、单卡测试环境下得出的。而真实世界里一个客服对话系统它的核心KPI是“95%的请求在800ms内返回”不是“BLEU得分高”。我们最初也走了弯路在A100上微调出一个BLEU 42.3的模型兴奋地部署到T4集群结果首日上线平均延迟飙到2.3秒错误率17%。根因排查发现问题不在模型本身而在三个被算法侧完全忽略的工程细节第一训练时用的FlashAttention-2在T4上因compute capability 7.5不支持自动fallback到慢速kernel推理吞吐直接腰斩第二微调时用的bf16精度但T4不支持bf16强制转为fp16后部分层权重出现NaN导致输出乱码第三最致命的是训练脚本里hardcode了max_length2048而线上用户输入的长对话历史经tokenizer处理后实际token数常达2300触发了vLLM的sequence overflow保护机制直接拒绝服务。这三点没有任何一篇论文会提但每一点都足以让项目停摆一周。SGG项目的设计起点就是承认这个撕裂算法优化的目标必须是“可工程化”的优化。我们定义了SGG的三条铁律所有算法改进必须附带对应的工程验证方案所有工程改造必须有可量化的算法影响评估任何技术选型必须同时通过“单卡性能测试”和“多卡服务压测”双关卡。2.2 技术栈选型逻辑为什么是vLLM LoRA Triton而不是HuggingFace TGI或DeepSpeed-Inference市面上的大模型推理框架不少TGI、vLLM、Text Generation InferenceTGI、llama.cpp甚至还有团队自己魔改PyTorch。我们花了三周时间用同一套模型、同一组测试数据在A10、A100、L4、T4四类卡上做了横向对比。结果很清晰TGI在A100上表现优异但在L4上其PagedAttention内存管理策略因L4的16GB显存限制导致prefill阶段频繁触发CPU-GPU数据搬运延迟波动极大llama.cpp主打CPU推理对我们要求的“亚秒级响应”完全不达标而vLLM在L4上展现出惊人的鲁棒性——它通过自定义的PagedKVCache将KV缓存按block切分每个block大小严格控制在L4显存页对齐边界4KB配合高效的block swapping策略使得即使在显存仅剩2GB时仍能维持85%以上的GPU利用率。这是算法层面的精巧设计更是工程落地的刚需。所以SGG选择了vLLM作为推理底座。微调方案上我们放弃了全参数微调Full Fine-tuning和QLoRA原因很实在全参数微调需要至少24GB显存超出我们主力L4卡的物理上限QLoRA的4-bit量化在推理时需实时dequantize引入额外计算开销实测在L4上反而比标准LoRA慢12%。最终选定标准LoRA但做了关键改造将LoRA的rrank参数从默认的8根据各层敏感度分析动态设为4/8/16三级使总参数量减少37%加载速度提升2.1倍。至于Triton它不是用来写新算子的而是用来重写vLLM中那个最耗时的函数paged_attention_v1。原生CUDA kernel在L4上存在严重的warp divergence我们用Triton重写后该kernel执行时间从1.8ms降至0.6ms占整个prefill阶段时间的比重从34%压到12%。这个选择不是为了炫技而是因为L4的SM数量32个远少于A100108个对kernel的并行效率极度敏感。每一个技术选型背后都是硬件规格、业务指标、团队能力三者的精确咬合。2.3 架构演进路径从单机单卡到高可用服务的五次迭代SGG的架构不是一开始就想好的而是踩着坑一步步长出来的。第一版V1本地Jupyter Notebook跑transformers.pipeline纯属验证想法连API都没有。第二版V2用FastAPI包装单进程单卡无任何并发控制。上线第一天一个用户发了个2000字长文直接把GPU占满其他所有请求排队等待P95延迟突破5秒。第三版V3引入vLLM配置--tensor-parallel-size 1 --pipeline-parallel-size 1解决了单卡瓶颈但未解决服务稳定性。我们发现vLLM的--max-num-seqs参数若设得过大会导致请求队列积压内存暴涨设得太小又浪费GPU资源。于是我们开发了动态队列控制器根据GPU显存剩余率和当前请求平均长度实时调整--max-num-seqs这个逻辑后来被我们抽成独立模块sgg-queue-adaptor。第四版V4加入PrometheusGrafana监控但只监GPU利用率、显存占用等基础指标。一次深夜告警GPU利用率98%显存95%但QPS却跌到谷底。深入排查才发现是PCIe带宽打满nvidia-smi dmon -s u -d 1显示rx_util持续100%根源是vLLM的--enable-chunked-prefill未开启导致大请求一次性拉取所有KV cache压垮PCIe。第五版V5也就是当前稳定版采用vLLM的--enable-chunked-prefill--max-num-batched-tokens 2048组合并在Nginx层配置proxy_buffering off彻底解决PCIe瓶颈同时将模型服务拆分为prefill和decode两个独立vLLM实例前者专攻长文本理解后者专注流式生成通过Redis Pub/Sub解耦实现真正的异步流水线。这五次迭代每一次都源于一个具体的、无法回避的线上问题而非理论推演。所谓“双重范式”其本质就是算法与工程在真实压力下的相互校准与驯化。3. 核心细节解析与实操要点那些文档里不会写的“魔鬼细节”3.1 LoRA微调中的权重冻结陷阱为什么你的微调结果在vLLM上失效LoRA微调看似简单peft.get_peft_model(model, lora_config)一行代码搞定。但SGG项目初期我们遇到了一个诡异现象在训练脚本里用model.generate()测试效果完美但将LoRA权重导出为adapter_model.bin加载到vLLM中输出质量断崖式下跌。排查了三天最终定位到一个被所有人忽略的细节peft_config.target_modules的设置。我们最初照搬HuggingFace示例设为[q_proj, v_proj]。这在训练时没问题因为transformers.Trainer会自动将这些模块替换为LoraLinear。但vLLM加载LoRA时其LoraRequest机制要求LoRA权重必须与base model的对应层完全同名且同结构。问题来了HuggingFace的LlamaForCausalLM源码里q_proj和v_proj是nn.Linear但vLLM的LlamaModel实现中这两个层被封装在LlamaAttention类里其属性名为qkv_proj一个将q/k/v合并的线性层。当我们用[q_proj, v_proj]微调时peft创建的LoraLinear层在vLLM的模型图中根本找不到匹配的父节点导致LoRA权重被静默忽略解决方案是必须查看vLLM源码中对应模型的forward函数找到其实际使用的层名。对于vLLM的Llama正确target_modules是[qkv_proj, o_proj, gate_up_proj, down_proj]。我们为此写了一个小工具sgg-lora-checker.py它能自动解析vLLM模型的forward签名列出所有可注入LoRA的层名并生成标准配置。这个细节没有任何官方文档提及但它决定了你的微调工作是否真的“生效”。3.2 vLLM服务启动参数的物理意义不只是调参是理解GPU的“呼吸节奏”vLLM的启动命令像天书python -m vllm.entrypoints.api_server --model /path/to/model --tensor-parallel-size 1 --pipeline-parallel-size 1 --max-num-seqs 256 --max-model-len 2048 --gpu-memory-utilization 0.9 --enforce-eager。新手常把它当作黑盒参数去试错。但在SGG项目中我们给每个参数赋予了明确的物理意义将其视为对GPU硬件资源的“精准调度指令”。--max-num-seqs不是“最多处理多少个请求”而是“最多在GPU显存中同时驻留多少个请求的KV Cache Block”。每个Block大小为block_size * (num_layers * 2 * hidden_size * dtype_size)其中block_size默认为16。这意味着--max-num-seqs 256在我们的7B模型hidden_size4096, num_layers32上仅KV Cache就需占用约1.8GB显存。--gpu-memory-utilization 0.9不是简单的“显存使用率90%”而是vLLM向CUDA申请显存时的“信用额度”。它告诉vLLM“你可以按90%的显存总量来规划Block Cache但实际使用中如果某个请求突发增长可以临时超限只要不超过100%”。这个参数必须与--max-num-seqs协同调整。我们曾将utilization设为0.95max-num-seqs设为512结果服务启动失败报错CUDA out of memory。原因在于vLLM的Block Cache预分配逻辑会按utilization * total_memory计算总Block数再除以单Block大小得到最大Block数。当utilization过高计算出的最大Block数超过了GPU物理显存所能容纳的极限就会在初始化阶段崩溃。最终我们通过nvidia-smi监控memory.used和memory.total结合vllm的日志Initializing KV cache with ... blocks反向推导出最优组合utilization0.85,max-num-seqs384在L4上实现了显存利用率达84.7%且无OOM风险。这不再是调参而是对GPU内存管理机制的一次深度测绘。3.3 Python环境与CUDA版本的“隐性绑定”为什么pip install vllm总是失败SGG项目部署在Ubuntu 22.04 LTS上Python版本3.10。我们遇到最头疼的问题不是模型而是环境。pip install vllm在不同机器上有时成功有时报错nvcc fatal : Unsupported gpu architecture compute_86。根源在于CUDA Toolkit版本与GPU compute capability的严格匹配。我们的L4卡compute capability是8.9而CUDA 11.8官方支持的最高compute capability是8.6。这意味着如果你的系统里装了CUDA 11.8pip install vllm会尝试编译一个针对compute_86的kernel自然失败。解决方案不是升级CUDA因为Ubuntu 22.04的nvidia-cuda-toolkit包只提供11.8而是强制vLLM使用预编译的wheel包。我们发现vllm的PyPI页面上有针对不同CUDA版本和平台的wheel文件。我们下载了vllm-0.4.2cu118-cp310-cp310-manylinux_2_28_x86_64.whl注意cu118后缀然后pip install ./vllm-0.4.2cu118-cp310-cp310-manylinux_2_28_x86_64.whl。这个wheel包是vLLM官方用CUDA 11.8编译的但它内部的kernel是用--generate-code archcompute_80,codesm_80 --generate-code archcompute_86,codesm_86 --generate-code archcompute_89,codesm_89指令编译的完美支持L4。这个细节vllm文档只字未提但却是能否在主流云服务器上顺利部署的生命线。我们为此建立了一个sgg-env-checklist.md里面明确列出L4卡 → 必须用cu118wheelA100卡 → 必须用cu118或cu121T4卡 → 必须用cu111。Python版本也必须严格匹配cp310代表Python 3.10用错版本wheel包会直接拒绝安装。环境不是“配好了就行”它是整个工程落地的第一道、也是最不可妥协的门槛。4. 实操过程与核心环节实现从零开始搭建SGG服务的完整流水线4.1 环境准备与依赖安装一份可直接复制粘贴的Shell脚本以下是我们SGG项目在Ubuntu 22.04上的标准环境初始化脚本经过21台不同配置服务器的验证成功率100%。它规避了所有常见的坑包括apt源、pip源、CUDA驱动冲突等。#!/bin/bash # sgg-env-setup.sh set -e echo 步骤1更新系统与安装基础依赖 sudo apt update sudo apt upgrade -y sudo apt install -y python3.10 python3.10-venv python3.10-dev build-essential libssl-dev libffi-dev echo 步骤2配置Python 3.10为默认python sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.10 1 sudo update-alternatives --config python # 手动选择python3.10 echo 步骤3创建并激活虚拟环境 python3.10 -m venv /opt/sgg-env source /opt/sgg-env/bin/activate pip install --upgrade pip echo 步骤4安装CUDA 11.8兼容的PyTorch # 注意此命令会自动下载并安装适配CUDA 11.8的torch和torchaudio pip3 install torch2.1.0cu118 torchaudio2.1.0cu118 --extra-index-url https://download.pytorch.org/whl/cu118 echo 步骤5安装vLLM预编译WheelL4专用 # 下载地址https://pypi.org/project/vllm/#files选择cu118版本 wget https://files.pythonhosted.org/packages/3c/1b/.../vllm-0.4.2cu118-cp310-cp310-manylinux_2_28_x86_64.whl pip install ./vllm-0.4.2cu118-cp310-cp310-manylinux_2_28_x86_64.whl echo 步骤6安装其他必要依赖 pip install fastapi uvicorn prometheus-client redis echo 步骤7验证安装 python -c import torch; print(PyTorch版本:, torch.__version__); print(CUDA可用:, torch.cuda.is_available()) python -c from vllm import LLM; print(vLLM导入成功) echo 环境准备完成请执行 source /opt/sgg-env/bin/activate 激活环境 这个脚本的关键在于它不依赖系统自带的nvidia-cuda-toolkit而是让PyTorch和vLLM各自携带所需的CUDA运行时库libcudart.so从根本上避免了系统CUDA版本与框架需求的冲突。我们曾试过用apt install nvidia-cuda-toolkit结果导致PyTorch的CUDA版本与vLLM的CUDA版本打架调试了整整两天。这份脚本是我们用血泪换来的“最小可行环境”。4.2 LoRA微调全流程从数据准备到权重导出的逐行注释SGG的微调数据并非网上爬取的通用语料而是我们业务中真实的1278条客服对话每条都包含“用户问题-客服回复-用户满意度评分1-5星”三元组。我们只选取评分≥4星的对话确保数据质量。微调脚本的核心是train_sgg_lora.py以下是关键片段及其深度注释# train_sgg_lora.py from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer from peft import LoraConfig, get_peft_model import torch # 1. 加载基础模型必须使用vLLM兼容的模型 # 我们选用的是meta-llama/Llama-2-7b-hf但注意vLLM 0.4.2要求模型必须有config.json和pytorch_model.bin # 不能是safetensors格式。因此我们先用transformers的convert_checkpoint_to_safetensors.py脚本转换。 model_name /data/models/llama-2-7b-hf tokenizer AutoTokenizer.from_pretrained(model_name) model AutoModelForCausalLM.from_pretrained( model_name, torch_dtypetorch.float16, # 必须是float16vLLM不支持bf16 device_mapauto # 让transformers自动分配到GPU ) # 2. LoRA配置这里的target_modules是vLLM的层名不是HuggingFace的 lora_config LoraConfig( r8, # rank我们实测8是L4卡的甜点值 lora_alpha16, # alpha通常设为2*r target_modules[qkv_proj, o_proj, gate_up_proj, down_proj], # 关键见3.1节 lora_dropout0.05, biasnone, task_typeCAUSAL_LM ) # 3. 应用LoRA此时model已经是peft模型 model get_peft_model(model, lora_config) model.print_trainable_parameters() # 输出trainable params: 4,194,304 || all params: 6,739,224,576 || trainable%: 0.0622 # 4. 数据预处理重点在于padding和truncation策略 def preprocess_function(examples): # 将对话拼接为用户{question}\n客服{answer}格式 texts [f用户{q}\n客服{a} for q, a in zip(examples[question], examples[answer])] # tokenizer会自动添加bos/eos token tokenized tokenizer( texts, truncationTrue, max_length2048, # 必须≤vLLM的--max-model-len否则加载失败 paddingmax_length, # 使用max_length填充保证batch内长度一致 return_tensorspt ) # labels必须与input_ids相同这是因果语言建模的要求 tokenized[labels] tokenized[input_ids].clone() # 将padding token的label设为-100使其在loss计算中被忽略 tokenized[labels][tokenized[labels] tokenizer.pad_token_id] -100 return tokenized # 5. 训练参数关键在于per_device_train_batch_size和gradient_accumulation_steps training_args TrainingArguments( output_dir/data/sgg-lora-output, per_device_train_batch_size4, # L4卡的极限再大就OOM gradient_accumulation_steps8, # 用梯度累积模拟更大的batch_size learning_rate2e-4, num_train_epochs3, save_steps100, logging_steps10, fp16True, # 必须开启L4不支持bf16 report_tonone, # 关闭wandb等减少干扰 # 最重要的一点disable_tqdmTrue关闭进度条防止jupyter notebook中日志混乱 disable_tqdmTrue ) trainer Trainer( modelmodel, argstraining_args, train_datasettokenized_dataset, data_collatorlambda x: x # 因为我们已经padding好了不需要collator ) trainer.train() # 6. 权重导出必须用merge_and_unload生成vLLM可读的格式 model model.merge_and_unload() # 将LoRA权重合并回base model model.save_pretrained(/data/sgg-merged-model) # 保存为标准transformers格式 tokenizer.save_pretrained(/data/sgg-merged-model)这个流程的每一个参数都经过了在L4卡上的实测。per_device_train_batch_size4是L4的硬性上限gradient_accumulation_steps8是为了达到等效batch_size32以稳定训练max_length2048是vLLM服务的--max-model-len的镜像。微调不是魔法它是一系列在硬件约束下做出的精确妥协。4.3 vLLM服务启动与API封装一个稳定、可观测的生产级服务SGG的vLLM服务不是简单地python -m vllm.entrypoints.api_server而是一个完整的、可运维的服务单元。我们将其打包为systemd服务并封装了健康检查和指标暴露。# /etc/systemd/system/sgg-vllm.service [Unit] DescriptionSGG vLLM Inference Service Afternetwork.target [Service] Typesimple Userubuntu WorkingDirectory/opt/sgg EnvironmentPATH/opt/sgg-env/bin:/usr/local/bin:/usr/bin:/bin # 启动命令关键参数已加注释 ExecStart/opt/sgg-env/bin/python -m vllm.entrypoints.api_server \ --model /data/sgg-merged-model \ # 微调后的合并模型 --tensor-parallel-size 1 \ # L4单卡 --max-num-seqs 384 \ # 经过测算的最优值 --max-model-len 2048 \ # 与训练时max_length一致 --gpu-memory-utilization 0.85 \ # 显存安全水位 --enforce-eager \ # 禁用CUDA Graph避免L4上偶发的graph capture失败 --port 8000 \ # API端口 --host 0.0.0.0 \ # 监听所有IP --enable-chunked-prefill \ # 解决PCIe瓶颈 --max-num-batched-tokens 2048 \ # 控制prefill阶段的token总数 --disable-log-requests \ # 关闭请求日志避免I/O瓶颈 --disable-log-stats \ # 关闭统计日志由Prometheus统一采集 Restartalways RestartSec10 StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target启动服务后我们通过一个轻量级的FastAPI应用封装vLLM的API并加入业务逻辑# api_server.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel import httpx import asyncio app FastAPI(titleSGG AI Service) # 使用httpx.AsyncClient进行异步HTTP调用避免阻塞 vllm_client httpx.AsyncClient(base_urlhttp://localhost:8000) class ChatRequest(BaseModel): messages: list[dict] # [{role: user, content: 你好}] temperature: float 0.7 app.post(/v1/chat/completions) async def chat_completions(request: ChatRequest): try: # 将FastAPI的request转换为vLLM期望的格式 vllm_payload { prompt: request.messages[-1][content], # 简化处理只取最后一条 temperature: request.temperature, max_tokens: 512, stream: False } # 调用vLLM API response await vllm_client.post(/generate, jsonvllm_payload, timeout30.0) response.raise_for_status() result response.json() # 将vLLM的response格式转换为OpenAI兼容格式 return { id: sgg- result[request_id], choices: [{message: {role: assistant, content: result[text]}}], usage: {prompt_tokens: result[prompt_len], completion_tokens: result[output_len]} } except httpx.HTTPStatusError as e: raise HTTPException(status_codee.response.status_code, detaile.response.text) except asyncio.TimeoutError: raise HTTPException(status_code408, detailRequest timeout) app.get(/health) async def health_check(): # 对vLLM的/generate端点做健康检查 try: response await vllm_client.post(/generate, json{prompt: test, max_tokens: 1}, timeout5.0) return {status: healthy, vllm_status: response.status_code} except Exception as e: return {status: unhealthy, error: str(e)}这个API服务不仅提供了标准的OpenAI兼容接口更重要的是它通过/health端点将vLLM的底层健康状态向上游如Nginx、K8s暴露实现了真正的服务可观测性。这才是工程落地的终点。5. 常见问题与排查技巧实录来自142天线上运维的“血泪清单”5.1 典型问题速查表快速定位与解决问题现象可能原因排查命令解决方案服务启动失败报错CUDA out of memory--gpu-memory-utilization设置过高或--max-num-seqs过大nvidia-smi查看显存总量cat /var/log/syslog | grep vllm看详细错误降低utilization至0.8或减小max-num-seqs参考3.2节计算公式API返回500 Internal Server Error日志显示RuntimeError: Expected all tensors to be on the same deviceLoRA微调时用了torch.bfloat16但vLLM不支持python -c import torch; print(torch.cuda.get_arch_list())确认GPU架构微调时强制torch_dtypetorch.float16见4.2节QPS极低nvidia-smi dmon -s u -d 1显示rx_util持续100%未开启--enable-chunked-prefill导致PCIe带宽打满nvidia-smi dmon -s u -d 1在启动命令中加入--enable-chunked-prefill --max-num-batched-tokens 2048模型输出乱码或重复如用户你好\n客服你好你好你好LoRA权重未正确加载或target_modules名称错误vllm日志中搜索Loading LoRA adapter确认是否成功用sgg-lora-checker.py验证target_modules见3.1节服务运行一段时间后nvidia-smi显示GPU利用率99%但QPS为0请求队列积压--max-num-seqs设置过小curl http://localhost:8000/stats查看num_requests_waiting启用动态队列控制器sgg-queue-adaptor或增大max-num-seqs这张表是我们142天运维中高频问题的结晶。它不追求全面只解决那些让你抓狂、让你凌晨三点还在服务器前刷新日志的“真问题”。5.2 独家避坑技巧那些只能靠经验才能get的点提示vLLM的--max-model-len不是“模型能处理的最长文本”而是“模型权重中position embedding的最大索引”。如果你的base model是Llama-2-7b其config.json里max_position_embeddings是4096那么--max-model-len就不能超过4096。但我们训练时用了max_length2048所以这里设2048是安全的。但如果未来你想支持更长上下文必须先用transformers的resize_token_embeddings方法扩展position embedding再重新微调否则vLLM会直接报错Position index out of range。注意不要在vLLM服务中启用--enable-prefix-caching。这个功能听起来很美能缓存prefill结果加速后续相同prompt的响应。但在我们的测试中它在L4上会导致显存泄漏服务运行24小时后显存占用从2GB缓慢爬升到10GB最终OOM。原因在于L4的显存管理器对prefix cache的block回收不够及时。我们已向vLLM社区提交issue目前的解决方案是禁用此功能用更激进的--max-num-seqs和--max-num-batched-tokens来控制内存。实操心得vllm的/generateAPI返回的text字段是模型生成的完整文本包括了你输入的prompt。例如你post{prompt: 用户你好}返回的text可能是用户你好\n客服您好有什么可以帮您。如果你只需要“客服”的回复部分必须用tokenizer对text进行后处理切掉prompt部分。我们为此写了一个sgg-postprocessor.py它能智能识别用户和客服的分隔符精准提取回复。这个细节决定了你的前端展示是否干净也决定了你能否将输出直接喂给下游的语音合成服务。避坑提醒pip install vllm安装的wheel包其CUDA版本是固定的。如果你的服务器上同时装了CUDA 11.8和CUDA 12.1pip install会优先使用系统PATH中第一个找到的nvcc。我们曾因此在一个装了CUDA 12.1的服务器上pip install vllm成功了但运行时报错undefined symbol: __cudaPopCallConfiguration。解决方案是在安装前用export PATH/usr/local/cuda-11.8/bin:$PATH临时切换CUDA版本再执行pip install。这个环境变量的切换是很多自动化部署脚本失败的根源。6. SGG项目的延伸思考当“双重范式”成为一种工作习惯SGG项目结束了但它的影响远未停止。它没有教会我们一个
返回列表