base-llm 4.1 模型部署实战 FastApi/docker-compose

FastAPI是基于Starlette和Pydantic构建。pydantic能利用Python的类型提示(Type Hints)实现自动的数据校验和转换,极大减少了繁琐的参数验证代码。 能根据代码自动生成API文档,方便开发者直接在页面上调试。 同时充分利用了async/await等现代python特性。

一、 环境准备

FastAPI[all]包含了FastAPI本身以及运行它需要的ASGI服务器uvicorn

pip install `fastapi[all]`

uvicorn 是一个高性能的 ASGI (Asynchronous Server Gateway Interface) 服务器,用于在生产环境中运行 FastAPI 应用。ASGI 是现代 Python Web 框架用于与 Web 服务器通信的标准接口

二、 Ner任务部署

# code/C14/NerPredictor/main.py

import logging
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from predict import NerPredictor

# --- 全局配置 ---
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

MODEL_DIR = "./checkpoints"

# --- 数据模型定义 ---
class NerRequest(BaseModel):
    text: str

# --- FastAPI 应用初始化 ---
app = FastAPI(
    title="命名实体识别 API",
    description="部署 NER 模型",
    version="1.0.0"
)

# --- 模型加载 ---
@app.on_event("startup")
async def startup_event():
    logger.info(f"开始加载模型,来源: {MODEL_DIR}")
    app.state.predictor = NerPredictor(model_dir=MODEL_DIR)
    logger.info("模型加载成功!")


# --- API 路由定义 ---
@app.post("/predict/ner")
async def predict_ner(request: NerRequest):
    """
    接收文本,返回命名实体识别结果。
    """
    try:
        text = request.text.strip()
        if not text:
            raise HTTPException(status_code=400, detail="输入文本不能为空")

        logger.info(f"接收到NER请求: '{text}'")
        
        predictor = app.state.predictor
        entities = predictor.predict(text)

        logger.info(f"识别出实体: {entities}")

        return {
            "code": 0,
            "message": "成功",
            "data": {
                "text": text,
                "entities": entities
            }
        }
    except Exception as e:
        logger.error(f"NER预测时发生错误: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {e}")

@app.get("/health")
async def health_check():
    return {"status": "ok"}

@app.get("/")
async def root():
    return {"message": "欢迎使用命名实体识别 (NER) API"}

其中:

  1. 请求参数使用的Pydantic的BaseModel -> NerRequest
  2. 模型加载: 在app.on_event('startup')时候启动, 初始化时会将NerPredictor实例存储在app.state对象里。这种方式模型只会在启动时创建一次。

@app.on_event("startup") 启动前置方法; app.on_event("shutdown") 服务结束后置方法

  1. 实体识别api使用的是post方法, 参数是NerRequest.。异常通过HttpException抛出
  2. 服务健康状态 @app.get("/health")
  3. 根服务 @app.get("/health")
  4. /docs 是FastAPI自动生成的交互式API文档

三、启动与测试

启动,使用的uvicorn

uvicorn main:app --reload

测试,使用curl 测试

curl -X POST "http://127.0.0.1:8000/predict/ner" -H "Content-Type: application/json" -d "{\"text\":\"患者自述发热、咳嗽,伴有轻微头痛。\"}"

JSON响应:

{
    "code": 0,
    "message": "成功",
    "data": {
        "text": "患者自述发热、咳嗽,伴有轻微头痛。",
        "entities": [
            {
                "text": "发热",
                "type": "sym",
                "start": 4,
                "end": 6
            },
            {
                "text": "咳嗽",
                "type": "sym",
                "start": 7,
                "end": 9
            },
            {
                "text": "头",
                "type": "bod",
                "start": 14,
                "end": 15
            }
        ]
    }
}

四、生产服务

开发时使用的是uvicorn main:app --reload来启动服务。默认只允许本地访问。如果希望云服务器上测试,比如制定--host 0.0.0.0,这种方式不够健壮。

Gunicorn 是一个成熟的 Python HTTP 服务器和进程管理器,通过 -k uvicorn.workers.UvicornWorker 可以以多进程方式托管 FastAPI 这样的 ASGI 应用。Uvicorn 负责异步处理请求,Gunicorn 负责监听端口、管理 worker 进程和日志,这是常见且稳定的生产部署组合。

gunicorn -w 3 -k uvicorn.workers.UvicornWorker main:app --bind 0.0.0.0:8000
  • -w 3: 启动 3 个工作进程(worker)。Gunicorn 官方文档推荐的通用设置是 2 * CPU核心数 + 1。但对于我们所使用的 UvicornWorker 这种异步工作进程,由于其高效的并发处理能力,通常设置为 CPU核心数 + 1 就足够了。我们的服务器是 2 核 CPU,所以设置为 3。
  • -k uvicorn.workers.UvicornWorker: 指定 Gunicorn 使用 Uvicorn 的工作进程类,以便支持 asyncio。
  • --bind 0.0.0.0:8000: 绑定到 0.0.0.0,意味着服务器将监听所有可用的 IP 地址上的 8000 端口,从而允许外网访问。

使用Systemd 持久化服务

gunicorn 命令, 一旦关闭SSH连接,服务就会中断。为了让我们的API服务能在后台长期运行,并在服务器重启后能自动启动,需要使用systemd --- Linux系统标准服务器管理。

(1)创建systemd 服务文件

sudo nano /etc/systemd/system/ner_api.service

(2) 编写服务配置

[Unit]
Description=NER API Service
After=network.target

[Service]
User=root
Group=root
# 工作目录
WorkingDirectory=/root/ner_deployment
# 启动服务的完整命令,务必使用gunicorn绝对路径
ExecStart=/root/ner_deployment/.venv/bin/gunicorn -w 3 -k uvicorn.workers.UvicornWorker main:app --bind 0.0.0.0:8000
# 失败自动重启
Restart=on-failure
RestartSec=5s
# 定义服务安装信息,表示服务器以多用户模式启动时启用
[Install]
WantedBy=multi-user.target

(3)管理服务

  • 重新加载systemd配置:
sudo systemctl daemon-reload
  • 启动服务
sudo systemctl start ner_api
  • 设置开机自启
sudo systemctl enable ner_api
  • 查看服务状态
sudo systemctl status ner_api
  • 查看实时日志
sudo journalctl -u ner_api -f

五、DockerCompose部署

5.1 Docker与DockerCompose

Docker 让软件变成集装箱模式,允许开发者将应用及其所有依赖项打包到一个轻量级、可抑制的容器中。

这个容器可以再任何安装了Docker的机器上运行。

DockerCompose 是通过定义和运行多容器Docker应用的工具,通过docker-compose.yaml的YAML文件,可以配置应用所需的所有服务。
docker compose up -> 启动了所有服务

5.2 NER 服务的镜像相关文件

Dockerfile

# ner_deployment/Dockerfile

# 基础镜像
FROM python:3.10-slim

#  关闭python输出缓冲、禁止生成.pyc文件,让容器中的日志更适合调试、镜像内容更简洁
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1

# 容器内荣做目录
WORKDIR /app

# 设置 PyPI 镜像源,加速依赖安装
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
RUN pip install --no-cache-dir uv

# 文件复制到镜像
COPY pyproject.toml ./

RUN uv pip install --system --no-cache .

COPY . .

# 用户
RUN useradd -m appuser
USER appuser

# 暴露端口
EXPOSE 8000

CMD ["gunicorn", "-w", "3", "-k", "uvicorn.workers.UvicornWorker", "main:app", "--bind", "0.0.0.0:8000"]

docker-compose.yml

# ner_deployment/docker-compose.yml

services:
  ner_api:
    build: .
    container_name: ner_api_service
    ports:
      - "8000:8000"
    restart: always

5.3 部署与测试

启动

sudo docker compose up --build -d

查看日志

# 查看正在运行的容器
sudo docker compose ps

# 实时查看服务日志
sudo docker compose logs -f

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容