- Регистрация
- 01.10.2015
- Сообщения
- 227
- Благодарностей
- 927
- Баллы
- 93
Многие из нас неплохо знакомы с различными моделями ИИ, которые в контексте использования с софтом Zenno отлично подходят для задач генерации контента. Большие языковые модели (LLM, Large Language Models) некоторое время назад совершили мощный рывок, ставший широко известным с появлением ChatGPT. Такие GPT-like модели шикарно подходят для генерации человекоподобных текстов, однако, ввиду их других сопутствующих достоинств и «сообразительности», на сегодня у них существует большое количество иных применений. Например, они отлично подходят в качестве репетиторов, помощников и ассистентов если вы изучаете иностранные языки, или же учитесь программированию. Иными словами, во многих профессиях и конкретных делах-задачах можно оптимизировать (улучшить/ускорить/масштабировать) свою работу/задачу с помощью LLM. Разработка шаблонов для ZennoPoster и ZennoDroid – не исключение. Собственно, именно эту тему мы и затронем в этой статье – как можно использовать большие языковые модели себе в помощь при работе с Zenno.
Акцент будем делать на использовании опенсорсовских LLM, которые можно просто запустить на своём компьютере или сервере. Причины выбора такого акцента:
Плюс к этому, даже если вы используете LLM только для генерации текстового контента, открытые модели так же весьма интересны в точки зрения себестоимости и меньшей зацензурированности.
О чём будем говорить – понятно, теперь давайте чуть больше конкретики. Какие именно юзкейсы LLM сходу можно придумать для разработки шаблонов?
Планирование проекта на начальном этапе.
Более-менее крупный шаблон или проект всегда надо с чего-то начинать, и в этом плане LLM может помочь ускорить и улучшить проектирование. Пишем краткий план чего хотим сделать, закидываем в промпт модельке с дополнительной затравкой по типу «делаю такую вот программу, помоги с проектированием структуры проекта». Базовое создание Zenno-шаблонов представляет собой визуальное программирование, поэтому контекст для промптов (запросов/затравок к LLM) можно использовать соответствующий.
Если вы разрабатываете шаблоны на заказ, примерно то же самое можно делать с ТЗ заказчика.
Генерация и отладка C#-сниппетов.
Почти все LLM весьма хороши в кодинге, особенно в кодинге небольших выделенных задач, для которых и используются C#-сниппеты в Zenno. Даже если модель написала неподходящий код, или выдающий ошибку код – всегда есть возможность сказать об этом модели (или скормить текст ошибки), чтобы она пофиксила проблему.
Понимание кода и сниппетов.
Для своих шаблонов на форуме можно найти множество как полезных сниппетов, так и крупных модулей кода (например, для блока «Общего кода» или целых внешних dll-библиотек). Если вы не знаете, что делает тот или иной код с форума, и будет ли конкретно в вашем случае полезен – вы можете скормить его LLM и попросить объяснить, вплоть до подробного разбора буквально каждой строчки. Языковые модели прекрасно с этим справляются.
Анализ информации/документации.
LLM отлично справляются с суммаризацией информации.
Понадобилось добавить в шаблон работу с каким-нибудь новым/непонятным для вас API? Скормите LLM документацию и примеры из этого API и попросите суммаризировать или кратко объяснить основные моменты. Или сразу написать в виде C#-кода имплементацию для своего шаблона.
Хотите всегда быть в курсе новых полезных решений с форума zennolab, актуальных вопросов и проблем Zenno, способов обхода и т.д., что обсуждается на форуме – но не хочется каждый день заходить на форум и всё это мониторить? Напишите шаблон-парсер форума, который будет отправлять контент в LLM для суммаризации LLM, а конечный результат выводить/отправлять вам регулярно в виде своеобразного фида.
Это несколько основных вариантов, которые в той или иной степени использую сам, и с которых можно начать, если вы ещё этим не занимались. Однако, помимо этих, почти наверняка можно найти ещё приличное количество юзкейсов, особенно если основываться на конкретно ваших индивидуальных потребностях и проектах.
Резюмируя, использование LLM в качестве помощника в таких задачах экономит ваше время и/или повышает вашу эффективность.
Теперь немного подробнее разберём, какие бывают большие языковые модели.
Платные-закрытые и бесплатные-опенсорсные.
Основные различия этих в нашем Zenno-контексте мы уже немного разобрали выше. Дополнительно стоит сказать, что неплохих опенсорс-моделей нет так уж и мало, а уж файн-тюнов для них (дообученых «модификаций» под конкретные задачи/сферы знаний) – великое множество. Пожалуй, наиболее интересные экземпляры – семейство моделей Llama. Их тренирует крупный IT-гигант (которым рулит один известный Марк), у которого ресурсов достаточно, чтобы иметь возможность создавать передового уровня модели. И тесты последней Llama это доказывают. В общем и целом, она не дотягивает до передовых закрытых моделей, но звание лучшей открытой явно принадлежит ей (по крайней мере на момент написания статьи). Её мы и будем запускать в следующей главе.
По количеству параметров – «тяжелые» и «лёгкие».
Почти всегда в названиях опенсорс-моделей вы будете видеть подобные приписки: «7B», «13B», «34B», «70B». Это обозначение количества их параметров, в миллиардах (B – billions). Как правило, чем больше параметров – тем более моделька «умна». Однако, вместе с тем, тем более она ест памяти компьютера. Например, для инференса (запуска и использования) модели с 7 миллиардами параметров в f16 требуется примерно 14 ГБ видеопамяти. С остальными размерами такое же соотношение (т.е. для 13B – около 26 ГБ видеопамяти, для 34B – около 68 ГБ). Для потребительского железа цифры жуткие, но, к счастью, есть такая штука, как квантизация. Если сильно упростить – это что-то типа сжатия модельки, сильно выигрываем в размере, мало проигрываем в качестве ответов. Так, например, квантованная до Q8 модель 7B занимает чуть больше 7 ГБ видеопамяти (потери по качеству ответов LLM при таком квантовании почти нулевые).
Желательно запускать модели в видеопамяти, т.е. в памяти видеокарты (в идеале от NVidia), так ответы от LLM будут наиболее быстрые. Однако, более-менее крупные модели (34B и выше) таким образом особо не позапускаешь из-за того, что в потребительских видеокартах довольно мало видеопамяти (исключение – если у вас есть парочка 3090 или 4090). Тем не менее, модель можно помещать и в оперативную память, которая дешевая и которую можно поставить довольно большое количество. Однако, в этом случае вычисления будут происходить на CPU, плюс пропускная способность ОЗУ значительно ниже таковой у видеопамяти. Поэтому скорость работы будет значительно ниже при использовании больших моделей. Ориентировочный пример: если модель N при инференсе на GPU и видеопамяти выдаст ответ в виде текста на 3 абзаца буквально за 5-10 секунд, то при инференсе на CPU и ОЗУ она же выдаст такой же ответ за более чем минуту, набирая его со скоростью среднего печатающего человека.
Также ныне в софте для запуска LLM нередко есть возможность часть слоев модели загрузить в видеопамять, часть – в ОЗУ, этакий компромиссный вариант.
Базовые и заточенные на инструкции.
Нередко опенсорсные модели выпускают в нескольких вариантах, чаще всего это Base и Instruct-модели. Первая – дефолтная модель, подходящая для любых целей. Вторая – дообученная на инструкциях базовая модель, из-за чего лучше понимает именно инструкции (соответственно, похожу в болтовне и других задачах). В наших Zenno-задачах в амплуа ассистента и помощника по коду – почти всегда лучше себя показывают Instruct-версии моделей. Как и размер, приписку «Instruct» почти всегда можно встретить в названии опенсорс-модели, поэтому определять и искать их легко.
Размер контекстного окна.
Контекстное окно – это ваш «чатик» с LLM, какого размера он может быть в токенах. Чем более большое контекстное окно поддерживает модель, тем больше в неё можно отправить информации виде промптов, тем больше контекста вашей задачи/проблемы она может учитывать при ответах. Однако, чем больше контекста вы закидываете в это окно (чем больше текста в вашем диалоге/чатике) – тем больше требуется вычислений модели и тем больше кушается оперативной памяти (сверх инференса из пункта выше). Также, в слишком большой куче текста модель куда хуже ориентируется, хуже вычленяет важные моменты и факты (в большинстве случаев). Поэтому, например, вне зависимости от поддерживаемого моделью размера контекстного окна, всегда стоит для 1 одной задачи использовать 1 «чатик», для каждой новой обязательно начинать новый диалог.
Для локального запуска моделей нам нужен соответствующий софт. Рассмотрим локальное использование LLM на примере «LM Studio». Официальный сайт, где можно как почитать про программу, так и скачать: https://lmstudio.ai/
Доступны версии для Windows и Linux (из требований – поддержка процессором AVX2), для Mac на M1 и выше. Если у вас видеокарта от AMD, есть отдельная версия программы тут: https://lmstudio.ai/rocm Улучшенная производительность для таких карт, но билд экспериментальный, могут быть проблемы/баги.
И некоторый дисклеймер – конкретно «LM Studio» проприетарный софт, и хоть они пишут на сайте, что не логируют ничего пользовательского, соответствующие риски есть. Поэтому, если необходима гарантировано приватное взаимодействие с моделью, используйте опенсорсные решения. В данной статье «LM Studio» выбрана как наиболее простая и понятная в использования для среднего пользователя программа.
Как работать с моделями в этой программе – рассмотрим в видео.
Использование в качестве локального сервера для своих шаблонов
Помимо прочего мы видим, что у «LM Studio» есть функционал локального сервера, со стандартной для индустрии OpenAI-форматом API (линк на документацию).
Это значит, что если вы уже используете в своих шаблонах GPT или другие нейронки через API - вы можете переключить генерацию на локальную модель буквально за пару минут.
Для этого нужно:
Запросы к LLM обычно называют промптами (от англ. prompt – затравка, запрос, инструкция к модели).
Из-за устройства и принципа работы больших языков моделей, их ответ на ваш запрос (промпт) довольно прилично зависит от того, как именно вы его сформулировали. Иными словами, если достаточно хорошо и подробно сформулировать вопрос, можно получить гораздо более качественный и точный ответ, чем если просто обычным образом задать вопрос. Нередко в ситуациях, когда подразумевается достаточно чёткий и однозначный ответ (например, код, делающий именно то, что надо без ошибок), от того, как написан промпт, напрямую зависит то, что получится в результате – либо неработающая муть, либо именно то, что требуется.
Вот пара наиболее популярных и простых, но тем не менее крайне эффективных техник.
Chain of Thought (цепочка размышлений)
Если в промпте попросить модель думать пошагово при ответе, то это может заставить её декомпозировать задачу, подробно описать каждый шаг перед ответом. Как правильно это значительно улучшает качество ответа и уменьшает галлюцинации.
Примеры фраз: «think step-by-step», «provide me your chain of thoughts»
Emotional prompting (запросы с эмоциональной окраской)
Упоминания о сильной важности ответа модели на вопрос в тексте промпта зачастую повышают качество ответа. К запросам, например, добавляют, что от качества ответа зависит судьба вашей или чьей-то ещё жизни.
Примеры фраз: «You'd better be sure», «This is very important to my career»
Выше я привел примеры фраз на английском языке, но мы же собираемся задавать вопросы на нашем языке? На самом деле крайне желательно писать промпты именно на английском, в большинстве случаев это даёт лучший результат. Все модели лучше всего понимают и отвечают на английском языке, даже если учились на множестве других тоже. Это актуально для любых моделей просто потому, что во всех трейнинг-сетах данных на английском большинство, просто потому что данных в мире интернете подавляющее большинство именно на этом языке. Даже китайские модели, тренируемые для использования на внутреннем рынке, ныне всё ещё лучше работают на английском, чем на китайском.
У опенсорс-моделей этот гэп значительно больше, чем у передовых закрытых. Соответственно, в среднем промпты даже на корявом английском будут давать лучше результаты, чем на хорошем русском. Поэтому если вы не знаете языка, имеет смысл закидывать в переводчик свой промпт и скармливать модели именно перевод, а потом переводить ответ. Тут, кстати, можно использовать саму модель в качестве переводчика (главное, перевод на вход делать отдельным чатом, или же стирать его изначальную формулировку на своем языке).
Так как мы рассматриваем опенсорс-модели, также стоит отметить, что промптинг для них может отличаться как от закрытых моделей, так и от других открытых. То есть, например, одна техника промптинга может давать отличные результаты с одной моделью, но с другой – не давать почти никакого дополнительного эффекта. Поэтому эксперименты – наше всё.
Помимо обычных диалоговых ролей User (вы, пользователь) и Assistant (модель) есть возможность задавать так называемый системный промпт (по сути самое первое сообщение в диалоге, в котором для модели можно задать её назначение и дополнительная информация). В него полезно помещать желаемую роль модели, важную информацию по сфере будущих запросов и техники промптинга. Пример системного промпта для чата, в котором планируем спрашивать модель за C#-сниппеты:
https://www.promptingguide.ai/ru/introduction/basics
https://docs.google.com/spreadsheets/d/19jzLgRruG9kjUQNKtCg1ZjdD6l6weA6qRXG5zLIAhC8/edit?usp=sharing
https://docs.anthropic.com/en/prompt-library/library
Так как это статья в рамках конкурса кейсов, в этой главе расскажу о личных примерах использования, которые можно вынести за скобки рабочих проектов.
Конкретно я все Zenno-проекты пишу почти полностью в коде в Visual Studio, поэтому большая часть моих юзкейсов связана с кодингом на C#. В частности, оптимизация и рефакторинг старого кода, создание тестов, написание (генерация LLM-кой) относительно простых методов и сущностей, для которых не требуется знания и структуры всего основного проекта и целиком фреймворка Zenno.
Далее под спойлером небольшой пример того, как мне ответила модель (это была CodeLlama Instruct 7B), когда я скормил ей один из своих методов расширения.
Также какие-то отдельные вещи типа написания регулярок тоже стал отдавать на откуп LLM, они их пишут тупо лучше меня.
Кстати, так как C# – объектно-ориентированный язык программирования, по умолчанию модели будут вам отвечать со всей структурой для копипаста в среду разработки – т.е. с юзингами, классами, методами и прочим. В случае с Zenno такой код подходит для блока «Общий код», но для C#-сниппетов надо удалять всё лишнее, или копипастить код только из тела методов.
Поэтому можно просто сразу просить модель давать только имплементацию или содержимое тело метода. Посмотрим на примере того же распарса «bounds».
Раньше, когда я изучал что-то новое или был какой-либо затык, поиск решения часто приводил в stackoverflow. Теперь до этого дело не доходит, так как LLM практически всегда может сразу подсказать/объяснить требуемое + написать хороший код, при том это все более релевантно конкретно моему случаю (меньше мороки с адаптацией сторонних решений).
Если вы пишите код для Zenno в какой-нибудь IDE, как и я – существуют ещё плагины для сред разработки, такие как GitHub Copilot и Codeium. По сути, это интеграции функционала LLM прямо IDE. Лично мне они показались не очень удобными и полезными в моём случае, поэтому я ничем таким на данный момент не пользуюсь. Тем не менее, некоторые разработчики находят их полезными, возможно, они пригодятся и вам.
Да, стоит сказать, что упомянутые выше плагины проприетарные, со всеми сопутствующими минусами. Есть ещё компромиссные варианты с гибкой настройкой, пример – плагин Continue. К нему можно прокинуть любую модель на свой вкус (в том числе через тот же «LM Studio» в режиме сервера) и настроить под свои нужды. Вот этим конкретно мне например уже интересно заняться, но на момент написания статьи ещё не добрался.
Несмотря на все плюшки LLM для нашего случая, есть один минус – модели либо ничего не знают о продуктах Zennolab и особенностях их использования, либо в лучшем случае такая информация у них затеряна среди тонны других данных обо всём на свете. Поэтому на вопросы сугубо по инфраструктуре Zenno, документации и API модели будут отвечать в лучшем случае посредственно. Однако, существуют способы «прокачать» модели так, чтобы они учитывали базу знаний по Zenno, могли отвечать развёрнуто именно по ней.
Соответственно, под конец немного поговорим о двух таких способах.
RAG (Retrieval Augmented Generation)
Этот метод представляет собой возможность дать доступ модели к вашей базе данных, чтобы она при ответе на запросы использовала соответствующие знания. Как именно это примерно работает.
Почему:
Резюмируя – RAG инструмент потенциально очень мощный, но для хорошего результата обычно требует значительное количество усилий.
Fine-tuning (дообучение).
Файн-тюнинг по сути своей представляет дообучение изначальной модели на вашем специализированном датасете. На данный момент существует достаточно много видов и подходов к файн-тюнингу. Плюс к тому, большинство открытых специализированных моделей, размещённых на том же HuggingFace – это именно файн-тюны Llama и других открытых LLM.
В нашем случае для файн-тюнинга модели надо собрать датасет по требуемой базе знаний – то есть взять те же документацию Zennolab, статьи и прочее с форума, и соорудить из них датасет, пригодный для дообучения.
Далее надо будет дообучить исходную модель на этом датасете, для этого скорее всего понадобиться покупать GPU-часы у какого-нибудь провайдера серверов со специализированными GPU. Насколько долго это продлится и сколько будет стоить – зависит от исходной модели, размера датасета, метода файн-тюнинга. Но, понятное дело, в наших масштабах это будет не сильно дорогое дело, тем более ни в какое сравнение не идёт с затратами на претрейн оригинальных моделей, на который компании обычно тратят миллионы долларов.
Также вам понадобится составить свой бенчмарк для оценки ответов, чтобы сравнивать ответы моделей до и после файн-тюнинга по нашей базе знаний. К тому же, маловероятно, что с первого раза у вас получится хороший результат, и надо будет как-то оценивать все получаемые файн-тюны.
Плюс ко всему, для занятия файн-тюнингом в идеале иметь компетенции в Machine Learning (ML), так как соответствующих нюансов при дообучении моделей хватает.
Резюмируя – с помощью файн-тюнинга можно получить специализированную модель-ассистента, которая, по сути, будет прекрасно ориентироваться в базе знаний Zenno и давать шикарные ответы по теме, но для хорошего результата почти наверняка понадобится временных и финансовых затрат ещё больше, чем для хорошей реализации RAG.
Как итог, что RAG, что Fine-tuning – крайне мощные и перспективные инструменты для «заточки» моделей под специфическую сферу знаний по типу экосистемы Zenno. Однако, когда речь идёт об одиночном разработчике шаблонов для Zenno – это скорее избыточные инструменты ввиду большого объёма трудозатрат. Но для организованных команд разработчиков или Zenno-энтузиастов, а также самой компании Zennolab – думаю, вполне посильная и имеющая смысл задача. Возможно, в будущем кто-нибудь сделает что-то подобное конкретно под Zenno. Если, конечно, до этого не появится какой-нибудь AGI, который за счёт своей продвинутости сделает неактуальным все эти вещи (или просто убьёт нас всех ).
Всем огромное спасибо за внимание! Успехов вам как на поприще Zenno, так и в обычной жизни.
Акцент будем делать на использовании опенсорсовских LLM, которые можно просто запустить на своём компьютере или сервере. Причины выбора такого акцента:
- Приватность (не отправляем никакие данные сторонним организациям)
- Низкая стоимость вычислений (платим, по сути, только за электричество, если запускаем на своём железе)
- Меньший уровень цензуры (при соответствующей необходимости)
Плюс к этому, даже если вы используете LLM только для генерации текстового контента, открытые модели так же весьма интересны в точки зрения себестоимости и меньшей зацензурированности.
Способы использования
О чём будем говорить – понятно, теперь давайте чуть больше конкретики. Какие именно юзкейсы LLM сходу можно придумать для разработки шаблонов?
Планирование проекта на начальном этапе.
Более-менее крупный шаблон или проект всегда надо с чего-то начинать, и в этом плане LLM может помочь ускорить и улучшить проектирование. Пишем краткий план чего хотим сделать, закидываем в промпт модельке с дополнительной затравкой по типу «делаю такую вот программу, помоги с проектированием структуры проекта». Базовое создание Zenno-шаблонов представляет собой визуальное программирование, поэтому контекст для промптов (запросов/затравок к LLM) можно использовать соответствующий.
Если вы разрабатываете шаблоны на заказ, примерно то же самое можно делать с ТЗ заказчика.
Генерация и отладка C#-сниппетов.
Почти все LLM весьма хороши в кодинге, особенно в кодинге небольших выделенных задач, для которых и используются C#-сниппеты в Zenno. Даже если модель написала неподходящий код, или выдающий ошибку код – всегда есть возможность сказать об этом модели (или скормить текст ошибки), чтобы она пофиксила проблему.
Понимание кода и сниппетов.
Для своих шаблонов на форуме можно найти множество как полезных сниппетов, так и крупных модулей кода (например, для блока «Общего кода» или целых внешних dll-библиотек). Если вы не знаете, что делает тот или иной код с форума, и будет ли конкретно в вашем случае полезен – вы можете скормить его LLM и попросить объяснить, вплоть до подробного разбора буквально каждой строчки. Языковые модели прекрасно с этим справляются.
Анализ информации/документации.
LLM отлично справляются с суммаризацией информации.
Понадобилось добавить в шаблон работу с каким-нибудь новым/непонятным для вас API? Скормите LLM документацию и примеры из этого API и попросите суммаризировать или кратко объяснить основные моменты. Или сразу написать в виде C#-кода имплементацию для своего шаблона.
Хотите всегда быть в курсе новых полезных решений с форума zennolab, актуальных вопросов и проблем Zenno, способов обхода и т.д., что обсуждается на форуме – но не хочется каждый день заходить на форум и всё это мониторить? Напишите шаблон-парсер форума, который будет отправлять контент в LLM для суммаризации LLM, а конечный результат выводить/отправлять вам регулярно в виде своеобразного фида.
Это несколько основных вариантов, которые в той или иной степени использую сам, и с которых можно начать, если вы ещё этим не занимались. Однако, помимо этих, почти наверняка можно найти ещё приличное количество юзкейсов, особенно если основываться на конкретно ваших индивидуальных потребностях и проектах.
Резюмируя, использование LLM в качестве помощника в таких задачах экономит ваше время и/или повышает вашу эффективность.
Какие бывают LLM
Теперь немного подробнее разберём, какие бывают большие языковые модели.
Платные-закрытые и бесплатные-опенсорсные.
Основные различия этих в нашем Zenno-контексте мы уже немного разобрали выше. Дополнительно стоит сказать, что неплохих опенсорс-моделей нет так уж и мало, а уж файн-тюнов для них (дообученых «модификаций» под конкретные задачи/сферы знаний) – великое множество. Пожалуй, наиболее интересные экземпляры – семейство моделей Llama. Их тренирует крупный IT-гигант (которым рулит один известный Марк), у которого ресурсов достаточно, чтобы иметь возможность создавать передового уровня модели. И тесты последней Llama это доказывают. В общем и целом, она не дотягивает до передовых закрытых моделей, но звание лучшей открытой явно принадлежит ей (по крайней мере на момент написания статьи). Её мы и будем запускать в следующей главе.
По количеству параметров – «тяжелые» и «лёгкие».
Почти всегда в названиях опенсорс-моделей вы будете видеть подобные приписки: «7B», «13B», «34B», «70B». Это обозначение количества их параметров, в миллиардах (B – billions). Как правило, чем больше параметров – тем более моделька «умна». Однако, вместе с тем, тем более она ест памяти компьютера. Например, для инференса (запуска и использования) модели с 7 миллиардами параметров в f16 требуется примерно 14 ГБ видеопамяти. С остальными размерами такое же соотношение (т.е. для 13B – около 26 ГБ видеопамяти, для 34B – около 68 ГБ). Для потребительского железа цифры жуткие, но, к счастью, есть такая штука, как квантизация. Если сильно упростить – это что-то типа сжатия модельки, сильно выигрываем в размере, мало проигрываем в качестве ответов. Так, например, квантованная до Q8 модель 7B занимает чуть больше 7 ГБ видеопамяти (потери по качеству ответов LLM при таком квантовании почти нулевые).
Желательно запускать модели в видеопамяти, т.е. в памяти видеокарты (в идеале от NVidia), так ответы от LLM будут наиболее быстрые. Однако, более-менее крупные модели (34B и выше) таким образом особо не позапускаешь из-за того, что в потребительских видеокартах довольно мало видеопамяти (исключение – если у вас есть парочка 3090 или 4090). Тем не менее, модель можно помещать и в оперативную память, которая дешевая и которую можно поставить довольно большое количество. Однако, в этом случае вычисления будут происходить на CPU, плюс пропускная способность ОЗУ значительно ниже таковой у видеопамяти. Поэтому скорость работы будет значительно ниже при использовании больших моделей. Ориентировочный пример: если модель N при инференсе на GPU и видеопамяти выдаст ответ в виде текста на 3 абзаца буквально за 5-10 секунд, то при инференсе на CPU и ОЗУ она же выдаст такой же ответ за более чем минуту, набирая его со скоростью среднего печатающего человека.
Также ныне в софте для запуска LLM нередко есть возможность часть слоев модели загрузить в видеопамять, часть – в ОЗУ, этакий компромиссный вариант.
Если вдруг вы однажды будете рассматривать покупку потребительской видеокарты именно с целью локального инференса LLM – основных критерия по сути только 2: количество видеопамяти и производитель NVidia (для карт AMD сейчас слишком много проблем и ограничений, к сожалению). Относительная мощность GPU мало влияет, основной цимес в памяти и её пропускной способности. Поэтому оптимальные карты в данном случае – 3060 на 12 ГБ и 4060ti на 16 ГБ. Дальше имеют смысл только 3090 или 4090 (24 ГБ) и специализированные карточки.
Базовые и заточенные на инструкции.
Нередко опенсорсные модели выпускают в нескольких вариантах, чаще всего это Base и Instruct-модели. Первая – дефолтная модель, подходящая для любых целей. Вторая – дообученная на инструкциях базовая модель, из-за чего лучше понимает именно инструкции (соответственно, похожу в болтовне и других задачах). В наших Zenno-задачах в амплуа ассистента и помощника по коду – почти всегда лучше себя показывают Instruct-версии моделей. Как и размер, приписку «Instruct» почти всегда можно встретить в названии опенсорс-модели, поэтому определять и искать их легко.
Размер контекстного окна.
Контекстное окно – это ваш «чатик» с LLM, какого размера он может быть в токенах. Чем более большое контекстное окно поддерживает модель, тем больше в неё можно отправить информации виде промптов, тем больше контекста вашей задачи/проблемы она может учитывать при ответах. Однако, чем больше контекста вы закидываете в это окно (чем больше текста в вашем диалоге/чатике) – тем больше требуется вычислений модели и тем больше кушается оперативной памяти (сверх инференса из пункта выше). Также, в слишком большой куче текста модель куда хуже ориентируется, хуже вычленяет важные моменты и факты (в большинстве случаев). Поэтому, например, вне зависимости от поддерживаемого моделью размера контекстного окна, всегда стоит для 1 одной задачи использовать 1 «чатик», для каждой новой обязательно начинать новый диалог.
Установка и запуск локальной LLM
Для локального запуска моделей нам нужен соответствующий софт. Рассмотрим локальное использование LLM на примере «LM Studio». Официальный сайт, где можно как почитать про программу, так и скачать: https://lmstudio.ai/
Доступны версии для Windows и Linux (из требований – поддержка процессором AVX2), для Mac на M1 и выше. Если у вас видеокарта от AMD, есть отдельная версия программы тут: https://lmstudio.ai/rocm Улучшенная производительность для таких карт, но билд экспериментальный, могут быть проблемы/баги.
И некоторый дисклеймер – конкретно «LM Studio» проприетарный софт, и хоть они пишут на сайте, что не логируют ничего пользовательского, соответствующие риски есть. Поэтому, если необходима гарантировано приватное взаимодействие с моделью, используйте опенсорсные решения. В данной статье «LM Studio» выбрана как наиболее простая и понятная в использования для среднего пользователя программа.
Как работать с моделями в этой программе – рассмотрим в видео.
Использование в качестве локального сервера для своих шаблонов
Помимо прочего мы видим, что у «LM Studio» есть функционал локального сервера, со стандартной для индустрии OpenAI-форматом API (линк на документацию).
Это значит, что если вы уже используете в своих шаблонах GPT или другие нейронки через API - вы можете переключить генерацию на локальную модель буквально за пару минут.
Для этого нужно:
- Загрузить любую подходящую модель в «LM Studio» (в самом верху, так же, как с чатом)
- В разделе программы «Local Server» нажать на «Start Server»
- В своих Zenno-шаблонах заменить URL API на « » и убрать ненужные параметры, если таковые есть (например, API-ключ и название модели по понятным причинам передавать не нужно)
Улучшение ответов техниками промптинга
Запросы к LLM обычно называют промптами (от англ. prompt – затравка, запрос, инструкция к модели).
Из-за устройства и принципа работы больших языков моделей, их ответ на ваш запрос (промпт) довольно прилично зависит от того, как именно вы его сформулировали. Иными словами, если достаточно хорошо и подробно сформулировать вопрос, можно получить гораздо более качественный и точный ответ, чем если просто обычным образом задать вопрос. Нередко в ситуациях, когда подразумевается достаточно чёткий и однозначный ответ (например, код, делающий именно то, что надо без ошибок), от того, как написан промпт, напрямую зависит то, что получится в результате – либо неработающая муть, либо именно то, что требуется.
Вот пара наиболее популярных и простых, но тем не менее крайне эффективных техник.
Chain of Thought (цепочка размышлений)
Если в промпте попросить модель думать пошагово при ответе, то это может заставить её декомпозировать задачу, подробно описать каждый шаг перед ответом. Как правильно это значительно улучшает качество ответа и уменьшает галлюцинации.
Примеры фраз: «think step-by-step», «provide me your chain of thoughts»
Emotional prompting (запросы с эмоциональной окраской)
Упоминания о сильной важности ответа модели на вопрос в тексте промпта зачастую повышают качество ответа. К запросам, например, добавляют, что от качества ответа зависит судьба вашей или чьей-то ещё жизни.
Примеры фраз: «You'd better be sure», «This is very important to my career»
Выше я привел примеры фраз на английском языке, но мы же собираемся задавать вопросы на нашем языке? На самом деле крайне желательно писать промпты именно на английском, в большинстве случаев это даёт лучший результат. Все модели лучше всего понимают и отвечают на английском языке, даже если учились на множестве других тоже. Это актуально для любых моделей просто потому, что во всех трейнинг-сетах данных на английском большинство, просто потому что данных в мире интернете подавляющее большинство именно на этом языке. Даже китайские модели, тренируемые для использования на внутреннем рынке, ныне всё ещё лучше работают на английском, чем на китайском.
У опенсорс-моделей этот гэп значительно больше, чем у передовых закрытых. Соответственно, в среднем промпты даже на корявом английском будут давать лучше результаты, чем на хорошем русском. Поэтому если вы не знаете языка, имеет смысл закидывать в переводчик свой промпт и скармливать модели именно перевод, а потом переводить ответ. Тут, кстати, можно использовать саму модель в качестве переводчика (главное, перевод на вход делать отдельным чатом, или же стирать его изначальную формулировку на своем языке).
Так как мы рассматриваем опенсорс-модели, также стоит отметить, что промптинг для них может отличаться как от закрытых моделей, так и от других открытых. То есть, например, одна техника промптинга может давать отличные результаты с одной моделью, но с другой – не давать почти никакого дополнительного эффекта. Поэтому эксперименты – наше всё.
Помимо обычных диалоговых ролей User (вы, пользователь) и Assistant (модель) есть возможность задавать так называемый системный промпт (по сути самое первое сообщение в диалоге, в котором для модели можно задать её назначение и дополнительная информация). В него полезно помещать желаемую роль модели, важную информацию по сфере будущих запросов и техники промптинга. Пример системного промпта для чата, в котором планируем спрашивать модель за C#-сниппеты:
Техник и подходов к промптингу довольно много, и в целом к моменту написания статьи промптинг вылился в отдельную большую дисциплину. Вот пара ссылок, где вы сможете как в целом больше узнать про искусство запросов к моделям, так и найти множество конкретных примеров:You are a professional C#-developer. Please, pay attention. Think step-by-step, evaluate yourself and provide me your chain of thoughts. Please, ask questions for clarification before generating your answer.
https://www.promptingguide.ai/ru/introduction/basics
https://docs.google.com/spreadsheets/d/19jzLgRruG9kjUQNKtCg1ZjdD6l6weA6qRXG5zLIAhC8/edit?usp=sharing
https://docs.anthropic.com/en/prompt-library/library
Личные юзкейсы в задачах на Zenno
Так как это статья в рамках конкурса кейсов, в этой главе расскажу о личных примерах использования, которые можно вынести за скобки рабочих проектов.
Конкретно я все Zenno-проекты пишу почти полностью в коде в Visual Studio, поэтому большая часть моих юзкейсов связана с кодингом на C#. В частности, оптимизация и рефакторинг старого кода, создание тестов, написание (генерация LLM-кой) относительно простых методов и сущностей, для которых не требуется знания и структуры всего основного проекта и целиком фреймворка Zenno.
Далее под спойлером небольшой пример того, как мне ответила модель (это была CodeLlama Instruct 7B), когда я скормил ей один из своих методов расширения.
Промпт:
How do you think, how it's possible to optimize that method:
Ответ модели:
The `IsFreeFromPopups` method is a simple method that checks if an element is free from pop-ups by checking the element's position and comparing it to the position of another element. However, there are some potential issues with this method:
1. The method assumes that the element being checked is in the same tab as the parent tab. If the element is not in the same tab, the method will return incorrect results.
2. The method uses `GetElementFromPoint` to get an element from a point on the screen. However, this method can be slow and may not always work correctly.
3. The method compares the outer HTML of the two elements to determine if they are the same. This may not always be accurate, as the outer HTML of two elements can be different even if they represent the same element.
To optimize this method, you could consider the following improvements:
1. Use a more robust method for checking if an element is in the same tab as the parent tab, such as comparing the `TabId` property of the two tabs.
2. Use a faster method for getting an element from a point on the screen, such as using the `GetElementFromPoint` method with a higher `ZIndex` parameter.
3. Use a more robust method for comparing the outer HTML of two elements, such as comparing the `Id` property of the two elements or using a library like `HtmlAgilityPack` to parse and compare the HTML code.
Here is an example of how you could optimize the method:
____________
Как видим, модель достаточно подробно и ясно ответила на вопрос и предложила изменения в коде. Первые два поинта оказались не особо релевантными, но по тексту видно, что лишь потому, что модель по понятным причинам не в курсе применения и особенностей работы Zenno и его API. Однако третий поинт был абсолютно релевантен, модель указала на мои косяки и исправила их.
How do you think, how it's possible to optimize that method:
C#:
public static bool IsFreeFromPopups (this HtmlElement elCheck)
{
var tab = elCheck.ParentTab;
int x = elCheck.DisplacementInTabWindow.X + elCheck.Width / 2;
int y = elCheck.DisplacementInTabWindow.Y + elCheck.Height / 2;
var elFromPoint = tab.GetElementFromPoint(x, y);
if (elFromPoint.OuterHtml == elCheck.OuterHtml)
{
return true;
}
return false;
}
The `IsFreeFromPopups` method is a simple method that checks if an element is free from pop-ups by checking the element's position and comparing it to the position of another element. However, there are some potential issues with this method:
1. The method assumes that the element being checked is in the same tab as the parent tab. If the element is not in the same tab, the method will return incorrect results.
2. The method uses `GetElementFromPoint` to get an element from a point on the screen. However, this method can be slow and may not always work correctly.
3. The method compares the outer HTML of the two elements to determine if they are the same. This may not always be accurate, as the outer HTML of two elements can be different even if they represent the same element.
To optimize this method, you could consider the following improvements:
1. Use a more robust method for checking if an element is in the same tab as the parent tab, such as comparing the `TabId` property of the two tabs.
2. Use a faster method for getting an element from a point on the screen, such as using the `GetElementFromPoint` method with a higher `ZIndex` parameter.
3. Use a more robust method for comparing the outer HTML of two elements, such as comparing the `Id` property of the two elements or using a library like `HtmlAgilityPack` to parse and compare the HTML code.
Here is an example of how you could optimize the method:
C#:
public static bool IsFreeFromPopups (this HtmlElement elCheck)
{
var tab = elCheck.ParentTab;
int x = elCheck.DisplacementInTabWindow.X + elCheck.Width / 2;
int y = elCheck.DisplacementInTabWindow.Y + elCheck.Height / 2;
var elFromPoint = tab.GetElementFromPoint(x, y, ZIndex.Max);
if (elFromPoint != null && elFromPoint.Id == elCheck.Id)
{
return true;
}
return false;
}
Как видим, модель достаточно подробно и ясно ответила на вопрос и предложила изменения в коде. Первые два поинта оказались не особо релевантными, но по тексту видно, что лишь потому, что модель по понятным причинам не в курсе применения и особенностей работы Zenno и его API. Однако третий поинт был абсолютно релевантен, модель указала на мои косяки и исправила их.
В данном случае мне надо было распарсить значения bounds по переменным у элемента в ZennoDroid, но мне лень было писать для этого код или регулярку.
Промпт:
Please, write code that parsing integer values "x1", "y1", "x2", "y2" via C#. Input string:
string bounds = "[90,875][989,1015]";
Ответ модели:
Here is a simple C# program that parses the input string and extracts the integer values for "x1", "y1", "x2", and "y2":
This program uses regular expressions to find all occurrences of the pattern "\[(\d+),(\d+)\]" in the input string. This pattern matches a left square bracket, followed by one or more digits (captured as group 1), a comma, one or more digits (captured as group 2), and a right square bracket.
The program then checks if there are exactly two matches. If so, it parses the captured groups as integers and prints them out. If not, it prints an error message.
____________
Конкретно данный случай внезапно оказался для меня особенно полезным, так как я вдруг узнал о существовании групп у регулярок. Регулярки я использую в проектах довольно редко, поэтому знания у меня по ним поверхностные – если про группы раньше и видел где-то, то сразу забыл. И тут я не просто получил ответ, но и узнал что-то новое для себя. Раньше, в случаях, когда надо использовать группы, я из-за незнания просто писал дополнительную обработку результатов регулярки C#-кодом, т.е., по сути, делал лишнюю работу.
Промпт:
Please, write code that parsing integer values "x1", "y1", "x2", "y2" via C#. Input string:
string bounds = "[90,875][989,1015]";
Ответ модели:
Here is a simple C# program that parses the input string and extracts the integer values for "x1", "y1", "x2", and "y2":
C#:
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string bounds = "[90,875][989,1015]";
MatchCollection matches = Regex.Matches(bounds, @"\[(\d+),(\d+)\]");
if (matches.Count == 2)
{
int x1 = int.Parse(matches[0].Groups[1].Value);
int y1 = int.Parse(matches[0].Groups[2].Value);
int x2 = int.Parse(matches[1].Groups[1].Value);
int y2 = int.Parse(matches[1].Groups[2].Value);
Console.WriteLine("x1: " + x1);
Console.WriteLine("y1: " + y1);
Console.WriteLine("x2: " + x2);
Console.WriteLine("y2: " + y2);
}
else
{
Console.WriteLine("Invalid input format.");
}
}
}
The program then checks if there are exactly two matches. If so, it parses the captured groups as integers and prints them out. If not, it prints an error message.
____________
Конкретно данный случай внезапно оказался для меня особенно полезным, так как я вдруг узнал о существовании групп у регулярок. Регулярки я использую в проектах довольно редко, поэтому знания у меня по ним поверхностные – если про группы раньше и видел где-то, то сразу забыл. И тут я не просто получил ответ, но и узнал что-то новое для себя. Раньше, в случаях, когда надо использовать группы, я из-за незнания просто писал дополнительную обработку результатов регулярки C#-кодом, т.е., по сути, делал лишнюю работу.
Поэтому можно просто сразу просить модель давать только имплементацию или содержимое тело метода. Посмотрим на примере того же распарса «bounds».
Промпт:
Please, write code snippet that parsing integer values "x1", "y1", "x2", "y2" via C#.
Write only inner statements without method implementation.
Input string:"[90,875][989,1015]";
Ответ модели:
Here is the code snippet to parse integer values "x1", "y1", "x2", "y2" from the input string:
In this code, we first split the input string into parts using '[' and ']' as delimiters. Then we take the second part (index 1) which contains the coordinates. We split this part again using ',' as a delimiter to get individual coordinates. Finally, we parse these strings into integers using `int.Parse` method.
Please, write code snippet that parsing integer values "x1", "y1", "x2", "y2" via C#.
Write only inner statements without method implementation.
Input string:"[90,875][989,1015]";
Ответ модели:
Here is the code snippet to parse integer values "x1", "y1", "x2", "y2" from the input string:
C#:
string[] parts = inputString.Split('[')[1].Split(']')[0].Split(',');
int x1 = int.Parse(parts[0]);
int y1 = int.Parse(parts[1]);
int x2 = int.Parse(parts[2]);
int y2 = int.Parse(parts[3]);
Если вы пишите код для Zenno в какой-нибудь IDE, как и я – существуют ещё плагины для сред разработки, такие как GitHub Copilot и Codeium. По сути, это интеграции функционала LLM прямо IDE. Лично мне они показались не очень удобными и полезными в моём случае, поэтому я ничем таким на данный момент не пользуюсь. Тем не менее, некоторые разработчики находят их полезными, возможно, они пригодятся и вам.
Да, стоит сказать, что упомянутые выше плагины проприетарные, со всеми сопутствующими минусами. Есть ещё компромиссные варианты с гибкой настройкой, пример – плагин Continue. К нему можно прокинуть любую модель на свой вкус (в том числе через тот же «LM Studio» в режиме сервера) и настроить под свои нужды. Вот этим конкретно мне например уже интересно заняться, но на момент написания статьи ещё не добрался.
Как ещё можно улучшить ответы
Несмотря на все плюшки LLM для нашего случая, есть один минус – модели либо ничего не знают о продуктах Zennolab и особенностях их использования, либо в лучшем случае такая информация у них затеряна среди тонны других данных обо всём на свете. Поэтому на вопросы сугубо по инфраструктуре Zenno, документации и API модели будут отвечать в лучшем случае посредственно. Однако, существуют способы «прокачать» модели так, чтобы они учитывали базу знаний по Zenno, могли отвечать развёрнуто именно по ней.
Соответственно, под конец немного поговорим о двух таких способах.
RAG (Retrieval Augmented Generation)
Этот метод представляет собой возможность дать доступ модели к вашей базе данных, чтобы она при ответе на запросы использовала соответствующие знания. Как именно это примерно работает.
- Надо собрать кучу релевантных документов (почти сколько угодно много) – например, всю документацию и справку Zenno, документацию макросов, все технические статьи с форума, все полезные топики и сообщения с форума (ну или вообще все).
- Далее это всё надо нарезать на небольшие кусочки текста (chunks) и скормить специальной модели-эмбеддеру, которая переведёт всё это добро в векторную базу данных. Все данные будут там хранится в виде эмбеддингов (векторов) – в сравнительно компактном виде, и при этом понятном, «родном» для LLM.
- При запросе к LLM текст промпта будет сначала преобразован в вектор, и по векторной БД будет произведён поиск наиболее близких (релевантных) данных/документов. Вектор запроса + найденные в базе вектора объединяются в единый промпт (вопрос + контекст) и доходят до LLM.
- Наконец, модель отвечает на такой запрос, используя данные контекста, т.е., например пару релевантных статей или страниц из документации ZennoLab.
Почему:
- Очень важно, насколько хорошо база знаний будет нарезана на куски. Если пользоваться простыми автоматическими «нарезателями», то качество знаний и связий между ними в базе векторов будет очень и очень посредственное, что сильно повлияет и на ответы. В идеале надо осмысленно (с хорошим пониманием того, как это работает) в ручном или полуручном режиме нарезать исходные документы на чанки. В базе могут быть сотни и тысячи документов (в нашем случае страниц в документации, статей и сообщений на форуме), т.е. для хорошего результата это достаточно много работы.
- Даже если вы отлично нарезали базу, много ещё зависит и от модели-эмбеддера, которая будет «оцифровывать» чанки в векторную БД. Большинство имеющихся моделей заточено на данные на английском языке. Конкретно под русский есть, но насколько они проигрывают передовым на английском – вопрос. Плюс, с одной моделью у вас может получится результат лучше, чем с другими, и заранее неизвестно, какая именно модель-эмбеддер сформирует базу конкретно в вашем случае.
Резюмируя – RAG инструмент потенциально очень мощный, но для хорошего результата обычно требует значительное количество усилий.
Fine-tuning (дообучение).
Файн-тюнинг по сути своей представляет дообучение изначальной модели на вашем специализированном датасете. На данный момент существует достаточно много видов и подходов к файн-тюнингу. Плюс к тому, большинство открытых специализированных моделей, размещённых на том же HuggingFace – это именно файн-тюны Llama и других открытых LLM.
В нашем случае для файн-тюнинга модели надо собрать датасет по требуемой базе знаний – то есть взять те же документацию Zennolab, статьи и прочее с форума, и соорудить из них датасет, пригодный для дообучения.
Далее надо будет дообучить исходную модель на этом датасете, для этого скорее всего понадобиться покупать GPU-часы у какого-нибудь провайдера серверов со специализированными GPU. Насколько долго это продлится и сколько будет стоить – зависит от исходной модели, размера датасета, метода файн-тюнинга. Но, понятное дело, в наших масштабах это будет не сильно дорогое дело, тем более ни в какое сравнение не идёт с затратами на претрейн оригинальных моделей, на который компании обычно тратят миллионы долларов.
Также вам понадобится составить свой бенчмарк для оценки ответов, чтобы сравнивать ответы моделей до и после файн-тюнинга по нашей базе знаний. К тому же, маловероятно, что с первого раза у вас получится хороший результат, и надо будет как-то оценивать все получаемые файн-тюны.
Плюс ко всему, для занятия файн-тюнингом в идеале иметь компетенции в Machine Learning (ML), так как соответствующих нюансов при дообучении моделей хватает.
Резюмируя – с помощью файн-тюнинга можно получить специализированную модель-ассистента, которая, по сути, будет прекрасно ориентироваться в базе знаний Zenno и давать шикарные ответы по теме, но для хорошего результата почти наверняка понадобится временных и финансовых затрат ещё больше, чем для хорошей реализации RAG.
Как итог, что RAG, что Fine-tuning – крайне мощные и перспективные инструменты для «заточки» моделей под специфическую сферу знаний по типу экосистемы Zenno. Однако, когда речь идёт об одиночном разработчике шаблонов для Zenno – это скорее избыточные инструменты ввиду большого объёма трудозатрат. Но для организованных команд разработчиков или Zenno-энтузиастов, а также самой компании Zennolab – думаю, вполне посильная и имеющая смысл задача. Возможно, в будущем кто-нибудь сделает что-то подобное конкретно под Zenno. Если, конечно, до этого не появится какой-нибудь AGI, который за счёт своей продвинутости сделает неактуальным все эти вещи (или просто убьёт нас всех ).
Всем огромное спасибо за внимание! Успехов вам как на поприще Zenno, так и в обычной жизни.
Последнее редактирование: