在Ubuntu24.04搭建VLLM, SGLang 和 LangChain环境
[!NOTE] 概述
整片文章是笔者的回忆(白天忙碌了一天,晚上进行的总结),所以有些地方的描述可能有误差,本文更多的是大体方向问题,细节步骤不是本文的重点,见谅 !!!
如何安装Ubuntu 24.04
- 制作启动
U盘
,作者使用的是rufus.exe
工具 - 下载
Ubuntu24.04
的ISO
镜像 - 使用
rufus.exe
工具刷入Ubuntu22.04.iso
文件 - 插入服务起(或电脑)进入
BISO
页面,选择U盘
作为启动项 - 选择
Try and Install Ubuntu
(可能记忆有错误,第一个位置的选项,整片文章是笔者的回忆,所以有些名词可能有误差,见谅) - 无脑
Next
,知道出现分区页面 (这里是重点,一定仔细!!!)- 选择手动分区(
Manual partitioning
,选择带有Manual
的选项) - 先点击左下角选择启动盘
- 点击后会出现
/et/uefi
区,这个分区不要手动修改 - 然后对下面的内容进行分区,如果你是新手,那么建议
- 分区
swap
大小和你的运存一样就行,如果你的运存512G
或者更大,那就无看你情况想给多大,有这么大分区的人,也不是新手,自己肯定也懂 - 剩下的都给
/
就可以了 - 这是最简单的,但是绝对不是最有效的
- 哦对了,分区格式为
/ext4
如果你没有特殊需求
- 分区
- 选择手动分区(
- 无脑Next,等待安装完成
- 选择重启电脑,然后在退出页面中,先
拔出U盘
,后敲击键盘Enter
按键
如何安装SGLang
安装NVIDIA驱动(重点,不要出错)
- 首先明确官方推荐的是
530
版本,但是Ubutnu24.04
的内核对它不兼容!!!(血泪的教训,卡了我上一上午) - 直接安装最新版的便可以
- 命令:
sudo apt update && sudo apt upgrade
获取并更新安装包的命令,装完系统后记得执行 sudo ubuntu-drivers autoinstall
, 自动安装适配的版本- 优势:无脑安装,兼容性好
- 劣势:如果你的项目不支持这个驱动,嘿嘿,那你就惨了
- 小幸运:
SGLang
支持 - 时间:
autoinstall
的安装版本会随时间变化,截止到2025-5-3
安装版本为575.51.03
- 命令:
安装CUDA,(一步一坑的噩梦)
SGLang
推荐的CUDA版本是CUDA 12.1
版本,但是实测CUDA 12.9
也可以- 多CUDA环境配置方法
- 从官网下载
.run
包
# CUDA 12.9 wget https://developer.download.nvidia.com/compute/cuda/12.9.0/local_installers/cuda_12.9.0_575.51.03_linux.run sudo sh cuda_12.9.0_575.51.03_linux.run # CUDA 12.1 wget https://developer.download.nvidia.com/compute/cuda/12.1.0/local_installers/cuda_12.1.0_530.30.02_linux.run sudo sh cuda_12.1.0_530.30.02_linux.run
sudo bash cuda_xxx_linux.run
来进行安装- 如果报错
cat /path/log.conf
,出错会告诉你在哪看日志sudo apt insnstall gcc, g++
#下载对应版本sudo bash cuda_xxx_linux.run --override
- 安装选项 重点
- 输入
accept
- 然后不要选择安装驱动
- 进入
Option
高级选项,选择下载路径,不要使用Sympol
链接
- 输入
- 修改
export
,source .bashrc
和将下面自动切换脚本写入.bashrc
文件
# ~/.bashrc 或 ~/.zshrc # 定义一个切换 CUDA 版本的函数 switch_cuda() { local desired_version=$1 # 假设你的 CUDA 版本都安装在 /usr/local/cuda-X.Y 格式的路径下 local cuda_path="/usr/local/cuda-${desired_version}" # 检查目标版本的 CUDA 目录是否存在 if [ -d "${cuda_path}" ]; then export CUDA_HOME="${cuda_path}" export CUDA_PATH="${CUDA_HOME}" # 有些应用可能也看这个变量 # 从 PATH 和 LD_LIBRARY_PATH 中移除旧的 CUDA 路径 (避免冲突) # (注意: 这个移除逻辑可能需要根据你的具体 PATH/LD_LIBRARY_PATH 结构调整) export PATH=$(echo "$PATH" | awk -v RS=':' -v ORS=':' '!/\/usr\/local\/cuda-[0-9.]+\/bin/' | sed 's/:$//') export LD_LIBRARY_PATH=$(echo "$LD_LIBRARY_PATH" | awk -v RS=':' -v ORS=':' '!/\/usr\/local\/cuda-[0-9.]+\/lib64/' | sed 's/:$//') # 添加新版本的 CUDA 路径 export PATH="${CUDA_HOME}/bin:${PATH}" # 确保 LD_LIBRARY_PATH 非空再加冒号 if [ -z "$LD_LIBRARY_PATH" ]; then export LD_LIBRARY_PATH="${CUDA_HOME}/lib64" else export LD_LIBRARY_PATH="${CUDA_HOME}/lib64:${LD_LIBRARY_PATH}" fi echo "Switched to CUDA ${desired_version}" echo "CUDA_HOME is now: ${CUDA_HOME}" echo "Verifying nvcc version:" nvcc --version else echo "Error: CUDA version ${desired_version} not found at ${cuda_path}" fi } # (可选) 在启动时设置一个默认的 CUDA 版本 # switch_cuda 12.1 # (可选) 创建别名方便切换 alias cuda12.1="switch_cuda 12.1" # 假设你的 "12.9" 版本在 /usr/local/cuda-12.9 (请根据实际情况修改) alias cuda12.9="switch_cuda 12.9"
- 使用
nvcc --version
和nvidia-smi
检查配置是否完成
- 从官网下载
[!NOTE] 吐槽
真的是一步一坑,最难是的是如果CUDA装错了,想要卸载很容易将驱动也破坏,还要考虑兼容性,Kernel, NVIDIA Driver 和 CUDA三者之间的兼容真的逆天,而且Ubuntu24.04的资料不多,很多都是笔者自己一种搭配一种搭配尝试出来的,哎
安装Miniconda/anaconda
- 去官网下载相关安装包Anaconda Linux版本
- 处理多人共享conda环境
sudo bash Anaconda3-2024.10-1-Linux-x86_64.sh
- 不要使用默认位置,要手动输入修改安装路径为
/opt/anaconda3
- 注意最后初始化要选则
no
sudo chmod -R u=rwX,go=rX /opt/miniconda3
修改权限
- 不要使用默认位置,要手动输入修改安装路径为
- 将
export PATH=/opt/anaconda3/bin:$PATH
写入~/.bashrc
文件 - 执行
conda init
[!IMPORTANT]赋予用户conda权限
为每一个需要运行conda的用户都执行3,4
步骤
安装SGLang步骤
conda create --name SGL python=3.10
pip install sglang
需要下载魔塔社区- AI模型安装
import torch from modelscope import AutoModelForCausalLM, AutoTokenizer from sglang import srt from transformers import BitsAndBytesConfig # 从 ModelScope 加载模型 model = AutoModelForCausalLM.from_pretrained( "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B", device_map="auto", trust_remote_code=True, quantization_config=quant_config ) tokenizer = AutoTokenizer.from_pretrained( "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B", trust_remote_code=True )
- 运行模型
python -m sglang.launch_server \ --model-path /home/bera/.cache/modelscope/hub/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B \ --port 30000 \ --log-level info \ --trust-remote-code \ --mem-fraction-static 0.7
- 测试代码
click.py
# 1.py (修改后) import sglang as sgl import torch # 如果需要清理缓存或者进行其他 PyTorch 操作 # 如果需要处理 Chat Template,保留这个 import from transformers import AutoTokenizer # --- 配置 --- # 模型文件所在的本地路径 (从之前的 ModelScope 下载日志中获取或者从魔塔社区进行下载) local_model_path = "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B" # *** 明确指定 SGLang 后端服务器的地址 (可选,如果使用默认 localhost:30000) *** sgl.set_default_backend(sgl.RuntimeEndpoint("http://localhost:30000")) # 定义 SGLang 推理函数 @sgl.function def generate_poem(s, user_prompt_text): # 当 SGLang 服务器已经加载了模型时,客户端的 @sgl.function # 【通常不需要】再写 s += sgl.Model(...) 了。 # 服务器会使用它启动时加载的模型。 # --- 处理 Chat/Instruction 模型的 Prompt --- # 这一步仍然非常重要,需要根据模型要求格式化输入 # 假设模型是 Qwen 类型,可能需要类似格式 (需要用实际的 Tokenizer 验证) try: # 仍然可以从本地加载 Tokenizer 来格式化 Prompt tokenizer = AutoTokenizer.from_pretrained(local_model_path, trust_remote_code=True) # 确保 tokenizer 加载也信任远程代码 # 构建适合模型的聊天或指令 Prompt (以 Qwen 为例,具体需核对) # messages = [{"role": "user", "content": user_prompt_text}] # formatted_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) # 临时代替:直接使用,效果可能不好,请替换为正确的格式化 formatted_prompt = f"User: {user_prompt_text}\nAssistant:" s += formatted_prompt # 将格式化后的 Prompt 传递给后端 except Exception as e: print(f"警告:无法格式化 Prompt 或加载 Tokenizer: {e}") print("将尝试使用原始 Prompt,效果可能不佳。") s += user_prompt_text # 备用 # 使用 sgl.gen 进行生成 s += sgl.gen( "poem_text", # 结果变量名 max_tokens=512, temperature=0.7 ) # 准备用户输入 prompt = "你好,请用中文写一首关于夏天的诗。" # 运行 SGLang 函数 (连接到正在运行的服务器) # 函数的参数名需要匹配 @sgl.function 定义中的参数名 (除了第一个 's') state = generate_poem.run(user_prompt_text=prompt) # 打印结果 print(state["poem_text"]) # (可选)清理缓存 # torch.cuda.empty_cache()
- 如果报错
conda update -c conda-forge libstdcxx-ng --force-reinstall
安装VLLM
[!Note] 注意
We’ll assume you want to use a common 7B Deepseek model available on Hugging Face, likedeepseek-ai/DeepSeek-Coder-V2-Lite-Instruct
(optimized for coding) ordeepseek-ai/DeepSeek-LLM-7B-Chat
(optimized for general chat). I’ll usedeepseek-ai/DeepSeek-Coder-V2-Lite-Instruct
in the examples, but you can substitute the other name if you prefer.
前提条件:
- NVIDIA GPU: 需配备NVIDIA GPU并确保显存充足(7B参数模型通常需要至少16GB显存,具体需求可能因量化和配置而异,请参考VLLM官方文档)。
- CUDA工具包: 安装兼容的NVIDIA驱动程序和CUDA工具包。VLLM安装通常会自动处理PyPI中的CUDA依赖,但需预先安装基础驱动。
- Python: 需Python 3.8或更新版本。
- pip: 确保已安装Python包管理工具。
分步操作指南:
步骤1:安装VLLM
打开终端或命令提示符,通过pip安装VLLM:
pip install vllm
- 注意: 安装时间可能较长,若预编译的CUDA内核不适用当前GPU架构,将自动进行本地编译。
步骤2:安装LangChain和OpenAI客户端库
安装LangChain核心库和OpenAI客户端库,VLLM的OpenAI兼容API需要这些依赖:
pip install langchain langchain-openai
步骤3:启动VLLM服务端
在新终端窗口运行以下命令启动服务端(保持此窗口常驻):
python -m vllm.entrypoints.openai.api_server \
--model deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct \
--trust-remote-code # Deepseek模型可能需要此参数
# 可选:多GPU环境下添加--tensor-parallel-size N(N=GPU数量)
# 可选:指定端口--port 8000(默认为8000)
- 说明:
- 服务端将自动从Hugging Face Hub下载模型(本地无缓存时)
- 成功启动后终端会显示
INFO: Uvicorn running on http://0.0.0.0:8000
,API端点位于http://localhost:8000/v1
步骤4:配置LangChain连接VLLM服务端
在Python脚本中配置LangChain指向本地VLLM服务:
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
MODEL_NAME = "deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct" # 需与VLLM加载的模型ID一致
llm = ChatOpenAI(
model=MODEL_NAME,
openai_api_key="dummy", # VLLM无需鉴权,此处为占位符
openai_api_base="http://localhost:8000/v1", # 本地API端点
max_tokens=100, # 可选:设置生成最大token数
temperature=0.7, # 可选:控制生成随机性
)
# 构建对话消息
messages = [
SystemMessage(content="你是一个基于DeepSeek Coder V2 Lite的编程助手"),
HumanMessage(content="编写一个计算阶乘的Python函数"),
]
try:
response = llm.invoke(messages)
print("模型响应:\n", response.content)
except Exception as e:
print(f"请求异常: {e}\n请检查VLLM服务是否正常运行")
步骤5:执行LangChain代码
- 将代码保存为
test_vllm.py
- 确保VLLM服务端正在运行
- 新终端中执行:
python test_vllm.py
观察终端输出,VLLM服务端窗口将显示请求处理日志。
故障排查与技巧:
- 显存不足: 运行
nvidia-smi
检查显存占用。可尝试更小模型、启用量化(参考VLLM文档)或升级硬件。 - 模型名称不匹配: 确保
ChatOpenAI
的model
参数与VLLM启动命令中的模型ID完全一致。 - 端口冲突: 若修改默认端口(如8000),需同步更新
openai_api_base
中的端口号。 - 远程代码信任: 部分模型需添加
--trust-remote-code
参数才能加载。 - 依赖版本: 确认CUDA版本与Python版本符合VLLM最新要求(参考官方文档)。
- 跨设备访问: 若服务端运行于其他设备,需将
localhost
替换为实际IP地址,并确保防火墙放行。
附加说明:
- 实际使用时建议将服务端部署为后台进程(如使用
nohup
或systemd
) - 生产环境需考虑启用API鉴权、设置速率限制等安全措施
- 可通过
--quantization awq
等参数启用量化压缩,降低显存占用
安装LangChain
conda create --name langchain python=3.10
pip install langchain langchain-openai
- 通用测试脚本
from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, SystemMessage, AIMessage import os import langchain # Import for debugging # --- Setup llm as before --- sglang_api_base_url = "http://localhost:30000/v1" # <----- change url to adaptive your back url sglang_model_name = "DeepSeep-R1-Distill-Qwen-1.5" # <------ chage model name to adaptive your model_name sglang_api_key = "" llm = ChatOpenAI( model=sglang_model_name, openai_api_key=sglang_api_key, openai_api_base=sglang_api_base_url, temperature=0.7, max_tokens=512, ) # --- Conversation Example --- # Start with system message and first question conversation_history = [ SystemMessage(content="You are a helpful assistant discussing machine learning."), HumanMessage(content="What is quantization?") ] print("--- Sending first question ---") first_response = llm.invoke(conversation_history) print("First response:", first_response.content) # Add the first response (as AIMessage) and the second question (as HumanMessage) conversation_history.append(AIMessage(content=first_response.content)) # Add AI's answer conversation_history.append(HumanMessage(content="How does it help make models faster on edge devices?")) # Add user's second question print("\n--- Sending second question (with context) ---") # The 'conversation_history' now contains the system prompt, Q1, A1, and Q2 second_response = llm.invoke(conversation_history) print("Second response:", second_response.content) # The 'conversation_history' list now contains: # [SystemMessage, HumanMessage (Q1), AIMessage (A1), HumanMessage (Q2)] # When invoking for the second response, LangChain sends this entire list.