Перейти к содержанию
Публикация AiManual

Кастомный harness или готовые инструменты вроде Unsloth: что выбрать для локальных LLM

Harness - это вся логика вокруг модели, поэтому выбор между своим кодом и готовыми инструментами вроде Unsloth или MLX Serve зависит от задачи. Разбираем, из че

Коротко

Что будет в материале

  1. 01

    Короткий ответ: harness - это обвязка, а не модель

  2. 02

    Что такое harness в LLM и из чего он состоит

  3. 03

    Unsloth и MLX Serve: это harness или нет

  4. 04

    Зачем строить кастомный harness: реальные причины

Короткий ответ: harness - это обвязка, а не модель

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

Метафора из обсуждения на r/LocalLLaMA точная: модель - двигатель, harness - весь автомобиль (тред). Двигатель без трансмиссии, руля и маршрута никуда не едет. Обратное тоже верно: кузов без мотора не поедет. Это два разных слоя, и путать их дорого.

Универсального ответа «берите готовое» или «стройте своё» нет. Unsloth и MLX Serve в строгом смысле не harness: первый связан с подготовкой и адаптацией модели, второй даёт доступ к модели по API. Набор функций у обоих зависит от версии, поэтому проверять его нужно в документации на конкретную дату. Дальше - как разграничить слои и по каким критериям выбрать.

Что такое harness в LLM и из чего он состоит

Рабочее определение: harness - слой между пользователем или приложением и моделью. Он превращает текстовый генератор в систему, которая умеет что-то делать. Типовые блоки:

  • Оркестрация запросов: системный промпт, история диалога, обрезка и переупаковка контекста при переполнении.
  • Вызов инструментов (tool calling): схемы инструментов, парсинг вызовов, валидация аргументов, повтор при ошибке.
  • Веб-поиск и RAG: запрос, загрузка страниц, извлечение фрагментов, ранжирование, вставка в контекст с цитатами.
  • Память: что сохранить между сессиями, что подгрузить, что выбросить.
  • Маршрутизация: какая модель обрабатывает запрос, когда включается маленькая локальная, когда большая.
  • Логирование и наблюдаемость: трассы вызовов, расход токенов, время ответа, причины падений.
  • Ограничения: белый список инструментов, лимиты на файлы и команды, подтверждение опасных действий.

Пример. Запрос «найди актуальные цены на две модели и сравни» требует минимум четырёх шагов: сформировать поисковые запросы, получить страницы, вырезать из них нужные фрагменты, собрать ответ с указанием источников. Модель участвует в каждом шаге, но последовательность задаёт harness.

Термин используют по-разному: в одних обсуждениях harness называют CLI-обёртку для кодинга, в других - весь агентный фреймворк. Договоритесь о значении до спора о выборе, иначе сравниваете разные вещи.

Чем harness отличается от модели и от fine-tuning

Три слоя, которые часто смешивают в один:

  1. Веса модели. Файлы с параметрами, часто в квантованном виде.
  2. Инференс-движок. Считает токены: llama.cpp, MLX, vLLM и их аналоги. От движка зависят скорость, поддержка квантований и формат API. Различия между движками разобраны в материале про overfit-рантаймы.
  3. Harness. Решает, что спросить у модели, с какими инструментами и что делать с ответом.

Fine-tuning меняет веса, harness их не трогает. Правка промптов и обвязки меняет поведение системы без переобучения, поэтому занимает минуты вместо часов на GPU. Аналогия: двигатель, трансмиссия и водитель с маршрутом. Мощность мотора не поможет, если маршрут проложен в стену.

Путаница возникает из-за упаковки. Готовые приложения совмещают движок, клиент и часть обвязки в одном интерфейсе. Пользователь видит один установочный файл и решает, что «всё уже есть».

Unsloth и MLX Serve: это harness или нет

Коротко: скорее нет. Это разные слои стека, и оба полезны, но задачу оркестрации поведения агента целиком они не закрывают.

Что реально умеет Unsloth, а что нет

Unsloth известен как библиотека для ускоренного fine-tuning, в первую очередь LoRA/QLoRA-адаптеров, с экономией памяти по сравнению со стандартными реализациями. Это работа с весами: вы готовите адаптер под свою задачу, а не описываете, как модель должна искать в вебе и вызывать инструменты.

В исходном обсуждении Unsloth упомянут как решение, у которого уже есть веб-поиск и tool calling. Воспринимайте это как формулировку автора вопроса, а не как проверенный факт: состав функций у быстро развивающихся проектов меняется от версии к версии, и сверять его нужно в документации. Даже если часть обвязки там появилась, fine-tuning и агентная оркестрация - разные задачи с разными издержками.

