Главная / Статьи / JSON, JSONL и TOON: какой формат данных под какое узкое место

JSON, JSONL и TOON: какой формат данных под какое узкое место

Сравниваем JSON, JSONL и TOON по тому, какую проблему решает каждый: примеры бок о бок, заметки об экономии токенов на входе LLM и подсказки, как выбрать.

1528 слов

Годами JSON был способом по умолчанию записывать структурированные данные. На нём держатся REST API, конфиги, базы данных, браузерные приложения и обмен между сервисами. Но то, как софт работает с данными, продолжает меняться. Датасеты огромные, события приходят потоками, а большие языковые модели теперь принимают структурированные данные на вход.

Из-за этого внимание привлекли ещё два формата: JSONL и TOON. На первый взгляд они похожи на соперников JSON, но каждый отвечает на свой вопрос. JSON создан для обмена структурированными данными. JSONL — для эффективной обработки независимых записей. TOON — чтобы данные в форме JSON становились компактнее и дешевле по токенам, когда их отправляют в LLM. Спрашивать, какой из них «лучше», — значит упускать суть. Полезнее понимать, для чего нужен каждый.

JSON: универсальная база

JSON, сокращение от JavaScript Object Notation, описывает данные объектами, массивами, строками, числами, булевыми значениями и null. Главная сила не в синтаксисе, а в экосистеме вокруг него: почти в каждом языке программирования есть библиотека для JSON, а веб-платформы поддерживают его нативно.

Типичный набор данных выглядит так:

{
  "users": [
    {
      "id": 1,
      "name": "Alice",
      "role": "admin"
    },
    {
      "id": 2,
      "name": "Bob",
      "role": "user"
    }
  ]
}

Такая форма подходит приложению, которому нужно передать структурированную информацию, поэтому JSON хорошо ложится на REST API, конфигурацию, данные приложения и любые случаи, где вся структура разумного размера.

Проблемы начинаются, когда ту же форму растягивают на очень большие датасеты или когда LLM должна прочитать тысячи похожих объектов.

JSONL: одна запись на строку

JSONL расшифровывается как JSON Lines. Вместо того чтобы заворачивать все записи в один большой массив, он пишет полноценный JSON-объект на каждой строке. Тех же пользователей можно хранить так:

{"id":1,"name":"Alice","role":"admin"}
{"id":2,"name":"Bob","role":"user"}
{"id":3,"name":"Carol","role":"user"}

Каждая строка — независимая запись. Выглядит как мелкая правка синтаксиса, но она меняет то, как можно обращаться с данными. Большой JSON-массив может вынудить программу разобрать всю структуру, прежде чем она доберётся хоть до одной записи. С JSONL программа читает строку, парсит её, обрабатывает и переходит к следующей.

Сильнее всего это окупается на лог-файлах, потоках событий, обучающих наборах для ML, ETL-задачах и любых других данных, которые велики или постоянно растут. Возьмём датасет на 50 ГБ. Загружать его целиком как один гигантский объект почти никогда не нужно. С JSONL записи можно обрабатывать постепенно, и память уходит в основном на те записи, которые обрабатываются прямо сейчас.

То есть JSONL решает задачу обработки данных.

TOON: меньше токенов для модели

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

{
  "users": [
    {"id": 1, "name": "Alice", "role": "admin"},
    {"id": 2, "name": "Bob", "role": "user"},
    {"id": 3, "name": "Carol", "role": "user"}
  ]
}

Посмотрите, как "id", "name" и "role" повторяются в каждом объекте. Обычному софту это почти безразлично. А вот для LLM все эти символы увеличивают число входных токенов.

Именно этот пробел закрывает TOON, Token-Oriented Object Notation. Это компактная и читаемая человеком кодировка модели данных JSON, рассчитанная в первую очередь на промпты и другие контексты, где важен расход токенов. Те же записи выглядят так:

users[3]{id,name,role}:
  1,Alice,admin
  2,Bob,user
  3,Carol,user

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

Какой вопрос задаёт каждый формат

Один из способов не путать эти три формата — посмотреть, что каждый пытается решить.

  • JSON: как представить структурированные данные в формате, который поддерживают все.
  • JSONL: как представить множество независимых записей, чтобы их можно было обрабатывать по частям.
  • TOON: как компактнее записать данные в форме JSON, когда они отправляются в LLM.

Поэтому JSONL и TOON не заменяют друг друга. JSONL меняет то, как организованы записи. TOON меняет то, как представлены структурированные данные, ради экономии токенов. А JSON во многих таких процессах остаётся под ними как универсальный формат.

Сценарий первый: нагруженный пайплайн логов

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

User logged in
Payment completed
Order created
Email sent

Если хранить эти события как отдельные JSON-объекты, по одному на строку, потребитель сможет обрабатывать их по мере поступления. Здесь JSONL и хорош. Он подходит для данных, которые велики, только дописываются, производятся непрерывно или по своей природе состоят из записей, так что его обычное место — логи, потоки событий, ML-пайплайны, ETL-системы и обработка больших данных.

JSON остаётся более естественным вариантом, когда вся структура — это один логический документ или когда приложения ждут обычный JSON API.

Сценарий второй: агент читает 10 000 клиентов

Теперь ИИ-агенту нужна информация о 10 000 клиентах. Если отправить её записями в стиле JSON, каждая строка повторяет свои ключи:

{"id":1,"name":"Alice","city":"Delhi"}
{"id":2,"name":"Bob","city":"Mumbai"}
{"id":3,"name":"Carol","city":"Pune"}

TOON может разложить однородную коллекцию в таблицу, указав имена полей один раз:

customers[3]{id,name,city}:
  1,Alice,Delhi
  2,Bob,Mumbai
  3,Carol,Pune

Отсюда и берётся экономия токенов. Согласно спецификации, TOON — это построчная кодировка на отступах для той же модели данных, что и у JSON, и каждый массив объявляет свою длину и список полей лишь один раз.

Проект также приводит бенчмарки, где на тестовых датасетах TOON расходовал заметно меньше токенов, чем отформатированный JSON. Но сколько вы сэкономите, зависит от формы данных и от токенизатора. TOON не становится автоматически лучше для любого датасета. Больше всего он выигрывает на однородных массивах объектов с повторяющимися полями.

Заменит ли TOON JSON?

Сказать так заманчиво, но слишком просто. Сама спецификация подаёт TOON прежде всего как представление для данных в форме JSON. В ней сказано, что TOON не предназначен заменять JSON в универсальных API, а также в случаях с глубокой вложенностью или неоднородной структурой.

Реалистичный процесс оставляет JSON там, где он уже работает, и добавляет TOON только на границе с моделью:

Application data
      ↓
    JSON
      ↓
Convert for LLM
      ↓
    TOON
      ↓
     LLM

JSON остаётся родным представлением приложения, а TOON становится форматом, в котором структурированные данные уходят в LLM. В этой роли TOON больше похож на слой перевода, чем на универсальную замену.

Использовать вместе

Эти форматы могут уживаться и в одной архитектуре. JSONL отвечает за то, как записи организованы и обрабатываются. TOON — за то, как эффективно представить структурированные данные для LLM. Приложение может выдавать большой поток записей в JSONL, обрабатывать их постепенно, отбирать нужное подмножество и уже его кодировать в TOON перед отправкой в модель.

Каждый формат снимает своё узкое место. JSONL помогает с обработкой записей в больших масштабах, TOON — с экономией токенов, а JSON — с универсальной совместимостью.

Как выбрать

Берите JSON, когда нужен широко поддерживаемый универсальный способ хранить структурированные данные. Публичные API, браузерные приложения, конфиги и датасеты скромного размера — очевидные случаи. Мало какой формат сравнится с ним по инструментам, а для небольшого обычного набора данных нет причин тащить что-то другое.

Присмотритесь к JSONL, когда данные — это груда независимых записей, которые хочется обрабатывать постепенно. Логи, потоки событий, обучающие данные для ML, ETL-пайплайны и большие датасеты — сильные примеры. Решающий вопрос: нужно ли обрабатывать весь датасет как одну структуру или достаточно по одной записи за раз. Если второе, JSONL стоит рассмотреть.

Присмотритесь к TOON, когда потребитель — LLM, а в данных много повторяющихся структурированных записей. Он подходит для однородных массивов, где одни и те же поля встречаются во множестве объектов, и именно это спецификация называет его сильной стороной. Глубоко вложенные или очень нерегулярные данные в JSON могут оказаться проще или даже меньше. Спросите себя, не тратятся ли токены на то, чтобы снова и снова описывать одну и ту же структуру. Если да, TOON заслуживает проверки.

Разное давление — разные форматы

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

Так что правильная модель в голове — это не цепочка, в конце которой JSON умирает. Она такая: JSON для универсальной структуры, JSONL для обработки записей в больших масштабах, TOON для экономного по токенам входа LLM. Вряд ли какой-то один формат заменит все остальные. Разумнее выбирать представление под то узкое место, которое у вас действительно есть.