Строгий JSON вывод в локальных LLM: Mistral vs Llama 3.1 | AiManual
AiManual Logo Ai / Manual.
08 Янв 2026 Гайд

Держите свой JSON: как заставить Mistral и Llama 3.1 перестать болтать и начать парсить

Практическое сравнение методов получения стабильного JSON из локальных моделей. Промпты, настройки температуры и реальные тесты.

Почему ваш код ломается на полпути

Вы переходите с OpenAI на локальные модели. В теории всё просто: меняете endpoint, обновляете ключ API, и ваш агент продолжает парсить JSON как ни в чём не бывало. На практике же получаете в ответ поток сознания с парой фигурных скобок где-то посередине. Потом ещё комментарий от модели о том, как она старалась.

Проблема не в вашем коде. Проблема в том, что локальные модели обучены на текстах, а не на API-ответах. Они хотят объяснять, рассуждать, добавлять отступы. Ваш парсер хочет чистый JSON. И эти две реальности почти никогда не пересекаются.

Ключевое отличие от OpenAI: облачные модели обучены специально для API-ответов. Локальные — для диалогов. Это фундаментальная разница, которую нужно обходить, а не игнорировать.

Mistral Nemo: формалист с характером

Mistral Small (или Nemo в некоторых дистрибутивах) ведёт себя как прилежный студент: делает то, что просят, но иногда слишком буквально. Дайте ему инструкцию "выведи JSON", и он выведет JSON. С комментариями до и после. С лишними пробелами. С нестандартным форматированием.

Тест: запрашиваю список покупок в формате JSON с полями "item", "quantity", "category".

💡
Не используйте просто "верни JSON в ответе". Mistral интерпретирует это как "включи JSON куда-то в текст". Нужно явно запрещать всё лишнее.

1 Рабочий промпт для Mistral

После двух дней проб и ошибок я вывел формулу, которая работает в 95% случаев:

  • Начинайте с [INST] тегов — Mistral их понимает
  • Чётко определите роль: "Ты — JSON API endpoint"
  • Запретите любые пояснения до и после JSON
  • Укажите точную схему вывода
  • Установите temperature=0.1 (не ноль! ноль делает ответы слишком шаблонными)

Пример структуры промпта:

[INST] Ты — JSON API endpoint. Твой ответ должен содержать ТОЛЬКО валидный JSON без каких-либо пояснений, комментариев или дополнительного текста. Схема ответа: { "items": [ { "name": "string", "count": number } ] }. Задача: составить список из 3 продуктов для ужина. [/INST]

Llama 3.1 8B: болтун, которого нужно заткнуть

Если Mistral — формалист, то Llama 3.1 — это тот коллега, который начинает каждое совещание с истории про своего кота. Модель обожает объяснять свои действия. Даже когда вы явно просите её этого не делать.

Здесь работает другой подход. Llama 3.1 лучше реагирует на системные промпты в формате, похожем на её собственное обучение. Нужно играть по её правилам.

Параметр Mistral Small Llama 3.1 8B
Оптимальная temperature 0.1 0.3
Формат промпта [INST] инструкция [/INST] Системное сообщение + user
Скобки в ответе Иногда забывает закрывающие Любит добавлять лишние
Стабильность вывода 8/10 6/10

2 Системный промпт для Llama 3.1

Вместо того чтобы бороться с болтливостью Llama, используйте её. Дайте модели пространство для "размышлений", но строго ограничьте формат вывода.

Работающая структура:

  1. Системное сообщение: "Ты — помощник, который всегда отвечает в формате JSON."
  2. User запрос с явным указанием: "Верни ответ ТОЛЬКО в виде JSON объекта."
  3. Пример ожидаемого вывода прямо в промпте
  4. Параметр min_p=0.1 (это помогает избежать абсолютно случайных ответов)

Инструменты, которые спасают нервы

Писать идеальные промпты — это искусство. Но есть инструменты, которые делают процесс менее болезненным.

LM Studio: не только для чатов

Большинство используют LM Studio как красивый интерфейс для общения с моделями. Мало кто знает, что там есть продвинутые настройки генерации, которые критически важны для JSON вывода.

  • Grammar sampling — заставляйте модель следовать точной схеме JSON
  • Stop sequences — установите "}" как стоп-слово, чтобы модель не продолжала после закрывающей скобки
  • Preset меню — сохраняйте рабочие комбинации temperature, top_p, min_p для разных задач

Если вы ещё не пробовали Router Mode в llama.cpp для переключения между моделями в зависимости от задачи — самое время. Mistral для строгих JSON ответов, Llama для творческих задач.

llama.cpp с grammars.json

Это секретное оружие. Файл grammars.json позволяет описать точную структуру JSON, которую должна выдать модель. Модель физически не сможет выдать невалидный JSON — система отсечёт некорректные токены на уровне генерации.

Настройка занимает 10 минут. Результат — 99.9% валидных JSON ответов. Даже от самых болтливых моделей.

💡
Grammar файлы работают только с llama.cpp и совместимыми обёртками. В Open WebUI или других фронтендах для OpenAI-совместимого API эта функция может быть недоступна.

Три ошибки, которые совершают все

  1. Temperature=0. Кажется логичным: ноль температуры — нулевая случайность. На практике модели с temperature=0 начинают "залипать" на шаблонных ответах и могут выдавать некорректный JSON из-за излишней уверенности в первых токенах.
  2. Один промпт для всех моделей. То, что работает для GPT-4, не работает для Llama. То, что работает для Llama, ломает Mistral. Каждая модель требует своего подхода.
  3. Попытки парсить "грязный" JSON. Не пишите костыли для очистки ответов. Лучше потратить час на настройку правильного промпта, чем годы поддерживать хрупкий парсер.

Что делать, если ничего не помогает

Бывают ситуации, когда модель упорно отказывается сотрудничать. Обычно это происходит со старыми версиями или сильно квантованными моделями.

Мой стек решений на такой случай:

  • Перейти на модель, специально обученную для структурированных ответов (не все об этом знают, но такие существуют)
  • Использовать post-processing: генерировать ответ, затем отправлять его той же модели с инструкцией "извлеки JSON из этого текста"
  • Добавить валидацию JSON в самом начале контекста, чтобы модель "видела" правильный формат

Иногда помогает банальное перефразирование запроса. Вместо "выведи JSON" попробуйте "сгенерируй JSON объект с такими полями". Разница кажется незначительной, но для модели это разные инструкции.

Итог: какая модель лучше для JSON?

После недели тестов на десятках запросов:

  • Mistral Small/Nemo выигрывает в стабильности. Раз настроил промпт — работает как часы. Но требует жёстких инструкций.
  • Llama 3.1 8B более гибкая, но непредсказуемая. Лучше справляется со сложными схемами, но может внезапно добавить комментарий.
  • Для production-систем с критичным JSON выводом я бы выбрал Mistral с grammar файлами.
  • Для исследовательских задач, где важен не только JSON, но и reasoning — Llama 3.1.

Самая большая ошибка — пытаться заставить локальные модели работать точно так же, как OpenAI. Они другие. И в этом есть своя прелесть. Нужно не бороться с их особенностями, а использовать их.

P.S. Если вы до сих пор мучаетесь с парсингом ответов — посмотрите на Router Mode в llama.cpp. Запускаете две модели параллельно: одна для строгих JSON ответов, другая для всего остального. И переключаетесь между ними без перезагрузки. Иногда лучшее решение — не заставить одну модель делать всё, а использовать несколько для разных задач.