Створення єдиного графа знань для 46 репозиторіїв
Я Раян, CTO в airCloset.
Я витратив три місяці на створення code-graph. Це єдиний граф знань, який об'єднує 46 репозиторіїв у різних сервісах.
Багато хто вважає, що можна просто віддати весь свій код штучному інтелекту та ставити запитання. Це не працює з двох причин:
- Контекстні вікна: Ви не зможете вмістити роки коду з 46 репозиторіїв в один промпт.
- Галюцинації: ШІ припускається помилок, коли намагається вивести зв'язки. Він пропускає з'єднання.
Щоб вирішити цю проблему, я використав статичний аналіз для створення першоджерела істини (source of truth).
Виклик: Подолання меж
Великий кодовий базис — це хаос. Один API може викликатися п'ятьма різними репозиторіями. Одна таблиця бази даних може використовуватися трьома різними сервісами.
Якщо ви дивитеся лише на один репозиторій, ви не бачите повної картини. Це небезпечно. Якщо ви зміните код і не побачите реального радіусу ураження (blast radius), ви зламаєте систему.
Мій підхід використовує tree-sitter для парсингу коду в синтаксичні дерева. Але сам по собі tree-sitter не може бачити за межі репозиторіїв.
Щоб вирішити це, я створив вузли меж (boundary nodes).
Як це працює:
- Ми витягуємо зв'язки всередині репозиторію за допомогою tree-sitter.
- Ми використовуємо TypeScript Compiler API для визначення типів і змінних.
- Ми використовуємо Gemini для обробки динамічних випадків, які пропускають інструменти.
Замість того, щоб просити ШІ вгадувати, ми надаємо йому факти. Ми кажемо йому: «Цей API також викликається з Repo X». Це запобігає галюцинаціям.
Найскладніша частина: «Зоопарк» фреймворків
Справжня битва полягала у витягуванні цих меж. Кожен фреймворк описує межі по-різному.
Одна команда використовує декоратори NestJS. Інша — маршрути Express. Ще одна — чистий jQuery. Кожен із них створює різну структуру в коді.
Щоб це запрацювало, нам довелося створити кастомні парсери для:
- NestJS and TypeORM
- Express and Fastify
- AngularJS and Redux
- Різних схем псевдонімів шляхів (path-alias)
Нам потрібно було прагнути до 99% точності. Якщо рівень з'єднань становить лише 90%, ШІ пропускає 10% зв'язків. У продуктивній системі саме в цих 10% ховаються баги.
Тепер ми проводимо щоденну перевірку. Якщо рівень з'єднань падає більш ніж на 5%, ми отримуємо сповіщення. Це дозволяє вчасно помітити, коли нові патерни коду ламають наші парсери.
Поточні обмеження
Граф не є ідеальним.
- Пошук є складним. Часто потрібно знати назву функції, щоб розпочати пошук.
- Вибух вузлів. Перехід за шляхом може залучити тисячі крихітних, марних допоміжних функцій.
- Підтримка. Щоразу, коли в наш стек додається новий фреймворк, ми маємо писати новий парсер.
Це частина 1. У частині 2 я розповім про шар service-product-graph (SPG), який я створив, щоб усунути ці прогалини.
Додаткова спільнота для навчання: https://t.me/GyaanSetuAi
