Переписали JSONata на Go с помощью ИИ за день — экономия $500K в год

Обложка: Переписали JSONata на Go с помощью ИИ за день — экономия $500K в год

Один инженер. Семь часов работы. $400 на токены для ИИ. Результат — чистая Go-библиотека, которая заменила целый флот Node.js-подов в Kubernetes и сэкономила компании $500 000 в год на инфраструктуре.

Это не абстрактный кейс из маркетингового блога. Это реальная история от Reco — SaaS-платформы безопасности, которая обрабатывает миллиарды событий в день. Их инженер Нир Барак взял подход, описанный Cloudflare в статье о переписывании Next.js с помощью ИИ, и применил его к собственной инфраструктуре. Получилась библиотека gnata — полная реализация JSONata 2.x на чистом Go с ускорением до 1000x на типовых выражениях.

JSONata — это язык запросов и трансформации JSON-данных. Его можно представить как jq, но с поддержкой лямбда-функций и более выразительным синтаксисом. JSONata позволяет писать сложные правила обработки данных без необходимости лезть в код основного приложения. Это делает его популярным в системах, где бизнес-аналитики или исследователи пишут правила детекции, а инженеры обеспечивают инфраструктуру.

Главное из статьи:

- JSONata-выражения через RPC обходились в $300 000/год на инфраструктуру
- ИИ-ассистированная перезапись на Go заняла 7 часов и стоила $400 в токенах
- Результат: 13 000 строк Go-кода, 1 778 пройденных тестов из официального набора
- Ускорение до 1000x на простых выражениях за счёт устранения RPC и JSON-парсинга
- Суммарная экономия после оптимизации пайплайна — $500 000/год

Проблема — JSONata как узкое место

У Reco есть policy engine, который проверяет JSONata-выражения на каждом событии в потоке данных. Миллиарды событий, тысячи различных выражений. Исследователи безопасности пишут правила детекции на JSONata, а инженеры обеспечивают их выполнение в реальном времени.

Загвоздка: референсная реализация JSONata написана на JavaScript, а весь пайплайн Reco — на Go. Годами компания держала в Kubernetes отдельный флот Node.js-подов (jsonata-js), к которым Go-сервисы обращались через RPC.

Для каждого события и каждого выражения это означало:

  1. Сериализовать данные на стороне Go
  2. Отправить по сети в Node.js-под
  3. Выполнить JSONata-выражение
  4. Сериализовать результат
  5. Отправить обратно в Go-сервис

Во что это обходилось

Прямые затраты на инфраструктуру jsonata-js составляли около $300 000 в год, и сумма росла с каждым новым клиентом и правилом детекции. На одном из крупных кластеров количество реплик jsonata-js перевалило за 200 — и команда столкнулась с лимитом IP-адресов в Kubernetes.

Но денежные затраты были даже не главной проблемой. RPC round-trip занимает ~150 микросекунд ещё до начала вычисления. Для простого выражения вроде user.email = "admin@co.com", которое должно выполняться за наносекунды, основная цена — пересечение языковой границы. На масштабе Reco эти микросекунды складываются в ощутимые задержки.

Команда пробовала разные подходы: оптимизировала выражения, кэшировала результаты, даже встраивала V8 прямо в Go-процесс. Всё это давало инкрементальные улучшения, но не решало корневую проблему — данные всё равно пересекали языковую границу.

Решение — переписать на Go с помощью ИИ

Толчком стала статья Cloudflare о том, как один инженер за неделю переписал API Next.js на Vite, потратив $1 100 на токены. Нир Барак прочитал её и понял: у Reco та же самая ситуация — есть спецификация, есть тестовый набор, нужна реализация на другом языке.

Подход: спецификация + тесты = контракт

Метод прямолинейный:

  1. Портировать официальный тестовый набор jsonata-js на Go
  2. Направить ИИ на реализацию, пока все тесты не пройдут
  3. Добавить оптимизации, специфичные для Go и задачи Reco

В выходные Нир составил план, разбитый на «волны» (с помощью ИИ). На следующий день нажал «старт».

