Вы потратили день, чтобы запустить Qwen3-VL-8B на своем ноутбуке. Настроили пайплайн извлечения данных из PDF. Модель работает, но вместо аккуратного JSON выдает:
{
"name": "Иван Петров",
"age": 35,
"profession": "Разработчик",
// Модель решила добавить комментарий
"skills": ["JavaScript", "TypeScript", "Python"
// Забыла закрыть массив
}Или такой подарочек:
Конечно, вот данные в JSON: {
"title": "Отчет",
"date": "2026-02-03",
"content": "Текст с кавычками \"внутри\" и переносами\nстрок"
}
Надеюсь, это поможет!JSON.parse() падает. Пайплайн стопится. Вы лезете в дебаггер и проклинаете всех идиотов, которые придумали локальные модели. Знакомо?
К 2026 году даже маленькие модели вроде Llama 3.2 3B, Qwen3-1.5B и Mistral-Nemo научились выполнять структурированные задачи, но JSON-вывод по-прежнему хромает. В этой статье я собрал каталог типовых ошибок, которые ломают парсеры, и показываю, как библиотека Loot-JSON превращает этот хаос в рабочие данные.
Каталог ошибок: что именно ломается
Я проанализировал около 500 ответов от разных локальных моделей (эксперимент из статьи «Почему LLM ломают JSON-парсеры: бенчмарк 672 вызовов») и выделил 7 основных типов сбоев. Вот они в порядке частоты:
| Тип ошибки | Частота | Пример |
|---|---|---|
| Лишний текст до/после JSON | ~35% | "Вот ваш JSON: {\"key\":\"value\"} Спасибо!" |
| Незакрытые строки/символы | ~25% | {"text": "Hello |
| Одиночные кавычки вместо двойных | ~15% | {'key': 'value'} |
| Лишние запятые в конце массивов/объектов | ~10% | {"a":1,} |
| Комментарии (//, /* */) | ~8% | {//comment "key":1} |
| Некорректное экранирование | ~5% | "path\to\file" |
| Пропущенные кавычки у ключей | ~2% | {key: "value"} |
Эти ошибки убивают до 40% вызовов JSON.parse() в типовом пайплайне. Хуже всего то, что модель может выдать идеальный JSON в одном запуске и полную кашу в следующем.
Как Loot-JSON вытаскивает данные из мусора
Библиотека Loot-JSON — это не очередной «улучшенный парсер». Это хирургический станок, который делает три вещи:
- Вырезает JSON из окружающего текста (убирает предисловия, постскриптумы, обёртки типа «Вот данные:»)
- Лечит синтаксические ошибки (незакрытые скобки, лишние запятые, одиночные кавычки)
- Экранирует спецсимволы внутри строк (переносы, кавычки, обратные слеши)
Установка:
npm install loot-json
# или
bun add loot-jsonВот как это выглядит в коде. Допустим, модель ответила мешаниной:
import { lootJson } from 'loot-json';
const dirtyResponse = `Пользователь запросил данные. Вот JSON: {
"name": "Анна",
"age": 28
} Надеюсь, это поможет!`;
const cleanJson = lootJson(dirtyResponse);
console.log(cleanJson); // {"name":"Анна","age":28}
const data = JSON.parse(cleanJson); // Всё окБиблиотека ищет первый объект или массив в потоке текста и пытается восстановить его до валидного состояния. Если JSON повреждён необратимо — возвращается null или выбрасывается ошибка (в зависимости от настроек).
Совет: Loot-JSON не волшебная палочка. Если модель выдала текст без единого символа { или [, библиотека бессильна. Но в 9 из 10 случаев она превращает "надеюсь это поможет" в рабочие данные.
Сравнение с альтернативами
На рынке есть несколько решений для восстановления JSON. Вот что предлагают конкуренты:
| Инструмент | Умеет вырезать из текста | Фиксит синтаксис | Экранирование | Размер |
|---|---|---|---|---|
| Loot-JSON | Да | Да | Да | ~3 KB |
| jsonrepair (Jos de Jong) | Нет (только чистый JSON) | Да (лучше) | Частично | ~5 KB |
| JSON.parse + try/catch | Нет | Нет | Нет | 0 KB |
| fast-json-parse | Нет | Нет (только safe parse) | Нет | ~1 KB |
jsonrepair — мощный инструмент, но он не умеет извлекать JSON из обрамляющего текста. Если модель обернула ответ в пояснения, jsonrepair выдаст ошибку. Loot-JSON сначала вырезает, потом чинит. По качеству исправления синтаксиса Loot-JSON чуть уступает jsonrepair (у того более богатый набор правил), но зато покрывает кейс, который встречается в 35% случаев — лишний текст вокруг.
Если ваш сценарий — строгий JSON без лишнего текста, выбирайте jsonrepair. Если же вы работаете с локальными LLM, где модель постоянно болтает — Loot-JSON незаменим.
Глубокое погружение: как Loot-JSON чинит каждую ошибку
Разберём каждый тип сбоя и покажем, как библиотека с ним справляется.
1 Лишний текст до/после
Алгоритм: пробегает строку, находит первое вхождение { или [, затем отслеживает баланс скобок до конца. Если в конце остаётся мусор — отбрасывает его. Результат — чистый JSON.
lootJson('Объяснение: {"a":1} конец');
// -> {"a":1}2 Незакрытые строки и символы
Модель часто забывает закрыть строку или массив. Loot-JSON дописывает недостающие кавычки и скобки, анализируя контекст.
lootJson('{"text": "Hello');
// -> {"text": "Hello"}3 Одиночные кавычки
Заменяет одинарные кавычки на двойные, но только если это не мешает логике (например, внутри строк с апострофами — но таких случаев почти нет).
lootJson("{'key': 'value'}");
// -> {"key": "value"}4 Лишние запятые и комментарии
Удаляет запятые перед закрывающими скобками и вырезает однострочные/многострочные комментарии.
lootJson('{"a":1, /*comment*/}');
// -> {"a":1}Подробнее о том, почему даже с параметром strict в VLLM или llama.cpp модели продолжают ошибаться, читайте в статье «Параметр strict в VLLM и llama.cpp: почему он ничего не делает и как с этим жить». Спойлер: strict не гарантирует валидный JSON, он лишь форсирует грамматику, но модели всё равно могут генерировать невалидные токены.
Когда одного парсера мало
Loot-JSON решает проблему на уровне вывода. Но часто корень зла глубже. Вы можете улучшить качество JSON на этапе промптинга или с помощью специальных протоколов. Например, SDF Protocol — это формат, который заставляет модель выдавать строго структурированные данные, практически исключая мусор. Мы в ecom.tech используем комбинацию: SDF на этапе запроса + Loot-JSON на этапе ответа. Это даёт 99.8% успешных парсингов.
Важно: Не надейтесь, что одна библиотека решит все проблемы. Если модель систематически выдаёт битый JSON — проверьте температуру, top_p и системный промпт. Иногда достаточно снизить температуру до 0.1, чтобы число ошибок упало вдвое.
Для тех, кто хочет понять, как именно LLM «думают» при генерации JSON и почему возникают типовые ошибки, рекомендую статью «Держите свой JSON: как заставить Mistral и Llama 3.1 перестать болтать и начать парсить». Там разобраны механики трансформеров, приводящие к «болтовне».
Кому подойдёт Loot-JSON?
- Разработчикам пайплайнов ETL/ELT на локальных моделях — вытаскивать данные из PDF, emails, логов.
- Инженерам, работающим с OpenRouter или другими прокси — даже API возвращают мусор, если модель маленькая.
- Создателям чат-ботов с функциями — когда LLM вызывает инструменты, JSON-аргументы часто битые.
- Исследователям, которые гоняют бенчмарки и хотят автоматически парсить сотни ответов.
Если ваш проект — ботаналитик на локальной LLM (как мы описывали в статье «Бот-аналитик на локальной LLM: как мы в ecom.tech разгрузили команду»), Loot-JSON станет обязательным слоем в пайплайне. Без него каждый десятый ответ будет ломать всю цепочку.