▍PrivateGPT¶
Запуск локального PrivateGPT в Docker Swarm¶
Вводная часть¶
Для запуска PrivateGPT
нам понадобится:
Директория с моделями:
/docker/data/private-gpt/models
Итак, приступим. Склонируем репозиторий:
┌─( root@swarm-manager1 ) - ( 23 files, ) - ( ~/src )
└─> git clone https://github.com/imartinez/privateGPT.git
Cloning into 'privateGPT'...
remote: Enumerating objects: 1510, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 1510 (delta 2), reused 15 (delta 0), pack-reused 1487
Receiving objects: 100% (1510/1510), 1.69 MiB | 4.10 MiB/s, done.
Resolving deltas: 100% (822/822), done.
Переходим в директорию:
и создаём файл Dockerfile c таким кодом:### IMPORTANT, THIS IMAGE CAN ONLY BE RUN IN LINUX DOCKER
### You will run into a segfault in mac
FROM python:3.11.6-slim-bookworm as base
# Install poetry
RUN pip install pipx
RUN python3 -m pipx ensurepath
RUN pipx install poetry
ENV PATH="/root/.local/bin:$PATH"
ENV PATH=".venv/bin/:$PATH"
# Dependencies to build llama-cpp
RUN apt update && apt install -y \
libopenblas-dev\
ninja-build\
build-essential\
pkg-config\
wget
# https://python-poetry.org/docs/configuration/#virtualenvsin-project
ENV POETRY_VIRTUALENVS_IN_PROJECT=true
FROM base as dependencies
WORKDIR /home/worker/app
COPY pyproject.toml poetry.lock ./
RUN poetry install --with local
RUN poetry install --with ui
FROM base as app
RUN pip install pipx
ENV PYTHONUNBUFFERED=1
ENV PORT=8080
EXPOSE 8080
# Prepare a non-root user
RUN adduser worker
WORKDIR /home/worker/app
RUN mkdir local_data; chown worker local_data
RUN mkdir models; chown worker models
COPY --chown=worker --from=dependencies /home/worker/app/.venv/ .venv
COPY --chown=worker private_gpt/ private_gpt
COPY --chown=worker fern/ fern
COPY --chown=worker *.yaml *.md ./
COPY --chown=worker scripts/ scripts
ENV PYTHONPATH="$PYTHONPATH:/private_gpt/"
USER worker
ENV PATH="/home/worker/.local/bin:$PATH"
COPY pyproject.toml poetry.lock ./
RUN pipx install poetry
ENTRYPOINT python -m private_gpt
Изменим файл settings.yaml, добавив следующий параметр:
Сборка контейнера¶
Возможные ошибки и их решение¶
Приведу несоклько примеров ошибок, с которыми пришлось столнуться. Например, если после сборки попробовать запустить котейнер, то можем увидеть:
10:03:37.474 [INFO ] httpx - HTTP Request: POST http://qdrant:6333/collections/make_this_parameterizable_per_api_call/points/search "HTTP/1.1 404 Not Found"
Traceback (most recent call last):
File "/home/worker/app/.venv/lib/python3.11/site-packages/gradio/queueing.py", line 495, in call_prediction
output = await route_utils.call_process_api(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
qdrant_client.http.exceptions.UnexpectedResponse: Unexpected Response: 404 (Not Found)
Raw response content:
b'{"status":{"error":"Not found: Collection `make_this_parameterizable_per_api_call` doesn\'t exist!"},"time":0.000071683}'
Как видим в qdrant не создана коллекция с именем make_this_parameterizable_per_api_call
. Ну что же, создаём:
root@f13b7f90a63c:/# curl -X PUT 'http://qdrant:6333/collections/make_this_parameterizable_per_api_call' \
-H 'Content-Type: application/json' \
--data-raw '{
"vectors": {
"size": 384,
"distance": "Dot"
}
}'
{"result":true,"status":"ok","time":1.054573524}
Столкнулся ещё с такой ошибкой:
13:45:34.751 [INFO ] private_gpt.settings.settings_loader - Starting application with profiles=['default', 'docker']
There was a problem when trying to write in your cache folder (/nonexistent/.cache/huggingface/hub). You should set the environment variable TRANSFORMERS_CACHE to a writable directory.
13:45:40.220 [WARNING ] matplotlib - Matplotlib created a temporary cache directory at /tmp/matplotlib-ji4jk7xx because the default path (/nonexistent/.config/matplotlib) is not a writable directory; it is highly recommended to set the MPLCONFIGDIR environment variable to a writable directory, in particular to speed up the import of Matplotlib and to better support multiprocessing.
13:45:40.564 [INFO ] matplotlib.font_manager - generated new fontManager
13:45:41.699 [INFO ] private_gpt.components.llm.llm_component - Initializing the LLM in mode=local
Traceback (most recent call last):
File "/home/worker/app/.venv/lib/python3.11/site-packages/injector/__init__.py", line 798, in get
return self._context[key]
~~~~~~~~~~~~~^^^^^
KeyError: <class 'private_gpt.ui.ui.PrivateGptUi'>
...
File "/home/worker/app/.venv/lib/python3.11/site-packages/llama_index/llms/llama_cpp.py", line 119, in __init__
raise ValueError(
ValueError: Provided model path does not exist. Please check the path or provide a model_url to download.
Если я правильно понял, то необходимо до запуска самого PrivateGPT скачать нужные модели. Можно скачать вручную в директорию /docker/data/private-gpt/models
:
wget "https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.2-GGUF/resolve/main/mistral-7b-instruct-v0.2.Q4_K_M.gguf?download=true" -O mistral-7b-instruct-v0.2.Q4_K_M.gguf
или лучше запустить скрипт, который автоматически скачает все необходимые файлы, именно для этого пришлось править файл Dockerfile:
Для начала зайдём внутрь контейнера и выполним ряд команд:
┌─( root@swarm-worker1 ) - ( 24 files, ) - ( ~/src/privateGPT )
└─> docker run --entrypoint "" -it --rm -v /docker/data/private-gpt/models:/home/worker/app/models enlr/gpt bash
worker@b21f9c89e085:~/app$ source .venv/bin/activate
(private-gpt-py3.11) worker@b21f9c89e085:~/app$ poetry run python scripts/setup
06:56:48.092 [INFO ] private_gpt.settings.settings_loader - Starting application with profiles=['default']
Downloading embedding BAAI/bge-small-en-v1.5
README.md: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 94.8k/94.8k [00:00<00:00, 9.51MB/s]
.gitattributes: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.52k/1.52k [00:00<00:00, 14.4MB/s]
config_sentence_transformers.json: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 124/124 [00:00<00:00, 1.53MB/s]
modules.json: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 349/349 [00:00<00:00, 3.80MB/s]
config.json: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 743/743 [00:00<00:00, 5.55MB/s]
1_Pooling/config.json: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 190/190 [00:00<00:00, 1.42MB/s]
special_tokens_map.json: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 125/125 [00:00<00:00, 813kB/s]
tokenizer_config.json: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 366/366 [00:00<00:00, 4.24MB/s]
sentence_bert_config.json: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 52.0/52.0 [00:00<00:00, 315kB/s]
vocab.txt: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 232k/232k [00:00<00:00, 1.71MB/s]
tokenizer.json: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 711k/711k [00:00<00:00, 1.75MB/s]
pytorch_model.bin: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 134M/134M [00:21<00:00, 6.14MB/s]
model.onnx: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 133M/133M [00:33<00:00, 3.97MB/s]
model.safetensors: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 133M/133M [00:33<00:00, 3.96MB/s]
Fetching 14 files: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 14/14 [00:34<00:00, 2.45s/it]
Embedding model downloaded!█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 133M/133M [00:33<00:00, 5.58MB/s]
Downloading LLM model-q4_K.gguf
model-q4_K.gguf: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4.37G/4.37G [06:16<00:00, 11.6MB/s]
LLM model downloaded!
Downloading tokenizer mistralai/Mistral-7B-Instruct-v0.2
tokenizer_config.json: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.46k/1.46k [00:00<00:00, 14.5MB/s]
tokenizer.model: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 493k/493k [00:00<00:00, 5.66MB/s]
tokenizer.json: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.80M/1.80M [00:00<00:00, 5.94MB/s]
special_tokens_map.json: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 72.0/72.0 [00:00<00:00, 576kB/s]
Tokenizer downloaded!
Setup done
Можно уже запустить GPT c моделями, указанными по умолчанию, но можно немного изменить файл settings.yaml и задать русскую модель сайгу изменив переменные llm_hf_repo_id
и llm_hf_model_file
:
local:
prompt_style: "mistral"
llm_hf_repo_id: IlyaGusev/saiga_mistral_7b_gguf
llm_hf_model_file: model-q4_K.gguf
embedding_hf_model_name: BAAI/bge-small-en-v1.5
Пример docker-compose¶
version: '3.9'
services:
private-gpt:
image: registry.enlr.ru/privategpt:latest
environment:
- PORT=8080
- PGPT_PROFILES=docker
- PGPT_MODE=local
- PGPT_HF_REPO_ID=IlyaGusev/saiga_mistral_7b_gguf
- PGPT_HF_MODEL_FILE=model-q4_K.gguf
- PGPT_EMBEDDING_HF_MODEL_NAME=BAAI/bge-small-en-v1.5
volumes:
- /docker/data/private-gpt/local_data:/home/worker/app/local_data
- /docker/data/private-gpt/models:/home/worker/app/models
networks:
- traefik-public
deploy:
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
update_config:
parallelism: 1
monitor: 60s
failure_action: rollback
order: stop-first
placement:
constraints: [node.role == worker]
labels:
- "traefik.enable=true"
- "traefik.http.routers.gpt.rule=Host(`gpt.example.ru`)"
- "traefik.http.routers.gpt.entrypoints=https"
- "traefik.http.routers.gpt.tls=true"
- "traefik.http.routers.gpt.middlewares=WhitelistHome"
- "traefik.http.services.gpt.loadbalancer.server.port=8080"
qdrant:
image: qdrant/qdrant:latest
volumes:
- /docker/data/qdrant:/qdrant/storage
networks:
- traefik-public
deploy:
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
update_config:
parallelism: 1
monitor: 60s
failure_action: rollback
order: stop-first
placement:
constraints: [node.role == worker]
labels:
- "traefik.enable=true"
- "traefik.http.routers.qdrant.rule=Host(`qdrant.example.ru`)"
- "traefik.http.routers.qdrant.entrypoints=https"
- "traefik.http.routers.qdrant.tls=true"
- "traefik.http.routers.qdrant.middlewares=WhitelistHome"
- "traefik.http.services.qdrant.loadbalancer.server.port=6333"
networks:
traefik-public:
external: true
Запуск¶
Теперь если перейти по адресу https://gpt.example.ru мы должны увидеть страницу чата:
На этом всё!
Теперь можно играться с разными моделями с сайта huggingface.
Полезные ссылки¶
Адрес дашборда qdrant: