From a247d4fb3f4b865f99d47bfa61cb7508ec2dc0da Mon Sep 17 00:00:00 2001 From: He4eT Date: Wed, 17 Jan 2024 13:51:05 +0100 Subject: [PATCH] posts: selfhosted_llm: linting --- src/pages/posts/2024/selfhosted_llm.md | 144 ++++++++++++------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/pages/posts/2024/selfhosted_llm.md b/src/pages/posts/2024/selfhosted_llm.md index 43af51d..718616f 100644 --- a/src/pages/posts/2024/selfhosted_llm.md +++ b/src/pages/posts/2024/selfhosted_llm.md @@ -15,18 +15,18 @@ description: 'Персональная LLM в docker-контейнере на # Your Own Private Large Language Models -С одной стороны, я сомневаюсь, что Большие Языковые Модели (LLM) смогут однажды эволюционировать в AGI. С другой - я по-настоящему впечатлён тем, что щепотка статистики справляется с написанием текстов лучше меня. +С одной стороны, я сомневаюсь, что Большие Языковые Модели (LLM) смогут однажды эволюционировать в AGI. С другой — я по-настоящему впечатлён тем, что щепотка статистики справляется с написанием текстов лучше меня. -В любом случае, джина обратно в бутылку уже не вернуть, и все те письма в различные организации, которые я не хочу писать сам, будут теперь написаны месивом из байтиков. +В любом случае, джина обратно в бутылку уже не вернуть, и все те письма в различные организации, которые я не хочу писать сам, будут теперь написаны месивом из байтиков. -Действительно пугает меня в этой ситуации только то, что флагманом новой эры почему-то стала компания OpenAI, которая, вопреки названию, совершенно не Open. -Множество компаний и людей вписали их продукты в свою рутину и не страшатся такой неподконтрольной зависимости. +Действительно пугает меня в этой ситуации только то, что флагманом новой эры почему-то стала компания OpenAI, которая, вопреки названию, совершенно не Open. +Множество компаний и людей вписали их продукты в свою рутину и не страшатся такой неподконтрольной зависимости. -Я так не могу. К счастью, я не один такой, и на данный момент уже есть множество альтернативных моделей от разных вендоров. Они отличаются друг от друга качеством, размером, возможностями и лицензиями, так что при желании можно надолго занять себя знакомством с обширным ассортиментом. Например, на портале [HuggingFace](https://huggingface.co/), который можно описать как "GitHub для LLM и всего, что вокруг". +Я так не могу. К счастью, я не один такой, и на данный момент уже есть множество альтернативных моделей от разных вендоров. Они отличаются друг от друга качеством, размером, возможностями и лицензиями, так что при желании можно надолго занять себя знакомством с обширным ассортиментом. Например, на портале [HuggingFace](https://huggingface.co/), который можно описать как «GitHub для LLM и всего, что вокруг». -Должен признаться, что очень слабо разбираюсь в параметрах и характеристиках языковых моделей, но оказалось, что для того, чтобы начать, эти знания не так уж и необходимы. +Должен признаться, что очень слабо разбираюсь в параметрах и характеристиках языковых моделей, но оказалось, что для того, чтобы начать, эти знания не так уж и необходимы. -Ниже инструкция, как запустить LLM на своём железе, как упаковать всё это в docker-контейнер, чтобы не размазать случайно по всей файловой системе, как получить совместимый с OpenAI API и как потом этим пользоваться. +Ниже инструкция, как запустить LLM на своём железе, как упаковать всё это в docker-контейнер, чтобы не размазать случайно по всей файловой системе, как получить совместимый с OpenAI API и как потом этим пользоваться. --- @@ -45,66 +45,66 @@ description: 'Персональная LLM в docker-контейнере на
-## Установка и настройка +## Установка и настройка -Существует несколько продуктов, которые стараются избавить пользователя от головной боли и возни с инфраструктурой. Мне понятнее всего оказался проект [Ollama](https://ollama.ai/), с ним мы и будем экспериментировать. +Существует несколько продуктов, которые стараются избавить пользователя от головной боли и возни с инфраструктурой. Мне понятнее всего оказался проект [Ollama](https://ollama.ai/), с ним мы и будем экспериментировать. -Кроме бинарников для Linux и MacOS, они [предоставляют](https://ollama.ai/blog/ollama-is-now-available-as-an-official-docker-image) официальный [docker-образ](https://hub.docker.com/r/ollama/ollama), работу с которым я и опишу. +Кроме бинарников для Linux и MacOS, они [предоставляют](https://ollama.ai/blog/ollama-is-now-available-as-an-official-docker-image) официальный [docker-образ](https://hub.docker.com/r/ollama/ollama), работу с которым я и опишу. -Использование docker-контейнеров, к сожалению, слегка усложняет взаимодействие с Ollama, так что большая часть текста и кода в этом посте посвящены решению проблем, которые, по сути, я придумал себе сам. +Использование docker-контейнеров, к сожалению, слегка усложняет взаимодействие с Ollama, так что большая часть текста и кода в этом посте посвящены решению проблем, которые, по сути, я придумал себе сам.
### Установка Ollama -Для создания и первого запуска контейнера нужно выполнить команду: +Для создания и первого запуска контейнера нужно выполнить команду: ``` docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama ``` -Счастливые владельцы видеокарт от Nvidia могут установить [Nvidia container toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html#installation) и активировать поддержку GPU с помощью флага `--gpus=all`. +Счастливые владельцы видеокарт от Nvidia могут установить [Nvidia container toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html#installation) и активировать поддержку GPU с помощью флага `--gpus=all`. -После создания запускать и останавливать контейнер `ollama` можно так: +После создания запускать и останавливать контейнер `ollama` можно так: ``` docker start ollama docker stop ollama ``` -Контейнер предоставляет доступ к [Ollama API](https://github.com/jmorganca/ollama/blob/main/docs/api.md) на 11434 порту, а также позволяет устанавливать и общаться с установленными LLM через терминал. +Контейнер предоставляет доступ к [Ollama API](https://github.com/jmorganca/ollama/blob/main/docs/api.md) на 11434 порту, а также позволяет устанавливать и общаться с установленными LLM через терминал.
-### Загрузка модели и диалог с ней +### Загрузка модели и диалог с ней -Ollama позволяет запускать любые GGUF, PyTorch или Safetensors модели (что бы это ни значило), но самый простой путь - загрузка моделей из специальной [библиотеки](https://ollama.ai/library). +Ollama позволяет запускать любые GGUF, PyTorch или Safetensors модели (что бы это ни значило), но самый простой путь — загрузка моделей из специальной [библиотеки](https://ollama.ai/library). -Для того, чтобы скачать модель и начать с ней диалог, нужно выполнить команду: +Для того, чтобы скачать модель и начать с ней диалог, нужно выполнить команду: ``` docker exec -it ollama ollama run mistral ``` -Вместо `mistral` от одноимённой комании можно выбрать любую другую модель из библиотеки, например, легкую `phi` от Microsoft Research. +Вместо `mistral` от одноимённой комании можно выбрать любую другую модель из библиотеки, например, легкую `phi` от Microsoft Research. -Кроме `run` доступны также `list`, `pull` и `rm` для просмотра списка, скачивания и удаления моделей соответственно. +Кроме `run` доступны также `list`, `pull` и `rm` для просмотра списка, скачивания и удаления моделей соответственно. -Чтобы не писать такие длинные заклинания каждый раз, я добавил в `.zshrc` пару алиасов: +Чтобы не писать такие длинные заклинания каждый раз, я добавил в `.zshrc` пару алиасов: ``` alias summonable='docker exec -it ollama ollama list' alias summon='clear && docker exec -it ollama ollama run' ``` -Теперь можно смотреть на список установленных моделей и запускать диалог с выбранной: +Теперь можно смотреть на список установленных моделей и запускать диалог с выбранной: ``` summonable summon phi ```
-### Кастомные модели и их тонкая настройка +### Кастомные модели и их тонкая настройка -Ollama позволяет на основе существующих создавать производные модели с заранее определёнными инструкциями или параметрами. Для этого нужно создать специальный файл, в котором указана родительская модель и определены желаемые значения параметров. Подробнее о формате этих файлов можно прочесть в документации: [Modelfile](https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md). +Ollama позволяет на основе существующих создавать производные модели с заранее определёнными инструкциями или параметрами. Для этого нужно создать специальный файл, в котором указана родительская модель и определены желаемые значения параметров. Подробнее о формате этих файлов можно прочесть в документации: [Modelfile](https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md). -Чтобы посмотреть, как должен выглядеть Modelfile, можно посетить [OllamaHub](https://ollamahub.com/) от разработчиков стороннего [Ollama Web UI](https://github.com/ollama-webui/ollama-webui/). На сайте есть [примеры очень тонкой настройки множества параметров](https://ollamahub.com/m/smoothbrainape/hu-tao:latest) модели для соответствия образу конкретного персонажа, но в качестве образца я буду использовать небольшой [English Teacher Modelfile](https://ollamahub.com/m/kamjin/english-teacher:latest): +Чтобы посмотреть, как должен выглядеть Modelfile, можно посетить [OllamaHub](https://ollamahub.com/) от разработчиков стороннего [Ollama Web UI](https://github.com/ollama-webui/ollama-webui/). На сайте есть [примеры очень тонкой настройки множества параметров](https://ollamahub.com/m/smoothbrainape/hu-tao:latest) модели для соответствия образу конкретного персонажа, но в качестве образца я буду использовать небольшой [English Teacher Modelfile](https://ollamahub.com/m/kamjin/english-teacher:latest): #### EnglishTeacher.Modelfile ``` @@ -116,9 +116,9 @@ You should always take the initiative to correct my mistakes in grammar and voca """ ``` -Вообще, для загрузки кастомной модели достаточно выполнить команду `create`, но в случае использования Ollama внутри docker-контейнера возникает необходимость каким-то образом файл с моделью в этот контейнер передать. +Вообще, для загрузки кастомной модели достаточно выполнить команду `create`, но в случае использования Ollama внутри docker-контейнера возникает необходимость каким-то образом файл с моделью в этот контейнер передать. -Для решения этой проблемы я набросал небольшой bash-скрипт: +Для решения этой проблемы я набросал небольшой bash-скрипт: #### applyModelfile.bash ```bash @@ -154,7 +154,7 @@ clear docker exec -it ollama ollama create $modelName -f $targetPath ``` -Этот скрипт нужно поместить по соседству с директорией `models` и сделать исполняемым с помощью `chmod +x applyModelfile.bash`. +Этот скрипт нужно поместить по соседству с директорией `models` и сделать исполняемым с помощью `chmod +x applyModelfile.bash`. Должна получиться примерно такая структура: ``` ├── models @@ -162,7 +162,7 @@ docker exec -it ollama ollama create $modelName -f $targetPath └── applyModelfile.bash ``` -После этого модель можно загрузить в контейнер и начать с ней диалог: +После этого модель можно загрузить в контейнер и начать с ней диалог: ``` ./applyModelfile.bash EnglishTeacher summon EnglishTeacher @@ -172,21 +172,21 @@ summon EnglishTeacher ## Использование -Разговоры с галлюцинирующим искусственным интеллектом в терминале - это, конечно, волшебно, но потенциал больших языковых моделeй по-настоящему раскрывается, когда они начинают портить данные в соседних приложениях! +Разговоры с галлюцинирующим искусственным интеллектом в терминале — это, конечно, волшебно, но потенциал больших языковых моделeй по-настоящему раскрывается, когда они начинают портить данные в соседних приложениях! -В [GitHub-репозитории Ollama](https://github.com/jmorganca/ollama#community-integrations) можно найти ссылки на множество веб-интерфейсов, библиотек и плагинов для текстовых редакторов и прочих Obsidian'ов. +В [GitHub-репозитории Ollama](https://github.com/jmorganca/ollama#community-integrations) можно найти ссылки на множество веб-интерфейсов, библиотек и плагинов для текстовых редакторов и прочих Obsidian'ов. -Не ручаюсь за весь список, но расскажу про то, с чем экспериментировал сам. +Не ручаюсь за весь список, но расскажу про то, с чем экспериментировал сам.
-### Мимикрия под API от OpenAI +### Мимикрия под API от OpenAI -API Ollama используется в меньшем числе продуктов, чем API от OpenAI. К счастью, это не проблема: с помощью прокси-прослойки под названием [LiteLLM](https://github.com/BerriAI/litellm) можно сделать их совместимыми. Инструкция по установке и использованию в общем случае есть в репозитории и довольно тривиальна, но мне опять потребовалось немного кода, чтобы заставить их работать вместе на моих условиях. +API Ollama используется в меньшем числе продуктов, чем API от OpenAI. К счастью, это не проблема: с помощью прокси-прослойки под названием [LiteLLM](https://github.com/BerriAI/litellm) можно сделать их совместимыми. Инструкция по установке и использованию в общем случае есть в репозитории и довольно тривиальна, но мне опять потребовалось немного кода, чтобы заставить их работать вместе на моих условиях. -Я хотел, чтобы LiteLLM-прокси и Ollama работали на разных компьтерах, и не хотел ставить pip-пакеты в систему. В результате родилось решение из docker-файла с хаками и скрипта, который в нём запускается. Я не специалист в написании docker-файлов, так что уверен в неоптимальности финального решения. Точно можно и нужно обойтись без `run --net=host` и отдельного скрипта, например. +Я хотел, чтобы LiteLLM-прокси и Ollama работали на разных компьтерах, и не хотел ставить pip-пакеты в систему. В результате родилось решение из docker-файла с хаками и скрипта, который в нём запускается. Я не специалист в написании docker-файлов, так что уверен в неоптимальности финального решения. Точно можно и нужно обойтись без `run --net=host` и отдельного скрипта, например. -Несмотря на костыльность связки, она справляется со своей задачей: +Несмотря на костыльность связки, она справляется со своей задачей: #### Dockerfile ```Dockerfile @@ -213,24 +213,24 @@ pip install litellm litellm --model ollama/mistral --api_base http://ollama.internal:11434 --drop_params ``` -Собрать и запустить docker-контейнер можно с помощью этих двух команд: +Собрать и запустить docker-контейнер можно с помощью этих двух команд: ```sh docker build -t diy-ollama-proxy . docker run --net=host diy-ollama-proxy ``` -После запуска вы получите API, который совместим с API от OpenAI и доступен по адресу `http://localhost:8000/`. +После запуска вы получите API, который совместим с API от OpenAI и доступен по адресу `http://localhost:8000/`.
-### Интеграция с NeoVim +### Интеграция с NeoVim -Языковые модели отлично умеют взаимодействовать с текстом, так что использование их в текстовом редакторе кажется разумной идеей. +Языковые модели отлично умеют взаимодействовать с текстом, так что использование их в текстовом редакторе кажется разумной идеей. -Мне не очень нравится идея Copilot, который зачем-то постоянно подсовывает тебе странные куски кода. Я пробовал использовать [Codeium](https://codeium.com/) в ручном режиме, но оказалось, что странные куски кода по запросу мне тоже не очень нужны. Гораздо более привлекательной мне кажется возможность выделить существующий фрагмент текста или кода и попросить бездушную машину что-нибудь с ним сделать: упростить, дополнить, изменить или даже перевести с одного языка на другой. Идеальным для такого подхода оказался [плагин ollama.nvim](https://github.com/nomnivore/ollama.nvim). +Мне не очень нравится идея Copilot, который зачем-то постоянно подсовывает тебе странные куски кода. Я пробовал использовать [Codeium](https://codeium.com/) в ручном режиме, но оказалось, что странные куски кода по запросу мне тоже не очень нужны. Гораздо более привлекательной мне кажется возможность выделить существующий фрагмент текста или кода и попросить бездушную машину что-нибудь с ним сделать: упростить, дополнить, изменить или даже перевести с одного языка на другой. Идеальным для такого подхода оказался [плагин ollama.nvim](https://github.com/nomnivore/ollama.nvim). -Кроме того, что он поддерживает кастомные промпты (в том числе интерактивные), он позволил мне обращаться к LLM, которая запущена на другом компьютере в локальной сети (для удобства я указал его адрес в `/etc/hosts/`). +Кроме того, что он поддерживает кастомные промпты (в том числе интерактивные), он позволил мне обращаться к LLM, которая запущена на другом компьютере в локальной сети (для удобства я указал его адрес в `/etc/hosts/`). -Установка и настройка с использованием пакетного менеджера lazy.nvim выглядит примерно так: +Установка и настройка с использованием пакетного менеджера lazy.nvim выглядит примерно так: ``` { 'nomnivore/ollama.nvim', @@ -278,63 +278,63 @@ docker run --net=host diy-ollama-proxy }, ``` -В этом конфиге я выключил несколько дефолтных промптов и добавил несколько своих: -- `Improve_Text` заменяет выделенный кусок текста "улучшенным". -- `Modify_Text` является аналогом встроенного `Modify_Code` и позволяет делать с выделенным текстом всякие глупости. Например, заменить все числа на слова. -- `Use_Selection_as_Prompt` просто заменяет выделенный текст на ответ от LLM. +В этом конфиге я выключил несколько дефолтных промптов и добавил несколько своих: +- `Improve_Text` заменяет выделенный кусок текста «улучшенным». +- `Modify_Text` является аналогом встроенного `Modify_Code` и позволяет делать с выделенным текстом всякие глупости. Например, заменить все числа на слова. +- `Use_Selection_as_Prompt` просто заменяет выделенный текст на ответ от LLM. -В итоге получается два сценария использования, оба доступны по ` + j`: -- В `normal` mode плагин спрашивает меня, какой код мне нужен, и вставляет его. -- В `visual` mode появляется меню действий над выделенным текстом. +В итоге получается два сценария использования, оба доступны по ` + j`: +- В `normal` mode плагин спрашивает меня, какой код мне нужен, и вставляет его. +- В `visual` mode появляется меню действий над выделенным текстом. -Как видно из конфига, я использую только `mistral`, но можно указать модель для кажого промпта и делегировать, например, манипуляции над кодом `codellama`, а операции над текстом - `llama2`. +Как видно из конфига, я использую только `mistral`, но можно указать модель для кажого промпта и делегировать, например, манипуляции над кодом `codellama`, а операции над текстом — `llama2`. -Возможность добавления кастомных промптов позволяет в будущем реализовать новые сценарии или вынести повторяющиеся действия в отдельный пункт меню или даже на отдельный шорткат. +Возможность добавления кастомных промптов позволяет в будущем реализовать новые сценарии или вынести повторяющиеся действия в отдельный пункт меню или даже на отдельный шорткат.
-## Обновление и удаление +## Обновление и удаление -Для обновления и удаления моделей можно использовать команды `pull` и `rm`: +Для обновления и удаления моделей можно использовать команды `pull` и `rm`: ``` docker exec -it ollama ollama pull mixtral -docker exec -it ollama ollama rm mistral +docker exec -it ollama ollama rm mistral ``` -Я знаю, что для обновления и удаления docker-образов и docker-контейнеров тоже есть специальные команды (это тоже `pull` и `rm`), но каждый раз ленюсь в этом разобраться, просто сношу всё с помощью утилиты [sen](https://github.com/TomasTomecek/sen) и разворачиваю нужное заново. +Я знаю, что для обновления и удаления docker-образов и docker-контейнеров тоже есть специальные команды (это тоже `pull` и `rm`), но каждый раз ленюсь в этом разобраться, просто сношу всё с помощью утилиты [sen](https://github.com/TomasTomecek/sen) и разворачиваю нужное заново.
## Производительность -Для эксплуатации LLM требуется гораздо меньше ресурсов, чем для её обучения. Запустить 7b-модель средней тупости можно практически на любом CPU и 8 GB RAM, но нагрузка на систему и скорость генерации ответов часто будут далеки от комфортных значений. +Для эксплуатации LLM требуется гораздо меньше ресурсов, чем для её обучения. Запустить 7b-модель средней тупости можно практически на любом CPU и 8 GB RAM, но нагрузка на систему и скорость генерации ответов часто будут далеки от комфортных значений. -Например, на моём немолодом Intel Core i7-10510U @ 8x 4.9GHz неаккуратный запрос к `llama2` может заставить систему шуршать вентиляторами пару-тройку минут. При этом `phi` на этом же процессоре способна отвечать на какие-нибудь не очень сложные вопросы практически мгновенно. +Например, на моём немолодом Intel Core i7-10510U @ 8x 4.9GHz неаккуратный запрос к `llama2` может заставить систему шуршать вентиляторами пару-тройку минут. При этом `phi` на этом же процессоре способна отвечать на какие-нибудь не очень сложные вопросы практически мгновенно. -К счастью, у меня случайно завалялся MacBook на процессоре M1 и он уже показывает куда более впечатляющие результаты. `Mistral` даже на непростые запросы отвечает за считанные секунды, а в режиме чата токены вылетают на экран заметно быстрее, чем в веб-интерфейсе ChatGPT. +К счастью, у меня случайно завалялся MacBook на процессоре M1 и он уже показывает куда более впечатляющие результаты. `Mistral` даже на непростые запросы отвечает за считанные секунды, а в режиме чата токены вылетают на экран заметно быстрее, чем в веб-интерфейсе ChatGPT. -Неприятным открытием стало то, что docker-версия Ollama на MacOS выполняется заметно медленнее (от 3 до 5 раз, если верить ощущениям), чем нативная. Возможно, всё дело в том, что я как-то неправильно настроил docker или приложение в контейнере нужно запускать с какими-нибудь специальными флагами для максимальной утилизации ресурсов. В любом случае, к порядку на этом ноутбуке я отношусь гораздо менее трепетно, поэтому просто установил и использую приложение с сайта Ollama. +Неприятным открытием стало то, что docker-версия Ollama на MacOS выполняется заметно медленнее (от 3 до 5 раз, если верить ощущениям), чем нативная. Возможно, всё дело в том, что я как-то неправильно настроил docker или приложение в контейнере нужно запускать с какими-нибудь специальными флагами для максимальной утилизации ресурсов. В любом случае, к порядку на этом ноутбуке я отношусь гораздо менее трепетно, поэтому просто установил и использую приложение с сайта Ollama.
## Зачем всё это нужно? -Конечно, GhatGPT умнее и умеет из коробки гораздо больше.
+Конечно, GhatGPT умнее и умеет из коробки гораздо больше.
Конечно, ChatGPT требует меньше телодвижений для использования.
-Конечно, самые умные модели требуют внушительных ресурсов, ведь для запуска нашумевшей [mixtral](https://ollama.ai/library/mixtral) или аналогичной модели нужно иметь 48 Gb оперативной памяти.
-Кончено, сидя в кафе задать вопрос Bard от Google гораздо проще, чем достучаться до модели в закрытом ноутбуке, который остался дома.
+Конечно, самые умные модели требуют внушительных ресурсов, ведь для запуска нашумевшей [mixtral](https://ollama.ai/library/mixtral) или аналогичной модели нужно иметь 48 Gb оперативной памяти.
+Кончено, сидя в кафе задать вопрос Bard от Google гораздо проще, чем достучаться до модели в закрытом ноутбуке, который остался дома.
-Я всё это прекрасно понимаю, но ничего из этого не стоит того, чтобы добровольно ставить себя в зависимость от монополистов с их закрытыми чёрными ящиками. +Я всё это прекрасно понимаю, но ничего из этого не стоит того, чтобы добровольно ставить себя в зависимость от монополистов с их закрытыми чёрными ящиками. -Даже если закрыть глаза на все идеологические вопросы, то любая локальная LLM отличается от любого облачного провайдера тем, что: -- Может работать в оффлайне. -- Не хранит и не сливает вашу переписку. -- Не станет завтра тупее, чем есть сегодня. -- Не забанит тебя за возмутивший кого-то там запрос. -- Обладает тем уровнем цензуры, который выбрал ты сам. +Даже если закрыть глаза на все идеологические вопросы, то любая локальная LLM отличается от любого облачного провайдера тем, что: +- Может работать в оффлайне. +- Не хранит и не сливает вашу переписку. +- Не станет завтра тупее, чем есть сегодня. +- Не забанит тебя за возмутивший кого-то там запрос. +- Обладает тем уровнем цензуры, который выбрал ты сам. -Я искренне рад, что для доступа даже к передовым технологиям, всё ещё не обязательно поступаться своей приватностью и своими свободами. +Я искренне рад, что для доступа даже к передовым технологиям, всё ещё не обязательно поступаться своей приватностью и своими свободами. --- -При написании этого поста не была использована ни одна LLM =) +При написании этого поста не была использована ни одна LLM =)