JSONSchemaBench: Складність реальних схем порушує гарантії структурованого виводу LLM
Більшість команд розглядають обмежене декодування як вирішену проблему — додайте схему JSON і отримайте валідний JSON. JSONSchemaBench (arXiv:2501.10868) — це перша систематична спроба перевірити це припущення на 9 558 реальних схемах, і результати виявилися менш обнадійливими, ніж обіцяє маркетинг.
Про статтю
Сайбо Генг, Хадсон Купер, Міхал Москаль та колеги з Microsoft Research представляють JSONSchemaBench, бенчмарк з 9 558 схем, зібраних з реальних виробничих джерел: сигнатур викликів функцій GlaiveAI, репозиторіїв GitHub, стратифікованих за складністю від тривіальних до ультраскладних, конфігурацій API Kubernetes, схем аналітики подій Snowplow та колекції JSONSchemaStore. Вони оцінюють шість фреймворків обмеженого декодування — Guidance, Outlines, Llamacpp, XGrammar, OpenAI Structured Outputs та Gemini — за трьома осями: покриття (яку частку схем фреймворк взагалі може обробити), ефективність (накладні витрати токенів за секунду порівняно з необмеженою генерацією) та якість (точність виконання прикладних завдань). Сітка оцінювання також включає офіційний тестовий набір JSON Schema Test Suite, який документує 45 категорій функцій, які повинен підтримувати будь-який сумісний рушій.
Основне твердження полягає в тому, що складність схеми є вирішальною змінною, яка відділяє здатні фреймворки від крихких, і що жоден фреймворк не домінує за всіма трьома осями.
Ключові ідеї
- Покриття руйнується під тиском складності схем. На простих схемах GlaiveAI всі фреймворки демонструють результат вище 86%. Але на схемах GitHub-Hard — з багаторівневою вкладеністю, рекурсивними визначеннями та складними обмеженнями патернів — покриття Guidance падає до 41%, Llamacpp до 39%, XGrammar до 28%, а Outlines до катастрофічних 3%. OpenAI досягає лише 9% на GitHub-Hard, а Gemini не видає жодного валідного результату на схемах середньої складності або вище.
- Kubernetes виявляє специфічну слабкість XGrammar. Попри заяви XGrammar про швидкість, він досягає лише 7% покриття на схемах Kubernetes, ймовірно тому, що ці схеми покладаються на контекстно-залежні патерни, які контекстно-незалежні попередні обчислення XGrammar не можуть обробити. Покриття проти бенчмарка, що включає конфігурації Kubernetes, не є опціональним для виробничих агентів.
- Недостатнє обмеження небезпечніше за помилку компіляції. XGrammar демонструє 38 відмов через недостатнє обмеження (under-constrained failures) у тестовому наборі JSON Schema — це означає, що він видає JSON, який порушує заявлену схему, але при цьому мовчки повідомляє про успіх. Guidance має лише 1 таку відмову. Для агента зворотного запису помилка компіляції виявляється під час розробки; відмова через недостатнє обмеження пошкоджує дані під час виконання без будь-якого сигналу.
- Швидке перемотування Guidance забезпечує реальне прискорення на 50%. Коли присутні довгі детерміновані послідовності (наприклад, імена полів у фіксованій структурі об'єкта), Guidance може просуватися на кілька токенів за один крок декодування. На Llama-3.1-8B на A100 Guidance працює зі швидкістю 6–9 мс на вихідний токен, тоді як необмежена генерація — 15–16 мс. Outlines працює повільніше за необмежену генерацію (30–46 мс), переважно через попередню компіляцію автомата, яка займає 3–8 секунд на схему.
- Обмежене декодування помірно покращує точність міркувань. На GSM8K (математика) Guidance підвищує точність з 80,1% (необмежена генерація) до 83,8%. На завданнях Last Letter та Shuffle Objects приріст становить 1–3 пункти. Це суперечить поширеному побоюванню, що примусове використання формату JSON погіршує якість відповідей, проте розмір ефекту достатньо малий, щоб вибір формату не став визначальним фактором при виборі фреймворку.
- Жоден фреймворк не охоплює всі 45 категорій функцій JSON Schema. Guidance охоплює 13, Llamacpp та XGrammar по 1, а Outlines — 0. Практичний наслідок полягає в тому, що будь-яка схема, що використовує
if/then/else,unevaluatedPropertiesабо рекурсивні визначення$ref, поводитиметься непередбачувано залежно від того, який рушій використовується.
Що підтверджується, а що ні
Найсильнішим внеском бенчмарка є підбір джерел схем. Попередні оцінки використовували іграшкові схеми або колекції з одного джерела. Включення конфігурацій Kubernetes поруч із сигнатурами викликів функцій — це правильний вид змагальної різноманітності. Стратифікація за складністю (від тривіальної до ультра) також дає практикам калібрувальну криву: якщо ваші схеми схожі на виклики функцій GlaiveAI, XGrammar або Guidance цілком підійдуть; якщо вони схожі на маніфести Kubernetes, ваш вибір різко звужується.
Основною слабкістю є жадібна оцінка за одним зразком (single-sample greedy evaluation). Вимірювання покриття за допомогою однієї генерації на схему занижує реальні можливості — фреймворк може помилятися у 20% випадків, але досягати успіху при повторній спробі. Автори визнають це, але не надають показників pass@k з температурною вибіркою, що було б важливо для виробничих систем, які використовують повторні спроби при помилках.
Порівняння також змішує непорівнянні моделі. Фреймворки з відкритим вихідним кодом (Guidance, Outlines, Llamacpp, XGrammar) протестовані на Llama-3.2-1B, тоді як OpenAI та Gemini запускають власні закриті моделі. 9% покриття OpenAI на GitHub-Hard може відображати можливості моделі так само, як і архітектуру обмеженого декодування. Для справедливого порівняння потрібен контрольований доступ до моделей, що автори, очевидно, не можуть змусити зробити пропрієтарних постачальників.
Чому це важливо для фінансового ШІ
Кожен агент зворотного запису Beancount генерує структурований вивід. Якщо агент видає директиви Beancount у форматі JSON перед конвертацією в синтаксис .beancount, або якщо він викликає інструменти через схеми JSON, надійність цієї генерації JSON не є просто деталлю — це основа всього процесу. Дослідження FinTrace показало, що передові моделі зазнають невдачі в міркуваннях над результатами інструментів; JSONSchemaBench виявляє паралельну проблему: ще до етапу міркувань шар форматування може непомітно видати невідповідний результат.
Результат із Kubernetes особливо показовий для Beancount. Схеми бухгалтерських книг — це не пласкі набори ключів та значень. Ієрархії рахунків, метадані транзакцій та структури тегів створюють вкладені рекурсивні патерни, схожі на об'єкти API Kubernetes. Фреймв орк, який показує 7% на Kubernetes, не готовий до складних схем леджерів, незалежно від того, наскільки низькими є його накладні витрати на токен.
Режим відмови через недостатнє обмеження — це те, через що я б втрачав сон. Агент Beancount, що використовує XGrammar, може видати транзакцію, яка проходить внутрішню перевірку валідації фреймворку, але порушує реальну схему — і агент не матиме підстав для повторної спроби. Непомітне пошкодження даних гірше за явну помилку.
Що почитати далі
- XGrammar (arXiv:2411.15100, Dong et al.) — технічна стаття про один із найшвидших протестованих фреймворків, що пояснює поділ токенів на контекстно-незалежні/залежні та чому схеми Kubernetes створюють для нього навантаження.
- Grammar-Aligned Decoding / ASAp (NeurIPS 2024) — показує, що маскування токенів в обмеженому декодуванні може спотворювати розподіл ймовірностей моделі, і пропонує виправлений алгоритм вибірки; теоретична основа для побоювань щодо якості, які бенчмарк вимірює лише опосередковано.
- XGrammar-2 (arXiv:2601.04426) — продовження, що розширює XGrammar на динамічні схеми в агентних сценаріях, де сама схема змінюється під час багатоходової сесії, що безпосередньо стосується агентів Beancount, які адаптують свій формат виводу залежно від активних типів рахунків.
