使用 Ollama 和 FastAPI 部署 Python AI 应用

一个在本地构建的 AI 项目,可能使用了像 Ollama 和 FastAPI 这样的库,最终需要部署到服务器上,以便更广泛地访问或实现可靠的 24/7 运行。本文档详细介绍了将这样一个基于 Python 的 AI 应用部署到 Linux 服务器上的常用流程。

这些步骤涵盖了连接到服务器、设置环境、管理 AI 模型、手动运行应用程序进行测试,以及使用 systemd 将其配置为可靠的后台服务运行。虽然这些步骤是基于部署使用 FastAPI 和 Ollama 的应用程序,但许多步骤展示了适用于各种 Python Web 应用程序的标准部署实践。

目录

通过 SSH 连接到服务器

安全外壳协议 (SSH) 是安全连接和管理远程 Linux 服务器的标准方法。这通常是部署过程的第一步。

生成 SSH 密钥

如果本地计算机上还没有 SSH 密钥对,需要生成一个:一个私钥(安全地保存在本地)和一个公钥(与服务器共享)。

在本地计算机上使用 ssh-keygen 命令。通常遵循提示即可。常见的算法是 ED25519 (推荐) 或 RSA。

# 使用 ED25519 的示例
ssh-keygen -t ed25519 -C "your_email@example.com"
# 遵循提示保存密钥(默认位置通常即可)并可选地设置密码。

在 macOS 和 Linux 上,密钥通常存储在 ~/.ssh 目录中。使用 ls -al ~/.ssh 检查:

  • id_ed25519id_rsa私钥切勿共享此文件。
  • id_ed25519.pubid_rsa.pub公钥。复制此文件的内容以提供给服务器管理员,或者如果有权限,自行添加。

服务器管理员(或自己)必须将公钥文件 (id_xxx.pub) 的内容添加到服务器上目标用户主目录下的 ~/.ssh/authorized_keys 文件中。

连接

一旦公钥在服务器上被授权,就可以使用私钥建立连接:

ssh -i /path/to/your/private_key your_server_username@your_server_hostname_or_ip -p <ssh_port_number>

替换占位符:

  • /path/to/your/private_key私钥文件的路径(例如 ~/.ssh/id_ed25519)。
  • your_server_username:远程服务器上的用户名。
  • your_server_hostname_or_ip:服务器的 IP 地址或可解析的主机名。
  • <ssh_port_number>:服务器上配置的 SSH 端口号(默认为 22,但为了安全通常会更改)。

注意: 替换像 <ssh_port_number> 这样的占位符时,省略尖括号 (<>)。

首次连接到新服务器时,可能会看到一个主机真实性警告。这是正常的。输入 yes 继续。

The authenticity of host '...' can't be established.
... key fingerprint is ...
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes

克隆项目代码库

成功建立 SSH 连接后,使用 Git 将项目代码获取到服务器上:

git clone your_repository_link
# 示例: git clone git@github.com:your_username/your_project.git
# 或: git clone https://github.com/your_username/your_project.git

your_repository_link 替换为 Git 代码库的实际 SSH 或 HTTPS URL。进入克隆的目录:cd your_project_directory_name

环境配置

在服务器上设置必要的软件和环境。

1. 安装 uv (可选但推荐)

uv 是一个用 Rust 编写的非常快速的 Python 包安装器和解析器。与标准的 pip 相比,使用它可以显著加快依赖项的安装速度。它是可选的,但推荐使用。

# 使用 pip 安装 uv (确保 pip 可用)
pip install uv
# 或者,遵循官方说明:https://github.com/astral-sh/uv#installation

验证安装:

uv --version
# 预期输出类似于:uv x.y.z

2. 安装 Python

确保安装了兼容的 Python 版本(例如 3.8-3.11,检查项目的需求)。

如果安装了 uv,可以用它来安装 Python:

# 将 3.x.y 替换为目标版本 (例如 3.10.13)
uv python install 3.x.y
# 遵循任何关于 PATH 更新的提示。

或者,使用系统的包管理器(在 Linux 服务器上很常见):

# Debian/Ubuntu 示例
sudo apt update
sudo apt install python3 python3-pip python3-venv

# CentOS/RHEL 示例
sudo yum update
sudo yum install python3 python3-pip

确认 Python 安装:

python3 --version
# 或有时只是 'python --version',取决于 PATH 设置

3. 安装软件依赖

项目依赖

项目应该有一个 requirements.txt 文件,列出了 Python 依赖项。导航到项目目录并安装它们。

使用 uv (如果已安装,推荐):

cd /path/to/your/project
uv pip install -r requirements.txt

或者,使用 pip (通常在虚拟环境中):

cd /path/to/your/project
# 最佳实践:首先创建并激活虚拟环境
# python3 -m venv venv
# source venv/bin/activate
pip install -r requirements.txt
# 或 pip3 install -r requirements.txt

注意:/path/to/your/project 替换为克隆的代码库的实际绝对路径。

安装并运行 Ollama

Ollama 允许在本地运行大型语言模型。使用官方脚本在 Linux 服务器上安装它:

curl -fsSL https://ollama.com/install.sh | sh

为了初步测试,可以在后台手动启动 Ollama 服务器:

ollama serve & # '&' 符号使其仅在当前会话的后台运行。

注意: 对于生产环境,Ollama 应设置为 systemd 服务(安装脚本通常会自动执行此操作,请使用 systemctl status ollama 检查)。运行 ollama serve & 主要用于临时测试。

验证 Ollama 是否正在运行且可访问(此命令与正在运行的服务器通信):

ollama list
# 应该显示一个空列表或任何已经拉取/创建的模型。
# 如果命令挂起或出错,则表示服务器未正确运行。

4. 准备 AI 模型

将所需的 AI 模型文件放在服务器上。选择一个合适的位置,例如项目内的 models/ 子目录或中央的 /opt/ai-models/ 目录。

上传/下载模型
  • 从 Hugging Face: 使用 huggingface-cli (通过 pip install huggingface_hub 安装):

    huggingface-cli download repo_id path/to/model.gguf --local-dir /path/on/server/models --local-dir-use-symlinks False
    # 替换 repo_id, 模型文件名, 和 /path/on/server/models
  • 从本地机器: 使用 scp (Secure Copy) 从开发机器上传模型。替换占位符。

    # 上传单个模型文件
    scp /path/on/local/model.gguf your_server_username@your_server_hostname_or_ip:/path/on/server/models/
    
    # 上传一个 Ollama Modelfile
    scp /path/on/local/Modelfile your_server_username@your_server_hostname_or_ip:/path/on/server/models/
    
    # 递归上传整个目录
    scp -r /path/on/local/model_directory your_server_username@your_server_hostname_or_ip:/path/on/server/models/
  • GGUF 合并: 如果模型被分割(例如 model-part-1.gguf, model-part-2.gguf),可能需要 llama.cpp 工具来合并它们。克隆 llama.cpp,构建它,并使用 llama-gguf-split:

    # 假设 llama.cpp 工具已构建并在 PATH 中
    # llama-gguf-split --merge input_part_*.gguf output_merged.gguf
使用 Ollama 构建模型

要将本地模型文件(如 .gguf)与 Ollama 集成或定义自定义模型参数,请使用 Modelfile。在服务器上,与基础模型文件 (.gguf) 相同的目录中创建这个文本文件(例如 MyModelModelfile)。

Modelfile 内容示例:

# 使用 FROM 指向同一目录中的模型文件的相对路径
FROM ./local_model_filename.gguf

# (可选) 定义提示模板
TEMPLATE """[INST] {{ .Prompt }} [/INST]"""

# (可选) 设置参数
PARAMETER temperature 0.7
PARAMETER top_k 40
# 根据需要添加其他参数 (停止序列等)

使用选定的名称构建模型并将其注册到 Ollama:

# 确保 Ollama 服务器正在运行
# 导航到包含 Modelfile 和 .gguf 文件的目录
cd /path/on/server/models/

# 创建模型 - 使用一个描述性的名称
ollama create your_custom_model_name -f MyModelModelfile

验证模型是否可用:ollama list

5. 设置环境变量

应用程序通常需要配置,如 API 密钥或数据库 URL,最好通过环境变量来管理。一种常见的方法是在项目的根目录中使用 .env 文件。切勿将 .env 文件提交到 Git。.env 添加到.gitignore 文件中。

在项目根目录 (/path/to/your/project/.env) 创建一个名为 .env 的文件,内容类似这样(替换占位符值):

# 示例 .env 文件内容
# 框架密钥 (生成一个强随机密钥)
SECRET_KEY=your_strong_random_secret_key

# 外部服务的 API 密钥
EXTERNAL_API_KEY=your_external_api_key_value

# 如果应用需要显式连接 Ollama 的配置
OLLAMA_HOST=http://127.0.0.1:11434

# 其他配置变量
DATABASE_URL=your_database_connection_string

Python 应用程序代码需要加载这些变量,通常使用像 python-dotenv (pip install python-dotenv) 这样的库。

6. 手动运行项目 (测试)

