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

My Architect, частка 9: Recursive context — як мы навучылі агента шчыра казаць, чаго ён не прачытаў

Гэта дзявяты артыкул серыі пра My Architect. Коратка для тых, хто далучыўся толькі што: My Architect — сістэма, дзе праект жыве паміж сесіямі AI-агента; агент вядзе яго праз MCP, чалавек бачыць прагрэс у візуальным інтэрфейсе. Гэты артыкул — гісторыя адной фічы: ад даследавання MIT да скіла recursive-context у плагіне my-architect v1.13.0. Усе лічбы нашых прагонаў — з рэальных запускаў 2026-07-03; лічбы даследавання RLM — з артыкула arXiv:2512.24601. Нічога не дадумана.

Пралог. Праблема, якую вялікі кантэкст не вырашае

У сучасных агентаў вялізнае кантэкстнае акно, і гэта стварае небяспечную ілюзію: «улезе — значыць справіцца». На практыцы праца з вялікімі данымі ламаецца трыма спосабамі, і ніводзін з іх не лечыцца памерам акна.

Першы: акно — расходнік. Агент, які «проста прачытаў» лог на 200 МБ, альбо не прачытаў яго (акно скончылася), альбо спаліў бюджэт сесіі на адзін файл — і далей працуе агрызкам кантэксту.

Другі: праўдападобнасць замест фактаў. Папрасі агента «збяры, што ўжо працуе ў кодзе» — і атрымаеш гладкі тэкст, у якім факты з коду, пераказ дакументацыі і здагадкі неадрозныя адно ад аднаго. Вялікі кантэкст не дае гарантый працы з данымі: мадэль умее гучаць упэўнена і без апоры на крыніцу.

Трэці: ціхае звужэнне пакрыцця. Агент апрацаваў 40 файлаў з 60, нешта ўпала па дарозе — а ў адказе ўсё роўна гучыць «я прааналізаваў рэпазіторый». Ніхто не схлусіў знарок; проста ніхто і не абяцаў лічыць, што прапушчана.

Да гэтай фічы вартай дысцыпліны на такія выпадкі ў нас не было: паводзіны агента — як пашанцуе канкрэтнай сесіі, пакрыццё ніхто не абяцаў лічыць, а факты ў адказах неадрозныя ад пераказу дакументацыі.

Раздзел 1. Ідэя: артыкул пра RLM і чаму нам не спатрэбілася іх бібліятэка

У снежні 2025 група з MIT (OASYS lab) апублікавала працу Recursive Language Models з open-source рэпазіторыем alexzhang13/rlm. Ідэя простая і прыгожая: замест таго каб запіхваць гіганцкі ўваход у промпт, rlm.completion() кладзе яго зменнай у REPL — і мадэль піша код, які гэты ўваход разглядае, наразае і рэкурсіўна выклікае суб-мадэль (rlm_query, з батчынгам і лімітам паралельных выклікаў) над кавалкамі. Кантэкст перастае быць тэкстам промпта і становіцца знешнім асяроддзем.

Лічбы з артыкула: апрацоўка ўваходаў да 100× даўжэйшых за роднае акно; на long-context бенчмарках медыянны адрыў ад vanilla GPT-5 — +26–130% у залежнасці ад baseline-стратэгіі (і ~+13% супраць baseline самога Claude Code), пры супастаўным кошце. Важная агаворка аўтараў: рэкурсіўная дэкампазіцыя выйграе на натуральна раскладальных задачах (аналіз коду, апрацоўка дакументаў) і шкодзіць цэласным паслядоўным разважанням. Рэпазіторый прапануе REPL-асяроддзі ад лакальнага працэсу да Docker і воблачных пясочніц і адзначае прымяненне ў DSPy, Symbolica і Google Cloud.

І тут мы заўважылі галоўнае: у Claude Code усе прымітывы RLM ужо ёсць, натыўна. Bash — гэта REPL для дэтэрмінаванай папярэдняй наразкі. Workflow-скрыпт — звычайны JavaScript-сцэнарый, з якога агент аркеструе суб-агентаў: agent() — літаральна «выклікаць суб-LLM як функцыю», ізалявана ад гісторыі сесіі; pipeline() і parallel() — батчынг з аўтаматычным лімітам паралелізму; budget — столь выдаткаў. Цягнуць python-залежнасць з другім слоем рэкурсіі ўнутр харнеса, які сам гэта ўмее, — залішне. Значыць, патрэбны не пакет, а скіл: дакумент, які замацоўвае дысцыпліну.

Раздзел 2. Што будавалі

Скіл recursive-context у плагіне my-architect: тонкі роўтэр + тры рэцэпты + адзін кананічны workflow-скрыпт. Задуму мы адразу заклалі шырэй, чым «адзін вялізны файл»: тыя ж прынцыпы пакрываюць аўдыт кодавай базы і здабычу фактаў з рэпазіторыя для патрабаванняў — аўдыт рэпо гэта роўна тая ж big-corpus задача, якую артыкул называе ідэальнай для рэкурсіі.

Ядро дысцыпліны ў адным абзацы: памер-гейт да чытання (ls/wc першым дзеяннем; ≤256 КБ і ≤5000 радкоў — чытай нармальна, скіл маўчыць) → index, don't ingest (межы кавалкаў рэжа код у scratchpad, кантэнт не цячэ праз акно; для «іголкавых» задач — спярша грубы grep) → fan-out ізаляваных суб-агентаў, кожнаму толькі яго кавалак + вузкае пытанне, вяртанне строга па схеме, не прозай → рэкурсія як цыкл (згортка агрэгата да малога ўнутры аднаго скрыпта) → сінтэз са шчырым пакрыццём (колькі кавалкаў апрацавана, якія ўпалі). Для фактаў з коду — асобны кантракт: {claim, evidence_path, confidence}, і жорсткае правіла — сцвярджэнне без шляху ў код фактам не з'яўляецца: яно ідзе ў дакумент плэйсхолдарам [факт: <пытанне>], а не праўдападобнай заглушкай.

Як гэта выглядае ўжывую

Першыя секунды працы — не чытанне, а разведка кодам. Рэальныя каманды з жывога прагону на 48.7-мегабайтным логе; увесь «кантакт» асноўнага агента са змесцівам файла — шэсць радкоў пробаў:

wc -lc fixture.log        # 600000 радкоў, 48 735 680 байт → гейт спрацаваў
head -4 fixture.log       # якой формы запісы? (4 радкі)
tail -2 fixture.log       # (яшчэ 2)
split -l 10000 -a 3 fixture.log chunks/chunk-   # 60 кавалкаў па ~793 КБ: рэжа код, не чытанне

Далей кожны суб-агент атрымлівае ізаляванае заданне — толькі свой кавалак і вузкае пытанне. Фрагмент рэальнага промпта з таго прагону:

Прааналізуй ТОЛЬКІ файл …/chunk-aat — гэта кавалак production-лога (~10000 радкоў). Працуй grep/awk/Read строга ўнутры гэтага файла, нікуды больш не хадзі. Фонавы шум лога мае выгляд: «\<timestamp\> DEBUG|INFO|WARN [auth|billing|catalog|gateway|search] request rid=N handled in Xms status=200». Пытанне: знайдзі УСЕ радкі, якія НЕ ўпісваюцца ў гэты шаблон шуму […] Калі анамалій няма — вярні пусты findings.

Адказваць суб-агент абавязаны не прозай, а структурай. Вось знаходка з таго прагону — даслоўна, як яна вярнулася (схема прымушае прыкласці дакладную цытату-доказ):

{
  "claim": "ERROR-level log line from an unexpected component (payment-reconciler)
            reporting a panic/ledger drift, not matching the standard noise template",
  "evidence": "2026-06-25T00:00:00 ERROR [payment-reconciler] PANIC: ledger drift detected txn=TXN-2222",
  "chunk": "…/chunks/chunk-aat"
}

Аркестрацыя — звычайны JavaScript, які агент перадае Workflow-тулу. Сэрца скрыпта (скарочана; поўны канон ляжыць у скіле):

const rawPartials = await pipeline(groups, (g, _o, i) =>
  agent(`Read ONLY these files: ${g.join(', ')}. Question: ${A.question}. …`,
        { label: `map:${i}`, schema: FINDING }))
const partials = rawPartials.filter(Boolean)                     // null = група, якая ўпала
const failedGroups = rawPartials.map((r, i) => (r ? -1 : i)).filter(i => i >= 0)

let prevSize = Infinity                                          // рэкурсія = цыкл са страхоўкай
while (JSON.stringify(working).length > 30_000) {
  const size = JSON.stringify(working).length
  if (size >= prevSize) { log(`no progress — stop`); break }     // гарантыя завяршэння
  prevSize = size
  /* …reduce-агенты згортваюць знаходкі партыямі… */
}
return { findings: working, groupsSucceeded: partials.length, failedGroups }  // пакрыццё шчырае

А так выглядае «факт» у задачы пра патрабаванні — даслоўны элемент з жывога прагону па нашым рэпазіторыі (звярні ўвагу: шлях і радкі, а не «недзе ў кодзе»):

{
  "claim": "updateNode(...) gates: if updates.status === 'done' && existing.status !== 'done',
            it computes getBlockers(...) and throws HierarchyValidationError(..., 'BLOCKED_BY_OPEN_ITEMS')",
  "evidence_path": "src/server/domain/hierarchy.ts:189-215",
  "confidence": "verified"
}

Раздзел 3. Чаму тэсты менавіта такія

Мы ішлі за «жалезным законам» распрацоўкі скілаў: eval-датасеты пішуцца да файлаў скіла, baseline здымаецца да аўтарынгу. Калі ты не бачыў, як агент памыляецца без скіла, — ты не ведаеш, чаму скіл вучыць. Тэсты выстраіліся ў тры слаі, кожны адказвае на сваё пытанне.

Трыгер-тэсты: «ці загрузіцца скіл сам?» Я з самага пачатку паставіў патрабаванне: агент павінен аўтаматычна разумець, калі ўзяць скіл, — без падказкі ад чалавека. У Claude Code рашэнне пра загрузку прымаецца па імені і апісанні — таму суддзі ў тэсце бачаць толькі name+description і запыт карыстальніка, нічога больш. Тры незалежныя суддзі на кейс; у датасеце не толькі пазітывы (лог 200 МБ, дамп, транскрыпт, аўдыт рэпо — па-руску і па-англійску), але і near-miss негатывы: YAML на 300 радкоў, праўка трох вядомых файлаў, 40 аднатыпных тыкетаў з CSV. Плюс крос-рэгрэсія: 10 пазітываў суседняга скіла myarchitect — новы скіл не павінен красці чужыя трыгеры. Скіл, які фаерыцца на ўсё запар, шкаднейшы за скіл, якога няма.

Паводзінскія тэсты: «ці выконваецца дысцыпліна?» Шэсць dry-run кейсаў, кожны б'е ў канкрэтны спосаб зламацца: гейт да чытання (супраць «спачатку проста прачытаю»); маўчанне пад парогам (супраць карга-культу — 180-радковы лог не заслугоўвае канвеера); grep да fan-out (эфектыўнасць); рэкурсія цыклам, а не ўкладзеным workflow() (жорсткае абмежаванне платформы — укладанне глыбей за адзін узровень немагчымае); кантракт фактаў; і фолбэк, калі Workflow-тула наогул няма. Выканаўцы пішуць план дзеянняў, незалежны грэйдар радок за радком звярае з assertions.

