Найти в Дзене

Как запустить локально LLM?

Как
только я решил свои мысли записывать на какой-то внешний носитель, так я
сразу начал осознавать проблему поиска в этих записях. Для дальнейшей
работы нам необходимо дать несколько определений: Некоторые особенности семантического поиска: Эмбеддинги (embeddings) —
это численные представления текста или слов в виде векторов, которые
отражают их семантическое значение. В контексте семантического поиска,
эмбеддинги используются для преобразования текста запроса и документов в
числовой формат, который можно анализировать на наличие схожести по
смыслу. Морфологический поиск —
часть процесса семантического поиска, связанный с обработкой
лингвистических особенностей запросов. Чаще всего системы предлагают
поиск по вхождению символов в текст документов, а это может вести к не
полным результатам поиска. Проблема становится актуальной, когда
документов много, как и текста в них. На данный момент у меня в базе
знаний более 2800 файлов и искать становится все сложнее и сложнее. 3
Оглавление

Цель и необходимость

Как
только я решил свои мысли записывать на какой-то внешний носитель, так я
сразу начал осознавать проблему поиска в этих записях. Для дальнейшей
работы нам необходимо дать несколько определений:

  1. Морфологический поиск связан
    с учётом различных форм слов при поиске. Есть два подхода: либо
    учитывать все формы, либо вырезать корень слова и искать только по нему.
    Второй способ называется stemming, он отличается быстротой и простотой,
    но имеет проблемы со словами, у которых корень изменчив (бег — бежать,
    расти — прирост, лев — львица).
  2. Семантический поиск
    способ и технология поиска информации, основанная на использовании
    контекстного (смыслового) значения запрашиваемых фраз, вместо словарных
    значений отдельных слов или выражений при поисковом запросе.

Некоторые особенности семантического поиска:

  • Учитывается
    информационный контекст, местонахождение и цель поиска пользователя,
    словесные вариации, синонимы, обобщённые и специализированные запросы,
    язык запроса и другие особенности.
  • Цель такого поиска — определять особенности пользователя и предоставлять ему наиболее релевантные результаты.
  • Ряд
    крупных поисковых систем, например Google и Bing, используют некоторые
    элементы семантического поиска, но не являются таковыми в чистом виде.

Эмбеддинги (embeddings)
это численные представления текста или слов в виде векторов, которые
отражают их семантическое значение. В контексте семантического поиска,
эмбеддинги используются для преобразования текста запроса и документов в
числовой формат, который можно анализировать на наличие схожести по
смыслу.

  • Семантический
    поиск использует эмбеддинги для сравнения семантической близости между
    запросом пользователя и документами. Если эмбеддинг запроса близок к
    эмбеддингу документа, это означает, что оба имеют схожий смысл.
  • Эмбеддинги
    позволяют системе понимать не только отдельные слова, но и контекст,
    что делает семантический поиск более умным и точным по сравнению с
    традиционными методами поиска (морфологический поиск).

Морфологический поиск
часть процесса семантического поиска, связанный с обработкой
лингвистических особенностей запросов. Чаще всего системы предлагают
поиск по вхождению символов в текст документов, а это может вести к не
полным результатам поиска. Проблема становится актуальной, когда
документов много, как и текста в них. На данный момент у меня в базе
знаний более 2800 файлов и искать становится все сложнее и сложнее.

3. LLM (Large Language Model) — это一большая языковая модель,
обученная на огромных объемах текстовых данных. Эти модели способны
понимать и генерировать человеческий язык, а также выполнять задачи
обработки естественного языка (NLP — Natural Language Processing).

С
течением времени при работе с базой знаний начал замечать, что все чаше
и чаще хочется обобщать большие тексты. Конечно же я начал некоторые
тексты выгружать в публичные LLM. Но параллельно начал осознавать, что
такие выгрузки нарушают приватность моей жизни.

В итоге какие проблемы имеем:

  1. Поиск и возможность искать по смыслу.
  2. Приватность
    производимых операций. Лично для меня выходом стало появление LLM,
    которые возможно свободно скачивать, устанавливать и использовать в
    своих проектах.

В статье будем устанавливать LLM на сервер и давать возможность нашим сервисам взаимодействовать с ней.

Virtual machine

Я использую VM в
proxmox, в настройках которой уже добавления видеокарта. Установку
драйверов NVIDIA не описываю, так как это описано в соответствующей
статье (см. ссылки в самом низу). Помимо этого необходимо процессор VM
указать как host. Важным в данном контексте для нас является поддержка 
Advanced Vector Extensions (AVX), так как позволяет быстрее обрабатывать данные в рамках GPU. Проверить поддержку AVX возможно (вывод должен быть как в тексте ниже):

$ grep avx /proc/cpuinfo
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm rep_good nopl cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw perfctr_core ssbd ibpb vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr virt_ssbd arat npt lbrv nrip_save tsc_scale vmcb_clean flushbyasid pausefilter pfthreshold v_vmsave_vmload vgif overflow_recov succor arch_capabilities
.....

doсker-compose

Для начала нам необходимо нарисовать архитектуру docker-compose.yml сервисов и работу с нашим оборудованием, чтобы понимать на верхнем уровне:

-2

Диаграмма показывает основные компоненты системы:

  1. Сервис anythingllm зависит от:Сервиса ollama Сервиса postgres-vector
  2. Для корректной работы сервисов ollama требуется:Установленный NVIDIA Container Toolkit на хостовой машине
    Драйверы NVIDIA и GPU-устройства
  3. Система предоставляет API для взаимодействия с LLM (от ollama) и веб-интерфейс (от anythingllm).

Теперь мы готовы создать файлы для запуска docker-compose.yml:

  1. touch .env docker-compose.yml Dockerfile init-vector.sql
  2. mkdir config_{anythingllm,ollama,postgres}

Содержимое .env (переменные с секретами):

POSTGRES_DB=<your database name>
POSTGRES_USER=<your vector user>
POSTGRES_PASSWORD=<your postgres password>
POSTGRES_PORT=<tyour postgres port>
JWT_SECRET=<your jwt secret>

Содержимое Dockerfile (сборка postgres с расширением pgvector):

FROM postgres:17-bookworm

# Устанавливаем необходимые пакеты
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
git \
postgresql-server-dev-17 \
&& rm -rf /var/lib/apt/lists/*

# Клонируем и устанавливаем pgvector
RUN git clone https://github.com/pgvector/pgvector.git \
&& cd pgvector \
&& make DISABLE_JIT=1 \
&& make install \
&& cd .. \
&& rm -rf pgvector

# Создаем директорию для скриптов инициализации
RUN mkdir -p /docker-entrypoint-initdb.d

# Копируем скрипт инициализации
COPY init-vector.sql /docker-entrypoint-initdb.d/

EXPOSE 5432

CMD ["postgres"]

Содержимое init-vector.sql (установка расширения pgvector):

-- Включаем расширение pgvector
CREATE EXTENSION IF NOT EXISTS vector;

-- Настройки для лучшей производительности векторов
ALTER SYSTEM SET shared_preload_libraries = 'vector';
ALTER SYSTEM SET max_connections = 200;
ALTER SYSTEM SET shared_buffers = '1GB';
ALTER SYSTEM SET work_mem = '50MB';

-- Перезагрузите конфигурацию
SELECT pg_reload_conf();

Содержимое docker-compose.yml:

services:
ollama:
image: ollama/ollama:latest
container_name: llm
restart: unless-stopped
volumes:
- ./config_ollama:/root
environment:
- OLLAMA_KEEP_ALIVE=60 minutes
- OLLAMA_FLASH_ATTENTION=1
- OLLAMA_HOST=0.0.0.0
- LD_LIBRARY_PATH=/opt/cuda/lib64:/usr/local/cuda/lib64
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=all
- CUDADIR=/usr/local/cuda
- CUDA_HOME=/usr/local/cuda
- FORCE_CUDA=1
- CUDA_VISIBLE_DEVICES=0
- CUDA_LAUNCH_BLOCKING=1
ports:
- "11434:11434"
devices:
- /dev/dri:/dev/dri
- /dev/nvidiactl:/dev/nvidiactl
- /dev/nvidia0:/dev/nvidia0
runtime: nvidia

postgres-vector:
build:
context: .
dockerfile: Dockerfile
container_name: postgres-vector
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./config_postgres:/var/lib/postgresql/data
env_file: .env
ports:
- "${POSTGRES_PORT:-5432}:5432"

anythingllm:
image: mintplexlabs/anythingllm:latest
container_name: anythingllm
restart: unless-stopped
ports:
- "3001:3001"
environment:
- STORAGE_DIR=/app/server/storage
- LLM_PROVIDER=ollama
- OLLAMA_BASE_PATH=http://ollama:11434
- OLLAMA_MODEL_PREF=deepseek-r1:14b
- OLLAMA_MODEL_TOKEN_LIMIT=4096
- EMBEDDING_ENGINE=ollama
- EMBEDDING_BASE_PATH=http://ollama:11434
- EMBEDDING_MODEL_PREF=bge-m3:latest
- EMBEDDING_MODEL_MAX_CHUNK_LENGTH=8192
- JWT_SECRET=${JWT_SECRET}
# Аудио функции
- WHISPER_PROVIDER=local
- TTS_PROVIDER=native
# Векторная база данных - PostgreSQL с pgvector
- VECTOR_DB=pgvector
- PGVECTOR_CONNECTION_STRING=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres-vector:${POSTGRES_PORT}/${POSTGRES_DB}
- PGVECTOR_TABLE_NAME=vector_embeddings
- PGVECTOR_EMBEDDING_DIMENSION=1536
# Дополнительные настройки PostgreSQL
- PGVECTOR_SSL=false
- PGVECTOR_SCHEMA=public
env_file: .env
volumes:
- ./config_anythingllm:/app/server/storage
depends_on:
- ollama
- postgres-vector

Сначала запускаем только ollama: docker-compose up -d ollama и проверяем какие модели доступны: docker exec -it llm ollama list. В самом начале должен быть пустой список, но мы можем это легко исправить:

-3

Дополнительный вариант модели с большей производительностью.

Умный дом

Для интеграции с умным домом (Homeassistant):

  • Настройки -> Устройства и службы -> Добавить интеграцию -> Набираем ollama -> Вставляем адрес http://<your local API>:11434 -> Выбираем модель qwen3:8b (downloaded).
  • Настройки
    -> Голосовые ассистенты -> Ассистенты -> Добавить ассистента
    -> Добавляем Ollama Conversation и делаем его предпочитаемым через 3
    точки возле названия ассистента.
-4
  • Настройки
    -> Голосовые ассистенты -> Доступ к объектам ->
    Проверяем/Смотрим какие у нас есть возможности, при необходимости
    редактируем. Теперь через значок диалога в верхнем правом углу основного
    интерфейса вызываем диалог и проверяем как все работает.
-5

Остался 1 шаг до своего голосового ассистента :)

Браузер

Для работы с локальной LLM прямо в браузере (Mozilla Firefox) устанавливаем page-assist. Идем в настройки расширения и добавляем адрес для работы: Начинаем чат:

-6
-7
-8

IDE

Лично я использую VSCode, поэтому все настройки далее будут для этой IDE. Устанавливаем расширение Continue :

code --install-extension Continue.continue

Вставляю настройки ~/.continue/config.yaml:

name: Local Assistant
version: 1.0.0
schema: v1
models:
- name: deepseek-r1:8b
provider: openai
model: deepseek-r1:8b
apiBase: http://<your address>/v1
apiKey: "sk-no-key-needed"
temperature: 0.7
maxTokens: 2048
contextWindow: 8192
forcePrompt: true

- name: deepseek-r1:14b
provider: openai
model: deepseek-r1:14b
apiBase: http://<your address>/v1
apiKey: "sk-no-key-needed"
temperature: 0.7
maxTokens: 2048
contextWindow: 8192
forcePrompt: true
assistant:
- name: deepseek-r1:8b
models:
- deepseek
- name: deepseek-r1:14b
models:
- deepseek
allowAnonymousTelemetry: false
tabAutocompleteModel:
title: deepseek-r1:8b
provider: openai
model: deepseek-r1:8b
context:
- provider: code
- provider: docs
- provider: diff
- provider: terminal
- provider: problems
- provider: folder
- provider: codebase

Проверяем работу:

-9

Obsidian

Ищем в community plugins Copilot. Действия:

  1. Переходим
    в модели и добавляем модель в «Chat Models» (deepseek-r1:8b и
    deepseek-r1:14b) и «Embedding Models» (ollama_bge-m3). Сам процесс
    добавления моделей похож на добавление моделей в другие сервисы выше,
    поэтому этот процесс не описываю.
  2. Как
    выяснилось моя база знаний не подходит для локальной векторризации,
    которая существует в этом плагине. Там важно, что в случае деление на
    партиции (для больших объемов данных), необходимо чтобы первая партиция
    была не более 500 мб. При различных комбинациях у меня не удалось этого
    достичь. В итоге я пользуюсь внутри obsidian только чатом и возможностью
    добавлять в контекст конкретную заметку. Для ускорения работы
    сделал/изменил шаблоны промтов, которые вызываются через /.
-10

Anythingllm

После запуска docker-compose зайти в интерфейс возможно через http://<your_ip>:3001.
Все необходимые настройки уже должны примениться. Первым делом нам
необходимо проиндексировать нашу базу знаний и перевести ее в векторный
вид, чтобы далее возможно было проводить с этими векторами операции.
Нюанс индексирования таков, что файлы добавляются только и это
становится причиной появления «дубликатов». Для себя делаю выгрузки
только с новыми файлами или измененными, далее планирую удалять все
файлы и заново их индексировать, чтобы актуализировать информацию. Сама
операция индексации заняла у меня несколько дней.

-11
-12

Open
settings -> Agent Skills -> Добавляем навыки. Рекомендую добавить
web-search (минимум), чтобы наша LLM могла искать информацию в
Интернете.

-13

Теперь можем искать в нашей базе знаний и при необходимости в интернете.

Итог

Теперь
у нас во всех наших инструментах есть доступ к локальной модели LLM и
мы можем это использовать в своей работе и жизни в частности.

Ссылки:

  1. Как запустить свою базу знаний?
  2. Как запустить прокси-сервер для сервисов?
  3. Как установить Docker?
  4. Как установить Proxmox?
  5. Как запустить прокси-сервер для сервисов?
  6. Как установить драйвера NVIDIA в Linux?
  7. Как запустить сервис по управлению умным домом?