← Назад Harupa
2026-07-04RU EN UA BY PL

My Architect, частина 10: пам'ять про репозиторій — код-граф, якому заборонено вірити на слово

Це десята стаття серії про My Architect і продовження дев'ятої — історії скіла recursive-context, який учить агента дисципліни роботи з даними, більшими за контекстне вікно. Цього разу: чотири релізи за один день (v1.14.0 → v1.16.1), які дали агентові персистентний граф коду, і контрольований експеримент, який виміряв його реальну користь замість переказу чужого маркетингу. Усі числа наших прогонів — із телеметрії реальних запусків 2026-07-03; факти про Graphify — з його README і живої установки; оцінки помічені явно. Нічого не додумано.

Пролог. Агент з амнезією

У LLM-агента немає пам'яті між сесіями. Кожна нова розмова про твій репозиторій починається з чистого аркуша: агент знову grep'ає, знову читає ті самі файли, знову будує в голові ту саму карту — і викидає її наприкінці сесії. Ми це виміряли на власному репозиторії: збір фактів про добре знайому кодову базу коштував ~77 тисяч токенів і 20 викликів інструментів — і так щосесії, по колу.

Окрема біда — питання на кшталт «що зламається, якщо я поміняю сигнатуру цієї функції?». Відповідь вимагає знати всіх споживачів символу. Grep їх знаходить, але за ціну повного проходу; а головне — в агента немає місця, де це знання могло б пережити сесію.

Довкола цього болю вже виріс ринок інструментів «код-як-граф» — із гаслами рівня «90% економії токенів» і «агент у 500 разів розумніший». Нам потрібні були не гасла, а відповідь на два питання: які класи помилок це прибирає і де економія справжня, а де популізм. Спойлер: наприкінці статті — таблиця з виміряними числами.

Розділ 1. Не будувати своє: Graphify

Інструмент для персистентної пам'яті про код уже існує — Graphify (open source, MIT, ~77k зірок): парсить код tree-sitter'ом повністю локально (36 мов, без API-викликів і телеметрії), складає граф символів і зв'язків у graphify-out/graph.json, поруч кладе інтерактивну HTML-карту і готовий текстовий звіт про репозиторій. Свіжість індексу підтримують git-хуки; для командної роботи є merge-driver, щоб граф можна було комітити без конфліктів.

Ми свідомо не стали будувати свій граф-рушій. Натомість навчили наш скіл decomposition-дисципліни розпізнавати індекс, що лежить у репозиторії, і правильно ним користуватися. Уся фіча — це markdown-довідник із правилами плюс кілька рядків-вказівників: у плагіна не з'явилося жодної жорсткої залежності. Немає графа — все працює як раніше; немає графа, а задача важка — агент один раз запропонує власникові поставити і зібрати (і зробить це сам після «так»; мовчазні установки заборонені).

Наскільки це дешево на практиці: на нашому репозиторії (351 файл) збірка графа зайняла секунди і дала 2655 вузлів, 4948 ребер і 153 автоматично знайдені кластери — 6.1 МБ на диску, нуль API-витрат. Один запит після цього виглядає так:

$ graphify explain "getBlockers"
Node: getBlockers()   Source: src/hierarchy/model.ts L419   Degree: 9
  <-- NodePropertiesPanel.tsx [imports]
  <-- validator.ts [imports]
  <-- validateHierarchy() [calls]
  ...

Секунда — і в агента всі споживачі функції зі шляхами. Те, що раніше вимагало повного проходу по репозиторію, стало запитом. Важлива деталь для всієї подальшої розмови про економіку: сам граф токенів не витрачає взагалі — і збірка, і запити — це локальні утиліти, а не виклики моделі.

Розділ 2. Правило, заради якого все затівалося

Індекс — це кеш, а кеш уміє брехати: він відстає від коду між перезбірками. Тому в центрі фічі не команди, а три правила:

  1. Граф — навігація і кандидати, НЕ джерело фактів. Відповідь графа каже, КУДИ дивитися; фактом стає лише те, що підтверджено живим файлом. Контракт фактів ({твердження, шлях-доказ, впевненість}) не змінився ні на йоту.
  2. Freshness-check обов'язковий. Насамперед агент порівнює час збірки індексу з часом останнього коміту. Протух — сказати вголос, запропонувати власникові перезбірку (а якщо git-хук не стоїть — один раз запропонувати і хук, щоб протухання не повторювалося щосесії), кандидатів помічати «за застарілим індексом».
  3. Verify — економно, регіонами. Кандидат приходить із шлях:рядок — перевірка читає ±30 рядків довкола, а не файл цілком. Без цього правила перевірка з'їдає все, що граф зекономив на пошуку.

Розділ 3. Як ми це тестували

Скіл — це текст, який має змінювати поведінку моделі. Текст не скомпілюєш і юніт-тестом не покриєш, тому перевірка — шарувата, і кожен шар ловить свій клас помилок. Залізне правило всіх релізів: тести пишуться до правок, і спершу фіксується «як агент помиляється без них».

