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. Правіла, дзеля якога ўсё задумвалася
Індэкс — гэта кэш, а кэш умее хлусіць: ён адстае ад коду паміж перазборкамі. Таму ў цэнтры фічы не каманды, а тры правілы:
- Граф — навігацыя і кандыдаты, НЕ крыніца фактаў. Адказ графа кажа, КУДЫ глядзець; фактам становіцца толькі тое, што пацверджана жывым файлам. Кантракт фактаў (
{сцвярджэнне, шлях-доказ, упэўненасць}) не змяніўся ні на ёту. - Freshness-check абавязковы. Найперш агент параўноўвае час зборкі індэкса з часам апошняга каміту. Пратух — сказаць уголас, прапанаваць уладальніку перазборку (а калі git-хук не стаіць — адзін раз прапанаваць і хук, каб пратуханне не паўтаралася кожную сесію), кандыдатаў пазначаць «па састарэлым індэксе».
- 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). Рукамі клікаць не трэба: скіл сам распазнае граф у рэпазіторыі, а на цяжкай задачы без графа — сам прапануе паставіць.
- Завядзі акаўнт на my-architect.app, вазьмі токен на старонцы API Keys і экспартуй яго ў той жа сесіі, дзе запускаеш Claude Code:
``bash export MCP_API_KEY=mcp_ВАШ_ТОКЕН ``
- Дадай маркетплейс і пастаў плагін:
`` /plugin marketplace add d7561985/my-architect-marketplace /plugin install my-architect@my-architect-marketplace ``
- Граф можна сабраць і рукамі, не чакаючы прапановы агента:
``bash pip install graphifyy && graphify build . ``
- Ужо стаіць плагін?
/plugin marketplace update my-architect-marketplace→/plugin update my-architect.
---
Факты і спасылкі
- Скіл-даведнік:
plugins/my-architect/skills/recursive-context/references/code-graph.mdу адкрытым рэпазіторыі github.com/d7561985/my-architect-marketplace; рэлізы v1.14.0 (f2ca07d), v1.15.0 (1257064), v1.16.0 (ee0a711), v1.16.1 (6f35623), усе — 2026-07-03. - Поўныя даныя тэстаў і эксперыменту:
skills/recursive-context/evals/RESULTS.md(RED/GREEN/LIVE/A/B); датасетыtrigger-evals.json(13 кейсаў),behavior-evals.json(10 кейсаў). - Graphify: github.com/safishamsi/graphify (MIT; PyPI-пакет
graphifyy); наша ўстаноўка: 0.9.5. - Папярэдняя частка цыкла: My Architect, частка 9 — пра сам скіл decomposition-дысцыпліны.