Оценка долга в проектировании схем GraphQL с помощью LLM и механизма CI Ratchet
Как использовать ревизор LLM и систему оценки от 1 до 5 для выявления субъективных проблем в дизайне GraphQL в новых пул-запросах, а также для отслеживания существующих проблем в вашей схеме.
Схема GraphQL, которую изменяют десятки или сотни инженеров в различных областях продукта, постепенно деградирует, независимо от качества руководства по стилю. Инструменты линтинга выявляют механические проблемы, но самые серьезные требуют субъективного осуждения: String, который должен был быть элементом перечисления, список, размер которого растет без ограничений, поле с возможностью значения null, которое на самом деле никогда не возвращает null. В этой статье описывается двухэтапная система для решения таких проблем: ревизор с использованием ИИ, который предотвращает появление новых долгов при создании пул-реквестов, и система оценки существующей схемы, превращающая старые долги в приоритизированный список задач с возможностью отслеживания, контролируемый инструментами CI.
Почему качество API становится проблемой всей системы
У небольшой группы инженеров согласованность API в основном зависит от общих предпочтений. Сотрудники работают рядом, проверяют изменения в схемах друг у друга и приходят к единым стандартам. Однако по мере роста организации это перестает срабатывать: постоянно добавляются новые функции, старые правила сосуществуют с новыми, а решения, которые казались очевидными первоначальной команде, интерпретируются иначе командами, которые с ней не встречались.
В такой ситуации требуются ответы на три вопроса, которые не зависят от внимания какого-либо одного проверяющего:
- Как сохранять согласованность дизайна API, когда множество команд одновременно редактируют схемы?
- Как гарантировать, что новые типы и поля соответствуют современным лучшим практикам?
- Как выявить те части API, которые были спроектированы до появления этих практик?
Первые два касаются профилактики. Третий посвящён археологии и является тем, что чаще всего игнорируют при реализации мер управления.
Где заканчиваются правила проверки и начинается суждение
Значительная часть стандартов API носит механический характер, и статический анализ эффективно с ними справляется. Конвенции именования, использование устаревших полей, обязательные описания и единая структура ошибок — всё это свойства схемы, для которых существует ответ «да» или «нет»: поле либо соответствует правилу, либо нет, и инструмент проверки может определить это.
Другие стандарты нельзя свести к простым правилам. Типичные примеры:
- Должен ли этот
Stringбыть элементом перечисления? - Должен ли этот список иметь пагинацию?
- Должен ли этот
Intбыть пользовательским скалярным типом? - Может ли это поле с возможностью значений null безопасно стать без неё?
- Соответствует ли эта структура способу моделирования аналогичных концепций в других частях API?
Ни для одного из этих случаев не существует ответа без учета контекста. Возвращение String или даже неоттипизированного JSON-объекта иногда бывает правильным решением. Чтобы определить, является ли это правильным, необходимо учитывать три фактора одновременно: объявление схемы, реализацию механизма обработки запросов и цель предоставления этих данных клиентам. Только с учетом всех трех факторов можно определить, какая форма данных наилучшим образом подойдет клиентам.
Компании обычно решают эту проблему с помощью проверки кода, встреч с командой платформы и письменных руководств. Этот подход работает, но плохо масштабируется. Давление по срокам сокращает время проверки, команда платформы не может отслеживать каждое изменение схемы в каждом репозитории, а лучшие практики развиваются быстрее, чем старые API получают обновления. В результате возникают две связанные проблемы: предотвращение новых долгов в проектировании и выявление уже существующих долгов.
Смещение влево: рецензент на основе JLL для изменений схемы
Первая часть системы преобразует руководящие принципы проектирования API в агента для автоматизированного рассмотрения кода. Цель не в замене людей-рецензентов, а в предоставлении им дополнительной проверки именно тех моментов, которые ускользают во время обычного рассмотрения pull request. Личное утверждение каждой изменения в GraphQL командой платформы во всех репозиториях неэффективно с точки зрения масштабируемости; в то время как применение стандартов к агенту на основе ИИ, работающему везде, позволяет решить эту проблему.
Поскольку агент видит не только различия в схеме, он может анализировать контекст, а не только синтаксис. Он читает объявление поля, его реализацию и соответствующий текст правил, после чего задаёт конкретные вопросы. Вот два примера комментариев:
- Поле с именем
updatedAtобъявляется как типString. Если резолвер возвращает временную метку в формате ISO 8601, ему следует использовать специальный скалярISO8601DateTimeвместо этого. Company.employeesвозвращает обычный список. У численности сотрудников компании нет естественного верхнего предела, поэтому это поле должно возвращать пагинационное соединение.
Ни один из этих случаев нельзя надежно обнаружить с помощью инструмента проверки кода. Правило проверки, гласящее, что «поля, заканчивающиеся на At, должны быть датовыми скалярами», приводит к ложноположительным результатам и упускает поле lastModified; правило, требующее, чтобы «все списки были пагинационными», неверно для поля, возвращающего три поддерживаемые валюты. Глубокая нейронная сеть может проанализировать то, что на самом деле делает резолвер.
Ключевым фактором является сроки. Обнаружение таких проблем на этапе разработки API обходится дешево. Обнаружение их после того, как клиенты уже начали использовать API, требует цикла устаревания и миграции.
Огляд в прошлое: оценка существующей схемы
Профилактика бесполезна для уже существующей части кода, а в зрелом API эта часть довольно большая. Часть её создавалась до появления современных стандартов. Часть содержит компромиссы, которые казались разумными на момент их принятия. Ещё часть имеет неравномерную структуру из-за того, что разные команды моделировали одни и те же концепции по-своему. Необходим способ оглянуться назад.
Вторая часть системы — это пакетная обработка, дополняющая инструменты статического анализа, уже обрабатывающие схему. Её работа включает следующее:
- Проанализировать схему по отдельным доменам и выделить поля или типы, в которых требуется субъективная оценка дизайнера.
Шаг 1 важен с точки зрения затрат и количества ненужной информации. Нет причин запрашивать мнение модели по полям, которые уже были классифицированы с помощью детерминистической проверки; LLM должен рассматривать только те кандидаты, по которым действительно требуется оценка.
Почему оценка от 1 до 5 лучше, чем «прошло/не прошло»
Поскольку речь идет о субъективных оценках, принуждение каждого результата к бинарному вердикту приводит к потере информации. Вместо этого каждому полю присваивается оценка от 1 до 5:
- 1: поле выглядит подходящим согласно замыслу разработчиков.
- 2: сигнал слабый, но, вероятно, всё в порядке.
- 3: необходимо, чтобы человек взглянул на это.
- 4: поле, скорее всего, нарушает правила.
- 5: это типичный пример случая, который следует избегать.
Чтобы сделать это конкретнее: поле типа String, в котором хранится произвольный текст, введённый пользователем, должно оказаться близко к значению 1. Поле типа String с именем errorCode, резолвер которого может возвращать только одно из трёх заранее заданных значений, должно оказаться близко к значению 5, поскольку это фактически enum в маске обычного поля.
Оценка с баллами дает гораздо более полезную информацию, чем простой список нарушений. Команды могут начать с записей с высокой степенью уверенности — 4 и 5, при этом оставаясь в курсе областей с более низкой уверенностью, которые требуют дополнительного анализа. Середина шкалы имеет ещё одну функцию: группа значений 3 указывает команде платформы на неоднозначности формулировок правил или запросов, что служит обратной связью для улучшения этих запросов до получения более точных результатов.
Если вы создаёте что-то подобное, попросите модель сгенерировать структурированный вывод (балл и объяснение в отдельных полях), чтобы результаты можно было хранить и агрегировать без необходимости парсинга прозы. Также сохраняйте версии текста правил и критериев оценки вместе с запросами, чтобы изменения баллов можно было связать с изменениями правил.
Преобразование результатов в действия
Значения в базе данных сами по себе ничего не меняют. Их агрегация по доменам в панели управления предоставляет каждой команде, ответственной за определённую область, чёткое представление о проблемах в проектировании API: не разрознённые примеры или единичные комментарии к обзорам, а приоритизированный список полей и типов, которые могут потребовать миграции.
Эти же данные позволяют использовать механизм постепенного улучшения в процессе непрерывной интеграции. Цель не в том, чтобы сразу исправить всё, что нереалистично для крупного API с большим количеством клиентов в производстве. Цель — обеспечить, чтобы ситуация не ухудшалась, в то время как текущее состояние постепенно улучшается:
- Все изменения схемы должны соответствовать действующим стандартам.
- Существующие проблемы фиксируются как известные долги, а не игнорируются.
- По мере того как команды мигрируют или устаревают старые паттерны, допустимый порог ужесточается, чтобы уже исправленные проблемы не могли снова возникнуть.
Рационы являются распространённым подходом при миграциях кода: фиксируется текущее количество нарушений в каждой области, сборка отклоняется при увеличении этого числа, а зафиксированный базовый уровень снижается каждый раз, когда кто-то исправляет соответствующее нарушение.
Этот подход особенно важен для публичных или широко используемых API, где очистка данных зависит от миграций со стороны клиентов. Результатом является не инструкция по удалению всех некорректных полей, а приоритизированная карта тех мест, где API больше не соответствует современным стандартам, что позволяет командам планировать дальнейшие действия.
Почему большие языковые модели — подходящий инструмент для этой задачи
Большие языковые модели не являются идеальными оценщиками дизайна API, и система не рассматривает их как таковые. Их сила заключается в более узкой специализации: они могут читать код и схемы вместе, сравнивать их с правилами, изложенными простым языком, и формировать структурированные оценки для случаев, которые невозможно описать с помощью статических правил.
Статическое правило может указать, что поле возвращает список. Однако оно не может сказать, увеличивается ли этот список под воздействием данных от пользователя и требуется ли тогда пагинация. Модель может прочитать информацию из резолвера, сравнить её с примерами из политики и объяснить, почему поле соответствует или не соответствует заданному шаблону.
Такое объяснение ценно больше, чем просто числовой показатель. Когда поле отмечается как проблемное, команда, ответственная за него, должна знать причину, чтобы быстро определить, является ли выявленная проблема реальной, и, если да, как спланировать миграцию. Оценка без обоснования лишь создаёт ещё одну очередь обработки.
Ограничения, с которыми следует считаться
Проверка с помощью LLM не заменяет ответственность за API или человеческую оценку дизайна, поэтому важно чётко указывать, что остаётся в процессе:
- Ложные положительные результаты всё ещё возможны.
Однако она предоставляет масштабируемый способ выявления шаблонов, ранее ограниченных количеством возможностей для человеческого анализа. Рекомендации кодируются один раз, последовательно применяются во всех репозиториях, и полученные результаты служат командам фактической отправной точкой для обсуждений дизайна.
Заключение
Система состоит из двух частей, объединённых одной идеей. При подаче запроса на интеграцию рецензент с использованием ИИ применяет руководящие принципы проектирования к новым изменениям схемы до того, как клиенты начнут от них зависеть. В режиме пакетной обработки тот же алгоритм оценивает существующую схему по шкале от 1 до 5; эти оценки суммируются в панелях управления для каждой команды, а механизм CI предотвращает увеличение общего количества баллов по мере ужесточения критериев со временем. Это не полностью автоматизированная система управления, и она не предназначена для этого. Она делает качество API достаточно видимым, чтобы команды могли принимать соответствующие действия, а также обеспечивает команде платформы цикл обратной связи для усовершенствования собственных правил по мере расширения применения этого подхода на большую часть схемы.