Инструменты и затраты

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

  • Время работы: 7 часов (один инженер)
  • Стоимость токенов: $400
  • Результат: 13 000 строк Go-кода
  • Тесты: 1 778 пройденных тест-кейсов из официального набора jsonata-js

Библиотека получила название gnata — полная реализация спецификации JSONata 2.x на чистом Go.

Технические результаты

Двухуровневая архитектура вычислений

gnata использует двухуровневую архитектуру оценки выражений. На этапе компиляции каждое выражение анализируется и классифицируется.

Быстрый путь (fast path) обрабатывает простые выражения: поиск по полям, сравнения и 21 встроенную функцию на чистых путях (например, $exists(a.b) или $lowercase(name)). Эти выражения вычисляются прямо по сырым JSON-байтам, без полного парсинга документа. Для выражения вроде account.status = "active" результат — ноль аллокаций в куче.

Полный путь (full path) — полноценный парсер и вычислитель с полной семантикой JSONata 2.x. Он парсит JSON, но только нужные поддеревья, а не весь документ целиком.

Потоковая обработка

Поверх двухуровневой оценки работает потоковый слой (StreamEvaluator), спроектированный под конкретную задачу Reco: применить N скомпилированных выражений к каждому событию, где события структурно похожи.

  • Все пути из всех выражений объединяются в один проход по данным — количество выражений не влияет на скорость чтения
  • После прогрева горячий путь работает без блокировок (lock-free)
  • Планы вычислений создаются один раз на схему событий и кэшируются неизменяемо — чтение через один атомарный load без синхронизации
  • Память ограничена: кэш с настраиваемой ёмкостью, вытесняющий старые записи

Бенчмарки

Ускорение на простых выражениях — в основном за счёт полного устранения RPC: gnata вычисляет прямо по сырым байтам без парсинга JSON. На сложных выражениях, где нужен полный парсинг и AST-вычисление, разрыв сужается, но они всё равно в 25–90 раз быстрее, чем через RPC.

На простых lookups ускорение достигает 1000x.

Пример использования

			import "github.com/recolabs/gnata"

expr, _ := gnata.Compile(`user.role = "admin" and user.loginCount > 100`)

json := []byte(`{
  "user": {
    "email": "admin@example.com",
    "role": "admin",
    "loginCount": 247
  }
}`)

result, _ := expr.EvalBytes(ctx, json)
fmt.Println(result) // true
		

Экономический эффект

Этап 1: устранение RPC-флота

Первый и самый очевидный эффект — полное устранение jsonata-js подов в Kubernetes:

  • До: ~$25 000/мес на compute для jsonata-js (200+ реплик Node.js)
  • После: $0 — gnata работает как библиотека внутри существующих Go-сервисов
  • Экономия: ~$300 000/год

Этап 2: рефакторинг rule engine

Но на этом история не закончилась. Старый JSONata через RPC мог обрабатывать только одно выражение за раз, и вся инфраструктура вокруг него была вынуждена подстраиваться. Rule engine запускал десятки тысяч горутин для максимизации параллелизма — со всеми вытекающими: избыточное потребление памяти и высокая конкуренция за CPU.

gnata не имеет таких ограничений. Команда заменила внутренности rule engine на более простую и эффективную реализацию с just-in-time батчингом (паттерн request coalescing), короткоживущими кэшами и групповыми запросами обогащения данных.

Результат: ещё ~$18 000/мес, или ~$200 000/год экономии.

Итого

$500 000/год снято с пайплайна за две недели работы. Из них 7 часов — создание gnata, остальное — тестирование, code review и раскатка.

Как внедряли — от shadow mode до продакшена

Создать библиотеку — половина дела. Вторая половина — убедиться, что она выдаёт ровно те же результаты, что и оригинал, на миллиардах реальных событий.

У Reco уже была инфраструктура для shadow-тестирования: feature flags, параллельное вычисление, логирование расхождений. Подключить gnata к ней было несложно.

Хронология раскатки:

  • День 1: gnata готова, PR открыт
  • Дни 2–6: code review, QA на реальных продакшен-выражениях, деплой в preprod в shadow mode. gnata вычисляет всё, но результаты jsonata-js остаются основными. Расхождения логируются и алертятся. Найденные edge-кейсы исправляются
  • День 7: три дня подряд ноль расхождений. gnata переведена в primary