Live-прагоны: «ці працуе машынэрыя па-сапраўднаму?» Dry-run правярае план, але не выкананне. L1 — сінтэтычны лог на 600 000 радкоў / 48.7 МБ з 12 засеянымі «іголкамі», пазіцыі якіх вядомыя дэтэрмінаванаму генератару: гэта дае вымяральныя recall і precision замест уражанняў. Іголкі трох тыпаў не выпадковыя: 4 рэдкія PANIC (пошук анамалій), 3 падазроныя config-перавызначэнні — і 5 крокаў адной сесіі (login → elevate-privileges → export-full-dump → wipe-audit-trail → logout), размазаных па розных канцах файла: гэты тып правярае сінтэз — ці зможа канвеер сабраць звязны сюжэт з кавалкаў, апрацаваных рознымі агентамі. L2 — не сінтэтыка: рэальны рэпазіторый і рэальнае пытанне — «што ўжо працуе ў кодзе і не павінна быць кранута?» — з выбарачнай ручной праверкай шляхоў-доказаў.

Раздзел 4. Цяжкасці. Тры кейсы, якія зрабілі фічу лепшай

Кейс 1. Baseline аказаўся занадта добрым

Непрыемны (і самы карысны) сюрпрыз RED-замеру — прагону тых жа задач без скіла, знятага да таго, як скіл быў напісаны. Мы далі агенту той самы 48.7-мегабайтны лог — чакаючы ўбачыць спробу чытання ў лоб. Замест гэтага Sonnet холаднакроўна зрабіў wc -l, паглядзеў 20 радкоў галавы і 21 хваста, прайшоўся grep/awk-статыстыкай па ўзроўнях і кампанентах — і знайшоў усе 12 іголак за 7 выклікаў інструментаў і ~37 тысяч токенаў. Baseline па здабычы фактаў са знаёмага рэпо таксама быў моцны.

Шчыры вывад давялося ўбудаваць і ў справаздачу, і ў сам скіл: на greppable-іголках у аднародным машыначытальным логе grep-first ужо «ў крыві» ў мадэляў — і скіл не павінен з гэтым змагацца, ён павінен гэта ўзаконіць (рэцэпт giant-file, крок 2: кандыдаты ўлезлі → адказвай наўпрост, fan-out не патрэбны, так і скажы). Сапраўдная дэльта скіла не «выратаванне ад наіўнага чытання», а тры іншыя рэчы: кантракт (схемы, confidence-разметка, плэйсхолдары, пакрыццё — baseline вярнуў моцную прозу, дзе факты з коду і пераказ докаў неадрозныя), маштабавальнасць на задачы разумення без grep-якараў і корпусы, большыя за акно, і кансістэнтнасць — дысцыпліна замацавана рэгрэсійнай сеткай, а не залежыць ад настрою канкрэтнай сесіі. Калі б мы не знялі baseline, мы б прадавалі скіл не за тое, што ён робіць.

Кейс 2. Цыкл, які мог не скончыцца, і пакрыццё, якое хлусіла

Зводнае рэўю знайшло ў кананічным скрыпце два дэфекты, крыўдныя менавіта сваёй тонкасцю. Першы: reduce-цыкл («згортвай знаходкі, пакуль агрэгат не стане маленькім») не меў гарантыі завяршэння — reduce-агент, якому загадалі «дэдуплікуй і адкінь нерэлевантнае», мае поўнае права вярнуць столькі ж знаходак, колькі атрымаў, калі ўсе ўнікальныя і рэлевантныя. Агрэгат перастае памяншацца — цыкл працягвае пладзіць агентаў. Фікс — no-progress guard: раўнд не паменшыў агрэгат → выходзім з логам; пасля фікса тэрмінацыя даказальная (адсочваны памер строга спадае).

Другі дэфект быў горшы, бо парушаў уласнае правіла скіла. Скрыпт вяртаў chunksProcessed: <усе чанкі> безумоўна — нават калі частка map-агентаў упала і іх кавалкі ніхто не чытаў. Тое самае «ціхае звужэнне пакрыцця» з пралога, толькі цяпер унутры інструмента, які абяцаў з ім змагацца. Фікс: неадфільтраваны масіў вынікаў захоўвае null на месцы кожнай групы, якая ўпала, — гэта адзіны спосаб даведацца, што менавіта не пакрыта; вяртанне стала шчырым: {groupsSucceeded, failedGroups, …}, і правіла «failedGroups абавязаны трапіць у фінальны адказ карыстальніку» ўпісана ў тэкст скіла.

Туды ж — урок пра рэўю тэставай абвязкі: рэўюер выконваў генератар фікстуры на межавых уваходах, а не чытаў яго. Так знайшліся бясконцы цыкл на нелічбавым аргуменце (POSIX awk параўноўвае лік з радком пасімвальна — умова цыкла вечна праўдзівая; 76 МБ смецця за 3 секунды) і ціхая страта іголкі на маленькіх памерах (пазіцыя абразалася ў неіснуючы радок 0).

Кейс 3. Чатырнаццаць мілісекунд

Першы live-запуск L1 завяршыўся за 14 мс з вынікам chunksTotal: 0. Ніводзін агент не стартаваў. Мінімальны воркфлоў-зонд паказаў прычыну: args прыходзіць у скрыпт JSON-радком, а не аб'ектам — нават калі перадаць аб'ект. args.count быў undefined, цыкл пабудовы спісу чанкаў не выканаўся ніводнага разу, скрыпт шчыра вярнуў пустэчу.

Ні dry-run, ні рэўю коду гэтага не злавілі б — дэфект жыве на мяжы паміж інструментам і скрыптам і праяўляецца толькі пры сапраўдным выкліку. Фікс — адзін радок ахоўнага парсу (const A = typeof args === 'string' ? JSON.parse(args) : args) — пайшоў у кананічны скрыпт скіла і ў план, з пазнакай «праверана жывым прагонам». Гэта найлепшы аргумент за тое, чаму прыёмка была live: яе задача — не пацвердзіць, што ўсё добра, а знайсці тое, што можа знайсці толькі рэальнасць.

Бонус таго ж роду: у субагентаў-выканаўцаў паводзінскіх тэстаў Workflow-тула фізічна няма — двое з іх самі выявілі гэта праз пошук інструментаў і карэктна перайшлі на задакументаваны фолбэк (паралельныя звычайныя агенты, тая ж дысцыпліна). Фолбэк-галінка скіла прайшла жывую праверку выпадкова — але па-сапраўднаму.

Раздзел 5. Было → стала

Было (RED, без скіла)Стала (GREEN + LIVE, са скілам)
Вялізны файлняма дысцыпліны: як пашанцуе канкрэтнай сесіі; пакрыццё не заяўляеццапамер-гейт да чытання; grep-first узаконены; fan-out 60 агентаў пры неабходнасці; recall 12/12, precision 12/12 — baseline таксама знайшоў 12/12, дэльта не ў дакладнасці пошуку, а ў яўна заяўленым пакрыцці 60/60 груп і кансістэнтнасці (гл. Кейс 1)
Факты з кодумоцная проза: факты з коду і пераказ докаў неадрозныя, дзірак не відаць40 фактаў, 100% са шляхам і радкамі, verified/inferred разведзены, 2 дзіркі — яўныя [факт: …]; выбарачная праверка 5/5 пацвердзіла даслоўна
Аўтавыбар скіла60/60 суддзейскіх галасоў (пазітывы, near-miss негатывы, крос-рэгрэсія суседа — 0 ілжывых спрацоўванняў)
Гарантыі канвеера— (без скіла канвеера не існавала); у чарнавіку скіла да рэўю: цыкл мог не завяршыцца, пакрыццё магло хлусіцьтэрмінацыя даказальная; failedGroups у вяртанні; args-радок абясшкоджаны
Акно main-агента~37k токенаў пробаў і grep-статыстык праходзяць праз акно (так прайшоў baseline)L1: праз акно прайшло 6 радкоў пробаў — сам 48.7-мегабайтны файл праз акно не праходзіў наогул

