团队小规模本地大模型服务平台搭建 - Ubuntu

实现目标和考虑因素

部署一个支持多用户同时使用、多模型运行的离线局域网大模型服务器
需要考虑以下几个关键因素:

  1. 大模型的加载和管理。使用一个基础大模型,根据实战需要创建多个专用模型,模型管理方便可靠。
  2. 并发用户和请求管理。设置管理员、用户角色,用户管理方便可靠,支持多名用户同时在线操作。
  3. 多模型同时运行与切换。多个模型可同时多人使用与切换,且能迅速响应、流畅使用。
  4. 硬件资源的优化利用。大模型服务后端支持充分利用多显卡资源。
  5. 高可用性和负载均衡。大模型服务前后端均有高可用性,前端支持负载均衡。
  6. 数据隐私与安全。全部使用离线本地平台和模型,数据保留在本地局域网内。

环境和平台配置

硬件环境

GPU: Nvidia Tesla P40 24G x2
CPU: Intel(R) Xeon(R) Gold 6226 CPU @ 2.70GHz x2
内存: 32G/DDR4-2933ER x8

系统环境

Ubuntu Server 24.04
python 3.11
astral-sh/uv

所需平台

Ollama(https://ollama.com/),为大模型管理和调用提供后端服务支持
Open-WebUI(https://docs.openwebui.com/,推荐 python 3.11 环境下通过pip或其他包管理工具安装),为大模型可视化使用和切换、用户管理提供前端服务支持

平台配置

ollama

设置环境变量

基础环境配置
# 根据实际网络情况选择是否换源
sudo cp -a /etc/apt/sources.list /etc/apt/sources.list.bak
sudo sed -i "s@http://.*archive.ubuntu.com@https://mirrors.huaweicloud.com@g" /etc/apt/sources.list
sudo sed -i "s@http://.*security.ubuntu.com@https://mirrors.huaweicloud.com@g" /etc/apt/sources.list
sudo apt update
# 安装gcc和g++
sudo apt install gcc g++
# 安装make
sudo apt install make
sudo apt install make-guile

校对一下时区和时间

安装Nvidia驱动
# 编辑黑名单配置,屏蔽开源nvidia显卡驱动,以安装官方驱动
sudo vi /etc/modprobe.d/blacklist.conf

在文件的最后添加下面两行

blacklist nouveau
options nouveau modeset=0

输入下面的命令更新并重启

sudo update-initramfs -u
sudo reboot

继续执行命令

lsmod | grep nouveau # 验证是否禁用成功,成功的话这行命令不会有输出
sudo apt-get purge nvidia* # 卸载已有的驱动

cuda工具包显卡驱动下载好后,在驱动所在目录执行

sudo chmod +x cuda_12.4.0_550.54.14_linux.run
sudo sh cuda_12.4.0_550.54.14_linux.run
# 如果上面完成后已自动安装显卡驱动,则跳过下面显卡驱动安装命令,否则手动安装如下
sudo chmod +x NVIDIA-Linux-x86_64-550.127.08.run
sudo sh NVIDIA-Linux-x86_64-550.127.08.run

设置全局环境变量

sudo vi /etc/profile.d/myenv.sh
export PATH="$PATH:/usr/local/cuda-12.4/bin"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/cuda-12.4/lib64"
export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/cuda-12.4/lib64"

重启使生效,指令nvcc -V测试
cuDNN下载好后,在所在目录执行

sudo dpkg -i cudnn-local-repo-ubuntu2404-9.6.0_1.0-1_amd64.deb
sudo cp /var/cudnn-local-repo-ubuntu2404-9.6.0/cudnn-*-keyring.gpg /usr/share/keyrings/
sudo apt-get update
sudo apt-get -y install cudnn-cuda-12
安装python
sudo apt-get install -y python3 python3-pip
pip config set global.index-url https://mirrors.huaweicloud.com/repository/pypi/simple # 换国内源
安装ollama

手动下载安装(若安装过旧版,则需先sudo rm -rf /usr/lib/ollama),在下好的tgz包所在目录执行

sudo tar -C /usr -xzf ollama-linux-amd64.tgz

添加开机自启

给Ollama创建用户和组:

sudo useradd -r -s /bin/false -U -m -d /usr/share/ollama ollama
sudo usermod -a -G ollama $(whoami)

添加服务配置

sudo vi /etc/systemd/system/ollama.service
[Unit]
Description=Ollama Service
After=network-online.target

[Service]
ExecStart=/usr/bin/ollama serve
User=ollama
Group=ollama
Restart=always
RestartSec=3
Environment="PATH=$PATH"
Environment="OLLAMA_ORIGINS=http://127.0.0.1"
Environment="OLLAMA_KEEP_ALIVE=-1"
Environment="OLLAMA_HOST=localhost:11434"
Environment="OLLAMA_DEBUG=0"
Environment="OLLAMA_NOHISTORY=1"
Environment="OLLAMA_MODELS=/usr/share/ollama/models"

[Install]
WantedBy=default.target

然后启动服务

sudo chmod 777 /etc/systemd/system/ollama.service
sudo systemctl daemon-reload
sudo systemctl enable ollama

启动Ollama

sudo systemctl start ollama
sudo systemctl status ollama

之后修改配置可直接

sudo systemctl edit ollama

修改文件夹及内所有内容权限使其他用户可写

sudo chmod -R 777 /usr/share/ollama

Ollama后端服务启动后,模型是未加载状态,当有用户调用时,会进行模型的加载过程,这个过程根据模型大小和性能不同持续时间也不同,之后模型会在内存中保持一段时间,方便用户快速调用模型,上面配置中模型在内存中保持加载的时长设置永久,即模型被调用后,永久加载于显存中直到后端服务停止或重启。按需调整配置参数,完成后重启计算机。

下载模型

根据需要下载不同大模型,可下载的大模型列表可在ollama官方网站找到,也可在本地使用已有或自制GGUF格式大模型创建。这里下载qwen2.5:14b-instruct-q8_0

ollama pull qwen2.5:14b-instruct-q8_0

后缀q8是量化参数,关于量化相关内容可网上搜索或搭建好之后问AI
如果要离线部署大模型,直接将已下载好的模型目录复制进相应目录即可,具体模型清单在ollama模型目录的manifests目录下

Open-WebUI

用uv安装python 3.11环境

设置全局环境变量

sudo vi /etc/profile.d/myenv.sh

前面PATH添加:/usr/local/uv/bin:/usr/local/uv/toolsbin,后面添加(HF_ENDPOINT、UV_INDEX_URL、UV_PYTHON_INSTALL_MIRROR根据实际网络情况设置)

export HF_ENDPOINT="https://hf-mirror.com"
export UV_INDEX_URL="https://mirrors.huaweicloud.com/repository/pypi/simple"
export UV_PYTHON_INSTALL_MIRROR="https://ghproxy.cn/https://github.com/indygreg/python-build-standalone/releases/download"
export UV_CACHE_DIR="/usr/local/uv/cache"
export UV_TOOL_DIR="/usr/local/uv/tools"
export UV_TOOL_BIN_DIR="/usr/local/uv/toolsbin"
export UV_PYTHON_INSTALL_DIR="/usr/local/uv/python"

重启使生效
安装uv
可根据实际网络环境选择自动安装还是离线安装,以下是离线安装过程
下载 https://astral.sh/uv/install.sh 得到 uv-installer.sh,下载 uv-x86_64-unknown-linux-gnu.tar.gz 到同一目录
修改 uv-installer.sh 文件,将379行if ! downloader "$_url" "$_file"; then这一段到判断结束的代码,改为

ensure cp "uv-x86_64-unknown-linux-gnu.tar.gz" "$_file"

执行命令

sudo -s
export UV_INSTALL_DIR="/usr/local/uv/bin"
chmod +x uv-installer.sh
sh uv-installer.sh

安装完毕后,重开终端,然后执行命令

uv python install 3.11
uv tool install open-webui -p 3.11

添加开机自启

给openwebui创建用户和组:

sudo useradd -r -s /bin/false -U -m -d /usr/share/openwebui openwebui
sudo usermod -a -G openwebui $(whoami)

添加服务配置(注意在这里可以更改服务端口)

sudo vi /etc/systemd/system/openwebui.service
[Unit]
Description=Open-WebUI Service
After=network-online.target

[Service]
ExecStart=/usr/local/uv/toolsbin/open-webui serve --port 8080
WorkingDirectory=/usr/share/openwebui
User=openwebui
Group=openwebui
Restart=always
RestartSec=3
Environment="PATH=$PATH"
Environment="WEBUI_NAME=OpenWebUI大模型服务平台"
Environment="AIOHTTP_CLIENT_TIMEOUT=300"
Environment="DATA_DIR=/usr/share/openwebui/data"
Environment="ENABLE_COMMUNITY_SHARING=False"
Environment="ENABLE_MESSAGE_RATING=False"
Environment="DEFAULT_LOCALE=cn"
Environment="OLLAMA_BASE_URL=http://localhost:11434"

[Install]
WantedBy=default.target

然后启动服务

sudo chmod 777 /etc/systemd/system/openwebui.service
sudo systemctl daemon-reload
sudo systemctl enable openwebui

启动Ollama

sudo systemctl start openwebui
sudo systemctl status openwebui

之后修改配置可直接

sudo systemctl edit openwebui

第一次启动会要求创建管理员账号,离线部署的邮箱部分,按程序要求后缀用“@localhost”或包含“@.字母或数字”。

若忘记了管理员账号和密码,可通过修改数据库找回

[!note] 修改管理员密码
关闭 open-webui 服务
使用在线工具生成Bcrypt密码哈希(https://www.bejson.com/encrypt/bcrpyt_encode/,Rounds为10)
找到设置的DATA_DIR目录里的 webui.db 文件,更新管理员密码
sqlite3 ./webui.db "UPDATE auth SET password='管理员密码哈希' WHERE email='admin@example.com';"

进入管理员面板,关闭竞技场匿名评价模型,创建新用户,其他按需进行设置

前端平台使用

详见Open-WebUI官方文档(https://docs.openwebui.com/)

这里说一下RAG方式怎么找中文embedding模型
默认给的embedding模型对中文不友好,需要到MTEB Leaderboard - a Hugging Face Space by mteb去看实时更新的embedding模型排行榜,选择Chinese,按实际需求选择排名靠前的即可
同时要注意模型支持的最大Tokens长度,比如Conan-embedding-v1 Max Tokens 为 512,则在Open-WebUI中设置文档语义向量模型为Conan-embedding-v1后,块参数中文本分割器的块大小要小于等于Max Tokens,块重叠为块大小的20%左右即可,比如这里可以设置块大小512、块重叠100,把pdf图像处理勾选上

前端平台数据定期备份

在备份分区盘内创建backup文件夹,创建backup_openwebui.sh进行定期备份,在当前文件夹内创建openwebui文件夹
backup_openwebui.sh:

#!/bin/bash

# 设置最大备份文件数量,超出部分自动清理旧备份
MAX_BACKUPS=1200

# 定义备份目录、文件名
basedir_backup="/mnt/data/backup/openwebui"
basedir_src="/usr/share/openwebui/data"
backup_filename_prefix="data_"
files_src=("vector_db" "webui.db" "functions" "tools")
checksum_file_src_name="webui.db"

current_date_time=$(date +"%Y%m%d%H%M%S")
backup_filename="${backup_filename_prefix}${current_date_time}.tar.gz"
checksum_file_src="${basedir_src}/${checksum_file_src_name}"
checksum_file_dst="${basedir_backup}/lastbackup_${checksum_file_src_name}.checksum"
log_file="${basedir_backup}/backup_log.txt"
backup_file="${basedir_backup}/${backup_filename}"

# 记录日志的函数
log_message() {
    local message="$1"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" >> "$log_file"
}

# 如果 checksum 文件存在,获取当前的 checksum 值
if [ -f "$checksum_file_dst" ]; then
    last_checksum=$(cat "$checksum_file_dst")
else
    last_checksum=""
fi

# 计算当前指定文件的 checksum
current_checksum=$(sha256sum "$checksum_file_src" | awk '{print $1}')

# 如果当前的 checksum 与上次的 checksum 相同,则不进行备份
if [ "$current_checksum" == "$last_checksum" ]; then
    log_message "The ${checksum_file_src_name} file has not changed. No backup needed."
    exit 0
fi

# 如果 checksum 不相同,则进行备份
log_message "The ${checksum_file_src_name} file has changed. Performing backup."

# 打包
files_src_str="" # 初始化空字符串,用于存储存在的文件或目录名
# 遍历每个文件或目录名称
for file_or_dir in "${files_src[@]}"
do
    if [ -e "$basedir_src/$file_or_dir" ]; then
        # 如果存在,则追加到 files_src_str 中
        if [ -z "$files_src_str" ]; then
            files_src_str="$file_or_dir"
        else
            files_src_str+=" $file_or_dir"
        fi
    fi
done

tar -czf "$backup_file" -C "$basedir_src" $files_src_str

log_message "Backup completed: $backup_file"

# 更新 checksum 文件
echo "$current_checksum" > "$checksum_file_dst"

log_message "Checksum ${current_checksum} updated in $checksum_file_dst"

# 获取当前备份目录中所有 .tar.gz 文件的数量
backup_count=$(find "$basedir_backup" -type f -name "${backup_filename_prefix}*.tar.gz" | wc -l)

# 如果备份文件数大于 MAX_BACKUPS,考虑删除旧的备份
if [ "$backup_count" -gt "$MAX_BACKUPS" ]; then
    # 获取需要删除的文件数量
    files_to_delete=$((backup_count - MAX_BACKUPS))

    # 删除超过数量的旧备份文件
    find "$basedir_backup" -type f -name "${backup_filename_prefix}*.tar.gz" | sort | head -n "$files_to_delete" | while read -r file; do
        rm -f "$file"
        log_message "Deleted old backup: ${file}, max backups: ${MAX_BACKUPS}"
    done
fi

赋予脚本执行权限(为安全要确保其他用户不具有编辑权限)

sudo chmod +x backup_openwebui.sh

当前用户编辑crontab文件

crontab -e

添加如下内容,如每周六凌晨2点备份

0 2 * * 6 /mnt/data/backup/backup_openwebui.sh
posted @   hvker  阅读(439)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~
点击右上角即可分享
微信分享提示