К моменту перевода gnata уже обработала миллиарды событий и выдала идентичные результаты. Более того, в процессе обнаружились баги в самом jsonata-js — случаи, где референсная реализация не соответствует собственной спецификации.

Побочный эффект: gnata стала одним из первых крупных PR в Reco, где ИИ-агенты ревьюили ИИ-сгенерированный код. Агенты помечали всё подряд — и реальные проблемы с конкурентностью, и косметические замечания. Команде пришлось научить их отличать одно от другого, и этот опыт теперь используется шире.

Уроки — когда ИИ-переписывание работает

gnata — удачный кейс. Но не каждая задача подходит для ИИ-переписывания. Вот что сделало этот проект идеальным кандидатом:

  1. Чёткая спецификация. JSONata имеет формальную спецификацию и обширный тестовый набор. ИИ не нужно придумывать поведение — нужно реализовать заданное
  2. Детерминированная проверка. Каждое выражение имеет однозначный правильный ответ. Можно автоматически проверить корректность — не нужен человек для оценки каждого результата
  3. Глубокая экспертиза инженера. Нир не просто «нажимал кнопку». Он спроектировал двухуровневую архитектуру, потоковую обработку и стратегию кэширования. ИИ генерировал код, но архитектурные решения принимал человек
  4. Существующая инфраструктура тестирования. Shadow mode, feature flags, сравнение результатов — всё это было готово до gnata. Без этого раскатить ИИ-сгенерированный код в продакшен было бы рискованно
  5. Ограниченная область. JSONata — это чётко ограниченная задача. Не «перепишите весь бэкенд», а «реализуйте этот конкретный язык на другом стеке»

Как отметил Андрей Карпати: программирование становится неузнаваемым, и на верхних уровнях глубокая техническая экспертиза — «ещё больший мультипликатор, чем раньше, из-за увеличенного рычага». gnata — хорошая иллюстрация этой мысли.

FAQ

Что такое JSONata и зачем он нужен?

JSONata — это язык запросов и трансформации для JSON-данных. Он позволяет писать выражения для фильтрации, преобразования и агрегации JSON без написания кода на языке общего назначения. Используется в IoT-платформах, ETL-пайплайнах и системах обработки событий.

Почему нельзя было просто оптимизировать существующий подход?

Reco пробовали: оптимизация выражений, кэширование, встраивание V8 в Go. Всё это давало инкрементальные улучшения, но корневая проблема — пересечение языковой границы через RPC — оставалась. Единственное радикальное решение — нативная реализация на Go.

Насколько gnata совместима с оригинальной JSONata?

gnata проходит 1 778 тест-кейсов из официального набора jsonata-js и 2 107 интеграционных тестов в продакшен-обёртке Reco. В процессе тестирования были обнаружены баги в самом jsonata-js, где референсная реализация не соответствует собственной спецификации.

Можно ли повторить этот подход в другом проекте?

Да, если есть формальная спецификация и тестовый набор. Подход Cloudflare (vinext) и Reco (gnata) одинаков: берём спеку + тесты, направляем ИИ на реализацию до прохождения всех тестов. Ключевое требование — детерминированная проверка результата.

Выводы

История gnata — это не про то, что ИИ «волшебным образом» пишет продакшен-код. Это про то, как опытный инженер с глубоким пониманием задачи использует ИИ как мультипликатор своей экспертизы.

Ключевые выводы:

  • ИИ-переписывание работает, когда есть чёткая спецификация и автоматизированная проверка
  • Экономический эффект может быть огромным: $400 на токены превратились в $500 000/год экономии
  • Архитектура важнее генерации кода: двухуровневая оценка, потоковая обработка и батчинг — решения инженера, не ИИ
  • Shadow mode обязателен: ИИ-сгенерированный код нельзя просто «выкатить» — нужна параллельная проверка на реальных данных
  • ROI считается просто: если задача имеет спеку и тесты, стоимость ИИ-переписывания предсказуема

gnata доступна как open-source библиотека: github.com/RecoLabs/gnata.

Источник: We Rewrote JSONata with AI — блог Reco.