在设置服务之前,从终端手动运行应用程序,以确保它能正确启动和运行。

  1. 确保 Ollama 正在运行: 使用 ollama listsystemctl status ollama (如果作为服务安装) 来验证。
  2. 激活环境 (如果使用 venv): source /path/to/your/project/venv/bin/activate
  3. 启动应用程序: 导航到项目根目录。使用像 uvicorn 这样的 ASGI 服务器来运行 FastAPI。替换占位符。

    cd /path/to/your/project
    
    # 使用 uvicorn 的示例命令
    # 假设 FastAPI 应用实例在 'main.py' 中名为 'app'
    # 使用应用配置监听的端口
    uvicorn main:app --host 0.0.0.0 --port <your_app_port> --reload
    • --host 0.0.0.0:使应用可以从网络上的其他机器访问(确保防火墙规则允许 <your_app_port> 端口的流量)。
    • --port <your_app_port>:应用程序将监听的端口(例如 8000)。
    • --reload仅用于测试。 在代码更改时启用自动重新加载。对于生产部署,请移除此标志。
  4. 测试:

    • API 端点: 使用 curl、Postman 或 Insomnia 等工具发送请求(例如 curl http://your_server_hostname_or_ip:<your_app_port>/api/some_endpoint)。
    • Web UI: 通过浏览器访问 http://your_server_hostname_or_ip:<your_app_port> 上的任何 Web 界面。
    • 日志: 检查终端输出以查找错误。

使用 systemd 作为服务部署

在终端中手动运行应用程序不适合生产环境。systemd 是标准的 Linux 服务管理器,用于:

  1. 在服务器启动时自动启动应用程序。
  2. 在应用程序崩溃时自动重启。
  3. 将应用程序作为后台进程进行管理,并进行适当的日志记录。

创建服务文件

使用具有 sudo 权限的文本编辑器创建一个服务定义文件。使用描述性的名称(例如 your-app-name.service)。

sudo nano /etc/systemd/system/your-app-name.service

将以下模板粘贴到文件中。请仔细阅读注释并替换所有占位符。

[Unit]
Description=My Python AI Application Service # 服务的描述性名称
After=network.target
# 如果应用严格要求 Ollama 首先运行 (并且 Ollama 是一个 systemd 服务), 取消注释:
# Wants=ollama.service
# After=network.target ollama.service

[Service]
# !!! 安全最佳实践:切勿以 ROOT 用户身份运行 !!!
# 为应用程序创建一个专用的非 root 用户。
# 将 'your_app_user' 替换为实际的用户名。确保此用户具有
# 读取项目文件和写入必要目录 (例如日志、上传文件) 的权限。
User=your_app_user
# Group=your_app_group # 通常与用户相同,如果需要则取消注释

# 将工作目录设置为项目的根目录绝对路径
WorkingDirectory=/path/to/your/project # !!! 务必替换此绝对路径 !!!

# 启动应用程序的命令。使用可执行文件 (uvicorn, gunicorn 等) 的绝对路径。
# 查找路径: 'which uvicorn' (以 your_app_user 身份, 可能在激活 venv 后)
# 或者可能是类似: /path/to/your/project/venv/bin/uvicorn 或 /home/your_app_user/.local/bin/uvicorn
# 调整 'main:app', host, port, 和其他参数。移除 --reload!
ExecStart=/path/to/executable/uvicorn main:app --host 0.0.0.0 --port <your_app_port> --forwarded-allow-ips='*' # !!! 务必替换路径, 应用, 端口并检查参数 !!!

# 重启策略
Restart=always
RestartSec=5 # 重启前等待 5 秒

# 日志记录: 将 stdout/stderr 重定向到 systemd journal
StandardOutput=journal
StandardError=journal

# 可选: 从 .env 文件加载环境变量
# 确保路径是绝对路径。权限必须允许 'your_app_user' 读取它。
# EnvironmentFile=/path/to/your/project/.env # !!! 务必替换此绝对路径 !!!
# 注意: 此处的变量可能会覆盖系统范围或用户特定的环境设置。

[Install]
WantedBy=multi-user.target # 在正常系统启动期间启动服务

需要验证的关键占位符和设置:

  1. Description:一个清晰的名称。
  2. User/Group必须更改为一个专用的非 root 用户 (your_app_user)。确保此用户的文件/目录权限正确。
  3. WorkingDirectory:项目根目录的绝对路径
  4. ExecStart

    • uvicorn(或其他 WSGI/ASGI 服务器)可执行文件的绝对路径。如果使用虚拟环境,通常在 venv/bin/ 内。
    • main:app 必须与 Python 文件和 FastAPI/Flask 应用实例匹配。
    • <your_app_port>--host 和其他参数必须适合生产环境。移除 --reload
    • 如果位于反向代理(如 Nginx 或 Apache)之后,可能需要 --forwarded-allow-ips='*'。根据安全需要进行调整。
  5. (可选) EnvironmentFile:如果使用,指向 .env 文件的绝对路径

保存文件并退出编辑器(在 nano 中按 Ctrl+X,然后按 Y,然后按 Enter)。

启用并启动服务

使用 systemctl 管理新服务:

  1. 重新加载 systemd 配置: 使其知道新文件。

    sudo systemctl daemon-reload
  2. 启用服务: 使其在启动时自动运行。使用创建的相同文件名。

    sudo systemctl enable your-app-name.service
  3. 启动服务: 立即运行它。

    sudo systemctl start your-app-name.service
  4. 检查状态: 验证它是否正在运行。

    sudo systemctl status your-app-name.service

    查找 active (running)。如果显示 failed 或不是 active,请检查日志。

  5. 查看日志: 查看应用程序输出并排查错误。

    sudo journalctl -u your-app-name.service -f
    • -u your-app-name.service:过滤特定服务的日志。
    • -f:实时跟踪日志(类似 tail -f)。按 Ctrl+C 停止跟踪。
    • 要查看较早的日志,移除 -fsudo journalctl -u your-app-name.service --since "1 hour ago"

      AI 应用程序现在应该作为托管的后台服务运行了。

常见问题 (FAQ)

设置或运行时遇到的常见问题。

环境配置问题

  • SSH 连接/输入缓慢:

    • 原因: 网络延迟高。
    • 解决方案: 使用 -C 标志启用 SSH 压缩:

      ssh -C your_server_username@your_server_hostname_or_ip ...

运行时问题

  • 缺少环境变量: 出现类似 KeyError: 'SECRET_KEY'ValueError: Required setting X not found 的错误。

    • 原因: 应用程序需要的环境变量在其运行上下文中未定义。
    • 解决方案: 确保所需变量已设置,可以通过以下方式之一:

      • .env 文件中,并且应用程序使用 python-dotenv 加载它。
      • 或者在 systemd 服务文件中使用 Environment="VAR_NAME=value" 指令(对于许多变量不太常见)或 EnvironmentFile= 指令指向 .env 文件。验证 systemd 服务用户是否有权限读取 EnvironmentFile。更改后重新加载 (daemon-reload) 并重启服务。
  • Ollama 运行时错误: Error: llama runner process has terminated: exit status X.

    • 原因: 多种多样。可能是 Ollama 的 bug、模型所需的 RAM/VRAM 不足、模型文件损坏或不兼容。
    • 解决方案:

      • 检查 Ollama 的日志:journalctl -u ollama.service(如果作为 systemd 服务运行)。
      • Ollama GitHub Issues 中搜索具体的错误消息或退出状态码。
      • 确保服务器满足模型的资源需求。
      • 尝试不同的(可能更小的)模型来隔离问题。
      • 考虑尝试不同的 Ollama 版本(降级或升级),检查兼容性说明。
  • Ollama 响应缓慢/无响应/推理时间长:

    • 原因 1: 网络代理干扰。
      解决方案 1: 如果手动运行 Ollama 或配置其环境,尝试取消设置代理变量:unset http_proxy https_proxy NO_PROXY。对于 systemd 服务,可能需要在系统范围或服务环境设置中配置/禁用代理。
    • 原因 2: 硬件资源不足 (CPU, RAM, VRAM 如果使用 GPU)。
    • 解决方案 2: 验证模型需求与服务器规格。监控资源使用情况 (htop, nvidia-smi 如果有 GPU)。如果需要,使用更小的模型或升级硬件。
  • ollama serve 失败:端口已被占用: 出现类似 listen tcp 127.0.0.1:11434: bind: address already in use 的错误。

    • 原因: 另一个进程(很可能是另一个 Ollama 实例或配置错误的应用程序)正在使用端口 11434。
    • 解决方案: 停止冲突的进程。

      • 如果 Ollama 是一个服务:sudo systemctl stop ollama
      • 手动查找并终止:

        sudo lsof -i :11434 # 查找使用该端口的 PID
        sudo kill <PID>      # 将 <PID> 替换为找到的进程 ID
        # 或者更强制地 (谨慎使用):
        # sudo pkill ollama
        # sudo killall ollama
      • 停止冲突后,再次尝试启动服务/Ollama。

结论

部署 Python AI 应用涉及仔细的环境配置、依赖管理、模型处理和健壮的进程管理。像 uv (提高速度)、Ollama (本地模型服务)、FastAPI (提供 API) 和 systemd (可靠的服务操作) 这样的工具提供了坚实的基础。请记住,通过使用非 root 用户并通过环境变量适当地管理密钥来优先考虑安全性。通过遵循这些步骤并根据具体项目需求进行调整,可以成功部署应用程序以实现持续运行。


Mitchell_C
4 声望1 粉丝