MLX Serve как слой запуска модели

Название отсылает к MLX, фреймворку Apple для вычислений на Apple Silicon. Серверная часть в этом стеке поднимает локальную модель и отдаёт к ней доступ по HTTP, чтобы с ней работали сторонние клиенты. Насколько API совместим с форматом OpenAI и какие эндпоинты доступны, зависит от конкретной реализации: сверяйтесь с документацией сборки, которую ставите.

Практический вывод: MLX Serve - двигатель с коробкой передач. Модель работает и отвечает на запросы, а поиск, инструменты, маршрутизацию и память к нему добавляют отдельно: готовым клиентом, готовым фреймворком или своим кодом. Сам по себе сервер не решает, что модели делать с найденной страницей.

Зачем строить кастомный harness: реальные причины

Совет «попроси Claude или ChatGPT собрать тебе harness» появляется в тредах, где у людей не получается результат с локальными моделями. Причины строить своё существуют, и они конкретные.

Контроль над логикой и интеграция в свои процессы

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

  • Свои источники данных. Внутренняя база знаний, тикеты, документация, локальные файлы. Нужен контроль над тем, что попадает в контекст и в каком порядке.
  • Внутренние API. Заказ в биллинге, запрос в CRM, запуск задачи в CI. Готовый клиент такие вызовы не поддержит, а MCP-сервер или собственный инструмент - да.
  • Жёсткий формат ответа. JSON по схеме, обязательные поля, цитата на каждый факт. Проверку схемы проще встроить в свой слой, чем надеяться на инструкции в промпте.
  • Аудит и воспроизводимость. Требование показать, какие инструменты вызывались и какие данные ушли в модель, часто решает выбор в пользу своего кода.
  • Метрики. Свои трассы вызовов, расход токенов, доля успешно закрытых задач.

Пример: пайплайн, который раз в сутки собирает изменения в документации, вытаскивает различия, прогоняет их через локальную модель и складывает отчёт в корпоративный мессенджер. Универсальный чат-клиент такое не сделает без вашего кода.

Эксперименты и обучение как отдельная цель

Автор обсуждения сам предполагает, что часть мотивации - тюнинг и эксперименты как хобби. Это честная причина. Если цель разобраться, как работает tool calling, что происходит с контекстом при длинных ответах и почему агент зацикливается, свой harness даёт ответ быстрее любого гайда.

Разница только в честности с собой: обучение и производственная необходимость - разные бюджеты. В первом случае нормально потратить выходные на код, который не пойдёт в работу. Во втором считайте стоимость поддержки и риск.

Издержки кастомной обвязки: что придётся заплатить

Самодельный harness - проект со своим жизненным циклом. Основные статьи расходов:

  • Поддержка кода. Обновления моделей, форматов квантования и API ломают совместимость. Свой веб-поиск - это запрос, парсинг, дедупликация, ранжирование, обрезка контекста и цитаты. Каждый пункт ломается по-своему.
  • Отладка промптов. Изменение одной инструкции меняет поведение на всех сценариях сразу. Нужен набор тестовых задач, иначе регрессии находят пользователи.
  • Обработка ошибок. Таймауты, повторы, частичные ответы, невалидный JSON от модели, пустой результат инструмента. На каждую ситуацию нужно решение.
  • Безопасность. Инъекции промптов через найденные страницы и прочитанные файлы, доступ инструментов к файловой системе и сети, подтверждение опасных действий. Готовые инструменты берут часть этого на себя.
  • Токены и время. Агентный цикл читает контекст многократно. Длинная история плюс результаты поиска быстро упираются в лимит окна, начинается обрезка, и качество падает.
  • Галлюцинации на стыках. Модель уверенно вызывает несуществующий инструмент или подставляет выдуманный аргумент. Валидация и повторные попытки - обязательная часть, а не улучшение.

Похожая логика работает и в других слоях стека: специализированный форк движка под одну модель обещает ускорение, но требует постоянного сопровождения. Разбор этой цены есть в материале про кастомную сборку llama.cpp. С harness то же самое, только ставки выше: ошибка в обвязке выглядит как «модель тупая», хотя модель может быть в порядке.

Практические критерии выбора: готовое или своё

Решайте по задаче, а не по принципу. Четыре вопроса отсекают лишнее:

  1. Задача типовая (чат, поиск, чтение документов) или в ней есть уникальная логика?
  2. Нужны свои данные, внутренние API или специфический формат ответа?
  3. Есть требования к аудиту и воспроизводимости?
  4. Кто будет поддерживать код через три месяца?