Пабочны прадукт L2, якога ніхто не заказваў: здабыча фактаў выкрыла рэальнае пытанне да прадукту — UI піша залежнасць dependsOn наўпрост у лакальны store, мінаючы HTTP-роўт з валідацыяй. Мы завялі на гэта асобную праверачную задачу. Добры канвеер фактаў знаходзіць не толькі тое, пра што пыталіся.

Раздзел 6. А эфектыўнасць?

Знаходзіць складанае — паўсправы; важна не плаціць канвеерам за ўсё запар. Эфектыўнасць тут спраектавана, і тэсты правяраюць менавіта яе.

Скіл умее маўчаць. Пад парогам (тэст «лог на 180 радкоў») — звычайнае чытанне, нуль машынэрыі. Негатыўныя трыгер-кейсы і крос-рэгрэсія пацвярджаюць на ўсіх правераных сцэнарыях (42/42 галасы «не фаерыць»), што канвеер не запускаецца на задачах, дзе ён — аверхэд.

Grep да fan-out. Іголкавая задача з вядомым якарам вырашаецца выразаннем рэгіёнаў без ніводнага суб-агента — і агент абавязаны яўна сказаць, што fan-out не спатрэбіўся (тэст 3).

Малы корпус — без Workflow. Рэцэпт requirements-mining наўпрост забараняе гармату па вераб'ях: ≤30 рэлевантных файлаў → адзін агент са спісам. Жывы L2 так і прайшоў: 1 агент, ~74k токенаў, 36 выклікаў — на выхадзе 40 правяральных фактаў.

Цана поўнага fan-out вядомая і заплачана свядома. L1 з 60 агентамі каштаваў ~1.22M суб-токенаў і ~2.5 хвіліны — на гэтай задачы grep быў бы ў ~33 разы таннейшы (~37k токенаў, Кейс 1). Мы гэта ведаем і не хаваем: на greppable-задачах скіл прадпісвае grep і канвеер не ўключае, а дарагі прагон быў разавай прыёмкай машынэрыі — і акупіўся першым жа знойдзеным багам (Кейс 3). Fan-out — інструмент для выпадкаў, калі grep не працуе ў прынцыпе (проза, транскрыпты, пытанні разумення), а не падатак на кожны вялікі файл. Пры гэтым суб-токены — расход ізаляваных вокнаў; акно асноўнай сесіі засталося чыстым, і гэта часта самая дэфіцытная валюта.

Бюджэт і глыбіня. Кананічны скрыпт паважае budget як абмежавальнік глыбіні згорткі і лагуе раннія прыпынкі. Дзеля шчырасці: гэтая галінка праверана толькі dry-run кейсам пра згортку — жывога прагону з рэальным budget-стопам не было.

Эпілог. Што засталося шчыра недаказаным

Парог 256 КБ / 5000 радкоў — стартавы дэфолт, не выпакутаваная лічба: яе цюніць па вопыце. Два сцэнарыі не правераны ўжывую — гэта найлепшыя кандыдаты наступнага eval-раўнду: repo-audit цалкам (multi-modal sweep + «капай, пакуль два раўнды запар не суха») на вялікім незнаёмым рэпазіторыі і празаічны транскрыпт без grep-якараў: менавіта там, паводле артыкула RLM, чакаецца максімальны адрыў ад baseline, і менавіта там шчыры baseline паказаў бы сапраўдны правал без скіла. І знойдзенае пытанне пра двайны шлях запісу dependsOn таксама чакае сваёй праверкі.

Як паспрабаваць

Скіл едзе ў плагіне my-architect пачынаючы з v1.13.0 і ўключаецца сам, калі задача пахне вялікім корпусам — рукамі яго клікаць не трэба (у гэтым і быў сэнс трыгер-тэстаў).

  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. Ужо стаіць плагін? /plugin marketplace update my-architect-marketplace/plugin update my-architect.

---

Факты і спасылкі