Шар 1 — тригери: чи завантажиться скіл сам. Судді бачать лише ім'я та опис скіла (рівно те, що бачить Claude Code при виборі) плюс запит; три незалежні судді на кейс; у наборі — позитиви двома мовами, підступні майже-влучання («перейменуй змінну» — схоже на impact-питання, але скіл має мовчати) і крос-перевірка, що новий скіл не краде тригери сусіднього. Фінальний прогін: 30/30 голосів рівно за ключем.

Шар 2 — поведінка: чи дотримано дисципліну. Виконавець читає скіл із диска і пише план за сценарієм; незалежний грейдер порядково звіряє із заздалегідь записаними твердженнями. Кожен сценарій б'є в конкретний спосіб зламатися: свіжий граф → запити до grep, але факти за файлами; протухлий → помітити і не довіряти; графа немає → запропонувати один раз і не ставити мовчки.

Шар 3 — зле рев'ю самого тексту. Окремий рев'юер не читає скіл увічливо — він його виконує: запускає шелл-сніпети на межових входах, піднімає docker, звіряє кожне ім'я команди з README апстріму.

Шар 4 — live-прогони: справжня установка (за згодою), справжній граф, справжній агент на справжньому репозиторії.

Шар 5 — контрольований експеримент (розділ 5): коли якісні перевірки пройдено, лишається питання «а скільки це коштує?» — і на нього відповідає лише A/B з телеметрією.

Розділ 4. Що зловили до експерименту. Чотири історії

Пастка умовного роутингу. Ми додали гілку «графа немає → запропонуй власникові зібрати» — а рев'ю показало, що вона недосяжна: усі вказівники, що ведуть агента в довідник графа, починалися зі слів «якщо граф Є». Агент без графа просто не відкрив би файл із пропозицією. Класична помилка: нова гілка є, але всі дороги до неї гейтяться на стан, за якого вона не потрібна.

Баг, який жив би лише на Linux. Сніпет freshness-перевірки використовував macOS-синтаксис stat із фолбеком на GNU-варіант. Рев'юер підняв docker і показав: у GNU stat той самий прапорець означає інше — команда «успішно» друкує сміття, і гейт вічно відповідає STALE. На будь-якій Linux-машині graph-first не ввімкнувся б ніколи, тихо.

Апстрім знає краще. Ми радили ховати graphify-out/ у .gitignore — а README Graphify рекомендує командам граф комітити (спільна карта; конфлікти розв'язує їхній merge-driver). Наша порада мовчки викидала командний сценарій; тепер пропозиція чесно дає вибір. Заодно з'ясувалося, що PyPI-пакет називається graphifyy — з двома «y».

Виконавець, який не повірив умові задачі. Сценарій поведінкового тесту стверджував «граф свіжий» — агент перевірив mtime по-справжньому, виявив, що граф його реального оточення протух (наші ж коміти встигли його обігнати), і обробив розбіжність за рецептом. Дисципліна «не довіряй, перевіряй» спрацювала навіть проти тексту завдання.

Окремим заходом ми провели аудит «до чого агент не додумається сам» — і закрили три прогалини: impact-питання отримали власний вхід у скіл (раніше «що зламається, якщо поміняю X?» поза трекованою задачею не вело до графа взагалі), готовий звіт GRAPH_REPORT.md тепер читається першим при аудиті (зведення вже пораховане — нерозумно збирати його запитами), а при протухлому графі без хука агент пропонує хук.

Розділ 5. Експеримент: міряємо самі, а не цитуємо маркетинг

Дизайн. Незнайомий обом групам великий репозиторій — NestJS, 2125 файлів (на порядок більший за наш). Два ідентичні клони: плече A — з графом (12309 вузлів, 22895 ребер, 738 кластерів; зібраний tree-sitter'ом за секунди, $0), плече B — без. Три класи питань, промпти ідентичні з точністю до шляху, про граф — ані слова (плече A зобов'язане знайти його само за дисципліною скіла), одна модель (Sonnet), один контракт виводу (≥8 фактів зі шляхами + чесне покриття + журнал усіх викликів). Метрики — токени і виклики з телеметрії, якість — кількість фактів і вибіркова звірка шляхів.

Результати:

Клас питанняA (граф)B (без графа)Дельта
Impact: «споживачі ModuleRef, що зламається при зміні get()»71.4k токенів · 26 викликів · соло · 12 фактів71.9k · 31 виклик · соло · 14 фактівпаритет (A: −16% викликів і часу)
Розуміння: «HTTP-request lifecycle end-to-end»75.9k · соло · 13 фактів56.1k зверху + 205.8k у прихованих суб-агентах (виміряно) ≈ 262k · 21 фактграф дешевший у ~3.5× (−71%)
Карта: «packages/core: модулі, API, ризики»≈445k (8 суб-агентів, оцінка*) · 24 факти≈500k (9 суб-агентів, оцінка*) · 25 фактів~паритет

\* Оцінка вкладеної вартості відкалібрована на єдиній точно виміряній комірці (Q2-B: 205 759 токенів на 5 агентів) і помічена як оцінка; напрямок похибки невідомий.

Висновок 1: економія справжня, але селективна. На класі «зрозуміти підсистему» — виміряні −71%: не тому що запити графа дешевші за grep, а тому що граф одразу звузив корпус, і один агент упорався там, де плече B було змушене мовчки розгорнути п'ятьох. На impact-класі економія — нуль (grep за буквальним ім'ям символу дешевий навіть на 2125 файлах; виграш графа там — повнота і швидкість, не токени). На повному аудиті — нуль (оркестрація потрібна обом; граф дає готове партиціонування і кандидатів, не знижку). Універсального множника «90%» не існує — існує клас задач.

Висновок 2, методологічний — прихована оркестрація. За верхніми цифрами плече B на «розумінні» виглядало дешевшим (56k проти 76k) — доки ми не розкрили в його транскриптах 205.8k токенів вкладених агентів. Красиві порівняння «агент з інструментом проти агента без» систематично недооцінюють плече, яке тихо делегує. Чесний замір зобов'язаний рахувати все дерево агентів — підозрюємо, що чимала частина популярних цифр цим не займається.

Дисципліна недовіри до графа відпрацювала і всередині експерименту: плече A на impact-питанні відсіяло хибнопозитивних кандидатів графа (barrel-імпорти) живим grep'ом, а на аудиті верифікувало цикли з графа і два хибні відкинуло. Граф давав наводки — фактами ставало лише підтверджене.

Бонус, якого не замовляли: аудит-агенти плеча B знайшли в ядрі NestJS два схожі на справжні баги (присвоєння в Map через індекс, яке ніколи не читається; return замість continue, що мовчки обрізає реєстрацію middleware) — незаплановане підтвердження, що глибина аудиту в дисципліни справжня.

Обмеження — чесно: n=1 на комірку (без дисперсії), один репозиторій, один тір моделі; вкладена вартість двох комірок оцінена за калібруванням на єдиній точно виміряній (і помічена як оцінка); плечі самі обирали стратегію — це фіча дизайну (міряємо систему цілком), але вона змішує «граф» із «рішенням не оркеструвати»; довгострокова амортизація повторних сесій цим експериментом не вимірювалася — вона лишається гіпотезою з сильним апріорі (~77k «податку на перевивчення» за сесію проти одноразової безплатної збірки).

Розділ 6. Було → стало

БулоСтало
Знання репо між сесіямине переживає сесію; ~77k токенів на перевивченняграф збирається за секунди один раз; кандидати — миттєві безплатні запити
«Хто кличе X / що зламається?»повний grep-прохід; поза трекованою задачею агент про граф не знавсамостійний вхід: graphify affected "X" → verify регіонами ±30 рядків — включно з indirect-зв'язками, яких grep не бачить
Розуміння підсистеми на великому репоприхований fan-out суб-агентів, ~262k токеніводин агент із графом, ~76k — −71%, виміряно
Аудит репозиторіюрозвідка з нуляGRAPH_REPORT.md (готові хаби, кластери, неочікувані зв'язки) читається першим
Довіра до індексуfreshness-гейт; протух → уголос + пропозиція перезбірки і хука; факти — лише за живими файлами
Установказа явним «так» власника: агент пропонує один раз, ставить і збирає сам; відмова поважається всю сесію

Епілог

Формула фічі: наявний інструмент (Graphify) + дисципліна поводження з ним (наш скіл) + шаруваті тести, які не вірять нікому — ні авторові тексту, ні красивому сніпету, ні умові власного сценарію, ні, як з'ясувалося в розділі 5, верхньому рядку чужого бенчмарка. З усіх суттєвих знахідок чотирьох релізів жодна не була знайдена «вичиткою» — усі принесло виконання: судді, грейдери, docker, живі прогони і телеметрія експерименту.

Свідомо відкладено: тріаж pull request'ів через граф (у нас немає PR-процесу — інструмент без споживача не робимо), петля пам'яті запитів save-result/reflect (окрема розмова) і повторення експерименту з n>1 і другим репозиторієм — якщо селективна економія підтвердиться і там, у «90% хайпу» з'явиться чесна заміна: «−70% на класі „розуміння“, нуль на решті».

Як спробувати

Код-граф їде в плагіні my-architect починаючи з v1.14.0 (актуальна — v1.16.1). Руками кликати не потрібно: скіл сам розпізнає граф у репозиторії, а на важкій задачі без графа — сам запропонує поставити.

  1. Заведи акаунт на my-architect.app, візьми токен на сторінці API Keys і експортуй його в тій самій сесії, де запускаєш Claude Code:

``bash export MCP_API_KEY=mcp_ВАШ_ТОКЕН ``

  1. Додай маркетплейс і постав плагін:

`` /plugin marketplace add d7561985/my-architect-marketplace /plugin install my-architect@my-architect-marketplace ``

  1. Граф можна зібрати і руками, не чекаючи на пропозицію агента:

``bash pip install graphifyy && graphify build . ``

  1. Уже стоїть плагін? /plugin marketplace update my-architect-marketplace/plugin update my-architect.

---

Факти і посилання