Когда достаточно готового инструмента

Признаки, что строить своё рано:

  • Сценарий стандартный: вопросы по документам, поиск в вебе, черновики текста, разбор файлов.
  • Своих источников и API нет.
  • Результат нужен сегодня, а не через две недели.
  • Нет ресурса на поддержку и тесты.
  • Вы ещё не поняли, чего именно не хватает: жалоба «плохо отвечает» чаще лечится моделью, квантованием и промптом, а не обвязкой.

Когда кастомный harness оправдан

  • Логика уникальна и повторяется: сбор данных из нескольких источников, вызовы внутренних сервисов, проверки по правилам.
  • Нужен контроль над тем, какие инструменты доступны и что логируется.
  • Требуется воспроизводимость: одинаковый вход даёт одинаковый маршрут обработки.
  • Идут эксперименты с агентными пайплайнами, нужна свобода менять каждый шаг.
  • Обучение - самостоятельная цель.

Между двумя крайностями есть рабочий вариант: готовый сервер локальной модели плюс лёгкая надстройка своим кодом на 200-500 строк. Сервер отвечает за инференс и API, скрипт - за поиск, инструменты и формат ответа. Такой гибрид закрывает большинство личных задач и не превращается во второй проект.

КритерийГотовый инструментКастомный harness
СценарийТиповой чат, поиск, документыУникальная логика и интеграции
Свои данные и APIНе нужны или хватает загрузки файловОбязательны
Время до результатаЧасыДни и недели
ПоддержкаНа разработчике инструментаНа вас
ГибкостьОграничена функциями инструментаПолная
Основной рискУпёрлись в потолок функцийУтонули в отладке и поддержке

Автор обсуждения прямо оговаривает, что ждёт разбора различий, а не универсального рецепта (тред). Это правильная рамка: выбор зависит от задачи, бюджета времени и готовности поддерживать код.

Как это выглядит на M5 Max и 64 ГБ RAM

Apple Silicon использует unified memory: CPU и GPU работают с одним пулом оперативной памяти. Для локальных LLM это удобно, потому что модель не нужно делить между дискретной видеопамятью и системной RAM. Практический потолок задаёт объём пула и скорость его чтения.

Прикидка по объёму: 4-битное квантование даёт примерно 0,5 ГБ на миллиард параметров плюс запас. Модель на 8B - около 5 ГБ весов, на 30B - около 18 ГБ, на 70B - около 40 ГБ. Это арифметика, а не замеры: к весам добавятся KV-кэш под длину контекста, буферы и сама система. 64 ГБ позволяют работать с моделями среднего размера с запасом на контекст, а на 70B остаётся мало места под длинные диалоги.

Скорость зависит от квантования, размера модели и длины контекста. Гоняться за большими числами токенов в секунду на такой машине смысла мало: агентный цикл с поиском и инструментами упирается в количество шагов, а не в один ответ.

Что это значит для выбора. На M5 Max реалистичны оба пути: готовый сервер с клиентом и лёгкий кастомный harness поверх того же API. MLX-стек ориентирован на Apple Silicon, поэтому он естественный кандидат в слой запуска. Многошаговые агенты с десятком инструментов на 30B-модели будут заметно медленнее облачных, и это стоит учитывать до того, как писать свой оркестратор.

С чего начать: последовательность шагов

  1. Освойте готовое. Поднимите локальный сервер с моделью и поработайте с ним неделю на своих реальных задачах. Записывайте, где именно не хватает функций.
  2. Добавьте тонкий слой. Скрипт, который вызывает локальный API, делает поиск и подставляет результаты в промпт, закрывает половину запросов «мне нужен свой harness». Для кодинга логика похожая: разбор того, как harness влияет на качество малых моделей, есть в материале little-coder против Pi.
  3. Стройте полноценную обвязку, когда появились требования. Логирование, валидация инструментов, обработка ошибок, тестовый набор задач. Связка модели и harness в локальном кодинге разобрана в статье про локальный coding: там видно, где заканчиваются возможности модели и начинается работа обвязки.
  4. Используйте Claude и ChatGPT как подрядчиков по коду. Они помогают написать парсер, схему инструментов или обработчик таймаутов. Архитектуру, отладку и ответственность за поведение системы они не берут.

Harness - инструмент под задачу, а не обязательный этап взросления в локальных LLM. Если готовая связка сервера и клиента даёт нужный результат, стройте своё только тогда, когда появилась причина, которую можно назвать одним предложением.

Подписаться на канал