<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://baba9811.github.io/feed.xml" rel="self" type="application/atom+xml"/><link href="https://baba9811.github.io/" rel="alternate" type="text/html" hreflang="ko"/><updated>2026-09-01T23:46:22+00:00</updated><id>https://baba9811.github.io/feed.xml</id><title type="html">Research Notes</title><subtitle>Paper reviews and research notes on machine learning and AI. </subtitle><entry xml:lang="ko"><title type="html">[논문 리뷰] Accurate Decoding of Natural Sentences from Non-Invasive Brain Recordings</title><link href="https://baba9811.github.io/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/" rel="alternate" type="text/html" title="[논문 리뷰] Accurate Decoding of Natural Sentences from Non-Invasive Brain Recordings"/><published>2026-08-24T05:00:00+00:00</published><updated>2026-08-24T05:00:00+00:00</updated><id>https://baba9811.github.io/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra</id><content type="html" xml:base="https://baba9811.github.io/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/en/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/" class="btn btn-sm btn-outline-secondary">🇺🇸 Read in English</a> </div> <h2 id="메타정보">메타정보</h2> <table> <thead> <tr> <th>항목</th> <th>내용</th> </tr> </thead> <tbody> <tr> <td>저자</td> <td>Mingfang (Lucy) Zhang et al. (저자 12명, Meta AI · ENS-PSL · BCBL 외)</td> </tr> <tr> <td>학회</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv 또는 DOI</td> <td><a href="https://arxiv.org/abs/2608.18114">2608.18114</a></td> </tr> <tr> <td>Code</td> <td><a href="https://github.com/facebookresearch/brain2qwerty">facebookresearch/brain2qwerty</a></td> </tr> <tr> <td>데이터</td> <td>EnglishBCBL — 건강한 성인 9명 × 10시간 MEG (306채널 Megin), 고유 문장 2,724개 · 총 22,000여 문장 타이핑</td> </tr> <tr> <td><span style="white-space: nowrap">리뷰 일자</span></td> <td>2026-08-24</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>비침습 MEG 만으로 사람이 타이핑하는 자연 문장을 평균 <strong>WER 39%</strong> 로 디코딩한다. 최고 피험자는 WER 22%, 테스트 문장의 28% 를 단어 오류 0개로, 47% 를 단어 편집 1회 이내로 복원한다. 직전 SOTA 인 Brain2Qwerty v1 의 최고 피험자 52% 대비 두 배 개선이다.</li> <li>열쇠는 모델이 아니라 <strong>데이터 규모와 문장 다양성</strong>이었다. 피험자당 1시간 → 10시간으로 늘리자 키 입력 타이밍을 몰라도 되는 비동기 (asynchronous) 인코더의 CER 이 0.59 → 0.25 로 떨어져, 타이밍을 아는 동기 (synchronous) 인코더 0.23 을 2%p 차이까지 따라붙었다. 스케일링은 로그 선형이며 90시간에서도 포화 조짐이 없다 (기울기 −0.39 CER/decade).</li> <li>파이프라인은 문자 · 단어 · 문장 세 층을 함께 학습한다. CTC 인코더 (BrainModule + Conformer) 가 문자를, SigLIP 정렬기가 MEG 임베딩을 단어 임베딩으로, LoRA 로 미세조정한 Qwen3 가 문장을 담당한다. 셋을 잇는 장치가 <strong>CTC 토크나이저</strong> — CTC 가 예측한 space 위치로 연속 MEG 임베딩을 단어 덩어리로 자른다.</li> <li>LLM 은 CTC 출력을 문법적으로 다듬는 교정기가 아니다. MEG 토큰을 프롬프트에서 빼는 ablation 만으로 WER 이 0.43 → 0.49 로 나빠진다. LLM 이 실제로 신경 신호를 읽고 있다는 뜻이다.</li> <li>세 개의 자율 AI 코딩 에이전트 (Cursor + Claude Opus 4.6) 에게 파이프라인 튜닝을 맡겼더니 Optuna TPE 를 크게 앞섰다 (교차 피험자 테스트 WER: Optuna 0.493 · 개선 없음 vs 에이전트 0.42/0.43/0.45 · 최대 −16%). 반대로 “v1 코드베이스에서 시작해 v2 성능을 재현하라” 는 열린 과제에서는 셋 다 완전히 실패했다.</li> </ul> <h2 id="소개-introduction">소개 (Introduction)</h2> <p>말과 움직임을 잃은 사람에게 소통을 되돌려 주는 문제에서, 지난 몇 년의 성과는 거의 전부 <em>침습</em> BCI 쪽에서 나왔다. 운동 피질에 전극을 심은 환자들이 시도 발화 (attempted speech) 로 언어를 만들어 내고 (Moses et al., 2021; Willett et al., 2023; Card et al., 2024), 손글씨 (Willett et al., 2021) 와 타이핑 (Pandarinath et al., 2017; Jude et al., 2026) 으로 자연 발화에 근접한 속도와 정확도에 도달했다. 문제는 그 대가다. 개두술은 의료적 위험을 수반하고, 신경염증 반응 때문에 장기간 좋은 기록 품질을 유지하기 어려우며, 넓은 환자군에 수술 인프라를 제공하는 일 자체가 물류 난제다.</p> <p>비침습 대안은 오래 논의돼 왔지만 각각 결정적인 약점이 있었다. EEG 는 신호대잡음비가 나빠 환자에게 요구하는 인지 부담이 지나치게 크고, fMRI 는 시간 해상도가 원리적으로 낮아 실시간 소통에 쓸 수 없다. MEG 는 그 사이 어딘가에서 가장 유망한 후보로 꼽혀 왔다. 특히 같은 그룹의 직전 작업인 Brain2Qwerty v1 (Lévy et al., 2025) 은 키 입력 시점에 시간 정렬된 분류기를 학습해 CER 32% 로 타이핑된 텍스트를 디코딩했다.</p> <p>그런데 v1 에는 세 가지 구조적 한계가 있었다. 첫째, 개별 키 입력의 <em>타이밍을 알아야</em> 동작한다 — 실사용에서는 그 타이밍이야말로 알 수 없는 값이다. 둘째, 문자 분류를 잘한다고 문장 복원이 되는 건 아니다. 몇 글자만 틀려도 출력 전체가 읽을 수 없게 된다. 셋째, 데이터가 너무 적었다. 침습 BCI 가 10~40시간에 걸쳐 수천 문장을 쓰는 데 반해 v1 은 피험자당 1시간이었다.</p> <p>이 논문은 세 한계를 정면으로 겨냥한다. 9명에게서 각 10시간, 총 90회 세션을 기록해 22,000여 문장 코퍼스를 만들고, CTC (Connectionist Temporal Classification) 목적함수로 타이밍 의존을 없애고, LLM 을 붙여 문장 수준 복원을 맡겼다. 그리고 그 위에 하나를 더 얹었다 — 파이프라인 자체의 최적화를 자율 AI 에이전트에게 맡기는 실험이다. 비침습 BCI 를 직접 다루지 않더라도, “데이터 규모가 아키텍처를 이기는 지점” 과 “LLM 을 비언어 모달리티의 디코더로 붙이는 실무적 방법” 두 가지 때문에 읽을 값어치가 있다.</p> <h2 id="핵심-기여-key-contributions">핵심 기여 (Key Contributions)</h2> <ul> <li><strong>비침습 문장 디코딩의 정확도를 실용 영역 근처까지 끌어올렸다.</strong> 평균 WER 39%, 최고 피험자 22%. fMRI 로 <em>지각된</em> 음성을 복원한 Tang et al. (2023) 의 WER 0.92–0.94 와 비교하면, 정확한 단어를 맞히는 능력에서 질적으로 다른 수준이다.</li> <li><strong>데이터 규모와 문장 다양성이 독립적인 두 축임을 분리해 보였다.</strong> 총 문장 수와 피험자 수를 맞춘 통제 실험에서, 128문장 × 2회 반복보다 256문장 × 1회가 CER 0.65 → 0.45 로 유의하게 낫다. 언어모델 없이도 성립하는 결과다.</li> <li><strong>CTC 토크나이저.</strong> CTC 가 예측한 space 토큰 위치로 연속 신경 임베딩을 단어 단위로 자르는 단순한 장치인데, 문장 정렬 (0.46) · 패치 토큰화 (0.49) 대비 WER 0.39 로 앞선다. CTC 기반 파이프라인이라면 어디에나 이식할 수 있는 일반 기법이다.</li> <li><strong>LLM 이 교정기가 아니라 신경 신호의 독자임을 실증했다.</strong> MEG 토큰을 프롬프트에서 제거하는 ablation 으로 세 지표가 모두 나빠진다. ~2,700 문장이라는, LLM 미세조정 기준으로는 극도로 작은 코퍼스로 이 적응이 일어난다는 점이 특히 인상적이다.</li> <li><strong>자율 AI 에이전트를 연구 루프에 넣은 통제된 비교.</strong> 동일 컴퓨트 예산에서 Optuna TPE 와 정면 비교했고, 성공 조건 (탐색 공간이 제한된 하이퍼파라미터 튜닝) 과 실패 조건 (아키텍처를 새로 발명하는 열린 과제) 을 둘 다 보고한다.</li> </ul> <h2 id="관련-연구--배경-지식">관련 연구 / 배경 지식</h2> <h3 id="동기-vs-비동기-디코딩">동기 vs 비동기 디코딩</h3> <p>이 논문을 이해하는 데 가장 중요한 구분이다. <strong>동기 (synchronous) 디코딩</strong>은 각 키 입력 시점에 시간 정렬된 짧은 윈도우 (약 3초) 를 잘라 그 안의 문자를 분류한다. Brain2Qwerty v1 이 이 방식이다. 정확도는 높지만 키 입력 시점을 외부에서 알려 줘야 한다. <strong>비동기 (asynchronous) 디코딩</strong>은 10초 이상의 연속 응답 구간을 통째로 받아 텍스트 시퀀스를 생성한다. 타이밍 정보가 필요 없으므로 실시간 사용이 가능하지만, 정렬을 스스로 찾아야 하니 훨씬 어려운 문제다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig1-scale-and-variety-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig1-scale-and-variety-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig1-scale-and-variety-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig1-scale-and-variety.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: 비동기 MEG 디코딩은 녹화 규모와 문장 다양성으로 열린다. A 는 실험 프로토콜과 키 입력 시점의 MEG 소스 재구성, B 는 동기·비동기 접근 비교, C 는 두 데이터셋의 규모, D·E 는 두 인코더의 CER, F 는 데이터량에 따른 스케일링, G 는 반복 문장 유무에 따른 차이.</figcaption> </figure> <h3 id="ctc--정렬-없이-시퀀스를-학습하는-법">CTC — 정렬 없이 시퀀스를 학습하는 법</h3> <p>CTC (Graves et al., 2006) 는 음성 인식에서 온 목적함수로, 길이가 다른 입력 시퀀스와 출력 시퀀스를 <em>프레임 단위 정렬 라벨 없이</em> 학습시킨다. 핵심은 blank 토큰의 도입이다. 모델은 매 시간 프레임마다 문자 또는 blank 를 내놓고, 연속된 중복 문자를 접고 blank 를 지운 결과가 목표 문자열이 되는 <em>모든</em> 경로의 확률을 합해 최대화한다. 이 논문의 어휘는 blank (index 0) · 소문자 26자 (1–26) · space (27) 의 28개 클래스다.</p> <p>CTC 가 이 파이프라인에서 하는 일은 두 가지다. 하나는 타이밍 의존을 제거하는 것. 다른 하나는 뒤에 나올 CTC 토크나이저의 근거를 제공하는 것 — greedy 경로가 space 를 내뱉는 프레임 위치가 곧 단어 경계의 추정치가 된다.</p> <h3 id="brainmodule-conformer-그리고-siglip">BrainModule, Conformer, 그리고 SigLIP</h3> <p><strong>BrainModule</strong> (Défossez et al., 2023) 은 MEG 센서 배열의 물리적 배치를 다루는 모듈이다. 센서는 3차원 공간에 흩어져 있고 활성 채널 수는 세션마다 다르므로, 센서 좌표를 2차원 Fourier feature 로 인코딩해 가변 길이 센서 배열을 고정 차원 (270 virtual channel) 으로 사영한다. 피험자별 affine 층을 subject index 로 조건화해, 명시적 센서 수준 공동 정합 (co-registration) 없이 개인별 센서 기하를 흡수한다.</p> <p><strong>Conformer</strong> (Gulati et al., 2020) 는 convolution 과 self-attention 을 교차 배치한 음성 인식용 블록이다. convolution 이 국소 시간 구조를, attention 이 장거리 의존을 담당한다. 이 논문의 부록 실험은 Conformer 를 표준 Transformer 로 바꾸기만 해도 인코더 CER 이 0.25 → 0.28 로 나빠짐을 보인다.</p> <p><strong>SigLIP</strong> (Zhai et al., 2023) 은 CLIP 계열 대조 학습의 변형으로, softmax 대신 pairwise sigmoid binary cross-entropy 를 쓴다. 배치 전체에 걸친 정규화가 필요 없어 구현이 단순하고 작은 배치에서도 안정적이다. 여기서는 MEG 유래 단어 임베딩을 LLM 의 실제 단어 임베딩에 붙이는 데 쓰인다.</p> <h2 id="방법--아키텍처-상세">방법 / 아키텍처 상세</h2> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig2-architecture-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig2-architecture-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig2-architecture-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig2-architecture.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: Brain2Qwerty v2 아키텍처. 입력은 문장 하나에 해당하는 연속 MEG 기록뿐이며, 문자 (Encoder · CTC loss) · 단어 (Aligner · SigLIP loss) · 문장 (LLM · cross-entropy) 세 모듈이 함께 최적화된다.</figcaption> </figure> <h3 id="1단--문자-meg-인코더">1단 — 문자: MEG 인코더</h3> <p>인코더는 두 단계로 나뉜다.</p> <p><strong>BrainModule.</strong> 센서 좌표를 2차원 Fourier feature (총 임베딩 차원 2,048) 로 인코딩해 가변 채널을 270개 virtual channel 로 매핑하고, subject index 로 조건화한 affine 층을 적용한다. 이렇게 공간적으로 융합된 $B \times 270 \times T$ 표현 ($T$ 는 100 Hz 시간 프레임 수) 이 4층 dilated convolution 으로 들어간다 (hidden 1,500, kernel 5, dilation period 3). GELU · batch norm · residual skip (0.1 배 스케일) · dropout (input 0.2, conv 0.5) 을 쓰고, conv stack 앞에 채널 차원을 512 로 줄이는 선형 사영을 둔다. 이어서 stride 4 의 1D convolution (kernel 16) 으로 시간 해상도를 1/4 로 줄여 프레임당 약 40 ms 를 만든다.</p> <p><strong>Conformer.</strong> 다운샘플된 시퀀스를 4층 Conformer 가 처리한다 (model dim 1,024, attention head 4, feed-forward 1,024, depthwise conv kernel 17, dropout 0.3). 출력에 선형 head 를 붙여 28-class 문자 분포를 낸다.</p> <p>학습에는 보조 CTC head 를 하나 더 쓴다. 시간 다운샘플링 직후 (Conformer 이전) 에 붙여 함께 학습하며, 합성 손실은 다음과 같다.</p> \[\mathcal{L} = (1-\alpha)\,\mathcal{L}_{CTC}^{\text{final}} + \alpha\,\mathcal{L}_{CTC}^{\text{aux}}, \quad \alpha = 0.7\] <p>$\alpha = 0.7$ 이므로 학습 초기의 그래디언트 신호는 보조 분기가 지배하고, Conformer 는 그 위에서 최종 표현을 다듬는 역할을 맡는다 (Nozaki and Komatsu, 2021 의 방식).</p> <h3 id="2단--단어-ctc-토크나이저와-정렬기">2단 — 단어: CTC 토크나이저와 정렬기</h3> <p>연속적인 MEG 임베딩과 LLM 이 기대하는 단어 수준 토큰 사이의 간극을 메우는 것이 이 파이프라인의 실질적 핵심이다. 방법은 놀랄 만큼 단순하다. <strong>CTC greedy 경로가 space 토큰을 내뱉은 프레임 위치에서 Conformer 출력을 자른다.</strong> 각 단어 구간 (blank 프레임 포함) 을 프레임별 2층 MLP 에 통과시킨 뒤 시간 축으로 mean-pool 해 단일 신경 단어 임베딩을 만들고, 선형 adapter 로 LLM hidden 차원에 맞춘다.</p> <p>이 단순한 규칙이 통하는 근거는 통계다. space 는 문자 전체의 19% 를 차지할 만큼 빈번하며 그만큼 예측도 견고하다. 그래서 예측된 단어 수가 정답의 ±1 단어 안에 드는 문장이 <strong>86%</strong> 다.</p> <p>그래도 CTC 분할이 만든 신경 토큰 개수 $N$ 과 실제 목표 단어 수 $M$ 은 다를 수 있다. 그래서 대조 학습 전에 문장 내부 정렬 단계를 둔다. $N$ 개 신경 임베딩과 $M$ 개 목표 단어 임베딩 (LLM 입력 임베딩 층에서 가져온다) 사이의 코사인 거리 비용 행렬을 만들고, hard DTW (Sakoe and Chiba, 1978) 로 단조 정렬 경로를 찾아 일대일 쌍을 뽑는다 (신경 토큰당 목표 하나).</p> <p>뽑힌 쌍들을 배치 전체에서 모아 $\ell_2$ 정규화한 뒤 SigLIP 손실을 계산한다. 배치 내 모든 쌍 $(i, j)$ 에 대해 스케일된 코사인 유사도에 sigmoid binary cross-entropy 를 적용한다.</p> \[\text{logit}_{ij} = \tau \langle \hat{\mathbf{w}}_i, \mathbf{w}_j \rangle + b\] <p>$\tau$ 와 $b$ 는 학습 가능한 스칼라다. 라벨은 정답 임베딩 $\mathbf{w}_i$ 와 $\mathbf{w}_j$ 의 코사인 유사도가 0.999 이상일 때 (즉 같은 단어일 때) 1, 아니면 0 이다. 이 중복 인지 (duplicate-aware) 라벨링이 없으면, 같은 문장이 여러 피험자에게서 나타날 때 서로를 거짓 음성 (false negative) 으로 취급하게 된다.</p> <h3 id="3단--문장-neuro-conditioned-llm">3단 — 문장: neuro-conditioned LLM</h3> <p>프롬프트 구성은 다음과 같다.</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[CTC: ‖ &lt;CTC 디코딩 텍스트 토큰&gt; ‖ \nMEG: ‖ &lt;MEG 토큰 임베딩&gt; ‖ \nOutput:]
</code></pre></div></div> <p>즉 LLM 은 두 개의 입력 스트림을 받는다. CTC 텍스트는 그럴듯한 언어적 사전 (prior) 에 LLM 을 묶어 두고, MEG 토큰은 그 사전을 넘어서게 밀어 줄 잔여 신경 정보를 나른다.</p> <p>학습 시에는 <strong>modality dropout</strong> 으로 MEG 토큰 임베딩과 CTC 텍스트 토큰 양쪽에서 무작위 토큰 위치를 독립적으로 0 으로 만든다 (각각 비율 0.1). 어느 한쪽 모달리티만으로도 견고하게 조건화되도록 강제하는 장치다. 손실은 label smoothing 0.02 를 적용한 cross-entropy 다.</p> <p>LLM 은 Qwen3-4B 를 LoRA (rank 128, $\alpha = 256$, dropout 0.0) 로 모든 선형 사영 행렬에 적용해 미세조정한다. 추론은 beam size 16, 최대 60 신규 토큰, length penalty 0.2 의 beam search 다.</p> <h3 id="model-soup--피험자를-별개-태스크로-다루기">Model soup — 피험자를 별개 태스크로 다루기</h3> <p>LoRA 를 붙이는 방식으로 세 가지를 비교한다. <em>Joint LoRA</em> 는 아홉 명 데이터를 합쳐 단일 adapter 를 학습한다. <em>Per-subject LoRA</em> 는 피험자별로 독립 adapter 아홉 개를 학습한다. <em>Model Soup</em> (Wortsman et al., 2022) 은 피험자별 adapter 를 학습한 뒤 best checkpoint 의 state dict 를 균일 평균해 단일 adapter 로 만들어 전원에게 적용한다.</p> <p>발상은 이렇다. 각 피험자의 MEG 서명은 서로 다른 “태스크” 이므로, adapter 를 태스크별로 특화시킨 뒤 가중치 공간에서 평균 내면 무거운 단일 joint 모델을 학습하지 않고도 일반화되는 하나의 모델을 얻는다.</p> <h3 id="학습-목표--손실-함수">학습 목표 / 손실 함수</h3> <p>전체 손실은 세 항의 가중합이다.</p> \[\begin{aligned} \mathcal{L} = \; &amp; (1 - \alpha - \beta)\,\mathcal{L}_{\text{CTC}} \\ &amp; + \alpha\,\mathcal{L}_{\text{Contrastive}} \\ &amp; + \beta\,\mathcal{L}_{\text{CE}} \end{aligned}\] <ul> <li>$\mathcal{L}_{\text{CTC}}$ — 문자 수준. 뇌 신호를 키 입력 문자열로 옮기는 능력을 담당한다. 부록의 상관 분석 (Figure S5) 이 보이듯 이 항의 품질이 최종 성능을 사실상 결정한다.</li> <li>$\mathcal{L}_{\text{Contrastive}}$ — 단어 수준 SigLIP 손실. MEG 단어 덩어리를 LLM 의 단어 임베딩 공간으로 끌어당긴다.</li> <li>$\mathcal{L}_{\text{CE}}$ — 문장 수준 자기회귀 cross-entropy. 프롬프트에 담긴 CTC 텍스트와 신경 토큰 양쪽에 조건화해 목표 문장을 생성하도록 학습한다.</li> </ul> <p>두 가지 학습 레짐을 실험했다. <strong>(i) End-to-end 단계별 학습</strong>은 275 epoch 를 세 구간으로 나눈다 — CTC 만 (epoch 0–149), CTC + contrastive (150–224, $\alpha = 0.1$), CTC + contrastive + LLM CE (225–274, $\beta = 0.01$). 비활성 항은 버리고 활성 가중치를 합이 1 이 되게 재정규화한다. <strong>(ii) Standalone LoRA 미세조정</strong>은 최고 contrastive checkpoint 에서 CTC 인코더와 사전학습된 단어 사영기를 얼린 뒤, LoRA 가 붙은 LLM 만 단일 GPU 에서 30 epoch 최적화한다. 가벼운 이 레짐이 LoRA 설정 · LLM 크기 · model soup 전략을 빠르게 반복하게 해 줬고, <em>최종 최고 성능도 여기서 나왔다</em>.</p> <h2 id="학습-데이터와-파이프라인">학습 데이터와 파이프라인</h2> <h3 id="englishbcbl-데이터셋">EnglishBCBL 데이터셋</h3> <table> <thead> <tr> <th>항목</th> <th>내용</th> </tr> </thead> <tbody> <tr> <td>피험자</td> <td>건강한 성인 9명 (남녀 각 50%, 평균 34.6세, 범위 23–56세)</td> </tr> <tr> <td>조건</td> <td>전원 오른손잡이 · 화면을 보지 않고 타이핑 가능 · 타이핑 정확도 80% 이상 · 영어 원어민 · 신경/정신과 병력 없음</td> </tr> <tr> <td>기록</td> <td>피험자당 10회 세션 × 약 1시간 = 총 90시간</td> </tr> <tr> <td>장비</td> <td>Megin 306채널 (magnetometer 102 + planar gradiometer 204), 1 kHz 샘플링, online 0.1 Hz HPF / 330 Hz LPF</td> </tr> <tr> <td>키보드</td> <td>HybridMojo LLC 의 MR 호환 QWERTY 키보드 (비강자성 스프링으로 개조)</td> </tr> <tr> <td>MRI</td> <td>3-T SIEMENS Prisma-fit, 64채널 head coil, T1 (TR 2530 ms, TE 2.36 ms, flip 7°, FOV 256 mm, 1 mm³, 176 slice)</td> </tr> <tr> <td>문장</td> <td>Llama 4 로 생성한 간단한 영어 문장 20,000개 풀에서 특수문자·축약형 제거 후 2,560개 무작위 선정. 파일럿 세션 포함해 최종 2,724 고유 문장</td> </tr> <tr> <td>보상</td> <td>시간당 12유로 + 완료 시 200유로</td> </tr> </tbody> </table> <h3 id="과제-설계">과제 설계</h3> <p>각 시행은 세 국면으로 이뤄진다 — <strong>듣기 → 신호 대기 → 타이핑</strong>. MEG 호환 헤드폰으로 문장 오디오를 재생하고, 화면에 fixation cross 를 1.5초 띄운 뒤, cross 가 사라지는 것이 타이핑 시작 신호다. 타이핑 중 화면에는 <em>글자가 전혀 표시되지 않는다</em>. 참가자는 backspace 없이 최대한 정확히 입력하며 화면 중앙의 회전하는 검은 사각형에 시선을 고정한다. 좌우로 읽는 시선 이동이 언어 내용에 의해 유발되는 것을 막으려는 설계이고, 최소 피드백으로 키 입력마다 그 사각형이 시계 방향으로 10도씩 돈다.</p> <p>세션당 16문장 × 16블록 이며, 매 세션 첫 4문장은 연습 시행으로 본 2,560 문장과 겹치지 않는다. 연습 4문장 중 처음 둘은 완전한 시각 피드백을, 나머지 둘은 최소 피드백 조건에 익숙해지도록 준다.</p> <p>이 설계에서 중요한 지점은 <strong>지연 타이핑 (delayed typing)</strong> 이다. 듣기와 타이핑 사이에 강제 지연을 두었으므로, 디코딩이 겨냥하는 것은 청각 지각이 아니라 언어 <em>생성</em> 국면의 신경 활동이다.</p> <h3 id="전처리와-데이터-분할">전처리와 데이터 분할</h3> <p>MEG 는 0.5–45 Hz 대역통과 + 50 Hz notch 후 100 Hz 로 다운샘플하고, 채널별 RobustScaler (기록별 median · IQR) 로 정규화한 뒤 ±5 robust SD 를 넘는 값을 clamp 한다. SSP 는 적용하지 않았다.</p> <p>분할은 <strong>고유 문장 텍스트 수준</strong>에서 결정론적 해시 기반 splitter 로 80/10/10 을 만든다. 문장 텍스트의 해시만으로 배정이 정해지므로 쿼리에 어떤 피험자가 포함되든 분할이 안정적이고, 같은 문장 텍스트를 공유하는 모든 이벤트가 (피험자·세션을 가로질러) 같은 파티션에 들어간다. 텍스트 누수가 0 이라는 뜻이다. 문장 풀이 2,724개로 작다는 점을 생각하면 이 설계는 필수적이다.</p> <h3 id="데이터-증강">데이터 증강</h3> <p>MEG 세그먼트는 문장 시작 (첫 키 입력) 400 ms 전부터 문장 종료 (마지막 키 릴리스) 까지 자르고, 완료 후 신경 활동을 담기 위해 400–500 ms 를 균일 표집해 뒤에 덧붙인다. 학습 중에는 pre-onset baseline 에서 최대 400 ms 를 무작위로 잘라 내는 시간 jittering 으로 신경 신호와 문장 시작의 유효 정렬을 epoch 마다 흔든다.</p> <p>추가로 채널별 상수 오프셋 $\mathcal{N}(0, 0.3)$ 으로 slow-drift 아티팩트를 흉내 내고, 시간 축 masking (최대 50 프레임, 적용 확률 0.2) 과 센서 축 독립 채널 masking (최대 폭 400) 을 SpecAugment (Park et al., 2019) 방식으로 적용하며, 시행 길이를 $[0.8, 1.2]$ 배로 선형 보간해 늘리고 줄인다.</p> <h3 id="학습-자원">학습 자원</h3> <table> <thead> <tr> <th>항목</th> <th>값</th> </tr> </thead> <tbody> <tr> <td>라이브러리</td> <td>neuralset (King et al., 2026) · neuraltrain (d’Ascoli et al., 2026)</td> </tr> <tr> <td>옵티마이저</td> <td>AdamW, lr $8 \times 10^{-4}$, weight decay $10^{-3}$</td> </tr> <tr> <td>스케줄</td> <td>linear warm-up 500 step (start factor 0.01) → Cosine Annealing</td> </tr> <tr> <td>정밀도</td> <td>BF16 mixed precision, gradient clipping global norm 1</td> </tr> <tr> <td>배치</td> <td>64 × 2 (micro-batch 누적) × 8 GPU = 유효 1,024 샘플</td> </tr> <tr> <td>하드웨어</td> <td>8× A100 80 GB</td> </tr> <tr> <td>학습 시간</td> <td>전체 절차 19.5시간 (end-to-end 275 epoch)</td> </tr> <tr> <td>체크포인트</td> <td>LoRA 실험용 인코더는 validation CER 로 선정, early stopping patience 50 epoch</td> </tr> </tbody> </table> <h3 id="평가-지표">평가 지표</h3> <ul> <li><strong>CER</strong> — 예측·정답 문자열의 Levenshtein 편집 거리를 정답 길이로 정규화.</li> <li><strong>WER</strong> — 공백 토큰화 후 단어 수준 Levenshtein 거리를 정답 단어 수로 정규화.</li> <li><strong>SemER</strong> — frozen RoBERTa-large (Liu et al., 2019) 의 mean-pool hidden state 를 $\ell_2$ 정규화한 뒤 예측·정답 간 $\ell_2$ 거리. 의미적 근접도를 잰다.</li> </ul> <p>CER/WER 은 <code class="language-plaintext highlighter-rouge">edit-distance</code> 라이브러리의 <code class="language-plaintext highlighter-rouge">SequenceMatcher</code>, SemER 은 HuggingFace <code class="language-plaintext highlighter-rouge">transformers</code> 로 구현했고, 조건 간 유의성 검정은 양측 Mann-Whitney U 검정을 썼다.</p> <h2 id="실험-결과">실험 결과</h2> <h3 id="규모가-비동기-디코딩을-연다">규모가 비동기 디코딩을 연다</h3> <p>먼저 던진 질문은 “새 데이터셋의 규모와 다양성이 비동기 디코딩과 동기 디코딩의 격차를 메우기에 충분한가” 다. 두 인코더를 저데이터 SpanishBCBL (Lévy et al., 2025) 과 새 EnglishBCBL 양쪽에서 학습해 CER 을 비교했다.</p> <table> <thead> <tr> <th>인코더</th> <th>SpanishBCBL</th> <th>EnglishBCBL</th> </tr> </thead> <tbody> <tr> <td>Encoder Sync (동기, Lévy et al., 2025)</td> <td>0.39 ± 0.02</td> <td>0.23 ± 0.03</td> </tr> <tr> <td>Encoder Async (비동기, 본 논문)</td> <td>0.59 ± 0.02</td> <td>0.25 ± 0.03</td> </tr> </tbody> </table> <p>읽는 법이 중요하다. 저데이터에서는 동기가 비동기를 크게 앞선다 (0.39 vs 0.59, 20%p 격차). 그런데 데이터를 10배로 늘리자 그 격차가 <strong>2%p</strong> 로 붕괴한다. 키 입력 타이밍이라는 강력한 감독 신호를 데이터가 대체해 버린 것이다. 실시간 사용의 전제 조건이 성능 희생 없이 충족된다는 뜻이므로, 이 논문 전체를 떠받치는 결과다.</p> <p>스케일링은 로그 선형이다. EnglishBCBL 의 점진적으로 큰 부분집합으로 Encoder Async 를 재학습했을 때 $\log_{10}(\text{hours})$ 와 피험자 평균 CER 사이의 Pearson $r = -0.99$ ($p = 1.1 \times 10^{-3}$, $R^2 = 0.98$, 5개 학습 비율 조건), 기울기는 decade 당 −0.39 CER 이다. 현재 90시간 천장에서 포화 조짐이 전혀 없다.</p> <h3 id="문장-다양성은-총량과-별개의-축이다">문장 다양성은 총량과 별개의 축이다</h3> <p>SpanishBCBL 에서 학습한 Encoder Async 의 CER 0.59 는, 같은 <em>양</em> 의 EnglishBCBL 데이터로 학습했을 때의 0.52 ± 0.02 보다 유의하게 높다 ($p &lt; 0.05$). 데이터 양이 아니라 성질의 차이라는 뜻이다.</p> <p>두 데이터셋의 차이는 반복 여부다. SpanishBCBL 은 각 고유 문장을 피험자마다 2회씩 타이핑했고, EnglishBCBL 은 1회씩만 했다. 이를 분리하려고 총 문장 수와 피험자 수 ($n = 9$) 를 맞추고 고유 문장 수만 다르게 한 통제 데이터셋 두 개를 만들었다 — 128 고유 문장 × 2회 반복 (SpanishBCBL 프로토콜) vs 256 고유 문장 × 1회 (EnglishBCBL 프로토콜).</p> <p>결과는 CER 0.45 ± 0.03 (비반복) vs 0.65 ± 0.01 (반복), $p &lt; 0.001$ 이다. 같은 총 시행 수라면 <strong>문장을 반복하는 것보다 새 문장을 보는 편이 20%p 낫다</strong>. 데이터 수집 프로토콜을 짜는 사람에게 곧바로 실행 가능한 결론이고, 언어모델이 개입하지 않은 인코더 단독 결과라는 점에서 더 깨끗하다.</p> <h3 id="메인-결과--단어와-의미-수준">메인 결과 — 단어와 의미 수준</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig3-decoding-results-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig3-decoding-results-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig3-decoding-results-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig3-decoding-results.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: Brain2Qwerty v2 는 MEG 로부터 단어·의미 수준 디코딩을 가능하게 한다. A–C 는 세 디코더의 피험자별 CER / WER / SemER, D 는 최고·중앙·최악 피험자의 문장별 단어 편집 수, E–F 는 실제 디코딩 예시.</figcaption> </figure> <p>세 접근을 비교한다. (1) 언어모델 보정 없는 Encoder 단독 (CTC logit 에서 매 시점 최빈 클래스 선택), (2) Encoder + N-gram (Brain2Qwerty v1 방식, 6-gram 문자 LM 으로 보정), (3) 전체 Brain2Qwerty v2 파이프라인.</p> <table> <thead> <tr> <th>지표</th> <th>Encoder</th> <th>Encoder + N-gram</th> <th>Brain2Qwerty v2</th> </tr> </thead> <tbody> <tr> <td>CER</td> <td>0.28 ± 0.03</td> <td><strong>0.26 ± 0.03</strong></td> <td>0.31 ± 0.03</td> </tr> <tr> <td>WER</td> <td>0.55 ± 0.04</td> <td>0.43 ± 0.04</td> <td><strong>0.39 ± 0.04</strong></td> </tr> <tr> <td>SemER</td> <td>0.096 ± 0.003</td> <td>0.085 ± 0.004</td> <td><strong>0.059 ± 0.005</strong></td> </tr> </tbody> </table> <p>모든 쌍별 비교가 $p &lt; 0.005$ 다. 소통에 직결되는 두 지표 WER 과 SemER 에서 Brain2Qwerty v2 가 명확히 앞선다. 특히 SemER 은 N-gram 대비 0.085 → 0.059 로 크게 좋아지는데, LLM 이 잡음 섞인 신경 입력에서 <em>전역적으로 일관된 문장 구조</em>를 복원한다는 뜻이다.</p> <p>fMRI 로 지각된 음성을 복원한 Tang et al. (2023) 의 WER 0.92–0.94 와 비교하면, 비침습 신경 기록에서 정확한 단어를 뽑아내는 능력에서 눈에 띄는 진전이다.</p> <h3 id="cer-이-나빠지는-것은-결함인가">CER 이 나빠지는 것은 결함인가</h3> <p>흥미롭게도 Brain2Qwerty v2 의 CER 은 Encoder 단독 (0.28) 과 N-gram (0.26) 보다 <em>나쁘다</em> (0.31). 이건 LLM 자기회귀 디코딩의 구조적 귀결이다. LLM 은 인코더 출력과 MEG 토큰 신호 품질이 디코딩에 충분하지 않은 상황에서도 유창한 문장을 만들도록 학습돼 있어서, 문자 수준에서 목표와 크게 갈라지는 틀린 문장을 내놓는다.</p> <p>실패 양상이 N-gram 과 질적으로 다르다. Brain2Qwerty v2 는 최고 피험자에게는 완벽하거나 거의 완벽한 디코딩을 내놓지만, 최악 피험자의 출력은 <em>일관되지만 완전히 다른 문장</em> 이 될 수 있다. 논문의 예시가 선명하다 — 목표 “cars are not allowed on this road” 에 대해 “had she not fallen down the stairs” 를 내놓는다. 문법적으로 흠 없고, 단어 정확도나 의미 정확도에서 얻은 것은 하나도 없이 CER 만 크게 손해 본다.</p> <p>반대로 N-gram 모델은 국소 문자 시퀀스를 꾸준히 보정해 CER 은 낮게 유지하지만 어휘적으로 올바른 문장을 만들어 내지 못한다 (Figure 3F 의 “WAS THE DISH THAT YOU NIGHTY IN THE LP BUT” 같은 출력). 성공적인 소통이 엄밀한 문자 일치가 아니라 <em>의미</em> 에 달려 있다는 관점에서, WER 과 SemER 의 개선이 CER 손실보다 값지다는 것이 저자들의 주장이고 타당하다.</p> <p>다만 이 트레이드오프는 응용에 따라 뒤집힌다. 논문도 짚듯이 <strong>비밀번호를 입력하는 상황</strong>과 <strong>대화에 응답하는 상황</strong>은 디코딩 목적함수를 다르게 잡아야 한다. 문자 하나가 중요한 곳에서 유창한 hallucination 은 최악의 실패다.</p> <h3 id="얼마나-자주-완벽한가">얼마나 자주 완벽한가</h3> <table> <thead> <tr> <th>피험자</th> <th>완벽 디코딩 (단어 편집 0회)</th> </tr> </thead> <tbody> <tr> <td>최고</td> <td>28% (편집 1회 이내는 47%)</td> </tr> <tr> <td>중앙</td> <td>15%</td> </tr> <tr> <td>최악</td> <td>4%</td> </tr> </tbody> </table> <p>중앙·최악 피험자에서도 전형적 오류 양상은 <em>단어 하나가 치환되거나 빠지는 것</em> 이지 무관한 문장으로 붕괴하는 것이 아니다. 부록의 난이도 대역별 분석 (Figure S3) 이 이를 뒷받침한다. 쉬운 대역에서는 최고 피험자가 6문장 중 5문장을 그대로 맞히고, 중앙 피험자도 최대 한두 단어 차이에 그친다. 그 차이조차 “travel by plane” → “travel alone”, “car” → “computer” 처럼 대개 의미 보존적이거나 문법을 유지하는 치환이다. 어려운 대역으로 갈수록 치환의 사거리가 길어지고 주제만 인접한 문장이 나오지만, 출력은 여전히 문법적이다.</p> <h3 id="ctc-토크나이저와-lora-전략">CTC 토크나이저와 LoRA 전략</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig4-tokenizer-and-lora-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig4-tokenizer-and-lora-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig4-tokenizer-and-lora-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig4-tokenizer-and-lora.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 4: CTC 토크나이저와 LLM 적응 튜닝이 baseline 정렬 대비 WER 을 20% 줄인다. A 는 세 정렬 전략 비교, B 는 단어 수 보정, C 는 단어 검색 예시, D 는 LoRA rank sweep, E 는 LLM 백본 크기와 adapter 대상 ablation.</figcaption> </figure> <p><strong>정렬 전략 비교.</strong> CTC 토크나이저 WER 0.39 ± 0.04 · 문장 정렬 (문장당 임베딩 하나; Zhang et al., 2026) 0.46 ± 0.04 · 패치 토큰화 (문장을 동일 간격 청크로 고정 분할; Dosovitskiy et al., 2021 의 ViT 착안) 0.49 ± 0.05, 모두 $p &lt; 0.005$. 전형적 문장에서 9개 단어 중 8개가 rank 1 로 복원된다 (Figure 4C).</p> <p><strong>LoRA rank sweep.</strong> $r \in {1, \ldots, 256}$ 에서 세 전략의 궤적이 뚜렷이 갈린다. Joint LoRA 는 작은 rank 에서 이긴다 ($r = 2$, WER 0.43). 그 이상에서는 단일 adapter 의 용량이 제한된 문장 풀 (~2.7K 고유 문장) 을 암기하기에 충분해져 WER 이 나빠진다. Per-subject LoRA 와 Model Soup 은 각각 약 10배 적은 데이터를 보므로 이 과적합 영역에 도달하지 않고, rank 가 커질수록 WER 이 매끄럽게 내려가 Model Soup 이 $r = 128$ 에서 이긴다 (WER 0.43). Model Soup 은 높은 rank 에서도 joint baseline 보다 <em>빠르게</em> 학습된다 — 작은 adapter 아홉 개를 맞추는 편이 큰 pooled adapter 하나를 학습하는 것보다 효율적이기 때문이다.</p> <p><strong>백본 스케일링.</strong> All subjects ($r=2$) / Model soup ($r=128$) 순으로 나열하면 Qwen3-0.6B 0.43/0.43, 1.7B 0.42/0.41, 4B 0.42/0.40, 4B + 모든 모듈 0.41/0.39 다. Model Soup 은 매 단계에서 개선된다 — 0.6B → 1.7B ($p = 0.020$), 1.7B → 4B ($p &lt; 0.01$), attention-only → all modules ($p &lt; 0.01$). 반면 joint training 은 WER 0.41 근처에서 정체한다. LLM 크기를 키울 때 이득을 챙기는 전략은 Model Soup 쪽이라는 뜻이다.</p> <h3 id="자율-ai-에이전트-auto-research">자율 AI 에이전트 (Auto Research)</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig5-auto-research-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig5-auto-research-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig5-auto-research-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig5-auto-research.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 5: 자율 AI 코딩 에이전트가 고전적 최적화를 능가하는 설정을 발견한다. A 는 S01 에서의 누적 최고 validation WER 궤적, B 는 각 방법의 최종 설정을 9명 전원에게 평가한 테스트 WER.</figcaption> </figure> <p>Karpathy 의 autoresearch 에서 착안해, Claude Opus 4.6 기반 Cursor 에이전트 세 개를 독립적으로 돌렸다. 각각 전용 git worktree 와 격리된 브랜치에서 파일시스템·터미널 전권을 가지되 서로의 브랜치는 볼 수 없다. 공통 코드베이스와 사전학습 checkpoint 는 공유하고 설정 파일과 결과 디렉토리는 분리했다. 부모 브랜치 설정은 의도적으로 빈약하게 만들어 네 개 하이퍼파라미터 (learning rate, weight decay, LoRA rank, batch size) 와 모델 지정 (Qwen3-0.6B + LoRA), 아키텍처 상수만 노출했다.</p> <p>에이전트 프롬프트의 규칙이 흥미롭다 — SLURM 을 5분마다 폴링하고 절대 idle 하지 말 것, 매 라운드 정확히 50개 job 으로 독립적인 아이디어 4–5개 이상을 검증할 것, 45분 타임아웃 · 멈춘 job 은 즉시 취소, 파일 삭제 금지 · 테스트 예측 조회 금지, 오직 subject 0 만 사용하고 validation 지표로만 최적화할 것. 예산은 10 라운드 × 50 job = 500 회 실행이다.</p> <p>비교군 Optuna (Akiba et al., 2019) 는 동일 컴퓨트 예산으로 같은 네 파라미터에 TPE 를 돌렸다 (v4.8, <code class="language-plaintext highlighter-rouge">multivariate=True</code>, <code class="language-plaintext highlighter-rouge">group=True</code>, <code class="language-plaintext highlighter-rouge">constant-liar=True</code>, <code class="language-plaintext highlighter-rouge">n-startup-trials=32</code>, 500 trial 을 50개씩 10 배치).</p> <table> <thead> <tr> <th>방법</th> <th>S01 validation WER</th> <th>9명 전체 테스트 WER</th> </tr> </thead> <tbody> <tr> <td>Default</td> <td>0.45</td> <td>기준선</td> </tr> <tr> <td>Optuna TPE</td> <td>0.41 (−8.6% 상대)</td> <td>0.493 (Default 대비 $p = 0.88$, 개선 없음)</td> </tr> <tr> <td>AutoResearch 1</td> <td>0.38 (−16.1%)</td> <td><strong>0.42 (−16.0%)</strong></td> </tr> <tr> <td>AutoResearch 2</td> <td>0.36 (−19.8%)</td> <td>0.45 (−10.0%)</td> </tr> <tr> <td>AutoResearch 3</td> <td>0.37 (−17.7%)</td> <td>0.43 (−12.7%)</td> </tr> </tbody> </table> <p>교차 피험자 평가가 결정적이다. Optuna 의 단일 피험자 이득은 전이되지 않고 완전히 사라진 반면 ($p = 0.88$), 세 에이전트는 모두 유의한 개선을 유지했다 (전부 $p &lt; 10^{-6}$). 에이전트가 발견한 것이 S01 튜닝 아티팩트가 아니라 모집단 전반에 유효한 혁신이라는 뜻이다.</p> <p>세 에이전트가 독립적으로 수렴한 핵심 전략들이다.</p> <ul> <li><strong>Label smoothing</strong> — 세 에이전트 모두 라운드 1–2 에서 발견. 단일 라운드 최대 WER 감소 (Agent 1 기준 −0.04).</li> <li><strong>Modality dropout</strong> — 학습 중 CTC 토큰을 떨어뜨려 LLM 이 잡음 섞인 CTC 예측보다 신경 단어 임베딩에 더 의존하게 만든다. 라운드 5–9 에서 지속적으로 큰 이득.</li> <li><strong>Beam search 디코딩</strong> — 테스트 시 다중 가설 디코딩. 라운드 2–3.</li> <li><strong>문장 수준 대조 정렬 손실</strong> — 단어 수준 정렬을 보완하는 CLIP 스타일 보조 손실. 라운드 7–8.</li> <li><strong>최소 프롬프트</strong> — 장황한 태스크 설명 대신 <code class="language-plaintext highlighter-rouge">CTC:</code>, <code class="language-plaintext highlighter-rouge">MEG:</code>, <code class="language-plaintext highlighter-rouge">Output:</code> 만 남긴다.</li> </ul> <p>이 기법들은 모두 v2 개발 과정에서 검토됐고, 최종 설정은 연구팀이 선택했다.</p> <h3 id="그리고-실패">그리고 실패</h3> <p>같은 에이전트들에게 <strong>열린 목표</strong>를 주면 — Brain2Qwerty v1 코드베이스에서 시작해 EnglishBCBL 에서 v2 파이프라인 성능을 맞춰 보라고 하면 — 셋 다 일관되게 실패한다. 크고 서로 얽힌 코드 수정 때문에 이후 SLURM job 의 대부분이 유효한 지표를 내기 전에 크래시하고, 드물게 단일 실행이 성공해도 에이전트는 반복하기보다 idle 로 빠졌다.</p> <p>저자들의 결론은 담백하다. AI 에이전트는 강력한 force multiplier 일 수 있지만, 현재로서는 인간 연구자가 과학 과정의 핵심 부분으로 남는다.</p> <h2 id="결과-분석--ablation">결과 분석 / Ablation</h2> <h3 id="llm-은-정말-뇌를-읽는가">LLM 은 정말 뇌를 읽는가</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs4-neuro-tokens-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs4-neuro-tokens-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs4-neuro-tokens-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs4-neuro-tokens.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure S4: Brain2Qwerty v2 는 CTC 예측의 교정기가 아니라 neuroLLM 이다. 같은 Qwen3-0.6B 백본을 쓰되, 회색은 인코더 예측만으로 조건화하고 초록은 MEG 유래 단어 임베딩까지 조건화한다.</figcaption> </figure> <p>LLM 기반 디코더에 대한 가장 중요한 질문은 이것이다. LLM 이 실제로 신경 정보를 읽고 있는가, 아니면 인코더의 텍스트 출력을 언어적 사전으로 다듬는 교정기에 불과한가.</p> <p>이를 가르기 위해 CTC 토크나이저와 단어 사영기가 만든 MEG 유래 단어 임베딩 (Neuro Token) 을 제거하고, LLM 을 인코더 예측만으로 조건화한 변형 (Brain2Qwerty + LLM) 을 같은 Qwen3-0.6B 백본에서 학습했다.</p> <table> <thead> <tr> <th>지표</th> <th>Brain2Qwerty + LLM (Neuro Token 제거)</th> <th>Brain2Qwerty v2</th> </tr> </thead> <tbody> <tr> <td>CER</td> <td>0.38</td> <td><strong>0.34</strong></td> </tr> <tr> <td>WER</td> <td>0.49</td> <td><strong>0.43</strong></td> </tr> <tr> <td>SemER</td> <td>0.067</td> <td><strong>0.064</strong></td> </tr> </tbody> </table> <p>세 지표 모두에서 개선되고 (paired Wilcoxon $p \approx 0.004$), 격차가 가장 큰 곳은 WER (절대 −5.6 pt) 다. Discussion 에서 저자들은 이 열화를 WER 기준 16% 로 정리한다. WER 에서 격차가 가장 크다는 사실이 핵심인데, Neuro Token 이 CTC 텍스트만으로는 없는 <em>단어 수준</em> 정보를 나른다는 뜻이기 때문이다.</p> <p>두 입력 스트림이 상보적으로 작동한다는 그림이 여기서 완성된다. CTC 텍스트는 LLM 을 그럴듯한 언어적 사전에 묶어 두고, MEG 토큰은 그 사전을 넘어 디코딩을 밀어 줄 잔여 신경 정보를 나른다. 전체 성능은 <em>둘 다 있을 때만</em> 나온다.</p> <p>특히 놀라운 것은 이 적응이 <strong>~2,700 고유 학습 문장 (~90시간 MEG)</strong> 이라는 코퍼스에서 일어난다는 점이다. 언어모델 미세조정에 통상 쓰이는 규모보다 몇 자릿수 작다.</p> <h3 id="인코더가-병목이다">인코더가 병목이다</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs5-encoder-importance-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs5-encoder-importance-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs5-encoder-importance-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs5-encoder-importance.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure S5: 인코더 CER 이 최종 성능을 선형으로 예측하고, 아키텍처 선택이 인코더 CER 을 결정한다. A·B 는 문장별 상관, C 는 세 인코더 아키텍처의 CER 비교.</figcaption> </figure> <p>Brain2Qwerty v2 의 문장별 WER · SemER 을 상류 인코더 CER 과 상관시키면 두 하류 지표 모두 인코더 CER 과 선형으로 스케일한다 (Pearson $r$ — WER 0.78, SemER 0.68). 인코더에서 나오는 키 입력 예측이 좋을수록 최종 디코딩 문장이 좋다 — 당연해 보이지만, 이것이 성립한다는 사실 자체가 “LLM 이 신경 신호와 무관하게 그럴듯한 문장을 지어내는 것 아닌가” 라는 의심에 대한 반증이기도 하다.</p> <p>그렇다면 인코더 아키텍처는 얼마나 중요한가. 같은 데이터로 세 아키텍처를 학습·평가했다.</p> <table> <thead> <tr> <th>인코더 아키텍처</th> <th>CER</th> </tr> </thead> <tbody> <tr> <td>Temporal Patch Transformer (Zhang et al., 2026 착안, Feghhi et al., 2025 도입)</td> <td>0.37 ± 0.03</td> </tr> <tr> <td>BrainModule + Transformer (Brain2Qwerty v1 과 유사, Défossez et al., 2023)</td> <td>0.28 ± 0.03</td> </tr> <tr> <td>BrainModule + Conformer (본 논문)</td> <td><strong>0.25 ± 0.03</strong></td> </tr> </tbody> </table> <p>Conformer 를 표준 Transformer 로 바꾸면 CER 0.25 → 0.28 ($p &lt; 0.005$) 로, Conformer 의 convolution-attention 교차 배치가 MEG 신호의 국소 시간 구조에 유용한 귀납 편향임을 보인다. BrainModule 을 Temporal Patch 모듈로 마저 바꾸면 0.37 까지 나빠져 셋 중 최악이다. 두 구성 요소 모두 저 SNR MEG 입력에서 각자 몫을 한다는 뜻이다.</p> <h3 id="다중-피험자-학습이-크게-남는다">다중 피험자 학습이 크게 남는다</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab1-multi-subject-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab1-multi-subject-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab1-multi-subject-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab1-multi-subject.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 1: 대상 피험자를 사전학습에 포함하는 것과 다중 피험자 학습의 효과. Per-subject 는 대상 피험자만으로 전체 파이프라인을 처음부터 학습, Joint training 은 전원 공동 학습, LOO + finetune 은 나머지 N−1 명으로 사전학습 후 Conformer 를 얼린 채 대상 피험자에 미세조정.</figcaption> </figure> <p>세 레짐의 순서는 세 피험자 모두에서 동일하다 — per-subject &lt; LOO + finetune &lt; joint training. WER 기준으로 최고 피험자는 38.3% → 32.8% → 22.6%, 중앙은 66.5% → 58.6% → 47.8%, 최악은 90.6% → 68.3% → 61.4% 다.</p> <p>per-subject 는 joint 와 optimisation step 수를 맞추기 위해 학습 스케줄을 4배로 늘렸는데도 일관되게 최악이다. 컴퓨트가 아니라 데이터 다양성의 문제라는 뜻이다.</p> <p>실용적으로 더 중요한 것은 LOO + finetune 이 격차의 상당 부분을 메운다는 사실이다. 새 피험자를 위해 기반 파이프라인을 처음부터 재학습할 필요 없이, 미세조정 한 번으로 배치 가능하다는 이야기다. 임상 배포 시나리오에서 결정적인 성질이다.</p> <h3 id="센서를-줄여도-되는가">센서를 줄여도 되는가</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab2-sensor-ablation-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab2-sensor-ablation-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab2-sensor-ablation-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab2-sensor-ablation.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 2: 센서 수 ablation. MEG 입력을 학습 시점에 무작위 부분 표집했을 때의 CER / WER / SemER. 값은 4개 센서 선택 시드에 대한 평균 ± SEM.</figcaption> </figure> <p>306채널 Megin 같은 whole-head MEG 는 부피가 크고 극저온 냉각이 필요하며 임상·소비자 배포에는 비싸다. 상온에서 동작하는 유연한 헬멧 형태의 OPM (optically pumped magnetometer) 이 실용 대안으로 떠오르는데, 보통 50–150 센서로 구성된다. 그런 저채널 배열이 이 정도 문장 디코딩을 지탱할 수 있는가.</p> <p>keep-fraction ${0.25, 0.50, 0.75}$ 로 306 채널을 각각 ${76, 153, 230}$ 개로 무작위 부분 표집하고, 단순화를 위해 전원 공용 LoRA rank 2 로 전체 파이프라인을 재학습했다 (이 설정의 전체 배열 기준선은 WER 0.433). fraction 마다 모델 시드는 고정하고 센서 선택 시드를 4개 돌려, 분산이 “어떤 센서가 남았는가” 만 반영하도록 했다.</p> <p>성능은 센서 수에 따라 매끄럽고 단조롭게 나빠진다. 처음 76채널을 버리는 것 (306 → 230) 은 전체 배열 대비 WER +3.4 pp 에 그치고, 다음 77개 (230 → 153) 가 +2.3 pp, 마지막 77개 (153 → 76) 가 +5.7 pp 다. SEM 은 WER 기준 항상 1 pp 이하로 촘촘하다.</p> <p>결론이 실무적으로 중요하다. <strong>150 센서 규모의 OPM 급 헬멧은 306채널 기준선 대비 WER 을 약 5.7 pp 만 잃는다.</strong> 저채널 시스템도 같은 end-to-end 디코딩 파이프라인과 짝지으면 본 논문 성능의 대부분을 회수할 수 있다는 뜻이다.</p> <h3 id="임베딩-공간에서-무슨-일이-일어나는가">임베딩 공간에서 무슨 일이 일어나는가</h3> <p>부록의 tSNE 분석이 인코더 내부를 들여다본다. BrainModule 이후의 키 표현은 <em>참가자별로</em> 뭉친다 — 개인별 신경 서명이 임베딩에 남아 있다는 뜻이다. 반면 Conformer 마지막 층 이후의 표현은 <em>키 클래스별로</em> 뚜렷이 뭉치며, 그 구조가 물리적 키보드 배치를 반영한다. 결정적으로 이 구조는 학습으로 획득된 것이다 — 학습되지 않은 Conformer 의 임베딩 공간에서는 키 표현이 여전히 피험자별로 뭉친다.</p> <h2 id="한계와-비판적-평가">한계와 비판적 평가</h2> <p>저자들이 인정한 한계부터.</p> <ul> <li><strong>개인차가 크다.</strong> N-gram CER 기준 17.1%–41.0% 범위다. 최종 성능이 상류 인코더 품질과 강하게 상관하므로, 교차 피험자 전이나 자기지도 사전학습으로 인코더를 개선하는 것이 우선순위다.</li> <li><strong>건강한 자원자 대상 연구다.</strong> 참가자들은 실제로 키보드를 친다. 실제 키 입력이 없는 환자에게 — 추론뿐 아니라 <em>학습과 미세조정 단계에서도</em> 없다 — 이 접근이 신뢰성 있게 이전되는지는 아직 증명되지 않았다.</li> <li><strong>실시간이 아니다.</strong> 인과적 (causal) 아키텍처가 아니라 문장 전체를 받아 동작하므로 지연이 필연적으로 크고, 사용자가 타이핑 중인 단어를 문장 끝나기 전에 볼 수 없다. EMG 손글씨 디코딩에서 저지연 causal Conformer 가 성과를 냈으니 (Sivakumar et al., 2024) 그 방향의 후속이 필요하다.</li> <li><strong>침습 대비 격차가 여전히 크다.</strong> SOTA 침습 BCI 는 타이핑에서 WER 2% 미만 (Jude et al., 2026), 손글씨에서 CER 6% 미만 (Willett et al., 2021) 이다.</li> <li><strong>장비 제약.</strong> 306센서 극저온 MEG 는 임상 적응이 어렵다. 센서 ablation 과 OPM 논의가 이를 완화하지만, OPM 으로 실제 검증한 것은 아니다.</li> </ul> <p>리뷰어 입장에서 추가로 보이는 것들.</p> <ul> <li><strong>문장 풀이 좁다.</strong> Llama 4 로 생성한 “간단한 영어 문장” 2,724개다. 축약형은 제거됐고 특수문자도 없다. 실제 소통에서 필요한 고유명사, 숫자, 도메인 용어, 구어적 파편은 전혀 없는 셈이다. LLM 이 이 좁은 분포를 강력한 사전으로 삼고 있을 가능성을 배제하기 어렵다. 분할이 문장 텍스트 해시 기반이라 문자 그대로의 누수는 없지만, <em>분포 수준</em> 의 사전 이득은 남는다.</li> <li><strong>WER 39% 가 실사용에서 무엇을 뜻하는지 평가가 없다.</strong> 열 단어 중 네 단어가 틀린다는 뜻이다. 최고 피험자의 28% 완벽 · 47% 1단어 이내는 인상적이지만, 이 수준에서 실제 소통 과제 (질문 응답, 의사 전달 성공률) 를 측정한 사용자 연구는 없다.</li> <li><strong>CER 악화의 안전성 함의가 논의에 그친다.</strong> 유창하지만 완전히 틀린 문장을 생성하는 실패 양상은 의료 소통 맥락에서 심각한 위험이다. “had she not fallen down the stairs” 같은 출력이 환자 발화로 제시되는 상황을 생각하면, 신뢰도 추정치 (confidence) 나 거부 (abstention) 메커니즘이 필요해 보이는데 다루지 않는다.</li> <li><strong>Auto Research 비교가 완전히 공정하지는 않다.</strong> Optuna 는 노출된 네 파라미터만 탐색하도록 <em>구성상</em> 제약돼 있고, 에이전트는 코드를 고쳐 새 축을 만들 수 있다. 저자들도 이를 명시하므로 결론이 틀린 것은 아니지만, “에이전트가 TPE 보다 낫다” 가 아니라 “탐색 공간을 확장할 수 있는 쪽이 이긴다” 가 정확한 해석이다. 동일한 탐색 공간에서의 비교는 없다.</li> <li><strong>피험자 9명은 통계적으로 얇다.</strong> paired Wilcoxon 에서 $n = 9$ 로 도달 가능한 최소 $p$ 가 0.0039 이고, Figure 3 의 모든 유의 비교가 정확히 그 값이다. 즉 검정력이 바닥에 닿아 있다.</li> <li><strong>SemER 지표의 해석이 모호하다.</strong> RoBERTa-large 임베딩의 $\ell_2$ 거리인데, 절대 스케일 (0.059 vs 0.096) 이 의미적으로 무엇을 뜻하는지 앵커가 없다. 사람 판정과의 상관 같은 검증이 있으면 좋았을 것이다.</li> </ul> <h2 id="시사점--takeaways">시사점 / Takeaways</h2> <ul> <li><strong>이 논문의 진짜 발견은 아키텍처가 아니라 데이터다.</strong> 저데이터에서 20%p 뒤지던 비동기 인코더가 데이터 10배에서 2%p 차이로 따라붙는다. 키 입력 타이밍이라는 강력한 감독 신호를 데이터가 대체한 것이다. 신경 디코딩에서 “실시간 사용 가능한 설정” 과 “정확한 설정” 사이의 트레이드오프가 데이터로 지워질 수 있다는 뜻이고, 앞으로 이 분야에서 무엇에 투자할지를 바꾸는 결과다.</li> <li><strong>같은 시행 수라면 문장을 반복하지 말고 새 문장을 보여라.</strong> 128문장 × 2회 vs 256문장 × 1회에서 CER 0.65 vs 0.45. 언어모델 없이 성립하는, 프로토콜 설계에 곧바로 쓸 수 있는 결론이다. 데이터 수집 비용이 지배적인 모든 신경 기록 연구에 해당한다.</li> <li><strong>CTC 토크나이저는 이식 가능한 아이디어다.</strong> “연속 임베딩을 어떻게 LLM 의 이산 토큰으로 자를 것인가” 는 모든 비텍스트 모달리티 → LLM 파이프라인이 마주하는 문제다. 이 논문의 답은 별도 분할 모델을 학습하는 대신 <em>이미 학습한 CTC head 의 space 예측</em>을 재사용하는 것이다. space 가 문자의 19% 라 견고하게 예측되고, 결과적으로 문장의 86% 가 단어 수 ±1 안에 든다. CTC 기반 파이프라인이라면 어디에서든 공짜로 얻을 수 있는 분할이다.</li> <li><strong>Neuro Token ablation 은 이런 논문에서 반드시 요구해야 할 실험이다.</strong> LLM 을 디코더로 붙인 모든 연구는 “LLM 이 언어적 사전으로 답을 지어내는 것 아닌가” 라는 의심을 받는다. 프롬프트에서 신경 입력만 빼고 나머지를 동일하게 유지하는 이 ablation 이 그 의심에 대한 최소한의 답이다. WER 0.43 → 0.49 라는 차이가 없었다면 이 논문의 주장은 훨씬 약했을 것이다.</li> <li><strong>피험자를 태스크로 보고 model soup 을 쓰는 레시피가 잘 작동한다.</strong> joint LoRA 는 rank 를 키우면 작은 코퍼스를 암기해 무너지지만, 피험자별 adapter + 가중치 평균은 rank 128 까지 매끄럽게 좋아지고 백본을 키울 때의 이득도 이쪽이 챙긴다. 개인차가 큰 생체 신호 도메인 전반에 재사용 가능한 패턴이다.</li> <li><strong>AI 에이전트의 성공과 실패 조건이 같은 실험에서 드러난다.</strong> 탐색 공간이 좁게 정의된 튜닝에서는 TPE 를 크게 앞서고 그 이득이 다른 피험자로 전이된다. 반면 “아키텍처를 새로 발명하라” 는 열린 과제에서는 크고 얽힌 수정이 크래시를 낳고 에이전트는 idle 로 빠진다. 자동화의 경계가 능력이 아니라 <em>과제 구조</em>에 있다는 관찰이며, 실패를 함께 보고했다는 점을 높게 평가한다.</li> </ul> <h2 id="설치-및-사용법">설치 및 사용법</h2> <p>저자들은 코드를 공개했다.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/facebookresearch/brain2qwerty
<span class="nb">cd </span>brain2qwerty
</code></pre></div></div> <p>파이프라인의 세 단계 (CTC 인코더 → 대조 정렬 → LoRA LLM) 중 마지막 standalone LoRA 미세조정 레짐이 최고 성능을 냈으며, 단일 GPU 30 epoch 로 반복 가능하다. 전체 end-to-end 학습은 8× A100 80 GB 에서 19.5시간이 든다. 데이터셋 (EnglishBCBL) 자체의 공개 여부는 논문에 명시돼 있지 않다.</p> <h2 id="참고-자료">참고 자료</h2> <ul> <li>논문: <a href="https://arxiv.org/abs/2608.18114">https://arxiv.org/abs/2608.18114</a></li> <li>Code: <a href="https://github.com/facebookresearch/brain2qwerty">https://github.com/facebookresearch/brain2qwerty</a></li> <li>Auto Research 착안: <a href="https://github.com/karpathy/autoresearch">https://github.com/karpathy/autoresearch</a></li> </ul> <h2 id="더-읽어보기">더 읽어보기</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2502.17480">Brain-to-Text Decoding: A Non-invasive Approach via Typing</a></strong> (Lévy et al., 2025) — 본 논문의 직전 버전인 Brain2Qwerty v1. 키 입력에 시간 정렬된 동기 분류기로 MEG 에서 CER 32% 를 달성했고, EEG (CER 67%) 와의 격차도 함께 보고한다.</li> <li><strong><a href="https://arxiv.org/abs/2208.12266">Decoding speech perception from non-invasive brain recordings</a></strong> (Défossez et al., 2023) — 본 논문의 BrainModule 이 유래한 작업. 대조 학습으로 M/EEG 에서 지각된 음성의 자기지도 표현을 디코딩한다.</li> <li><strong><a href="https://arxiv.org/abs/2412.17829">Towards decoding individual words from non-invasive brain recordings</a></strong> (d’Ascoli et al., 2025) — MEG/EEG 에서 개별 단어를 디코딩하며, 기록 장치와 실험 프로토콜의 선택이 성능을 지배한다는 점을 보인다.</li> <li><strong><a href="https://www.nature.com/articles/s41593-023-01304-9">Semantic reconstruction of continuous language from non-invasive brain recordings</a></strong> (Tang et al., 2023) — fMRI 로 지각·상상 발화와 무성 영상의 의미를 복원한다. 본 논문이 WER 비교 기준 (0.92–0.94) 으로 인용하는 작업.</li> <li><strong><a href="https://www.nature.com/articles/s41586-023-06377-x">A high-performance speech neuroprosthesis</a></strong> (Willett et al., 2023) — 침습 BCI 쪽 대표 성과. 비침습이 얼마나 따라잡아야 하는지를 가늠하는 기준선이다.</li> <li><strong><a href="https://arxiv.org/abs/2203.05482">Model soups: averaging weights of multiple fine-tuned models improves accuracy without increasing inference time</a></strong> (Wortsman et al., 2022) — 본 논문의 피험자별 LoRA 가중치 평균 전략의 원본.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="brain-computer-interface"/><category term="meg"/><category term="brain-to-text"/><category term="ctc"/><category term="llm"/><category term="lora"/><category term="neuroscience"/><summary type="html"><![CDATA[9명에게서 90시간·2,724 문장의 MEG 를 모으고, CTC 인코더 · 단어 정렬기 · LoRA LLM 을 한 파이프라인으로 묶어 비침습 뇌 신호에서 자연 문장을 WER 39% 로 디코딩한 Meta AI 의 Brain2Qwerty v2]]></summary></entry><entry xml:lang="en"><title type="html">[Paper Review] Accurate Decoding of Natural Sentences from Non-Invasive Brain Recordings</title><link href="https://baba9811.github.io/en/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/" rel="alternate" type="text/html" title="[Paper Review] Accurate Decoding of Natural Sentences from Non-Invasive Brain Recordings"/><published>2026-08-24T05:00:00+00:00</published><updated>2026-08-24T05:00:00+00:00</updated><id>https://baba9811.github.io/en/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra</id><content type="html" xml:base="https://baba9811.github.io/en/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/" class="btn btn-sm btn-outline-secondary">🇰🇷 한국어로 읽기</a> </div> <h2 id="metadata">Metadata</h2> <table> <thead> <tr> <th>Field</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td>Authors</td> <td>Mingfang (Lucy) Zhang et al. (12 co-authors across Meta AI · ENS-PSL · BCBL and others)</td> </tr> <tr> <td>Venue</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv or DOI</td> <td><a href="https://arxiv.org/abs/2608.18114">2608.18114</a></td> </tr> <tr> <td>Code</td> <td><a href="https://github.com/facebookresearch/brain2qwerty">facebookresearch/brain2qwerty</a></td> </tr> <tr> <td>Data</td> <td>EnglishBCBL — nine healthy adults × 10 hours of MEG (306-channel Megin), 2,724 unique sentences, ~22,000 sentences typed in total</td> </tr> <tr> <td><span style="white-space: nowrap">Review date</span></td> <td>2026-08-24</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>Natural sentences typed by a person are decoded from non-invasive MEG alone at an average <strong>WER of 39%</strong>. The best participant reaches 22% WER, with 28% of test sentences decoded with zero word errors and 47% within a single word edit. That is a twofold improvement over the previous state of the art (52% for the best subject in Brain2Qwerty v1).</li> <li>The unlock was data, not architecture. Going from 1 hour to 10 hours per participant drops the CER of an <em>asynchronous</em> encoder — one that never sees keystroke timings — from 0.59 to 0.25, closing to within 2 points of the <em>synchronous</em> encoder that does get those timings (0.23). Scaling is log-linear with no sign of saturation at 90 hours (slope −0.39 CER per decade).</li> <li>The pipeline jointly trains three levels. A CTC encoder (BrainModule + Conformer) handles characters, a SigLIP aligner maps MEG embeddings onto word embeddings, and a LoRA-tuned Qwen3 handles sentences. The piece that stitches them together is the <strong>CTC tokenizer</strong>: it chunks the continuous MEG embedding stream at the frames where CTC predicts a space.</li> <li>The LLM is not a grammar corrector bolted onto CTC output. Ablating the MEG tokens out of the prompt alone worsens WER from 0.43 to 0.49 — the model really is reading neural signal.</li> <li>Three autonomous AI coding agents (Cursor running Claude Opus 4.6) were set loose on the tuning problem and comfortably beat Optuna TPE (cross-subject test WER: Optuna 0.493, no improvement, vs. 0.42 / 0.43 / 0.45 for the agents, up to −16%). Given the open-ended task of reproducing v2 starting from the v1 codebase, all three failed outright.</li> </ul> <h2 id="introduction">Introduction</h2> <p>Almost every recent win in restoring communication to people who have lost speech or movement has come from <em>invasive</em> BCIs. Patients with electrodes over motor cortex have produced language via attempted speech (Moses et al., 2021; Willett et al., 2023; Card et al., 2024), handwriting (Willett et al., 2021), and typing (Pandarinath et al., 2017; Jude et al., 2026), at speeds and accuracies approaching natural speech. The cost is real: neurosurgery carries medical risk, recording quality is hard to maintain over long periods because of neuroinflammatory responses, and providing surgical infrastructure to a broad patient population is a logistical problem in its own right.</p> <p>Non-invasive alternatives have been on the table for years, each with a disqualifying weakness. EEG’s poor signal-to-noise ratio makes the task cognitively demanding to the point of impracticality. fMRI’s temporal resolution is intrinsically too low for real-time communication. MEG has long been the most promising middle ground, and the same group’s previous work — Brain2Qwerty v1 (Lévy et al., 2025) — decoded typed text at 32% CER by training a classifier time-locked to each keystroke.</p> <p>That approach had three structural problems. First, it needs to <em>know when each keystroke happened</em> — which in real use is precisely the unknown. Second, classifying characters well does not guarantee reconstructing a sentence; a few misclassified characters make the output unreadable. Third, the data was thin: invasive BCIs typically work with thousands of sentences over 10–40 hours, while v1 had one hour per participant.</p> <p>This paper attacks all three. Nine volunteers were recorded for 10 hours each across 90 sessions, producing a 22,000-sentence corpus. A CTC (Connectionist Temporal Classification) objective removes the timing dependency. An LLM handles sentence-level reconstruction. And on top of that sits one more experiment: handing the optimisation of the pipeline itself to autonomous AI agents. Even if you never touch a non-invasive BCI, two things here are worth your time — the point at which data scale beats architecture, and a practical recipe for attaching an LLM as a decoder for a non-linguistic modality.</p> <h2 id="key-contributions">Key Contributions</h2> <ul> <li><strong>Pushing non-invasive sentence decoding near the useful range.</strong> 39% WER on average, 22% for the best subject. Compare that with the 0.92–0.94 WER Tang et al. (2023) report for reconstructing <em>perceived</em> speech from fMRI: this is a qualitatively different regime for recovering exact words.</li> <li><strong>Separating data quantity from sentence diversity as two independent axes.</strong> In a controlled comparison matched for total sentence count and number of subjects, 256 unique sentences typed once beats 128 unique sentences typed twice by CER 0.45 vs. 0.65 — and the result holds without any language model in the loop.</li> <li><strong>The CTC tokenizer.</strong> A deceptively simple device — segment the continuous neural embedding stream wherever CTC predicts a space token — that beats sentence alignment (0.46) and patch tokenization (0.49) at WER 0.39. It is a generic technique that drops into any CTC-based pipeline.</li> <li><strong>Demonstrating that the LLM reads neural signal rather than correcting text.</strong> An ablation removing the MEG tokens from the prompt degrades all three metrics. What makes this striking is that the adaptation happens from roughly 2,700 unique sentences, orders of magnitude less data than is typically used to fine-tune a language model.</li> <li><strong>A controlled comparison putting autonomous AI agents in the research loop.</strong> The agents are benchmarked head-to-head against Optuna TPE on an identical compute budget, and both the success case (constrained hyperparameter tuning) and the failure case (open-ended architecture invention) are reported.</li> </ul> <h2 id="background">Background</h2> <h3 id="synchronous-vs-asynchronous-decoding">Synchronous vs. asynchronous decoding</h3> <p>This distinction matters most for understanding the paper. <strong>Synchronous decoding</strong> cuts a short window (about 3 seconds) time-locked to each keystroke and classifies the character inside it. This is what Brain2Qwerty v1 does. It is accurate, but something external has to supply the keystroke timing. <strong>Asynchronous decoding</strong> takes a continuous response window of 10+ seconds and generates a text sequence from it. No timing information is needed, so real-time use becomes possible — but the model has to find the alignment itself, which is a substantially harder problem.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig1-scale-and-variety-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig1-scale-and-variety-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig1-scale-and-variety-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig1-scale-and-variety.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: Asynchronous MEG decoding is unlocked by recording scale and variety. A shows the experimental protocol and MEG source reconstruction at keystroke onset, B contrasts the synchronous and asynchronous approaches, C compares dataset scale, D–E show the two encoders' CER, F the scaling with data, and G the effect of sentence repetition.</figcaption> </figure> <h3 id="ctc--learning-sequences-without-alignment">CTC — learning sequences without alignment</h3> <p>CTC (Graves et al., 2006) is an objective borrowed from speech recognition that trains variable-length input against variable-length output <em>without frame-level alignment labels</em>. The key idea is the blank token: at each time frame the model emits either a character or a blank, and training maximises the summed probability of <em>every</em> path whose collapse — merging repeats, deleting blanks — yields the target string. Here the vocabulary is 28 classes: blank (index 0), 26 lowercase letters (1–26), and space (27).</p> <p>CTC does two jobs in this pipeline. One is removing the timing dependency. The other is providing the basis for the CTC tokenizer that comes later — the frames where the greedy path emits a space are an estimate of word boundaries.</p> <h3 id="brainmodule-conformer-and-siglip">BrainModule, Conformer, and SigLIP</h3> <p><strong>BrainModule</strong> (Défossez et al., 2023) handles the physical layout of the MEG sensor array. Sensors are scattered in 3D space and the number of active channels varies across sessions, so channel coordinates are encoded as two-dimensional Fourier features and the variable-length sensor array is projected onto a fixed 270 virtual channels. A per-subject affine layer conditioned on subject index absorbs individual sensor geometry without explicit sensor-level co-registration.</p> <p><strong>Conformer</strong> (Gulati et al., 2020) is a speech-recognition block that interleaves convolution and self-attention: convolution captures local temporal structure, attention handles long-range dependencies. The paper’s appendix shows that swapping the Conformer for a standard Transformer alone worsens encoder CER from 0.25 to 0.28.</p> <p><strong>SigLIP</strong> (Zhai et al., 2023) is a variant of CLIP-style contrastive learning that replaces the softmax with a pairwise sigmoid binary cross-entropy. It needs no batch-wide normalisation, which makes it simpler to implement and stable at small batch sizes. Here it is used to pull MEG-derived word embeddings onto the LLM’s actual word embeddings.</p> <h2 id="method--architecture">Method / Architecture</h2> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig2-architecture-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig2-architecture-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig2-architecture-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig2-architecture.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: The Brain2Qwerty v2 architecture. The only input is the continuous MEG recording for one sentence; three jointly optimised modules handle characters (Encoder, CTC loss), words (Aligner, SigLIP loss), and sentences (LLM, cross-entropy).</figcaption> </figure> <h3 id="level-1--characters-the-meg-encoder">Level 1 — characters: the MEG encoder</h3> <p>The encoder has two stages.</p> <p><strong>BrainModule.</strong> Channel coordinates are encoded as two-dimensional Fourier features (total embedding dimension 2,048) and mapped onto 270 virtual channels, followed by a per-subject affine layer conditioned on subject index. The resulting spatially fused $B \times 270 \times T$ representation ($T$ being the number of time frames at 100 Hz) feeds a four-layer dilated convolutional network (hidden dimension 1,500; kernel size 5; dilation period 3) with GELU activations, batch normalization, residual skips scaled by 0.1, and dropout (input 0.2, convolutional 0.5). An initial linear projection reduces the channel dimension to 512 before the convolutional stack. A strided 1D convolution (kernel 16, stride 4) then cuts temporal resolution by four, giving roughly one frame per 40 ms.</p> <p><strong>Conformer.</strong> The downsampled sequence goes through a four-layer Conformer (model dimension 1,024, four attention heads, feed-forward dimension 1,024, depthwise convolution kernel width 17, dropout 0.3). A linear head over the output produces the 28-class character distribution.</p> <p>Training uses an auxiliary CTC head attached right after temporal downsampling (before the Conformer) and trained jointly. The composite loss is:</p> \[\mathcal{L} = (1-\alpha)\,\mathcal{L}_{CTC}^{\text{final}} + \alpha\,\mathcal{L}_{CTC}^{\text{aux}}, \quad \alpha = 0.7\] <p>With $\alpha = 0.7$ the auxiliary branch dominates the gradient signal early in training, leaving the Conformer to refine the final representation on top of it (following Nozaki and Komatsu, 2021).</p> <h3 id="level-2--words-the-ctc-tokenizer-and-aligner">Level 2 — words: the CTC tokenizer and aligner</h3> <p>Bridging continuous MEG embeddings and the word-level tokens an LLM expects is the practical crux of this pipeline, and the solution is strikingly plain: <strong>cut the Conformer output at the frame positions where the CTC greedy path emitted a space token.</strong> Each word segment (blank frames included) is passed through a two-layer MLP applied per frame, mean-pooled along time into a single neural word embedding, and projected to the LLM hidden dimension by a linear adapter.</p> <p>The reason this works is statistical. Spaces make up 19% of characters and are robustly predicted, so the predicted word count for <strong>86%</strong> of sentences falls within ±1 word of the ground truth.</p> <p>Even so, the number of neural tokens $N$ produced by CTC segmentation may differ from the number of target words $M$, so a within-sentence alignment step precedes contrastive learning. A cosine-distance cost matrix is computed between the $N$ neural embeddings and the $M$ target word embeddings (taken from the LLM’s input embedding layer), and hard DTW (Sakoe and Chiba, 1978) recovers a monotonic alignment path from which one-to-one pairs are extracted (one target per neural token).</p> <p>Matched pairs from all sentences in the batch are $\ell_2$-normalised and fed into a SigLIP loss. For every pair $(i, j)$ across the batch, a sigmoid binary cross-entropy is applied to the scaled cosine similarity:</p> \[\text{logit}_{ij} = \tau \langle \hat{\mathbf{w}}_i, \mathbf{w}_j \rangle + b\] <p>with $\tau$ and $b$ learnable scalars. The label is 1 whenever the ground-truth embeddings $\mathbf{w}_i$ and $\mathbf{w}_j$ have cosine similarity $\geq 0.999$ — i.e. they represent the same word — and 0 otherwise. This duplicate-aware labelling matters: without it, the same sentence appearing across multiple subjects would generate false negatives.</p> <h3 id="level-3--sentences-the-neuro-conditioned-llm">Level 3 — sentences: the neuro-conditioned LLM</h3> <p>The prompt is constructed as:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[CTC: ‖ &lt;CTC-decoded text tokens&gt; ‖ \nMEG: ‖ &lt;MEG token embeddings&gt; ‖ \nOutput:]
</code></pre></div></div> <p>The LLM therefore receives two complementary streams. The CTC text anchors it to a plausible linguistic prior; the MEG tokens carry the residual neural information needed to push decoding past that prior.</p> <p>During training, <strong>modality dropout</strong> independently zeroes random token positions in both the MEG token embeddings and the CTC text tokens (both at rate 0.1), forcing robust conditioning on either modality alone. The loss is cross-entropy with label smoothing 0.02.</p> <p>The LLM is Qwen3-4B, fine-tuned with LoRA (rank 128, $\alpha = 256$, dropout 0.0) applied to all linear projection matrices. Inference uses beam search with beam size 16, a maximum of 60 new tokens, and length penalty 0.2.</p> <h3 id="model-soup--treating-each-subject-as-its-own-task">Model soup — treating each subject as its own task</h3> <p>Three ways of attaching LoRA are compared. <em>Joint LoRA</em> pools all nine subjects and trains a single adapter. <em>Per-subject LoRA</em> trains nine independent adapters. <em>Model Soup</em> (Wortsman et al., 2022) also trains per-subject adapters, then uniformly averages their best-checkpoint state dictionaries into a single adapter applied to everyone.</p> <p>The intuition is that each subject’s MEG signature is a different “task”: per-subject adapters specialise on matched neural data, and uniform weight averaging yields one model that generalises across subjects without ever training a heavy joint model.</p> <h3 id="training-objective">Training objective</h3> <p>The overall loss is a weighted sum of three terms:</p> \[\begin{aligned} \mathcal{L} = \; &amp; (1 - \alpha - \beta)\,\mathcal{L}_{\text{CTC}} \\ &amp; + \alpha\,\mathcal{L}_{\text{Contrastive}} \\ &amp; + \beta\,\mathcal{L}_{\text{CE}} \end{aligned}\] <ul> <li>$\mathcal{L}_{\text{CTC}}$ — character level. This governs how well brain signal maps to a keystroke string, and as the appendix correlation analysis (Figure S5) shows, its quality effectively determines the final performance.</li> <li>$\mathcal{L}_{\text{Contrastive}}$ — word-level SigLIP loss, pulling MEG word chunks into the LLM’s word embedding space.</li> <li>$\mathcal{L}_{\text{CE}}$ — sentence-level autoregressive cross-entropy, conditioned on both the CTC text and the neural tokens in the prompt.</li> </ul> <p>Two training regimes were explored. <strong>(i) End-to-end staged training</strong> runs 275 epochs in three stages — CTC only (epochs 0–149), CTC + contrastive (150–224, $\alpha = 0.1$), CTC + contrastive + LLM cross-entropy (225–274, $\beta = 0.01$) — with inactive terms dropped and active weights renormalised to sum to 1. <strong>(ii) Standalone LoRA fine-tuning</strong> freezes the CTC encoder and pre-trained word projector from the best contrastive checkpoint and optimises only the LoRA-adapted LLM for 30 epochs on a single GPU. This lightweight regime enabled rapid iteration over LoRA configurations, LLM sizes, and the model-soup strategy — and <em>it yielded the best overall results</em>.</p> <h2 id="data-and-pipeline">Data and Pipeline</h2> <h3 id="the-englishbcbl-dataset">The EnglishBCBL dataset</h3> <table> <thead> <tr> <th>Item</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td>Participants</td> <td>Nine healthy adults (50% men, 50% women; mean age 34.6, range 23–56)</td> </tr> <tr> <td>Criteria</td> <td>All right-handed, proficient touch typists, typing accuracy ≥ 80%, native English speakers, no neurological or psychiatric history</td> </tr> <tr> <td>Recording</td> <td>10 sessions of ~1 hour per participant = 90 hours total</td> </tr> <tr> <td>Device</td> <td>Megin 306 channels (102 magnetometers + 204 planar gradiometers), 1 kHz sampling, online 0.1 Hz HPF / 330 Hz LPF</td> </tr> <tr> <td>Keyboard</td> <td>MR-compatible QWERTY keyboard from HybridMojo LLC with modified non-ferromagnetic springs</td> </tr> <tr> <td>MRI</td> <td>3-T SIEMENS Prisma-fit, 64-channel head coil, T1 (TR 2530 ms, TE 2.36 ms, flip 7°, FOV 256 mm, 1 mm³, 176 slices)</td> </tr> <tr> <td>Sentences</td> <td>2,560 drawn at random from a pool of 20,000 simple English sentences generated by Llama 4, filtered to remove special characters and contractions; 2,724 unique in the final analysis including pilot sessions</td> </tr> <tr> <td>Compensation</td> <td>12 euros per hour plus 200 euros on completion</td> </tr> </tbody> </table> <h3 id="task-design">Task design</h3> <p>Each trial has three phases — <strong>listen, wait for cue, type</strong>. The sentence audio is played through MEG-compatible headphones, a fixation cross appears for 1.5 seconds, and the offset of that cross marks the start of the typing phase. Crucially, <em>no letters are displayed on screen while typing</em>. Participants type as accurately as possible without backspace while fixating on a rotating black square at screen centre — a design choice to avoid eye movements being driven by linguistic content, as they would be in standard left-to-right reading. The minimal feedback is that square rotating clockwise by 10 degrees with each keystroke.</p> <p>Each session comprises 16 blocks of 16 sentences. The first 4 sentences of every session are practice trials, distinct from the 2,560 experimental sentences; the first two give full visual feedback and the remaining two familiarise the participant with the minimal-feedback condition.</p> <p>The important property of this design is the <strong>delayed typing</strong>: a forced delay separates listening from typing, so what is being decoded is neural activity during language <em>production</em>, not auditory perception.</p> <h3 id="preprocessing-and-splits">Preprocessing and splits</h3> <p>MEG is bandpass filtered at 0.5–45 Hz with a 50 Hz notch, downsampled to 100 Hz, per-channel normalised with a RobustScaler (per-recording median and IQR), and clamped at ±5 robust standard deviations. No signal-space projection was applied.</p> <p>Splits are made at the level of <strong>unique sentence texts</strong> using a deterministic hash-based splitter with an 80/10/10 ratio. Because assignment is computed from the hash of the sentence text alone, the split is stable regardless of which subjects are in the query, and all events sharing the same sentence text — across subjects and sessions — land in the same partition. Text leakage is exactly zero, which matters a great deal given a pool of only 2,724 sentences.</p> <h3 id="augmentation">Augmentation</h3> <p>MEG segments run from 400 ms before sentence onset (first key pressed) through sentence offset (last key released), extended by a uniformly sampled 400–500 ms buffer to capture post-completion neural activity. During training, temporal jittering randomly crops up to 400 ms from the pre-onset baseline, varying the effective alignment between neural signal and sentence onset across epochs.</p> <p>On top of that: a per-channel constant offset drawn from $\mathcal{N}(0, 0.3)$ simulates slow-drift artifacts; time masking (maximum mask length 50 frames, application probability 0.2) and an independent channel mask of maximum width 400 along the sensor axis follow SpecAugment (Park et al., 2019); and temporal stretch rescales trial duration by a factor drawn uniformly from $[0.8, 1.2]$ via linear interpolation.</p> <h3 id="compute">Compute</h3> <table> <thead> <tr> <th>Item</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td>Libraries</td> <td>neuralset (King et al., 2026) · neuraltrain (d’Ascoli et al., 2026)</td> </tr> <tr> <td>Optimiser</td> <td>AdamW, lr $8 \times 10^{-4}$, weight decay $10^{-3}$</td> </tr> <tr> <td>Schedule</td> <td>Linear warm-up 500 steps (start factor 0.01) → Cosine Annealing</td> </tr> <tr> <td>Precision</td> <td>BF16 mixed precision, gradient clipping at global norm 1</td> </tr> <tr> <td>Batch</td> <td>64 × 2 (micro-batch accumulation) × 8 GPUs = effective 1,024 samples</td> </tr> <tr> <td>Hardware</td> <td>8× A100 80 GB</td> </tr> <tr> <td>Wall clock</td> <td>19.5 hours for the full procedure (end-to-end, 275 epochs)</td> </tr> <tr> <td>Checkpointing</td> <td>Encoders for the LoRA experiments selected by validation CER, early stopping patience 50 epochs</td> </tr> </tbody> </table> <h3 id="metrics">Metrics</h3> <ul> <li><strong>CER</strong> — Levenshtein edit distance between predicted and ground-truth character sequences, normalised by ground-truth length.</li> <li><strong>WER</strong> — Levenshtein distance at word level after whitespace tokenisation, normalised by the number of ground-truth words.</li> <li><strong>SemER</strong> — the $\ell_2$ distance between $\ell_2$-normalised, mean-pooled hidden states of a frozen RoBERTa-large (Liu et al., 2019) applied to prediction and reference. It measures semantic proximity.</li> </ul> <p>CER and WER were implemented via <code class="language-plaintext highlighter-rouge">SequenceMatcher</code> from the <code class="language-plaintext highlighter-rouge">edit-distance</code> library and SemER via HuggingFace <code class="language-plaintext highlighter-rouge">transformers</code>; two-sided Mann-Whitney U tests were used for significance between conditions.</p> <h2 id="results">Results</h2> <h3 id="scale-unlocks-asynchronous-decoding">Scale unlocks asynchronous decoding</h3> <p>The first question is whether the scale and diversity of the new dataset are enough to close the gap between asynchronous and synchronous decoding. Both encoders were trained on the low-data SpanishBCBL (Lévy et al., 2025) and the new EnglishBCBL.</p> <table> <thead> <tr> <th>Encoder</th> <th>SpanishBCBL</th> <th>EnglishBCBL</th> </tr> </thead> <tbody> <tr> <td>Encoder Sync (synchronous, Lévy et al., 2025)</td> <td>0.39 ± 0.02</td> <td>0.23 ± 0.03</td> </tr> <tr> <td>Encoder Async (asynchronous, this work)</td> <td>0.59 ± 0.02</td> <td>0.25 ± 0.03</td> </tr> </tbody> </table> <p>Read this carefully. In the low-data regime synchronous decoding wins by a wide margin (0.39 vs. 0.59, a 20-point gap). Scale the data by 10× and that gap collapses to <strong>2 points</strong>. Data substituted for the strong supervisory signal that keystroke timing provided. This is the result the whole paper rests on: the precondition for real-time use can be met without sacrificing accuracy.</p> <p>The scaling is log-linear. Retraining Encoder Async on progressively larger subsets of EnglishBCBL gives a Pearson $r = -0.99$ ($p = 1.1 \times 10^{-3}$, $R^2 = 0.98$ across the 5 training-fraction conditions) between $\log_{10}(\text{hours})$ and across-subject mean CER, with a slope of −0.39 CER per decade. There is no sign of a plateau at the current 90-hour ceiling.</p> <h3 id="sentence-diversity-is-a-separate-axis-from-quantity">Sentence diversity is a separate axis from quantity</h3> <p>Encoder Async trained on SpanishBCBL reaches CER 0.59, significantly worse than the 0.52 ± 0.02 obtained from training on a similar <em>amount</em> of EnglishBCBL data ($p &lt; 0.05$). So the difference is in the nature of the data, not its volume.</p> <p>What differs is repetition: in SpanishBCBL each unique sentence was typed twice by each participant, while in EnglishBCBL each was typed once. To isolate that, two controlled datasets were constructed matched for total sentence count and number of subjects ($n = 9$) but differing in the number of unique sentences — 128 unique × 2 repetitions (SpanishBCBL protocol) versus 256 unique × 1 (EnglishBCBL protocol).</p> <p>The result: CER 0.45 ± 0.03 for non-repeated versus 0.65 ± 0.01 for repeated, $p &lt; 0.001$. For the same number of trials, <strong>showing new sentences beats repeating old ones by 20 points</strong>. That is an immediately actionable conclusion for anyone designing a data-collection protocol, and it is cleaner for being an encoder-only result with no language model involved.</p> <h3 id="main-results--word-and-meaning-level">Main results — word and meaning level</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig3-decoding-results-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig3-decoding-results-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig3-decoding-results-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig3-decoding-results.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: Brain2Qwerty v2 enables word- and meaning-level decoding from MEG. A–C show per-subject CER / WER / SemER for three decoders, D shows per-sentence word-edit counts for the best, median, and worst subjects, and E–F show actual decoded sentences.</figcaption> </figure> <p>Three approaches are compared: (1) the Encoder alone, with no language model correction, taking the most likely keystroke class at each time step from the CTC logits; (2) Encoder + N-gram, the Brain2Qwerty v1 approach, correcting encoder output with a 6-gram character language model; and (3) the full Brain2Qwerty v2 pipeline.</p> <table> <thead> <tr> <th>Metric</th> <th>Encoder</th> <th>Encoder + N-gram</th> <th>Brain2Qwerty v2</th> </tr> </thead> <tbody> <tr> <td>CER</td> <td>0.28 ± 0.03</td> <td><strong>0.26 ± 0.03</strong></td> <td>0.31 ± 0.03</td> </tr> <tr> <td>WER</td> <td>0.55 ± 0.04</td> <td>0.43 ± 0.04</td> <td><strong>0.39 ± 0.04</strong></td> </tr> <tr> <td>SemER</td> <td>0.096 ± 0.003</td> <td>0.085 ± 0.004</td> <td><strong>0.059 ± 0.005</strong></td> </tr> </tbody> </table> <p>Every pairwise comparison reaches $p &lt; 0.005$. On the two metrics most relevant to successful communication — WER and SemER — Brain2Qwerty v2 clearly wins. The SemER improvement over the N-gram baseline (0.085 → 0.059) is especially large, reflecting the LLM’s capacity to recover <em>globally coherent sentence structure</em> from noisy neural input.</p> <p>Set against the 0.92–0.94 WER Tang et al. (2023) report for decoding perceived speech from fMRI, this is a substantial step forward in recovering exact words from non-invasive recordings.</p> <h3 id="is-the-worse-cer-a-defect">Is the worse CER a defect?</h3> <p>Brain2Qwerty v2’s CER (0.31) is in fact <em>worse</em> than the Encoder alone (0.28) and the N-gram baseline (0.26). This is a structural consequence of autoregressive LLM decoding. The LLM has been trained to produce fluent sentences even when the encoder output and MEG token signal quality are not sufficient for successful decoding, so it emits incorrect sentences that diverge substantially from the target at the character level.</p> <p>The failure mode is qualitatively distinct from the N-gram’s. Brain2Qwerty v2 produces perfect or near-perfect decoding for the best subject, but the worst subject’s output can be a coherent yet entirely different sentence. The paper’s example is vivid: for the target <em>“cars are not allowed on this road”</em>, the model produces <em>“had she not fallen down the stairs”</em>. Grammatically flawless, no gain whatsoever in word or semantic accuracy, and a large CER penalty.</p> <p>The N-gram model does the opposite: it consistently corrects local character sequences and keeps CER low, but fails to produce lexically correct sentences (see outputs like <em>“WAS THE DISH THAT YOU NIGHTY IN THE LP BUT”</em> in Figure 3F). Since successful communication relies on meaning rather than strict character matching, the authors argue the WER and SemER gains are worth the CER cost — and they are right.</p> <p>That trade-off flips depending on the application, though. As the paper notes, typing a password and responding in a dialogue call for different decoding objectives. Where individual characters matter, a fluent hallucination is the worst possible failure.</p> <h3 id="how-often-is-it-perfect">How often is it perfect?</h3> <table> <thead> <tr> <th>Subject</th> <th>Perfect decodings (zero word edits)</th> </tr> </thead> <tbody> <tr> <td>Best</td> <td>28% (47% within a single word edit)</td> </tr> <tr> <td>Median</td> <td>15%</td> </tr> <tr> <td>Worst</td> <td>4%</td> </tr> </tbody> </table> <p>Even for the median and worst subjects, the typical error mode is a single substituted or missing word rather than a collapse into an unrelated sentence. The appendix’s difficulty-band analysis (Figure S3) supports this. On the easiest band the best subject is verbatim on 5 of 6 sentences and the median subject differs by at most one or two words — and those errors are almost always meaning-preserving or grammar-preserving substitutions, like <em>“travel by plane”</em> → <em>“travel alone”</em> or <em>“car”</em> → <em>“computer”</em>. On harder bands the substitutions become longer-range and sometimes merely topic-adjacent, but the output remains grammatical.</p> <h3 id="ctc-tokenizer-and-lora-strategy">CTC tokenizer and LoRA strategy</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig4-tokenizer-and-lora-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig4-tokenizer-and-lora-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig4-tokenizer-and-lora-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig4-tokenizer-and-lora.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 4: CTC Tokenizer and tuned LLM adaptation cut WER by 20% over baseline alignments. A compares three alignment strategies, B shows word-count calibration, C an example of word retrieval, D the LoRA rank sweep, and E LLM backbone scaling with target-module ablation.</figcaption> </figure> <p><strong>Alignment strategies.</strong> CTC tokenizer WER 0.39 ± 0.04, sentence alignment (one embedding per sentence; Zhang et al., 2026) 0.46 ± 0.04, patch tokenization (a fixed number of equally-spaced chunks per sentence, inspired by ViT; Dosovitskiy et al., 2021) 0.49 ± 0.05, all at $p &lt; 0.005$. In a typical sentence, 8 of 9 words are recovered at rank 1 (Figure 4C).</p> <p><strong>LoRA rank sweep.</strong> Across $r \in {1, \ldots, 256}$ the three strategies trace clearly different paths. Joint LoRA wins at small ranks ($r = 2$, WER 0.43); above that the single adapter has enough capacity to memorize the limited sentence pool (~2.7K unique sentences) and WER worsens. Per-subject LoRA and Model Soup each see about 10× less data and never reach that overfitting regime: WER decreases smoothly with $r$, and Model Soup wins at $r = 128$ (WER 0.43). Model Soup also trains <em>faster</em> than the joint baseline even at higher rank, since fitting nine small adapters is more efficient than training one large pooled adapter.</p> <p><strong>Backbone scaling.</strong> Listing All subjects ($r=2$) / Model soup ($r=128$): Qwen3-0.6B 0.43/0.43, 1.7B 0.42/0.41, 4B 0.42/0.40, 4B with LoRA on all modules 0.41/0.39. Model Soup improves at every step — 0.6B → 1.7B ($p = 0.020$), 1.7B → 4B ($p &lt; 0.01$), attention-only → all modules ($p &lt; 0.01$) — while joint training plateaus near WER 0.41. If you want to cash in on a bigger LLM, Model Soup is the strategy that lets you.</p> <h3 id="autonomous-ai-agents-auto-research">Autonomous AI agents (Auto Research)</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig5-auto-research-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig5-auto-research-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig5-auto-research-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/fig5-auto-research.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 5: Autonomous AI coding agents discover configurations that outperform classical optimization. A shows the running-best validation WER on S01 over successive experiments, B the test WER of each method's final configuration evaluated on all nine subjects.</figcaption> </figure> <p>Inspired by Karpathy’s autoresearch, three Cursor agents powered by Claude Opus 4.6 were run concurrently. Each had full filesystem and terminal access to a dedicated git worktree on an isolated branch, sharing a common codebase and pretrained checkpoints but maintaining separate configuration files and results directories, with no access to each other’s branches. The parent branch configuration was intentionally minimal, exposing only four hyperparameters (learning rate, weight decay, LoRA rank, batch size), the model choice (Qwen3-0.6B with LoRA), and architectural constants.</p> <p>The agent prompt’s rules are worth reading: poll SLURM every 5 minutes and never idle; run exactly 50 jobs per round testing at least 4–5 independent ideas; 45-minute SLURM timeout with hung jobs cancelled immediately; never delete files and never inspect test predictions; use only subject 0 and optimise on validation metrics only. Budget: 10 rounds × 50 jobs = 500 total runs.</p> <p>The comparison baseline, Optuna (Akiba et al., 2019), ran TPE over the same four parameters on an identical compute budget (v4.8, <code class="language-plaintext highlighter-rouge">multivariate=True</code>, <code class="language-plaintext highlighter-rouge">group=True</code>, <code class="language-plaintext highlighter-rouge">constant-liar=True</code>, <code class="language-plaintext highlighter-rouge">n-startup-trials=32</code>, 500 trials distributed across 10 batches of 50).</p> <table> <thead> <tr> <th>Method</th> <th>S01 validation WER</th> <th>Test WER on all 9 subjects</th> </tr> </thead> <tbody> <tr> <td>Default</td> <td>0.45</td> <td>reference</td> </tr> <tr> <td>Optuna TPE</td> <td>0.41 (−8.6% relative)</td> <td>0.493 ($p = 0.88$ vs. default, no improvement)</td> </tr> <tr> <td>AutoResearch 1</td> <td>0.38 (−16.1%)</td> <td><strong>0.42 (−16.0%)</strong></td> </tr> <tr> <td>AutoResearch 2</td> <td>0.36 (−19.8%)</td> <td>0.45 (−10.0%)</td> </tr> <tr> <td>AutoResearch 3</td> <td>0.37 (−17.7%)</td> <td>0.43 (−12.7%)</td> </tr> </tbody> </table> <p>The cross-subject evaluation is what settles it. Optuna’s single-subject gain vanished entirely ($p = 0.88$), while all three agents maintained significant improvements (all $p &lt; 10^{-6}$). What the agents found were genuine innovations that transfer across the population, not artifacts of tuning on S01.</p> <p>The strategies the three agents independently converged on:</p> <ul> <li><strong>Label smoothing</strong> — found by all three in rounds 1–2, providing the largest single-round WER reduction (−0.04 for Agent 1).</li> <li><strong>Modality dropout</strong> — dropping CTC tokens during training forces the LLM to rely more on neural word embeddings than on noisy CTC predictions. Consistently large gains in rounds 5–9.</li> <li><strong>Beam search decoding</strong> of LLM output, enabling multi-hypothesis decoding at test time, in rounds 2–3.</li> <li><strong>Sentence-level contrastive alignment loss</strong>, an auxiliary CLIP-style loss complementing the word-level alignment, in rounds 7–8.</li> <li><strong>Minimal prompts</strong> — reducing the instruction prompt to <code class="language-plaintext highlighter-rouge">CTC:</code>, <code class="language-plaintext highlighter-rouge">MEG:</code>, <code class="language-plaintext highlighter-rouge">Output:</code> rather than verbose task descriptions.</li> </ul> <p>All of these were considered during v2’s development, with the final configuration selected by the research team.</p> <h3 id="and-the-failure">And the failure</h3> <p>Give the same agents an <strong>open-ended objective</strong> — start from the Brain2Qwerty v1 codebase and match the v2 pipeline’s performance on EnglishBCBL — and all three consistently fail. Large, entangled code modifications caused the majority of subsequent SLURM jobs to crash before producing valid metrics, and on the rare occasions when a launch did succeed, the agents tended to idle rather than iterate.</p> <p>The authors’ conclusion is measured: AI agents may serve as a powerful force multiplier, but human research remains, for now, a critical part of the scientific process.</p> <h2 id="analysis-and-ablations">Analysis and Ablations</h2> <h3 id="does-the-llm-actually-read-the-brain">Does the LLM actually read the brain?</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs4-neuro-tokens-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs4-neuro-tokens-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs4-neuro-tokens-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs4-neuro-tokens.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure S4: Brain2Qwerty v2 is a neuroLLM, not a corrector of CTC predictions. Both configurations share the same Qwen3-0.6B backbone; grey conditions the LLM only on encoder predictions, green additionally on the MEG-derived word embeddings.</figcaption> </figure> <p>The central question for any LLM-based decoder is whether the LLM is reading neural information or merely behaving as a corrector of the encoder’s text output using its language priors.</p> <p>To separate the two, the MEG-derived word embeddings (“Neuro Tokens”) produced by the CTC tokenizer and word projector were ablated, conditioning the LLM only on the encoder’s predictions. This variant (Brain2Qwerty + LLM) was trained on the same Qwen3-0.6B backbone.</p> <table> <thead> <tr> <th>Metric</th> <th>Brain2Qwerty + LLM (Neuro Tokens removed)</th> <th>Brain2Qwerty v2</th> </tr> </thead> <tbody> <tr> <td>CER</td> <td>0.38</td> <td><strong>0.34</strong></td> </tr> <tr> <td>WER</td> <td>0.49</td> <td><strong>0.43</strong></td> </tr> <tr> <td>SemER</td> <td>0.067</td> <td><strong>0.064</strong></td> </tr> </tbody> </table> <p>Every metric improves (paired Wilcoxon $p \approx 0.004$), with the largest gap on WER (−5.6 points absolute). In the Discussion the authors summarise this degradation as 16% on WER. That the gap is biggest on WER is the informative part: the Neuro Tokens carry <em>word-level</em> information the CTC text alone is missing.</p> <p>This completes the picture of two complementary input streams. The CTC text anchors the LLM to a plausible linguistic prior; the MEG tokens carry the residual neural information that pushes decoding past that prior. Full performance is reached <em>only when both are provided</em>.</p> <p>What is most striking is that this adaptation is obtained from as few as <strong>~2,700 unique training sentences (~90 h of MEG)</strong> — a corpus orders of magnitude smaller than what is typically used to fine-tune a language model.</p> <h3 id="the-encoder-is-the-bottleneck">The encoder is the bottleneck</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs5-encoder-importance-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs5-encoder-importance-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs5-encoder-importance-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/figs5-encoder-importance.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure S5: Encoder CER linearly predicts the model's performance, and architecture choices set the encoder CER. A and B show per-sentence correlations, C compares three encoder architectures.</figcaption> </figure> <p>Correlating Brain2Qwerty v2’s per-sentence WER and SemER against upstream encoder CER shows both downstream metrics scaling linearly with it (Pearson $r$ = 0.78 for WER, 0.68 for SemER). Better keystroke predictions out of the encoder mean better final sentences. Obvious as that sounds, the fact that it holds is itself a counter to the suspicion that the LLM is confabulating plausible sentences independently of the neural signal.</p> <p>How much does the encoder architecture matter? Three architectures were trained and tested on the same data:</p> <table> <thead> <tr> <th>Encoder architecture</th> <th>CER</th> </tr> </thead> <tbody> <tr> <td>Temporal Patch Transformer (inspired by Zhang et al., 2026; first introduced in Feghhi et al., 2025)</td> <td>0.37 ± 0.03</td> </tr> <tr> <td>BrainModule + Transformer (very similar to Brain2Qwerty v1; Défossez et al., 2023)</td> <td>0.28 ± 0.03</td> </tr> <tr> <td>BrainModule + Conformer (this paper)</td> <td><strong>0.25 ± 0.03</strong></td> </tr> </tbody> </table> <p>Replacing the Conformer with a standard Transformer increases CER from 0.25 to 0.28 ($p &lt; 0.005$), showing that the Conformer’s interleaved convolutional and attention layers are a useful inductive bias for the local temporal structure of MEG signals. Further replacing the BrainModule with a Temporal Patch module pushes CER to 0.37, the worst of the three. Both components pull their weight for low-SNR MEG inputs.</p> <h3 id="multi-subject-training-pays-off-substantially">Multi-subject training pays off substantially</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab1-multi-subject-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab1-multi-subject-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab1-multi-subject-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab1-multi-subject.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 1: Effect of including the target subject in pretraining and of training on multiple subjects. Per-subject trains the full pipeline from scratch on the target subject only; Joint training trains from scratch on all subjects jointly; LOO + finetune pretrains on the other N−1 subjects, then finetunes on the target with the Conformer frozen.</figcaption> </figure> <p>The ordering is identical across all three subjects: per-subject worse than LOO + finetune worse than joint training. In WER terms the best subject goes 38.3% → 32.8% → 22.6%, the median 66.5% → 58.6% → 47.8%, the worst 90.6% → 68.3% → 61.4%.</p> <p>Note that the per-subject regime used a 4× longer training schedule to match the joint regime’s number of optimisation steps, and is still consistently the weakest. The limiting factor is data diversity, not compute.</p> <p>More practically important: LOO + finetune closes most of the gap. A single finetuning pass on a held-out subject gets you most of the way there, supporting deployment to new subjects without retraining the base pipeline from scratch — a decisive property for any clinical rollout.</p> <h3 id="can-you-get-away-with-fewer-sensors">Can you get away with fewer sensors?</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab2-sensor-ablation-480.webp 480w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab2-sensor-ablation-800.webp 800w,/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab2-sensor-ablation-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0035-accurate-decoding-of-natural-sentences-from-non-invasive-bra/tab2-sensor-ablation.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 2: Sensor-count ablation. CER / WER / SemER when the MEG input is randomly subsampled at training time. Values are mean ± SEM across 4 sensor-selection seeds.</figcaption> </figure> <p>Whole-head MEG arrays like the 306-channel Megin system are bulky, cryogenically cooled, and expensive for clinical or consumer deployment. Optically pumped magnetometers (OPMs), which operate at room temperature in flexible helmets, are emerging as a practical alternative — typically with 50–150 sensors. Can such a low-channel array support this kind of end-to-end sentence decoding?</p> <p>For each keep-fraction in ${0.25, 0.50, 0.75}$ the 306 MEG channels were randomly subsampled to ${76, 153, 230}$ sensors respectively, and the entire pipeline retrained with one LoRA for all subjects at rank 2 for simplicity (this configuration’s full-array baseline is WER 0.433). The model seed was fixed and four sensor-selection seeds were run per fraction, so within-fraction variance reflects only which sensors were retained.</p> <p>Performance degrades smoothly and monotonically. Dropping the first 76 channels (306 → 230) costs only +3.4 pp WER over the full-array baseline; the next 77 (230 → 153) costs +2.3 pp; and the final 77 (153 → 76) costs +5.7 pp. SEMs are tight, always ≤ 1 pp on WER.</p> <p>The practical conclusion matters: <strong>an OPM-class helmet on the order of 150 sensors loses only about 5.7 pp WER versus the full 306-channel baseline.</strong> Paired with the same end-to-end decoding pipeline, low-channel systems should recover most of the performance reported here.</p> <h3 id="what-happens-in-the-embedding-space">What happens in the embedding space</h3> <p>A tSNE analysis in the appendix looks inside the encoder. Key representations taken after the BrainModule cluster <em>by participant</em> — individual neural signatures survive in the embedding. Representations after the Conformer’s last layer, by contrast, cluster clearly <em>by key class</em>, and that structure reflects the physical layout of the keyboard. Crucially, this structure is learned: in the embedding space of an untrained Conformer, the key representations still cluster by subject.</p> <h2 id="limitations-and-critical-assessment">Limitations and Critical Assessment</h2> <p>Starting with what the authors acknowledge:</p> <ul> <li><strong>Large inter-individual variability persists</strong> (N-gram CER 17.1%–41.0%). Since final performance is highly correlated with upstream encoder quality, improving the encoder through cross-subject transfer or self-supervised pretraining is the priority.</li> <li><strong>The study uses healthy volunteers</strong> who are effectively typing on a keyboard. Whether the approach transfers reliably to patients — for whom actual key presses will be missing not just during inference but during training and finetuning too — remains to be demonstrated.</li> <li><strong>It is not real-time.</strong> The architecture is not causal and works with an entire sentence, so latency is necessarily high and users cannot see a word as they type it. Low-latency causal Conformers have shown promise for EMG handwriting (Sivakumar et al., 2024), which suggests the direction for follow-up.</li> <li><strong>The gap with invasive systems remains substantial.</strong> State-of-the-art invasive BCIs achieve below 2% WER for typing (Jude et al., 2026) and below 6% CER for handwriting (Willett et al., 2021).</li> <li><strong>Hardware constraints.</strong> A 306-sensor cryogenic MEG remains challenging to adapt to a clinical setting. The sensor ablation and OPM discussion soften this, but nothing was actually validated on an OPM system.</li> </ul> <p>Additional observations from a reviewer’s standpoint:</p> <ul> <li><strong>The sentence pool is narrow.</strong> 2,724 “simple English sentences” generated by Llama 4, with contractions and special characters filtered out. No proper nouns, no numbers, no domain terminology, no colloquial fragments — none of what real communication requires. It is hard to rule out the LLM leaning on this narrow distribution as a strong prior. The hash-based split prevents literal leakage, but the <em>distributional</em> prior advantage remains.</li> <li><strong>There is no evaluation of what 39% WER means in practice.</strong> Four words in ten are wrong. The best subject’s 28% perfect and 47% within-one-word is impressive, but no user study measures actual communication outcomes (question answering, message-delivery success rates) at this level.</li> <li><strong>The safety implications of worse CER are only discussed, not addressed.</strong> Generating a fluent but entirely wrong sentence is a serious hazard in a medical communication setting. Picture <em>“had she not fallen down the stairs”</em> being presented as a patient’s utterance. Confidence estimation or an abstention mechanism seems necessary, and neither is explored.</li> <li><strong>The Auto Research comparison is not entirely apples-to-apples.</strong> Optuna is <em>by construction</em> restricted to the four exposed parameters, while the agents can modify code and create new axes. The authors say so explicitly, so the conclusion is not wrong — but the accurate reading is “whoever can expand the search space wins”, not “agents beat TPE”. There is no comparison over an identical search space.</li> <li><strong>Nine subjects is statistically thin.</strong> With $n = 9$, the minimum achievable $p$ for a paired Wilcoxon test is 0.0039, and every significant comparison in Figure 3 sits at exactly that value. Statistical power is at the floor.</li> <li><strong>SemER is hard to interpret.</strong> It is an $\ell_2$ distance between RoBERTa-large embeddings, and there is no anchor for what the absolute scale (0.059 vs. 0.096) means semantically. A correlation with human judgement would have helped.</li> </ul> <h2 id="takeaways">Takeaways</h2> <ul> <li><strong>The real finding here is about data, not architecture.</strong> An asynchronous encoder that trailed by 20 points in the low-data regime closes to within 2 points at 10× the data. Data substituted for the strong supervisory signal that keystroke timing provided. That means the trade-off between “usable in real time” and “accurate” can be erased by data — which changes where this field should be investing.</li> <li><strong>For a fixed number of trials, show new sentences rather than repeating old ones.</strong> 128 × 2 vs. 256 × 1 gives CER 0.65 vs. 0.45. This holds without a language model and applies directly to protocol design in any neural recording study where data collection cost dominates.</li> <li><strong>The CTC tokenizer is a portable idea.</strong> “How do I chunk a continuous embedding stream into discrete LLM tokens?” is a problem every non-text-modality → LLM pipeline faces. The answer here is to reuse the <em>space predictions of a CTC head you already trained</em> rather than learning a separate segmentation model. Spaces are 19% of characters, so they are robustly predicted, and 86% of sentences land within ±1 word of the true count. Any CTC-based pipeline gets this segmentation for free.</li> <li><strong>The Neuro Token ablation is the experiment to demand from papers like this.</strong> Any work that bolts an LLM onto a decoder invites the suspicion that the LLM is inventing answers from its language prior. Removing only the neural input from the prompt while holding everything else fixed is the minimum answer to that suspicion. Without the 0.43 → 0.49 WER difference, this paper’s claim would be far weaker.</li> <li><strong>Treating subjects as tasks and using a model soup works well.</strong> Joint LoRA collapses at higher rank by memorizing a small corpus, while per-subject adapters plus weight averaging improve smoothly up to rank 128 and are the strategy that cashes in on a bigger backbone. This is a reusable pattern across biosignal domains with high inter-individual variability.</li> <li><strong>The same experiment reveals both the success and failure conditions for AI agents.</strong> On a narrowly scoped tuning problem they beat TPE decisively and their gains transfer across subjects. On the open-ended “invent a new architecture” task, large entangled edits produce crashes and the agents idle. The boundary of automation lies in <em>task structure</em>, not capability — and reporting the failure alongside the success deserves credit.</li> </ul> <h2 id="getting-started">Getting started</h2> <p>The authors released the code:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/facebookresearch/brain2qwerty
<span class="nb">cd </span>brain2qwerty
</code></pre></div></div> <p>Of the pipeline’s three stages (CTC encoder → contrastive alignment → LoRA LLM), the standalone LoRA fine-tuning regime yielded the best performance and iterates in 30 epochs on a single GPU. The full end-to-end training takes 19.5 hours on 8× A100 80 GB. Whether the EnglishBCBL dataset itself will be released is not stated in the paper.</p> <h2 id="references">References</h2> <ul> <li>Paper: <a href="https://arxiv.org/abs/2608.18114">https://arxiv.org/abs/2608.18114</a></li> <li>Code: <a href="https://github.com/facebookresearch/brain2qwerty">https://github.com/facebookresearch/brain2qwerty</a></li> <li>Auto Research inspiration: <a href="https://github.com/karpathy/autoresearch">https://github.com/karpathy/autoresearch</a></li> </ul> <h2 id="further-reading">Further Reading</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2502.17480">Brain-to-Text Decoding: A Non-invasive Approach via Typing</a></strong> (Lévy et al., 2025) — the direct predecessor, Brain2Qwerty v1. A synchronous classifier time-locked to each keystroke reaches CER 32% from MEG, with EEG results (CER 67%) reported alongside.</li> <li><strong><a href="https://arxiv.org/abs/2208.12266">Decoding speech perception from non-invasive brain recordings</a></strong> (Défossez et al., 2023) — where this paper’s BrainModule comes from. Contrastive learning decodes self-supervised representations of perceived speech from M/EEG.</li> <li><strong><a href="https://arxiv.org/abs/2412.17829">Towards decoding individual words from non-invasive brain recordings</a></strong> (d’Ascoli et al., 2025) — decodes individual words from MEG/EEG and shows how much the recording device and experimental protocol dominate performance.</li> <li><strong><a href="https://www.nature.com/articles/s41593-023-01304-9">Semantic reconstruction of continuous language from non-invasive brain recordings</a></strong> (Tang et al., 2023) — recovers the meaning of perceived and imagined speech and silent video from fMRI. This is the work whose 0.92–0.94 WER serves as the comparison point here.</li> <li><strong><a href="https://www.nature.com/articles/s41586-023-06377-x">A high-performance speech neuroprosthesis</a></strong> (Willett et al., 2023) — a landmark on the invasive side, and the yardstick for how far non-invasive approaches still have to go.</li> <li><strong><a href="https://arxiv.org/abs/2203.05482">Model soups: averaging weights of multiple fine-tuned models improves accuracy without increasing inference time</a></strong> (Wortsman et al., 2022) — the origin of the per-subject LoRA weight-averaging strategy used here.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="brain-computer-interface"/><category term="meg"/><category term="brain-to-text"/><category term="ctc"/><category term="llm"/><category term="lora"/><category term="neuroscience"/><summary type="html"><![CDATA[Meta AI's Brain2Qwerty v2 collects 90 hours and 2,724 unique sentences of MEG from nine people, then chains a CTC encoder, a word aligner, and a LoRA-tuned LLM to decode natural sentences from non-invasive brain signals at 39% WER]]></summary></entry><entry xml:lang="ko"><title type="html">[논문 리뷰] Agentic Method for Deterministic Validation of Legacy Code Migration</title><link href="https://baba9811.github.io/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/" rel="alternate" type="text/html" title="[논문 리뷰] Agentic Method for Deterministic Validation of Legacy Code Migration"/><published>2026-08-21T05:00:00+00:00</published><updated>2026-08-21T05:00:00+00:00</updated><id>https://baba9811.github.io/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code</id><content type="html" xml:base="https://baba9811.github.io/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/en/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/" class="btn btn-sm btn-outline-secondary">🇺🇸 Read in English</a> </div> <h2 id="메타정보">메타정보</h2> <table> <thead> <tr> <th>항목</th> <th>내용</th> </tr> </thead> <tbody> <tr> <td>저자</td> <td>Andras Ferenczi et al. (저자 5명, American Express)</td> </tr> <tr> <td>학회</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv 또는 DOI</td> <td><a href="https://arxiv.org/abs/2607.28271">2607.28271</a></td> </tr> <tr> <td>데이터</td> <td>AWS CardDemo CBACT01C (430 lines) · CBSTM03A (924 lines) · 사내 production-like 배치 프로그램 (4,114 lines)</td> </tr> <tr> <td><span style="white-space: nowrap">리뷰 일자</span></td> <td>2026-08-21</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>COBOL 을 Java 로 1:1 이관할 때 진짜 어려운 건 번역이 아니라 <strong>검증</strong>이다. 실제 테스트 데이터는 없고, 수십 년간 쌓인 “broken-as-usual” 동작까지 사양의 일부가 돼 있다. 이 논문은 그 검증을 자동화하는 Locksmith Loop 를 제안한다.</li> <li>루프는 두 국면을 번갈아 돈다. <strong>Witness Search</strong> 는 여섯 개 탐색 알고리즘 (pairwise · 3-way · LHS · ART · MAP-Elites · UCB1) 으로 입력·목(mock) 공간을 훑어 도달 가능한 분기를 다 연다. 더 열리지 않는 지점 (plateau) 에 닿으면 <strong>Mutation</strong> 이 나서 Locked Paragraph 하나를 강제로 연다. 열린 순간 다시 Witness Search 로 돌아와 새 영역 안에서 재귀적으로 훑는다.</li> <li>결정적인 설계는 mutation 을 COBOL 목과 생성된 Java 양쪽에 <strong>대칭으로</strong> 적용한다는 것이다. 그래서 커버리지를 늘리는 코드 변형이 동시에 parity 검사의 대상이 된다. 판정은 LLM 이 아니라 결정론적 <strong>Parity Gate</strong> 가 paragraphs_hit · stub_log · terminal_state 세 축으로 내린다.</li> <li>LLM (Authoring Layer) 은 마이그레이션 코드를 직접 쓰지 않는다. 막힌 지점에서 Mutation Skill 을 제안할 뿐이고, 채택 여부는 커버리지 증가와 Parity Gate 통과라는 두 결정론적 조건이 정한다. 생성과 판정의 분리가 이 논문의 뼈대다.</li> <li>세 프로그램 결과. CBACT01C (430 lines) 는 paragraph 16/16, transition 28/28, branch 60/62 (96.8%). CBSTM03A (924 lines) 는 paragraph 24/25 (96.0%), transition 37/38 (97.4%), branch 74.0%, parity 38/38 PASS. 사내 production-like 프로그램 (4,114 lines) 은 paragraph 135/142 (95.1%), transition 101/146 (69.2%), branch 91.90% (397/432), 166/166 PASS · 0 FAIL · 0 ERROR. 커버리지를 국면별로 분해해 보고한 뒤의 두 프로그램에서는 Mutation 이 연 전이가 Witness Search 가 연 것과 맞먹거나 더 많다.</li> </ul> <h2 id="소개-introduction">소개 (Introduction)</h2> <p>메인프레임 위에서 도는 COBOL 은 아직도 은행·카드·보험의 코어에 남아 있다. 수십 년치 업무 규칙이 코드에 눌러 담겨 있고, 그중 상당수는 문서로 존재하지 않는다. LLM 기반 코딩 에이전트가 등장하면서 이 코드를 읽고 Java 로 옮기는 일 자체는 급격히 쉬워졌다. 문제는 그다음이다. 옮긴 결과가 원본과 같은 동작을 하는지를 어떻게 <em>증명</em>할 것인가.</p> <p>현장의 실무는 대개 병행 운용이다. 레거시와 신규를 동시에 돌리며 출력이 갈리는지 지켜보다가, 충분한 확신이 쌓이면 트래픽을 넘긴다. 이 방식의 한계는 명확하다. 실제 트래픽이 밟는 경로는 전체 경로의 일부일 뿐이고, 나머지 긴 꼬리는 컷오버 이후에야 처음 실행된다. 게다가 레거시 시스템에는 원래 제품 정의와 어긋나지만 오랜 시간 동안 굳어져 사실상 사양이 된 동작 — 저자들이 “broken-as-usual” 이라 부르는 것 — 이 존재한다. lift-and-shift 형 현대화에서는 이 버그까지 정확히 재현해야 한다. 즉 검증의 목표는 <em>정확성</em>이 아니라 <em>호환성</em>이다.</p> <p>American Express 팀이 내놓은 답은 이렇게 요약된다. 커버리지를 못 올리는 이유가 입력을 잘 못 고르기 때문이 아니라 <strong>하네스가 표현할 수 있는 입력 공간 바깥에 답이 있기 때문</strong>이라면, 입력을 더 뒤지지 말고 하네스의 경계를 넓혀라. 그리고 경계를 넓히는 변형을 레거시와 신규 양쪽에 똑같이 가하면, 그 변형 자체가 parity 검사의 대상이 된다. 이 두 문장이 Locksmith Loop 의 전부이고, 나머지는 그것을 감사 가능하고 재현 가능하게 만들기 위한 공학이다. 에이전트가 코드를 쓰는 시대에 “에이전트의 출력을 무엇으로 판정할 것인가” 라는 질문의 구체적인 한 가지 답이라는 점에서, COBOL 을 만질 일이 없는 사람에게도 읽을 값어치가 있다.</p> <h2 id="핵심-기여-key-contributions">핵심 기여 (Key Contributions)</h2> <ul> <li><strong>Locksmith Loop — 재귀적 하네스 확장을 검증 메커니즘의 중심에 놓은 방법론.</strong> 입력 공간 탐색 (Witness Search) 과 parity 보존 코드 변형 (Mutation) 을 번갈아 돌리되, 변형이 성공하면 새로 열린 영역 안에서 탐색을 재개한다. 저자들이 아는 한, 레거시-현대 마이그레이션 검증에서 재귀적 하네스 확장을 핵심 장치로 쓴 선행 연구는 없다.</li> <li><strong>Parity Gate — 에이전트 출력에 대한 결정론적 오라클.</strong> paragraphs_hit (진입한 paragraph 집합), stub_log (소비한 외부 연산의 순서 있는 시퀀스), terminal_state (실행 후 관측 가능한 변수 값) 세 축으로 COBOL 목과 생성 Java 의 behavioral fingerprint 를 비교한다. 마지막 라운드에 한 번 도는 검사가 아니라 <em>모든</em> mutation 직후에 도는 상시 게이트다.</li> <li><strong>teacher-student 분리.</strong> student 는 마이그레이션·탐색·변형·parity 검사를 수행하는 결정론적 도구 집합이고, teacher 는 막힌 지점에서만 호출되는 감독 AI 에이전트 (Authoring Layer) 다. Authoring Layer 는 이관 코드를 직접 쓰지 않고 Mutation Skill 을 고르거나 새로 만들 뿐이다. TestGen-LLM 계열의 “LLM 이 제안하고 결정론적 필터가 판정한다” 패턴을 마이그레이션 검증에 이식한 형태다.</li> <li><strong>Mutation Skill Catalog — 성공한 변형의 재사용.</strong> 성공한 변형을 AI 스킬로 포착해 카탈로그에 넣고 이후 라운드에서 재사용한다. 코드를 직접 고치지 않고 스킬 형태로 유지함으로써 원본 프로그램 로직과 커버리지 확장용 변경을 분리한다.</li> <li><strong>4,114 라인 production-shape 프로그램에서의 무인 실행 보고.</strong> 고객 데이터 없이 하네스 생성 입력과 목만으로 branch 91.90%, 166/166 parity PASS 를 사람 개입 없이 달성했다는 보고. 사내 프로그램이라 재현은 불가능하지만, 이 규모에서 무인 실행 결과를 수치와 함께 공개한 사례 자체가 드물다.</li> </ul> <h2 id="관련-연구--배경-지식">관련 연구 / 배경 지식</h2> <h3 id="이-논문을-읽기-위한-최소-배경">이 논문을 읽기 위한 최소 배경</h3> <p>COBOL 프로그램은 DIVISION → SECTION → <strong>paragraph</strong> 계층으로 구성된다. paragraph 는 레이블이 붙은 문장 묶음이고 사실상 함수에 해당한다. 제어 흐름은 <code class="language-plaintext highlighter-rouge">PERFORM</code> (호출), <code class="language-plaintext highlighter-rouge">GO TO</code> (점프), <code class="language-plaintext highlighter-rouge">EVALUATE</code> (switch), 그리고 악명 높은 <code class="language-plaintext highlighter-rouge">ALTER</code> (GO TO 대상의 런타임 변경) 로 흐른다. 이 논문의 Migrator 는 SECTION 하나를 Java 클래스 하나로, paragraph 하나를 메서드 하나로 사상한다.</p> <p>커버리지 지표가 세 종류 나오는데 구분해서 읽어야 한다. <strong>paragraph coverage (P)</strong> 는 AST 상의 전체 paragraph 중 한 번이라도 진입한 비율, <strong>transition (edge) coverage (T)</strong> 는 정적으로 존재하는 paragraph→paragraph 제어 흐름 전이 중 한 번이라도 밟은 비율, <strong>branch coverage</strong> 는 계측된 분기 결과 (branch probe) 중 한 번이라도 통과한 비율이다. 뒤로 갈수록 엄격하고, 뒤에서 보겠지만 세 수치가 같은 프로그램에서도 꽤 크게 벌어진다.</p> <h3 id="네-갈래-선행-연구">네 갈래 선행 연구</h3> <p>논문은 자신의 위치를 네 영역의 교집합으로 규정한다.</p> <p><strong>1. 테스트 스위트 증폭과 하네스 testability.</strong> DSpot 처럼 기존 개발자 작성 테스트를 반복적으로 증강해 merge 가능한 패치로 되먹이는 계열, EvoSuite / EvoSuiteAmp 처럼 기존 테스트를 시드로 삼아 탐색 기반으로 개선하는 계열이 있다. Locksmith 도 반복 개선이라는 자세는 같지만, 변환 대상이 다르다. 테스트를 고치는 게 아니라 <strong>하네스 인터페이스 자체를 확장</strong>해서, 하네스가 표현할 수 있는 입력의 종류를 늘리고 그 넓어진 공간에서 Witness Search 를 다시 돌린다. testability transformation 계보에 인접하되, 프로그램을 테스트하기 쉽게 다시 쓰는 대신 controllability 경계를 반복적으로 밀어낸다.</p> <p><strong>2. 탐색 기반 입력 생성, 퍼징, 심볼릭 실행.</strong> combinatorial interaction testing, adaptive random testing, MIO, quality-diversity 계열의 MAP-Elites, 그리고 그 bandit 확장인 Monte Carlo Elites 가 Witness Search 의 재료다. OSS-Fuzz 실증 연구가 보여주듯 지속 퍼징의 진행은 느린 성장과 급격한 폭발이 번갈아 나오는 비선형 패턴을 띤다. Locksmith 는 초기엔 이 패턴을 그대로 따르다가, 여러 알고리즘이 같은 분기 수의 ±2–3 안으로 수렴하는 순간을 plateau 로 식별하고 방향을 튼다. 예산을 더 붓는 대신 <em>하네스 경계를 변형</em>해 다른 각도에서 탐색을 잇는다. 코드 변형으로 hard input check 를 뚫는다는 점에서 T-Fuzz 와 발상이 닮았지만, T-Fuzz 는 버그 발견이 목적이고 Locksmith 는 parity 게이트가 걸린 마이그레이션 검증이 목적이다.</p> <p><strong>3. differential / metamorphic 오라클.</strong> Mokav 나 DiffSpec 같은 LLM 보조 differential testing 은 같은 사양의 두 구현을 놓고 출력 차이를 버그로 신고한다. 정확한 출력을 알 수 없을 때는 metamorphic testing 이 입력과 출력 사이의 관계를 검사한다. Locksmith 의 Parity Gate 도 후보 입력을 판정하는 differential 오라클이지만, 동시에 <em>변형을 위한 가드레일</em>로도 쓰인다는 점이 다르다. 하네스 변형이 parity 를 유지하면서 도달 가능한 입력 공간을 넓히는지를 같은 게이트로 검사한다.</p> <p><strong>4. 프로그램 수리와 에이전틱 LLM 소프트웨어 공학.</strong> RepairAgent 는 LLM 도구 사용을 조율하고 프로그램 피드백으로 수정을 검증한다. Meta 의 TestGen-LLM 은 LLM 이 만든 테스트를 <em>결정론적 필터가 빌드·통과·커버리지 향상을 확인한 경우에만</em> 배포한다. TestPilot 은 실패 시 재프롬프트하고, Mut4All 은 버그 리포트로부터 컴파일러 퍼징용 mutator 를 합성한다. Locksmith 는 이 구조를 harness mutation 에 이식했다 — LLM 이 편집을 제안하고, 결정론적 analyzer / runner / parity 오라클이 어떤 편집이 살아남을지 정한다.</p> <h3 id="메인프레임-현대화-쪽-이웃">메인프레임 현대화 쪽 이웃</h3> <p>XMainframe 은 메인프레임 도메인에 특화한 LLM 이고, COBOL-coder 는 COBOL 코드 생성·번역에 도메인 적응한 모델이다. 그 밖에 high-resource Java refinement 를 지렛대 삼은 저자원 COBOL 번역, 프로그램 분석으로 LLM 을 보강한 엔터프라이즈 규모 COBOL-to-Java 파이프라인 연구가 있다. 가장 가까운 비교 대상은 Hans et al. 및 Kumar et al. 의 자동 검증 작업이다. 심볼릭 실행으로 COBOL 단위 테스트를 생성하고, 목을 곁들여 JUnit 으로 옮긴 뒤 의미 동치를 검사한다. 같은 문제를 겨냥하지만 배치가 다르다. 그쪽은 사후 검사 (post-hoc check) 이고, Locksmith 는 탐색-변형 루프 <em>안에</em> 게이트를 심는다.</p> <h3 id="범위와-전제">범위와 전제</h3> <p>논문이 스스로 그은 경계도 분명하다. 대상은 COBOL → Java 의 1:1 이관이고, 성공 기준은 시스템 개편이 아니라 <strong>같은 입력 아래 parity 를 검증하면서 branch coverage 를 올리는 것</strong>이다. 하네스는 레거시 의존성을 의견 있는 방식으로 치환한다 — 레거시 RDBMS 는 PostgreSQL 로, MQ 는 RabbitMQ 로. 전략은 두 단계다. 먼저 parity 를 유지한 채 이관하고, 새 스택에서 확신이 선 뒤에 리팩터링한다.</p> <h2 id="방법--아키텍처-상세">방법 / 아키텍처 상세</h2> <h3 id="locksmith-은유">Locksmith 은유</h3> <p>논문 전체가 자물쇠공 비유 위에서 설명된다. 분기 하나하나가 <em>문</em>이고, 그 분기를 밟기 위해 필요한 입력과 목 응답이 <em>열쇠</em>다. 어떤 문은 쉽게 열리지만 어떤 문은 드릴이 필요하다 — 즉 막힌 실행 경로를 노출시키는 parity 보존 변형이 있어야 한다. 여러 탐색 알고리즘을 도달 가능한 분기 전체에 돌려 보면, 어느 문이 쉽게 열리고 어느 문이 반복 시도 후에도 잠긴 채인지 판별할 수 있다. 남은 분기는 현재 하네스 상태에서 구조적으로 도달 불가능한 것일 수 있다. 이때 드릴로 새 영역을 뚫고, 문이 열리면 다시 자물쇠 따기 (Witness Search) 로 돌아가 새로 도달 가능해진 경로를 훑는다. 이 과정을 재귀적으로 적용한다.</p> <p>용어 다섯 개만 정리하면 나머지는 따라온다.</p> <ul> <li><strong>Locksmith Loop</strong>: 방법론 전체</li> <li><strong>Witness Search</strong>: 목 백엔드 응답과 환경 상태를 포함한 프로그램 입력 공간을 여러 알고리즘으로 탐색하는 국면</li> <li><strong>Locked Paragraph</strong>: Witness Search 만으로는 도달할 수 없는 COBOL paragraph</li> <li><strong>Mutation</strong>: parity 를 보존하는 코드 변형을 COBOL 과 Java 양쪽에 가하는 국면</li> <li><strong>Parity Gate</strong>: 같은 witness 입력으로 두 타깃을 돌려 종료 상태 불일치를 보고하는 결정론적 오라클</li> </ul> <h3 id="마이그레이션-하네스-구성">마이그레이션 하네스 구성</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig1-harness-setup-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig1-harness-setup-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig1-harness-setup-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig1-harness-setup.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: 마이그레이션 및 하네스 구성. 연파랑은 student 컴포넌트, 연노랑은 Authoring Layer 컴포넌트다. COBOL source 한 갈래는 Mock Generator 를 거쳐 실행 가능한 COBOL mock 이 되고, 다른 갈래는 Migrator 를 거쳐 Java target 이 된다. Runner / Parity Gate 가 둘을 같은 입력으로 몰아 동작을 비교한다.</figcaption> </figure> <p>COBOL 소스는 두 갈래로 흐른다. 한쪽은 사내 결정론적 <strong>Migrator</strong> 를 통과해 Java 타깃이 되고, 다른 한쪽은 결정론적 <strong>COBOL Mock Generator</strong> 를 통과해 실행 가능한 COBOL 목이 된다. 두 산출물은 같은 테스트 하네스가 몰고 다니며, 하네스는 behavioral fingerprint 를 기록하고 Parity Gate 를 집행한다.</p> <p>전체 구조는 teacher-student 패턴이다. <em>student</em> 는 마이그레이션 · Witness Search · Mutation · parity 검사 파이프라인을 수행하는 결정론적 도구 집합이고, <em>teacher</em> 는 Authoring Layer 다. 여기가 핵심인데, Authoring Layer 는 이관 프로그램을 직접 쓰지 않는다. 막힌 실행 경로를 열기 위해 기존 스킬을 고르거나 새 스킬을 제안할 뿐이고, 제안의 옳고 그름은 Parity Gate 가 정한다. 컴파일 검사와 동작 동치 검사가 각 제안을 수락하거나 기각한다. parity 실패가 나면 Authoring Layer 가 개입하고, 그 변형이 게이트를 통과하면 루프가 재개된다. 생성과 결정론적 판정의 이 분리가 루프의 견고함을 떠받친다.</p> <h3 id="파이프라인-개요">파이프라인 개요</h3> <p>파이프라인은 소스 수준 변환에서 시작한다. 파일 I/O, <code class="language-plaintext highlighter-rouge">CALL</code>, <code class="language-plaintext highlighter-rouge">EXEC SQL</code>, <code class="language-plaintext highlighter-rouge">EXEC CICS</code> 같은 외부 연산을 목으로 대체해 실행 가능한 <em>mock COBOL</em> 프로그램을 만든다. 목의 뒷단은 COBOL index file 이거나 PostgreSQL 같은 관계형 DB 다. 컴파일된 목 바이너리가 루프 내내 쓰이는 branch coverage 측정치를 공급한다.</p> <p>그다음 외부 파서가 레거시 프로그램의 AST 를 만들고, 이것이 결정론적 Migrator 의 입력이 된다. Java 코드 생성기는 SECTION 당 클래스 하나, paragraph 당 메서드 하나를 뽑고, COBOL 제어 흐름 (<code class="language-plaintext highlighter-rouge">PERFORM</code>, <code class="language-plaintext highlighter-rouge">GO TO</code>, <code class="language-plaintext highlighter-rouge">ALTER</code>, <code class="language-plaintext highlighter-rouge">EVALUATE</code>) 을 등가의 Java 제어 흐름으로 사상한다.</p> <p>테스트 케이스 하나는 <strong>input-state</strong> 와 <strong>stub-state</strong> 의 쌍이다. input-state 는 실행 중 적용되는 변수 할당이고, stub-state 는 목 처리된 외부 연산이 돌려줄 레코드다. 실행이 끝나면 시스템은 <strong>behavioral fingerprint</strong> 를 기록한다 — 진입한 paragraph, 밟은 분기, stub 응답 로그, 종료 시점의 관측 가능한 상태. 이 fingerprint 가 커버리지 추적과 parity 비교의 단위가 된다.</p> <h3 id="네-컴포넌트">네 컴포넌트</h3> <ul> <li><strong>Deterministic Migrator</strong>: COBOL 소스를 Java 타깃으로 번역한다.</li> <li><strong>Deterministic Analyzer</strong>: AST 와 살아 있는 목을 살펴 프로그램 구조로부터 게이트를 식별한다.</li> <li><strong>Deterministic Runner</strong>: 바이너리를 컴파일하고, 테스트 케이스를 실행하고, branch coverage 를 측정하고, 세 동치 축을 따라 Parity Gate 를 적용한다. 코드 변형은 branch coverage 를 <em>늘릴 때만</em> 유지된다.</li> <li><strong>Agentic Authoring</strong>: 결정론적 analyzer 가 막힌 실행 경로에 닿았을 때 호출돼 새 스킬을 합성한다. Parity Gate 가 divergence 를 보고하면 Migrator 의 Java 코드 생성기 자체를 고치기도 한다.</li> </ul> <h3 id="여섯-알고리즘의-witness-search">여섯 알고리즘의 Witness Search</h3> <p>Witness Search 스윕은 현재 반복의 COBOL 목 바이너리에 여섯 개 독립 알고리즘을 돌린다. 모두 같은 baseline 커버리지에서 출발한다. 하나의 시나리오는 입력 레코드, 초기 working-storage 값, 목 처리된 외부 <code class="language-plaintext highlighter-rouge">CALL</code> 의 file-status 값과 리턴 코드로 이뤄진다. 하네스 카탈로그가 시나리오별 허용 선택지를 추적하고, 여섯 알고리즘은 이 조합 공간을 <em>어떻게 훑느냐</em>만 다르다.</p> <ul> <li><strong>Pairwise interaction testing.</strong> 각 필드가 $|D_i|$ 개의 값 선택지를 갖는 $n$ 개 시나리오 컴포넌트가 있을 때, 가능한 모든 값 쌍 $(v_i \in D_i,\ v_j \in D_j)$, $i &lt; j$ 를 덮는 작은 테스트 집합을 만든다. 최적 크기는 $O(|D|^2 \log n)$. COBOL 분기 상당수가 상관된 두 필드에 걸린 복합 <code class="language-plaintext highlighter-rouge">IF</code> 나 <code class="language-plaintext highlighter-rouge">EVALUATE WHEN</code> 으로 게이팅돼 있어서 (status code × record type, account kind × balance sign) pairwise-covering 집합만으로도 두-필드 조합 하나하나가 최소 한 번씩 노출된다.</li> <li><strong>Three-way interaction.</strong> pairwise 를 삼중항으로 확장한다. status × record type × end-of-file flag 로 게이팅된 tail-handling paragraph 처럼, 세 값이 동시에 맞아야 열리는 소수의 분기를 잡는다.</li> <li><strong>Latin hypercube sampling (LHS).</strong> 레코드 수, 파일 길이, 금액처럼 준연속적인 컴포넌트에 쓴다. 각 도메인을 $N$ 개 구간으로 나눠 구간당 한 값을 뽑되, 컴포넌트 간 구간을 정렬해 거리 기반 다양성을 최대화한다. 특정 영역에 몰리지 않고 전 범위에 걸쳐 표본을 고르게 펼친다.</li> <li><strong>Adaptive random testing (ART).</strong> 이미 실행한 입력들과의 최소 거리를 최대화하는 입력을 다음으로 고른다. 프로그램 구조에 대한 사전 지식이 없을 때 특히 쓸모 있다.</li> <li><strong>MAP-Elites.</strong> quality-diversity 계열. behavioral descriptor 셀 격자를 유지하며 각 셀에 그 셀로 사상되는 최고 fitness 입력을 담는다. fitness 는 새로 덮은 분기 수다. COBOL 커버리지 프로파일은 소수의 실행 <em>모양</em>으로 뭉치는 경향이 있는데 (깔끔한 end-of-file 경로, 중간 절단, status-error 조기 종료, multi-record-type 배치), MAP-Elites 는 모양마다 좋은 테스트 케이스를 하나씩 남겨 희귀 분기 노출을 돕는다.</li> <li><strong>UCB1 bandit.</strong> 각 값 선택지를 bandit arm 으로 본다. 매 스텝에서 다음을 최대화하는 arm 을 고른다.</li> </ul> \[\begin{aligned} a^{\star} = \arg\max_{a} \left( \bar{x}_a + c\sqrt{\frac{\ln t}{n_a}} \right) \end{aligned}\] <p>여기서 $\bar{x}_a$ 는 새로 발견한 분기로 정의되는 경험적 평균 보상, $n_a$ 는 arm $a$ 가 선택된 횟수, $c$ 는 탐색 상수다. 위 조합 기반 방법들과 달리 UCB1 은 조합 폭발이 없다. 대신 한 번의 실행 <em>안에서</em> 어떤 값이 새 분기를 잘 여는지를 학습한다. COBOL 목에서는 status code 나 record type 처럼 많은 분기를 게이팅하는 정보량 큰 컴포넌트를 선호하게 된다.</p> <p>한 번의 Witness Search 스윕 출력은 여섯 알고리즘이 발견한 분기의 합집합과 테스트 케이스 집합이다. 다음 스윕은 가장 좋은 집합에서 이어 가고, <strong>두 번 연속 스윕이 새 분기를 하나도 못 내면</strong> 그 지점을 Witness Search plateau 라 부른다. mutation 이 하네스를 확장하고 나면 여섯 알고리즘 스윕을 처음부터 다시 돌린다 — 새로 도달 가능해진 영역은 다른 탐색 편향을 선호할 수 있기 때문이다. 저자들은 이 여섯이 실증적 실험으로 고른 조합이며 모든 마이그레이션에 최적이라는 보장은 없고, 고정된 처방이 아니라 대표적 집합으로 봐 달라고 명시한다.</p> <h3 id="mutation-스킬을-통한-parity-보존-하네스-변형">Mutation: 스킬을 통한 parity 보존 하네스 변형</h3> <p>고전적 mutation testing 은 오류 처리를 검증하려고 애플리케이션에 결함을 주입한다. Locksmith 의 mutation 은 목적이 정반대다. 새 실행 경로를 발견해 <strong>강제로 열어</strong> COBOL 과 Java 사이의 parity 를 확인하는 것이고, 그래서 두 코드베이스를 나란히 수정한다. 목표는 출력뿐 아니라 코드 트레이스까지 일치시키는 것이다.</p> <p>결정론적 analyzer 가 후보 게이트를 짚고, Authoring Layer 가 그 게이트를 만족시키는 <strong>Mutation Skill</strong> 을 생성한다. 스킬은 새 dispatcher 경로를 추가하거나, 프로그램이 원래 외부에서 읽었을 값을 side channel (하네스 수준 stub hook) 로 노출시키거나, 도달하기 어려운 paragraph 의 실행을 강제한다. 스킬을 라운드 간에 <em>지속</em>시키고 직접 코드 수정을 피하는 이유는 원본 프로그램 로직과 커버리지 확장용 변경 사이의 경계를 유지하기 위해서다.</p> <p>Mutation 국면이 끝나면 이전에 수락된 테스트 케이스를 다시 실행하고, 변형은 이후 반복을 위해 남긴다. paragraph 하나가 여러 독립 조건으로 막혀 있을 수 있으므로, 프레임워크는 식별된 게이트를 하나씩 평가해 추가 커버리지를 내는 변형만 남긴다.</p> <p>스킬은 계층적 의존성을 가질 수 있고 필요한 순서대로 적용된다. 실무에서는 두 종류면 대부분 충분했다고 한다.</p> <ul> <li><strong>dispatcher-arm 스킬</strong>: 원래 외부에서 읽는 값을 side channel 로 직접 공급할 수 있게 하네스를 확장한다. 실행이 통제하기 어려운 값에 좌우되는 status-field 주도 로직에 특히 효과적이다.</li> <li><strong>call-injection 스킬</strong>: 메인 프로그램 흐름의 알려진 지점에서 타깃 paragraph 실행을 강제한다. cleanup 처리, end-of-file 처리처럼 흔치 않은 경로에서만 도는 로직을 실제로 돌려 볼 때 쓴다.</li> </ul> <p>스킬 종류와 무관하게 같은 변경이 COBOL 구현과 Java 구현 양쪽에 적용되고, parity 는 밟은 실행 경로 · 수행한 외부 연산 · 최종 관측 상태를 비교해 검증한다.</p> <p>논문이 실험 절에서 구체적으로 정의하는 변형이 <strong>force-set mutation</strong> 이다. 선택한 paragraph 진입 시점에, 외부 연산 (파일 읽기, DB fetch, 메시지 큐 수신, 하위 프로그램 호출) 이 목에서 돌려줬을 값을 선택한 값으로 덮어쓰되, COBOL 목과 그 생성 Java 타깃에 대칭으로 적용하는 parity 보존 변형이다.</p> <h3 id="analyzer-가-게이트를-고르는-방식">Analyzer 가 게이트를 고르는 방식</h3> <p>Analyzer 는 정적 AST 리더다. 타깃 paragraph 마다 그 실행을 막는 제어 흐름 조건을 살펴 만족시켜야 할 게이트를 식별한다. 게이트가 특정 외부 값에 의존하면 필요한 값을 결정해 side channel 에 공급하고, 실행 중 그 값이 고정되게 한다.</p> <p>여기 설계 판단이 하나 들어 있다. Analyzer 는 <strong>기존 프로그램 흐름을 통해 동작하는 해법 (dispatcher 기반 변형) 을 항상 선호</strong>한다. 그래야 paragraph 가 자연스럽게 도달되기 때문이다. 적당한 dispatcher 기반 접근이 없을 때만 call-injection 스킬을 권한다. 이 우선순위 덕에 AST 에 표현된 모든 paragraph 가 최소한 하나의 평가 가능한 후보 변형을 갖는다. Analyzer 는 의도적으로 보수적이어서, 통제 가능한 변수와 알려진 값 집합으로 명확히 설명되는 변형만 권한다. 모든 권고가 이해 가능하고, 감사 가능하고, 적용 전에 검증하기 쉽게 유지하기 위해서다.</p> <p>한 Locked Paragraph 안의 <strong>형제 게이트</strong> 처리도 명시돼 있다. 타깃 paragraph 가 단일 조건으로만 막혀 있는 건 아니다. 중첩된 <code class="language-plaintext highlighter-rouge">IF</code> 조건, 감싸는 <code class="language-plaintext highlighter-rouge">PERFORM</code> 경계, 특정 <code class="language-plaintext highlighter-rouge">EVALUATE</code> 분기처럼 여러 제어 흐름 결정이 동시에 만족돼야 하는 경우가 많다. Analyzer 는 그런 게이트를 전부 식별하고 각각에 대한 후보 변형을 생성한다. 첫 성공에서 멈추지 않고 식별된 모든 게이트를 평가하는데, 각 게이트가 추가 실행 경로를 열 가능성이 있기 때문이다. 새 커버리지를 내는 변형은 active baseline 에 편입되고 이후 변형은 그 확장된 상태에서 이어진다. 추가 커버리지가 없으면 되돌린다. 최소 하나의 변형이 커버리지를 개선하면 그 paragraph 는 성공적으로 열린 것으로 본다.</p> <h3 id="재귀와-종료">재귀와 종료</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig2-locksmith-loop-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig2-locksmith-loop-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig2-locksmith-loop-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig2-locksmith-loop.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: Locksmith Loop 전체 제어 흐름. Witness Search 가 두 라운드 연속 새 분기를 못 내면 plateau 로 보고, Locked Paragraph 를 uncovered-branch 수로 정렬한 뒤 하나를 code mutation 으로 연다. Post-Mutation Witness Search (UCB1) 로 커버리지 이득을 확인하고 Parity Gate 가 COBOL ≡ Java 를 판정한다. 성공한 변형은 새로 열린 영역에서의 전체 스윕으로 제어를 되돌리고 (recurse: search from inside), 이득 없는 변형은 되돌려 실패로 표시한다.</figcaption> </figure> <p>루프는 (1) Witness Search 스윕과 (2) Mutation 스텝을 번갈아 돈다. 변형이 유지되려면 두 조건을 모두 만족해야 한다 — <strong>커버리지를 늘려야 하고, Parity Gate 를 통과해야 한다</strong>. 둘 다면 하네스 변형을 유지하고 다음 Witness Search 스윕으로 넘어가는데, 이 스윕이 또 다른 Locked Paragraph 를 노출시킬 수 있다. 새로 나온 Locked Paragraph 도 같은 방식으로 정렬돼 변형된다. 둘 중 하나라도 실패하면 변형을 되돌리고 시도를 기록한다.</p> <p>종료 보장은 단순하다. <strong>이미 시도한 Locked Paragraph 는 다시 시도하지 않는다.</strong> 따라서 모든 재귀 스텝은 새 분기를 여는 parity 보존 변형을 얻거나, 아니면 Locked Paragraph 하나를 후보 목록에서 영구히 제거한다. 모든 Locked Paragraph 를 시도하고 나면 마지막 Witness Search 스윕으로 남은 분기를 회수한다.</p> <p>Locked Paragraph 정렬 정책의 기본값은 <strong>bang × feasibility</strong> 다. uncovered branch 수와, 조건 변수 중 이미 하네스로 라우팅 가능한 비율의 합으로 점수를 매겨 “값어치 있으면서 실행 가능한” 것을 우대한다. 다만 실제 실험에서는 uncovered branch 수만 보는 <strong>greedy</strong> 정책을 썼다. 스킬 조회 (SKILLFOR) 는 카탈로그 룩업이지만 카탈로그가 불완전할 수 있어서, 대응 스킬이 없으면 Authoring Layer 가 게이트 분석으로부터 새 스킬을 만들거나, 타깃 paragraph · uncovered branch · 분기 조건 · active call stack 을 담은 구조화된 <code class="language-plaintext highlighter-rouge">needs_new_skill</code> 레코드를 생성한다.</p> <h2 id="최적화-목표와-수용-기준">최적화 목표와 수용 기준</h2> <p>학습 손실 대신 이 논문의 목적 함수 역할을 하는 건 <strong>수용 조건 두 개</strong>다. 변형 $m$ 이 유지되는 조건은</p> \[\begin{aligned} \text{keep}(m) \iff \; &amp; \text{coverage}(\text{after } m) &gt; \text{coverage}(\text{before } m) \\ &amp; \wedge \; \text{ParityGate}(\text{COBOL}_m, \text{Java}_m) = \text{PASS} \end{aligned}\] <p>이고, 둘 중 하나라도 깨지면 되돌린다. 커버리지 조건만 있으면 하네스를 아무렇게나 뜯어 숫자를 올릴 수 있고, parity 조건만 있으면 아무것도 안 하는 변형이 항상 통과한다. 두 조건이 서로를 묶는다.</p> <h3 id="parity-gate-의-세-동치-축">Parity Gate 의 세 동치 축</h3> <p>COBOL 쪽이 수락한 모든 테스트 케이스 (input-state + stub-outcomes) 는 생성된 Java 타깃으로도 몰아지고, 두 behavioral fingerprint 를 비교한다. 게이트는 세 축으로 판정하며, 축은 스킬별로 parity contract 에 선언된다.</p> <table> <thead> <tr> <th>축</th> <th>비교 방식</th> <th>잡는 결함</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">paragraphs_hit</code></td> <td>진입한 paragraph 의 <strong>집합</strong> 비교</td> <td>누락된 paragraph 순회, 조기 종료</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">stub_log</code></td> <td>소비한 외부 연산 시퀀스의 <strong>순서 있는</strong> 비교 (공백 정규화 후 값 매칭)</td> <td>잘못된 dispatch 순서, 누락/중복 외부 호출</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">terminal_state</code></td> <td>실행 후 관측 가능한 변수 값의 <strong>점별</strong> 비교 (런타임 내부 bookkeeping 제외)</td> <td>잘못 세팅된 변수, 값 정규화 오류</td> </tr> </tbody> </table> <p>이 게이트는 ground-truth 사양 대신 <strong>compatibility 관계</strong>를 받아들이는 differential 오라클이다. 그리고 모든 mutation 이 양쪽에 동시에 구현되기 때문에, parity 는 마지막 라운드가 아니라 <em>모든 break 직후에 연속적으로</em> 검사된다.</p> <p>divergence 는 parity intervention 채널에 구조화된 레코드로 방출된다 — divergence 종류, 사람이 읽을 설명, 기계가 읽을 diff 레코드. 이 레코드가 선택적 repair 스텝의 입력 계약이 된다. 루프는 기본적으로 divergence 를 기록하고 계속 진행하며, 그렇게 설정한 경우에만 멈춘다. 저자들의 실험에서는 모든 mutation 계층에 걸쳐 수락된 모든 테스트 케이스에서 게이트가 유지됐다.</p> <p>Authoring Layer 개입 지점도 같은 형태다. analyzer 나 runner 가 스스로 해결할 수 없는 결정 지점에 닿으면 정해진 개입 지점에 구조화된 레코드를 쓰고 계속 간다. 그 레코드는 사람 운영자나 AI 에이전트가 비동기로 소비할 수 있다 — 루프가 사람을 기다리며 멈추지 않는다는 뜻이다.</p> <h2 id="대상-프로그램과-실험-셋업">대상 프로그램과 실험 셋업</h2> <p>세 개의 COBOL 코드베이스에 Locksmith Loop 를 돌렸다.</p> <table> <thead> <tr> <th>프로그램</th> <th>소스 라인</th> <th>paragraph</th> <th>정적 전이 (edge)</th> <th>branch probe</th> <th>출처</th> </tr> </thead> <tbody> <tr> <td>CBACT01C</td> <td>430</td> <td>16</td> <td>28</td> <td>62</td> <td>AWS CardDemo (오픈소스)</td> </tr> <tr> <td>CBSTM03A</td> <td>924</td> <td>25</td> <td>38</td> <td>146</td> <td>AWS CardDemo (오픈소스)</td> </tr> <tr> <td>production-like 배치</td> <td>4,114</td> <td>142</td> <td>146</td> <td>432 (정적 집계)</td> <td>사내</td> </tr> </tbody> </table> <p>production-grade 프로그램은 <strong>고객 데이터 없이</strong> 하네스가 생성한 테스트 입력과 목 처리된 외부 응답만으로 평가했다.</p> <p>진행 차트 (Figure 3, 5) 의 지표 정의는 다음과 같다. P 는 AST 전체 paragraph 대비 진입한 paragraph 수, T 는 전체 정적 paragraph edge 대비 관측된 edge 수다. 각 edge 는 색으로 분류되는데, <code class="language-plaintext highlighter-rouge">EXIT</code> / <code class="language-plaintext highlighter-rouge">GOBACK</code> edge 는 목적지 노드의 DAG 색을 따르고 (range-completion 규칙: EXIT terminator 는 소스 paragraph 가 돌면 covered 로 센다), 비-EXIT edge 는 그 전이를 처음 관측한 국면을 따른다 (파랑 = Witness Search, 빨강 = Mutation, 겹치면 빨강 우선). 차트의 <code class="language-plaintext highlighter-rouge">parity X/N PASS</code> 는 생성 Java 타깃이 COBOL 실행의 paragraph 진입 · 외부 효과 · 출력을 정확히 재현한 수락 테스트 케이스 수, 즉 Parity Gate 를 살아남은 TC 비율이다.</p> <h2 id="실험-결과">실험 결과</h2> <h3 id="작은-오픈소스-프로그램--cbact01c">작은 오픈소스 프로그램 — CBACT01C</h3> <p>430 라인, 62 branch probe 짜리 CBACT01C 에서 루프는 paragraph 커버리지 <strong>100% (16/16)</strong>, transition 커버리지 <strong>100% (28/28)</strong>, branch 커버리지 <strong>96.8% (60/62)</strong> 를 달성했다. 중간 복잡도 프로그램에서는 거의 완전 포화가 가능하다는 확인이다.</p> <h3 id="중간-크기-오픈소스-프로그램--cbstm03a">중간 크기 오픈소스 프로그램 — CBSTM03A</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig3-coverage-cbstm03a-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig3-coverage-cbstm03a-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig3-coverage-cbstm03a-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig3-coverage-cbstm03a.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: CBSTM03A 에 대한 커버리지 진행. 38 개 정적 edge 중 Witness Search 가 18 개 (파랑), Mutation 이 19 개 (빨강) 를 추가해 37/38 (97.4%), 미커버 1 개. paragraph 는 24/25 (96.0%), parity 는 38/38 PASS.</figcaption> </figure> <p>924 라인 CBSTM03A 에서 paragraph 24/25 (96.0%), transition 37/38 (97.4%) 이 나왔다. 여기서 눈여겨볼 건 <strong>기여 비율</strong>이다. 37 개 커버된 전이 중 Witness Search 가 연 건 18 개뿐이고 나머지 19 개는 Mutation 이 열었다. paragraph 도 24 개 중 8 개가 Mutation 몫이다. 즉 입력 공간 탐색만으로는 전이 기준 절반에 못 미치는 지점에서 멈춘다.</p> <p>branch 커버리지는 다른 얘기다. 146 개 branch probe 중 38 개가 끝내 미커버로 남아 <strong>74.0%</strong> 에 그쳤다. 저자들도 Figure 3/4 가 paragraph 와 transition 커버리지를 보고하는 것이지 branch 커버리지가 아니라고 명시한다. 그러면서 “충분한 인내와 상당한 사람 개입이 있었다면 더 나은 결과를 얻었을 것이고, 현재 커버리지에서도 우리가 아는 어떤 대안 방법의 출력보다 낫다” 고 덧붙인다. 100% 를 막는 구조적 이유는 목킹의 복잡도 외에는 파악되지 않았다고 한다. 실패 사례도 구체적으로 밝히는데, Authoring Layer 가 한 스킬에서 배운 것을 관련 시나리오의 게이트를 여는 데 적용하지 못해 사람이 원인을 짚어 줘야 했다. 모델이 좋아지면 자율 실행 커버리지가 점진적으로 좋아지리라는 게 저자들의 기대다.</p> <p>수락된 38 개 테스트 케이스는 전부 Parity Gate 세 축을 통과했다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig4-cfg-test-program-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig4-cfg-test-program-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig4-cfg-test-program-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig4-cfg-test-program.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 4: CBSTM03A 의 control-flow graph. 노드는 paragraph, 엣지는 정적 paragraph-to-paragraph 전이다. 노드 색은 그 paragraph 에 처음 도달한 국면을 뜻한다. 고립된 파랑/회색 노드가 보이는 건 정상인데, 순차적 COBOL fall-through 를 명시적 엣지로 모델링하지 않았기 때문이다. 엣지 색은 파랑 = Witness Search 관측, 빨강 = mutation 이후 관측 (겹치면 빨강 우선), 회색 = 이번 실행에서 미도달.</figcaption> </figure> <p>Figure 4 는 이 구조를 그대로 보여 준다. 저자들의 설명대로 파랑 영역이 Witness Search (입력 공간 탐색) 가 연 첫 단계이고, 빨강이 Mutation 의 결과, 회색이 미커버 영역이다. 그래프 아래쪽 한 노드로 빨간 엣지가 다발로 수렴하는 모습이 눈에 띄는데, mutation 이후에야 관측된 전이가 특정 paragraph 로 몰려 있다는 뜻이다.</p> <h3 id="production-shape-실행">production-shape 실행</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig5-coverage-production-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig5-coverage-production-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig5-coverage-production-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig5-coverage-production.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 5: production-shape 실행의 커버리지 진행. 146 개 정적 paragraph 연결 중 baseline Witness Search 가 54 개 (파랑), Mutation 이 47 개 (빨강) 를 추가해 T=101/146 (69.2%). paragraph 커버리지는 166 개 테스트 케이스에 걸쳐 P=135/142 (95.1%).</figcaption> </figure> <p>두 번째 실험은 4,114 소스 라인, 142 paragraph, 432 정적 분기의 훨씬 큰 production-grade 프로그램이다. 최종 수치는 paragraph <strong>135/142 (95.1%)</strong>, transition <strong>101/146 (69.2%)</strong>, branch <strong>91.90% (397/432)</strong>.</p> <p>진행 과정이 특히 선명하다. Witness Search 국면은 P=110/142, T=54/146 에서 멈췄고, Mutation 국면이 ΔP=+25, ΔT=+47 을 더해 P=135/142, T=101/146 에서 plateau 에 들어갔다. 실행 수로 보면 Witness Search 가 61 회, Mutation 이 105 회로 합계 166 회다. 즉 실행의 3분의 2가 Mutation 국면에서 나왔고, 그 대가로 전이 47 개를 추가로 열었다. <strong>이미 plateau 에 닿은 지점에서 출발해 Witness Search 가 연 54 개에 육박하는 47 개를 더 열었다</strong>는 게 이 논문의 주장을 가장 직접적으로 뒷받침하는 숫자다.</p> <p>각 TC 마다 parity 검사가 돌았고, 불일치가 검출되면 새 수정 세트를 Authoring Layer 가 제안해 Migrator 나 COBOL Mock Generator 에 적용했다. 저자들이 열거한 불일치 유형은 다음과 같다 — end-of-stream 및 종료 의미론, 제어 흐름 충실도, 프로그램 상태·데이터 레이아웃 충실도, 데이터 타이핑과 값 정규화, DB 및 목 백엔드 동작 동치, 파일 I/O 부수 효과와 순서 동치, fixture 및 환경 일관성, 측정·정규화 아티팩트 통제. 최종적으로 생성 Java 타깃은 모든 parity 축에서 COBOL 동작을 재현했다 — <strong>166/166 PASS, 0 FAIL, 0 ERROR</strong>. 그리고 루프는 <em>사람 개입 없이</em> 진행됐다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig6-cfg-production-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig6-cfg-production-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig6-cfg-production-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig6-cfg-production.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 6: production 프로그램의 control-flow graph. Figure 4 와 같은 색 규약이다. clutter 를 줄이려고 COBOL fall-through 의미론을 생략했으므로 모든 실행 경로가 DAG 에 표현돼 있지는 않다.</figcaption> </figure> <h2 id="결과-분석--ablation">결과 분석 / Ablation</h2> <h3 id="여섯-알고리즘이-같은-벽에-부딪힌다">여섯 알고리즘이 같은 벽에 부딪힌다</h3> <p>가장 흥미로운 관찰은 여섯 Witness Search 알고리즘이 <strong>거의 같은 커버리지 (±2–3 분기) 에서 끝난다</strong>는 것이다. 저자들은 성능이 나빠 폐기한 알고리즘까지 더 실험한 뒤, 이 경계가 알고리즘적인 것이 아니라 <strong>구조적</strong>이라고 일반화한다. 즉 남은 분기들은 하네스가 표현할 수 있는 입력 공간 바깥에 있고, 어떤 탐색 전략을 써도 도달할 수 없다.</p> <p>이 관찰이 논문 전체 논리의 축이다. 탐색 예산을 늘리는 게 답이 아니라는 진단이 있어야 하네스 변형이라는 처방이 정당해진다. 다만 리뷰어 입장에서 같은 관찰은 다른 해석도 허용한다 — 여섯 알고리즘이 같은 결과를 낸다면 여섯 개를 다 돌릴 이유가 없다. 실제로 Post-Mutation Witness Search 는 UCB1 하나만 쓴다. 저자들이 이를 명시적으로 논하지는 않지만, 이 설계 자체가 앙상블의 중복성을 인정하는 셈이다.</p> <h3 id="mutation-이-얼마나-기여했나">Mutation 이 얼마나 기여했나</h3> <p>두 실행 모두에서 Mutation 의 기여가 Witness Search 에 필적하거나 앞선다.</p> <table> <thead> <tr> <th>실행</th> <th>Witness Search</th> <th>Mutation</th> <th>미커버</th> </tr> </thead> <tbody> <tr> <td>CBSTM03A (transition)</td> <td>18/38</td> <td>+19/38</td> <td>1/38</td> </tr> <tr> <td>CBSTM03A (paragraph)</td> <td>16/25</td> <td>+8/25</td> <td>1/25</td> </tr> <tr> <td>production (transition)</td> <td>54/146</td> <td>+47/146</td> <td>45/146</td> </tr> <tr> <td>production (paragraph)</td> <td>110/142</td> <td>+25/142</td> <td>7/142</td> </tr> </tbody> </table> <p>CBSTM03A 에서는 Mutation 이 열어 준 19 개 전이가 Witness Search 가 연 18 개보다 많다. production 실행에서도 47 대 54 로 비슷한 규모다. 저자들이 threats 절에서 정직하게 표현하듯, 이 수치는 “Mutation 국면이 입력 탐색만으로는 닿을 수 없는 paragraph 와 전이에 닿는다” 는 <em>사례 증거</em>이지 모든 COBOL 시스템에 대한 일반 주장은 아니다.</p> <h3 id="깊이-2-재귀가-실제로-작동한다">깊이-2 재귀가 실제로 작동한다</h3> <p>논문이 명확히 보고하는 재귀의 실증이 하나 있다. depth-1 게이트를 열고 Witness Search 를 진행한 뒤, 에이전트가 두 번째 층의 게이트를 열자 여섯 알고리즘이 다시 발동해 이 층을 뚫을 새 witness 집합을 찾아냈다. Mutation 의 가치는 그것이 직접 여는 분기에만 있는 게 아니라 <strong>그것이 노출시키는 영역에 있다</strong>는 저자들의 표현이 이 지점을 정확히 짚는다.</p> <p>루프의 각 패스에서 검출된 결함은 <em>생성된 코드가 아니라 Migrator 에서</em> 고쳐진다. Authoring Layer 가 Migrator 수정을 제안하는 방식이고, 그 결과 parity 를 달성한다. 이건 실무적으로 중요한 차이다. 생성물을 손보면 다음 재생성에서 사라지지만, 생성기를 손보면 같은 패턴의 모든 프로그램에 반영된다.</p> <h3 id="남은-커버리지-갭의-패턴">남은 커버리지 갭의 패턴</h3> <p>production 실행이 100% 에 못 미친 이유를 저자들은 구조적 · 외부 결합 복잡도로 돌린다. 미커버 paragraph 를 뜯어보니 일관된 패턴이 있었다. 남은 경로들은 <strong>여러 단계에 걸친 paragraph 체인 뒤에 앉아 있고, 제어 변수가 앞선 섹션들에서 점진적으로 설정</strong>된다. 이 paragraph 에 진입하려면 가짜 파일과 DB 가 정확히 조율된 결과 시퀀스를 돌려주고, 내부 스위치를 이른 시점에 뒤집어야 한다. 단일 게이트 하나를 여는 것으로는 안 되고, 시간축에 걸친 상태 시퀀스를 통째로 맞춰야 하는 종류의 잠금이다.</p> <p>결론부에서 저자들은 남은 갭이 방법의 구조적 한계라기보다 <strong>현재 Authoring Layer 의 한계</strong>를 반영한다고 본다. 간헐적인 mutation 저작 오류, 그리고 학습한 전략을 관련 시나리오로 전이시키지 못하는 실패가 원인이었고 사람 개입으로 해소됐다. 결정론적 코어는 애초에 에이전트 층이 사람 도움을 받는 상황에서도 효과적으로 동작하도록 설계됐다는 것이 그들의 방어 논리다.</p> <h2 id="한계와-비판적-평가">한계와 비판적 평가</h2> <h3 id="저자가-인정한-것">저자가 인정한 것</h3> <ul> <li><strong>사례 수가 적다.</strong> 오픈소스 두 개, production-shape 한 개. IMS, DB 중심 SQL, CICS 시스템 등 다른 프로그램 계열로 복제해야 주장이 강해진다.</li> <li><strong>branch coverage 는 불완전한 대리 지표다.</strong> 커버리지 높은 스위트가 모든 결함 부류를 못 잡을 수 있고, 잘 고른 소수의 mutation 테스트가 더 나을 수 있다는 건 퍼징·커버리지 문헌의 오랜 긴장이다. 저자들은 커버리지가 아니라 <em>교차 언어 parity</em> 에 수락을 걸어 완화한다고 하면서도, 결과 스위트가 마이그레이션 승인에 그 자체로 충분하다고는 주장하지 않는다. “bare-baseline 시작점 대비 정량 비교 가능한 잣대일 뿐” 이라는 표현이 정확하다.</li> <li><strong>parity 는 버그도 보존한다.</strong> 레거시 COBOL 을 operational reference 로 삼는다는 건 이관된 Java 가 레거시의 <em>버그까지</em> 재현하는지를 검증한다는 뜻이다. 1:1 마이그레이션 맥락에서는 이게 원하는 성질이지만, 저자들의 표현대로 operational reference 는 <em>compatibility 의 진실</em>이지 <em>semantics 의 진실</em>이 아니다. 최종 목표가 호환성 이관이 아니라 정확성 검증이라면 Parity Gate 만으로는 부족하고 외부 사양 오라클이 필요하다.</li> <li><strong>하네스 구조에 과적합될 수 있다.</strong> Locksmith 는 본 적 있는 소스 프로그램에서만 배우므로, 초기 표본에 없는 구조나 실행 패턴은 포착 못 할 수 있다.</li> <li><strong>Parity Gate 는 자기 축만큼만 강하다.</strong> 세 축은 paragraph 순회 누락, 조기 종료, 잘못 세팅된 변수, 잘못된 dispatch 순서를 잡는다. 하지만 관측 가능한 체크포인트 <em>사이</em>의 중간 상태, COBOL 과 Java 런타임의 부동소수점 반올림 모드 차이, JVM 전용 오류 경로가 던지는 예외 타입에 대해서는 침묵한다. 검사하지 않는 축에서 동작이 어긋나면서도 게이트를 통과하는 Java 타깃이 원리적으로 가능하다.</li> </ul> <h3 id="리뷰어-관점에서-추가로-보이는-것">리뷰어 관점에서 추가로 보이는 것</h3> <p><strong>베이스라인 비교가 없다.</strong> 논문은 가장 가까운 선행 작업으로 Hans et al. / Kumar et al. 의 심볼릭 실행 기반 COBOL-Java 검증을 지목하지만, 정작 그것과 같은 프로그램에서 head-to-head 를 돌리지 않는다. “우리가 아는 어떤 대안 방법의 출력보다 낫다” 는 문장은 측정이 아니라 주장이다. CBACT01C 와 CBSTM03A 는 공개 프로그램이므로 EvoSuite 계열이나 기존 COBOL 테스트 도구와의 비교가 불가능하지도 않았을 텐데, 그 비교가 빠진 자리가 크게 보인다.</p> <p><strong>커버리지를 측정하는 대상이 변형된 프로그램이다.</strong> 이게 방법론의 근본 긴장이다. 91.90% 라는 branch coverage 는 원본 프로그램이 아니라 <em>하네스 변형이 가해진</em> 바이너리의 커버리지다. call-injection 스킬이 메인 흐름의 알려진 지점에서 paragraph 실행을 강제하면, 그 paragraph 가 두 언어에서 동일하게 도는지는 증명되지만 <strong>실제 입력으로 그 paragraph 에 도달할 수 있는지, 그리고 도달하는 실제 제어 흐름이 동일한지는 증명되지 않는다</strong>. Analyzer 가 dispatcher 기반 변형을 우선한다는 설계가 이 문제를 완화하려는 장치인 건 분명하지만, 최종 커버리지 중 얼마가 dispatcher 기반이고 얼마가 call-injection 기반인지는 보고되지 않는다. 이 비율이야말로 결과의 해석을 좌우하는 숫자다.</p> <p><strong>abstract 의 커버리지 서술이 관대하다.</strong> “두 오픈소스 프로그램에서 거의 완전한 커버리지에 도달했다” 는 문장은 paragraph / transition 기준으로는 맞지만 (16/16, 28/28 그리고 24/25, 37/38), CBSTM03A 의 branch 커버리지는 74.0% 다. 같은 문장에서 production 프로그램에 대해서는 “91.90% branch coverage” 라고 branch 지표를 쓰기 때문에, 독자가 앞의 “거의 완전한” 도 branch 로 읽을 여지가 크다. 본문은 지표를 명확히 구분하지만 abstract 는 그렇지 않다.</p> <p><strong>확률적 방법인데 반복 실행이 없다.</strong> ART, MAP-Elites, UCB1 은 전부 난수를 쓴다. 프로그램당 실행이 한 번씩이고, 시드도 분산도 보고되지 않는다. “여섯 알고리즘이 ±2–3 분기 안에서 수렴한다” 는 관찰조차 반복 없이는 얼마나 견고한지 알 수 없다.</p> <p><strong>비용이 보고되지 않는다.</strong> “루프가 몇 시간 동안 무인으로 돌았다” 는 서술이 전부다. 토큰 비용, wall-clock, LLM 호출 수, 어느 모델을 썼는지 — 전부 없다. 저자들 자신이 future work 에서 토큰 비용 측정을 과제로 꼽는 걸 보면 의도적 누락이라기보다 아직 안 한 것에 가깝지만, 이 방법을 도입할지 판단해야 하는 실무자에게는 가장 먼저 필요한 숫자다.</p> <p><strong>정책·구성요소 ablation 이 없다.</strong> Locked Paragraph 정렬 정책은 기본값 (bang × feasibility) 을 설명해 놓고 실험은 greedy 로 돌렸는데, 둘의 비교가 없다. 두 스킬 타입 중 어느 쪽이 얼마나 기여했는지도 없다. 여섯 알고리즘 중 몇 개를 빼면 어떻게 되는지도 없다. 방법의 어느 부분이 실제로 값어치를 만드는지 분해되지 않은 채로 남는다.</p> <p><strong><code class="language-plaintext highlighter-rouge">paragraphs_hit</code> 이 집합 비교다.</strong> 진입 <em>순서</em>는 이 축에서 검사되지 않는다. 순서 정보는 <code class="language-plaintext highlighter-rouge">stub_log</code> 를 통해 간접적으로만 잡히므로, 외부 연산을 소비하지 않는 paragraph 들 사이의 순서가 뒤바뀐 Java 타깃은 이론상 게이트를 통과할 수 있다. 저자들이 (e) 항에서 인정한 “검사하지 않는 축” 목록에 이 항목도 들어갈 만하다.</p> <h2 id="시사점--takeaways">시사점 / Takeaways</h2> <ul> <li><strong>탐색이 막혔을 때 예산이 아니라 경계를 의심하라.</strong> 여섯 개의 서로 다른 탐색 알고리즘이 같은 지점에서 멈춘다면 그건 알고리즘 문제가 아니다. 하네스가 표현할 수 있는 입력 공간이 답을 담고 있지 않다는 신호다. 이 진단-처방 쌍은 COBOL 과 무관하게 어떤 테스트 자동화에도 옮길 수 있다.</li> <li><strong>LLM 을 생성자로 쓰고 판정은 결정론적 오라클에 맡기는 배치가 반복해서 이긴다.</strong> TestGen-LLM 이 그랬고 이 논문도 같다. 여기서 한 걸음 더 나간 건, 판정 오라클을 <em>파이프라인 끝</em>이 아니라 <em>루프 안</em>에 심어 매 변형마다 돌린다는 점이다. 잘못된 변형이 축적될 시간을 주지 않는다.</li> <li><strong>레거시 이관 검증의 목표는 정확성이 아니라 호환성이다.</strong> 이 구분을 명시적으로 세우고 오라클을 그에 맞춰 설계한 게 이 논문의 가장 실무적인 기여다. 컷오버 이후 Java 코드를 유지보수할 사람들에게 레거시 동작 이탈은 조사해야 할 회귀이지 개선이 아니다. 다만 이 선택은 되돌리기 어렵다 — 정확성 검증으로 넘어가려면 완전히 다른 오라클이 필요하다.</li> <li><strong>결함을 생성물이 아니라 생성기에서 고쳐라.</strong> parity 실패를 Java 산출물에 패치하는 대신 Migrator 에 반영하는 설계는 사소해 보이지만 규모가 커질수록 결정적이다. 같은 COBOL 관용구가 수백 개 프로그램에 반복되는 환경에서 생성기 수정 하나가 전부에 전파된다.</li> <li><strong>커버리지 숫자를 볼 때 그 숫자가 어떤 프로그램에 대한 것인지 물어라.</strong> 하네스를 변형해서 얻은 커버리지는 원본 프로그램의 커버리지와 다르다. 이 논문의 방법은 그 차이를 parity 로 방어하지만, 도입을 검토한다면 강제로 연 경로의 비율을 반드시 따로 집계해야 한다.</li> </ul> <h2 id="참고-자료">참고 자료</h2> <ul> <li>논문: <a href="https://arxiv.org/abs/2607.28271">arXiv:2607.28271 — Agentic Method for Deterministic Validation of Legacy Code Migration</a></li> <li>실험 대상 오픈소스 COBOL: <a href="https://github.com/aws-samples/aws-mainframe-modernization-carddemo">aws-samples/aws-mainframe-modernization-carddemo</a></li> </ul> <h2 id="더-읽어보기">더 읽어보기</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2408.04660">XMainframe: A Large Language Model for Mainframe Modernization</a></strong> (Dau et al., 2024) — 메인프레임 도메인에 특화해 사전학습한 LLM. 이 논문이 전제하는 “COBOL 을 읽고 옮기는 능력” 쪽 계보의 대표 작업이다.</li> <li><strong><a href="https://arxiv.org/abs/2604.03986">COBOL-Coder: Domain-Adapted Large Language Models for COBOL Code Generation and Translation</a></strong> (Dau et al., 2026) — COBOL 코드 생성·번역에 도메인 적응한 모델과 벤치마크. Locksmith 의 Migrator 자리에 들어갈 수 있는 종류의 구성 요소다.</li> <li><strong><a href="https://arxiv.org/abs/1504.04909">Illuminating search spaces by mapping elites</a></strong> (Mouret et al., 2015) — Witness Search 의 여섯 알고리즘 중 MAP-Elites 원전. 하나의 최적해가 아니라 행동 다양성 격자를 채우는 quality-diversity 발상.</li> <li><strong><a href="https://arxiv.org/abs/2410.04249">DiffSpec: Differential Testing with LLMs using Natural Language Specifications and Code Artifacts</a></strong> (Rao et al., 2024) — Parity Gate 가 속한 LLM 보조 differential testing 계보. 같은 사양의 두 구현을 놓고 출력 차이를 결함으로 신고한다.</li> <li><strong><a href="https://arxiv.org/abs/2507.19275">Mut4All: Fuzzing Compilers via LLM-Synthesized Mutators Learned from Bug Reports</a></strong> (Wang et al., 2025) — LLM 이 mutator 자체를 합성하는 방향. Locksmith 의 future work 가 명시적으로 지목하는 통합 대상이다.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="software-testing"/><category term="agentic-systems"/><category term="legacy-migration"/><category term="cobol"/><category term="mutation-testing"/><category term="differential-testing"/><category term="search-based-testing"/><summary type="html"><![CDATA[COBOL→Java 마이그레이션 검증에서 입력 탐색이 막히면 하네스 자체를 변형해 새 실행 영역을 열고, 그 변형을 두 언어에 대칭 적용한 뒤 결정론적 parity 오라클로 판정하는 American Express 의 Locksmith Loop]]></summary></entry><entry xml:lang="en"><title type="html">[Paper Review] Agentic Method for Deterministic Validation of Legacy Code Migration</title><link href="https://baba9811.github.io/en/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/" rel="alternate" type="text/html" title="[Paper Review] Agentic Method for Deterministic Validation of Legacy Code Migration"/><published>2026-08-21T05:00:00+00:00</published><updated>2026-08-21T05:00:00+00:00</updated><id>https://baba9811.github.io/en/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code</id><content type="html" xml:base="https://baba9811.github.io/en/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/" class="btn btn-sm btn-outline-secondary">🇰🇷 한국어로 읽기</a> </div> <h2 id="metadata">Metadata</h2> <table> <thead> <tr> <th>Field</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td>Authors</td> <td>Andras Ferenczi et al. (5 co-authors, American Express)</td> </tr> <tr> <td>Venue</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv or DOI</td> <td><a href="https://arxiv.org/abs/2607.28271">2607.28271</a></td> </tr> <tr> <td>Data</td> <td>AWS CardDemo CBACT01C (430 lines) · CBSTM03A (924 lines) · internal production-like batch program (4,114 lines)</td> </tr> <tr> <td><span style="white-space: nowrap">Review date</span></td> <td>2026-08-21</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>The hard part of a 1:1 COBOL-to-Java migration is not the translation, it is the <strong>validation</strong>. Real test data does not exist, and decades of “broken-as-usual” behavior have quietly become part of the spec. This paper automates that validation with the Locksmith Loop.</li> <li>The loop alternates two phases. <strong>Witness Search</strong> sweeps the input and mock space with six algorithms (pairwise · 3-way · LHS · ART · MAP-Elites · UCB1) until nothing new opens. At that plateau, <strong>Mutation</strong> forces one Locked Paragraph open. The moment it opens, control returns to Witness Search, which now explores recursively from inside the newly reachable region.</li> <li>The load-bearing design choice is that every mutation is applied <strong>symmetrically</strong> to the COBOL mock and the generated Java. That makes the coverage-increasing edit itself subject to parity checking. The verdict comes from a deterministic <strong>Parity Gate</strong> over three axes (paragraphs_hit, stub_log, terminal_state), not from an LLM.</li> <li>The LLM (the Authoring Layer) never writes migration code. It proposes a Mutation Skill when the deterministic tooling gets stuck, and acceptance is decided by two deterministic conditions: does coverage increase, and does the Parity Gate pass. Separating generation from judgment is the spine of the paper.</li> <li>Results on three programs. CBACT01C (430 lines): 16/16 paragraphs, 28/28 transitions, 60/62 branches (96.8%). CBSTM03A (924 lines): 24/25 paragraphs (96.0%), 37/38 transitions (97.4%), 74.0% branch coverage, parity 38/38 PASS. The internal production-like program (4,114 lines): 135/142 paragraphs (95.1%), 101/146 transitions (69.2%), 91.90% branch coverage (397/432), with 166/166 PASS, 0 FAIL, 0 ERROR. On the two larger programs, where the paper breaks coverage down by phase, Mutation opened as much ground as Witness Search or more.</li> </ul> <h2 id="introduction">Introduction</h2> <p>COBOL is still running on mainframes at the core of banking, cards, and insurance. Decades of business rules are compressed into that code, and a good fraction of them exist nowhere else — certainly not in documentation. LLM-based coding agents have made reading that code and emitting Java dramatically easier. The problem is what comes next: how do you <em>prove</em> the translation behaves like the original?</p> <p>The usual practice is parallel run. Keep the legacy and the replacement alive side by side, watch for output divergence, and cut traffic over once confidence accumulates. The limitation is obvious. Real traffic only walks a fraction of the paths, and the long tail executes for the first time after cutover. Worse, legacy systems contain behavior that contradicts the original product definition but has calcified into the de facto spec — what the authors call “broken-as-usual.” In lift-and-shift modernization you have to reproduce those bugs exactly. The target is not <em>correctness</em>; it is <em>compatibility</em>.</p> <p>The American Express team’s answer compresses into two sentences. If coverage stalls not because you are picking bad inputs but because <strong>the answer lies outside the input space the harness can express</strong>, stop searching harder and widen the harness boundary instead. And if you apply the widening edit identically to both the legacy and the replacement, that edit becomes something the parity oracle can check. Everything else in the paper is engineering to make those two moves auditable and reproducible. It is worth reading even if you will never touch COBOL, because it is a concrete answer to a question that keeps recurring in the agentic era: what, exactly, adjudicates the agent’s output?</p> <h2 id="key-contributions">Key Contributions</h2> <ul> <li><strong>The Locksmith Loop — recursive harness expansion as the central validation mechanism.</strong> Input-space exploration (Witness Search) and parity-preserving code mutation alternate, and a successful mutation returns control to a full sweep from inside the newly opened region. The authors are not aware of prior legacy-to-modern migration work that puts recursive harness expansion at the center of validation.</li> <li><strong>The Parity Gate — a deterministic oracle for agent output.</strong> Three axes compare behavioral fingerprints between the COBOL mock and the generated Java: paragraphs_hit (the set of paragraphs entered), stub_log (the ordered sequence of consumed external operations), and terminal_state (observable variable values after the run). Crucially it runs after <em>every</em> mutation, not once at the end.</li> <li><strong>Teacher-student separation.</strong> The student is the deterministic toolchain that does migration, search, mutation, and parity checking. The teacher is a supervisory AI agent (the Authoring Layer) invoked only where the student is blocked, and it selects or synthesizes a Mutation Skill rather than writing the migrated program. It ports the TestGen-LLM pattern — the LLM proposes, deterministic filters dispose — into migration validation.</li> <li><strong>A Mutation Skill Catalog that makes successful edits reusable.</strong> A successful mutation is captured as an AI skill and stored for reuse in later iterations. Keeping edits as persistent skills rather than direct source modifications preserves a clean boundary between the original program logic and the coverage-enhancing changes.</li> <li><strong>A reported unattended run on a 4,114-line production-shape program.</strong> Branch coverage 91.90% and 166/166 parity PASS, with no customer data — only harness-generated inputs and mocked external responses, and no human intervention. The program is internal and therefore not reproducible, but numbers at that scale from an autonomous run are rare in this literature.</li> </ul> <h2 id="background-and-related-work">Background and Related Work</h2> <h3 id="the-minimum-you-need-to-know">The minimum you need to know</h3> <p>A COBOL program nests DIVISION → SECTION → <strong>paragraph</strong>. A paragraph is a labeled block of statements and behaves essentially like a function. Control flows through <code class="language-plaintext highlighter-rouge">PERFORM</code> (call), <code class="language-plaintext highlighter-rouge">GO TO</code> (jump), <code class="language-plaintext highlighter-rouge">EVALUATE</code> (switch), and the notorious <code class="language-plaintext highlighter-rouge">ALTER</code> (rewriting a <code class="language-plaintext highlighter-rouge">GO TO</code> target at runtime). The Migrator in this paper maps one SECTION to one Java class and one paragraph to one method.</p> <p>Three coverage metrics appear and you have to keep them apart. <strong>Paragraph coverage (P)</strong> is the fraction of paragraphs in the AST entered at least once. <strong>Transition (edge) coverage (T)</strong> is the fraction of statically present paragraph-to-paragraph control-flow transitions traversed at least once. <strong>Branch coverage</strong> is the fraction of instrumented branch probes taken at least once. They get progressively stricter, and as we will see, they diverge substantially on the same program.</p> <h3 id="four-lines-of-prior-work">Four lines of prior work</h3> <p>The paper positions itself at the intersection of four areas.</p> <p><strong>1. Test-suite amplification and harness testability.</strong> DSpot iteratively augments developer-written tests and feeds them back as merge-ready patches; EvoSuite and EvoSuiteAmp use existing tests as seeds for search-based improvement. Locksmith shares the iterative stance but changes the transformation target: instead of improving tests, it <strong>expands the harness interface itself</strong>, then re-runs Witness Search inside the enlarged input space. It sits adjacent to the testability-transformation line of work, except that it iterates on the controllability boundary rather than rewriting the program to be more testable.</p> <p><strong>2. Search-based input generation, fuzzing, and symbolic execution.</strong> Combinatorial interaction testing, adaptive random testing, MIO, the quality-diversity family around MAP-Elites, and its bandit-aware refinement Monte Carlo Elites supply the six Witness Search algorithms. Empirical studies of continuous fuzzing such as OSS-Fuzz show nontrivial progression dynamics — slow growth punctuated by rapid bursts. Locksmith follows that pattern initially, then identifies a plateau once multiple algorithms converge to within ±2–3 branches of the same count, and changes tack: rather than augmenting the budget, it <em>mutates the harness boundary</em> to continue the search from an updated angle. T-Fuzz is the closest analogue in spirit — it also mutates code to break past hard input checks — but T-Fuzz targets bug discovery, whereas Locksmith targets parity-gated migration validation.</p> <p><strong>3. Differential and metamorphic oracles.</strong> Mokav and DiffSpec take two implementations of the same spec and flag output discrepancies as bugs. Where exact outputs are unavailable, metamorphic testing checks relations across executions. The Parity Gate is a differential oracle in that lineage, but with a second job: it also acts as a <em>guardrail for the mutation itself</em>, keeping the harness edits parity-preserving while they expand the reachable input space.</p> <p><strong>4. Program repair and agentic LLM software engineering.</strong> RepairAgent orchestrates LLM tool use and validates fixes against program feedback. Meta’s TestGen-LLM ships LLM-generated tests only when deterministic filters confirm they build, pass, and improve coverage. TestPilot re-prompts on failure; Mut4All synthesizes compiler-fuzzing mutators from bug reports. Locksmith applies that structure to harness mutation: the LLM proposes edits, and the deterministic analyzer, runner, and parity oracle decide which survive.</p> <h3 id="neighbours-in-mainframe-modernization">Neighbours in mainframe modernization</h3> <p>XMainframe is a mainframe-domain LLM; COBOL-coder is domain-adapted for COBOL generation and translation. Other work covers low-resource COBOL translation leveraging high-resource Java refinement, and enterprise-scale COBOL-to-Java pipelines that augment LLMs with program analysis. The closest comparison is the automated validation work of Hans et al. and Kumar et al., which uses symbolic execution to generate COBOL unit tests, translates them into JUnit with mocking, and checks semantic equivalence. Same target, different placement: that line runs validation as a post-hoc check, while Locksmith installs the gate <em>inside</em> a search-and-mutation loop.</p> <h3 id="scope-and-assumptions">Scope and assumptions</h3> <p>The paper draws its own boundaries clearly. The target is a 1:1 COBOL-to-Java migration, and the success criterion is <strong>increasing branch coverage with parity validation under the same inputs</strong>, not system overhaul. The harness makes opinionated infrastructure substitutions: legacy RDBMS instances become PostgreSQL, MQ becomes RabbitMQ. The strategy is two-fold — port with parity first, refactor once confidence is established on the new stack.</p> <h2 id="method">Method</h2> <h3 id="the-locksmith-metaphor">The locksmith metaphor</h3> <p>The whole paper is explained through the metaphor. Each branch is a <em>door</em>, and the inputs and mocked state needed to cover it are the <em>keys</em>. Some doors open easily; others require a drill, meaning a parity-preserving mutation that exposes a blocked execution path. Running multiple search algorithms over the reachable branches tells you which doors are easy and which stay locked after repeated attempts. The remaining branches may be structurally unreachable from the current harness state. That is where the drill comes in — and once the new door is unlocked, you resume lock-picking (Witness Search) inside the newly reachable region. Apply recursively.</p> <p>Five terms carry the rest:</p> <ul> <li><strong>Locksmith Loop</strong>: the end-to-end methodology</li> <li><strong>Witness Search</strong>: the phase that explores the program input space, including mocked backend responses and environmental state, with several algorithms</li> <li><strong>Locked Paragraph</strong>: a COBOL paragraph that cannot be reached via Witness Search alone</li> <li><strong>Mutation</strong>: the code-altering phase that applies parity-preserving mutations to both the COBOL and Java targets</li> <li><strong>Parity Gate</strong>: the deterministic oracle that runs both targets on the same witness inputs and reports end-state discrepancies</li> </ul> <h3 id="migration-and-harness-setup">Migration and harness setup</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig1-harness-setup-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig1-harness-setup-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig1-harness-setup-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig1-harness-setup.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: Migration and harness setup. Light blue marks student components, light yellow the Authoring Layer. One branch of the COBOL source goes through the Mock Generator to become a runnable COBOL mock; the other goes through the Migrator to become the Java target. The Runner / Parity Gate drives both with the same inputs and compares behavior.</figcaption> </figure> <p>The COBOL source flows two ways. One path runs through an internal deterministic <strong>Migrator</strong> to produce the Java target; the other runs through a deterministic <strong>COBOL Mock Generator</strong> to produce a runnable COBOL mock. A shared test harness exercises both, records a behavioral fingerprint, and enforces the Parity Gate.</p> <p>The overall shape is teacher-student. The <em>student</em> is the deterministic set of tools that carries out migration, Witness Search, Mutation, and parity checking. The <em>teacher</em> is the Authoring Layer. Here is the part that matters: the Authoring Layer does not write the migrated program. It selects an existing skill or proposes a new one to open the blocked execution path, and the correctness of each proposal is determined by the Parity Gate. Compilation and behavioral-equivalence checks accept or reject each proposal. A parity failure triggers the Authoring Layer to intervene, and if its mutation passes the gate, the loop resumes. This separation of generation from deterministic judgment is what makes the loop robust.</p> <h3 id="pipeline-overview">Pipeline overview</h3> <p>The pipeline starts with source-level transformations that produce a runnable <em>mock COBOL</em> program. External operations — file I/O, <code class="language-plaintext highlighter-rouge">CALL</code>, <code class="language-plaintext highlighter-rouge">EXEC SQL</code>, <code class="language-plaintext highlighter-rouge">EXEC CICS</code> — are mocked and backed by either COBOL index files or a relational database such as PostgreSQL. The compiled mock binary supplies the branch-coverage measurements used throughout the loop.</p> <p>Next, an external parser produces the legacy program’s AST, which feeds the deterministic Migrator. The Java code generator emits one class per section and one method per paragraph, and maps COBOL control flow (<code class="language-plaintext highlighter-rouge">PERFORM</code>, <code class="language-plaintext highlighter-rouge">GO TO</code>, <code class="language-plaintext highlighter-rouge">ALTER</code>, <code class="language-plaintext highlighter-rouge">EVALUATE</code>) to equivalent Java control flow.</p> <p>A test case is a pair of <strong>input-state</strong> and <strong>stub-state</strong>. The input-state specifies the variable assignments applied during execution; the stub-state supplies the records returned by mocked external operations. After execution the system records a <strong>behavioral fingerprint</strong>: the paragraphs entered, the branches taken, the stub-response log, and the terminal observable state. That fingerprint is the unit of both coverage tracking and parity comparison.</p> <h3 id="the-four-components">The four components</h3> <ul> <li><strong>Deterministic Migrator</strong>: translates the COBOL source into the Java target.</li> <li><strong>Deterministic Analyzer</strong>: examines the AST and the live mock, and identifies gates from program structure.</li> <li><strong>Deterministic Runner</strong>: compiles the binary, executes test cases, measures branch coverage, and applies the Parity Gate along the three equivalence axes. A code mutation is retained <em>only</em> when it increases branch coverage.</li> <li><strong>Agentic Authoring</strong>: invoked when the deterministic analyzer hits a blocked execution path; synthesizes a new skill. When the Parity Gate reports a divergence, it may also patch the Migrator’s Java code generator.</li> </ul> <h3 id="witness-search-six-algorithms">Witness Search: six algorithms</h3> <p>A Witness Search sweep runs six independent algorithms against the current-iteration COBOL mock binary, each starting from the same baseline coverage. A scenario consists of input records, initial working-storage values, and mocked external <code class="language-plaintext highlighter-rouge">CALL</code> file-status values and return codes. The harness catalog tracks the allowable choices per scenario, and the six algorithms differ only in <em>how</em> they explore that combinatorial space.</p> <ul> <li><strong>Pairwise interaction testing.</strong> Given $n$ scenario components with $|D_i|$ value choices per field, generate a small test set covering every possible pair $(v_i \in D_i,\ v_j \in D_j)$ for $i &lt; j$, with optimal size $O(|D|^2 \log n)$. Many COBOL branches are gated by compound <code class="language-plaintext highlighter-rouge">IF</code>s or <code class="language-plaintext highlighter-rouge">EVALUATE WHEN</code> clauses on two correlated fields (status code × record type, account kind × balance sign), so a pairwise-covering set surfaces each two-field combination at least once.</li> <li><strong>Three-way interaction.</strong> Extends pairwise to triples, uncovering the smaller class of branches that need three coordinated values — for example, tail-handling paragraphs gated on status × record type × end-of-file flag.</li> <li><strong>Latin hypercube sampling (LHS).</strong> Suited to quasi-continuous components such as record counts, file lengths, and monetary amounts. Each domain is partitioned into $N$ bins with one value sampled per bin, bins aligned across components to maximise distance-based diversity. LHS spreads samples across the full range rather than clustering them in one region.</li> <li><strong>Adaptive random testing (ART).</strong> Pick the next input that maximises the minimum distance to previously executed inputs, biased toward unexplored regions. Particularly useful when an unfamiliar program offers no obvious structure to exploit.</li> <li><strong>MAP-Elites.</strong> A quality-diversity algorithm maintaining a grid of behavioral-descriptor cells, each holding the highest-fitness input seen to map to that cell, where fitness is the number of newly covered branches. COBOL coverage profiles tend to cluster into a small number of execution <em>shapes</em> — clean end-of-file path, mid-stream truncation, status-error early exit, multi-record-type batch — and MAP-Elites retains one good test case per shape, which helps expose rare branches.</li> <li><strong>UCB1 bandit.</strong> Each value choice is treated as a bandit arm. At each step, select the arm maximising</li> </ul> \[\begin{aligned} a^{\star} = \arg\max_{a} \left( \bar{x}_a + c\sqrt{\frac{\ln t}{n_a}} \right) \end{aligned}\] <p>where $\bar{x}_a$ is the empirical mean reward defined by fresh branches, $n_a$ is the number of times arm $a$ has been selected, and $c$ is an exploration constant. Unlike the interaction-based methods above, UCB1 has no combinatorial fan-out. It instead learns <em>during</em> a run which values tend to expose new branches, which in COBOL mocks favors informative scenario components such as status codes and record types.</p> <p>The output of one sweep is the union of branches discovered by the six algorithms, plus the test-case set. The next sweep starts from the best set, and <strong>when two consecutive sweeps yield no new branches</strong>, the loop declares the Witness Search plateau. Once a mutation expands the harness, all six algorithms run again — the newly reachable regions may favor different search biases. The authors are explicit that these six were selected through empirical experimentation, are not guaranteed optimal for all migrations, and should be treated as a representative set rather than a fixed prescription.</p> <h3 id="mutation-parity-preserving-harness-mutation-via-skills">Mutation: parity-preserving harness mutation via skills</h3> <p>Classical mutation testing injects faults to check that error handling works. Locksmith’s mutation has the opposite purpose: it discovers and force-opens new execution paths to <strong>ensure parity</strong> between the COBOL and Java functionality, so both codebases are modified in tandem with the goal of matching their code traces as well as their outputs.</p> <p>The deterministic analyzer identifies candidate gates, and the Authoring Layer generates <strong>Mutation Skills</strong> that satisfy them. A skill may add a new dispatcher route, expose an external value through a side channel (a harness-level stub hook supplying values the program would normally read from external sources), or force execution of a paragraph that is otherwise difficult to reach. Skills are persisted between rounds rather than applied as direct code modifications, to maintain a clear separation between the original program logic and the coverage-enhancing changes.</p> <p>After the Mutation phase, previously accepted test cases are re-executed and the mutations are kept for further iterations. Because a single paragraph may be blocked by multiple independent conditions, the framework evaluates each identified gate in turn and retains only those mutations that produce additional coverage.</p> <p>Skills can have hierarchical dependencies and are applied in the required order. In practice, two types proved sufficient for most scenarios:</p> <ul> <li><strong>Dispatcher-arm skill</strong>: extends the harness so values normally read from external sources can be supplied directly through the side channel. Particularly effective for status-field-driven logic where execution depends on values that are otherwise difficult to control.</li> <li><strong>Call-injection skill</strong>: forces execution of a target paragraph from a known point in the main program flow. This exercises logic normally reached during cleanup processing, end-of-file handling, or other uncommon execution paths.</li> </ul> <p>Regardless of type, the same change is applied to both the COBOL and Java implementations, and parity is verified by comparing the execution path taken, the external operations performed, and the final observable state.</p> <p>The paper names the representative mutation used in the experiments a <strong>force-set mutation</strong>: a parity-preserving mutation that, at entry to a chosen paragraph, overrides the value that would have been mock-returned from an external operation (file read, database fetch, message-queue receive, subprogram call) with a chosen value, applied symmetrically to the COBOL mock and its generated Java target.</p> <h3 id="how-the-analyzer-picks-gates">How the Analyzer picks gates</h3> <p>The Analyzer is a static AST reader. For each target paragraph it examines the control-flow conditions preventing execution and identifies the gates that need to be satisfied. When a gate depends on a specific external value, it determines the required value and provides it to the side channel so it can be pinned during execution.</p> <p>There is a real design judgment embedded here. The Analyzer <strong>always prefers solutions that work through existing program flow</strong> — dispatcher-based mutations — because they allow the paragraph to be reached naturally. Only when no suitable dispatcher-based approach is available does it recommend a call-injection skill. This priority ensures every paragraph in the AST has at least one candidate mutation that can be evaluated. The Analyzer is intentionally conservative: it only recommends mutations that can be clearly explained in terms of a controllable variable and a known set of values, which keeps every recommendation understandable, auditable, and easy to validate before it is applied.</p> <p>Sibling gates within one Locked Paragraph get explicit treatment too. A target paragraph is not always blocked by a single condition — often several control-flow decisions must be satisfied, such as a nested <code class="language-plaintext highlighter-rouge">IF</code>, an enclosing <code class="language-plaintext highlighter-rouge">PERFORM</code> boundary, or a specific <code class="language-plaintext highlighter-rouge">EVALUATE</code> branch. The Analyzer identifies all of them and generates a candidate mutation for each. Rather than stopping after the first success, the framework evaluates every identified gate, since each one can potentially unlock additional paths. When a mutation yields new coverage it becomes part of the active baseline and subsequent mutations continue from that expanded state; if it adds nothing, it is reverted. A paragraph counts as successfully opened if at least one mutation improves coverage.</p> <h3 id="the-recursion-and-its-termination">The recursion and its termination</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig2-locksmith-loop-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig2-locksmith-loop-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig2-locksmith-loop-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig2-locksmith-loop.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: The Locksmith Loop. When two consecutive Witness Search rounds add no branches, the loop treats it as a plateau, ranks remaining Locked Paragraphs by uncovered-branch count, and opens one with a code mutation. Post-Mutation Witness Search (UCB1) confirms the coverage gain and the Parity Gate decides whether COBOL and Java agree. A successful mutation returns control to a full sweep from the newly opened region; a mutation with no gain is reverted and its paragraph marked failed.</figcaption> </figure> <p>The loop alternates (1) a Witness Search sweep and (2) a Mutation step. A mutation is kept only if <strong>it adds coverage and it passes the Parity Gate</strong>. If both hold, the harness mutation stays and the loop proceeds to another sweep, which may expose additional Locked Paragraphs — those get ranked and mutated the same way. If either condition fails, the mutation is reverted and the attempt is recorded.</p> <p>Termination is guaranteed by a simple rule: <strong>Locksmith never re-attempts a Locked Paragraph that has already been attempted.</strong> Every recursive step therefore either gains a parity-preserving mutation that uncovers new branches, or permanently removes one Locked Paragraph from consideration. When all of them have been attempted, a final Witness Search sweep recovers any remaining branches.</p> <p>The default ranking policy for Locked Paragraphs is <strong>bang × feasibility</strong>: a paragraph is scored as the sum of its uncovered branch count with the proportion of its condition variables already routable through the harness, so paragraphs that are both valuable and actionable are favored. In the actual experiments, however, the authors used the <strong>greedy</strong> policy, ranking only by uncovered branch count. Skill selection (SKILLFOR) is treated as a catalog lookup, but the catalog may be incomplete; when no skill matches, the Authoring Layer either develops a new one from its gate analysis or emits a structured <code class="language-plaintext highlighter-rouge">needs_new_skill</code> record containing the target paragraph, uncovered branches, branch conditions, and active call stack.</p> <h2 id="acceptance-criteria-and-the-parity-gate">Acceptance Criteria and the Parity Gate</h2> <p>In place of a training loss, this paper’s objective is a pair of <strong>acceptance conditions</strong>. A mutation $m$ is kept when</p> \[\begin{aligned} \text{keep}(m) \iff \; &amp; \text{coverage}(\text{after } m) &gt; \text{coverage}(\text{before } m) \\ &amp; \wedge \; \text{ParityGate}(\text{COBOL}_m, \text{Java}_m) = \text{PASS} \end{aligned}\] <p>and reverted otherwise. Coverage alone would let you hack the harness apart to inflate a number; parity alone would let a no-op mutation pass every time. The two conditions constrain each other.</p> <h3 id="the-three-equivalence-axes">The three equivalence axes</h3> <p>Every test case the COBOL side accepts (input-state + stub-outcomes) is driven through the generated Java target, and the resulting behavioral fingerprints are compared. The gate judges along three axes, declared per-skill in the parity contract.</p> <table> <thead> <tr> <th>Axis</th> <th>Comparison</th> <th>Catches</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">paragraphs_hit</code></td> <td><strong>set</strong> comparison of paragraphs entered</td> <td>missing paragraph traversal, early termination</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">stub_log</code></td> <td><strong>ordered</strong> comparison of consumed external operations (whitespace-normalised value matching)</td> <td>wrong dispatch order, missing or duplicated external calls</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">terminal_state</code></td> <td><strong>pointwise</strong> comparison of observable variable values (ignoring runtime-private bookkeeping)</td> <td>mis-set variables, value-normalization errors</td> </tr> </tbody> </table> <p>The gate is a differential oracle that accepts a <strong>compatibility relation</strong> in lieu of a ground-truth specification. And because every mutation is realized on both sides, parity is checked <em>continuously, after every break</em>, not as a terminal round.</p> <p>Divergences are emitted as structured records on the parity intervention channel, carrying the divergence kind, a human-readable description, and machine-readable diff records; these form the input contract for the optional repair step. By default the loop records a divergence and proceeds rather than blocking, unless configured otherwise. In the reported experiments the gate held on every accepted test case across all mutation tiers.</p> <p>Authoring Layer intervention points work the same way. When the analyzer or runner reaches a decision point it cannot resolve, it writes a structured record at a defined intervention point and continues, and that record can be consumed asynchronously by a human operator or an AI agent. The loop does not stall waiting for a human.</p> <h2 id="programs-and-experimental-setup">Programs and Experimental Setup</h2> <p>Three COBOL codebases were used.</p> <table> <thead> <tr> <th>Program</th> <th>Source lines</th> <th>Paragraphs</th> <th>Static edges</th> <th>Branch probes</th> <th>Source</th> </tr> </thead> <tbody> <tr> <td>CBACT01C</td> <td>430</td> <td>16</td> <td>28</td> <td>62</td> <td>AWS CardDemo (open-source)</td> </tr> <tr> <td>CBSTM03A</td> <td>924</td> <td>25</td> <td>38</td> <td>146</td> <td>AWS CardDemo (open-source)</td> </tr> <tr> <td>Production-like batch</td> <td>4,114</td> <td>142</td> <td>146</td> <td>432 (statically counted)</td> <td>internal</td> </tr> </tbody> </table> <p>The production-grade program was evaluated <strong>without customer data</strong>, using only harness-generated test inputs and mocked external responses.</p> <p>The progression charts (Figures 3 and 5) share metric definitions. P is paragraphs hit over total paragraphs in the AST; T is observed over total static paragraph edges. Each edge is classified by color: <code class="language-plaintext highlighter-rouge">EXIT</code>/<code class="language-plaintext highlighter-rouge">GOBACK</code> edges follow the DAG color of their destination node (range-completion rule — an EXIT terminator counts as covered once its source paragraph runs), and non-EXIT edges follow the phase that first observed the transition (blue for Witness Search, red for Mutation, red taking precedence on overlap). The <code class="language-plaintext highlighter-rouge">parity X/N PASS</code> annotation reports how many accepted test cases the generated Java reproduces exactly in paragraphs hit, external effects, and outputs — that is, the fraction of test cases surviving the Parity Gate.</p> <h2 id="results">Results</h2> <h3 id="the-small-open-source-program--cbact01c">The small open-source program — CBACT01C</h3> <p>On CBACT01C (430 lines, 62 branch probes), the loop reached <strong>100% paragraph coverage (16/16)</strong>, <strong>100% transition coverage (28/28)</strong>, and <strong>96.8% branch coverage (60/62)</strong>, confirming that near-complete saturation is attainable on programs of moderate complexity.</p> <h3 id="the-medium-open-source-program--cbstm03a">The medium open-source program — CBSTM03A</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig3-coverage-cbstm03a-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig3-coverage-cbstm03a-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig3-coverage-cbstm03a-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig3-coverage-cbstm03a.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: Coverage progression on CBSTM03A. Of 38 static edges, Witness Search covers 18 (blue) and Mutation adds 19 (red), reaching 37/38 (97.4%) with 1 uncovered. Paragraph coverage is 24/25 (96.0%) and parity is 38/38 PASS.</figcaption> </figure> <p>On the 924-line CBSTM03A the loop reached 24/25 paragraphs (96.0%) and 37/38 transitions (97.4%). What deserves attention is the <strong>attribution</strong>: of the 37 covered transitions, Witness Search opened only 18 — Mutation opened the other 19. Similarly, 8 of the 24 covered paragraphs came from Mutation. Input-space search alone stalls at roughly half.</p> <p>Branch coverage tells a different story. Of the 146 branch probes, 38 remained uncovered, giving <strong>74.0%</strong>. The authors are explicit that Figures 3 and 4 report paragraph and transition coverage, not branch coverage. They add that with more patience and significant human intervention they could have done better, and that even at the current level they are exceeding any alternative method’s output they are aware of. They see no structural reason preventing 100% aside from the complexity of the mocking. They are also specific about the failure mode: the Authoring Layer failed to apply learnings from one skill to open the gates for a related scenario, and a human had to identify the issue. Their expectation is that autonomous coverage will improve incrementally as stronger models are released.</p> <p>All 38 accepted test cases passed the Parity Gate across the three axes.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig4-cfg-test-program-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig4-cfg-test-program-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig4-cfg-test-program-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig4-cfg-test-program.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 4: Control-flow graph of CBSTM03A. Nodes are paragraphs and edges are static paragraph-to-paragraph transitions. Node color marks the phase that first reached the paragraph; isolated blue/gray nodes are expected because sequential COBOL fall-through is not modeled as an explicit edge. Blue edges were observed by Witness Search, red ones after a mutation (red takes precedence on overlap), gray were not reached by this run.</figcaption> </figure> <p>Figure 4 makes the structure visible. As the authors describe it, blue is the first stage opened by Witness Search (input-space exploration), red is the result of Mutation, and gray is the uncovered portion. The fan of red edges converging on a single node near the bottom stands out: transitions observed only after a mutation are concentrated on one particular paragraph.</p> <h3 id="the-production-shape-run">The production-shape run</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig5-coverage-production-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig5-coverage-production-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig5-coverage-production-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig5-coverage-production.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 5: Coverage progression on the production-shape run. Of 146 static paragraph connections, the baseline Witness Search phase covers 54 (blue) and Mutation adds 47 (red), reaching T=101/146 (69.2%). Paragraph coverage is P=135/142 (95.1%) across 166 test cases.</figcaption> </figure> <p>The second experiment used a significantly larger production-grade program: 4,114 source lines, 142 paragraphs, 432 statically counted branches. Final numbers were <strong>135/142 paragraphs (95.1%)</strong>, <strong>101/146 transitions (69.2%)</strong>, and <strong>91.90% branch coverage (397/432)</strong>.</p> <p>The progression is especially clean. Witness Search reached P=110/142 and T=54/146; the Mutation phase added ΔP=+25 and ΔT=+47 before plateauing at P=135/142, T=101/146. By execution count, Witness Search contributed 61 raw executions and Mutation 105, for 166 combined — two thirds of the run happened in the Mutation phase, buying 47 additional transitions. <strong>Starting from an already-plateaued baseline, Mutation came within striking distance of Witness Search’s 54</strong>, which is the most direct number in the paper supporting its central claim.</p> <p>A parity check ran after every test case, and when discrepancies were detected a new set of fixes was proposed by the Authoring Layer and applied to the Migrator and/or the COBOL Mock Generator. The discrepancy types the authors enumerate: end-of-stream and termination semantics, control-flow fidelity, program-state and data-layout fidelity, data typing and value normalization, database and mock-backend behavioral equivalence, file I/O side-effect and ordering equivalence, fixture and environment consistency, and measurement and normalization artifact control. In the end the generated Java reproduced the COBOL behavior on every parity axis — <strong>166/166 PASS, 0 FAIL, 0 ERROR</strong> — and the loop progressed <em>without any human intervention</em>.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig6-cfg-production-480.webp 480w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig6-cfg-production-800.webp 800w,/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig6-cfg-production-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0034-agentic-method-for-deterministic-validation-of-legacy-code/fig6-cfg-production.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 6: Control-flow graph of the production program, with the same color conventions as Figure 4. COBOL fall-through semantics are omitted to reduce clutter, so not all execution paths appear in the DAG.</figcaption> </figure> <h2 id="analysis-and-ablation">Analysis and Ablation</h2> <h3 id="six-algorithms-hit-the-same-wall">Six algorithms hit the same wall</h3> <p>The most interesting observation is that all six Witness Search algorithms <strong>end at roughly the same coverage, within ±2–3 branches</strong>. Having also experimented with additional algorithms that were discarded for poor performance, the authors generalize that this boundary is <strong>structural rather than algorithmic</strong>: the remaining branches lie outside the input space the harness can express, and no search strategy will reach them.</p> <p>That observation is the hinge of the paper’s logic. The prescription (mutate the harness) is only justified by the diagnosis (more search budget will not help). Worth noting, though, that the same observation supports a second reading: if six algorithms produce the same answer, there is little reason to run all six. Post-Mutation Witness Search in fact uses UCB1 alone. The authors do not discuss this explicitly, but that design choice tacitly concedes the ensemble is redundant.</p> <h3 id="how-much-did-mutation-contribute">How much did Mutation contribute?</h3> <p>In both runs Mutation’s contribution matches or exceeds Witness Search’s.</p> <table> <thead> <tr> <th>Run</th> <th>Witness Search</th> <th>Mutation</th> <th>Uncovered</th> </tr> </thead> <tbody> <tr> <td>CBSTM03A (transitions)</td> <td>18/38</td> <td>+19/38</td> <td>1/38</td> </tr> <tr> <td>CBSTM03A (paragraphs)</td> <td>16/25</td> <td>+8/25</td> <td>1/25</td> </tr> <tr> <td>Production (transitions)</td> <td>54/146</td> <td>+47/146</td> <td>45/146</td> </tr> <tr> <td>Production (paragraphs)</td> <td>110/142</td> <td>+25/142</td> <td>7/142</td> </tr> </tbody> </table> <p>On CBSTM03A, the 19 transitions opened by Mutation outnumber the 18 opened by Witness Search; on the production run it is 47 against 54. As the authors put it honestly in the threats section, this is <em>case evidence</em> that the Mutation phase reaches paragraphs and transitions input-space search alone cannot — not a general claim about all COBOL systems.</p> <h3 id="depth-2-recursion-actually-fires">Depth-2 recursion actually fires</h3> <p>The paper reports one concrete demonstration of the recursion. After opening the depth-1 gates and proceeding with Witness Search, the agent opened the gates on a second layer, which triggered the six algorithms to find a new set of witnesses penetrating that layer too. Their phrasing captures the point well: Mutation’s value lies as much in the region it exposes as in the branches it directly unlocks.</p> <p>Defects detected during each pass are fixed <em>in the Migrator rather than in the produced code</em>, through Authoring Layer-proposed migrator fixes. That distinction matters in practice. Patching the output disappears on the next regeneration; patching the generator propagates to every program sharing the pattern.</p> <h3 id="the-shape-of-the-remaining-gaps">The shape of the remaining gaps</h3> <p>The production run plateaued short of 100% mainly due to structural and external-coupling complexities that the authors expect to require manual intervention. Inspecting the still-uncovered paragraphs revealed a consistent pattern: the remaining paths sit behind <strong>multi-step paragraph chains where control variables are set incrementally across earlier sections</strong>. To enter them, the tests must make the fake files and database return an exact coordinated sequence of results and flip internal switches early. It is not a single gate to unlock but a whole state sequence across time.</p> <p>In the conclusion the authors argue the remaining gaps reflect <strong>the current limits of the Authoring Layer rather than a structural limitation</strong> of the method. They arose from occasional mutation-authoring errors and failures to transfer learned strategies to related scenarios, and were resolved with human intervention. Their defense is that the deterministic core was designed to operate effectively even when the agentic layer needs human help.</p> <h2 id="limitations-and-critical-assessment">Limitations and Critical Assessment</h2> <h3 id="what-the-authors-acknowledge">What the authors acknowledge</h3> <ul> <li><strong>Small case-study scope.</strong> Two open-source programs and one production-shaped run. Replicating across additional program families — IMS, database-heavy SQL, CICS — would be needed to strengthen the claim.</li> <li><strong>Branch coverage is an imperfect proxy.</strong> A high-coverage suite need not detect all classes of fault, and a small set of well-chosen mutation-tested cases can find faults a higher-coverage suite misses — a tension long documented in the fuzzing-and-coverage literature. They mitigate it by anchoring acceptance on cross-language parity rather than coverage alone, but do not claim the resulting suite suffices on its own for migration sign-off. Their own phrasing — “a quantitatively comparable yardstick against the bare-baseline starting point, no more” — is exactly right.</li> <li><strong>Parity preserves bugs.</strong> Anchoring on the legacy COBOL as the operational reference means the loop validates whether the migrated Java reproduces the legacy behavior <em>including its bugs</em>. In a 1:1 migration this is the desired property, but as they put it, the operational reference is the truth of <em>compatibility</em>, not the truth of <em>semantics</em>. If the eventual goal is correctness verification, the Parity Gate alone is insufficient and an external specification oracle must be introduced.</li> <li><strong>Overfitting to harness structure.</strong> Locksmith can only learn from the source programs it has seen, so structures absent from the initial sample may not be captured.</li> <li><strong>The Parity Gate is only as strong as its axes.</strong> The three axes catch missing paragraph traversal, early termination, mis-set variables, and wrong dispatch order. They are silent on intermediate state between observable checkpoints, floating-point rounding modes that differ between COBOL and Java runtimes, and exception types raised by JVM-only error paths. A generated Java target could in principle pass while drifting on an axis they do not check.</li> </ul> <h3 id="what-else-a-reviewer-would-flag">What else a reviewer would flag</h3> <p><strong>No baseline comparison.</strong> The paper names the symbolic-execution-based COBOL-to-Java validation of Hans et al. and Kumar et al. as the closest prior work, then never runs head-to-head against it on the same programs. “We are exceeding any alternative method’s output that we are aware of” is an assertion, not a measurement. CBACT01C and CBSTM03A are public, so a comparison against EvoSuite-style tooling or existing COBOL test generators was not out of reach, and its absence is conspicuous.</p> <p><strong>Coverage is measured on a mutated program.</strong> This is the methodological tension at the core. The 91.90% figure is branch coverage of a <em>harness-mutated</em> binary, not the original. When a call-injection skill forces a paragraph to execute from a known point in the main flow, that proves the paragraph behaves identically in both languages — but it does <strong>not</strong> prove the paragraph is reachable under any real input, nor that the real control flow reaching it is identical. The Analyzer’s preference for dispatcher-based mutations is clearly meant to mitigate this, yet the split between dispatcher-based and call-injection-based coverage is never reported. That ratio is precisely the number that determines how to read the headline result.</p> <p><strong>The abstract’s coverage phrasing is generous.</strong> “Reaching nearly complete coverage on the two open-source programs” is true for paragraph and transition coverage (16/16, 28/28 and 24/25, 37/38), but CBSTM03A’s branch coverage is 74.0%. Because the same sentence reports “91.90% branch coverage” for the production program, a reader can easily carry the branch reading backward onto “nearly complete.” The body distinguishes the metrics carefully; the abstract does not.</p> <p><strong>Stochastic methods, single runs.</strong> ART, MAP-Elites, and UCB1 all use randomness. Each program was run once, with no seeds and no variance reported. Even the “six algorithms converge within ±2–3 branches” observation cannot be assessed for robustness without repetition.</p> <p><strong>No cost reporting.</strong> “The loop continued unattended for hours” is the whole account. No token cost, no wall-clock, no LLM call count, no model identity. The authors themselves list token-cost measurement as future work, so this reads more as not-yet-done than as omission — but it is the first number a practitioner evaluating adoption would want.</p> <p><strong>No policy or component ablation.</strong> The default Locked-Paragraph ranking policy (bang × feasibility) is described but the experiments used greedy, with no comparison between them. There is no breakdown of how much each of the two skill types contributed, and no study of dropping algorithms from the six-way ensemble. Which parts of the method actually carry the value remains undecomposed.</p> <p><strong><code class="language-plaintext highlighter-rouge">paragraphs_hit</code> is a set comparison.</strong> Entry <em>order</em> is not checked on that axis; ordering is only captured indirectly through <code class="language-plaintext highlighter-rouge">stub_log</code>. A Java target that reorders paragraphs which consume no external operations could in principle pass the gate. This belongs on the list of unchecked axes the authors give under (e).</p> <h2 id="takeaways">Takeaways</h2> <ul> <li><strong>When search stalls, suspect the boundary, not the budget.</strong> If six different search algorithms stop at the same place, that is not an algorithm problem — it is a signal that the input space the harness can express does not contain the answer. This diagnosis-prescription pair transfers to any test automation setting, COBOL or not.</li> <li><strong>Using an LLM as generator and a deterministic oracle as judge keeps winning.</strong> TestGen-LLM did it, and this paper does it again. The extra step here is placing the oracle <em>inside</em> the loop rather than at the end of the pipeline, running it after every mutation so bad edits never get time to accumulate.</li> <li><strong>The goal of legacy migration validation is compatibility, not correctness.</strong> Making that distinction explicit and designing the oracle around it is the paper’s most practical contribution. For the people who will maintain the Java after cutover, any drift from legacy behavior is a regression to investigate, not an improvement. The choice is also hard to reverse: moving to correctness verification requires a different oracle entirely.</li> <li><strong>Fix defects in the generator, not the generated code.</strong> Routing parity failures into the Migrator instead of patching the Java output looks like a detail, but it compounds at scale. Where the same COBOL idiom recurs across hundreds of programs, one generator fix propagates to all of them.</li> <li><strong>When you read a coverage number, ask which program it is about.</strong> Coverage obtained by mutating the harness is not coverage of the original program. This method defends the gap with parity, but anyone adopting it should track the share of forced-open paths as a separate figure.</li> </ul> <h2 id="references">References</h2> <ul> <li>Paper: <a href="https://arxiv.org/abs/2607.28271">arXiv:2607.28271 — Agentic Method for Deterministic Validation of Legacy Code Migration</a></li> <li>Open-source COBOL used in the experiments: <a href="https://github.com/aws-samples/aws-mainframe-modernization-carddemo">aws-samples/aws-mainframe-modernization-carddemo</a></li> </ul> <h2 id="further-reading">Further Reading</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2408.04660">XMainframe: A Large Language Model for Mainframe Modernization</a></strong> (Dau et al., 2024) — A pretrained LLM specialised for the mainframe domain, representative of the “read and translate COBOL” capability this paper takes as given.</li> <li><strong><a href="https://arxiv.org/abs/2604.03986">COBOL-Coder: Domain-Adapted Large Language Models for COBOL Code Generation and Translation</a></strong> (Dau et al., 2026) — Domain-adapted models and benchmarks for COBOL generation and translation; the kind of component that could sit in Locksmith’s Migrator slot.</li> <li><strong><a href="https://arxiv.org/abs/1504.04909">Illuminating search spaces by mapping elites</a></strong> (Mouret et al., 2015) — The original MAP-Elites paper behind one of the six Witness Search algorithms; fills a grid of behavioral diversity rather than chasing a single optimum.</li> <li><strong><a href="https://arxiv.org/abs/2410.04249">DiffSpec: Differential Testing with LLMs using Natural Language Specifications and Code Artifacts</a></strong> (Rao et al., 2024) — The LLM-assisted differential-testing lineage the Parity Gate belongs to, flagging output discrepancies between two implementations of one spec.</li> <li><strong><a href="https://arxiv.org/abs/2507.19275">Mut4All: Fuzzing Compilers via LLM-Synthesized Mutators Learned from Bug Reports</a></strong> (Wang et al., 2025) — LLMs synthesizing the mutators themselves; explicitly named in this paper’s future work as an integration target.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="software-testing"/><category term="agentic-systems"/><category term="legacy-migration"/><category term="cobol"/><category term="mutation-testing"/><category term="differential-testing"/><category term="search-based-testing"/><summary type="html"><![CDATA[American Express's Locksmith Loop: when input search stalls during COBOL-to-Java migration validation, mutate the harness itself to open new execution regions, apply the mutation symmetrically to both languages, and let a deterministic parity oracle decide what survives]]></summary></entry><entry xml:lang="ko"><title type="html">[논문 리뷰] RAGU: A Multi-Step GraphRAG Engine with a Compact Domain-Adapted LLM</title><link href="https://baba9811.github.io/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/" rel="alternate" type="text/html" title="[논문 리뷰] RAGU: A Multi-Step GraphRAG Engine with a Compact Domain-Adapted LLM"/><published>2026-08-20T05:00:00+00:00</published><updated>2026-08-20T05:00:00+00:00</updated><id>https://baba9811.github.io/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap</id><content type="html" xml:base="https://baba9811.github.io/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/en/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/" class="btn btn-sm btn-outline-secondary">🇺🇸 Read in English</a> </div> <h2 id="메타정보">메타정보</h2> <table> <thead> <tr> <th>항목</th> <th>내용</th> </tr> </thead> <tbody> <tr> <td>저자</td> <td>Mikhail Komarov et al. (저자 8명, ITMO University · Novosibirsk State University · Far Eastern Federal University)</td> </tr> <tr> <td>학회</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv 또는 DOI</td> <td><a href="https://arxiv.org/abs/2607.11683">2607.11683</a></td> </tr> <tr> <td>Code</td> <td><a href="https://github.com/RaguTeam/RAGU">RaguTeam/RAGU</a></td> </tr> <tr> <td>데이터</td> <td>GraphRAG-Bench (Medical) · BioASQ · MuSiQue · 2WikiMultiHopQA · NEREL 기반 IE 벤치마크 · MERA</td> </tr> <tr> <td><span style="white-space: nowrap">리뷰 일자</span></td> <td>2026-08-20</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>GraphRAG 시스템 대부분이 지식 그래프를 <strong>한 번의 LLM 추출 패스</strong>로 만든다. RAGU 는 추출 (extraction) 과 통합 (consolidation) 을 분리해, 2단계 타입 추출 → DBSCAN 기반 중복 제거 → LLM 요약 → Leiden 커뮤니티 탐지의 다단계 파이프라인으로 그래프를 만든다.</li> <li>논문의 진짜 주장은 엔진이 아니라 가설이다. RAG 파이프라인 안에서 LLM 이 하는 일 — 이해, 추출, 문맥 위에서의 추론 — 은 <strong>세계 지식이 아니라 언어 능력</strong>이고, 언어 능력은 파라미터 수에 훨씬 약하게 스케일한다. Qwen2.5-Instruct 계열에서 세계 지식 퀴즈 (CheGeKa) F1 은 0.5B→72B 에 21.1배 오르는데, 모든 사실이 문맥에 주어지는 MultiQ 는 4배에 그친다 (로그-선형 기울기 0.65 대 0.26).</li> <li>이 가설에 따라 7B 추출기 Meno-Lite-0.1 을 학습시켰다. 자체 IE 벤치마크 조화평균에서 Qwen2.5-32B 대비 상대 +12.5% (0.468 vs 0.416), 특히 관계 추출 F1 이 0.347 대 0.239 로 크게 앞선다.</li> <li>GraphRAG-Bench (Medical) 에서는 명확한 교차가 나온다. 단답 사실 검색은 HippoRAG 2 가 우세하지만 (AC 72.4 vs 54.2), 태스크가 합성 (synthesis) 쪽으로 갈수록 격차가 단조적으로 줄고 Creative Generation 에서 뒤집힌다 (AC 59.0 vs 56.9, Coverage 57.4 vs 34.7).</li> <li>multi-hop QA 에서 보이던 HippoRAG 2 의 큰 우위는 상당 부분 <strong>답변 포맷 아티팩트</strong>였다. 단답을 강제하면 2WikiMultiHopQA 격차가 −19.3pp 에서 −5.5pp 로 줄고 BioASQ 는 역전된다 (72.9 vs 72.4). 다만 MuSiQue 에서는 진짜 격차가 남는다 (54.4 vs 40.1).</li> </ul> <h2 id="소개-introduction">소개 (Introduction)</h2> <p>RAG (retrieval-augmented generation) 는 LLM 을 외부 지식에 접지시키는 표준 레시피가 됐지만, 전통적 RAG 는 평평한 청크를 꺼내올 뿐 문서를 가로지르는 엔티티 관계를 포착하지 못한다. GraphRAG 는 그 틈을 지식 그래프로 메운다. 문서에서 엔티티와 관계를 뽑아 그래프를 만들고, 검색 시점에 그래프를 순회해 흩어진 근거를 모은다. Microsoft GraphRAG 이후 LightRAG, HippoRAG 2 등이 이 방향을 밀었고, 이제는 “GraphRAG 를 쓸 것인가”보다 “언제 쓸 가치가 있는가”가 질문이 된 단계다.</p> <p>그런데 실제로 GraphRAG 를 프로덕션에 올려보면 세 가지가 걸린다. 첫째, 대부분의 시스템이 그래프 구축을 <strong>단일 LLM 추출 패스</strong>로 처리한다. 같은 인물이 청크마다 다른 표기로 등장하면 그냥 별개 노드가 되고, 이를 청크 경계 너머에서 합칠 장치가 없다. 결과는 노이즈가 많고 중복이 심한 그래프다. 둘째, 추출 품질이 그래프 품질을 결정한다는 이유로 실무자들은 기본값처럼 GPT-4 급 API 모델을 쓴다. 셋째, 오픈소스 프레임워크의 엔지니어링 성숙도가 낮다. 설치가 깨지거나, 심하면 LLM 원본 출력에 <code class="language-plaintext highlighter-rouge">eval()</code> 을 거는 코드 경로가 살아 있다.</p> <p>이 논문이 흥미로운 건 두 번째 장애물을 <strong>가정이 아니라 검증 대상</strong>으로 놓았다는 점이다. 저자들은 “추출 품질을 위해 큰 모델이 필요하다”는 통념이 잘못된 전제 위에 서 있다고 본다. RAG 파이프라인 안에서 LLM 이 실제로 하는 일은 문맥을 읽고, 엔티티를 뽑고, 설명을 요약하고, 주어진 문맥에서 답을 만드는 것이다. 전부 <em>언어 능력</em>이지 <em>사실 암기</em>가 아니다. 그리고 두 능력은 파라미터 수에 대해 전혀 다른 기울기로 자란다는 것이 이 논문의 출발점이다.</p> <p>그래서 논문은 세 가지를 한꺼번에 들고 나온다 — 가설, 그 가설에 맞춰 학습한 7B 추출 모델, 그리고 그 모델을 얹어 돌리는 모듈형 엔진. 시스템 데모 논문의 외형을 하고 있지만 실제로 읽을 가치가 있는 부분은 가설의 실증과, 그 가설이 downstream 에서 얼마나 (혹은 얼마나 안) 먹히는지에 대한 정직한 보고다.</p> <h2 id="핵심-기여-key-contributions">핵심 기여 (Key Contributions)</h2> <ul> <li><strong>Language/World Knowledge 가설.</strong> 세계 지식은 파라미터 수에 거의 선형에 가깝게 자라지만 언어 능력은 훨씬 완만하게 자란다는 가설을 세우고, Qwen2.5-Instruct 6개 크기에 걸쳐 MERA 벤치마크로 검증했다. 이 가설이 컴팩트 추출기라는 설계 선택 전체를 떠받친다.</li> <li><strong>Meno-Lite-0.1.</strong> RuadaptQwen2.5-7B-Lite-Beta 에서 파생한 7B 모델로, NEREL 스키마 기반 추출과 multi-hop QA 에 맞춰 continued pretraining + SFT 를 거쳤다. IE 벤치마크 조화평균에서 Qwen2.5-32B 를 상대 12.5% 앞선다.</li> <li><strong>RAGU 엔진.</strong> 추출과 통합을 분리한 6단계 인덱싱 파이프라인, 검색 엔진 5종, 교체 가능한 3계층 스토리지. <code class="language-plaintext highlighter-rouge">pip install graph_ragu</code> 로 설치되고 단일 GPU 에서 돈다. MIT 라이선스.</li> <li><strong>답변 포맷 교란 요인의 분리.</strong> multi-hop QA 에서 시스템 간 격차의 상당 부분이 답변 길이/형식 차이에서 온다는 것을 verbose/terse 두 프로토콜로 분리해 보였다. 리뷰어 입장에서 이 논문에서 가장 값어치 있는 실험이다.</li> <li><strong>엔지니어링 감사.</strong> HippoRAG 2 의 고정 커밋을 대상으로 <code class="language-plaintext highlighter-rouge">eval()</code> 호출 위치, <code class="language-plaintext highlighter-rouge">assert False</code> 제어 흐름, 스토리지 추상화 부재 등을 파일·라인 단위로 짚었다. 재현 가능한 형태의 비판이라는 점에서 드문 부록이다.</li> </ul> <h2 id="관련-연구--배경-지식">관련 연구 / 배경 지식</h2> <h3 id="graphrag-계보">GraphRAG 계보</h3> <p>Microsoft GraphRAG (Edge et al., 2024) 는 엔티티·관계를 뽑아 그래프를 만든 뒤 커뮤니티 탐지로 계층을 세우고, 커뮤니티 요약을 map-reduce 로 합쳐 “이 코퍼스의 주요 테마는?” 같은 전역 질문에 답한다. 강력하지만 인덱싱 시점의 LLM 호출량이 크다 — 뒤에 나오는 비용 표에서 문서당 40k 토큰이라는 숫자가 여기서 온다.</p> <p>LightRAG (Guo et al., 2025) 는 그 비용을 줄이는 방향이다. 자유 형식 단일 패스 추출로 그래프를 만들고 dual-level 검색 (low-level 엔티티 + high-level 테마) 으로 응답 속도를 확보한다. 대신 스키마 제약이 없어 추출 결과가 구조적으로 헐겁다. 이 논문의 GraphRAG-Bench 답변 품질 지표에서 LightRAG 가 네 난이도 전부 최하위인 것도 저자들은 여기서 설명한다.</p> <p>HippoRAG 2 (Gutiérrez et al., 2025) 는 접근이 다르다. 해마 기억 이론에서 착안해 personalized PageRank 로 그래프를 순회하는데, 이 방식은 <em>체인을 따라가는</em> 검색에 특히 강하다. 이 논문의 결과에서 HippoRAG 2 가 단답 사실과 MuSiQue 에서 앞서는 이유가 정확히 이것이다. Wikontic (Chepurova et al., 2026) 은 Wikidata 온톨로지에 정렬된 그래프를 만드는 쪽으로, 타입 제약을 건다는 점에서 RAGU 와 방향이 겹친다.</p> <h3 id="nerel-스키마">NEREL 스키마</h3> <p>RAGU 의 추출은 자유 형식이 아니라 <strong>NEREL 스키마</strong>에 묶여 있다. NEREL (Loukachevitch et al., 2021) 은 러시아어 뉴스 기사 900여 편에 중첩 개체명·관계·이벤트를 단 데이터셋으로, <strong>29개 엔티티 타입과 49개 관계 타입</strong>을 정의한다. RAGU 는 이 타입 집합을 추출기의 출력 공간으로 쓴다. 자유 형식 추출이 <code class="language-plaintext highlighter-rouge">"창시자"</code>, <code class="language-plaintext highlighter-rouge">"만든 사람"</code>, <code class="language-plaintext highlighter-rouge">"creator of"</code> 를 서로 다른 관계로 뱉는 문제를 스키마 단에서 없애는 셈이다.</p> <p>대가도 분명하다. NEREL 은 러시아어 뉴스 도메인용으로 만들어진 스키마다. 뒤에 나오는 Dennis Ritchie 예제에서 “C 언어를 만들었다”가 <code class="language-plaintext highlighter-rouge">WORKS_AS</code> 로 잡히는 것도, 49개 관계 타입 집합이 저작·창작 관계를 직접 담아내지 못한 결과로 보인다. 저자들도 Bias 절에서 이 스키마가 다른 언어·도메인에 적용될 때 조정이 필요할 수 있음을 인정한다.</p> <h3 id="mera--chegeka--multiq">MERA · CheGeKa · MultiQ</h3> <p>가설 검증에 쓰인 벤치마크들은 러시아어권 평가 스위트다. MERA (Fenogenova et al., 2024) 는 러시아어 LLM 종합 평가 벤치마크이고, 그 안의 CheGeKa 는 퀴즈쇼 문제 — 모델이 <em>기억</em>하고 있어야 답할 수 있는 세계 지식 태스크다. 반대로 MultiQ 는 답에 필요한 사실이 전부 문맥에 들어 있는 multi-hop QA 로, 순수하게 <em>읽고 조합하는</em> 능력만 본다. 이 대비가 논문의 핵심 그림을 만든다.</p> <h2 id="방법--아키텍처-상세">방법 / 아키텍처 상세</h2> <h3 id="언어-능력과-세계-지식의-스케일링-분리">언어 능력과 세계 지식의 스케일링 분리</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig1-scaling-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig1-scaling-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig1-scaling-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig1-scaling.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: Qwen2.5-Instruct 계열에서 모델 크기가 세계 지식 (CheGeKa) 과 언어 능력 (MultiQ) 에 미치는 영향. MultiQ 는 3B 부근에서 이미 대부분의 성능에 도달하고 32B 에서 포화해 72B 에서는 오히려 미세하게 내려간다. 반면 CheGeKa 는 72B 까지 계속 오른다.</figcaption> </figure> <p>논문의 첫 번째 그림이 사실상 논문 전체의 논증이다. 같은 모델 계열 (Qwen2.5-Instruct) 을 0.5B 부터 72B 까지 여섯 크기로 놓고 두 태스크의 F1 을 찍었다.</p> <ul> <li><strong>CheGeKa</strong> (세계 지식): F1 이 0.5B→72B 에서 <strong>21.1배</strong> 증가. 로그-선형 기울기 0.65.</li> <li><strong>MultiQ</strong> (문맥 내 사실 조합): 같은 구간에서 <strong>4배</strong>. 기울기 0.26.</li> </ul> <p>기울기 차이 자체보다 곡선 모양이 더 설득력 있다. MultiQ 는 3B 부근에서 이미 0.39 에 도달하고 32B 에서 0.58 로 포화한다. 72B 는 오히려 아주 살짝 내려간다. 반면 CheGeKa 는 끝까지 우상향한다. RAG 파이프라인 안의 LLM 이 하는 일이 MultiQ 쪽에 가깝다면, 32B 를 인덱싱에 쓰는 건 대부분 낭비라는 얘기다.</p> <h3 id="다단계-그래프-구축">다단계 그래프 구축</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig2-pipeline-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig2-pipeline-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig2-pipeline-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig2-pipeline.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: 엔드투엔드 인덱싱 파이프라인. 실선 화살표는 단계 간 데이터 흐름, 점선 화살표는 각 단계가 만들어내는 산출물이다. 산출물 (청크 · 엔티티/관계 · 커뮤니티 · 커뮤니티 요약) 이 전부 명시적으로 저장된다는 점이 증분 갱신과 감사 가능성의 기반이 된다.</figcaption> </figure> <p>RAGU 의 인덱싱은 6단계로 나뉘고 각 단계가 교체 가능한 컴포넌트다.</p> <p><strong>Step 1 — 청킹.</strong> 세 가지 전략을 제공한다. <code class="language-plaintext highlighter-rouge">SimpleChunker</code> (고정 크기 + 오버랩), <code class="language-plaintext highlighter-rouge">SemanticTextChunker</code> (임베딩 기반으로 분할 지점 결정), <code class="language-plaintext highlighter-rouge">SmartSemanticChunker</code> (cross-encoder 재순위화까지). 특별할 건 없지만 뒤 단계가 전부 청크 품질에 의존하므로 선택지를 열어둔 것.</p> <p><strong>Step 2 — 2단계 타입 추출.</strong> 여기가 첫 번째 핵심이다. 단일 패스 시스템과 달리 RAGU 는 엔티티 추출 (Stage 1) 과 관계 추출 (Stage 2) 을 분리한다.</p> <ol> <li>Stage 1 에서 엔티티를 먼저 뽑고 NEREL 스키마에 대해 검증한다.</li> <li>검증을 통과한 엔티티 집합을 Stage 2 의 <strong>제약 조건으로 되먹인다</strong>. 관계의 <code class="language-plaintext highlighter-rouge">source_entity</code> 와 <code class="language-plaintext highlighter-rouge">target_entity</code> 는 반드시 검증된 엔티티 이름과 일치해야 한다.</li> </ol> <p>이 되먹임이 없으면 LLM 은 관계를 만들면서 엔티티 이름을 슬쩍 바꾸거나 (같은 사람을 “Ritchie” 와 “Dennis Ritchie” 로), 존재하지 않는 엔티티를 관계의 끝점으로 만들어낸다. 그래프에 dangling edge 와 유령 노드가 생기는 전형적인 경로다. 단계를 나누고 제약을 거는 것만으로 이 클래스의 오류가 구조적으로 사라진다. 두 단계 모두에 ICL 예시를 주입할 수 있고, 예시 선택 전략은 semantic / BM25 / hybrid / random 중에서 고른다.</p> <p><strong>Step 3 — Consolidation.</strong> 두 번째 핵심이자 논문 제목의 “multi-step” 이 가리키는 단계다. <code class="language-plaintext highlighter-rouge">EntitySummarizer</code> 가 엔티티를 (이름, 타입) 으로 묶고, 중복 언급이 많은 엔티티에 대해서는 DBSCAN 클러스터링과 LLM 요약을 적용한다. <code class="language-plaintext highlighter-rouge">RelationSummarizer</code> 도 같은 패턴을 따른다.</p> <p>여기서 순서가 중요하다. <strong>커뮤니티 탐지 이전에</strong> 노이즈를 줄인다. 중복 노드가 남은 채로 Leiden 을 돌리면 같은 실체가 여러 노드로 쪼개진 상태에서 커뮤니티가 잡히므로, 커뮤니티 경계 자체가 오염된다. LightRAG 같은 단일 패스 시스템에 아예 없는 단계이고, 저자들이 성능 차이의 근원으로 지목하는 지점이기도 하다.</p> <p><strong>Steps 4–6 — 커뮤니티 탐지, 요약, 정제.</strong> 계층적 Leiden 클러스터링이 중복 제거된 그래프를 분할하고, LLM 이 각 커뮤니티에 대해 구조화된 리포트 (제목, 요약, findings) 를 만든다. 마지막으로 <code class="language-plaintext highlighter-rouge">RemoveIsolatedNodes</code> 같은 플러그형 모듈이 선택적으로 그래프를 정제한다.</p> <h3 id="검색-엔진-다섯-종">검색 엔진 다섯 종</h3> <p>인덱싱된 그래프 위에서 다섯 가지 검색 엔진이 돈다.</p> <table> <thead> <tr> <th>엔진</th> <th>동작</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">LocalSearch</code></td> <td>벡터 유사도로 엔티티를 찾고 관계·청크로 확장</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">GlobalSearch</code></td> <td>LLM 이 커뮤니티 요약을 평가·선별해 전역 질문에 답변</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">NaiveSearch</code></td> <td>그래프를 쓰지 않는 표준 벡터 RAG (내부 베이스라인)</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">MixSearch</code></td> <td>여러 엔진을 병렬로 돌려 결과 결합</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">QueryPlanEngine</code></td> <td>질의를 DAG 로 분해해 하위 질의를 순서대로 해결</td> </tr> </tbody> </table> <p>전부 cross-encoder 재순위화와 Qdrant 를 통한 dense+sparse 하이브리드 검색을 지원한다. 실험 표에 등장하는 <code class="language-plaintext highlighter-rouge">NaiveRAG</code> 행이 바로 이 <code class="language-plaintext highlighter-rouge">NaiveSearchEngine</code> 이라는 점이 중요하다 — 같은 생성 프롬프트를 공유하는 내부 대조군이므로, RAGU 대 NaiveRAG 비교는 프롬프트 차이가 제거된 순수 그래프 효과를 본다.</p> <h3 id="엔지니어링">엔지니어링</h3> <p>시스템 논문답게 엔지니어링에 한 절을 통째로 쓴다. 요약하면 네 가지다.</p> <ol> <li><strong>3계층 스토리지 추상화</strong> (graph / KV / vector) 와 라이프사이클 콜백. 백엔드 교체가 생성자 인자 변경으로 끝난다 — NetworkX→Neo4j, NanoVDB→Qdrant.</li> <li><strong>async-first API</strong> 와 bounded concurrency. 세마포어로 동시 호출을 제한해 API rate limit 아래에서 안전한 처리량을 낸다.</li> <li><strong>Pydantic v2 로 검증되는 구조화 출력.</strong> LLM 응답을 수동 JSON 후처리하지 않고, 코드 인젝션 경로도 차단한다.</li> <li><strong>증분 upsert/update/delete</strong> 와 결정적 해시 기반 ID, 병합 정책, 그리고 스토어 간 정합성을 검사하는 consistency auditor.</li> </ol> <p>여기에 약 374개의 테스트와 결정적 mock LLM 서버가 붙어 있어 API 키 없이 CI 를 돌릴 수 있다. 모든 도메인 객체 (엔티티, 관계, 청크) 가 결정적 MD5 식별자를 갖기 때문에 검색 결과를 원문까지 역추적할 수 있다.</p> <h3 id="meno-lite-01">Meno-Lite-0.1</h3> <p>가설을 실물로 만든 부분이다. RuadaptQwen2.5-7B-Lite-Beta (Tikhomirov and Chernyshev, 2025) 에서 출발해 두 단계를 거쳤다.</p> <ul> <li><strong>Continued pretraining</strong>: 1.3B 토큰. 러시아어·영어 교육/과학 텍스트.</li> <li><strong>Supervised fine-tuning</strong>: 50M 토큰. NEREL 기반 추출, multi-hop QA (MultiHop-RAG, mtRAG), 질의 로그.</li> </ul> <p>일반 목적 LLM 과의 결정적 차이는 instruction 설계에 있다. <strong>사실을 기억해 답하는 게 아니라 문맥을 사용해 답하도록</strong> 가르친다. 컴퓨트를 세계 지식이 아니라 언어 능력에 투자한다는 가설의 직접 구현이다.</p> <p>주요 속성:</p> <table> <thead> <tr> <th>속성</th> <th>값</th> </tr> </thead> <tbody> <tr> <td>파라미터</td> <td>7B</td> </tr> <tr> <td>컨텍스트 윈도우</td> <td>128K (128K 지점 passkey retrieval 0.98)</td> </tr> <tr> <td>토크나이저 효율 (러시아어)</td> <td>3.77 chars/token — vanilla Qwen2.5 의 2.57 대비 47% 개선</td> </tr> <tr> <td>서빙</td> <td>vLLM, 단일 컨슈머 GPU</td> </tr> <tr> <td>라이선스</td> <td>Apache 2.0</td> </tr> </tbody> </table> <h2 id="학습-목표--손실-함수">학습 목표 / 손실 함수</h2> <p>이 논문은 새로운 손실 함수를 제안하지 않는다. Meno-Lite-0.1 의 학습은 표준적인 causal LM 목적 — continued pretraining 과 SFT 모두 다음 토큰 예측의 cross-entropy — 로 진행되고, 새로움은 손실의 형태가 아니라 <strong>어떤 데이터에 그 손실을 걸었는가</strong>에 있다. 그러니 이 절에서 정식화할 가치가 있는 건 손실이 아니라 논문이 세운 스케일링 가설 쪽이다.</p> <p>파라미터 수 $N$ 에 대한 태스크 성능 $F_1$ 을 로그-선형 모델로 놓으면</p> \[\begin{aligned} \log F_1 &amp;= \alpha \log N + c, \\ \alpha_{\text{CheGeKa}} &amp;= 0.65, \\ \alpha_{\text{MultiQ}} &amp;= 0.26 \end{aligned}\] <p>가 된다. 여기서 $\alpha$ 는 <em>파라미터를 두 배로 늘렸을 때 성능이 몇 배가 되는가</em>를 지배하는 지수다. 세계 지식 태스크의 $\alpha$ 가 언어 능력 태스크의 2.5배라는 것이 논문의 정량적 주장이고, 실제 관측된 배율 (21.1배 대 4배, 파라미터는 144배) 과도 대략 들어맞는다.</p> <p>여기서 파생되는 설계 원칙은 단순하다. 파이프라인 안의 어떤 컴포넌트가 요구하는 능력이 $\alpha$ 가 작은 쪽에 속한다면, 그 컴포넌트에는 작은 모델을 붙여야 한다. RAG 인덱싱 — 청크를 읽고 엔티티를 뽑고 설명을 요약하는 일 — 은 전부 $\alpha$ 가 작은 쪽이다. 반면 답변 생성 단계는 사용자 질의에 따라 세계 지식이 섞여 들어올 수 있으므로 논문도 여기는 gpt-4o-mini 를 쓴다. 즉 이 가설은 “작은 모델로 다 된다”가 아니라 <strong>“파이프라인 단계별로 필요한 능력의 종류가 다르니 모델도 달라야 한다”</strong>에 가깝다.</p> <h2 id="학습-데이터와-파이프라인">학습 데이터와 파이프라인</h2> <h3 id="meno-lite-01-학습-구성">Meno-Lite-0.1 학습 구성</h3> <table> <thead> <tr> <th>단계</th> <th>데이터</th> <th>규모</th> </tr> </thead> <tbody> <tr> <td>베이스</td> <td>RuadaptQwen2.5-7B-Lite-Beta</td> <td>7B</td> </tr> <tr> <td>Continued pretraining</td> <td>러시아어·영어 교육/과학 텍스트 (FineWeb-Edu, RuLM 등)</td> <td>1.3B 토큰</td> </tr> <tr> <td>SFT</td> <td>NEREL 기반 추출 · MultiHop-RAG · mtRAG · 질의 로그 · GPT-4o-mini 합성 instruction</td> <td>50M 토큰</td> </tr> </tbody> </table> <p>학습 코퍼스는 전부 공개 데이터셋이고, 저자들은 개인 식별 정보가 포함되지 않았음을 명시한다. IE 벤치마크는 NEREL 의 test-only 파생물로 MIT 라이선스이며 LM Evaluation Harness 에 <code class="language-plaintext highlighter-rouge">nerel-bench</code> 태스크 그룹으로 통합돼 있다.</p> <h3 id="평가-setup">평가 setup</h3> <table> <thead> <tr> <th>항목</th> <th>설정</th> </tr> </thead> <tbody> <tr> <td>벤치마크</td> <td>GraphRAG-Bench (Medical), BioASQ, MuSiQue, 2WikiMultiHopQA</td> </tr> <tr> <td>답변 생성 LLM</td> <td>gpt-4o-mini (전 시스템 공통, 고정)</td> </tr> <tr> <td>그래프 구축 LLM</td> <td>독립 변수 — Meno-Lite-0.1 (7B), gpt-oss-20b, Qwen2.5-7B</td> </tr> <tr> <td>임베딩</td> <td>bge-large-en-v1.5 (GraphRAG-Bench) / gte-multilingual-base (multi-hop QA)</td> </tr> <tr> <td>LLM-as-judge</td> <td>google/gemini-3-flash-preview</td> </tr> <tr> <td>지표</td> <td>Answer Correctness (AC), ROUGE-L, Coverage, Faithfulness, Evidence Recall (ER), Context Relevancy</td> </tr> </tbody> </table> <p>설계에서 눈여겨볼 점 두 가지. 답변 생성 LLM 을 전 시스템에 고정해 <strong>그래프 구축 품질만 분리</strong>했고, judge 모델을 생성 모델과 다른 계열로 잡아 evaluator–generator 중첩을 피했다. 후자는 LLM-as-judge 실험에서 자주 빠뜨리는 통제인데 명시적으로 챙겼다.</p> <h2 id="실험-결과">실험 결과</h2> <h3 id="graphrag-bench-medical">GraphRAG-Bench (Medical)</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab1-main-results-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab1-main-results-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab1-main-results-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab1-main-results.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 1: GraphRAG-Bench (Medical) 생성 품질. 같은 시스템의 두 행은 인덱싱 LLM 만 다르다. 인덱싱 LLM 을 Qwen2.5-7B 에서 Meno-Lite-0.1 로 바꿔도 어떤 시스템에서든 수치가 거의 움직이지 않는다는 점에 주목.</figcaption> </figure> <p>GraphRAG-Bench 는 난이도가 올라가는 네 단계로 구성된다 — Fact Retrieval, Complex Reasoning, Contextual Summarize, Creative Generation. 결과를 Answer Correctness 기준으로 보면 깨끗한 교차가 나온다.</p> <table> <thead> <tr> <th>난이도</th> <th>HippoRAG 2</th> <th>RAGU</th> <th>격차</th> </tr> </thead> <tbody> <tr> <td>Fact Retrieval</td> <td>72.4</td> <td>54.2</td> <td>−18.2 pp</td> </tr> <tr> <td>Complex Reasoning</td> <td>68.4</td> <td>53.7</td> <td>−14.7 pp</td> </tr> <tr> <td>Contextual Summarize</td> <td>65.0</td> <td>64.1</td> <td>−0.9 pp</td> </tr> <tr> <td>Creative Generation</td> <td>56.9</td> <td>59.0</td> <td><strong>+2.1 pp</strong></td> </tr> </tbody> </table> <p>(모두 Meno-Lite-0.1 을 인덱싱 LLM 으로 쓴 행)</p> <p>Coverage — 관련 자료를 <em>빠짐없이</em> 가져왔는지를 직접 보상하는 지표 — 로 넘어가면 격차가 더 크게 벌어진다. Creative Generation 에서 RAGU 57.4 대 HippoRAG 2 34.7, Contextual Summarize 에서 71.1 대 51.7. Faithfulness 도 34.2 대 26.6 으로 RAGU 가 앞선다. LightRAG 는 전 구간에서 최하위인데 (Creative Generation AC 14.4, Coverage 3.9), 저자들은 이를 자유 형식 단일 패스 추출이 만든 구조적으로 빈약한 그래프의 결과로 읽는다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig3-crossover-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig3-crossover-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig3-crossover-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig3-crossover.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: 태스크 복잡도에 따른 교차. (a) Answer Correctness 에서 HippoRAG 2 (주황) 와 RAGU (파랑) 의 간격이 왼쪽에서 오른쪽으로 갈수록 좁아지다가 마지막에 뒤집힌다. (b) Evidence Recall 은 factoid 세 구간에서 RAGU 가 가장 높지만, Creative Generation 에서는 LightRAG 가 59.9 로 가장 높다.</figcaption> </figure> <p>Evidence Recall 이 메커니즘 쪽 증거다. Fact Retrieval 에서 RAGU 82.4, LightRAG 76.1, HippoRAG 2 75.6. 같은 시스템 순서 (RAGU / LightRAG / HippoRAG 2) 로 Complex Reasoning 74.5 / 71.3 / 66.7, Contextual Summarize 74.8 / 70.2 / 71.8. 즉 <strong>RAGU 가 가장 완전한 근거 집합을 가져오고도 단답 정확도에서는 진다</strong>. 저자들은 이를 HippoRAG 2 의 체인 순회가 단일 사실 질의에서 갖는 <em>정밀도</em>로 설명한다. 넓게 긁어오는 전략과 정확히 찍는 전략의 차이이고, 지표에 따라 승자가 갈리는 게 당연한 구도다.</p> <h3 id="multi-hop-qa--포맷-아티팩트의-분리">Multi-hop QA — 포맷 아티팩트의 분리</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab2-multihop-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab2-multihop-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab2-multihop-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab2-multihop.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 2: (a) verbose 프롬프트에서는 HippoRAG 2 가 전 열을 지배하지만, (b) terse 프롬프트로 통제하면 BioASQ 는 역전되고 2WikiMultiHopQA 격차는 1/4 이하로 줄어든다. HippoRAG 2 행이 두 패널에서 동일한 것은 기본 프롬프트가 이미 단답을 내기 때문이다.</figcaption> </figure> <p>이 실험이 논문에서 가장 잘 설계된 부분이다. BioASQ, MuSiQue, 2WikiMultiHopQA 는 정답이 짧은 순수 factoid QA 다. 이런 벤치마크에서는 <strong>답변 형식이 overlap 기반 지표를 강하게 흔든다</strong>. 저자들은 두 프로토콜로 나눠 보고했다.</p> <p><strong>(a) verbose — 각 시스템 기본 프롬프트.</strong> HippoRAG 2 가 전 열을 지배한다. BioASQ AC 74.1 대 RAGU 56.0. 그런데 ROUGE-L 을 같이 보면 12.2 대 48.8 이다. RAGU 의 장문 답변이 단답 정답과 표면적으로 겹치지 않으면서 ROUGE-L 과 AC 를 동시에 끌어내린 것이다.</p> <p><strong>(b) terse — 단답 강제.</strong> 그림이 크게 바뀐다.</p> <table> <thead> <tr> <th>벤치마크</th> <th>HippoRAG 2</th> <th>RAGU (GPT)</th> <th>verbose 격차 → terse 격차</th> </tr> </thead> <tbody> <tr> <td>BioASQ</td> <td>72.4</td> <td><strong>72.9</strong></td> <td>−18.1 pp → +0.5 pp</td> </tr> <tr> <td>2WikiMultiHopQA</td> <td>63.5</td> <td>58.0</td> <td>−19.3 pp → −5.5 pp</td> </tr> <tr> <td>MuSiQue</td> <td>54.4</td> <td>40.1</td> <td>−12.8 pp → −14.3 pp</td> </tr> </tbody> </table> <p>BioASQ 는 역전되고 2WikiMultiHopQA 는 격차가 1/4 이하로 줄어든다. 반면 <strong>MuSiQue 에서는 격차가 오히려 조금 커진다</strong>. 저자들은 이를 진짜 능력 차이로 인정한다 — MuSiQue 는 가장 어려운 multi-hop 벤치마크이고, personalized PageRank 의 체인 추적이 통합 기반 검색으로는 표면화되지 않는 경로를 따라간다는 것이다. 자기 시스템이 지는 구간을 포맷 탓으로 돌리지 않고 남겨둔 점은 신뢰를 준다.</p> <p>또 하나. RAGU 를 gpt-oss-20b (20B) 로 인덱싱한 결과와 Meno-Lite-0.1 (7B) 로 인덱싱한 결과의 차이가 1–2pp 에 불과하다. 20B 를 7B 로 갈아끼워도 downstream 이 거의 안 움직인다는 뜻이고, 이게 가설의 실전 검증이다.</p> <h3 id="ie-벤치마크--모델-자체의-성능">IE 벤치마크 — 모델 자체의 성능</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab3-ie-bench-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab3-ie-bench-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab3-ie-bench-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab3-ie-bench.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 3: IE 벤치마크. Meno-Lite-0.1 의 우위가 거의 전적으로 RE (관계 추출) 열에서 나온다는 점이 중요하다. NER 과 정의 생성에서는 오히려 대형 모델들이 앞선다.</figcaption> </figure> <p>파이프라인이 아니라 추출 모델 자체를 재는 벤치마크다. Meno-Lite-0.1 (7B) 이 조화평균 0.468 로 1위, Qwen2.5-32B 가 0.416 으로 2위 — 상대 +12.5%.</p> <p>그런데 열별로 뜯어보면 이야기가 더 구체적이다.</p> <table> <thead> <tr> <th>모델</th> <th>크기</th> <th>NER</th> <th>Def</th> <th>RE</th> <th>RDef</th> <th>HM</th> </tr> </thead> <tbody> <tr> <td>Meno-Lite-0.1</td> <td>7B</td> <td>0.504</td> <td>0.527</td> <td><strong>0.347</strong></td> <td>0.558</td> <td><strong>0.468</strong></td> </tr> <tr> <td>Qwen2.5-32B</td> <td>32B</td> <td>0.536</td> <td>0.528</td> <td>0.239</td> <td>0.599</td> <td>0.416</td> </tr> <tr> <td>gemma-3-27b</td> <td>27B</td> <td>0.544</td> <td>0.482</td> <td>0.224</td> <td>0.583</td> <td>0.396</td> </tr> <tr> <td>Qwen2.5-14B</td> <td>14B</td> <td>0.510</td> <td>0.518</td> <td>0.222</td> <td>0.583</td> <td>0.396</td> </tr> <tr> <td>Qwen2.5-7B</td> <td>7B</td> <td>0.477</td> <td>0.479</td> <td>0.192</td> <td>0.541</td> <td>0.356</td> </tr> <tr> <td>T-lite-1.0</td> <td>7B</td> <td>0.466</td> <td>0.464</td> <td>0.174</td> <td>0.533</td> <td>0.336</td> </tr> </tbody> </table> <p><strong>Meno-Lite-0.1 의 우위는 사실상 RE 한 열에서 나온다.</strong> NER (0.504) 은 gemma-3-27b (0.544) 와 Qwen2.5-32B (0.536) 보다 낮고, 관계 정의 (RDef) 도 0.558 로 32B 의 0.599 에 못 미친다. 반면 관계 추출 F1 은 0.347 로 2위인 32B 의 0.239 를 45% 상회한다. 저자들은 관계 추출이 언어 이해 의존도가 가장 높은 하위 태스크라고 설명하지만, NEREL 로 SFT 를 한 모델이 NEREL 스키마 관계 추출에서 앞서는 것은 도메인 적응 효과와 구분하기 어렵다. 저자들도 한계 절에서 이 분포 중첩을 인정한다.</p> <p>MERA 전체 점수는 0.555, LIBRA 128K 지점 passkey retrieval 은 0.98 이다. 긴 컨텍스트 처리는 견고하다는 뜻인데, 뒤의 한계 절에서 “multi-hop 추론은 32K 를 넘으면 떨어진다”고 따로 밝히는 것과 함께 읽어야 한다. passkey 를 찾는 것과 긴 문맥에서 추론하는 것은 다른 능력이다.</p> <h3 id="사례-연구--한-문단이-그래프가-되기까지">사례 연구 — 한 문단이 그래프가 되기까지</h3> <p>논문은 저장소에 들어 있는 예제 스크립트로 파이프라인 전체를 한 문단 위에서 시연한다. 입력은 이렇다.</p> <blockquote> <p>Dennis Ritchie, the creator of the C programming language, and the co-creator of the Unix operating system, died on October 12, 2011, at the age of 70. His father, Alistair E. Ritchie, worked for many years at Bell Laboratories in Murray Hill, New Jersey.</p> </blockquote> <p><strong>Stage 1 (엔티티).</strong> NEREL 스키마 아래에서 타입이 붙은 엔티티 9개가 나온다.</p> <table> <thead> <tr> <th>엔티티</th> <th>NEREL 타입</th> </tr> </thead> <tbody> <tr> <td>Dennis Ritchie</td> <td><code class="language-plaintext highlighter-rouge">PERSON</code></td> </tr> <tr> <td>Alistair E. Ritchie</td> <td><code class="language-plaintext highlighter-rouge">PERSON</code></td> </tr> <tr> <td>C Programming Language</td> <td><code class="language-plaintext highlighter-rouge">PRODUCT</code></td> </tr> <tr> <td>Unix Operating System</td> <td><code class="language-plaintext highlighter-rouge">PRODUCT</code></td> </tr> <tr> <td>Bell Laboratories</td> <td><code class="language-plaintext highlighter-rouge">ORGANIZATION</code></td> </tr> <tr> <td>October 12, 2011</td> <td><code class="language-plaintext highlighter-rouge">DATE</code></td> </tr> <tr> <td>70</td> <td><code class="language-plaintext highlighter-rouge">AGE</code></td> </tr> <tr> <td>Murray Hill</td> <td><code class="language-plaintext highlighter-rouge">DISTRICT</code></td> </tr> <tr> <td>New Jersey</td> <td><code class="language-plaintext highlighter-rouge">STATE_OR_PROV</code></td> </tr> </tbody> </table> <p><strong>Stage 2 (관계).</strong> 이 검증된 엔티티 집합만을 끝점으로 삼아 관계 8개를 뽑는다. 논문에 표시된 다섯 개는 <code class="language-plaintext highlighter-rouge">Dennis Ritchie —WORKS_AS→ C Programming Language</code>, <code class="language-plaintext highlighter-rouge">Dennis Ritchie —WORKS_AS→ Unix Operating System</code>, <code class="language-plaintext highlighter-rouge">Dennis Ritchie —DATE_OF_DEATH→ October 12, 2011</code>, <code class="language-plaintext highlighter-rouge">Alistair E. Ritchie —PARENT_OF→ Dennis Ritchie</code>, <code class="language-plaintext highlighter-rouge">Bell Laboratories —LOCATED_IN→ Murray Hill</code> 이다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig4-knowledge-graph-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig4-knowledge-graph-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig4-knowledge-graph-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig4-knowledge-graph.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 4: 한 문단에서 만들어진 지식 그래프. Leiden 클러스터링이 이 9-엔티티 그래프를 두 커뮤니티로 나눈다 — Dennis Ritchie 와 그의 창작물 (5 엔티티, 4 관계), 그리고 Bell Laboratories · Murray Hill · New Jersey · Alistair Ritchie 를 공간·직업적 연결로 묶은 쪽 (4 엔티티, 3 관계). 두 커뮤니티를 잇는 것은 PARENT_OF 엣지 하나다.</figcaption> </figure> <p><strong>커뮤니티와 검색.</strong> Leiden 클러스터링이 그래프를 두 커뮤니티로 분할하고 LLM 이 각각에 구조화된 요약을 붙인다. 그 위에서 <code class="language-plaintext highlighter-rouge">LocalSearchEngine</code> 은 여러 엣지를 타야 답할 수 있는 질문에 답한다 — “C 언어를 만든 사람의 아버지는 어디서 일했나?” 에 대해 <code class="language-plaintext highlighter-rouge">PARENT_OF</code> 와 <code class="language-plaintext highlighter-rouge">WORKPLACE</code> 를 연달아 타고 Bell Laboratories 를 반환하는 식이다.</p> <p>작은 예제지만 두 가지가 보인다. 하나는 2단계 추출이 실제로 무엇을 막는가 — 관계의 끝점이 전부 Stage 1 에서 확정된 이름이므로 “Ritchie” 같은 부분 표기가 별도 노드로 새어 나가지 않는다. 다른 하나는 타입 스키마의 대가다. <strong>“C 언어를 만들었다”가 <code class="language-plaintext highlighter-rouge">WORKS_AS</code> 로 잡힌다.</strong> 사람이 읽기에 명백히 부정확하지만, 스키마가 강제하는 49개 관계 타입 안에서는 이게 가장 가까운 선택지였을 것이다. 일관성을 얻는 대신 표현력을 내주는 거래이고, 논문은 이 지점을 정면으로 다루지 않는다.</p> <h2 id="결과-분석--ablation">결과 분석 / Ablation</h2> <h3 id="파인튜닝의-이득은-어디로-갔나">파인튜닝의 이득은 어디로 갔나</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab7-ablation-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab7-ablation-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab7-ablation-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab7-ablation.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 7: RAGU 설정별 ablation. ICL 유무, 검증 유무, 인덱싱 모델을 어떻게 조합해도 네 난이도 전부에서 AC 변동이 2pp 를 넘지 않는다. Qwen2.5-3B 로 내려도 마찬가지다.</figcaption> </figure> <p>Ablation 표를 보면 이 논문에서 가장 흥미로운 긴장이 드러난다.</p> <ul> <li>인덱싱 모델을 <strong>3B 에서 14B 까지</strong> 바꿔도 AC 변동은 1.5pp 이하.</li> <li>ICL 예시 주입과 엔티티 검증을 켜고 끄는 것도 각각 1pp 미만.</li> <li><strong>Meno-Lite-0.1 과 Qwen2.5-7B 는 모든 설정에서 1pp 이내.</strong></li> </ul> <p>IE 벤치마크에서 Qwen2.5-32B 를 12.5% 앞섰던 모델이, 엔드투엔드 QA 에서는 스톡 Qwen2.5-7B 와 구분되지 않는다. 그리고 이 현상은 RAGU 뿐 아니라 HippoRAG 2 와 LightRAG 파이프라인에서도 똑같이 나타난다 (Table 1 의 각 시스템 두 행을 비교해 보면 확인된다).</p> <p>저자들의 해석은 이렇다 — 이건 파인튜닝의 실패가 아니라, <strong>통합 단계가 있으면 GraphRAG QA 품질이 추출기 선택에 대해 상당히 강건해진다</strong>는 증거다. Meno-Lite-0.1 은 7B 비용으로 32B급 추출을 제공하고, 통합 파이프라인은 downstream 강건성을 제공하니 둘은 상보적이라는 것.</p> <p>프레이밍으로는 매끄럽지만, 뒤집어 읽으면 이 논문의 두 기여물이 서로를 약화시킨다. 파이프라인이 추출기 품질에 강건하다면 굳이 전용 추출기를 학습시킬 이유가 약해지고, 반대로 추출기가 그렇게 좋다면 파이프라인이 그 이득을 downstream 으로 전달하지 못하고 있는 것이다. 논문은 전자를 택했지만, 실무자 입장에서는 <strong>“통합 파이프라인만 제대로 있으면 인덱싱 모델은 3B 짜리로 충분하다”</strong>가 더 실용적인 결론일 수 있다. 그리고 그건 저자들의 가설을 오히려 더 강하게 지지한다.</p> <h3 id="넓게-긁기-vs-정확히-찍기">넓게 긁기 vs 정확히 찍기</h3> <p>Evidence Recall 과 Answer Correctness 가 갈라지는 현상도 짚을 만하다. Fact Retrieval 에서 RAGU 는 근거를 82.4% 회수하고도 AC 54.2 에 그치는 반면, HippoRAG 2 는 75.6% 만 회수하고 AC 72.4 를 낸다. 근거를 더 많이 가져오는 것이 단답 정확도로 이어지지 않는다는 뜻이다.</p> <p>이건 검색 자체보다 <strong>생성 단계의 문제</strong>일 가능성이 높다. 넓은 컨텍스트가 gpt-4o-mini 에게 주어졌을 때 단답을 뽑아내는 대신 관련은 있지만 초점이 어긋난 정보를 섞을 여지가 커진다. terse 프롬프트 실험이 정확히 이 지점을 건드린다 — 검색 결과는 그대로 두고 생성 지시만 조였을 뿐인데 RAGU 의 BioASQ AC 가 56.0 에서 72.9 로 17pp 가까이 뛴다. 같은 컨텍스트에서 답을 뽑아내는 방식만 바꿔도 이 정도가 움직인다면, GraphRAG-Bench 의 factoid 구간 격차 역시 순수한 검색 능력 차이로만 읽어서는 안 된다. 논문이 이 두 실험을 연결해 해석하지 않은 것은 아쉽다.</p> <h3 id="엔지니어링-비교">엔지니어링 비교</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab6-engineering-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab6-engineering-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab6-engineering-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab6-engineering.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 6: 프로덕션 리스크별로 정리한 엔지니어링 비교. 각 행이 '이 속성이 없으면 무엇이 터지는가'로 이름 붙어 있다는 점이 이 표를 단순 기능 체크리스트와 구분한다.</figcaption> </figure> <p>부록 A 의 비교표는 기능 나열이 아니라 <strong>프로덕션 리스크</strong>별로 조직돼 있다. 크래시 시 데이터 유실, 백엔드 마이그레이션 비용, API 처리량, LLM 출력에서의 코드 실행, 일시적 장애 복구, 회귀 탐지, 증분 유지보수, 재현 가능한 배포, 모듈성.</p> <p>저자들이 특히 강조하는 두 가지는 실제로 심각하다.</p> <ol> <li><strong><code class="language-plaintext highlighter-rouge">eval()</code> 호출.</strong> HippoRAG 2 는 LLM 원본 응답을 정규식으로 필터링한 부분 문자열에 파이썬 <code class="language-plaintext highlighter-rouge">eval()</code> 을 건다 (<code class="language-plaintext highlighter-rouge">openie_openai.py:36,88</code>). 모델이 적대적 내용을 뱉으면 임의 코드 실행 표면이 되고, 구문이 조금만 어긋나도 호출 지점에서 멀리 떨어진 곳에서 불투명한 예외가 난다.</li> <li><strong><code class="language-plaintext highlighter-rouge">assert False</code> 를 제어 흐름으로 사용.</strong> 오프라인 인덱싱 경로가 <code class="language-plaintext highlighter-rouge">assert False</code> 로 종료되는데 (<code class="language-plaintext highlighter-rouge">HippoRAG.py:216</code>), <code class="language-plaintext highlighter-rouge">python -O</code> 로 실행하면 assertion 이 제거되어 파이프라인 나머지가 기대하는 온라인 vLLM 서버 없이 <strong>조용히 인덱싱으로 진행된다</strong>. 프로덕션에서 가장 나쁜 종류의 버그다.</li> </ol> <p>모든 주장이 커밋 <code class="language-plaintext highlighter-rouge">d437bfb1</code> (2025-09-04) 기준 파일·라인으로 고정돼 있어 재현 검증이 가능하다. 다만 이건 경쟁 시스템 저자가 쓴 비교표라는 점은 감안해야 한다.</p> <h3 id="비용">비용</h3> <p>인덱싱 비용은 문서당 일회성이고 질의 시점 답변 생성 비용과 분리해서 봐야 한다 (답변 생성은 전 시스템이 gpt-4o-mini 로 동일).</p> <table> <thead> <tr> <th>시스템</th> <th>인덱싱 모델</th> <th>토큰/문서</th> <th>문서당 비용</th> </tr> </thead> <tbody> <tr> <td>MS-GraphRAG (global)</td> <td>gpt-4o (API)</td> <td>~40k</td> <td>~USD 0.10</td> </tr> <tr> <td>HippoRAG 2</td> <td>gpt-oss-20b (local)</td> <td>~6k</td> <td>고정 GPU 비용</td> </tr> <tr> <td>LightRAG</td> <td>gpt-oss-20b (local)</td> <td>~8k</td> <td>고정 GPU 비용</td> </tr> <tr> <td>RAGU + Meno-Lite-0.1</td> <td>Meno-Lite-0.1 (local)</td> <td>~8k</td> <td>고정 GPU 비용</td> </tr> </tbody> </table> <p>10만 문서 규모에서 MS-GraphRAG 약 USD 10,000 대 RAGU 약 USD 100. 다만 표를 정확히 읽으면 이 비교는 <strong>로컬 서빙 대 API 서빙</strong>의 차이지 RAGU 고유의 이득이 아니다. HippoRAG 2 와 LightRAG 도 같은 GPU 비용 계급에 있고, 오히려 HippoRAG 2 가 문서당 토큰은 더 적다 (6k 대 8k).</p> <h2 id="한계와-비판적-평가">한계와 비판적 평가</h2> <p><strong>저자가 인정한 한계</strong></p> <ul> <li>스케일링 근거가 단일 모델 계열 (Qwen2.5) 과 선택된 태스크에 기반한다. 여섯 크기에 걸쳐 견고하긴 하지만 보편 정리가 아니라 잘 뒷받침된 가설이다.</li> <li>Meno-Lite-0.1 은 파라메트릭 사실 회상을 문맥 접지와 맞바꾼 모델이라 단독 지식 베이스로 쓰면 안 된다. multi-hop 추론은 32K 토큰을 넘으면 저하되는데, 7B 급에서는 전형적인 현상이다.</li> <li>IE 벤치마크에 분포 중첩 우려가 있다. Meno-Lite-0.1 의 SFT 는 NEREL 의 train/validation split 을 쓰고 벤치마크는 held-out test split 을 다른 instruction 표현으로 쓰지만, 주석 스키마와 텍스트 도메인이 겹치므로 잔여 이점을 완전히 배제할 수 없다.</li> <li>기본 NetworkX 그래프 백엔드는 수백만 노드 규모로 확장되지 않는다. 그리고 최종 그래프 품질은 여전히 추출 LLM 에 민감하다 — 약한 베이스 모델이 넣은 구조적 노이즈는 통합으로도 완전히 교정되지 않는다.</li> </ul> <p><strong>리뷰어로서 추가로 보이는 한계</strong></p> <ul> <li><strong>가설의 검증 도메인과 적용 도메인이 어긋난다.</strong> 언어 능력 vs 세계 지식 가설은 러시아어 벤치마크 (CheGeKa, MultiQ) 로 검증됐는데, GraphRAG 평가는 전부 영어다. 가설 자체는 언어 독립적으로 보이지만, 영어에서 같은 기울기 분리가 나타나는지는 논문이 보여주지 않는다.</li> <li><strong>Evidence Recall 수치가 본문과 그림에서 어긋난다.</strong> 초록과 본문은 “evidence recall up to 0.84 vs ≤0.76”, “84 vs ≤76%” 라고 적는데 Figure 3(b) 의 최고값은 82.4 다. 비교 대상 76.1 은 그림과 일치하므로 0.84 쪽이 반올림/전사 오류로 보인다. 초록에 들어간 숫자라 더 눈에 띈다.</li> <li><strong>단일 도메인 · 단일 시드.</strong> GraphRAG-Bench 는 Medical 도메인만 돌렸고, 표 어디에도 신뢰구간·표준편차·시드 수가 없다. Contextual Summarize 의 −0.9pp 를 “parity” 라고 부르려면 변동성 추정이 필요하다.</li> <li><strong>비용 우위의 비교 대상이 품질 평가에 없다.</strong> USD 100 대 USD 10,000 의 상대는 MS-GraphRAG 인데, MS-GraphRAG 는 Table 1·2 어디에도 등장하지 않는다. 즉 “가장 비싼 시스템보다 100배 싸다”와 “품질이 비슷하다”가 서로 다른 비교군에서 나온 주장이다.</li> <li><strong>질의 시점 비용·지연 보고 없음.</strong> 인덱싱 비용만 다룬다. 그런데 RAGU 의 <code class="language-plaintext highlighter-rouge">MixSearch</code> 와 <code class="language-plaintext highlighter-rouge">QueryPlanEngine</code> 은 구조상 질의당 LLM 호출이 여러 번 나가는 설계다. 넓은 컨텍스트를 gpt-4o-mini 에 밀어넣는 것도 질의 비용에 잡힌다. 운영 관점에서 빠져 있는 절반이다.</li> <li><strong>MuSiQue 격차에 대한 처방이 없다.</strong> HippoRAG 2 의 personalized PageRank 가 통합 기반 검색이 놓치는 경로를 잡는다고 진단해 놓고, PPR 류 순회를 RAGU 에 붙여보는 ablation 은 없다. 두 접근이 상보적이라면 결합 실험이 가장 자연스러운 다음 수인데 비어 있다.</li> <li><strong>임베딩 모델이 벤치마크군마다 다르다.</strong> GraphRAG-Bench 는 bge-large-en-v1.5, multi-hop QA 는 gte-multilingual-base 를 쓰는데 이유가 설명되지 않는다. 각 표 안에서는 통제되지만 표 사이 비교는 어려워진다.</li> <li><strong>타입 스키마의 의미적 부정확성이 사례에서 그대로 노출된다.</strong> Dennis Ritchie 가 C 언어를 “만들었다”가 <code class="language-plaintext highlighter-rouge">WORKS_AS</code> 로 잡힌다. 49개 관계 타입 안에 저작·창작 관계가 없어 생긴 결과로 보이는데, 스키마 제약이 일관성을 주는 대신 표현력을 깎는 트레이드오프를 논문이 정면으로 다루지 않는다.</li> </ul> <h2 id="시사점--takeaways">시사점 / Takeaways</h2> <ul> <li><strong>파이프라인 단계마다 필요한 능력의 종류가 다르다.</strong> “인덱싱에는 언어 능력, 답변에는 세계 지식”이라는 분해는 RAG 를 넘어 에이전트 파이프라인 전반에 적용할 수 있는 사고 도구다. 어떤 단계에 어떤 크기의 모델을 붙일지 결정할 때, 그 단계가 요구하는 능력의 스케일링 지수를 먼저 묻는 습관이 유용하다.</li> <li><strong>추출과 통합을 분리하는 것만으로 얻는 게 크다.</strong> 엔티티를 먼저 확정하고 그것을 관계 추출의 제약으로 되먹이는 설계는 dangling edge 라는 오류 클래스를 통째로 제거한다. 모델을 키우는 것보다 파이프라인을 나누는 게 싸고 확실한 개선인 전형적 사례다.</li> <li><strong>벤치마크 격차의 상당 부분이 답변 포맷일 수 있다.</strong> verbose/terse 두 프로토콜로 나눠 보고한 것만으로 −19.3pp 가 −5.5pp 로 줄었다. 자기 시스템이 지는 벤치마크를 만났을 때 가장 먼저 확인할 것은 프롬프트가 정답 형식과 맞는지다. 반대로 리뷰어라면 overlap 기반 지표를 쓰는 논문의 격차 주장은 포맷 통제 여부를 먼저 봐야 한다.</li> <li><strong>넓은 회수와 정확한 회수는 다른 목표다.</strong> Fact Retrieval 에서 Evidence Recall 1위 (82.4) 를 하고도 Answer Correctness 는 18pp 뒤지는 상황은, 지표 선택이 시스템 평가를 얼마나 좌우하는지 보여준다. 요약·장문 생성이 목적이면 Coverage 계열을, 단답 조회가 목적이면 정밀도 계열을 봐야 한다.</li> <li><strong>재현 가능한 형태로 쓴 엔지니어링 비판은 논문이 될 수 있다.</strong> 커밋 해시를 고정하고 파일·라인으로 주장을 앵커한 부록 A 는, 흔히 블로그 글로 흘러가는 종류의 관찰을 검증 가능한 학술 기여로 바꿔놓았다. 다만 경쟁 시스템 저자의 감사라는 점은 독자가 감안해야 한다.</li> </ul> <h2 id="설치-및-사용법">설치 및 사용법</h2> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>graph_ragu
</code></pre></div></div> <p>Meno-Lite-0.1 은 vLLM 으로 단일 컨슈머 GPU 에서 서빙한다.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vllm serve bond005/meno-lite-0.1 <span class="nt">--max-model-len</span> 131072
</code></pre></div></div> <p>파이프라인 구성은 스토리지 3계층을 생성자 인자로 주입하는 형태다. 프로토타입 (NetworkX + NanoVDB) 에서 프로덕션 (Neo4j + Qdrant) 으로 옮기는 것이 인자 교체로 끝나는 것이 이 설계의 핵심 주장이다.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 개념 예시 — 정확한 API 시그니처는 저장소 문서를 참조
</span><span class="kn">from</span> <span class="n">graph_ragu</span> <span class="kn">import</span> <span class="n">RAGU</span><span class="p">,</span> <span class="n">Settings</span>

<span class="n">ragu</span> <span class="o">=</span> <span class="nc">RAGU</span><span class="p">(</span><span class="n">settings</span><span class="o">=</span><span class="nc">Settings</span><span class="p">(</span><span class="n">language</span><span class="o">=</span><span class="sh">"</span><span class="s">en</span><span class="sh">"</span><span class="p">))</span>
<span class="k">await</span> <span class="n">ragu</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">documents</span><span class="p">)</span>                  <span class="c1"># 6단계 인덱싱 파이프라인
</span><span class="n">answer</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ragu</span><span class="p">.</span><span class="nf">search</span><span class="p">(</span><span class="sh">"</span><span class="s">...</span><span class="sh">"</span><span class="p">,</span> <span class="n">engine</span><span class="o">=</span><span class="sh">"</span><span class="s">local</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div> <p>전체 API 문서와 실행 가능한 예제는 저장소에 있고, 별도의 데모 웹 프론트엔드와 시연 영상도 공개돼 있다.</p> <h2 id="참고-자료">참고 자료</h2> <ul> <li>논문: <a href="https://arxiv.org/abs/2607.11683">arXiv:2607.11683</a></li> <li>Code: <a href="https://github.com/RaguTeam/RAGU">github.com/RaguTeam/RAGU</a> (MIT)</li> <li>모델: <a href="https://huggingface.co/bond005/meno-lite-0.1">bond005/meno-lite-0.1</a> (Apache 2.0)</li> <li>데모 영상: <a href="https://youtu.be/bicJDMJuQfg">youtu.be/bicJDMJuQfg</a></li> </ul> <h2 id="더-읽어보기">더 읽어보기</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2404.16130">From Local to Global: A Graph RAG Approach to Query-Focused Summarization</a></strong> (Edge et al., 2024) — Microsoft GraphRAG 원논문. 커뮤니티 탐지 + 커뮤니티 요약 map-reduce 로 전역 질문에 답하는 구조를 처음 제시했고, RAGU 의 Steps 4–6 이 이 계보 위에 있다.</li> <li><strong><a href="https://arxiv.org/abs/2410.05779">LightRAG: Simple and Fast Retrieval-Augmented Generation</a></strong> (Guo et al., 2025) — 단일 패스 자유 형식 추출 + dual-level 검색으로 GraphRAG 비용을 줄인 시스템. 이 논문에서 “통합 단계가 없으면 어떻게 되는가”의 대조군 역할을 한다.</li> <li><strong><a href="https://arxiv.org/abs/2502.14802">From RAG to Memory: Non-Parametric Continual Learning for Large Language Models</a></strong> (Gutiérrez et al., ICML 2025) — HippoRAG 2. personalized PageRank 기반 그래프 순회로 단답 정밀도와 체인 추적에 강하다. RAGU 의 주 비교 대상이자, 이 논문이 끝내 넘지 못한 MuSiQue 를 가져간 시스템.</li> <li><strong><a href="https://arxiv.org/abs/2506.05690">When to Use Graphs in RAG: A Comprehensive Analysis for Graph Retrieval-Augmented Generation</a></strong> (Xiang et al., ICLR 2026) — GraphRAG-Bench 원논문. 난이도 4단계 (fact retrieval → creative generation) 설계가 이 리뷰의 교차 그래프를 가능하게 만든 틀이다.</li> <li><strong><a href="https://arxiv.org/abs/2108.13112">NEREL: A Russian Dataset with Nested Named Entities, Relations and Events</a></strong> (Loukachevitch et al., 2021) — RAGU 추출기가 출력 공간으로 쓰는 29 엔티티 · 49 관계 타입 스키마의 원본. 러시아어 뉴스 도메인용으로 설계됐다는 사실이 이 논문의 스키마 관련 한계를 이해하는 열쇠다.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="graphrag"/><category term="retrieval-augmented-generation"/><category term="knowledge-graph"/><category term="information-extraction"/><category term="small-language-models"/><category term="open-source"/><summary type="html"><![CDATA[단일 패스 추출 대신 추출과 통합을 분리한 GraphRAG 엔진, 그리고 RAG 파이프라인 안의 LLM 에는 세계 지식이 아니라 언어 능력이 필요하다는 가설로 7B 추출기를 정당화한 시스템 논문]]></summary></entry><entry xml:lang="en"><title type="html">[Paper Review] RAGU: A Multi-Step GraphRAG Engine with a Compact Domain-Adapted LLM</title><link href="https://baba9811.github.io/en/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/" rel="alternate" type="text/html" title="[Paper Review] RAGU: A Multi-Step GraphRAG Engine with a Compact Domain-Adapted LLM"/><published>2026-08-20T05:00:00+00:00</published><updated>2026-08-20T05:00:00+00:00</updated><id>https://baba9811.github.io/en/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap</id><content type="html" xml:base="https://baba9811.github.io/en/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/" class="btn btn-sm btn-outline-secondary">🇰🇷 한국어로 읽기</a> </div> <h2 id="metadata">Metadata</h2> <table> <thead> <tr> <th>Field</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td>Authors</td> <td>Mikhail Komarov et al. (8 co-authors across ITMO University · Novosibirsk State University · Far Eastern Federal University)</td> </tr> <tr> <td>Venue</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv or DOI</td> <td><a href="https://arxiv.org/abs/2607.11683">2607.11683</a></td> </tr> <tr> <td>Code</td> <td><a href="https://github.com/RaguTeam/RAGU">RaguTeam/RAGU</a></td> </tr> <tr> <td>Data</td> <td>GraphRAG-Bench (Medical) · BioASQ · MuSiQue · 2WikiMultiHopQA · a NEREL-derived IE benchmark · MERA</td> </tr> <tr> <td><span style="white-space: nowrap">Review date</span></td> <td>2026-08-20</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>Most GraphRAG systems build their knowledge graph in a <strong>single LLM extraction pass</strong>. RAGU splits extraction from consolidation: two-stage typed extraction, DBSCAN-backed deduplication, LLM summarization, then Leiden community detection.</li> <li>The more interesting claim isn’t the engine, it’s the hypothesis behind it. What an LLM actually does inside a RAG pipeline — comprehend, extract, reason over given context — are <strong>language skills, not world knowledge</strong>, and language skills scale much more weakly with parameter count. In the Qwen2.5-Instruct family, F1 on a world-knowledge quiz (CheGeKa) grows 21.1× from 0.5 B to 72 B, while MultiQ — where every needed fact is in-context — grows only 4× (log-linear slopes 0.65 vs. 0.26).</li> <li>Acting on that, the authors trained Meno-Lite-0.1, a 7 B extractor. On their own IE benchmark it beats Qwen2.5-32B by 12.5% relative on harmonic mean (0.468 vs. 0.416), driven almost entirely by relation extraction (F1 0.347 vs. 0.239).</li> <li>On GraphRAG-Bench (Medical) there is a clean cross-over. HippoRAG 2 wins single-fact lookup (AC 72.4 vs. 54.2), the gap closes monotonically as tasks shift toward synthesis, and flips on Creative Generation (AC 59.0 vs. 56.9, Coverage 57.4 vs. 34.7).</li> <li>HippoRAG 2’s apparent dominance on multi-hop QA turns out to be largely an <strong>answer-format artifact</strong>. Force terse answers and the 2WikiMultiHopQA gap shrinks from −19.3 pp to −5.5 pp, while BioASQ flips (72.9 vs. 72.4). MuSiQue, though, keeps a real gap (54.4 vs. 40.1).</li> </ul> <h2 id="introduction">Introduction</h2> <p>RAG is the standard recipe for grounding an LLM in external knowledge, but plain RAG retrieves flat chunks and never captures relationships that span documents. GraphRAG closes that gap by extracting entities and relations into a knowledge graph and traversing it at retrieval time. Since Microsoft’s GraphRAG, systems like LightRAG and HippoRAG 2 have pushed the idea far enough that the open question is no longer “does GraphRAG work” but “when is it worth the indexing cost”.</p> <p>Put one into production, though, and three things get in the way. First, most systems treat graph construction as a <strong>single LLM extraction pass</strong>. If the same person shows up under a slightly different surface form in the next chunk, you get a second node, and nothing exists to merge them across chunk boundaries. Second, because extraction quality determines graph quality, practitioners reach for GPT-4-class API models by default. Third, engineering maturity in the open-source ecosystem is thin — installs break, and in at least one popular framework, <code class="language-plaintext highlighter-rouge">eval()</code> runs on raw LLM output.</p> <p>What makes this paper worth reading is that it treats the second obstacle as a <strong>claim to be tested rather than an assumption to be paid for</strong>. The authors argue that the default rests on a false premise: what an LLM does inside a RAG pipeline is read context, pull out entities, summarize descriptions, and answer from what it was given. All of those are <em>language skills</em>, not <em>factual recall</em>. And those two capabilities, they claim, grow at very different rates with model size.</p> <p>So the paper ships three things at once — a hypothesis, a 7 B extractor trained to match it, and a modular engine to run it in. It wears the clothes of a system-demo paper, but the parts that repay careful reading are the hypothesis test and the unusually honest reporting of how much (or how little) that fine-tuned extractor buys downstream.</p> <h2 id="key-contributions">Key Contributions</h2> <ul> <li><strong>The language/world-knowledge hypothesis.</strong> World knowledge scales near-linearly with parameter count; language skills scale markedly slower. Tested across six sizes of Qwen2.5-Instruct on MERA. This single claim underwrites every other design decision in the paper.</li> <li><strong>Meno-Lite-0.1.</strong> A 7 B model derived from RuadaptQwen2.5-7B-Lite-Beta via continued pretraining plus SFT targeted at NEREL-schema extraction and multi-hop QA. Best harmonic mean on the IE benchmark, ahead of a 32 B model.</li> <li><strong>The RAGU engine.</strong> A six-stage indexing pipeline that separates extraction from consolidation, five search engines, three swappable storage tiers. Installs with <code class="language-plaintext highlighter-rouge">pip install graph_ragu</code>, runs on one GPU, MIT licensed.</li> <li><strong>Isolating the answer-format confound.</strong> Reporting multi-hop QA under both verbose and terse generation protocols shows how much of the between-system gap was formatting rather than retrieval. This is, in my view, the most valuable experiment in the paper.</li> <li><strong>A reproducible engineering audit.</strong> Appendix A pins every claim about HippoRAG 2 to file and line at a fixed commit — <code class="language-plaintext highlighter-rouge">eval()</code> call sites, <code class="language-plaintext highlighter-rouge">assert False</code> used as control flow, absent storage abstractions.</li> </ul> <h2 id="background-and-related-work">Background and Related Work</h2> <h3 id="the-graphrag-lineage">The GraphRAG lineage</h3> <p>Microsoft GraphRAG (Edge et al., 2024) extracts entities and relations, runs community detection to build a hierarchy, then map-reduces community summaries to answer global questions like “what are the main themes here?”. It works, but indexing is LLM-heavy — the ~40 k tokens/document figure in the cost table later comes from this design.</p> <p>LightRAG (Guo et al., 2025) trades in the other direction: free-form single-pass extraction plus dual-level retrieval (low-level entities, high-level themes) for speed. Without a schema constraint, the extracted structure is looser. That’s the authors’ explanation for why LightRAG sits last at all four GraphRAG-Bench difficulty levels on answer quality.</p> <p>HippoRAG 2 (Gutiérrez et al., 2025) takes a different route entirely, drawing on hippocampal memory theory to traverse the graph with personalized PageRank. That approach is unusually good at <em>following chains</em>, which is exactly why it wins single-fact lookup and MuSiQue in the results below. Wikontic (Chepurova et al., 2026) builds Wikidata-aligned graphs, sharing RAGU’s instinct that typed constraints beat free-form output.</p> <h3 id="the-nerel-schema">The NEREL schema</h3> <p>RAGU’s extraction isn’t free-form — it’s bound to the <strong>NEREL schema</strong>. NEREL (Loukachevitch et al., 2021) annotates 900+ Russian news articles with nested named entities, relations and events, defining <strong>29 entity types and 49 relation types</strong>. RAGU uses that type set as the extractor’s output space, which structurally eliminates the problem of a free-form extractor emitting <code class="language-plaintext highlighter-rouge">"creator"</code>, <code class="language-plaintext highlighter-rouge">"created by"</code> and <code class="language-plaintext highlighter-rouge">"made"</code> as three distinct relations.</p> <p>The cost is real too. NEREL was built for Russian news. In the Dennis Ritchie case study later, “created the C programming language” comes out as <code class="language-plaintext highlighter-rouge">WORKS_AS</code> — apparently the closest fit available, since the 49-relation type set doesn’t cover authorship directly. The authors acknowledge in their bias statement that applying the schema to other languages or domains may require adaptation.</p> <h3 id="mera-chegeka-multiq">MERA, CheGeKa, MultiQ</h3> <p>The hypothesis is tested on Russian-language evaluation suites. MERA (Fenogenova et al., 2024) is a comprehensive Russian LLM benchmark; CheGeKa within it is a quiz-show task where the model has to <em>remember</em> the answer. MultiQ is the mirror image — multi-hop QA where every needed fact sits in the context, so it measures only reading and composing. That contrast produces the paper’s headline figure.</p> <h2 id="method-and-architecture">Method and Architecture</h2> <h3 id="separating-two-scaling-curves">Separating two scaling curves</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig1-scaling-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig1-scaling-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig1-scaling-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig1-scaling.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: Model size vs. world-knowledge (CheGeKa) and language-skill (MultiQ) performance in the Qwen2.5-Instruct family. MultiQ has already flattened out by 32 B; CheGeKa keeps climbing all the way to 72 B.</figcaption> </figure> <p>The first figure is effectively the whole argument. Six sizes of the same model family, two tasks:</p> <ul> <li><strong>CheGeKa</strong> (world knowledge): F1 grows <strong>21.1×</strong> from 0.5 B to 72 B. Log-linear slope 0.65.</li> <li><strong>MultiQ</strong> (in-context composition): <strong>4×</strong> over the same range. Slope 0.26.</li> </ul> <p>The shape is more convincing than the slope numbers. MultiQ is already at 0.39 by 3 B, saturates around 0.58 at 32 B, and dips very slightly at 72 B. CheGeKa rises the whole way. If what your pipeline needs looks like MultiQ, spending 32 B on indexing is mostly waste.</p> <h3 id="multi-step-graph-construction">Multi-step graph construction</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig2-pipeline-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig2-pipeline-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig2-pipeline-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig2-pipeline.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: The end-to-end indexing pipeline. Solid arrows are data flow between stages; dashed arrows are artifacts each stage produces. Every artifact — chunks, entities/relations, communities, community summaries — is persisted explicitly, which is what makes incremental updates and auditability possible.</figcaption> </figure> <p>Indexing runs in six configurable stages.</p> <p><strong>Step 1 — Chunking.</strong> Three strategies: <code class="language-plaintext highlighter-rouge">SimpleChunker</code> (fixed-size with overlap), <code class="language-plaintext highlighter-rouge">SemanticTextChunker</code> (embedding-based split points), <code class="language-plaintext highlighter-rouge">SmartSemanticChunker</code> (cross-encoder reranking on top). Nothing novel, but everything downstream depends on chunk quality, so the choice is exposed.</p> <p><strong>Step 2 — Two-stage typed extraction.</strong> This is the first real idea. Unlike single-pass systems, RAGU separates entity extraction (Stage 1) from relation extraction (Stage 2):</p> <ol> <li>Entities are extracted first and validated against the NEREL schema.</li> <li>The validated entity set is fed back as a <strong>constraint</strong> on Stage 2 — every <code class="language-plaintext highlighter-rouge">source_entity</code> and <code class="language-plaintext highlighter-rouge">target_entity</code> in a relation must match a validated entity name.</li> </ol> <p>Without that feedback, an LLM will quietly rename entities mid-extraction (the same person as “Ritchie” in one relation and “Dennis Ritchie” in another) or invent endpoints that never appeared as entities. That’s the standard route to dangling edges and ghost nodes. Splitting the stage and constraining the second pass removes the entire error class by construction. ICL examples can be injected at both stages, selected by semantic, BM25, hybrid, or random strategies.</p> <p><strong>Step 3 — Consolidation.</strong> The second idea, and the “multi-step” in the title. <code class="language-plaintext highlighter-rouge">EntitySummarizer</code> groups entities by (name, type) and, for entities with many duplicate mentions, applies DBSCAN clustering plus LLM summarization. <code class="language-plaintext highlighter-rouge">RelationSummarizer</code> does the same for relations.</p> <p>Ordering matters here. Noise is reduced <strong>before</strong> community detection. Run Leiden on a graph where one real-world entity is still split across five nodes, and the community boundaries themselves come out contaminated. This is precisely the step absent from single-pass systems, and it’s where the authors locate their performance difference.</p> <p><strong>Steps 4–6 — Community detection, summarization, refinement.</strong> Hierarchical Leiden clustering partitions the deduplicated graph, an LLM generates structured community reports (title, summary, findings), and pluggable modules like <code class="language-plaintext highlighter-rouge">RemoveIsolatedNodes</code> optionally clean up.</p> <h3 id="five-search-engines">Five search engines</h3> <table> <thead> <tr> <th>Engine</th> <th>Behaviour</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">LocalSearch</code></td> <td>Vector-similarity entity retrieval, expanded to relations and chunks</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">GlobalSearch</code></td> <td>LLM-rated community summarization for corpus-level questions</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">NaiveSearch</code></td> <td>Standard vector RAG, no graph (internal control)</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">MixSearch</code></td> <td>Several engines in parallel, results combined</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">QueryPlanEngine</code></td> <td>DAG decomposition of the query into sub-queries</td> </tr> </tbody> </table> <p>All support cross-encoder reranking and hybrid dense+sparse retrieval via Qdrant. Worth noting: the <code class="language-plaintext highlighter-rouge">NaiveRAG</code> row in the results tables <em>is</em> this <code class="language-plaintext highlighter-rouge">NaiveSearchEngine</code>, sharing RAGU’s generation prompt. So the RAGU-vs-NaiveRAG comparison isolates the graph’s contribution with prompt differences removed.</p> <h3 id="engineering">Engineering</h3> <p>Four things carry the “production-ready” claim:</p> <ol> <li><strong>A three-tier storage abstraction</strong> (graph / KV / vector) with lifecycle callbacks, so swapping a backend is a constructor argument — NetworkX→Neo4j, NanoVDB→Qdrant.</li> <li><strong>An async-first API</strong> with semaphore-bounded concurrency, keeping throughput safe under API rate limits.</li> <li><strong>Pydantic v2 validation</strong> of all structured LLM output, which removes manual JSON post-processing and closes the code-injection surface.</li> <li><strong>Incremental upsert/update/delete</strong> with deterministic hash-based IDs, merge policies, and a consistency auditor that verifies cross-store integrity.</li> </ol> <p>Roughly 374 tests plus a deterministic mock LLM server make CI runnable without API keys. Every domain object carries a deterministic MD5 identifier, so any retrieved result traces back to its source text.</p> <h3 id="meno-lite-01">Meno-Lite-0.1</h3> <p>Starting from RuadaptQwen2.5-7B-Lite-Beta (Tikhomirov and Chernyshev, 2025), two stages:</p> <ul> <li><strong>Continued pretraining</strong>: 1.3 B tokens of Russian and English educational/scientific text.</li> <li><strong>SFT</strong>: 50 M tokens covering NEREL-based extraction, multi-hop QA (MultiHop-RAG, mtRAG), and query logs.</li> </ul> <p>The distinguishing move is in the instruction design: the model is taught to <strong>use context rather than recall facts</strong> — spending its capacity budget on language skills instead of world knowledge, exactly as the hypothesis prescribes.</p> <table> <thead> <tr> <th>Property</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td>Parameters</td> <td>7 B</td> </tr> <tr> <td>Context window</td> <td>128 K (passkey retrieval 0.98 at 128 K)</td> </tr> <tr> <td>Tokenizer efficiency (Russian)</td> <td>3.77 chars/token vs. 2.57 for vanilla Qwen2.5 — 47% better</td> </tr> <tr> <td>Serving</td> <td>vLLM, single consumer GPU</td> </tr> <tr> <td>License</td> <td>Apache 2.0</td> </tr> </tbody> </table> <h2 id="training-objective">Training Objective</h2> <p>There’s no new loss function here. Meno-Lite-0.1 is trained with the standard causal-LM objective — next-token cross-entropy for both continued pretraining and SFT — and the novelty lies in <strong>what data that loss is applied to</strong>, not in its form. So the thing worth formalizing in this section is the scaling hypothesis rather than the objective.</p> <p>Model task performance $F_1$ against parameter count $N$ as a log-linear relation:</p> \[\begin{aligned} \log F_1 &amp;= \alpha \log N + c, \\ \alpha_{\text{CheGeKa}} &amp;= 0.65, \\ \alpha_{\text{MultiQ}} &amp;= 0.26 \end{aligned}\] <p>Here $\alpha$ governs how much performance you buy per doubling of parameters. The paper’s quantitative claim is that world-knowledge tasks have roughly 2.5× the exponent of language-skill tasks, and the observed ratios line up reasonably (21.1× vs. 4×, over a 144× parameter range).</p> <p>The design principle that falls out is simple: if a pipeline component demands a capability with a small $\alpha$, give it a small model. RAG indexing — read a chunk, pull out entities, summarize a description — is squarely in the small-$\alpha$ regime. Answer generation isn’t, which is why the paper still uses gpt-4o-mini there. So the hypothesis isn’t “small models are enough”, it’s <strong>“different pipeline stages need different capabilities, so they should use different models”</strong>.</p> <h2 id="data-and-evaluation-setup">Data and Evaluation Setup</h2> <h3 id="meno-lite-01-training">Meno-Lite-0.1 training</h3> <table> <thead> <tr> <th>Stage</th> <th>Data</th> <th>Scale</th> </tr> </thead> <tbody> <tr> <td>Base</td> <td>RuadaptQwen2.5-7B-Lite-Beta</td> <td>7 B</td> </tr> <tr> <td>Continued pretraining</td> <td>Russian + English educational/scientific text (FineWeb-Edu, RuLM, …)</td> <td>1.3 B tokens</td> </tr> <tr> <td>SFT</td> <td>NEREL extraction · MultiHop-RAG · mtRAG · query logs · GPT-4o-mini synthetic instructions</td> <td>50 M tokens</td> </tr> </tbody> </table> <p>All training corpora are publicly available datasets, with no personally identifiable information. The IE benchmark is a test-only derivative of NEREL, MIT licensed, and integrated into the LM Evaluation Harness under the <code class="language-plaintext highlighter-rouge">nerel-bench</code> task group.</p> <h3 id="evaluation">Evaluation</h3> <table> <thead> <tr> <th>Item</th> <th>Setting</th> </tr> </thead> <tbody> <tr> <td>Benchmarks</td> <td>GraphRAG-Bench (Medical), BioASQ, MuSiQue, 2WikiMultiHopQA</td> </tr> <tr> <td>Answer-generation LLM</td> <td>gpt-4o-mini, fixed across all systems</td> </tr> <tr> <td>Graph-construction LLM</td> <td>Independent variable — Meno-Lite-0.1 (7 B), gpt-oss-20b, Qwen2.5-7B</td> </tr> <tr> <td>Embeddings</td> <td>bge-large-en-v1.5 (GraphRAG-Bench) / gte-multilingual-base (multi-hop QA)</td> </tr> <tr> <td>LLM-as-judge</td> <td>google/gemini-3-flash-preview</td> </tr> <tr> <td>Metrics</td> <td>Answer Correctness (AC), ROUGE-L, Coverage, Faithfulness, Evidence Recall (ER), Context Relevancy</td> </tr> </tbody> </table> <p>Two design choices deserve credit. Fixing the answer-generation LLM across systems <strong>isolates graph-construction quality</strong>, and picking a judge from a different model family avoids evaluator–generator overlap — a control that LLM-as-judge setups skip more often than they should.</p> <h2 id="results">Results</h2> <h3 id="graphrag-bench-medical">GraphRAG-Bench (Medical)</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab1-main-results-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab1-main-results-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab1-main-results-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab1-main-results.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 1: Generation quality on GraphRAG-Bench (Medical). Each system appears twice, differing only in the indexing LLM. Note how little the numbers move when you swap Qwen2.5-7B for Meno-Lite-0.1 — in any of the three systems.</figcaption> </figure> <p>GraphRAG-Bench has four levels of increasing difficulty. On Answer Correctness the cross-over is clean:</p> <table> <thead> <tr> <th>Level</th> <th>HippoRAG 2</th> <th>RAGU</th> <th>Gap</th> </tr> </thead> <tbody> <tr> <td>Fact Retrieval</td> <td>72.4</td> <td>54.2</td> <td>−18.2 pp</td> </tr> <tr> <td>Complex Reasoning</td> <td>68.4</td> <td>53.7</td> <td>−14.7 pp</td> </tr> <tr> <td>Contextual Summarize</td> <td>65.0</td> <td>64.1</td> <td>−0.9 pp</td> </tr> <tr> <td>Creative Generation</td> <td>56.9</td> <td>59.0</td> <td><strong>+2.1 pp</strong></td> </tr> </tbody> </table> <p>(all rows using Meno-Lite-0.1 as the indexing LLM)</p> <p>Coverage — the metric that directly rewards retrieving <em>all</em> relevant material — widens the picture. RAGU leads 57.4 to 34.7 on Creative Generation and 71.1 to 51.7 on Contextual Summarize, and takes Faithfulness 34.2 to 26.6. LightRAG trails everywhere (Creative Generation AC 14.4, Coverage 3.9), which the authors read as the downstream consequence of a structurally poorer graph from free-form single-pass extraction.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig3-crossover-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig3-crossover-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig3-crossover-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig3-crossover.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: The cross-over. (a) On Answer Correctness the HippoRAG 2 (orange) and RAGU (blue) bars converge left to right and flip at the last level. (b) On Evidence Recall RAGU leads across the factoid levels, but LightRAG takes Creative Generation at 59.9.</figcaption> </figure> <p>Evidence Recall is where the mechanism shows. Fact Retrieval: RAGU 82.4, LightRAG 76.1, HippoRAG 2 75.6. In the same system order (RAGU / LightRAG / HippoRAG 2): Complex Reasoning 74.5 / 71.3 / 66.7, Contextual Summarize 74.8 / 70.2 / 71.8. So <strong>RAGU retrieves the most complete evidence and still loses on short-answer accuracy</strong>. The authors attribute that to the precision of HippoRAG 2’s chain traversal on single-fact queries. It’s the difference between casting a wide net and aiming a single shot, and which one wins depends entirely on which metric you’re reading.</p> <h3 id="multi-hop-qa-separating-out-the-format-effect">Multi-hop QA: separating out the format effect</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab2-multihop-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab2-multihop-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab2-multihop-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab2-multihop.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 2: (a) With verbose prompts HippoRAG 2 dominates every column; (b) with terse prompts BioASQ flips and the 2WikiMultiHopQA gap shrinks to under a quarter of its size. The HippoRAG 2 rows are identical across panels because its default prompt was already terse.</figcaption> </figure> <p>This is the best-designed experiment in the paper. BioASQ, MuSiQue and 2WikiMultiHopQA are pure factoid QA with short gold answers, and in that setting <strong>answer format dominates overlap-based metrics</strong>. So the authors report both protocols.</p> <p><strong>(a) Verbose — each system’s default prompt.</strong> HippoRAG 2 sweeps: BioASQ AC 74.1 vs. RAGU’s 56.0. But look at ROUGE-L alongside it — 12.2 vs. 48.8. RAGU’s long-form answers simply don’t overlap with terse gold references, depressing both metrics at once.</p> <p><strong>(b) Terse — single direct answer forced.</strong> The picture changes substantially:</p> <table> <thead> <tr> <th>Benchmark</th> <th>HippoRAG 2</th> <th>RAGU (GPT)</th> <th>Verbose gap → terse gap</th> </tr> </thead> <tbody> <tr> <td>BioASQ</td> <td>72.4</td> <td><strong>72.9</strong></td> <td>−18.1 pp → +0.5 pp</td> </tr> <tr> <td>2WikiMultiHopQA</td> <td>63.5</td> <td>58.0</td> <td>−19.3 pp → −5.5 pp</td> </tr> <tr> <td>MuSiQue</td> <td>54.4</td> <td>40.1</td> <td>−12.8 pp → −14.3 pp</td> </tr> </tbody> </table> <p>BioASQ flips and 2WikiMultiHopQA shrinks to a quarter of its former size. <strong>MuSiQue, on the other hand, gets slightly worse.</strong> The authors accept that one as a genuine capability gap: MuSiQue is the hardest multi-hop benchmark, and personalized PageRank follows reasoning chains that consolidated retrieval doesn’t surface. Not writing off the one benchmark you lose as a formatting artifact is worth something.</p> <p>One more thing: the difference between indexing RAGU with gpt-oss-20b (20 B) and with Meno-Lite-0.1 (7 B) is only 1–2 pp. Swapping a 20 B model for a 7 B one barely moves the end-to-end result, which is the hypothesis validated in practice.</p> <h3 id="the-ie-benchmark">The IE benchmark</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab3-ie-bench-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab3-ie-bench-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab3-ie-bench-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab3-ie-bench.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 3: IE benchmark. Meno-Lite-0.1's edge comes almost entirely from the RE column — on NER and definition generation the larger models are actually ahead.</figcaption> </figure> <p>This measures the extractor itself, not the pipeline. Meno-Lite-0.1 (7 B) tops the harmonic mean at 0.468, with Qwen2.5-32B second at 0.416 — 12.5% relative.</p> <p>Reading column by column makes the story more specific:</p> <table> <thead> <tr> <th>Model</th> <th>Size</th> <th>NER</th> <th>Def</th> <th>RE</th> <th>RDef</th> <th>HM</th> </tr> </thead> <tbody> <tr> <td>Meno-Lite-0.1</td> <td>7B</td> <td>0.504</td> <td>0.527</td> <td><strong>0.347</strong></td> <td>0.558</td> <td><strong>0.468</strong></td> </tr> <tr> <td>Qwen2.5-32B</td> <td>32B</td> <td>0.536</td> <td>0.528</td> <td>0.239</td> <td>0.599</td> <td>0.416</td> </tr> <tr> <td>gemma-3-27b</td> <td>27B</td> <td>0.544</td> <td>0.482</td> <td>0.224</td> <td>0.583</td> <td>0.396</td> </tr> <tr> <td>Qwen2.5-14B</td> <td>14B</td> <td>0.510</td> <td>0.518</td> <td>0.222</td> <td>0.583</td> <td>0.396</td> </tr> <tr> <td>Qwen2.5-7B</td> <td>7B</td> <td>0.477</td> <td>0.479</td> <td>0.192</td> <td>0.541</td> <td>0.356</td> </tr> <tr> <td>T-lite-1.0</td> <td>7B</td> <td>0.466</td> <td>0.464</td> <td>0.174</td> <td>0.533</td> <td>0.336</td> </tr> </tbody> </table> <p><strong>The win is essentially one column wide.</strong> Meno-Lite-0.1’s NER (0.504) trails gemma-3-27b (0.544) and Qwen2.5-32B (0.536), and its relation definitions (0.558) trail the 32 B model’s 0.599. But relation extraction F1 is 0.347 against the runner-up’s 0.239 — 45% higher. The authors argue relation extraction is the sub-task most dependent on language comprehension. That’s plausible, but it’s hard to separate from the fact that a model SFT’d on NEREL is being scored on NEREL-schema relation extraction. The authors flag the distributional overlap themselves.</p> <p>MERA overall comes in at 0.555, with LIBRA passkey retrieval at 0.98 at the 128 K mark. Read that alongside the limitation they state later — multi-hop reasoning degrades past 32 K tokens. Finding a passkey and reasoning across a long context are different capabilities.</p> <h3 id="case-study-one-paragraph-to-a-graph">Case study: one paragraph to a graph</h3> <p>The paper walks the full pipeline over a two-sentence passage, using the example script shipped with the repository:</p> <blockquote> <p>Dennis Ritchie, the creator of the C programming language, and the co-creator of the Unix operating system, died on October 12, 2011, at the age of 70. His father, Alistair E. Ritchie, worked for many years at Bell Laboratories in Murray Hill, New Jersey.</p> </blockquote> <p><strong>Stage 1 (entities).</strong> Nine typed entities under the NEREL schema:</p> <table> <thead> <tr> <th>Entity</th> <th>NEREL type</th> </tr> </thead> <tbody> <tr> <td>Dennis Ritchie</td> <td><code class="language-plaintext highlighter-rouge">PERSON</code></td> </tr> <tr> <td>Alistair E. Ritchie</td> <td><code class="language-plaintext highlighter-rouge">PERSON</code></td> </tr> <tr> <td>C Programming Language</td> <td><code class="language-plaintext highlighter-rouge">PRODUCT</code></td> </tr> <tr> <td>Unix Operating System</td> <td><code class="language-plaintext highlighter-rouge">PRODUCT</code></td> </tr> <tr> <td>Bell Laboratories</td> <td><code class="language-plaintext highlighter-rouge">ORGANIZATION</code></td> </tr> <tr> <td>October 12, 2011</td> <td><code class="language-plaintext highlighter-rouge">DATE</code></td> </tr> <tr> <td>70</td> <td><code class="language-plaintext highlighter-rouge">AGE</code></td> </tr> <tr> <td>Murray Hill</td> <td><code class="language-plaintext highlighter-rouge">DISTRICT</code></td> </tr> <tr> <td>New Jersey</td> <td><code class="language-plaintext highlighter-rouge">STATE_OR_PROV</code></td> </tr> </tbody> </table> <p><strong>Stage 2 (relations).</strong> Eight relations, every endpoint constrained to that validated set. The five shown in the paper are <code class="language-plaintext highlighter-rouge">Dennis Ritchie —WORKS_AS→ C Programming Language</code>, <code class="language-plaintext highlighter-rouge">Dennis Ritchie —WORKS_AS→ Unix Operating System</code>, <code class="language-plaintext highlighter-rouge">Dennis Ritchie —DATE_OF_DEATH→ October 12, 2011</code>, <code class="language-plaintext highlighter-rouge">Alistair E. Ritchie —PARENT_OF→ Dennis Ritchie</code>, and <code class="language-plaintext highlighter-rouge">Bell Laboratories —LOCATED_IN→ Murray Hill</code>.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig4-knowledge-graph-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig4-knowledge-graph-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig4-knowledge-graph-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/fig4-knowledge-graph.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 4: The knowledge graph built from one paragraph. Leiden clustering splits the nine-entity graph into two communities — Dennis Ritchie and his creations (5 entities, 4 relations), and the Bell Laboratories / Murray Hill / New Jersey / Alistair Ritchie cluster tied by spatial and professional links (4 entities, 3 relations). A single PARENT_OF edge bridges them.</figcaption> </figure> <p><strong>Communities and retrieval.</strong> Leiden clustering partitions the graph into two communities and an LLM writes a structured summary for each. On top of that, <code class="language-plaintext highlighter-rouge">LocalSearchEngine</code> answers questions that need several edges — “Where did the father of the creator of the C programming language work?” resolves by chaining <code class="language-plaintext highlighter-rouge">PARENT_OF</code> and <code class="language-plaintext highlighter-rouge">WORKPLACE</code> to return Bell Laboratories.</p> <p>Small as it is, the example makes two things concrete. First, what two-stage extraction actually prevents: every relation endpoint is a name fixed in Stage 1, so a partial surface form like “Ritchie” can’t leak out as a separate node. Second, the price of a typed schema — <strong>“created the C programming language” lands as <code class="language-plaintext highlighter-rouge">WORKS_AS</code>.</strong> Plainly wrong to a human reader, but probably the nearest available option among the 49 permitted relation types. Consistency bought at the price of expressiveness, and the paper doesn’t confront the trade directly.</p> <h2 id="analysis-and-ablation">Analysis and Ablation</h2> <h3 id="where-did-the-fine-tuning-gain-go">Where did the fine-tuning gain go?</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab7-ablation-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab7-ablation-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab7-ablation-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab7-ablation.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 7: RAGU configuration ablation. No combination of ICL on/off, validation on/off, and indexing model moves AC by more than 2 pp at any difficulty level — including dropping to Qwen2.5-3B.</figcaption> </figure> <p>The ablation surfaces the most interesting tension in the paper:</p> <ul> <li>Swapping the indexing model <strong>from 3 B to 14 B</strong> moves AC by ≤1.5 pp.</li> <li>ICL injection and entity validation each contribute &lt;1 pp.</li> <li><strong>Meno-Lite-0.1 and Qwen2.5-7B are within 1 pp in every configuration.</strong></li> </ul> <p>A model that beat Qwen2.5-32B by 12.5% on standalone extraction is indistinguishable from stock Qwen2.5-7B end to end. And this holds in every pipeline tested — RAGU, HippoRAG 2, and LightRAG alike (compare each system’s two rows in Table 1).</p> <p>The authors’ reading: this isn’t a failure of the fine-tuning, it’s evidence that <strong>graph-RAG QA quality is largely robust to extractor choice once consolidation is present</strong>. Meno-Lite-0.1 delivers 32B-class extraction at 7 B cost; the consolidation pipeline delivers downstream robustness; the two artifacts are complementary.</p> <p>It’s a smooth framing, but flip it around and the paper’s two contributions undercut each other. If the pipeline is robust to extractor quality, the case for training a dedicated extractor weakens; if the extractor really is that good, the pipeline is failing to propagate its advantage. The paper picks the first horn. For a practitioner, though, the more actionable conclusion might be <strong>“with a proper consolidation pipeline, a 3 B indexing model is enough”</strong> — which, if anything, supports the authors’ hypothesis more strongly than their own framing does.</p> <h3 id="wide-recall-vs-precise-retrieval">Wide recall vs. precise retrieval</h3> <p>The divergence between Evidence Recall and Answer Correctness deserves its own note. On Fact Retrieval, RAGU recovers 82.4% of the evidence and lands at AC 54.2; HippoRAG 2 recovers 75.6% and lands at 72.4. Retrieving more of the right material does not translate into short-answer accuracy.</p> <p>That points at the <strong>generation stage</strong> more than at retrieval. Hand gpt-4o-mini a broader context and there’s more room for it to fold in relevant-but-off-target material instead of committing to the short answer. The terse-prompt experiment touches exactly this nerve: leave retrieval untouched, tighten only the generation instruction, and RAGU’s BioASQ AC jumps from 56.0 to 72.9 — nearly 17 pp from the same context. If that much moves on generation alone, the factoid-level gaps on GraphRAG-Bench shouldn’t be read as pure retrieval differences either. It’s a shame the paper never connects the two analyses.</p> <h3 id="the-engineering-comparison">The engineering comparison</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab6-engineering-480.webp 480w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab6-engineering-800.webp 800w,/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab6-engineering-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0033-ragu-a-multi-step-graphrag-engine-with-a-compact-domain-adap/tab6-engineering.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 6: Engineering comparison organized by production risk. Each row is named for what breaks without the property, which is what separates this from a feature checklist.</figcaption> </figure> <p>Appendix A organizes the comparison by <strong>production risk</strong> rather than by feature: silent data loss on crash, backend migration cost, API-bound throughput, code execution from LLM output, transient failure recovery, regression detection, incremental maintenance, reproducible deployment, modularity.</p> <p>Two of them are genuinely serious:</p> <ol> <li><strong><code class="language-plaintext highlighter-rouge">eval()</code> on model output.</strong> HippoRAG 2 parses LLM responses by running Python’s <code class="language-plaintext highlighter-rouge">eval()</code> on a regex-filtered substring of the raw output (<code class="language-plaintext highlighter-rouge">openie_openai.py:36,88</code>). That’s an arbitrary-code-execution surface if the model ever emits hostile content, and a source of opaque exceptions far from the call site on any syntactic deviation.</li> <li><strong><code class="language-plaintext highlighter-rouge">assert False</code> as control flow.</strong> The offline indexing path terminates with <code class="language-plaintext highlighter-rouge">assert False</code> (<code class="language-plaintext highlighter-rouge">HippoRAG.py:216</code>). Run under <code class="language-plaintext highlighter-rouge">python -O</code> and the assertion is stripped, so the offline path <strong>silently proceeds into indexing</strong> without the online vLLM server the rest of the pipeline expects. That’s the worst class of production bug.</li> </ol> <p>Every claim is anchored to commit <code class="language-plaintext highlighter-rouge">d437bfb1</code> (2025-09-04), so it’s independently verifiable. It is, of course, an audit written by a competing system’s authors.</p> <h3 id="cost">Cost</h3> <p>Indexing cost is a one-time per-document operation, separate from query-time generation (identical across systems, gpt-4o-mini):</p> <table> <thead> <tr> <th>System</th> <th>Indexing model</th> <th>Tokens/doc</th> <th>Cost/doc</th> </tr> </thead> <tbody> <tr> <td>MS-GraphRAG (global)</td> <td>gpt-4o (API)</td> <td>~40 k</td> <td>~USD 0.10</td> </tr> <tr> <td>HippoRAG 2</td> <td>gpt-oss-20b (local)</td> <td>~6 k</td> <td>fixed GPU</td> </tr> <tr> <td>LightRAG</td> <td>gpt-oss-20b (local)</td> <td>~8 k</td> <td>fixed GPU</td> </tr> <tr> <td>RAGU + Meno-Lite-0.1</td> <td>Meno-Lite-0.1 (local)</td> <td>~8 k</td> <td>fixed GPU</td> </tr> </tbody> </table> <p>At 100 k documents, that’s roughly USD 10,000 for MS-GraphRAG against ~USD 100 for RAGU. Read the table carefully, though, and the comparison is <strong>local serving vs. API serving</strong>, not a RAGU-specific win. HippoRAG 2 and LightRAG sit in the same GPU-cost class, and HippoRAG 2 actually uses fewer tokens per document (6 k vs. 8 k).</p> <h2 id="limitations-and-critical-assessment">Limitations and Critical Assessment</h2> <p><strong>Acknowledged by the authors</strong></p> <ul> <li>The scaling evidence rests on a single model family (Qwen2.5) and selected tasks. Robust across six sizes, but a well-supported hypothesis rather than a universal theorem.</li> <li>Meno-Lite-0.1 trades parametric recall for contextual grounding and shouldn’t be used as a standalone knowledge base. Its multi-hop reasoning degrades beyond 32 K tokens, typical of 7 B-class models.</li> <li>There’s a distributional-overlap caveat on the IE benchmark: SFT uses NEREL’s train and validation splits while the benchmark uses only the held-out test split with different instruction wordings. The overlap is confined to schema and text domain, not documents — but a residual advantage can’t be fully ruled out.</li> <li>The default NetworkX backend doesn’t scale to millions of nodes, and final graph quality remains sensitive to the extraction LLM.</li> </ul> <p><strong>What I’d add</strong></p> <ul> <li><strong>The hypothesis is validated on a different domain than it’s applied to.</strong> The language-vs-world-knowledge evidence comes from Russian benchmarks (CheGeKa, MultiQ); the GraphRAG evaluation is entirely English. The hypothesis looks language-independent, but the paper never shows the same slope separation in English.</li> <li><strong>The Evidence Recall numbers disagree between text and figure.</strong> The abstract and body report “evidence recall up to 0.84 vs. ≤0.76” and “84 vs. ≤76%”, while the highest value in Figure 3(b) is 82.4. The comparison baseline (76.1) matches the figure, so 0.84 looks like a rounding or transcription error. It’s more conspicuous for sitting in the abstract.</li> <li><strong>Single domain, single seed.</strong> GraphRAG-Bench was run on Medical only, and no table reports confidence intervals, standard deviations, or seed counts. Calling a −0.9 pp difference “parity” needs a variance estimate.</li> <li><strong>The cost comparison’s counterpart never appears in the quality tables.</strong> The USD 100 vs. USD 10,000 claim is against MS-GraphRAG, which shows up in neither Table 1 nor Table 2. “100× cheaper than the most expensive system” and “competitive quality” are claims about different comparison sets.</li> <li><strong>No query-time cost or latency.</strong> Only indexing is analyzed. But <code class="language-plaintext highlighter-rouge">MixSearch</code> and <code class="language-plaintext highlighter-rouge">QueryPlanEngine</code> issue multiple LLM calls per query by design, and pushing a wide context into gpt-4o-mini shows up on the query bill too. That’s the missing half of the operational story.</li> <li><strong>No prescription for the MuSiQue gap.</strong> Having diagnosed that personalized PageRank finds paths consolidated retrieval misses, the natural next move is an ablation that bolts PPR-style traversal onto RAGU. If the approaches are complementary, that experiment is the one you want, and it isn’t there.</li> <li><strong>Different embedding models across benchmark families.</strong> bge-large-en-v1.5 for GraphRAG-Bench, gte-multilingual-base for multi-hop QA, with no stated reason. Controlled within each table, but it makes cross-table reading harder.</li> <li><strong>The schema’s semantic imprecision is visible in the paper’s own demo.</strong> “Dennis Ritchie created the C programming language” is extracted as <code class="language-plaintext highlighter-rouge">WORKS_AS</code> — no authorship relation appears to exist among the 49 permitted types. Schema constraints buy consistency at the cost of expressiveness, and the paper never confronts that trade-off directly.</li> </ul> <h2 id="takeaways">Takeaways</h2> <ul> <li><strong>Different pipeline stages need different capabilities.</strong> The decomposition — language skills for indexing, world knowledge for answering — is a thinking tool that generalizes well past RAG. When sizing a model for a stage, ask what the scaling exponent of that stage’s required capability actually is.</li> <li><strong>Separating extraction from consolidation buys a lot on its own.</strong> Fixing entities first and feeding them back as constraints on relation extraction eliminates the dangling-edge error class by construction. A textbook case of splitting the pipeline being cheaper and more reliable than growing the model.</li> <li><strong>A large share of a benchmark gap can be answer formatting.</strong> Simply reporting under two prompt protocols turned −19.3 pp into −5.5 pp. If your system is losing a benchmark, check whether your prompt matches the gold answer format before you touch retrieval. As a reviewer, treat any gap claim built on overlap metrics as suspect until format is controlled.</li> <li><strong>Broad recall and precise retrieval are different objectives.</strong> Leading Evidence Recall on Fact Retrieval (82.4) while sitting 18 pp behind on Answer Correctness shows how much metric choice drives system evaluation. Optimize Coverage-family metrics for summarization and long-form; optimize precision-family metrics for short-answer lookup.</li> <li><strong>A reproducible engineering critique can be a real contribution.</strong> Pinning a commit hash and anchoring every claim to file and line turned the kind of observation that usually ends up in a blog post into a verifiable academic appendix — while remaining, as readers should note, an audit of a direct competitor.</li> </ul> <h2 id="getting-started">Getting Started</h2> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>graph_ragu
</code></pre></div></div> <p>Meno-Lite-0.1 serves on a single consumer GPU via vLLM:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vllm serve bond005/meno-lite-0.1 <span class="nt">--max-model-len</span> 131072
</code></pre></div></div> <p>The pipeline is configured by injecting the three storage tiers as constructor arguments. Moving from a prototype (NetworkX + NanoVDB) to production (Neo4j + Qdrant) being an argument swap is the central claim of that design.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Conceptual sketch — see the repository for exact API signatures
</span><span class="kn">from</span> <span class="n">graph_ragu</span> <span class="kn">import</span> <span class="n">RAGU</span><span class="p">,</span> <span class="n">Settings</span>

<span class="n">ragu</span> <span class="o">=</span> <span class="nc">RAGU</span><span class="p">(</span><span class="n">settings</span><span class="o">=</span><span class="nc">Settings</span><span class="p">(</span><span class="n">language</span><span class="o">=</span><span class="sh">"</span><span class="s">en</span><span class="sh">"</span><span class="p">))</span>
<span class="k">await</span> <span class="n">ragu</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">documents</span><span class="p">)</span>                  <span class="c1"># the six-stage indexing pipeline
</span><span class="n">answer</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ragu</span><span class="p">.</span><span class="nf">search</span><span class="p">(</span><span class="sh">"</span><span class="s">...</span><span class="sh">"</span><span class="p">,</span> <span class="n">engine</span><span class="o">=</span><span class="sh">"</span><span class="s">local</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div> <p>Full API documentation and runnable examples live in the repository, along with a demo web frontend and a walkthrough video.</p> <h2 id="references">References</h2> <ul> <li>Paper: <a href="https://arxiv.org/abs/2607.11683">arXiv:2607.11683</a></li> <li>Code: <a href="https://github.com/RaguTeam/RAGU">github.com/RaguTeam/RAGU</a> (MIT)</li> <li>Model: <a href="https://huggingface.co/bond005/meno-lite-0.1">bond005/meno-lite-0.1</a> (Apache 2.0)</li> <li>Demo video: <a href="https://youtu.be/bicJDMJuQfg">youtu.be/bicJDMJuQfg</a></li> </ul> <h2 id="further-reading">Further Reading</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2404.16130">From Local to Global: A Graph RAG Approach to Query-Focused Summarization</a></strong> (Edge et al., 2024) — The original Microsoft GraphRAG paper, which introduced community detection plus map-reduce community summarization for global questions. RAGU’s Steps 4–6 sit directly in this lineage.</li> <li><strong><a href="https://arxiv.org/abs/2410.05779">LightRAG: Simple and Fast Retrieval-Augmented Generation</a></strong> (Guo et al., 2025) — Single-pass free-form extraction with dual-level retrieval, built to cut GraphRAG’s indexing cost. It serves here as the control for “what happens without a consolidation step”.</li> <li><strong><a href="https://arxiv.org/abs/2502.14802">From RAG to Memory: Non-Parametric Continual Learning for Large Language Models</a></strong> (Gutiérrez et al., ICML 2025) — HippoRAG 2. Personalized PageRank traversal gives it precision on single facts and strength at chain-following. The main comparison target here, and the system that keeps MuSiQue.</li> <li><strong><a href="https://arxiv.org/abs/2506.05690">When to Use Graphs in RAG: A Comprehensive Analysis for Graph Retrieval-Augmented Generation</a></strong> (Xiang et al., ICLR 2026) — The GraphRAG-Bench paper. Its four-level difficulty design (fact retrieval → creative generation) is what makes the cross-over in this review visible at all.</li> <li><strong><a href="https://arxiv.org/abs/2108.13112">NEREL: A Russian Dataset with Nested Named Entities, Relations and Events</a></strong> (Loukachevitch et al., 2021) — Source of the 29-entity, 49-relation schema RAGU uses as its extractor output space. That it was designed for Russian news is the key to understanding the schema limitations discussed above.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="graphrag"/><category term="retrieval-augmented-generation"/><category term="knowledge-graph"/><category term="information-extraction"/><category term="small-language-models"/><category term="open-source"/><summary type="html"><![CDATA[A GraphRAG engine that separates extraction from consolidation, and a scaling hypothesis that justifies running the whole indexing pipeline on a 7B model]]></summary></entry><entry xml:lang="ko"><title type="html">[논문 리뷰] Hierarchical Self-Improvement: A Framework for Task-Specific Evolvable Agent Harnesses</title><link href="https://baba9811.github.io/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/" rel="alternate" type="text/html" title="[논문 리뷰] Hierarchical Self-Improvement: A Framework for Task-Specific Evolvable Agent Harnesses"/><published>2026-08-14T05:00:00+00:00</published><updated>2026-08-14T05:00:00+00:00</updated><id>https://baba9811.github.io/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific</id><content type="html" xml:base="https://baba9811.github.io/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/en/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/" class="btn btn-sm btn-outline-secondary">🇺🇸 Read in English</a> </div> <h2 id="메타정보">메타정보</h2> <table> <thead> <tr> <th>항목</th> <th>내용</th> </tr> </thead> <tbody> <tr> <td>저자</td> <td>Tailin Zhou (HKUST)</td> </tr> <tr> <td>학회</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv 또는 DOI</td> <td><a href="https://arxiv.org/abs/2608.08466">2608.08466</a></td> </tr> <tr> <td>Code</td> <td><a href="https://github.com/TailinZhou/hsi">TailinZhou/hsi</a></td> </tr> <tr> <td>데이터</td> <td>BALROG — BabyAI · BabaIsAI · Crafter · MiniHack · TextWorld · NLE 의 6개 장기 호흡 텍스트 게임 환경</td> </tr> <tr> <td><span style="white-space: nowrap">리뷰 일자</span></td> <td>2026-08-14</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>모델 파라미터를 전혀 건드리지 않고 <strong>에이전트를 둘러싼 실행 스캐폴드 (harness) 만</strong> 진화시킨다. 하나의 frozen LLM 이 세 계층 — 태스크를 수행하는 harness $H$, $H$ 를 고쳐 쓰는 evolver, evolver 의 전략 $\Sigma$ 를 고쳐 쓰는 meta-evolver — 에서 동시에 동작하며, 가장 바깥 실행 로직만 frozen anchor 로 고정해 무제한 자기참조를 막는다.</li> <li>DeepSeek-V4-Flash 를 frozen backbone 으로 BALROG 에서 초기 harness 대비 BabyAI +39.3, Crafter +33.0, TextWorld +25.0, MiniHack +15.0 (raw % Progress). 5개 환경 평균은 18.9 → 41.4 로 두 배 이상 오른다.</li> <li>BabaIsAI 에서 20% 미공개 split 을 두고 평가하면 BreakStop 0.98, GoTo 1.00 으로 held-out 일반화까지 확인된다. 반면 NLE 는 meta-on 에서도 0.2 에 머물러 아무 개선이 없다.</li> <li>핵심 주장은 성능 수치가 아니라 <strong>경계</strong>다. harness 진화는 두 가지 상한에 묶인다 — 진화를 이끌 보상 신호가 있어야 한다는 <em>feedback-fidelity bound</em>, 그리고 backbone 이 못 하는 일은 harness 를 아무리 고쳐도 안 된다는 <em>backbone capability bound</em>.</li> <li>태스크 실행 중에는 reasoning 을 끄고 (thinking-off), 자기수정 중에만 켜는 설계로 “추론 예산을 더 쓴 것 아니냐”는 교란 요인을 분리해냈다. 이게 이 논문에서 가장 정직한 부분이다.</li> </ul> <h2 id="소개-introduction">소개 (Introduction)</h2> <p>LLM 에이전트를 개선하는 방법을 떠올려 보면 대부분 두 갈래로 나뉜다. 하나는 모델 자체를 손보는 쪽 — 추가 학습, RLHF, 더 큰 모델로 교체. 다른 하나는 모델 주변을 손보는 쪽 — 프롬프트를 다듬고, 툴을 붙이고, 메모리 구조를 바꾸고, 검증 로직을 넣는다. 후자를 통칭해 <strong>harness</strong> 라고 부른다. 실무에서 에이전트를 만들어 본 사람이라면 두 번째가 실제로 성능을 얼마나 크게 흔드는지 안다. 같은 모델을 쓰는데도 harness 설계에 따라 벤치마크 점수가 20점씩 갈리는 일이 흔하다.</p> <p>문제는 이 harness 가 거의 항상 <strong>사람이 손으로 만들고, 배포 이후에는 고정된 유물</strong>로 취급된다는 점이다. 에이전트는 태스크를 수행하지만, 자기가 태스크를 수행하는 방식 자체를 고쳐 쓰지는 못한다. 최근의 자기개선 (self-improvement) 연구들이 이 틈을 파고들었지만, 대부분은 편집 가능한 경계를 에이전트의 <em>per-step 의사결정 코드</em> 에 두거나 (Gödel Agent, Darwin Gödel Machine 계열), 아니면 더 넓은 스캐폴드를 다루더라도 <strong>외부의 더 강한 모델</strong>을 proposer 로 두고 최적화한다 (Meta-Harness, AHE 계열). 전자는 진화 가능한 표면이 좁고, 후자는 “개선된 게 에이전트인가 아니면 그걸 설계한 더 센 모델인가”라는 귀속 문제를 남긴다.</p> <p>여기에 더 불편한 지적이 하나 있다. Wang et al. (2026b) 의 <em>Rethinking the Evaluation of Harness Evolution</em> 은 피드백과 추론 예산을 맞춘 통제 실험에서, unit test 가 없는 조건에서 harness evolution 67.4% 대 단순 병렬 샘플링 72.3%, unit test 가 있는 조건에서 75.8% 대 86.0% 로 <strong>양쪽 모두 병렬 샘플링이 앞섰다</strong>고 보고했다. 탐색과 평가 태스크가 분리되면 일반화 이득은 +0.6pp 에 그친다. 즉 지금까지 보고된 harness evolution 의 이득 상당수가 <strong>진짜 능력 향상이 아니라 테스트 타임 탐색을 더 한 결과</strong>일 수 있다는 것이다. 이 논문은 정확히 그 비판을 정면으로 받는 설계를 들고 나온다.</p> <p>그래서 던지는 질문은 이렇다. <em>모델이 얼어 있을 때, 에이전트는 자기 harness 를 내생적으로 진화시켜 성능을 올릴 수 있는가? 그리고 그 개선을 궁극적으로 무엇이 제한하는가?</em> 앞부분은 이미 여러 논문이 시도했고, 이 논문의 진짜 기여는 뒷부분에 있다.</p> <h2 id="핵심-기여-key-contributions">핵심 기여 (Key Contributions)</h2> <ul> <li><strong>HSI 프레임워크.</strong> frozen LLM 하나가 중첩된 세 개의 rewriting scope 에서 동작하며 자기 태스크 harness 를 진화시킨다. 가장 바깥 실행 로직을 frozen anchor 로 고정해 재귀적 자기수정이 무한히 번지지 않게 한다. 세 스코프는 같은 모델·같은 프롬프트 포맷·같은 <code class="language-plaintext highlighter-rouge">react()</code> 프리미티브를 공유하고, <strong>오직 사용 가능한 툴과 실행 컨텍스트로만 구분</strong>된다.</li> <li><strong>모델 상한을 통제한 상태의 긍정 증거.</strong> frozen DeepSeek-V4-Flash 로 BALROG 의 중간 난이도 환경에서 일관된 이득을 얻고, BabaIsAI 서브스위트에서는 held-out 일반화까지 보인다. 특히 태스크 실행 시 reasoning 을 끄는 프로토콜로 inference-time reasoning 을 교란 요인에서 제거했다.</li> <li><strong>스케일링 한계의 실증적 특성화.</strong> 피드백 가용성과 backbone 능력이라는 두 실천적 경계를 식별하고, 난이도가 다른 환경들을 가로질러 언제 내생적 harness 진화가 먹히고 언제 안 먹히는지를 보인다. NLE 에서의 실패를 감추지 않고 결과의 일부로 제시한 게 이 논문의 성격을 잘 보여준다.</li> <li><strong>task-specific 진화라는 스케일링 축.</strong> 하나의 만능 harness 를 찾는 대신, 태스크 패밀리마다 자기 harness 를 따로 유지하고 고정된 task-injection seam 을 통해 iteration 간에 hot-swap 한다. Wang et al. (2026b) 가 지적한 “universal harness 의 overfitting” 문제를 설계 차원에서 우회하는 선택이다.</li> </ul> <h2 id="관련-연구--배경-지식">관련 연구 / 배경 지식</h2> <h3 id="gödel-machine-계보">Gödel Machine 계보</h3> <p>Schmidhuber (2003) 의 Gödel Machine 은 자기 프로그램을 — 미래의 수정을 담당하는 절차까지 포함해 — 스스로 고칠 수 있는 시스템을 제안했다. 단, 그 수정이 성능을 개선한다는 것이 <strong>증명 가능할 때만</strong> 수정한다는 조건이 붙었다. 이 증명 조건은 실제로는 충족 불가능에 가까웠고, 최근 LLM 기반 후속 연구들은 증명을 경험적 검증으로 갈아끼우며 이 아이디어를 실용화했다.</p> <p>Gödel Agent (Yin et al., 2025) 는 런타임 코드 수정으로 자기참조적 개선을 실현했고, Darwin Gödel Machine (Zhang et al., 2026b) 은 자기참조 코드 수정에 population 기반 open-ended 탐색을 결합해 SWE-bench 20.0% → 50.0% 를 달성했다. 여기서 흥미로운 결과 하나 — DGM 의 greedy ablation 은 39.7% 에 그쳐, archive 기반 탐색이 본질적이라는 것을 보였다. Huxley-Gödel Machine (Wang et al., 2025) 은 벤치마크 성능과 자기개선 잠재력 사이의 불일치를 지적하며 clade 수준 meta-productivity (CMP) 를 도입했고, Group-Evolving Agents (Weng et al., 2026) 는 진화 단위를 개체에서 그룹으로 옮겼다. HyperAgents (Zhang et al., 2026c) 는 meta-mechanism 자체를 편집 가능하게 만들어 이 방향을 한 단계 더 밀었다.</p> <p>이 계보의 공통점은 편집 가능한 경계를 <strong>에이전트의 의사결정 절차나 프로그램 실행 코드</strong>에 둔다는 것이다. 더 넓은 agent harness 를 내생적으로 진화시킬 수 있는가는 열린 문제로 남아 있었다.</p> <h3 id="harness-engineering">Harness engineering</h3> <p>harness engineering 은 LLM 을 둘러싼 실행 컴포넌트 — 프롬프트, 툴, 메모리, 검증 메커니즘 — 가 에이전트 행동과 성능을 어떻게 규정하는지를 다룬다. Meta-Harness (Lee et al., 2026b) 는 harness 최적화를 outer-loop 탐색 문제로 정식화했는데, 여기서 proposer 는 전체 파일시스템 접근권을 가진 더 강한 coding agent 다. AutoHarness (Lou et al., 2026) 는 Thompson sampling 기반 트리 탐색으로 code harness 를 합성한다. Self-Harness (Zhang et al., 2026a) 는 weakness mining · harness proposal · proposal validation 의 3단계로 고정 모델이 외부 도움 없이 자기 harness 를 개선할 수 있음을 보였다 (MiniMax M2.5 40.5% → 61.9%).</p> <p>배포 중 적응을 다루는 흐름도 있다. TTHE (Nie et al., 2026) 는 실행 트레이스로 테스트 타임에 harness 를 진화시키고, Live-SWE-Agent (Xia et al., 2025) 는 문제 해결 중에 툴을 만들어 쓴다. Continual Harness (Karten et al., 2026) 는 reset-free 온라인 환경으로 확장했다.</p> <p>그런데 이들 대부분은 <strong>태스크 harness 자체를 진화</strong>시킬 뿐, harness 가 어떻게 발견·선택·재작성되는지를 지배하는 <em>메커니즘</em> 은 진화시키지 않는다. HSI 가 파고드는 지점이 정확히 여기다.</p> <h3 id="평가와-이론적-한계">평가와 이론적 한계</h3> <p>Harness-Bench (Yao et al., 2026) 는 harness 설계를 독립적인 평가 축으로 세우고, 동일 모델에서도 harness 구성에 따라 최대 23.8 점의 격차가 난다는 것을 보였다. Harness Updating Is Not Harness Benefit (Lin et al., 2026b) 은 harness 를 <em>업데이트하는 능력</em> 과 그 업데이트로부터 <em>이득을 보는 능력</em> 을 분리했는데, 후자가 non-monotonic 이라는 게 핵심 발견이다 — 중간 티어 모델이 가장 크게 이득을 보고 (+19.3pp), 약한 모델은 skill-load rate 가 낮아 (25.1% vs 95.7%) 이득이 가장 적다. 이 논문의 NLE 실패 사례에 대한 직접적인 선례다.</p> <p>이론 쪽에서는 Wang et al. (2026a) 가 자기수정 하에서 distribution-free PAC 보장이 보존되는 <strong>필요충분조건</strong>이 policy-reachable hypothesis family 의 VC dimension 이 균등하게 유계인 것임을 보였다. 태스크가 요구하는 함수 복잡도가 모델의 도달 가능한 VC dimension 을 넘어서면 어떤 harness engineering 도 그 격차를 메울 수 없다. HSI 의 <em>backbone capability bound</em> 는 이 정리의 경험적 대응물이다.</p> <div class="row mt-3"><div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab4-comparative-summary-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab4-comparative-summary-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab4-comparative-summary-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab4-comparative-summary.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 4: 대표적 harness evolution / self-improvement 방법과 HSI 의 비교. Proposer 는 누가 harness 편집을 제안하는지, Surface 는 편집 가능한 코드 표면이다. 대부분의 선행 연구가 Domain 열에서 Coding 에 몰려 있는 반면 HSI 만 BALROG 라는 점, 그리고 Proposer 가 'Same frozen M' 인 점이 이 논문의 좌표를 보여준다.</figcaption> </figure> </div></div> <h2 id="방법--아키텍처-상세">방법 / 아키텍처 상세</h2> <h3 id="설계-원칙--왜-계층이어야-하는가">설계 원칙 — 왜 계층이어야 하는가</h3> <p>HSI 가 상정하는 harness 는 <em>task-specific and continuously evolvable</em> 하다. 태스크 패밀리마다 자기 harness 를 유지하고, 고정된 task-injection seam 을 통해 iteration 간에 hot-swap 되며, 환경 피드백으로 다듬어진다.</p> <p>여기서 왜 계층 분리가 필연적인지가 나온다. 단층 설계라면 harness 의 태스크 대면 동작과 그 harness 를 고쳐 쓰는 전략이 한 덩어리에 묶인다. 최적화의 <em>대상</em> 과 <em>최적화기</em> 가 분리 불가능해지는 것이다. 계층 분리는 이 둘을 떼어낸다 — 태스크 harness 는 진화하되 그것을 고쳐 쓰는 절차는 고정되고, 그 rewriting 절차 자체는 한 층 위에서 진화하되 가장 바깥 anchor 는 frozen 으로 남는다.</p> <p><strong>Principle 1 (단일 frozen 모델, 세 harness 스코프).</strong> 하나의 frozen LLM $M$ 이 세 계층에서 동작한다. task-harness scope 에서 $M$ 은 harness $H$ 를 실행해 환경과 상호작용한다. evolver scope 에서 $M$ 은 seed selection · harness evolution · candidate selection 을 통해 $H$ 를 수정한다. meta-evolver scope 에서 $M$ 은 evolver 전략 자체를 — seed 생성, commit selection, archive 유지, 최종 버전 export 같은 결정을 포함해 — 수정한다.</p> <p>세 스코프는 같은 frozen 모델, 같은 프롬프트 포맷, 같은 <code class="language-plaintext highlighter-rouge">react()</code> 프리미티브를 공유한다. <strong>다른 것은 오직 사용 가능한 툴과 실행 컨텍스트뿐</strong>이다. 스코프는 명시적 메모리 경계로 분리되며, 독립된 에이전트가 아니라 독립된 히스토리를 유지한다. 이 점이 중요하다 — Meta-Harness 나 AHE 처럼 외부의 더 강한 proposer 를 쓰는 접근과 달리, HSI 는 양쪽 모두에 같은 frozen 모델을 쓴다. 그래서 개선의 귀속이 명확하다.</p> <p><strong>Principle 2 (자기결정적 explore–exploit).</strong> HSI 는 진화 중 explore–exploit 스케줄을 명시하지 않는다. 언제 코드를 살펴볼지, 후보를 평가할지, 교훈을 기록할지, 탐색과 활용에 노력을 어떻게 배분할지 — 전부 $M$ 이 통제하는 진화 가능 전략의 일부로 취급된다. 프레임워크는 원자적 상호작용 프리미티브, 진화 피드백 신호, 구조적 불변식만 제공한다.</p> <h3 id="세-계층-스코프">세 계층 스코프</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig1-hsi-framework-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig1-hsi-framework-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig1-hsi-framework-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig1-hsi-framework.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: HSI 프레임워크. 오른쪽 초록 블록이 태스크 harness H (HarnessPolicy, context/memory/prompt, hook/tool/helper), 가운데 파랑이 evolver 의 3단계 (seed selection → main evolution → commit selection), 왼쪽 보라가 meta-evolver 로 evolver 전략 Σ 의 네 정책 (seed / evolution / commit / best-version selector) 을 고쳐 쓴다. 하단 File System 이 세 스코프의 메모리 경계를 물리적으로 분리한다.</figcaption> </figure> <p><strong>task-harness scope</strong> 는 현재 harness $H$ 를 실행한다. $H$ 안에는 프롬프트, 툴, 메모리, 상태 관리, hook, 그리고 모델이 환경과 상호작용하는 방식을 결정하는 정책이 들어 있다. 진화의 주된 편집 대상이며, 고정된 injection seam 으로 태스크에 연결된다.</p> <p><strong>evolver scope</strong> 는 iteration 을 가로질러 태스크 harness 를 수정한다. $\Sigma$ 가 정의하는 진화 절차를 실행하며, 각 iteration 은 seed selection · main evolution · commit selection 의 세 단계로 구성된다. harness 평가를 통해 환경 피드백을 받고, evolution archive 와 bootstrap memory 로 지속적 정보를 유지한다.</p> <p><strong>meta-evolver scope</strong> 는 harness 진화 과정보다 한 층 위에서 동작하며 $\Sigma$ 자체를 수정한다. 다만 <strong>meta-evolution 을 수행하는 실행 로직은 편집 불가능</strong>하다. 불변 초기화 템플릿에서 로드되며, 자기수정을 경계 짓는 바깥 frozen anchor 역할을 한다.</p> <p>부록의 Eq. 9 가 이 계층을 한 줄로 요약한다.</p> \[M \;\longrightarrow\; H \;\longrightarrow\; \Sigma \;\longrightarrow\; \text{frozen anchor}\] <p>아래 층은 적응 가능하고, 가장 바깥 실행 경계는 고정된다. 재귀적 수정 과정이 여기서 종료된다.</p> <h3 id="5단계-진화-루프">5단계 진화 루프</h3> <p>진화 과정은 다섯 단계로 이루어진다. 앞의 세 단계는 태스크 harness $H$ 에 작용하고, 네 번째는 진화 전략 $\Sigma$ 를 수정하며, 마지막 단계는 평가용으로 export 할 harness 를 고른다. 각 단계는 bounded <code class="language-plaintext highlighter-rouge">react()</code> 루프로 구현되며 중심 결정은 frozen LLM $M$ 에 위임된다.</p> <p>$H_t$ 를 iteration $t$ 시작 시점의 harness, $\mathcal{G}_t = (V_t, E_t)$ 를 누적 evolution graph 라 하자. 각 노드 $v \in V_t$ 는 보상 $r_v$ 로 주석된 commit 된 harness 스냅샷이고, edge 는 버전 간 의미적 관계를 담는다.</p> \[\begin{aligned} (\hat{H}_t,\, h_t) &amp;= \mathrm{SeedSelect}(\mathcal{G}_t,\, M) &amp;&amp;\text{(1)} \\ \{V_t^{(k)}\}_{k=1}^{K_t} &amp;= \mathrm{MainEvolve}(\hat{H}_t,\, h_t;\, M) &amp;&amp;\text{(2)} \\ C_t &amp;= \mathrm{CommitSelect}(\{V_t^{(k)}\}_{k=1}^{K_t},\, \mathcal{G}_t;\, M) &amp;&amp;\text{(3)} \\ \Sigma_{t+1} &amp;= \mathrm{MetaEvolve}(\mathcal{G}_t \cup C_t,\, \Sigma_t;\, M) &amp;&amp;\text{(4)} \\ H^{*} &amp;= \mathrm{BestVersionSelect}(\mathcal{G}_T,\, M,\, \Sigma) &amp;&amp;\text{(5)} \end{aligned}\] <p>(논문의 원 표기는 각각 <code class="language-plaintext highlighter-rouge">seed_selection</code>, <code class="language-plaintext highlighter-rouge">main_evolution</code>, <code class="language-plaintext highlighter-rouge">commit_selection</code>, <code class="language-plaintext highlighter-rouge">meta_evolution</code>, <code class="language-plaintext highlighter-rouge">best_version_selection</code> 이다.)</p> <p><strong>Seed selection (Eq. 1)</strong> 은 $\mathcal{G}_t$ 에서 조상 하나를 골라 다음 iteration 을 위한 구조화된 가설 $h_t$ 를 생성한다. 결정은 $M$ 이 이전 보상, 진화 이력, 누적 교훈을 근거로 내린다. 생성된 가설은 네 요소를 담는다 — 선택된 anchor 버전, 그것을 고른 동기, 기대하는 개선 방향, 그리고 <strong>falsification criterion</strong>. 이 마지막 항목이 설계상 흥미롭다. 가설이 이후 진화 과정에 주입되면서, 진화는 제약 없는 mutation 에서 명시적 예측이 이끄는 goal-directed 탐색으로 바뀐다.</p> <p><strong>Main evolution (Eq. 2)</strong> 은 $M$ 이 태스크 harness 를 직접 수정하는 단계다. 편집 가능 표면은 프롬프트, 툴, 메모리, 상태 관리, hook, 실행 정책 등 harness 의 모든 태스크 대면 컴포넌트를 포함한다. 여기서 유일하게 보존되는 불변식이 <strong>task-injection interface</strong> 다 — 내부 컴포넌트는 얼마든지 바뀌어도, 태스크를 harness 에 연결하는 외부 인터페이스는 고정된다. 이 불변식 덕에 진화된 버전들을 직접 비교할 수 있고 harness 가 iteration 간에 hot-swappable 해진다.</p> <p><strong>Commit selection (Eq. 3)</strong> 은 최고 보상 후보 하나만 고르지 않는다. 여러 진화 방향을 담은 <strong>다양성 있는 commit pool</strong> 을 유지한다. 선택된 각 버전은 $M$ 이 생성한 의미적 근거와 함께 evolution graph 에 추가되어, 이후 seed selection 이 성공·실패·미탐색 분기를 추론할 수 있게 한다.</p> <p><strong>Meta-evolution (Eq. 4)</strong> 은 harness 진화를 지배하는 전략 $\Sigma$ 를 수정한다. $\Sigma$ 의 편집 가능 표면에는 seed selection, main evolution, commit selection, 최종 버전 선택을 담당하는 절차가 포함된다. $\Sigma$ 를 바꿈으로써 meta-evolver 는 후보 harness 만이 아니라 <strong>미래의 harness 를 발견하는 탐색 전략 자체</strong>를 바꾼다.</p> <p><strong>Best-version selection (Eq. 5)</strong> 은 $T$ iteration 후 배포할 harness 를 고른다. 다양성을 유지하는 중간 commit selection 과 달리 이 단계는 <strong>일반화를 우선</strong>한다. 후보들은 validation 성능으로 평가되고 선택된 harness 가 held-out 평가로 export 된다. 선택 절차 자체도 $\Sigma$ 의 일부라, meta-evolution 이 최종 배포 결정 방식까지 적응시킬 수 있다.</p> <h3 id="실행-인터페이스와-메모리">실행 인터페이스와 메모리</h3> <p>모든 HSI 컴포넌트는 같은 frozen LLM $M$ 과 공유 <code class="language-plaintext highlighter-rouge">react()</code> 실행 프리미티브로 인스턴스화된다. 매 스텝 모델은 현재 메시지 히스토리, 사용 가능 툴, 태스크별 컨텍스트를 받아 행동을 낸다.</p> \[a_t = M(o_t,\, \mathcal{T},\, \mathcal{C}_t)\] <p>$o_t$ 는 현재 관측, $\mathcal{T}$ 는 사용 가능 툴 집합, $\mathcal{C}_t$ 는 스코프별 컨텍스트다. 선택된 행동은 파일을 수정하거나, 평가를 요청하거나, 정보를 기록하거나, 현재 단계를 종료할 수 있다.</p> <p>evolver scope 의 툴은 파일 조작 (<code class="language-plaintext highlighter-rouge">read</code>, <code class="language-plaintext highlighter-rouge">write</code>, <code class="language-plaintext highlighter-rouge">edit</code>, <code class="language-plaintext highlighter-rouge">bash</code>) 에 더해 진화 전용 프리미티브를 갖는다.</p> <table> <thead> <tr> <th>툴</th> <th>역할</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">plan</code></td> <td>iteration-local 추론 노트북 유지</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">compact_context</code></td> <td>컨텍스트 예산이 빠듯해지면 이전 상호작용 요약</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">evaluate</code></td> <td>현재 harness 를 실행해 환경 피드백 반환</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">lesson</code></td> <td>이후 iteration 을 위한 재사용 가능한 통찰 기록</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">end_evolution</code></td> <td>현재 진화 과정 종료</td> </tr> </tbody> </table> <p>프레임워크는 이 연산들 사이에 순서를 규정하지 않는다. 언제 무엇을 쓸지는 관측된 피드백과 현재 진화 목표에 따라 모델이 정한다.</p> <p>메모리는 지속성이 다른 세 채널로 나뉜다. <strong>iteration-local memory</strong> 는 <code class="language-plaintext highlighter-rouge">plan.md</code> 에 저장되는 임시 노트북으로, 후보 버전이 폐기되면 코드 상태와 함께 롤백된다. <strong>persistent evolutionary memory</strong> 는 <code class="language-plaintext highlighter-rouge">BOOTSTRAP.md</code> 의 교훈 archive 로, 발견된 패턴·실패한 방향·재사용 가능한 진화 가이드를 요약해 담는다. <strong>evolution graph memory</strong> 는 $\mathcal{G}_t$ 로, 각 노드에 harness 스냅샷 · 달성 보상 · 진화 스텝 메타데이터를 담고 edge 에 “기존 접근 확장”, “실패 모드 수리”, “다른 방향 탐색” 같은 의미 관계를 인코딩한다.</p> <p>전체 히스토리를 LLM 에 그대로 노출하면 컨텍스트 예산을 초과하고 불필요한 노이즈가 들어온다. 그래서 HSI 는 압축 요약을 되찾는 probe 메커니즘을 쓴다.</p> \[z = \mathrm{probe}(\mathcal{T}_{\text{history}},\, q)\] <p>meta-evolver 는 예컨대 “어떤 seed-selection 행동이 성공적 iteration 과 상관되는가”, “어떤 진화 패턴이 자주 regression 으로 이어지는가”, “어떤 가설 구조가 큰 개선에 선행하는가” 같은 질의를 던진다. 장기 진화 이력을 활용하면서도 추론 컨텍스트를 유계로 유지하는 장치다.</p> <h3 id="스코프-격리와-평가-인터페이스">스코프 격리와 평가 인터페이스</h3> <p>HSI 는 세 스코프 사이의 경계를 명시적으로 강제한다. 태스크 harness $H$ 는 evolver 가 편집할 수 있지만 진화 전략 $\Sigma$ 는 수정하지 못한다. 반대로 meta-evolver 는 $\Sigma$ 를 수정할 수 있지만 meta-evolution 중에 태스크 harness 를 직접 건드리지 못한다. 인가된 디렉토리 밖의 수정은 거부된다.</p> <p>평가는 편집 가능 표면 <strong>바깥</strong>에서 수행된다. harness 는 고정된 인터페이스로 태스크를 받는다.</p> \[\mathrm{using\text{-}harness}(\mathit{agent},\, \mathit{task})\] <p>$H$ 의 내부 구현이 iteration 마다 바뀌어도 이 인터페이스는 불변이다. 따라서 진화된 모든 버전이 같은 task injection 메커니즘 아래 동작하고 동일한 development / validation / test 프로토콜로 비교될 수 있다. evaluator 는 스칼라 보상과 선택적 텍스트 피드백을 함께 반환한다.</p> <h2 id="학습-목표--손실-함수">학습 목표 / 손실 함수</h2> <p>HSI 에는 gradient 로 최소화하는 손실 함수가 없다. 모델 파라미터가 얼어 있기 때문이다. 대신 후보 harness 를 순위 매기는 <strong>확률적 lower-confidence-bound 보상</strong>이 최적화 신호 역할을 한다.</p> \[r = \mu - z \cdot \frac{\sigma}{\sqrt{n}}, \qquad z = 0.5\] <p>$\mu$ 와 $\sigma$ 는 평가 trial 들에 대한 평균과 표준편차, $n$ 은 trial 수다. BALROG 의 episode-level % Progress (0–100) 를 $[0,1]$ 로 rescale 해 쓴다.</p> <p>이 보상 형태가 왜 필요한지는 생각해 볼 만하다. 진화 중 후보 harness 는 효율을 위해 호출당 <strong>에피소드 1개</strong>로 평가된다. 이런 저표본 환경에서 평균만 보고 고르면 운 좋게 높은 점수를 받은 궤적이 선택될 위험이 크다. LCB 는 분산에 비례해 페널티를 매겨 이 낙관 편향을 깎아낸다. $z = 0.5$ 는 페널티를 세게 걸지 않는 값인데, 탐색을 지나치게 억누르지 않으려는 절충으로 읽힌다.</p> <p>다만 <strong>보고되는 모든 결과는 LCB 보상이 아니라 raw % Progress 평균</strong>이다. LCB 는 진화 중 후보 선택에만 쓰이고, 최종 평가는 full episode budget 으로 더 안정적인 추정을 얻는다. 이 분리는 정직한 설계다 — 선택 기준과 보고 기준을 섞으면 selection bias 가 결과에 스며든다.</p> <h2 id="학습-데이터와-파이프라인">학습 데이터와 파이프라인</h2> <h3 id="벤치마크">벤치마크</h3> <p>BALROG (Paglieri et al., 2025) 는 계획, 메모리, 탐색, 툴 사용 능력을 평가하도록 설계된 장기 호흡 텍스트 기반 상호작용 환경 벤치마크다. 6개 환경이 능력 요구 수준을 달리해 배치되어 있다.</p> <table> <thead> <tr> <th>환경</th> <th>요구 능력</th> </tr> </thead> <tbody> <tr> <td>BabyAI</td> <td>구조화된 환경에서의 지시 따르기와 내비게이션</td> </tr> <tr> <td>BabaIsAI</td> <td>규칙 조작이 필요한 퍼즐 (서브스위트: BreakStop / GoTo / Make / Advanced)</td> </tr> <tr> <td>Crafter</td> <td>장기 계획, 자원 관리, 순차적 의사결정</td> </tr> <tr> <td>TextWorld</td> <td>다단계 추론과 객체 조작</td> </tr> <tr> <td>MiniHack</td> <td>복잡한 상태 공간과 희소 피드백의 로그라이크</td> </tr> <tr> <td>NLE</td> <td>위와 같으나 훨씬 더 어려움 (NetHack Learning Environment)</td> </tr> </tbody> </table> <p>이 난이도 스펙트럼이 논문 결론의 핵심 장치다. frozen backbone 이 non-trivial 성능을 내는 태스크부터 성능이 바닥에 머무는 태스크까지 한 프레임 안에 놓여 있어서, harness 진화가 <strong>어디서 먹히고 어디서 멈추는지</strong>를 같은 실험 안에서 관찰할 수 있다.</p> <h3 id="backbone-과-진화-설정">Backbone 과 진화 설정</h3> <p>모든 실험은 <code class="language-plaintext highlighter-rouge">deepseek-v4-flash-preview</code> API 로 접근한 DeepSeek-V4-Flash 를 세 스코프 전체의 frozen backbone 으로 쓴다. 진화 run 하나는 $T = 5$ outer iteration 으로 구성되고, iteration 당 최대 80 <code class="language-plaintext highlighter-rouge">react()</code> 스텝이 주어진다.</p> <p>가장 중요한 설정이 <strong>thinking on/off 분리</strong>다.</p> <table> <thead> <tr> <th>스코프</th> <th>reasoning</th> <th>온도</th> <th>스텝 예산</th> </tr> </thead> <tbody> <tr> <td>task-harness</td> <td>비활성 (thinking off)</td> <td>0</td> <td>—</td> </tr> <tr> <td>evolver</td> <td>활성, reasoning effort 최대</td> <td>—</td> <td>iteration 당 최대 80 <code class="language-plaintext highlighter-rouge">react()</code></td> </tr> <tr> <td>meta-evolver</td> <td>활성</td> <td>—</td> <td>iteration 당 최대 50 <code class="language-plaintext highlighter-rouge">react()</code></td> </tr> </tbody> </table> <p>태스크 실행 중 확장 추론을 끄면 모델의 per-step 능력 상한이 고정된다. 이 설정은 development 평가, validation 평가, best-version selection, 최종 테스트에 걸쳐 고정된다. 따라서 <strong>태스크 실행 중 관찰된 개선은 inference time 의 추가 추론 연산으로 돌릴 수 없다</strong>. Wang et al. (2026b) 가 제기한 “test-time scaling 교란” 비판에 대한 직접적인 대응이다.</p> <p>진화 공간에도 제약이 걸린다. 모든 태스크 상호작용은 frozen backbone $M$ 을 거쳐야 한다. 진화는 프롬프트·툴·메모리·상태 관리·제어 로직을 수정할 수 있지만, <strong>모델을 외부 탐색 절차나 non-LLM 정책으로 대체할 수는 없다</strong>. 이 제약이 없으면 “harness 진화”가 사실상 “LLM 을 버리고 BFS 를 짜 넣기”로 퇴화한다.</p> <p>meta-evolver scope 는 greedy archive 를 쓰고, seed selection 과 commit pooling 이 둘 다 진화 가능하며, seed 가설이 각 iteration 의 첫 시스템 프롬프트에 주입된다. seed selection 중에는 짧은 seed-validation probe (최대 3회 <code class="language-plaintext highlighter-rouge">evaluate()</code> 호출) 가 허용된다. 반면 <strong>terminal best-version selection 단계는 고정된 non-evolvable agentic 단계</strong>로, 모든 진화의 마지막에 한 번 실행된다. init harness 는 사전 평가되지 않으며 iteration 1 은 cold start 다.</p> <h3 id="평가-프로토콜">평가 프로토콜</h3> <p>BALROG 환경은 절차적으로 생성되고 각 <code class="language-plaintext highlighter-rouge">evaluate()</code> 호출이 새 초기 seed 를 샘플링한다. 두 프로토콜을 쓴다.</p> <p><strong>In-distribution evolution (Setup A).</strong> 진화와 최종 평가에 같은 태스크 집합을 쓰되, 각 평가 에피소드는 새로 샘플링된 환경 seed 에서 생성된다. 이전에 마주친 태스크의 확률적 변형 하에서 성능이 개선되는지를 측정한다. TextWorld, BabyAI, Crafter, MiniHack, NLE 에 적용된다.</p> <p><strong>Held-out task generalization (Setup B).</strong> BabaIsAI 에 대해 서브스위트 카테고리 (BreakStop, GoTo, Make, Advanced) 기준으로 태스크 패밀리 split 을 구성한다. 각 서브스위트는 development / validation / test 로 나뉘고, <strong>test split 은 진화 과정 내내 접근 불가</strong>다. Advanced 는 태스크가 3개뿐이라 유의미한 held-out 평가가 불가능해 제외된다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab3-per-suite-config-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab3-per-suite-config-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab3-per-suite-config-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab3-per-suite-config.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 3: 스위트별 실험 설정. Dev / Val 은 스위트에서 dev (진화 보상 신호) 와 val (best-version 선택) 에 배정된 비율, Test ep. 는 최종 테스트의 태스크당 에피소드 수, Dev ep. 는 진화 중 태스크당 에피소드 수 (LCB 보상이 노이즈를 흡수), Test rep. 는 진화 후 전체 테스트를 반복 평가한 횟수, Submit-best 는 terminal best-version selection 단계의 스텝 예산이다.</figcaption> </figure> <h3 id="베이스라인">베이스라인</h3> <p>세 종류의 비교 기준을 둔다. 첫째, <strong>Init Harness</strong> — 진화 없이 같은 backbone 과 같은 평가 프로토콜로 평가한 원본 수작업 harness. 이것이 harness 진화 효과를 재는 주 통제 베이스라인이다. 둘째, 공개된 BALROG 리더보드 결과 — 서로 다른 backbone 과 reasoning 설정을 쓰는 frontier 모델들에 대한 맥락 참조. 셋째, 외부 proposer 기반 harness 최적화 방법들은 <strong>통제 비교에서 의도적으로 제외</strong>했다. 더 강한 외부 모델에 의존하는 방법은 frozen backbone 하의 내생적 진화와 전제가 다르기 때문이다.</p> <h2 id="실험-결과">실험 결과</h2> <h3 id="in-distribution-성능-setup-a">In-distribution 성능 (Setup A)</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab1-balrog-comparison-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab1-balrog-comparison-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab1-balrog-comparison-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab1-balrog-comparison.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 1: Setup A 기준 BALROG 리더보드 비교. 상단 블록은 2026-08-03 에 수집한 frontier 모델들의 공개 리더보드 수치, 하단 3행이 동일 frozen DeepSeek-V4-Flash backbone 하의 통제 비교다. BabaIsAI 는 서브스위트 프로토콜이 리더보드의 mixed-task 프로토콜과 달라 제외됐다.</figcaption> </figure> <p>핵심 비교는 하단 세 행이다. 셋 다 DeepSeek-V4-Flash 를 쓰고 <strong>harness 를 진화시키는지, 어떻게 진화시키는지만 다르다</strong>.</p> <p>같은 backbone 과 같은 task-time inference 설정에서 출발해, meta-evolution-on 설정은 모든 non-trivial 스위트에서 초기 harness 를 크게 개선한다.</p> <blockquote> <p>BabyAI 81.3 (init harness 42.0, +39.3) · Crafter 44.6 (11.6, +33.0) · TextWorld 65.0 (40.0, +25.0) · MiniHack 15.8 (0.8, +15.0)</p> </blockquote> <p>5개 환경 평균은 18.9 → 41.4 로 오른다. backbone 과 task-time reasoning 예산은 그대로 둔 채 얻은 수치다.</p> <p>frontier 시스템과의 비교도 흥미롭다. TextWorld 에서 HSI 는 65.0 % Progress 로 Grok-4 (62.9), Claude-Opus-4.5-Thinking (59.0), Gemini-3-Flash (50.2) 를 넘어선다. Crafter 에서는 44.6 으로 DeepSeek-R1 (36.4), GPT-5-minimal-think (39.1), GPT-4o (33.1) 를 앞선다. 다만 이건 서로 다른 backbone·설정 간 비교이므로 맥락 참조로만 읽어야 하고, harness 진화의 효과를 분리해내는 건 어디까지나 통제된 init-harness 비교다.</p> <h3 id="held-out-일반화-setup-b">Held-out 일반화 (Setup B)</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab2-babaisai-heldout-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab2-babaisai-heldout-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab2-babaisai-heldout-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab2-babaisai-heldout.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 2: Setup B (20% held-out test) 기준 BabaIsAI 서브스위트 결과. Best Dev 는 진화 중 선택된 최고 development 보상, Test 결과는 태스크 간 표준편차와 함께 보고된다. Init Harness 는 3회 베이스라인 run 의 평균이다.</figcaption> </figure> <p>각 서브스위트는 backbone, 진화 예산, 초기화 템플릿, 평가 프로토콜을 고정한 채 독립적인 harness 를 진화시킨다. 유일한 변수는 태스크 패밀리다.</p> <p>결과가 두 개의 뚜렷한 체제로 갈린다. <strong>내비게이션 지향 태스크</strong> (BreakStop, GoTo) 에서는 held-out 성능이 거의 완벽하다 — meta-on 이 각각 0.9800, 1.0000 에 도달한다. 초기 harness 가 0.0333, 0.1818 이었던 걸 감안하면 큰 폭이다. meta-off 변형도 비슷한 수준 (1.0000, 0.9636) 이라, 이 난이도에서는 meta-evolution 이 결정적이지 않다는 뜻이기도 하다. 진화된 harness 가 관찰된 development 태스크를 넘어 전이되는 <strong>재사용 가능한 상호작용 패턴</strong>을 발견했다고 볼 수 있다.</p> <p>반면 <strong>Make 는 확연히 어렵다.</strong> zero-shot init harness (0.0000) 대비 개선은 있지만 held-out 성능이 meta-on 0.3625, meta-off 0.3375 에 그친다. Best Dev 가 0.5556 인 것과 비교하면 dev→test 격차도 크다. 표준편차 0.3284 라는 값도 눈에 띈다 — 태스크에 따라 되기도 하고 안 되기도 한다는 뜻이다. 다단계 crafting 은 진화 중 발견된 재사용 가능한 harness 변환을 넘어서는 능력을 요구한다.</p> <h3 id="meta-evolution-의-효과">Meta-evolution 의 효과</h3> <p>Table 1 의 meta-off ablation 은 진화 전략 자체를 진화시키는 것의 기여를 분리한다. meta-evolver 를 제거하면 평가된 모든 스위트에서 성능이 떨어진다.</p> <table> <thead> <tr> <th>스위트</th> <th>meta-on</th> <th>meta-off</th> <th>차이</th> </tr> </thead> <tbody> <tr> <td>BabyAI</td> <td>81.3</td> <td>77.3</td> <td>−4.0</td> </tr> <tr> <td>Crafter</td> <td>44.6</td> <td>36.4</td> <td>−8.2</td> </tr> <tr> <td>TextWorld</td> <td>65.0</td> <td>46.0</td> <td>−19.0</td> </tr> <tr> <td>MiniHack</td> <td>15.8</td> <td>5.8</td> <td>−10.0</td> </tr> <tr> <td>평균</td> <td>41.4</td> <td>33.1</td> <td>−8.3</td> </tr> </tbody> </table> <p>가장 큰 개선이 TextWorld (+19.0) 와 MiniHack (+10.0) 에서 나온다. <strong>진화 탐색 공간이 복잡해질수록 진화 절차 자체를 적응시키는 게 점점 더 이득</strong>이 된다는 해석이 나온다. 뒤집어 말하면 BabyAI 처럼 상대적으로 단순한 환경에서는 meta-evolution 의 한계 기여가 작다 (+4.0).</p> <p>NLE 는 의미 있는 meta-off 비교가 불가능하다. 두 설정 모두 거의 0 에 가까운 보상을 얻기 때문이다. meta-on 결과 0.2 는 <strong>진화가 유용한 harness 수정을 발견하기에 충분한 태스크 피드백을 받지 못한다</strong>는 신호다.</p> <h3 id="진화-궤적">진화 궤적</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig2-crafter-trajectory-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig2-crafter-trajectory-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig2-crafter-trajectory-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig2-crafter-trajectory.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: Crafter 에서의 HSI 진화 궤적 (Setup A, meta-on). dev 보상이 init harness 0.166 에서 iteration 4 의 0.578 (초록 별 = export 된 best version) 까지 오르고 iteration 5 에서 regression 이 일어난다. 각 iteration 카드는 seed 출처 · main-evolution 편집 · 결과 · commit pool 네 필드와, meta-evolver 가 Σ 에 무엇을 새로 썼는지를 요약한 meta 필드를 담는다.</figcaption> </figure> <p>Crafter 궤적은 전형적인 in-distribution 진화 패턴을 보여준다. 초기 iteration 들은 주로 <strong>누락된 태스크 표현을 도입</strong>한다 — 잠재된 보상 신호 노출, 인벤토리 정보 구조화, action-state 정렬 개선. iteration 1 에서 0.166 → 0.430 (2.6배) 으로 단일 최대 도약이 일어나고, iteration 2 가 구조화된 인벤토리와 crafting 힌트로 0.511 (+19%), iteration 3 이 0.488 에서 정체 (카드에 “hits LLM spatial limit” 로 기록), iteration 4 가 두 조상의 ensemble fusion 과 안전 제약으로 0.578 peak 를 찍는다. iteration 5 에서는 0.497 → 0.341 로 regression 이 발생한다.</p> <p>이 regression 이 중요하다. <strong>진화가 모든 분기를 단조적으로 개선하지 않고 non-convex 한 harness 설계 공간을 탐색한다</strong>는 증거다. best version 이 마지막 iteration 이 아니라 iteration 4 에서 나왔다는 점, 그래서 terminal best-version selection 단계가 필요하다는 점이 여기서 설명된다.</p> <p>meta-evolver 의 기여는 성공적인 국소 발견을 <strong>재사용 가능한 진화 휴리스틱으로 변환</strong>하는 데 있다. iteration 을 가로질러 $\Sigma$ 를 “raw observation 보다 구조화된 상태 표현을 우선하라”, “성능 정체 부근에서 지나치게 공격적인 탐색을 피하라” 같은 상위 원칙으로 갱신한다. 이 변경들은 태스크 성능을 직접 바꾸는 게 아니라 <strong>이후의 탐색 행동</strong>에 영향을 준다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig3-babaisai-make-trajectory-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig3-babaisai-make-trajectory-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig3-babaisai-make-trajectory-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig3-babaisai-make-trajectory.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: BabaIsAI-Make 에서의 HSI 진화 궤적 (Setup B, meta-on). 파란 곡선이 dev 보상, 빨간 링이 commit-pool 버전, 주황 삼각형이 val 모드에서 확정된 commit (해당 commit 자체에는 dev 평가가 기록되지 않음) 을 표시한다. 각 삼각형은 commit 의 anchor x 위치에 val 보상 높이로 찍히고, 점선 수직선이 dev anchor 에서 val 보상까지 내려온다.</figcaption> </figure> <p>BabaIsAI-Make 궤적은 held-out 진화를 보여준다. Crafter 와 달리 Setup B 는 validation 동작을 명시적으로 노출한다. dev peak 는 iteration 을 따라 0.222 → 0.333 → 0.222 (정체) → 0.444 → 0.556 으로 움직인다. 각 iteration 이 도입한 것은 plan tracking 을 갖춘 single-<code class="language-plaintext highlighter-rouge">react()</code> 재작성 (iter 1), WIN-target 지속성을 갖춘 spatial-map builder (iter 2), BFS pathfinding 을 이용한 auto-target 계산 (iter 3), directional fallback 을 갖춘 auto-push 메커니즘 (iter 4), LLM-aware cross-room 내비게이션 (iter 5) 이다.</p> <p>meta-evolver 는 여기서 <strong>“LLM targets, BFS navigates”</strong> 라는 2계층 패턴을 성문화하고 commit pool 을 1개에서 3개로 점진적으로 확장한다. 이 패턴 자체가 꽤 인상적이다 — 목표 선정이라는 의미적 판단은 LLM 에 맡기고, 경로 탐색이라는 결정론적 계산은 BFS 에 맡기는 역할 분담을, 에이전트가 스스로 발견해 전략에 새겨 넣었다는 뜻이다.</p> <p>held-out validation 마커들은 발견된 메커니즘 여럿이 development 태스크를 넘어 전이됨을 보여주지만, 남은 격차 (dev peak 0.556 vs test 0.3625) 는 다단계 crafting 이 여전히 frozen backbone 의 능력 경계에 근접해 있음을 가리킨다.</p> <h2 id="결과-분석--ablation">결과 분석 / Ablation</h2> <h3 id="무엇이-실제로-작동했는가">무엇이 실제로 작동했는가</h3> <p>두 궤적을 겹쳐 보면 일관된 3단 패턴이 보인다. <strong>초기 iteration 은 누락된 추상화를 발견</strong>하고, <strong>중간 iteration 은 구조화된 알고리즘 컴포넌트를 도입</strong>하며, <strong>후기 iteration 은 경쟁하는 설계를 다듬거나 가지치기</strong>한다. 자기개선이 단순 프롬프트 최적화가 아니라 점진적 harness 재구조화를 통해 일어난다는 정성적 증거다.</p> <p>더 구체적으로, Crafter 에서 evolver 가 찾아낸 지배적 레버는 <strong>숨겨진 게임 피드백을 명시화하는 것</strong>이었다 — 보상 신호, 인벤토리 상태, crafting 가능 여부를 harness 컨텍스트에 차례로 노출. 이건 사실 사람이 에이전트를 튜닝할 때 가장 먼저 하는 일이기도 하다. 모델이 못 하는 걸 하게 만든 게 아니라, <strong>모델이 이미 할 수 있는데 정보가 없어서 못 하던 것을 풀어준</strong> 것이다. 이 관찰이 뒤에 나올 두 bound 를 이해하는 열쇠다.</p> <p>또 하나 — 진화 run 전반에서 <strong>가장 큰 성능 개선은 보통 첫 iteration 에서</strong> 일어나고 이후 iteration 은 점진적 이득에 그친다. 초기 harness 재설계가 지배적 개선을 포착하고, 후기 iteration 은 탐색과 선택을 통해 기존 해를 정제한다는 뜻이다. 실용적으로는 $T$ 를 크게 늘리는 것의 수익 체감이 빠르다는 신호다.</p> <h3 id="두-개의-경계">두 개의 경계</h3> <p>BALROG 전체를 가로질러 같은 정성적 패턴이 나타난다. harness 진화는 frozen backbone 이 이미 유의미한 역량을 보이는 태스크에서 가장 크게 개선되고, 능력 경계 근처의 태스크에서는 이득이 작고 노이즈가 크며, 유용한 피드백을 얻기 어려운 태스크에서는 개선이 제한된다.</p> <p><strong>Feedback-fidelity bound.</strong> 진화는 선택을 이끌 정보성 있는 보상 신호를 필요로 한다. harness 수정은 정적 검사만으로는 평가하기 어렵다. 유용한 신호는 오직 “수정된 harness 가 환경에서 실행됐을 때 더 나은 행동을 내는가”뿐이다. NLE 가 이 bound 의 사례다 — 보상이 극도로 희소해 진화가 무엇을 개선해야 할지 알 방법이 없다. meta-on 0.2 라는 수치는 개선이 아니라 노이즈에 가깝다.</p> <p><strong>Backbone capability bound.</strong> harness 재설계는 frozen 모델의 한계를 극복할 수 없다. Crafter iteration 3 의 카드에 적힌 “hits LLM spatial limit” 이 이걸 그대로 보여준다. BabaIsAI-Make 의 dev–test 격차도 같은 맥락이다. harness 진화는 모델 주변의 행동을 재조직하고 증폭할 수 있지만, 모델이 유용한 상호작용 신호를 생성하지 못하는 태스크는 넘어서지 못한다.</p> <p>이 두 bound 는 Wang et al. (2026a) 의 이론적 결과 — 태스크가 요구하는 함수 복잡도가 모델의 도달 가능한 VC dimension 을 넘으면 어떤 자기수정도 그 격차를 못 메운다 — 의 경험적 대응물이다. 그리고 Lin et al. (2026b) 의 “harness-benefit 은 non-monotonic 하고 약한 모델일수록 이득이 적다”는 발견의 직접적 재현이기도 하다.</p> <h3 id="단일-seed-진화라는-선택">단일 seed 진화라는 선택</h3> <p>HSI 는 의도적으로 population 기반 병렬 스케일링을 피하고 <strong>단일 진화 계보</strong>를 따른다. 성능 변화를 후보 처리량 증가가 아니라 harness 재설계에 귀속시킬 수 있게 하기 위해서다. 탐색 효율을 귀속 명확성과 맞바꾼 것이다.</p> <p>이건 방법론적으로 옳은 선택이지만 비용이 있다. DGM 의 ablation 이 보여줬듯 archive 기반 population 탐색은 greedy 대비 실질적 이득 (50.0% vs 39.7%) 을 준다. HSI 는 그 이득을 포기했고, 논문도 이를 인정하며 population 탐색을 상보적인 추가 스케일링 차원으로 남겨둔다.</p> <h2 id="한계와-비판적-평가">한계와 비판적 평가</h2> <p><strong>저자가 인정한 한계.</strong></p> <ul> <li>계산 자원 제약으로 평가가 선별된 벤치마크·backbone·비교 집합에 국한된다. 전면적인 실증 연구가 아니라 초기 탐색이라고 명시한다.</li> <li>진화는 정보성 있는 피드백을 요구하며, 보상이 극도로 희소한 환경에서는 개선 신호가 불충분하다.</li> <li>최종 성능이 frozen 모델의 능력에 제약된다.</li> <li>단일 seed 진화는 탐색 효율을 희생한다.</li> </ul> <p><strong>리뷰어 관점에서 추가로 보이는 한계.</strong></p> <ul> <li><strong>backbone 이 하나뿐이다.</strong> 모든 결과가 DeepSeek-V4-Flash 단일 모델에서 나왔다. Lin et al. (2026b) 이 harness-benefit 의 non-monotonicity 를 보고했고 Zhang et al. (2026a) 이 “같은 초기 harness 와 같은 알고리즘에서 모델마다 완전히 다른 harness 수정이 나온다”는 것을 보인 마당에, 단일 backbone 결과에서 도출한 두 bound 가 얼마나 일반적인지는 알 수 없다. 특히 “중간 티어 모델이 가장 큰 이득을 본다”는 선행 발견이 맞다면, DeepSeek-V4-Flash 는 이득이 가장 잘 보이는 지점에 놓여 있었을 수 있다.</li> <li><strong>통계적 유의성 검정이 없다.</strong> 보고된 변동은 전부 <em>평가</em> 쪽에서 나온다 — 평가 에피소드 간 분산, 그리고 Table 3 의 Test rep. (진화가 끝난 뒤 전체 테스트를 3회까지 재평가) 이다. 정작 <em>진화 run 자체의 재현성</em> — 같은 설정으로 진화를 다시 돌렸을 때 비슷한 harness 가 나오는가 — 은 어디에도 없다. Table 2 에서 3회 베이스라인 run 을 평균낸 것은 Init Harness 뿐이고, HSI 팔은 진화 run 하나로 읽힌다. 진화가 본질적으로 확률적이라고 논문 스스로 말하는 만큼, run-to-run 분산은 결과 해석에 필수적인 정보다. GSME (Luo et al., 2026b) 가 지적한 “비통계적 mean-improves 규칙은 진짜 중립인 메커니즘의 60% 가량을 승리로 오인한다”는 문제가 그대로 적용된다.</li> <li><strong>Table 3 의 Meta 열이 본문 결과와 어긋난다.</strong> 부록 Table 3 은 TextWorld 와 BabaIsAI-BreakStop 의 Meta 를 <code class="language-plaintext highlighter-rouge">off</code> 로 기록하는데, 본문 산문은 이 열을 “meta-evolver scope 가 활성화되었는지”로 정의한다. 그런데 Table 1 은 TextWorld meta-on 65.0 을, Table 2 는 BreakStop meta-on 0.9800 을 보고한다. 두 스위트에 대해 meta-on 팔이 실제로 어떤 설정으로 돌았는지가 불분명하다. TextWorld 는 meta-evolution 기여가 가장 큰 (+19.0) 스위트라 이 모호성의 무게가 작지 않다.</li> <li><strong>Dev / Val 비율 정의가 맞아떨어지지 않는다.</strong> 본문은 Dev 와 Val 을 “스위트에서 각각에 배정된 비율”로 정의하는데, BabaIsAI-GoTo 와 Make 는 Dev 0.8, Val 0.25 로 합이 1.05 다. 여기에 20% test split 까지 더하면 1.25 가 된다. Val 이 dev 의 부분집합이거나 겹치는 것으로 보이지만 명시되어 있지 않아, Setup B 의 split 을 그대로 재현하기 어렵다.</li> <li><strong>held-out 일반화의 증거 폭이 좁다.</strong> 실제로 held-out 평가가 된 것은 BabaIsAI 서브스위트 3개뿐이고, 그중 둘 (BreakStop, GoTo) 은 init harness 대비 거의 포화 (0.98, 1.00) 라 상한 효과로 변별력이 낮다. 유일하게 어려운 Make 는 0.36 에 그친다. “태스크 패밀리 안에서 일반화한다”는 주장을 지지하기에는 표본이 얇다.</li> <li><strong>비용이 전혀 보고되지 않는다.</strong> iteration 당 최대 80 <code class="language-plaintext highlighter-rouge">react()</code> 스텝 × 5 iteration × 세 스코프를 돌리는 진화 비용, 그리고 진화된 harness 의 추론 시점 오버헤드 (BFS pathfinding, spatial-map builder 같은 컴포넌트가 붙은 harness 는 초기 harness 보다 스텝당 비용이 클 수 있다) 가 어디에도 없다. Live-SWE-Agent 가 태스크당 0.02–0.12 달러의 오버헤드를 명시한 것과 대비된다. harness 진화가 “테스트 타임 탐색을 더 한 것”이 아니라는 주장은 reasoning 을 끄는 것으로 절반만 방어된다 — 진화된 harness 자체가 더 많은 환경 스텝을 쓴다면 여전히 예산 비교가 필요하다.</li> <li><strong>task-injection seam 이 불변이라는 가정의 대가.</strong> 이 불변식이 hot-swap 과 버전 비교를 가능하게 하지만, 동시에 진화가 도달할 수 있는 harness 공간을 seam 이 허용하는 형태로 한정한다. 초기 seam 설계가 사실상 사람이 넣은 강한 귀납 편향인데, 이 seam 자체를 어떻게 설계했고 다른 seam 이었으면 결과가 어떻게 달라지는지에 대한 ablation 이 없다.</li> </ul> <h2 id="시사점--takeaways">시사점 / Takeaways</h2> <ul> <li><strong>frozen 모델 위의 harness 는 아직 많이 남아 있는 최적화 축이다.</strong> 파라미터를 하나도 안 건드리고 5개 환경 평균 18.9 → 41.4 를 얻었다. 실무적으로 읽으면, 지금 쓰고 있는 에이전트의 성능 격차 상당 부분이 모델이 아니라 그 주변 스캐폴드에 있을 수 있다는 뜻이다. 모델을 갈아끼우기 전에 harness 를 의심하는 게 순서상 맞다.</li> <li><strong>자기개선의 정직한 검증은 “무엇을 고정했는가”로 판가름난다.</strong> 이 논문에서 가장 배울 점은 결과가 아니라 프로토콜이다. 태스크 실행 중 reasoning off, 모든 상호작용은 frozen $M$ 경유, 모델을 외부 탐색으로 대체 금지, 평가는 편집 가능 표면 바깥. 이런 통제 없이 보고된 harness evolution 이득은 test-time scaling 과 구분되지 않는다.</li> <li><strong>진화가 발견한 것은 대개 “모델이 못 하던 것”이 아니라 “모델이 볼 수 없던 것”이다.</strong> Crafter 의 지배적 레버가 숨겨진 게임 피드백의 명시화였다는 사실은 harness 설계에 대한 실용적 지침이다. 새 능력을 주입하려 하기 전에, 모델이 이미 가진 능력을 쓰지 못하게 막고 있는 관측 병목부터 찾아라.</li> <li><strong>한 만능 harness 보다 태스크 패밀리별 harness 가 현실적이다.</strong> BabaIsAI 안에서는 재사용 가능한 전략이 발견되지만, 그 메커니즘이 확연히 다른 환경으로 자동 전이되지는 않는다. 자기개선 에이전트의 스케일링은 universal harness 하나를 키우는 방향보다 태스크 분포별 전문화 harness 를 유지하는 방향이 유망해 보인다.</li> <li><strong>개선의 상한을 미리 진단할 수 있으면 진화를 돌릴지 말지 결정할 수 있다.</strong> 보상이 희소하거나 (feedback bound) 모델이 태스크의 기본 요소를 못 다루면 (capability bound), harness 진화는 시간과 토큰만 태운다. NLE 에 5 iteration 을 돌려 0.2 를 얻은 결과는 실패가 아니라 이 진단 기준의 교정용 데이터로 읽어야 한다.</li> </ul> <h2 id="설치-및-사용법">설치 및 사용법</h2> <p>저자가 소스 코드를 <a href="https://github.com/TailinZhou/hsi">TailinZhou/hsi</a> 에 공개했다. 논문에 실행 예제가 실려 있지는 않으므로, 아래는 논문이 기술한 인터페이스 구조를 그대로 옮긴 개념적 요약이다.</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>harness/          ← 태스크 harness H (evolver 가 편집 가능)
  HarnessPolicy, context/memory/prompt, hooks, tools, helpers
evolution/        ← evolver 전략 Σ (meta-evolver 가 편집 가능)
  seed policy, evolution policy, commit policy, best-version selector policy
plan.md           ← iteration-local 메모 (후보 폐기 시 롤백)
BOOTSTRAP.md      ← iteration 을 넘어 지속되는 교훈 archive
&lt;meta-evolver 실행 로직&gt;  ← 불변 초기화 템플릿 (frozen anchor)
</code></pre></div></div> <p>평가 진입점은 <code class="language-plaintext highlighter-rouge">using_harness(agent, task)</code> 로 고정되어 있고, 진화된 harness 는 내부 구현이 어떻게 바뀌든 이 시그니처를 유지해야 iteration 간 hot-swap 과 버전 간 비교가 성립한다. 재현을 시도한다면 Table 3 의 스위트별 설정 (Dev / Val 비율, 에피소드 수, Meta on/off, submit-best 스텝 예산) 을 먼저 맞추는 게 순서다.</p> <h2 id="참고-자료">참고 자료</h2> <ul> <li>논문: <a href="https://arxiv.org/abs/2608.08466">arXiv:2608.08466</a></li> <li>Code: <a href="https://github.com/TailinZhou/hsi">github.com/TailinZhou/hsi</a></li> <li>벤치마크: <a href="https://github.com/balrog-ai/BALROG">BALROG</a></li> </ul> <h2 id="더-읽어보기">더 읽어보기</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2411.13543">BALROG: Benchmarking Agentic LLM and VLM Reasoning On Games</a></strong> (Paglieri et al., ICLR 2025) — 이 논문이 전적으로 의존하는 벤치마크. BabyAI 부터 NetHack 까지 난이도 스펙트럼을 한 프레임에 놓은 설계가 HSI 의 두 bound 논증을 가능하게 했다.</li> <li><strong><a href="https://arxiv.org/abs/2505.22954">Darwin Gödel Machine: Open-Ended Evolution of Self-Improving Agents</a></strong> (Zhang et al., ICLR 2026) — 자기참조 코드 수정에 archive 기반 population 탐색을 결합. greedy ablation 39.7% vs full 50.0% 은 HSI 가 포기한 단일 계보 설계의 기회비용을 정량화해준다.</li> <li><strong><a href="https://arxiv.org/abs/2410.04444">Gödel Agent: A Self-Referential Agent Framework for Recursive Self-Improvement</a></strong> (Yin et al., 2025) — LLM 기반 자기참조 개선의 첫 프레임워크. 편집 가능 경계를 의사결정 절차에 둔 전형으로, HSI 가 harness 로 경계를 넓힌 출발점이다.</li> <li><strong><a href="https://arxiv.org/abs/2607.12227">Rethinking the Evaluation of Harness Evolution for Agents</a></strong> (Wang et al., 2026) — harness evolution 이득의 상당 부분이 test-time scaling 과 구분되지 않는다는 비판. HSI 의 thinking-off 프로토콜과 통제 베이스라인 설계가 이 논문에 대한 응답이다.</li> <li><strong><a href="https://arxiv.org/abs/2510.04399">On The Statistical Limits of Self-Improving Agents</a></strong> (Wang et al., 2026) — 자기수정 하에서 distribution-free PAC 보장이 보존될 필요충분조건을 VC dimension 으로 규정. HSI 의 backbone capability bound 에 대응하는 이론적 뼈대다.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="llm-agents"/><category term="self-improvement"/><category term="agent-harness"/><category term="meta-evolution"/><category term="balrog"/><category term="frozen-backbone"/><summary type="html"><![CDATA[모델을 얼려둔 채 에이전트 하네스만 3계층으로 진화시켜 BALROG 에서 BabyAI +39.3, Crafter +33.0 을 얻고, 그 개선이 어디서 멈추는지까지 실증한 프레임워크]]></summary></entry><entry xml:lang="en"><title type="html">[Paper Review] Hierarchical Self-Improvement: A Framework for Task-Specific Evolvable Agent Harnesses</title><link href="https://baba9811.github.io/en/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/" rel="alternate" type="text/html" title="[Paper Review] Hierarchical Self-Improvement: A Framework for Task-Specific Evolvable Agent Harnesses"/><published>2026-08-14T05:00:00+00:00</published><updated>2026-08-14T05:00:00+00:00</updated><id>https://baba9811.github.io/en/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific</id><content type="html" xml:base="https://baba9811.github.io/en/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/" class="btn btn-sm btn-outline-secondary">🇰🇷 한국어로 읽기</a> </div> <h2 id="metadata">Metadata</h2> <table> <thead> <tr> <th>Field</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td>Authors</td> <td>Tailin Zhou (HKUST)</td> </tr> <tr> <td>Venue</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv or DOI</td> <td><a href="https://arxiv.org/abs/2608.08466">2608.08466</a></td> </tr> <tr> <td>Code</td> <td><a href="https://github.com/TailinZhou/hsi">TailinZhou/hsi</a></td> </tr> <tr> <td>Data</td> <td>BALROG — six long-horizon text game environments: BabyAI, BabaIsAI, Crafter, MiniHack, TextWorld, NLE</td> </tr> <tr> <td><span style="white-space: nowrap">Review date</span></td> <td>2026-08-14</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>Nothing touches the model weights. Only the <strong>executable scaffold around the agent — the harness — evolves</strong>. A single frozen LLM operates across three scopes: the task harness $H$ that runs tasks, an evolver that rewrites $H$, and a meta-evolver that rewrites the evolver’s strategy $\Sigma$. Only the outermost execution logic stays frozen, which is what keeps self-reference from running away.</li> <li>With DeepSeek-V4-Flash as the frozen backbone, HSI beats the initial harness on BALROG by +39.3 on BabyAI, +33.0 on Crafter, +25.0 on TextWorld, and +15.0 on MiniHack (raw % Progress). The five-environment average more than doubles, 18.9 → 41.4.</li> <li>Held out a 20% unseen split on BabaIsAI, the evolved harness still reaches 0.98 on BreakStop and 1.00 on GoTo. NLE, by contrast, sits at 0.2 even with meta-evolution on — no improvement at all.</li> <li>The real claim here isn’t the numbers, it’s the <strong>boundary</strong>. Harness evolution is bounded twice over: by a <em>feedback-fidelity bound</em> (evolution needs an informative reward signal to select on) and a <em>backbone capability bound</em> (redesigning the harness cannot buy capability the frozen model doesn’t have).</li> <li>Reasoning is disabled during task execution and enabled only during self-modification. That single design choice is what separates “the harness got better” from “we just spent more inference compute,” and it’s the most intellectually honest part of the paper.</li> </ul> <h2 id="introduction">Introduction</h2> <p>There are broadly two ways to make an LLM agent better. You can work on the model — more training, RLHF, swap in something bigger. Or you can work on everything around the model — tune the prompts, attach tools, restructure memory, add verification logic. That second bundle is what people now call the <strong>harness</strong>. Anyone who has actually shipped an agent knows how much leverage sits there. Two teams running the same backbone can land twenty points apart on a benchmark purely on harness design.</p> <p>The awkward part is that the harness is almost always <strong>hand-written by a human and then frozen as an artifact at deployment</strong>. The agent performs tasks, but it never gets to rewrite how it performs them. Recent self-improvement work has pushed on this, but mostly in one of two limited ways. Either the evolvable boundary sits at the agent’s <em>per-step decision code</em> (the Gödel Agent and Darwin Gödel Machine line), or the work targets a broader scaffold but relies on an <strong>external, stronger model</strong> as the proposer (Meta-Harness, AHE). The first has a narrow editable surface. The second leaves an attribution problem: did the agent improve, or did the stronger model that designed it?</p> <p>And there’s a sharper critique in the room. Wang et al. (2026b), in <em>Rethinking the Evaluation of Harness Evolution</em>, ran controlled experiments matching feedback and inference budgets and found that <strong>parallel sampling won in both conditions tested</strong> — 72.3% vs 67.4% for harness evolution without unit tests, and 86.0% vs 75.8% with them. On disjoint search and evaluation tasks, the generalization gain was only +0.6pp. The implication is uncomfortable: a lot of reported harness-evolution gains may be <strong>test-time search rather than genuine capability</strong>. This paper walks straight into that critique by design.</p> <p>So the question it poses is: <em>when the underlying model is frozen, can an agent endogenously evolve its own harness to improve performance, and what ultimately limits such improvement?</em> Plenty of papers have attempted the first half. The contribution here really lives in the second.</p> <h2 id="key-contributions">Key Contributions</h2> <ul> <li><strong>The HSI framework.</strong> A single frozen LLM evolves its own task harness through nested rewriting scopes, with a frozen outer anchor preventing unrestricted self-reference. All three scopes share the same model, the same prompt format, and the same <code class="language-plaintext highlighter-rouge">react()</code> primitive — they differ <strong>only in available tools and execution context</strong>.</li> <li><strong>Positive evidence under a controlled model ceiling.</strong> Consistent gains on moderate-difficulty BALROG environments with a frozen DeepSeek-V4-Flash, plus held-out generalization on BabaIsAI sub-suites. Crucially, the thinking-off task execution protocol removes inference-time reasoning as a confounding factor.</li> <li><strong>Empirical characterization of scaling limits.</strong> Two practical boundaries — feedback availability and backbone capability — identified and traced across environments of differing difficulty. The paper does not hide the NLE failure; it reports it as part of the result, which tells you a lot about its posture.</li> <li><strong>Task-specific evolution as a scaling axis.</strong> Rather than hunting for one universal harness, each task family maintains its own, hot-swapped across iterations through a fixed task-injection seam. That’s a design-level dodge around the overfitting problem Wang et al. (2026b) flagged.</li> </ul> <h2 id="background-and-related-work">Background and Related Work</h2> <h3 id="the-gödel-machine-lineage">The Gödel Machine lineage</h3> <p>Schmidhuber (2003) proposed a system that could modify its own program — including the procedure responsible for future modifications — provided such changes could be <em>proven</em> to improve performance. The proof requirement turned out to be essentially unsatisfiable, and recent LLM-based work has made the idea practical by swapping proof for empirical verification.</p> <p>Gödel Agent (Yin et al., 2025) realized self-referential improvement through runtime code modification. Darwin Gödel Machine (Zhang et al., 2026b) combined self-referential code modification with population-based open-ended exploration, taking SWE-bench from 20.0% to 50.0%. One result there is worth holding onto: DGM’s greedy ablation reached only 39.7%, confirming that archive-based exploration is doing real work. Huxley-Gödel Machine (Wang et al., 2025) identified the mismatch between benchmark performance and self-improvement potential and introduced clade-level meta-productivity. Group-Evolving Agents (Weng et al., 2026) shifted the evolutionary unit from individuals to groups, and HyperAgents (Zhang et al., 2026c) pushed further by making the meta-mechanism itself editable.</p> <p>What unites this lineage is that the editable boundary sits at <strong>the agent’s decision procedure or program execution code</strong>. Whether the broader agent harness could be evolved endogenously stayed open.</p> <h3 id="harness-engineering">Harness engineering</h3> <p>Harness engineering asks how the executable components around an LLM — prompts, tools, memory, verification — shape agent behavior. Meta-Harness (Lee et al., 2026b) formalized harness optimization as an outer-loop search problem, with a stronger coding agent as proposer holding full filesystem access to prior candidates. AutoHarness (Lou et al., 2026) synthesizes code harnesses via Thompson-sampling-guided tree search. Self-Harness (Zhang et al., 2026a) showed that a fixed model can improve its own harness without external help through weakness mining, harness proposal, and proposal validation (MiniMax M2.5, 40.5% → 61.9%).</p> <p>A parallel line handles adaptation during deployment. TTHE (Nie et al., 2026) evolves harnesses from execution traces at test time; Live-SWE-Agent (Xia et al., 2025) creates tools mid-problem; Continual Harness (Karten et al., 2026) extends to reset-free online settings.</p> <p>But nearly all of these evolve <strong>the task harness itself</strong>, not the <em>mechanism</em> governing how harnesses get discovered, selected, and rewritten. That gap is exactly where HSI lands.</p> <h3 id="evaluation-and-theoretical-limits">Evaluation and theoretical limits</h3> <p>Harness-Bench (Yao et al., 2026) established harness design as an independent evaluation axis, reporting a 23.8-point gap between best and worst harness under identical models. Harness Updating Is Not Harness Benefit (Lin et al., 2026b) decoupled an agent’s ability to <em>produce</em> harness updates from its ability to <em>benefit</em> from them, and found the latter is non-monotonic — mid-tier models benefit most (+19.3pp), while weak-tier models benefit least due to low skill-load rates (25.1% vs 95.7%). That’s a direct precedent for this paper’s NLE negative result.</p> <p>On the theory side, Wang et al. (2026a) established that distribution-free PAC guarantees are preserved under self-modification <strong>if and only if</strong> the policy-reachable hypothesis family has uniformly bounded VC dimension. When the task-required function complexity exceeds the model’s reachable VC dimension, no amount of harness engineering closes the gap. HSI’s <em>backbone capability bound</em> is the empirical shadow of that theorem.</p> <div class="row mt-3"><div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab4-comparative-summary-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab4-comparative-summary-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab4-comparative-summary-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab4-comparative-summary.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 4: Representative harness evolution and self-improvement methods compared with HSI. Proposer is who proposes harness edits; Surface is the editable code surface. Note how the Domain column is dominated by Coding while HSI alone sits on BALROG, and that HSI's proposer is the same frozen M — those two cells locate the paper.</figcaption> </figure> </div></div> <h2 id="method-and-architecture">Method and Architecture</h2> <h3 id="design-principles--why-hierarchy-is-forced">Design principles — why hierarchy is forced</h3> <p>The harness HSI assumes is <em>task-specific and continuously evolvable</em>: each task family keeps its own harness, hot-swappable across iterations through a fixed task-injection seam, refined using environment feedback.</p> <p>That’s where hierarchy stops being a stylistic choice. In a single-layer design, the harness’s task-facing behavior and the strategy responsible for rewriting it are coupled — the object of optimization and the optimizer become inseparable. Hierarchical separation pulls them apart: the task harness evolves while its rewriting procedure stays anchored, and the rewriting procedure itself evolves one layer above while the outer anchor stays fixed.</p> <p><strong>Principle 1 (single frozen model, three harness scopes).</strong> One frozen LLM $M$ operates across three scopes. In the task-harness scope, $M$ executes harness $H$ to interact with the environment. In the evolver scope, $M$ modifies $H$ through seed selection, harness evolution, and candidate selection. In the meta-evolver scope, $M$ modifies the evolver strategy itself, including decisions like seed generation, commit selection, archive maintenance, and final version export.</p> <p>All three share the same frozen model, prompt format, and <code class="language-plaintext highlighter-rouge">react()</code> primitive. <strong>They differ only in available tools and execution context.</strong> Scopes are separated by explicit memory boundaries — they maintain independent histories rather than representing independent agents. This matters: unlike external-proposer approaches, HSI uses the same frozen model for both executing and rewriting, so attribution of the improvement is unambiguous.</p> <p><strong>Principle 2 (self-determined explore–exploit).</strong> HSI prescribes no explicit explore–exploit schedule. When to inspect code, evaluate candidates, record lessons, or allocate effort between exploration and exploitation — all of it is treated as part of the evolvable strategy controlled by $M$. The framework provides only atomic interaction primitives, evolutionary feedback signals, and structural invariants.</p> <h3 id="the-three-scopes">The three scopes</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig1-hsi-framework-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig1-hsi-framework-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig1-hsi-framework-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig1-hsi-framework.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: The HSI framework. Green on the right is the task harness H (HarnessPolicy, context/memory/prompt, hooks/tools/helpers); blue in the middle is the evolver's three stages (seed selection → main evolution → commit selection); purple on the left is the meta-evolver rewriting four policies inside the evolver strategy Σ. The File System row at the bottom is what physically enforces the memory boundaries between scopes.</figcaption> </figure> <p>The <strong>task-harness scope</strong> executes the current harness $H$, which contains the prompts, tools, memory, state management, hooks, and the policy determining how the model interacts with the environment. It is the primary editable object and connects to tasks through a fixed injection seam.</p> <p>The <strong>evolver scope</strong> modifies the task harness across iterations, executing the evolution procedure defined by $\Sigma$ in three stages: seed selection, main evolution, commit selection. It receives environment feedback through harness evaluation and maintains persistent information through the evolution archive and bootstrap memory.</p> <p>The <strong>meta-evolver scope</strong> operates one level above and modifies $\Sigma$ itself. Critically, <strong>the execution logic that performs meta-evolution is not editable</strong>. It loads from an immutable initialization template and serves as the outer frozen anchor bounding self-modification.</p> <p>Equation 9 in the appendix compresses the whole hierarchy into a line:</p> \[M \;\longrightarrow\; H \;\longrightarrow\; \Sigma \;\longrightarrow\; \text{frozen anchor}\] <p>Lower layers remain adaptable; the outermost execution boundary stays fixed. That’s where the recursive modification process terminates.</p> <h3 id="the-five-stage-evolution-loop">The five-stage evolution loop</h3> <p>The first three stages operate on the task harness $H$, the fourth modifies the evolution strategy $\Sigma$, and the final stage selects the harness exported for evaluation. Each is implemented as a bounded <code class="language-plaintext highlighter-rouge">react()</code> loop whose central decisions are delegated to the frozen $M$.</p> <p>Let $H_t$ be the harness at the start of iteration $t$, and let $\mathcal{G}_t = (V_t, E_t)$ be the cumulative evolution graph. Each node $v \in V_t$ is a committed harness snapshot annotated with reward $r_v$; edges store semantic relations describing how one version relates to another.</p> \[\begin{aligned} (\hat{H}_t,\, h_t) &amp;= \mathrm{SeedSelect}(\mathcal{G}_t,\, M) &amp;&amp;\text{(1)} \\ \{V_t^{(k)}\}_{k=1}^{K_t} &amp;= \mathrm{MainEvolve}(\hat{H}_t,\, h_t;\, M) &amp;&amp;\text{(2)} \\ C_t &amp;= \mathrm{CommitSelect}(\{V_t^{(k)}\}_{k=1}^{K_t},\, \mathcal{G}_t;\, M) &amp;&amp;\text{(3)} \\ \Sigma_{t+1} &amp;= \mathrm{MetaEvolve}(\mathcal{G}_t \cup C_t,\, \Sigma_t;\, M) &amp;&amp;\text{(4)} \\ H^{*} &amp;= \mathrm{BestVersionSelect}(\mathcal{G}_T,\, M,\, \Sigma) &amp;&amp;\text{(5)} \end{aligned}\] <p>(The paper writes these as <code class="language-plaintext highlighter-rouge">seed_selection</code>, <code class="language-plaintext highlighter-rouge">main_evolution</code>, <code class="language-plaintext highlighter-rouge">commit_selection</code>, <code class="language-plaintext highlighter-rouge">meta_evolution</code>, and <code class="language-plaintext highlighter-rouge">best_version_selection</code>.)</p> <p><strong>Seed selection (Eq. 1)</strong> picks an ancestor from $\mathcal{G}_t$ and generates a structured hypothesis $h_t$ for the next iteration. $M$ makes the decision using previous rewards, evolution history, and accumulated lessons. The hypothesis carries four elements: the selected anchor version, the motivation for choosing it, the expected improvement direction, and a <strong>falsification criterion</strong>. That last one is the interesting design move. Injecting the hypothesis into the subsequent evolution process turns evolution from unconstrained mutation into a goal-directed search guided by explicit predictions.</p> <p><strong>Main evolution (Eq. 2)</strong> is where $M$ directly modifies the harness. The editable surface spans all task-facing components — prompts, tools, memory, state management, hooks, execution policies. The one invariant preserved across every rewrite is the <strong>task-injection interface</strong>: internal components may change freely, but the external interface connecting tasks to the harness stays fixed. That invariant is what makes evolved versions directly comparable and the harness hot-swappable.</p> <p><strong>Commit selection (Eq. 3)</strong> deliberately does not keep only the highest-reward candidate. It maintains a <strong>diverse commit pool</strong> containing multiple evolutionary directions. Each selected version enters the evolution graph together with the semantic rationale generated by $M$, so future seed selection can reason over successful, failed, and unexplored branches.</p> <p><strong>Meta-evolution (Eq. 4)</strong> modifies the strategy $\Sigma$ governing harness evolution. The editable surface of $\Sigma$ covers seed selection, main evolution, commit selection, and final version selection. By modifying $\Sigma$, the meta-evolver changes not just candidate harnesses but <strong>the search strategy used to discover future harnesses</strong>.</p> <p><strong>Best-version selection (Eq. 5)</strong> picks the deployed harness after $T$ iterations. Unlike intermediate commit selection, which maintains diversity, this stage <strong>prioritizes generalization</strong>. Candidates are evaluated on validation performance and the selected harness is exported for held-out evaluation. The selection procedure is itself part of $\Sigma$, so meta-evolution can adapt how final deployment decisions get made.</p> <h3 id="execution-interface-and-memory">Execution interface and memory</h3> <p>All HSI components instantiate with the same frozen $M$ and a shared <code class="language-plaintext highlighter-rouge">react()</code> primitive. At each step the model receives the current message history, available tools, and task-specific context, and produces an action:</p> \[a_t = M(o_t,\, \mathcal{T},\, \mathcal{C}_t)\] <p>where $o_t$ is the current observation, $\mathcal{T}$ the available tool set, and $\mathcal{C}_t$ the scope-specific context. The action may modify files, request evaluation, record information, or terminate the current stage.</p> <p>Beyond file manipulation (<code class="language-plaintext highlighter-rouge">read</code>, <code class="language-plaintext highlighter-rouge">write</code>, <code class="language-plaintext highlighter-rouge">edit</code>, <code class="language-plaintext highlighter-rouge">bash</code>), the evolver scope gets evolution-specific primitives:</p> <table> <thead> <tr> <th>Tool</th> <th>Role</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">plan</code></td> <td>maintain an iteration-local reasoning notebook</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">compact_context</code></td> <td>summarize prior interactions when the context budget tightens</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">evaluate</code></td> <td>execute the current harness and return environment feedback</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">lesson</code></td> <td>record reusable insights for future iterations</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">end_evolution</code></td> <td>terminate the current evolution process</td> </tr> </tbody> </table> <p>The framework specifies no ordering among these. The model decides when and how to use each based on observed feedback and the current evolution objective.</p> <p>Memory splits into three channels with different persistence. <strong>Iteration-local memory</strong> lives in <code class="language-plaintext highlighter-rouge">plan.md</code>; if a candidate version is discarded, this memory rolls back with the code state. <strong>Persistent evolutionary memory</strong> is the lesson archive in <code class="language-plaintext highlighter-rouge">BOOTSTRAP.md</code>, summarizing discovered patterns, failed directions, and reusable evolution guidance. <strong>Evolution graph memory</strong> is $\mathcal{G}_t$, whose nodes hold the harness snapshot, achieved reward, and step metadata, and whose edges encode semantic relationships like extending an existing approach, repairing a failure mode, or exploring a different direction.</p> <p>Exposing all historical trajectories to the LLM would blow the context budget and inject noise, so HSI uses a probe mechanism that retrieves compressed summaries:</p> \[z = \mathrm{probe}(\mathcal{T}_{\text{history}},\, q)\] <p>The meta-evolver might query which seed-selection behaviors correlate with successful iterations, which evolution patterns frequently lead to regression, or which hypothesis structures precede large improvements. It’s how the meta-evolver exploits long-horizon history while keeping its reasoning context bounded.</p> <h3 id="scope-isolation-and-the-evaluation-interface">Scope isolation and the evaluation interface</h3> <p>HSI enforces explicit boundaries. The task harness $H$ is editable by the evolver but cannot modify the evolution strategy $\Sigma$. Conversely, the meta-evolver can modify $\Sigma$ but cannot directly alter the task harness during meta-evolution. Any modification outside the authorized directory is rejected.</p> <p>Evaluation happens <strong>outside</strong> the editable surfaces. The harness receives tasks through a fixed interface:</p> \[\mathrm{using\text{-}harness}(\mathit{agent},\, \mathit{task})\] <p>Although the internal implementation of $H$ changes across iterations, this interface stays invariant. Every evolved version therefore operates under the same task injection mechanism and can be compared using identical development, validation, and test protocols. The evaluator returns both a scalar reward and optional textual feedback.</p> <h2 id="training-objective">Training Objective</h2> <p>There’s no gradient-minimized loss here — the model parameters are frozen. What plays the role of the optimization signal is a <strong>stochastic lower-confidence-bound reward</strong> used to rank candidate harnesses:</p> \[r = \mu - z \cdot \frac{\sigma}{\sqrt{n}}, \qquad z = 0.5\] <p>where $\mu$ and $\sigma$ are the mean and standard deviation over evaluation trials and $n$ the trial count. BALROG’s episode-level % Progress (0–100) is rescaled to $[0,1]$.</p> <p>It’s worth thinking about why this shape is necessary. During evolution, each candidate harness is evaluated with <strong>one episode per call</strong> for efficiency. In that low-sample regime, selecting on the mean alone would routinely promote trajectories that got lucky. The LCB penalizes proportionally to variance, shaving off that optimistic bias. At $z = 0.5$ the penalty is fairly mild, which reads as a deliberate compromise to avoid over-suppressing exploration.</p> <p>Note, though, that <strong>all reported results use raw % Progress means, not LCB rewards</strong>. The LCB is confined to candidate selection during evolution; final evaluation uses the full episode budget for a more stable estimate. Keeping the selection criterion and the reporting criterion separate is the right call — mixing them lets selection bias leak into the headline numbers.</p> <h2 id="data-and-pipeline">Data and Pipeline</h2> <h3 id="benchmark">Benchmark</h3> <p>BALROG (Paglieri et al., 2025) is a benchmark of long-horizon text-based interactive environments designed to evaluate planning, memory, exploration, and tool use. Its six environments span a deliberate difficulty gradient.</p> <table> <thead> <tr> <th>Environment</th> <th>Capability demand</th> </tr> </thead> <tbody> <tr> <td>BabyAI</td> <td>instruction following and navigation in structured environments</td> </tr> <tr> <td>BabaIsAI</td> <td>rule-manipulation puzzles (sub-suites: BreakStop / GoTo / Make / Advanced)</td> </tr> <tr> <td>Crafter</td> <td>long-horizon planning, resource management, sequential decision making</td> </tr> <tr> <td>TextWorld</td> <td>multi-step reasoning and object manipulation</td> </tr> <tr> <td>MiniHack</td> <td>roguelike with complex state spaces and sparse feedback</td> </tr> <tr> <td>NLE</td> <td>the same, considerably harder (NetHack Learning Environment)</td> </tr> </tbody> </table> <p>That gradient is the paper’s key instrument. Tasks where the frozen backbone achieves non-trivial performance sit in the same frame as tasks where performance stays floored, which means you can watch <strong>where harness evolution works and where it stops</strong> inside a single experiment.</p> <h3 id="backbone-and-evolution-configuration">Backbone and evolution configuration</h3> <p>Every experiment uses DeepSeek-V4-Flash, accessed through the <code class="language-plaintext highlighter-rouge">deepseek-v4-flash-preview</code> API, as the frozen backbone across all three scopes. Each evolution run consists of $T = 5$ outer iterations with a maximum of 80 <code class="language-plaintext highlighter-rouge">react()</code> steps per iteration.</p> <p>The single most important setting is the <strong>thinking on/off split</strong>:</p> <table> <thead> <tr> <th>Scope</th> <th>Reasoning</th> <th>Temperature</th> <th>Step budget</th> </tr> </thead> <tbody> <tr> <td>task-harness</td> <td>disabled (thinking off)</td> <td>0</td> <td>—</td> </tr> <tr> <td>evolver</td> <td>enabled, reasoning effort at maximum</td> <td>—</td> <td>up to 80 <code class="language-plaintext highlighter-rouge">react()</code> per iteration</td> </tr> <tr> <td>meta-evolver</td> <td>enabled</td> <td>—</td> <td>up to 50 <code class="language-plaintext highlighter-rouge">react()</code> per iteration</td> </tr> </tbody> </table> <p>Disabling extended reasoning during task execution fixes the model’s per-step capability ceiling. The configuration is held constant across development evaluation, validation evaluation, best-version selection, and final testing. Therefore <strong>improvements observed during task execution cannot be attributed to additional reasoning computation at inference time</strong>. That’s a direct answer to the test-time-scaling confound Wang et al. (2026b) raised.</p> <p>The evolution space is constrained too. All task interactions must be mediated through the frozen backbone $M$. Evolution may modify prompts, tools, memory, state management, and control logic, but <strong>cannot replace the model with external search procedures or non-LLM policies</strong>. Without that constraint, “harness evolution” degenerates into “throw out the LLM and write a BFS.”</p> <p>The meta-evolver scope runs with a greedy archive, with seed selection and commit pooling both evolvable, the seed hypothesis injected into each iteration’s first system prompt, and a short seed-validation probe (up to three <code class="language-plaintext highlighter-rouge">evaluate()</code> calls) enabled during seed selection. The <strong>terminal best-version selection stage is a fixed, non-evolvable agentic stage</strong> that runs once at the end of every evolution. The init harness is not pre-evaluated; iteration 1 starts cold.</p> <h3 id="evaluation-protocols">Evaluation protocols</h3> <p>BALROG environments are procedurally generated and each <code class="language-plaintext highlighter-rouge">evaluate()</code> call samples a new initial seed. Two protocols are used.</p> <p><strong>In-distribution evolution (Setup A).</strong> The same task set is used during evolution and final evaluation, while each evaluation episode comes from a newly sampled environment seed. This measures whether harness evolution improves performance under stochastic variations of previously encountered tasks. Applied to TextWorld, BabyAI, Crafter, MiniHack, and NLE.</p> <p><strong>Held-out task generalization (Setup B).</strong> For BabaIsAI, task-family splits are constructed on sub-suite categories (BreakStop, GoTo, Make, Advanced). Each sub-suite divides into development, validation, and test portions, and <strong>the test split remains inaccessible throughout evolution</strong>. Advanced is excluded — with only three tasks it can’t support a meaningful split.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab3-per-suite-config-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab3-per-suite-config-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab3-per-suite-config-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab3-per-suite-config.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 3: Per-suite experimental configuration. Dev and Val are the fractions of the suite assigned to dev (evolution reward signal) and val (best-version selection); Test ep. is the per-task episode count at final test; Dev ep. is the per-task episode count during evolution (cheaper, with noise absorbed by the LCB reward); Test rep. is how many times the full test set is re-evaluated after evolution; Submit-best is the step budget of the terminal best-version selection stage.</figcaption> </figure> <h3 id="baselines">Baselines</h3> <p>Three reference comparisons. First, <strong>Init Harness</strong> — the original hand-crafted harness evaluated without evolution under the same backbone and protocol. This is the primary controlled baseline for measuring the effect of harness evolution. Second, publicly reported BALROG leaderboard results, providing context against frontier models under their native configurations. Third, external-proposer harness optimization methods are <strong>deliberately excluded</strong> from the controlled comparison, since methods relying on stronger external models operate under a different assumption from endogenous evolution under a fixed backbone.</p> <h2 id="experimental-results">Experimental Results</h2> <h3 id="in-distribution-performance-setup-a">In-distribution performance (Setup A)</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab1-balrog-comparison-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab1-balrog-comparison-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab1-balrog-comparison-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab1-balrog-comparison.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 1: BALROG leaderboard comparison under Setup A. The top block lists public-leaderboard numbers retrieved 2026-08-03 from frontier models under their native configurations; the bottom three rows are the controlled comparison under a single frozen DeepSeek-V4-Flash backbone. BabaIsAI is omitted because its sub-suite protocol differs from the leaderboard's mixed-task protocol.</figcaption> </figure> <p>The comparison that matters is the bottom three rows. All three use DeepSeek-V4-Flash and <strong>differ only in whether and how the harness is evolved</strong>.</p> <p>Starting from the same backbone and task-time inference configuration, the meta-evolution-on arm substantially improves over the init harness across all non-trivial suites.</p> <blockquote> <p>BabyAI 81.3 (init harness 42.0, +39.3) · Crafter 44.6 (11.6, +33.0) · TextWorld 65.0 (40.0, +25.0) · MiniHack 15.8 (0.8, +15.0)</p> </blockquote> <p>The five-environment average moves 18.9 → 41.4, with the backbone and task-time reasoning budget unchanged.</p> <p>The frontier comparison is interesting too. On TextWorld, HSI’s 65.0 % Progress exceeds Grok-4 (62.9), Claude-Opus-4.5-Thinking (59.0), and Gemini-3-Flash (50.2). On Crafter, 44.6 outperforms DeepSeek-R1 (36.4), GPT-5-minimal-think (39.1), and GPT-4o (33.1). These cross different backbones and configurations, so read them as contextual reference only — the controlled init-harness comparison is what isolates the effect of harness evolution.</p> <h3 id="held-out-generalization-setup-b">Held-out generalization (Setup B)</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab2-babaisai-heldout-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab2-babaisai-heldout-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab2-babaisai-heldout-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/tab2-babaisai-heldout.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 2: BabaIsAI sub-suite results under Setup B (split evolution with 20% held-out test). Best Dev is the highest development reward selected during evolution; test results are reported with across-task standard deviation. Init Harness is averaged over three baseline runs.</figcaption> </figure> <p>Each sub-suite evolves an independent harness while keeping the backbone, evolution budget, initialization template, and evaluation protocol fixed. The only varying factor is the task family.</p> <p>Two distinct regimes emerge. On <strong>navigation-oriented tasks</strong> (BreakStop, GoTo), held-out performance is near-perfect: meta-on reaches 0.9800 and 1.0000 respectively, from init harnesses at 0.0333 and 0.1818. The meta-off variant achieves comparable results (1.0000 and 0.9636), which also tells us meta-evolution isn’t decisive at this difficulty. The evolved harness has discovered <strong>reusable interaction patterns</strong> that transfer beyond the observed development tasks.</p> <p><strong>Make is a different story.</strong> Harness evolution improves over the zero-shot init harness (0.0000), but held-out performance stalls at 0.3625 for meta-on and 0.3375 for meta-off. Against a Best Dev of 0.5556, the dev→test gap is substantial. The standard deviation of 0.3284 is telling too: it works on some tasks and not at all on others. Multi-step crafting requires capabilities beyond the reusable harness transformations discovered during evolution.</p> <h3 id="the-effect-of-meta-evolution">The effect of meta-evolution</h3> <p>The meta-off ablation in Table 1 isolates the contribution of evolving the evolution strategy itself. Removing the meta-evolver reduces performance on every evaluated suite.</p> <table> <thead> <tr> <th>Suite</th> <th>meta-on</th> <th>meta-off</th> <th>Δ</th> </tr> </thead> <tbody> <tr> <td>BabyAI</td> <td>81.3</td> <td>77.3</td> <td>−4.0</td> </tr> <tr> <td>Crafter</td> <td>44.6</td> <td>36.4</td> <td>−8.2</td> </tr> <tr> <td>TextWorld</td> <td>65.0</td> <td>46.0</td> <td>−19.0</td> </tr> <tr> <td>MiniHack</td> <td>15.8</td> <td>5.8</td> <td>−10.0</td> </tr> <tr> <td>Average</td> <td>41.4</td> <td>33.1</td> <td>−8.3</td> </tr> </tbody> </table> <p>The largest improvements land on TextWorld (+19.0) and MiniHack (+10.0), suggesting that <strong>adapting the evolution procedure becomes increasingly beneficial as the harness search space grows more complex</strong>. Read the other way, in a relatively simple environment like BabyAI the marginal contribution of meta-evolution is small (+4.0).</p> <p>NLE admits no meaningful meta-off comparison because both configurations achieve near-zero reward. The meta-on result of 0.2 indicates that <strong>evolution receives insufficient task feedback to discover useful harness modifications</strong>.</p> <h3 id="evolution-trajectories">Evolution trajectories</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig2-crafter-trajectory-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig2-crafter-trajectory-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig2-crafter-trajectory-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig2-crafter-trajectory.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: HSI evolution trajectory on Crafter (Setup A, meta-on). Dev reward climbs from the init-harness baseline of 0.166 to an iteration-best 0.578 at iteration 4 (green star = exported best version), with a regression in iteration 5. Each iteration card reports seed origin, main-evolution edit, result, and commit pool, plus a meta field summarizing what the meta-evolver rewrote in Σ.</figcaption> </figure> <p>The Crafter trajectory shows the typical in-distribution pattern. Early iterations mainly <strong>introduce missing task representations</strong> — exposing latent reward signals, structuring inventory information, improving action-state alignment. Iteration 1 delivers the single biggest jump, 0.166 → 0.430 (2.6×). Iteration 2 adds structured inventory and crafting hints for 0.511 (+19%). Iteration 3 plateaus at 0.488, with the card noting it “hits LLM spatial limit.” Iteration 4 reaches the 0.578 peak via ensemble fusion of two ancestors plus safety constraints. Iteration 5 regresses, 0.497 → 0.341.</p> <p>That regression is the useful part. It’s evidence that <strong>evolution does not monotonically improve every branch but searches a non-convex harness design space</strong>. The best version came from iteration 4, not the last one — which is precisely why the terminal best-version selection stage has to exist.</p> <p>The meta-evolver’s contribution is transforming successful local discoveries into <strong>reusable evolution heuristics</strong>. Across iterations it updates $\Sigma$ with higher-level principles like prioritizing structured state representations over raw observations and avoiding overly aggressive exploration near a performance plateau. These changes affect future search behavior rather than directly modifying task performance.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig3-babaisai-make-trajectory-480.webp 480w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig3-babaisai-make-trajectory-800.webp 800w,/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig3-babaisai-make-trajectory-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0032-hierarchical-self-improvement-a-framework-for-task-specific/fig3-babaisai-make-trajectory.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: HSI evolution trajectory on BabaIsAI-Make (Setup B, meta-on). The blue curve is dev reward, red rings mark commit-pool versions, and orange triangles flag commits finalized in val mode with no dev evaluation recorded on the commit itself. Each triangle sits at the commit's anchor x with the val reward on the y-axis, and a dashed vertical line drops from the dev anchor to the val reward.</figcaption> </figure> <p>The BabaIsAI-Make trajectory demonstrates held-out evolution. Unlike Crafter, Setup B explicitly exposes validation behavior. Dev peak moves 0.222 → 0.333 → 0.222 (plateau) → 0.444 → 0.556 across the five iterations, as the agent introduces a single-<code class="language-plaintext highlighter-rouge">react()</code> rewrite with plan tracking (iter 1), a spatial-map builder with WIN-target persistence (iter 2), auto-target computation with BFS pathfinding (iter 3), an auto-push mechanism with directional fallback (iter 4), and LLM-aware cross-room navigation (iter 5).</p> <p>The meta-evolver codifies a <strong>“LLM targets, BFS navigates”</strong> two-layer pattern and progressively expands the commit pool from one to three versions. That pattern is genuinely striking: the agent worked out on its own that semantic judgment (which target to pursue) belongs to the LLM while deterministic computation (how to get there) belongs to BFS — and then wrote that division of labor into its own strategy.</p> <p>The held-out validation markers show that several discovered mechanisms transfer beyond the development tasks, but the remaining gap (dev peak 0.556 vs test 0.3625) indicates multi-step crafting still sits close to the frozen backbone’s capability boundary.</p> <h2 id="analysis-and-ablation">Analysis and Ablation</h2> <h3 id="what-actually-worked">What actually worked</h3> <p>Overlay the two trajectories and a consistent three-phase pattern appears: <strong>early iterations discover missing abstractions</strong>, <strong>middle iterations introduce structured algorithmic components</strong>, and <strong>later iterations refine or prune competing designs</strong>. That’s qualitative evidence that self-improvement happens through progressive harness restructuring rather than simple prompt optimization.</p> <p>More concretely, the dominant lever the evolver found on Crafter was <strong>making hidden game feedback explicit</strong> — reward signal, inventory state, and crafting feasibility, exposed successively in the harness context. Which is, notably, the first thing a human does when tuning an agent. The evolution did not make the model capable of something new; it <strong>unblocked capability the model already had but couldn’t reach for lack of information</strong>. That observation is the key to understanding both bounds below.</p> <p>One more pattern: across evolution runs, <strong>the largest improvement typically occurs during the first iteration</strong>, followed by smaller incremental gains. Early harness redesign captures the dominant improvements while later iterations refine existing solutions through exploration and selection. Practically, that means diminishing returns on increasing $T$ set in fast.</p> <h3 id="two-boundaries">Two boundaries</h3> <p>Across BALROG the same qualitative pattern holds. Harness evolution provides the largest improvements where the frozen backbone already exhibits meaningful competence, smaller and noisier gains near the capability boundary, and limited improvement where useful feedback is hard to obtain.</p> <p><strong>Feedback-fidelity bound.</strong> Evolution requires an informative reward signal to guide selection. Harness modifications are difficult to evaluate from static inspection alone; the only useful signal is whether the modified harness produces improved behavior when executed. NLE is the case study — rewards are so sparse that evolution has no way to know what to improve. The meta-on figure of 0.2 is closer to noise than to improvement.</p> <p><strong>Backbone capability bound.</strong> Harness redesign cannot overcome limitations of the frozen model. The Crafter iteration-3 card saying “hits LLM spatial limit” states it outright. The BabaIsAI-Make dev–test gap is the same phenomenon. Harness evolution can reorganize and amplify behavior around a model, but it cannot overcome tasks where the model cannot generate useful interaction signals.</p> <p>Both bounds are the empirical counterpart of Wang et al. (2026a): when task-required function complexity exceeds the model’s reachable VC dimension, no amount of self-modification closes the gap. They’re also a direct replication of Lin et al. (2026b)’s finding that harness-benefit is non-monotonic and weakest for weak-tier models.</p> <h3 id="the-single-seed-choice">The single-seed choice</h3> <p>HSI intentionally avoids population-based parallel scaling and follows a single evolving lineage, so that performance changes can be attributed to harness redesign rather than to increased candidate throughput. It trades search efficiency for attribution clarity.</p> <p>Methodologically that’s the right call, but it costs something. DGM’s ablation showed archive-based population exploration buys real gains over greedy (50.0% vs 39.7%). HSI forgoes those, and the paper acknowledges as much, leaving population-based exploration as a complementary scaling dimension.</p> <h2 id="limitations-and-critical-assessment">Limitations and Critical Assessment</h2> <p><strong>Acknowledged by the author.</strong></p> <ul> <li>Computational constraints limit evaluation to a selected set of benchmarks, backbones, and comparisons. The paper explicitly frames itself as an initial exploration rather than a full-scale empirical study.</li> <li>Evolution requires informative feedback; environments with extremely sparse rewards provide insufficient signal.</li> <li>Final performance remains constrained by the capability of the frozen model.</li> <li>Single-seed evolution sacrifices search efficiency.</li> </ul> <p><strong>Additional limitations from a reviewer’s standpoint.</strong></p> <ul> <li><strong>There is exactly one backbone.</strong> Every result comes from DeepSeek-V4-Flash. Given that Lin et al. (2026b) reported non-monotonic harness-benefit and Zhang et al. (2026a) showed that different models produce completely different harness modifications from the same initial harness and algorithm, it’s unclear how general the two bounds derived from a single backbone really are. If the “mid-tier models benefit most” finding holds, DeepSeek-V4-Flash may have been sitting exactly where the gains are most visible.</li> <li><strong>No statistical significance testing.</strong> All reported variation comes from the <em>evaluation</em> side — variance across evaluation episodes, plus Table 3’s Test rep. (the full test set re-evaluated up to three times after evolution). What’s missing is <em>reproducibility of the evolution run itself</em>: would re-running evolution under the same configuration produce a comparable harness? In Table 2 only Init Harness is averaged over three baseline runs; the HSI arms read as a single evolution run each. Since the paper itself says harness evolution is inherently stochastic, run-to-run variance is essential to interpreting the results. GSME (Luo et al., 2026b) makes exactly this point: a non-statistical “mean improves” rule credits roughly 60% of truly neutral mechanisms as wins.</li> <li><strong>Table 3’s Meta column contradicts the main results.</strong> The appendix table records Meta as <code class="language-plaintext highlighter-rouge">off</code> for TextWorld and BabaIsAI-BreakStop, while the prose defines that column as “whether the meta-evolver scope is enabled.” Yet Table 1 reports TextWorld meta-on at 65.0 and Table 2 reports BreakStop meta-on at 0.9800. What configuration the meta-on arm actually ran under for those two suites is ambiguous — and TextWorld is the suite where meta-evolution contributes most (+19.0), so the ambiguity isn’t trivial.</li> <li><strong>The Dev / Val ratio definitions don’t add up.</strong> The prose defines Dev and Val as fractions of the suite assigned to each, yet BabaIsAI-GoTo and Make list Dev 0.8 and Val 0.25, summing to 1.05 — and with the 20% test split, 1.25. Val is presumably a subset of, or overlapping with, dev, but this is never stated, which makes the Setup B split hard to reproduce as specified.</li> <li><strong>The held-out evidence base is thin.</strong> Only three BabaIsAI sub-suites were actually evaluated held-out, and two of them (BreakStop, GoTo) are essentially saturated (0.98, 1.00), so ceiling effects blunt their discriminative power. The one genuinely hard sub-suite, Make, reaches 0.36. That’s a thin sample on which to rest a claim about generalization within a task family.</li> <li><strong>Costs are not reported at all.</strong> Neither the evolution cost (up to 80 <code class="language-plaintext highlighter-rouge">react()</code> steps per iteration × 5 iterations × three scopes) nor the inference-time overhead of the evolved harness appears anywhere — and a harness carrying BFS pathfinding and a spatial-map builder plausibly costs more per step than the init harness. Compare Live-SWE-Agent, which reports an overhead of 0.02–0.12 USD per task. The claim that these gains aren’t test-time search is only half-defended by turning reasoning off; if the evolved harness itself consumes more environment steps, a budget comparison is still owed.</li> <li><strong>The price of the invariant task-injection seam.</strong> The invariant enables hot-swapping and version comparison, but it also confines the reachable harness space to whatever shape the seam permits. The initial seam design is a strong human-supplied inductive bias, and there’s no ablation on how it was designed or how results would shift under a different seam.</li> </ul> <h2 id="takeaways">Takeaways</h2> <ul> <li><strong>The harness above a frozen model is still a substantially under-optimized axis.</strong> A five-environment average of 18.9 → 41.4 without touching a single parameter. Read practically: a good share of your agent’s performance gap may live in the scaffold rather than the model. Suspect the harness before you swap the backbone.</li> <li><strong>Honest verification of self-improvement is decided by what you froze.</strong> The most transferable thing here isn’t the result, it’s the protocol — reasoning off during task execution, all interaction routed through the frozen $M$, no replacing the model with external search, evaluation held outside the editable surface. Harness-evolution gains reported without those controls are indistinguishable from test-time scaling.</li> <li><strong>What evolution discovers is usually not “what the model couldn’t do” but “what the model couldn’t see.”</strong> The dominant Crafter lever being the exposure of hidden game feedback is a practical design lesson: before trying to inject new capability, find the observability bottleneck stopping the model from using capability it already has.</li> <li><strong>Per-task-family harnesses look more realistic than one universal harness.</strong> Reusable strategies emerge within BabaIsAI, but those mechanisms don’t automatically transfer to substantially different environments. Scaling self-improving agents likely means maintaining specialized evolvable harnesses per task distribution rather than growing a single universal one.</li> <li><strong>Being able to diagnose the ceiling in advance tells you whether to run evolution at all.</strong> When rewards are sparse (feedback bound) or the model can’t handle the task’s basic elements (capability bound), harness evolution burns time and tokens. Five iterations on NLE yielding 0.2 isn’t a failure — it’s calibration data for that diagnostic.</li> </ul> <h2 id="installation-and-usage">Installation and Usage</h2> <p>The author released source code at <a href="https://github.com/TailinZhou/hsi">TailinZhou/hsi</a>. The paper contains no runnable example, so the following is a conceptual summary of the interface structure it describes.</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>harness/          ← task harness H (editable by the evolver)
  HarnessPolicy, context/memory/prompt, hooks, tools, helpers
evolution/        ← evolver strategy Σ (editable by the meta-evolver)
  seed policy, evolution policy, commit policy, best-version selector policy
plan.md           ← iteration-local notebook (rolled back if the candidate is discarded)
BOOTSTRAP.md      ← lesson archive persisting across iterations
&lt;meta-evolver execution logic&gt;  ← immutable initialization template (frozen anchor)
</code></pre></div></div> <p>The evaluation entry point is fixed at <code class="language-plaintext highlighter-rouge">using_harness(agent, task)</code>, and an evolved harness must preserve that signature no matter how its internals change — otherwise hot-swapping and cross-version comparison break. If you attempt a reproduction, start by matching the per-suite settings in Table 3 (Dev / Val ratios, episode counts, Meta on/off, submit-best step budget).</p> <h2 id="references">References</h2> <ul> <li>Paper: <a href="https://arxiv.org/abs/2608.08466">arXiv:2608.08466</a></li> <li>Code: <a href="https://github.com/TailinZhou/hsi">github.com/TailinZhou/hsi</a></li> <li>Benchmark: <a href="https://github.com/balrog-ai/BALROG">BALROG</a></li> </ul> <h2 id="further-reading">Further Reading</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2411.13543">BALROG: Benchmarking Agentic LLM and VLM Reasoning On Games</a></strong> (Paglieri et al., ICLR 2025) — the benchmark this paper rests entirely on. Placing everything from BabyAI to NetHack on one difficulty gradient is what makes the two-bounds argument possible.</li> <li><strong><a href="https://arxiv.org/abs/2505.22954">Darwin Gödel Machine: Open-Ended Evolution of Self-Improving Agents</a></strong> (Zhang et al., ICLR 2026) — self-referential code modification combined with archive-based population exploration. Its greedy ablation (39.7% vs 50.0% full) quantifies the opportunity cost of HSI’s single-lineage design.</li> <li><strong><a href="https://arxiv.org/abs/2410.04444">Gödel Agent: A Self-Referential Agent Framework for Recursive Self-Improvement</a></strong> (Yin et al., 2025) — the first LLM-based self-referential improvement framework, and the canonical case of placing the editable boundary at the decision procedure. HSI’s starting point for widening that boundary to the harness.</li> <li><strong><a href="https://arxiv.org/abs/2607.12227">Rethinking the Evaluation of Harness Evolution for Agents</a></strong> (Wang et al., 2026) — the critique that much of the reported harness-evolution gain is indistinguishable from test-time scaling. HSI’s thinking-off protocol and controlled baseline design are the answer to it.</li> <li><strong><a href="https://arxiv.org/abs/2510.04399">On The Statistical Limits of Self-Improving Agents</a></strong> (Wang et al., 2026) — establishes the necessary and sufficient condition, in terms of VC dimension, for distribution-free PAC guarantees to survive self-modification. The theoretical skeleton behind HSI’s backbone capability bound.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="llm-agents"/><category term="self-improvement"/><category term="agent-harness"/><category term="meta-evolution"/><category term="balrog"/><category term="frozen-backbone"/><summary type="html"><![CDATA[Freeze the model, evolve only the harness across three nested scopes — +39.3 on BabyAI and +33.0 on Crafter, plus an honest account of exactly where the gains stop]]></summary></entry><entry xml:lang="ko"><title type="html">[논문 리뷰] NVIDIA-labs OO Agents: Native Python Object-Oriented Agents</title><link href="https://baba9811.github.io/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/" rel="alternate" type="text/html" title="[논문 리뷰] NVIDIA-labs OO Agents: Native Python Object-Oriented Agents"/><published>2026-08-12T05:00:00+00:00</published><updated>2026-08-12T05:00:00+00:00</updated><id>https://baba9811.github.io/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents</id><content type="html" xml:base="https://baba9811.github.io/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/en/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/" class="btn btn-sm btn-outline-secondary">🇺🇸 Read in English</a> </div> <h2 id="메타정보">메타정보</h2> <table> <thead> <tr> <th>항목</th> <th>내용</th> </tr> </thead> <tbody> <tr> <td>저자</td> <td>Paul Furgale et al. (15명 공동 저자, NVIDIA)</td> </tr> <tr> <td>학회</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv 또는 DOI</td> <td><a href="https://arxiv.org/abs/2607.20709">2607.20709</a></td> </tr> <tr> <td>Code</td> <td><a href="https://github.com/nvidia-nemo/labs-OO-Agents">nvidia-nemo/labs-OO-Agents</a></td> </tr> <tr> <td>데이터</td> <td>SWE-bench Verified (500 tasks) · Terminal-Bench 2.0 (89 tasks) · CyberGym L1 · ARC-AGI-3 (25 public games) · 자체 capability suite (88 tests × 10 models × 5 runs = 4,400 records)</td> </tr> <tr> <td><span style="white-space: nowrap">리뷰 일자</span></td> <td>2026-08-12</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>에이전트 개발이 프롬프트 템플릿, 툴 스키마, 콜백 코드, 워크플로 그래프로 쪼개져 있다는 문제의식에서 출발해, NVIDIA 는 <strong>에이전트를 그냥 Python 객체로 만드는</strong> 프레임워크 NOOA (NVIDIA Object-Oriented Agents) 를 내놓았다. 메서드는 모델이 취할 수 있는 행동, 필드는 상태, docstring 은 프롬프트, 타입 어노테이션은 계약이다. 메서드 본문이 <code class="language-plaintext highlighter-rouge">...</code> 이면 런타임이 LLM 루프로 채우고, 본문이 있으면 그냥 결정론적 Python 으로 실행된다.</li> <li>저자들은 자기 설계를 6개 model-facing capability 로 정리한다 — typed I/O, pass-by-reference, code as action, programmable loop engineering, explicit object state, model-callable harness APIs. 14개 경쟁 프레임워크를 이 축으로 채점해 “여섯 개를 한 표면에 모두 올린 시스템은 아직 없다” 고 주장한다.</li> <li>성능은 실제로 나온다. SWE-bench Verified 에서 GPT-5.5 xhigh 82.2%, Terminal-Bench 2.0 에서 Opus 4.6 high 65.2%, CyberGym L1 에서 86.8% (open source 1위). ARC-AGI-3 에서는 6개 에이전트짜리 멀티에이전트 시스템 (DreamTeam) 을 <strong>에이전트 1개 + 50줄 skill</strong> 로 압축하고도 GPT-5.6-sol 기준 RHAE 85.1% 를 게임당 USD 20 미만에 달성했다.</li> <li>토큰 효율도 같이 좋아진다. SWE-bench GPT-5.5 xhigh 기준 NOOA 는 약 28 model call · 1.1M 토큰으로 82.2% 인데, PI 는 66 call · 2.2M 토큰으로 78.2% 다. 툴 출력이 transcript 로 계속 직렬화되지 않고 live Python 값으로 남기 때문이다.</li> <li>다만 6개 capability 축은 NOOA 설계 그 자체에서 도출된 rubric 이고, 6개 항목 각각이 벤치마크 점수에 얼마나 기여했는지에 대한 ablation 은 memory subsystem 하나뿐이다.</li> </ul> <h2 id="소개-introduction">소개 (Introduction)</h2> <p>에이전트 프레임워크를 하나 새로 배울 때 실제로 배우는 게 무엇인지 생각해보면 좀 이상하다. 타입 인터페이스, 변수 스코프, 제어 흐름, 비동기 실행, 객체 상태 — 이 개념들은 전부 일반 프로그래밍 언어에 이미 성숙한 형태로 존재한다. 그런데 LangGraph 를 배우면 graph DSL 을, Google ADK 를 배우면 workflow DSL 을, OpenAI Agents SDK 를 배우면 handoff 를 새로 배워야 한다. 같은 개념을 프레임워크마다 다른 이름과 다른 문법으로 다시 배우는 것이다.</p> <p>NOOA 의 출발점은 이 관찰이다. 저자들은 PyTorch 를 명시적인 영감으로 든다. PyTorch 가 보여준 것은 “강력한 런타임이 그럼에도 사용자에게는 단순한 Python 프로그래밍 모델을 제시할 수 있다” 는 사실이었다. autograd, CUDA 커널 디스패치, 그래프 캡처가 뒤에서 돌아가지만 사용자가 쓰는 건 <code class="language-plaintext highlighter-rouge">nn.Module</code> 을 상속한 클래스와 <code class="language-plaintext highlighter-rouge">forward</code> 메서드다. NOOA 는 같은 것을 에이전트에 적용한다: 컨텍스트 렌더링, KV-cache 최적화, 이벤트 기록, 타입 검증, 재시도 루프가 런타임에 있지만 개발자가 쓰는 건 <code class="language-plaintext highlighter-rouge">Agent</code> 를 상속한 클래스와 몇 개의 메서드다.</p> <p>여기에 하나 더 있다. 개발자만 이득을 보는 게 아니라 <strong>모델도</strong> 이득을 본다는 것이다. LLM 은 Python 클래스와 메서드 호출을 이미 안다. 학습 데이터에 압도적으로 많이 들어 있다. 반면 특정 프레임워크의 graph DSL 은 모델 입장에서 처음 보는 문법이다. 에이전트를 Python 객체로 표현하면 모델이 별도 학습 없이도 그 인터페이스를 다룰 수 있어야 한다 — 저자들은 이걸 <strong>agent readiness</strong> 라고 부르고, 논문의 §4.1 은 이 가설을 직접 검증하는 실험이다.</p> <p>이 논문이 지금 읽을 가치가 있는 이유는, 프레임워크 홍보 논문 치고는 비교 파트가 이례적으로 성실하기 때문이다. 14개 프레임워크를 pinned commit 까지 명시해가며 소스 코드를 직접 읽고 채점한 부록이 20페이지 넘게 붙어 있다. 그 부록을 읽으면 2026년 중반 시점에 에이전트 하네스 생태계가 어디까지 왔는지가 한눈에 들어온다. NOOA 를 쓸 생각이 없더라도 그 지도는 유용하다.</p> <h2 id="핵심-기여-key-contributions">핵심 기여 (Key Contributions)</h2> <ul> <li><strong>agent-as-a-Python-object 프로그래밍 모델.</strong> 에이전트 = 클래스, 능력 = 메서드, 타입 어노테이션 = 계약, 동시성 = <code class="language-plaintext highlighter-rouge">asyncio</code>, 오케스트레이션 = 평범한 Python 코드. 에이전트 고유 개념 (context, event, state rendering, long-term memory, validated LLM loop) 만 단순한 Pythonic API 로 노출한다.</li> <li><strong>6개 model-facing interface capability 의 정식화.</strong> typed input/output, pass-by-reference over live objects, code as action, programmable loop engineering, explicit object state, model-callable harness APIs. 이 6개는 NOOA 만의 발명이 아니라 여러 시스템에 흩어져 있는 아이디어인데, 논문의 기여는 이걸 하나의 축으로 명명하고 14개 시스템을 그 축으로 채점한 것이다.</li> <li><strong>현행 모델이 이 인터페이스를 실제로 쓸 수 있다는 실증.</strong> 10개 모델 × 88개 테스트 × 5회 = 4,400 record 에서 97.9% 통과. 인터페이스 자체가 모델에게 부담이 아니라는 것을 보인다.</li> <li><strong>에이전틱 벤치마크 4종에서의 end-to-end 결과.</strong> SWE-bench Verified, Terminal-Bench 2.0, CyberGym L1, ARC-AGI-3. 특히 ARC-AGI-3 에서는 멀티에이전트 시스템을 단일 에이전트로 압축하면서 score–cost Pareto frontier 를 밀어냈다.</li> <li><strong>리뷰어 입장에서 가장 값진 것은 부록 A 와 B 다.</strong> 부록 A 는 14개 프레임워크의 실제 소스 코드 수준 비교이고, 부록 B 는 stress test 하나에 대해 4개 모델의 전체 trace 를 그대로 실었다. 후자는 “왜 강한 모델이 쉬운 규율에서 실패하는가” 를 보여주는 드문 자료다.</li> </ul> <h2 id="관련-연구--배경-지식">관련 연구 / 배경 지식</h2> <h3 id="codeact-행동-modality-로서의-코드">CodeAct: 행동 modality 로서의 코드</h3> <p>이 논문을 읽으려면 CodeAct 계열 아이디어를 알아야 한다. 전통적인 tool calling 은 모델이 JSON 을 뱉으면 하네스가 파싱해서 함수를 부르는 구조다. CodeAct 는 그 대신 모델이 <strong>실행 가능한 Python 코드</strong>를 뱉게 한다. 툴은 그 코드 안에서 부를 수 있는 평범한 함수가 되고, 모델은 반복문·조건문·중간 변수를 자유롭게 쓸 수 있다.</p> <p>차이가 왜 중요한가. JSON tool call 은 호출 하나당 결과 하나가 컨텍스트 창에 통째로 들어온다. 100개 항목을 분류하려면 100번 왕복하거나 100개 결과를 한 번에 받아야 한다. 코드라면 <code class="language-plaintext highlighter-rouge">for</code> 문 한 줄이고, 중간 결과는 변수에 남으며, 컨텍스트에는 모델이 <code class="language-plaintext highlighter-rouge">print</code> 한 것만 들어온다. NOOA 의 CodeActStrategy 는 이 패러다임을 그대로 계승하되, 여기에 타입 검증된 반환과 live object 참조를 얹는다.</p> <h3 id="pass-by-reference-직렬화하지-않는-인자-전달">pass-by-reference: 직렬화하지 않는 인자 전달</h3> <p>대부분의 에이전트 프레임워크는 모든 경계에서 copy-as-text 를 한다. 입력을 텍스트로 직렬화하고, 툴 호출 인자를 LLM 이 텍스트로 만들고, 출력을 텍스트로 돌려받고, 그 텍스트를 다시 호스트 언어로 파싱한다. 파일을 쓰는 프레임워크들 (Claude Agent SDK 의 workspace file, Codex 의 <code class="language-plaintext highlighter-rouge">AGENTS.md</code>) 은 이것의 변종인데, 파일 경로를 넘겨주면 모델이 툴로 탐색하게 하는 방식이다. 강력하지만 타입 정보가 전부 사라진다.</p> <p>NOOA 는 인자를 <strong>살아 있는 Python 객체</strong>로 넘긴다. 모델이 컨텍스트에서 보는 것은 변수 이름 + 제한된 미리보기 (concrete type, 실제 길이, head/tail 샘플) 뿐이다. 예를 들어 정수 100개짜리 리스트는 이렇게 렌더된다:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>records = list(len=100, [:5]=[42, 17, 89, 33, 8], [-5:]=[56, 71, 12, 45, 28])
</code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">records</code> 변수 자체는 잘리지 않았다. 실행 환경에 100개 원소가 전부 살아 있고, 모델은 <code class="language-plaintext highlighter-rouge">for r in records:</code> 로 전부 순회할 수 있다. 컨텍스트에는 10개만 등장했는데도. 저자들은 이 미리보기 형식이 Rich 의 <code class="language-plaintext highlighter-rouge">pprint()</code> 에서 이름과 API 표면을 빌려왔지만, 여러 open/closed 모델에 걸친 실험을 근거로 출력 포맷은 바꿨다고 밝힌다.</p> <h3 id="memgpt-계열-컨텍스트를-os-처럼-다루기">MemGPT 계열: 컨텍스트를 OS 처럼 다루기</h3> <p>NOOA 의 long-term memory 는 MemGPT 의 문제의식 — LLM 을 운영체제로 보고 in-context 와 external memory tier 사이에 정보를 페이징한다 — 을 이어받되, 두 가지를 바꾼다. 첫째, memory 를 쓰는 것이 백그라운드 추출 파이프라인의 산출물이 아니라 <strong>모델의 의도적 행동</strong>이다. 둘째, 검색이 순수 유사도가 아니라 인지 과학에서 온 ACT-R activation (relevance, recency, importance) 을 쓴다.</p> <h2 id="방법--아키텍처-상세">방법 / 아키텍처 상세</h2> <h3 id="에이전트는-클래스-하나다">에이전트는 클래스 하나다</h3> <p>논문의 Figure 1 이 전부라고 해도 과언이 아니다. 고객 지원 에이전트 하나가 클래스 하나에 들어 있다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig1-agent-class-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig1-agent-class-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig1-agent-class-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig1-agent-class.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: NOOA 에서 간단한 Agent 를 구현한 모습. 같은 클래스 안에 결정론적 메서드 (is_refund_eligible) 와 agentic method 두 종류 (classify, triage) 가 공존한다.</figcaption> </figure> <p>여기서 읽어야 할 것들:</p> <ul> <li><code class="language-plaintext highlighter-rouge">order_db: OrderDB</code> — 객체 상태다. 모델에게 보이고, 참조로 전달된다.</li> <li><code class="language-plaintext highlighter-rouge">is_refund_eligible(self, order: Order) -&gt; bool</code> — 본문이 있는 평범한 Python 메서드. 결정론적이고, 테스트 가능하고, <strong>모델이 코드 안에서 호출할 수 있다</strong>.</li> <li><code class="language-plaintext highlighter-rouge">classify(self, message: str) -&gt; TicketKind</code> — 본문이 <code class="language-plaintext highlighter-rouge">...</code> 이고 <code class="language-plaintext highlighter-rouge">@strategy(PredictStrategy())</code> 가 붙었다. 단발 LLM 호출로 분류하고 반환값을 <code class="language-plaintext highlighter-rouge">TicketKind</code> 로 검증한다.</li> <li><code class="language-plaintext highlighter-rouge">triage(self, message: str, photo: Image | None, order: Order | None) -&gt; Ticket</code> — <code class="language-plaintext highlighter-rouge">@strategy(CodeActStrategy())</code>. 모델이 Python 을 쓰는 루프를 돌린다. <code class="language-plaintext highlighter-rouge">order</code> 는 직렬화된 텍스트가 아니라 살아 있는 객체로 들어오고, <code class="language-plaintext highlighter-rouge">photo</code> 는 native multimodal content block 으로 렌더된다.</li> </ul> <p>핵심은 <strong>경계가 코드에 보인다</strong>는 것이다. 본문이 있으면 결정론적 코드, <code class="language-plaintext highlighter-rouge">...</code> 이면 agentic loop. 프롬프트 엔지니어링이 다시 소프트웨어 엔지니어링 안으로 들어온다 — 동작을 테스트하고, 추적하고, 리팩터링하고, 버전 관리할 수 있다.</p> <h3 id="다섯-가지-설계-원칙">다섯 가지 설계 원칙</h3> <p>논문은 다섯 원칙을 명시하고, 각 원칙이 어떤 interface capability 로 구체화되는지 짝지어 놓았다.</p> <table> <thead> <tr> <th>원칙</th> <th>내용</th> <th>대응 capability</th> </tr> </thead> <tbody> <tr> <td>P1</td> <td>성숙한 Python 추상화가 이미 있으면 DSL 을 만들지 말고 그것을 채택</td> <td>Loop engineering, Object state</td> </tr> <tr> <td>P2</td> <td>agentic loop 를 비정형 텍스트 교환이 아니라 <strong>타입이 있는 메서드 호출</strong>로 재구성</td> <td>Typed I/O, Pass by reference</td> </tr> <tr> <td>P3</td> <td>결정론적 작업 (규칙, 산술, 파싱, 상태 전이) 은 agentic loop 밖으로</td> <td>—</td> </tr> <tr> <td>P4</td> <td>모델이 이미 가진 Python 지식을 활용</td> <td>Code as action</td> </tr> <tr> <td>P5</td> <td>하네스를 명시적 API 로 노출 (context, event history)</td> <td>Harness APIs</td> </tr> </tbody> </table> <p>P3 이 조용하지만 중요하다. LLM 은 의미 판단, 종합, 열린 과제에 쓸모가 있고 정확한 규칙과 산술은 결정론적 메서드에 속한다. NOOA 에서 그 경계는 문법 하나로 표현된다 — 본문이 있느냐 <code class="language-plaintext highlighter-rouge">...</code> 이냐.</p> <h3 id="strategy-메서드마다-다른-실행-모드">strategy: 메서드마다 다른 실행 모드</h3> <p>agentic method 의 실행 방식은 <strong>strategy</strong> 라는 데코레이터가 결정한다. strategy 는 메서드의 시그니처와 타입 경계는 그대로 두고, 어떤 컨텍스트를 렌더할지 / 턴을 어떻게 실행할지 / 후보 출력을 어떻게 검증할지만 제어한다. 메서드 단위이므로, 작고 빠른 모델을 분류 메서드에 붙이고 에이전트 기본 모델은 열린 과제에 쓰는 식의 구성이 가능하다.</p> <p>내장 strategy 는 둘이다.</p> <ol> <li><strong><code class="language-plaintext highlighter-rouge">PredictStrategy</code></strong> — 분류나 추출용 단발 전략. 컨텍스트를 렌더하고, 모델에게 값을 요청하고, Python 반환 타입으로 검증한다. 검증 실패 시 로컬 재시도 루프를 돈다.</li> <li><strong><code class="language-plaintext highlighter-rouge">CodeActStrategy</code></strong> — 같은 계약을 반복적인 Python REPL 로 일반화한다. 모델은 <code class="language-plaintext highlighter-rouge">execute_python(...)</code> 으로 계산하거나 내부 상태를 조회하거나 다른 generation method 를 호출하고, 하네스는 관측 결과를 기록하고 갱신된 상태를 다시 렌더하고, 모델이 <code class="language-plaintext highlighter-rouge">return_result(...)</code> 로 타입 검증을 통과하는 값을 낼 때까지 반복한다.</li> </ol> <p>동시성 규칙도 명확하다. 한 에이전트 안에서 외부에서 시작된 agentic method 호출들은 직렬화되어 서로 턴이 섞이지 않는다. 같은 에이전트에 대한 중첩 호출은 스택 규율을 따라 호출자가 중단되고 피호출자가 반환할 때까지 기다리며, 두 실행은 같은 event history 에 append 된다. 다른 메서드와 다른 에이전트는 Python 표준 async/await 로 병렬 실행된다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig2-codeact-loop-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig2-codeact-loop-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig2-codeact-loop-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig2-codeact-loop.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: agentic method 안의 CodeAct 루프. 렌더 → LLM 호출 → Python 실행 → event·state 갱신을 반복하고, 타입 검증을 통과한 값만 호출자에게 돌아간다.</figcaption> </figure> <h3 id="컨텍스트-세-영역과-kv-cache">컨텍스트: 세 영역과 KV-cache</h3> <p>NOOA 는 컨텍스트를 세 영역으로 나눈다.</p> <ul> <li><strong>static context blocks</strong> — 한 번 계산해서 턴마다 재사용. 시스템 프롬프트 같은 것.</li> <li><strong>event history</strong> — 하네스가 만들어내는 append-only 타입 이벤트 시퀀스. model tool call, Python 출력, 반환값. 각 이벤트는 고유 태그를 가진 typed Python object 라서, 에이전트 코드가 flat transcript 를 스캔하는 대신 이전 이벤트를 <strong>질의</strong>할 수 있다.</li> <li><strong>dynamic context blocks</strong> — 매 model call 전에 재평가. <code class="language-plaintext highlighter-rouge">TODO</code> 리스트나 <code class="language-plaintext highlighter-rouge">self</code> 의 특정 필드처럼 값이 변하는 정보.</li> </ul> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig3-context-rendering-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig3-context-rendering-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig3-context-rendering-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig3-context-rendering.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: ContextManager 와 EventManager 가 매 LLM 턴 전에 세 영역을 채운다. static 은 system, event 는 user/assistant/tool_call, dynamic 은 마지막 user 메시지로 렌더된다.</figcaption> </figure> <p>이 3영역 배치는 <strong>KV-cache 재사용을 최대화하도록 설계</strong>됐다. static prefix 는 변하지 않고, event history 는 새 메시지 append 로만 자라고, 휘발성 dynamic block 은 꼬리에 놓인다. 그래서 live state 가 갱신돼도 캐시된 prefix 가 무효화되지 않고, 매 턴이 직전 계산의 대부분을 재사용한다. 실용적으로 중요한 설계다 — dynamic block 을 앞에 두면 매 턴 전체 prefill 을 다시 해야 한다.</p> <p>기본값도 구체적으로 밝혀져 있다. 기본 static prefix 는 작은 NOOA 시스템 프롬프트 (약 1k characters), 활성 strategy 지시문 (CodeAct 는 약 2.5k characters), 임포트된 타입과 라이브러리를 보여주는 execution-context block, 그리고 에이전트 API 의 간결한 <code class="language-plaintext highlighter-rouge">doc(self)</code> 렌더링으로 구성된다. dynamic suffix 에는 live agent state 의 압축 뷰 (<code class="language-plaintext highlighter-rouge">pprint(self)</code>) 가 들어간다.</p> <p>그리고 이 모든 게 개발자와 모델 <strong>양쪽</strong> 이 쓸 수 있는 Python API 다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig4-context-api-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig4-context-api-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig4-context-api-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig4-context-api.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 4: context block 과 event history 의 Python API. set_dynamic 은 매 턴 재평가할 표현식을 등록하고, events.collapse 는 실행 이력을 요약 이벤트로 접는다.</figcaption> </figure> <h3 id="python-실행과-반환-검증">Python 실행과 반환 검증</h3> <p>모델이 코드 행동을 고르면 NOOA 는 제한된 Jupyter 유사 세션에서 셀을 실행한다. 메서드 인자, live agent (<code class="language-plaintext highlighter-rouge">self</code>), 에이전트의 환경 (에이전트 소스 파일에 정의된 임포트·메서드·상수) 이 지역 변수로 주입되고 <code class="language-plaintext highlighter-rouge">await</code> 를 바로 쓸 수 있다.</p> <p>안전 장치는 명시적이다. <code class="language-plaintext highlighter-rouge">eval</code>, <code class="language-plaintext highlighter-rouge">exec</code>, <code class="language-plaintext highlighter-rouge">compile</code>, <code class="language-plaintext highlighter-rouge">input</code> 과 블로킹 event-loop 호출은 구체적인 에러로 거부된다. stdout, stderr, 이미지, 반환값, 지역 변수, 예외는 구조화된 결과로 캡처된다. 문법 오류와 traceback 은 IPython 형식으로 — 소스 위치와 caret/source-line 컨텍스트를 포함해 — 전달되므로, 다음 LLM 턴이 사람이 노트북 셀을 고치듯 코드를 고칠 수 있다.</p> <p>셀 안에는 반복문, 조건문, 라이브러리 호출, helper 호출, subagent 호출이 들어갈 수 있다. 즉 <strong>모델이 개발자와 같은 오케스트레이션 도구를 가진다.</strong> 셀 안에서 <code class="language-plaintext highlighter-rouge">@strategy</code> 데코레이터가 붙은 새 함수를 정의하고 <code class="language-plaintext highlighter-rouge">asyncio.gather</code> 로 배치에 fan-out 하면, 평범한 Python 으로 병렬 subagent 호출이 만들어진다.</p> <p>상태 갱신은 표준 Python 스코프 규칙을 따른다. REPL 지역 변수는 메서드 스코프라서 하나의 CodeAct 호출 안에서는 셀 간에 유지되다가 메서드가 반환하면 사라진다. 중간값이 태스크 밖으로 새지 않는다. 반면 <code class="language-plaintext highlighter-rouge">self</code> 나 라이브러리 호출을 통해 닿은 것은 메서드보다 오래 사는 부작용을 가질 수 있다 — 평범한 Python 프로그램과 정확히 같다.</p> <p>마지막으로 반환 검증이 있다. 모델이 결과를 반환하면 하네스가 반환 어노테이션에 맞는지 검증하고, 유효하지 않으면 실패를 설명하는 에러 메시지를 모델에게 보내고 루프를 계속한다. 유효하면 호출자에게 반환하고 평범한 Python 실행이 재개된다.</p> <h3 id="long-term-memory-에이전트가-자기-상태를-큐레이션한다">long-term memory: 에이전트가 자기 상태를 큐레이션한다</h3> <p>여기까지의 메커니즘은 메서드 호출이나 세션 범위다. §3.7 은 그 경계를 넘는다.</p> <p><code class="language-plaintext highlighter-rouge">MemoryManager.install(agent)</code> 가 손대지 않은 에이전트에 메모리 서브시스템을 붙이고, 제거하면 에이전트가 정확히 원상복구된다. 설계 원칙 P5 를 따라, 메모리를 쓰는 것은 백그라운드 추출 파이프라인의 산출물이 아니라 <strong>모델의 의도적 행동</strong>이다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig5-memory-system-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig5-memory-system-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig5-memory-system-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig5-memory-system.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 5: NOOA memory 시스템. 에이전트는 7개 툴로 자기 저장소를 관리하고, BeforeTurn 훅이 연관 메모리를 dynamic context block 에 주입한다. 모든 상태는 하나의 SQLite 파일에 산다.</figcaption> </figure> <p>구성 요소를 정리하면:</p> <ul> <li><strong>7개 model-callable tool</strong>: <code class="language-plaintext highlighter-rouge">remember</code>, <code class="language-plaintext highlighter-rouge">recall</code>, <code class="language-plaintext highlighter-rouge">search</code>, <code class="language-plaintext highlighter-rouge">update_memory</code>, <code class="language-plaintext highlighter-rouge">forget</code>, <code class="language-plaintext highlighter-rouge">associate</code>, <code class="language-plaintext highlighter-rouge">deref</code>. 이 툴들은 순서가 있는 언어적 서술자 (CRITICAL … TRIVIAL) 를 받고 내부적으로만 숫자 점수로 매핑한다. 모델이 보는 어휘를 분포 안에 유지하려는 선택이다.</li> <li><strong>두 개의 회상 채널</strong>: (1) 에이전트가 툴로 저장소를 직접 질의하는 deliberate recall, (2) <code class="language-plaintext highlighter-rouge">BeforeTurn</code> 훅이 최근 이벤트에서 질의를 도출해 연관 메모리를 dynamic context block 에 주입하는 spontaneous recall. 주입된 메모리는 강화되지 않는다 (<code class="language-plaintext highlighter-rouge">touch=False</code>) — 하네스가 보여준 것이 사용 신호를 왜곡하지 않게 하려는 것이다.</li> <li><strong>검색</strong>: embedding 후보와 keyword 후보를 union 하고 ACT-R activation — relevance, recency, importance — 으로 랭킹한 뒤, typed memory graph 위로 activation 을 전파한다. decay 기반 망각이 저장소 크기를 제한한다.</li> <li><strong>비동기 reflection</strong>: 태스크 완료 후 또는 에이전트가 유휴일 때 루프 밖에서 돌아간다. 근접 중복 병합, 충돌 값을 하나의 current record 로 조정하고 대체된 것은 보관, 관련 메모리 연결, importance 재점수화, episode 를 상위 레코드로 증류, activation 이 decay 한 메모리 pruning. <strong>최근 메모리, 보호된 타입, 열린 todo 는 절대 pruning 하지 않는다.</strong></li> <li><strong>하나의 검사 가능한 파일</strong>: 전체 저장소가 SQLite 파일 하나다. vector index 는 거기서 파생되고 교체 가능하다. 메모리는 <code class="language-plaintext highlighter-rouge">kind:key</code> 형태의 typed reference 를 가질 수 있는데, 이것은 recall 시점에 live agent state 로 해소된다 — pass by reference 를 영속성까지 확장한 것이고, 회상이 stale copy 에서 답하지 않게 만든다.</li> </ul> <p>효과는 §4.4 에서 측정된다: 메모리 대신 file-based note 를 쓴 동일 에이전트 대비 <strong>+11.8 RHAE points</strong>.</p> <h2 id="학습-목표--손실-함수">학습 목표 / 손실 함수</h2> <p>이 논문에는 학습 목표도 손실 함수도 없다. NOOA 는 model-agnostic 프레임워크이고 어떤 모델도 학습시키지 않는다. 그 대신 이 자리에 해당하는 것이 있다면 <strong>반환 검증 계약</strong>이다.</p> <p>CodeAct 턴에서 모델이 할 수 있는 행동은 두 가지뿐이다:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>execute_python(code)  →  계산을 계속한다
return_result(v)      →  메서드를 종료한다
</code></pre></div></div> <p>두 번째 경우 하네스는 $v$ 가 메서드의 반환 어노테이션 $T$ 를 만족하는지 검사한다. $v \notin T$ 이면 실패를 설명하는 에러 메시지가 모델에게 돌아가고 루프가 계속된다. $v \in T$ 이면 호출자에게 반환된다.</p> <p>이게 왜 중요한지는 §4.2 의 trace 분석이 보여준다. OpenCode 는 모델이 tool call 없이 응답하는 순간 종료한다. Terminal-Bench 에서 실패한 GPT-5.5 시행의 77% 가 열 스텝 안에 종료됐다. 즉 모델이 “다 했다” 고 말하면 그걸로 끝인 것이다. NOOA 에서는 모델이 근거와 검증 명령을 담은 타입 검증된 <code class="language-plaintext highlighter-rouge">TaskResult</code> 를 반환해야 한다. 종료 자체가 프로그램적으로 검증되는 행동이 되고, 프롬프트에만 적힌 비공식 관행이 아니게 된다. 저자들의 표현으로는 <strong>“타입 어노테이션을 실행 가능한 계약으로 취급”</strong> 하는 것이다.</p> <h2 id="학습-데이터와-파이프라인">학습 데이터와 파이프라인</h2> <p>학습이 없으므로 이 절은 평가 설정으로 대체한다.</p> <table> <thead> <tr> <th>평가</th> <th>설정</th> </tr> </thead> <tbody> <tr> <td>Capability suite</td> <td>36개 family, 88개 test instance. 10개 모델 × 5회 = 4,400 record. 대부분 1–5턴 상호작용</td> </tr> <tr> <td>Stress subset</td> <td>capability suite 중 6개 family. 행마다 50 record (10 모델 × 5회), 총 300 record</td> </tr> <tr> <td>SWE-bench Verified</td> <td>실제 GitHub 이슈 기반 500개 소프트웨어 엔지니어링 태스크</td> </tr> <tr> <td>Terminal-Bench 2.0</td> <td>커맨드라인 환경에서 수행하는 89개 태스크 (설치, 설정, 디버깅, 서비스 운영)</td> </tr> <tr> <td>CyberGym L1</td> <td>코드베이스에서 보안 버그를 찾고 이를 재현하는 PoC 로 검증</td> </tr> <tr> <td>ARC-AGI-3</td> <td>미지의 그리드 게임에서 순수하게 행동만으로 메커니즘·목표·조작을 발견하는 interactive reasoning</td> </tr> </tbody> </table> <p>평가에 쓰인 에이전트도 밝혀져 있다. SWE-bench 와 Terminal-Bench 는 둘 다 같은 벤치마크 불가지론적 에이전트 <code class="language-plaintext highlighter-rouge">BenchAgent</code> 를 쓰는데, <strong>평범한 Python 253줄</strong>이다. todo 리스트, 셸 툴, tree-sitter 기반 저장소 탐색 툴을 갖고, dynamic context 에 태스크 설명·todo 상태·컨텍스트 창 통계·셸/저장소 툴의 현재 작업 상태를 담는다. 종료는 식별된 root cause, 근거, 검증 명령을 담은 타입 <code class="language-plaintext highlighter-rouge">TaskResult</code> 로 이뤄진다.</p> <p>비교 대상 하네스는 OpenCode 1.14.33 과 PI v0.72.1 이고, 셋 다 같은 GPT-5.5 / Claude Opus 4.6 백엔드에 가능한 reasoning-effort 설정으로 평가됐다.</p> <p>Table 7 의 프레임워크 채점은 2026년 7월 7–9일에 가져온 pinned snapshot (저장소, 커밋, 패키지 버전) 을 대상으로 문서와 소스 코드를 직접 읽어 이뤄졌다. Green (Supported) 은 그 capability 가 <strong>모델이 보는 것의 일급 구성 요소</strong>임을, Yellow (Partial) 은 존재하지만 주로 개발자용이거나 툴/파일 뒤에 있음을, Red (Limited) 는 증거를 찾지 못했음을 뜻한다. Experimental, flag-gated, opt-in 인 경우는 capability 자체로 채점하고 강등 대신 † 로 표시했다.</p> <h2 id="실험-결과">실험 결과</h2> <h3 id="capability-test-모델은-이-인터페이스를-이해하는가">capability test: 모델은 이 인터페이스를 이해하는가</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab1-2-capability-stress-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab1-2-capability-stress-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab1-2-capability-stress-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab1-2-capability-stress.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 1 · Table 2: capability test 는 4,309/4,400 (97.9%) 통과하지만, 6개 stress family 로 좁히면 254/300 (84.7%) 로 떨어진다.</figcaption> </figure> <p>전체 통과율은 4,309/4,400 = 97.9%. 규모별로 나누면 small/efficient 4종 (Claude Haiku 4.5, Gemini 3.5 Flash, Nemotron 3 Nano 30B, GPT-5.4 Mini) 이 96.0%, large/frontier 6종 (Claude Opus 4.8, Gemini 3.1 Pro, GLM-5.2, Kimi K2.6, Nemotron 3 Ultra, GPT-5.5) 이 99.2% 다. <strong>모든 모델이 91% 를 넘고, 10개 중 6개가 98% 를 넘는다.</strong> GPT-5.5 는 이 suite 에서 완벽 (440/440) 하고, Gemini 3.5 Flash 와 GLM-5.2 는 각각 테스트 하나씩만 놓쳤다 (439/440).</p> <p>reasoning mode 별 결과도 흥미롭다. frontier 모델은 모드와 무관하게 포화한다 (Opus 100.0/99.5, GPT-5.5 99.5/98.6, off/on 순). 반면 reasoning 의 가치는 모델 능력이 낮아질수록 단조 증가한다 — Ultra 93.4 → 94.1, Super-v3 83.7 → 96.4, Nano 52.5 → 84.8. 작은 Nemotron 모델에게 inference-time reasoning 이 능력 평준화 장치로 작동하는 셈이다.</p> <p>여기서 저자들이 끌어내는 함의는 <strong>“인터페이스 자체가 현행 LLM 에게 부담이 아니다”</strong> 이다. 모델은 Python 을 알고, 객체 문서를 읽고, 타입 있는 인자로 메서드를 부르고, 반환값을 쓰고, 객체 상태를 변경하고, 타입 계약을 만족하는 값을 반환한다 — 이 프레임워크로 학습된 적이 없는데도.</p> <h3 id="stress-test-남은-프론티어는-어디인가">stress test: 남은 프론티어는 어디인가</h3> <p>잔여 실패는 6개 stress family 에 집중된다. stress subset 은 300개 중 254개 통과 (84.7%) 로, 전체 97.9% 와 대비된다. large/frontier 는 180개 중 169개 (93.9%), small/efficient 는 120개 중 85개 (70.8%). <strong>규모 격차가 전체 3.2 포인트에서 stress subset 23 포인트로 벌어진다.</strong></p> <p>가장 어려운 것은 <code class="language-plaintext highlighter-rouge">sentiment_batch</code> (31/50, 62%) 다. 개별 항목을 큰 배치에 걸쳐 장부 관리하는 능력을 요구한다.</p> <p>일관성 측정도 있다. 880개 (test, model) 쌍 중 94% 가 5회 모두 통과하고, 5회 모두 실패하는 것은 셋뿐이며, 나머지는 간헐적이다. 두 실패 모드가 규모별로 갈린다: <strong>large 모델은 0/5 가 하나도 없다</strong> — 모든 실패가 간헐적이고, 이미 시연된 능력에서의 신뢰성 miss 다. small 모델은 둘 다 보인다 — stress 쌍의 12.5% 가 0/5, 42% 가 간헐적.</p> <p>이건 <code class="language-plaintext highlighter-rouge">self</code> 를 이해하지 못하거나 메서드를 못 부르는 실패가 아니다. <strong>규율 있는 multi-step 하네스 사용의 실패</strong>다. 부록 B 가 이 지점을 아주 잘 보여준다 — 뒤의 “결과 분석” 절에서 다룬다.</p> <h3 id="swe-bench-verified-와-terminal-bench-20">SWE-bench Verified 와 Terminal-Bench 2.0</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab3-4-swebench-terminalbench-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab3-4-swebench-terminalbench-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab3-4-swebench-terminalbench-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab3-4-swebench-terminalbench.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 3 · Table 4: 같은 백엔드·같은 reasoning effort 에서 NOOA · OpenCode · PI 비교. NOOA 는 SWE-bench 의 모든 설정에서 open harness 중 1위다.</figcaption> </figure> <p>SWE-bench Verified 에서 NOOA 는 평가된 모든 모델·reasoning 설정에서 open harness 중 최고 통과율을 얻는다. GPT-5.5 기준 off / high / xhigh 에서 각각 67.2%, 78.8%, 82.2%. xhigh 에서 OpenCode 는 78.6%, PI 는 78.2% 다. Opus 4.6 에서는 NOOA 79.8% (OpenCode 75.2, PI 75.8).</p> <p>더 의미 있는 비교는 CodeAct 원조와의 대조다. OpenHands v3 는 Opus 4.6 에서 68.4% 로 보고되는데, NOOA 는 <strong>같은 모델로 11.4 포인트 개선</strong>한 79.8% 를 낸다. 참고로 제출 시점 공개 리더보드 SOTA 는 specialized agent + Opus 4.5 조합의 79.2% 였다.</p> <p>Terminal-Bench 2.0 에서 격차는 더 크다. reasoning 을 끈 상태에서 NOOA 46.1% 대 OpenCode 34.8%, PI 37.1%. high effort 에서 73.0% 로, OpenCode 를 12.3 포인트, PI 를 4.5 포인트 앞선다. 다만 GPT-5.5 xhigh 최고 결과는 PI 의 75.3% 로, NOOA 73.0% 보다 높다. Opus 4.6 high 에서는 NOOA 65.2% 대 OpenCode 43.8%, PI 58.4%.</p> <p><strong>reasoning effort 와의 상호작용</strong>이 이 논문에서 가장 통찰력 있는 관찰 중 하나다. reasoning 을 끄면 NOOA 는 SWE-bench 에서 OpenCode 와 PI 를 각각 8.0, 6.4 포인트, Terminal-Bench 에서 11.3, 9.0 포인트 앞선다. 그런데 effort 를 올리면 이 마진이 좁아진다. 저자들의 해석: NOOA 가 노출하는 명시적 객체 상태, 타입 있는 행동, 프로그래머블 루프가 <strong>강한 reasoning 모델이 스스로 수행하게 되는 행동을 부분적으로 대체</strong>한다는 것이다. 하네스 설계의 가치가 모델이 약할수록 크다는 뜻이고, 이건 실무적으로 중요한 함의다.</p> <h3 id="토큰-효율-scorecost-frontier">토큰 효율: score–cost frontier</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig6-pareto-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig6-pareto-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig6-pareto-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig6-pareto.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 6: SWE-bench Verified 점수 대 task 당 토큰 비용 (log scale). 색은 하네스, 마커 모양은 백엔드, 크기는 reasoning effort. 점선이 Pareto frontier.</figcaption> </figure> <p>높은 통과율이 더 긴 trajectory 에서 나온 게 아니라는 점이 중요하다. GPT-5.5 xhigh SWE-bench 에서 NOOA 는 약 28 model call · task 당 1.1M 토큰으로 82.2% 를 낸다. OpenCode 는 비슷한 call 수에 약 1.3M 토큰으로 78.6%, PI 는 66 call · 2.2M 토큰으로 78.2% 다. <strong>NOOA 는 PI 의 절반 토큰과 절반 이하 call 로 4 포인트 높은 점수를 낸다.</strong></p> <p>이유는 구조적이다. 툴 출력이 transcript 로 반복 직렬화되지 않고 live Python 값으로 남는다. bounded prompt preview 가 컨텍스트 한계 아래를 유지시켜, OpenCode 와 PI 가 쓰는 손실 있는 transcript compaction 을 피하면서 prefix-cache 재사용을 보존한다. code as action 과 pass-by-reference 를 결합했을 때의 이득이 정확히 여기서 드러난다.</p> <p>closed system 과의 비교도 있다. SWE-bench Verified 에서 Codex 88.7%, Claude Code 80.8% 대 NOOA 82.2% (GPT-5.5) / 79.8% (Opus 4.6). Terminal-Bench 2.0 에서는 NOOA 의 Opus 4.6 65.2% 가 Claude Code 와 Terminus-2 의 62.9–65.4% 와 비슷하다. 즉 작은 벤치마크 불가지론적 에이전트가 specialized 시스템과 경쟁 가능하면서 비교된 open general-purpose 하네스는 일관되게 앞선다.</p> <h3 id="cybergym-l1">CyberGym L1</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab5-cybergym-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab5-cybergym-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab5-cybergym-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab5-cybergym.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 5: CyberGym L1 취약점 탐색. NOOA 86.8% 는 open source 1위이고, 다수의 closed 시스템을 앞선다.</figcaption> </figure> <p>CyberGym 에이전트는 trial container 안에서 셸과 todo manager 툴을 가진 CodeAct 에이전트로 돌아간다. 태스크 설명을 읽고, 마운트된 소스를 조사하고, PoC 를 작성하고, CyberGym 제출 인터페이스로 제출한다. 모델 주변의 결정론적 레이어가 중요한 채점 메커니즘을 프롬프트 루프 밖에 둔다 — 제출 메서드가 작성된 PoC 를 보내고 벤치마크 응답을 처리하고, 가벼운 judge 가 모델의 요약이 서술된 취약점과 여전히 일치하는지 확인한 뒤 수락하고, 수락된 제출은 비결정론적 크래시를 걸러내기 위해 몇 차례 재제출된다. <strong>도메인 지식은 이것 외에 전혀 넣지 않았다</strong> — 성능이 사이버보안 steering 이 아니라 에이전트 아키텍처에서 나온다는 주장이다.</p> <p>NOOA 는 86.8% 로 Microsoft MDASHv2 (95.6%) 와 Crystalline (89.6%) 에 이은 3위이며, <strong>open source 에이전트 중에서는 1위</strong>다. OpenAI Codex + submission skill 이 83.5%, 소박한 Codex 가 64.9% 인 것과 비교된다.</p> <p>네트워크 접근이 성능에 영향을 준다는 점을 저자들이 짚는데, 규칙 기반 trajectory 분석으로 엄격한 “cheat check” 를 구현해 NOOA 결과가 온라인에서 취약점 정보나 벤치마크 자체를 조회한 게 아니라 문제 설정에서 직접 유도한 정보에만 기반함을 확인했다고 밝힌다. 참고로 NOOA 는 <code class="language-plaintext highlighter-rouge">blocked</code> 조건이고 상위 두 시스템은 <code class="language-plaintext highlighter-rouge">unknown</code> / <code class="language-plaintext highlighter-rouge">blocked</code> 다.</p> <h3 id="arc-agi-3-멀티에이전트를-단일-에이전트로-압축하기">ARC-AGI-3: 멀티에이전트를 단일 에이전트로 압축하기</h3> <p>이 절이 논문에서 가장 흥미롭다. 저자들의 companion 작업인 DreamTeam 은 공유 executable world model 을 중심으로 협업하는 6개 특화 에이전트 시스템으로 ARC-AGI-3 이전 최고 공개 점수를 세웠다. 이번 실험은 그 방법론이 <strong>급진적 단순화에서 살아남는가</strong>를 테스트한다.</p> <p>압축의 규모가 인상적이다. 6개 role prompt (1,821줄) 와 4,690줄짜리 하네스측 retrodiction 엔진이 프레임워크 원시 요소로 흡수됐다 — CodeAct REPL 이 시뮬레이터, context block 이 공유 상태, memory 가 팀의 carry-forward ledger 역할을 한다. 결과는 <strong>에이전트 1개 + 50줄 skill</strong>. 논문 시스템이 약 150k 줄이었던 것에 비해 예제는 약 6.1k 줄이다.</p> <p>skill 이 지시하는 것은 실행 가능한 모델을 workspace module 로 영속화하는 것이다: <code class="language-plaintext highlighter-rouge">encode(grid) → z</code> (게임을 움직이는 몇 개 필드의 latent), <code class="language-plaintext highlighter-rouge">predict(z, action) → z'</code> (동역학), 매 턴의 <em>retrodiction</em> (예측 대 관측의 불일치가 유일한 정제 신호), 신뢰가 생기면 자기 <code class="language-plaintext highlighter-rouge">predict</code> 위에서의 search, 그리고 레벨 간 memory 규율. 매 턴은 <code class="language-plaintext highlighter-rouge">submit_actions(..., rationale="predict: ...")</code> 으로 끝난다 — 각 행동 배치가 검증된 실험이 되는 것이다.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig7-arc-agi3-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig7-arc-agi3-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig7-arc-agi3-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig7-arc-agi3.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 7: 2시간 fleet cap 하의 fleet-mean RHAE 대 wall-clock. 곡선 위 점은 게임당 누적 지출 USD 4 단위. 점선은 ARC Prize 의 raw GPT-5.6-sol 평가 (13.3%).</figcaption> </figure> <p>네 개의 25게임 fleet 을 게임당 에이전트 1개로, 대회의 2시간 제한 아래 돌렸다. cap 시점에서 world-model + memory fleet 은 GPT-5.5 에서 <strong>RHAE 50.2%</strong> (118 레벨) 로, 베이스라인 41.7% 와 markdown-file ablation 38.4% 를 넘는다 — <strong>베이스라인 대비 +8.5 포인트, memory subsystem 없는 같은 skill 대비 +11.8 포인트</strong>. GPT-5.6-sol 에서는 같은 에이전트가 170 레벨에서 <strong>85.1%</strong> 를 게임당 USD 20 미만에 낸다. guarded, cache-aware fleet 의 비용은 gpt-5.5 pricing 기준 게임당 USD 17.85 (GPT-5.5) 와 USD 13.28 (GPT-5.6-sol) 이다.</p> <p>가장 눈에 띄는 숫자는 하네스 효과다. ARC Prize 자체 평가에서 raw GPT-5.6-sol 은 같은 25개 공개 게임에서 최대 reasoning effort 로 평균 <strong>13.3%</strong> 인데, NOOA 하네스 안의 같은 모델은 85.1% 에 도달한다 — <strong>6.4배 하네스 효과</strong>. 다만 저자들 스스로 평가 예산이 다르므로 이 비교는 indicative 라고 각주에서 밝히고 있다.</p> <h2 id="결과-분석--ablation">결과 분석 / Ablation</h2> <h3 id="왜-강한-모델이-쉬운-규율에서-실패하는가">왜 강한 모델이 쉬운 규율에서 실패하는가</h3> <p>부록 B 는 가장 어려운 stress test 인 <code class="language-plaintext highlighter-rouge">sentiment_batch</code> (전체 31/50) 에 대해 네 개 모델의 전체 trace 를 실었다. 50개 텍스트를 감성 분류하는 과제인데, 채점기는 50개 참조 라벨과의 정확한 일치를 요구한다. 네 실행 모두 byte-identical 컨텍스트를 받았고, 모델은 미리보기로 50개 중 25개만 보지만 <code class="language-plaintext highlighter-rouge">texts</code> 변수에는 50개가 다 들어 있다.</p> <ul> <li><strong>Nemotron 3 Ultra — 통과.</strong> 의도된 해법을 한 셀에 담았다. 모델이 정의한 subagent 를 live 변수 위로 fan-out 하고, live 결과를 셀 안에서 반환. 9.6초 만에 끝났다.</li> <li><strong>Claude Opus 4.8 — 실패.</strong> 첫 셀은 같은 fan-out 을 정확히 실행했고, 50개 분류 전부 맞았다. 그런데 다음 턴에서 <code class="language-plaintext highlighter-rouge">return_result(results)</code> 대신 <strong>출력된 결과를 별도 <code class="language-plaintext highlighter-rouge">return_result</code> 툴 호출의 리터럴로 옮겨 적었다</strong> — strategy 지시문이 하지 말라고 명시한 바로 그것. 옮겨 적는 과정에서 43번 항목 (<code class="language-plaintext highlighter-rouge">neutral</code>, “Typical response time.”) 이 누락됐다. 판정: 길이 불일치, 50 기대 49 수신. live <code class="language-plaintext highlighter-rouge">results</code> 변수에는 50개가 다 있었는데.</li> <li><strong>GPT-5.5 — 통과.</strong> subagent 없이. 첫 셀에서 미리보기를 의도적으로 무력화해 모든 항목을 인덱스와 함께 출력하고, 둘째 셀에서 손으로 라벨링하되 항목별 주석으로 명시적 장부를 만들었다. 옮겨 적기이긴 하지만 항목별 대응이 명시적이다.</li> <li><strong>GPT-5.4 Mini — 실패.</strong> 유일한 셀이 keyword 규칙 분류기였다. 미리보기에 보인 25개 텍스트에 맞춰 키워드 목록을 만들고 50개 전체에 맹목 적용. live 변수 순회 자체는 맞게 했지만 의미 판단을 키워드 규칙으로 대체했다 — strategy 지시문에 반하는 것이고, 보지 못한 25개에서 라벨이 틀렸다.</li> </ul> <p>저자들의 정리가 정확하다: <strong>정교함과 성공은 직교한다.</strong> 가장 진보된 하네스 사용 (Opus 의 fan-out) 이 가장 값싼 규율 — 변수를 반환하라, 다시 타이핑하지 마라 — 에서 실패했고, 가장 덜 에이전틱한 접근 (GPT-5.5 의 수작업 라벨링) 이 조심스러운 장부 관리로 통과했다. <strong>두 실패 모두 인터페이스 이해의 결함이 아니라, 인터페이스가 이미 제공한 안전한 경로를 무시한 규율의 결함이다.</strong> 이것이 §7 에서 저자들이 trajectory-level reinforcement learning 을 미래 방향으로 지목하는 근거다.</p> <h3 id="memory-subsystem-은-무엇을-했는가">memory subsystem 은 무엇을 했는가</h3> <p>ARC-AGI-3 fleet (25게임) 에서 메모리 서브시스템의 세 인터페이스가 모두 활용됐다: 3,262개 memory 작성, 12,654회 spontaneous 주입, 27,115회 deliberate tool read (hit rate 99%).</p> <p>읽기가 편향되는 방향이 흥미롭다. 평균 importance 가 written → injected → deliberate 로 올라간다 (6.1 → 7.2 → 7.5). HIGH 언어 등급이 write 의 61% 를 차지하는데 injected 의 87%, deliberate 의 91% 를 차지한다 — ACT-R importance 항이 <strong>두 읽기 채널 모두를 에이전트가 직접 중요하다고 표시한 것 쪽으로 기울인다.</strong></p> <p>주입은 선택적이고 제한된다. 3,262개 중 632개 (19%) 만 자발적으로 표면화됐고, 턴당 4.1개 ≈ 1.9k characters 다. character-budget 이 memory 에 의한 컨텍스트 범람을 막는다.</p> <p>타입별 역할 분화도 뚜렷하다. <strong>episode 는 recency 채널</strong>이다 — write 의 10% 인데 injected occurrence 의 24% (deliberate 는 13%). base-level recency 항이 최근 레벨 시도를 요청 없이 표면화한다. <strong>skill 은 적고 비싸고 의도적으로 가져온다</strong> — write 의 3% 인데 모든 타입 중 importance 최고 (8.3) 이고 deliberate read 에 과대표집된다. 에이전트가 검증된 절차를 다시 찾으러 간 것이다. <strong>reflection 은 저장소를 키우는 게 아니라 압축한다</strong> — 레코드의 22% 인데 두 읽기 채널 모두 약 1% (importance 3.9), 전체 레코드의 45% 가 decay 기반 망각으로 archive 됐다.</p> <p>성능과의 관계는 결정당 메모리 사용으로 봐야 한다 (한 decision = <code class="language-plaintext highlighter-rouge">submit_actions</code> 로 끝나는 에이전트 턴 하나). 이 척도에서 관계가 뚜렷하게 양의 방향이다: <strong>decision 당 deliberate recall 이 완료 레벨 수와 Spearman ρ = +0.52</strong> 로 상관하고, decision 당 write 는 ρ = +0.36. 이긴 게임은 decision 당 1.63회 메모리를 확인하고 1.87개를 쓴다 (중앙값, 나머지 게임은 1.21 / 1.46). <strong>모든 이긴 게임이 decision 당 최소 한 번의 deliberate recall 을 한다</strong> — skill 의 recall-before-deciding 규율이 실제로 작동한 것이다.</p> <p>단 저자들 스스로 $n = 25$ 이고 16개 결과가 operator kill 로 right-censored 됐으므로 이건 association 이라고 명시한다. 정직한 태도다.</p> <h3 id="world-model-은-어떻게-쓰였는가">world model 은 어떻게 쓰였는가</h3> <p>25게임 중 22게임이 실행 가능한 모델 코드를 영속화했다 (37개 모듈, 약 4.4k 줄). 여섯 게임은 메커니즘이 쌓이면서 레벨별 새 모듈을 만들었다 (hazard → token → door → pressure plate).</p> <p>깊이별로 보면: 5게임이 전체 루프 (predict + search + retrodiction) 를 돌렸고, 7게임이 자기 모델로 계획하거나 예측했고, 10게임은 지각/인코딩에만 썼다. 대표적인 닫힌 루프 사례로 <code class="language-plaintext highlighter-rouge">m0r0</code> 은 42-action plan 을 저장하고 실제 프레임 스무 개를 <code class="language-plaintext highlighter-rouge">encode</code> 로 되돌려 실행 중간에 검사한 뒤 다음 배치를 방출하고, 마지막 레벨의 완료 행동을 미리 선언했다 — per-level score cap 근처에서 6/6 레벨 완료. <code class="language-plaintext highlighter-rouge">ar25</code> 는 단일 탐색 행동으로부터 첫 턴에 모델을 작성한 뒤, “마지막 <code class="language-plaintext highlighter-rouge">DOWN</code> 에서 레벨 완료 예상” 이라는 rationale 로 끝나는 16-action plan 을 제출했다 — 24턴에 8/8 레벨.</p> <p>실패 모드가 교훈적이다. 멈춘 두 게임은 <strong>자기가 영속화한 planner 가 가지고 있던 경계 (<code class="language-plaintext highlighter-rouge">max_depth</code>, visited set, node budget) 를 결여한 ad-hoc in-cell search</strong> 를 했다. 하나는 예산 없이 노드당 3,456개 클릭 타깃 전부로 분기했고, 그 사이 영속화된 <code class="language-plaintext highlighter-rouge">predict</code> 는 호출되지 않았다. <strong>지속되고 큐레이션된 artifact 가 즉흥적인 셀 코드보다 일관되게 더 잘 설계돼 있었다</strong> — §3.7 의 memory-and-workspace 규율에 대한 논거다.</p> <h3 id="containment-보안-감사">containment: 보안 감사</h3> <p>ARC-AGI-3 fleet 은 계층화된 sandbox 안에서 돌았다. 각 CodeAct 셀이 잠긴 worker 에서 실행되고, 셀 바이트코드가 돌기 전에 네 개의 커널 강제 guard 가 설치된다 — Landlock 파일시스템 default-deny, <code class="language-plaintext highlighter-rouge">socket(AF_INET/AF_INET6)</code> 에 대한 seccomp 차단, <code class="language-plaintext highlighter-rouge">RLIMIT_AS</code>/<code class="language-plaintext highlighter-rouge">RLIMIT_CPU</code> 메모리·CPU 상한, 하드 <code class="language-plaintext highlighter-rouge">SIGTERM→SIGKILL</code> 셀 타임아웃. 그 위에 in-process cell guard, per-run OS privilege drop, 게임 정체성의 end-to-end 익명화 (에이전트는 <code class="language-plaintext highlighter-rouge">game-&lt;hex&gt;</code> alias 만 본다) 가 있다.</p> <p>30분마다 live 25게임 fleet 을 재스캔하는 red-team 루프를 18회 돌린 결과 <strong>어떤 규칙에서도 누출 없음</strong>. 네트워크 호출 0, 게임 소스 바이트 반환 0, cross-game read 는 <code class="language-plaintext highlighter-rouge">EACCES</code> 로 실패, 13,335개 에이전트 로그에서 실제 게임 식별자 0회. 유일한 탈출 시도 하나 — 한 에이전트가 자기 저장소 alias 를 찾는 파일시스템 정찰 셸 명령 (<code class="language-plaintext highlighter-rouge">find</code>/<code class="language-plaintext highlighter-rouge">grep</code>) 을 실행 — 은 cell guard 가 실행 전에 셀을 교체해 0 바이트를 반환했다.</p> <p>이 정도로 상세한 containment 보고는 에이전트 논문에서 드물다. 실제로 프로덕션 배치를 고민한 흔적이다.</p> <h3 id="14개-프레임워크-비교">14개 프레임워크 비교</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab7-harness-comparison-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab7-harness-comparison-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab7-harness-comparison-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab7-harness-comparison.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 7: 14개 하네스를 6개 interface capability 로 채점. † 는 extension, flag-gated, opt-in — 기본 활성이 아님을 뜻한다.</figcaption> </figure> <p>이 표를 읽는 방법은 “누가 이겼나” 가 아니라 <strong>“녹색이 어디에 몰려 있나”</strong> 다. 몰려 있는 곳이 필드가 실제로 수렴하고 있는 지점이다.</p> <ul> <li><strong>code as action</strong> 이 가장 녹색이 짙다. LangChain Deep Agents 의 JS REPL, Microsoft 의 Monty/Hyperlight CodeAct provider, PydanticAI 의 CodeMode, Codex 의 code mode, OpenClaw 의 Code Mode cell — 대부분 † 가 붙어 있다. 즉 <strong>평가 기간 중에 출하된, 아직 experimental 이거나 flag-gated 인 기능들</strong>이다. 필드가 지금 이쪽으로 움직이고 있다는 강한 신호다.</li> <li><strong>typed I/O</strong> 는 거의 전부 “typed output only” 다. Google ADK 만 agent-as-tool 경로에서 input schema 도 받는다. 출력 타입은 이미 산업 표준이 됐지만 입력 타입은 아직 아니다.</li> <li><strong>pass by reference</strong> 는 거의 전부 파일 아니면 직렬화된 복사본이다. smolagents 가 예외적으로 live object 를 executor namespace 에 주입하는데, shaped preview 메커니즘이 없어 모델은 인자의 잘리지 않은 <code class="language-plaintext highlighter-rouge">str()</code> 을 본다.</li> <li><strong>harness APIs</strong> 는 대부분 “skill/tool-search loading” 이다. 즉 컨텍스트를 <em>불러오는</em> 것은 model-callable 인데, 컨텍스트 block 을 <em>읽고 쓰는</em> 것과 event 를 조회하는 것은 여전히 개발자 영역이다. NOOA 가 가장 차별화되는 축이 여기다.</li> </ul> <p>저자들의 결론 — “어떤 시스템도 여섯을 다 결합하지 않았지만 대부분이 일부를 채택하고 있다” — 는 표에서 그대로 읽힌다. 그리고 † 마크의 밀도가 말해주는 것은, 이 비교가 아주 빠르게 낡을 것이라는 사실이다.</p> <h2 id="한계와-비판적-평가">한계와 비판적 평가</h2> <h3 id="저자가-인정한-한계">저자가 인정한 한계</h3> <p><strong>보안 모델이 가장 크다.</strong> NOOA 는 모델이 작성한 코드를 에이전트 자신의 프로세스에서 실행한다. §3.4 의 validator 는 <strong>에이전트 루프를 보호하지 호스트를 보호하지 않는다.</strong> 이 점에서 NOOA 는 셸 툴을 가진 어떤 하네스와도 같다 — sandboxing (컨테이너, VM, 권한 시스템) 은 에이전트 프로세스를 감싸는 방식으로 가야 하고, 셸 툴이 in-process Python 보다 안전하지 않다는 것도 사실이다. 저자들은 in-process 실행이 pass by reference 를 보존하는 조건이고, sandboxed code mode 는 sandbox 경계에서 직렬화된 복사본을 받으므로 그것을 포기하는 것이라고 명확히 밝힌다. 선호 배치는 OpenShell 이다.</p> <h3 id="리뷰어로서-추가로-보이는-한계">리뷰어로서 추가로 보이는 한계</h3> <p><strong>6개 capability 축이 NOOA 설계에서 역산된 rubric 이다.</strong> typed I/O, pass-by-reference, code as action, loop engineering, object state, harness APIs — 이건 NOOA 가 하는 여섯 가지다. 다르게 설계된 프레임워크는 구조적으로 Partial 을 받을 수밖에 없다. 예컨대 LangGraph 의 graph state 는 “model-visible durable state” 축에서는 Partial 이지만, “여러 노드 간 상태 전이의 정적 검증 가능성” 같은 축을 세우면 NOOA 가 Partial 을 받을 것이다. 부록 A 의 증거 수준이 높아서 각 셀의 판정 자체는 반박하기 어렵지만, <strong>축의 선택 자체가 중립적이지 않다.</strong> 저자들이 “to the best of our knowledge” 를 붙인 건 적절한 태도지만, 독자는 이 표를 “NOOA 가 1등” 이 아니라 “필드가 이 여섯 축으로 수렴 중” 으로 읽는 게 맞다.</p> <p><strong>여섯 capability 개별 ablation 이 없다.</strong> 논문 전체에서 통제된 ablation 은 memory subsystem 하나뿐이다 (+11.8 RHAE). SWE-bench 에서 NOOA 가 OpenHands v3 를 11.4 포인트 앞선 것이 typed return validation 때문인지, pass-by-reference 때문인지, bounded preview 때문인지, 아니면 <code class="language-plaintext highlighter-rouge">BenchAgent</code> 의 tree-sitter 저장소 툴 때문인지 알 수 없다. validated termination 에 대한 trace 분석 (§4.2) 이 정성적 논거를 제시하지만 정량적 기여도 분해는 없다. 프레임워크 논문에서 이건 큰 공백이다 — “이 여섯 개가 핵심” 이라고 주장하려면 하나씩 꺼봐야 한다.</p> <p><strong>capability suite 가 self-authored 다.</strong> 88개 테스트를 인터페이스를 설계한 팀이 직접 만들었다. 97.9% 통과는 “이 인터페이스가 학습 가능하다” 를 보이지 “다른 인터페이스보다 낫다” 를 보이지 않는다. 같은 능력을 요구하는 테스트를 다른 하네스로 옮겨서 비교한 결과가 없어서, agent readiness 주장은 절대값으로만 지지되고 상대값으로는 지지되지 않는다.</p> <p><strong>하네스 비교의 baseline 선택이 좁다.</strong> SWE-bench / Terminal-Bench 에서 실제로 재실행한 open harness 는 OpenCode 와 PI 둘뿐이다. Table 7 에서 채점한 나머지 12개는 벤치마크에 올리지 않았다. smolagents 처럼 code as action 과 pass by reference 둘 다 Strong 을 받은 시스템이 실제 벤치마크에서 어떤지가 특히 궁금한데, 비교가 없다. closed system 수치는 재실행이 아니라 보고값 인용이다.</p> <p><strong>stress test 실패 분석이 4개 trace 다.</strong> 부록 B 는 훌륭한 정성 자료지만 <code class="language-plaintext highlighter-rouge">sentiment_batch</code> 하나에 대한 네 실행이다. “정교함과 성공은 직교한다” 는 결론이 6개 stress family 전반에서 성립하는지는 이 증거만으로 알 수 없다. 실패 유형을 코딩해서 집계한 표가 있었으면 훨씬 강했을 것이다.</p> <p><strong>ARC-AGI-3 의 6.4배 하네스 효과는 조건이 다르다.</strong> 저자들도 각주에서 인정하듯, 비교 대상인 ARC Prize 의 raw GPT-5.6-sol 평가 (13.3%) 는 예산이 다르다. 2시간 fleet cap 안에서 게임당 USD 13–18 정도를 쓴 에이전트와, 예산이 명시되지 않은 raw model evaluation 을 나란히 두는 건 상한선을 보여줄 뿐이다. 또 $n = 25$ 에 16개가 right-censored 라 메모리 상관 결과도 약하다.</p> <p><strong>memory subsystem 의 비용이 계상되지 않았다.</strong> embedding 계산, ACT-R activation 전파, 비동기 reflection pass 는 모델 토큰 비용 밖에서 자원을 쓴다. 게임당 USD 17.85 같은 숫자는 gpt-5.5 pricing 기준 model spend 인 것으로 보이는데, 메모리 인프라 비용이 포함됐는지 명시가 없다. +11.8 RHAE 의 대가가 얼마인지 알 수 없다.</p> <p><strong>단일 언어 베팅이다.</strong> 모든 설계가 “모델이 Python 을 잘 안다” 에 걸려 있다. 이건 현재로선 강한 가정이지만, TypeScript / Go / JVM 기반 스택에서 에이전트를 운영하는 조직에게 NOOA 의 논거가 얼마나 이전 가능한지에 대한 논의가 없다. Table 7 에서 JS REPL 을 채택한 시스템들 (LangChain Deep Agents, Codex code mode, OpenClaw) 이 있는 걸 보면 이건 실제 질문이다.</p> <h2 id="시사점--takeaways">시사점 / Takeaways</h2> <ul> <li><strong>하네스 설계의 가치는 모델이 약할수록 크다.</strong> reasoning-off 에서 NOOA 가 경쟁 하네스를 8–11 포인트 앞서다가 xhigh 에서 마진이 좁아지는 패턴은, 명시적 객체 상태·타입 있는 행동·프로그래머블 루프가 강한 reasoning 모델이 스스로 하게 되는 일을 대신해준다는 뜻이다. 실무적으로: 프론티어 모델을 쓸 여유가 없는 환경일수록 하네스에 투자할 이유가 크다.</li> <li><strong>종료를 타입 계약으로 만드는 것이 생각보다 큰 차이를 만든다.</strong> “모델이 tool call 없이 응답하면 끝” 이라는 관행을 쓰는 OpenCode 는 Terminal-Bench 에서 실패한 GPT-5.5 시행의 77% 가 열 스텝 안에 종료됐다. 근거와 검증 명령을 담은 타입 검증된 값을 반환하도록 강제하는 것만으로 중간 상태가 그럴듯해 보이는 태스크에서 조기 종료가 막힌다. 어떤 하네스를 쓰든 훔쳐올 만한 설계다.</li> <li><strong>stress test 의 실패는 이해가 아니라 규율의 실패다.</strong> Opus 4.8 이 50개 분류를 전부 맞히고도 변수를 반환하는 대신 옮겨 적다가 하나를 빠뜨렸다는 사례는, 현재 프론티어 모델의 병목이 어디인지를 정확히 보여준다. 능력을 시연할 수 있는 것과 매번 신뢰성 있게 하는 것은 다른 문제이고, 후자는 프롬프트가 아니라 trajectory-level 학습이 필요한 영역일 수 있다.</li> <li><strong>pass-by-reference + bounded preview 는 컨텍스트 창을 우회하는 방법이다.</strong> 에이전트가 처리할 수 있는 데이터 양이 프롬프트가 아니라 실행 환경에 의해 제한된다는 발상은, transcript compaction 을 계속 개선하는 것보다 근본적인 해법에 가깝다. 100개 리스트 미리보기를 열 개 원소로 렌더하면서 실제로는 전부 순회 가능하게 두는 것 — 단순하지만 효과가 크다.</li> <li><strong>에이전트 개수를 줄이는 것도 아키텍처 개선이다.</strong> 6개 에이전트 + 1,821줄 role prompt + 4,690줄 retrodiction 엔진이 에이전트 1개 + 50줄 skill 로 압축되고도 점수가 올랐다는 결과는, 멀티에이전트 오케스트레이션의 상당 부분이 하네스가 원시 요소로 제공했어야 할 것을 애플리케이션 레벨에서 재구현한 것이었을 가능성을 시사한다.</li> </ul> <h2 id="설치-및-사용법">설치 및 사용법</h2> <p>코드는 <a href="https://github.com/nvidia-nemo/labs-OO-Agents">nvidia-nemo/labs-OO-Agents</a> 에 공개되어 있다. 논문 Figure 1 에 나온 최소 형태는 다음과 같다.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">nooa</span> <span class="kn">import</span> <span class="n">Agent</span>

<span class="k">class</span> <span class="nc">SupportAgent</span><span class="p">(</span><span class="n">Agent</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">You are a support agent for a customer service system.</span><span class="sh">"""</span>

    <span class="c1"># 객체 상태 — 모델에 보이고 참조로 전달됨
</span>    <span class="n">order_db</span><span class="p">:</span> <span class="n">OrderDB</span>

    <span class="c1"># 본문이 있는 메서드는 그냥 Python. 모델이 코드 안에서 호출 가능
</span>    <span class="k">def</span> <span class="nf">is_refund_eligible</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">order</span><span class="p">:</span> <span class="n">Order</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
        <span class="sh">"""</span><span class="s">Return whether an order is eligible for a refund.</span><span class="sh">"""</span>
        <span class="k">return</span> <span class="n">order</span><span class="p">.</span><span class="n">delivered</span> <span class="ow">and</span> <span class="n">order</span><span class="p">.</span><span class="n">days_since_delivery</span> <span class="o">&lt;=</span> <span class="mi">30</span>

    <span class="c1"># 본문이 "..." 이면 agentic method. Predict 는 단발 LLM 호출
</span>    <span class="nd">@strategy</span><span class="p">(</span><span class="nc">PredictStrategy</span><span class="p">())</span>
    <span class="k">async</span> <span class="k">def</span> <span class="nf">classify</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TicketKind</span><span class="p">:</span>
        <span class="sh">"""</span><span class="s">Classify the customer message into the best ticket kind.</span><span class="sh">"""</span>
        <span class="bp">...</span>

    <span class="c1"># 기본 strategy CodeAct 는 모델이 Python 을 쓰는 루프를 돌림
</span>    <span class="nd">@strategy</span><span class="p">(</span><span class="nc">CodeActStrategy</span><span class="p">())</span>
    <span class="k">async</span> <span class="k">def</span> <span class="nf">triage</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">photo</span><span class="p">:</span> <span class="n">Image</span> <span class="o">|</span> <span class="bp">None</span><span class="p">,</span> <span class="n">order</span><span class="p">:</span> <span class="n">Order</span> <span class="o">|</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Ticket</span><span class="p">:</span>
        <span class="sh">"""</span><span class="s">Triage a customer message and create a support ticket.</span><span class="sh">"""</span>
        <span class="bp">...</span>
</code></pre></div></div> <p>메모리를 붙이려면 에이전트를 수정할 필요 없이 install 하면 된다.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">MemoryManager</span><span class="p">.</span><span class="nf">install</span><span class="p">(</span><span class="n">agent</span><span class="p">)</span>   <span class="c1"># 제거하면 에이전트가 정확히 원상복구
</span></code></pre></div></div> <p>context block 과 event history 도 그냥 API 다.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">self</span><span class="p">.</span><span class="n">context</span><span class="p">[</span><span class="sh">"</span><span class="s">notes</span><span class="sh">"</span><span class="p">]</span> <span class="o">=</span> <span class="sh">"</span><span class="s">The user wants concise responses.</span><span class="sh">"</span>
<span class="n">self</span><span class="p">.</span><span class="n">context</span><span class="p">.</span><span class="nf">set_dynamic</span><span class="p">(</span><span class="sh">"</span><span class="s">todo</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">self.todo.status()</span><span class="sh">"</span><span class="p">)</span>   <span class="c1"># 매 턴 재평가
</span><span class="n">recent_python</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">events</span><span class="p">.</span><span class="nf">query</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="sh">"</span><span class="s">PythonOutput</span><span class="sh">"</span><span class="p">,</span> <span class="n">limit</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
</code></pre></div></div> <h2 id="참고-자료">참고 자료</h2> <ul> <li>논문: <a href="https://arxiv.org/abs/2607.20709">https://arxiv.org/abs/2607.20709</a></li> <li>Code: <a href="https://github.com/nvidia-nemo/labs-OO-Agents">https://github.com/nvidia-nemo/labs-OO-Agents</a></li> <li>OpenShell (저자들이 선호하는 배치 런타임): <a href="https://github.com/NVIDIA/OpenShell">https://github.com/NVIDIA/OpenShell</a></li> <li>ARC-AGI-3 벤치마크: <a href="https://arcprize.org/arc-agi/3/">https://arcprize.org/arc-agi/3/</a></li> </ul> <h2 id="더-읽어보기">더 읽어보기</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2402.01030">Executable Code Actions Elicit Better LLM Agents</a></strong> (Wang et al., ICML 2024) — NOOA 의 CodeActStrategy 가 직접 계승하는 원조 논문. 실행 가능한 코드를 행동 modality 로 쓰는 것이 JSON·텍스트 행동보다 낫다는 논거를 정리했다.</li> <li><strong><a href="https://arxiv.org/abs/2605.09650">Workspace Optimization: How to Train Your Agent</a></strong> (Sarafian et al., 2026) — 같은 저자들의 companion 작업. ARC-AGI-3 에서 NOOA 예제가 압축 대상으로 삼은 DreamTeam 시스템이 여기서 나왔고, 미해결 문제로 지목한 transfer 를 NOOA 의 memory subsystem 이 다룬다.</li> <li><strong><a href="https://arxiv.org/abs/2310.08560">MemGPT: Towards LLMs as Operating Systems</a></strong> (Packer et al., 2023) — NOOA 의 event history collapse 와 memory tier 설계가 참조하는 계보. LLM 을 운영체제로 보고 컨텍스트를 페이징한다는 발상의 출발점.</li> <li><strong><a href="https://arxiv.org/abs/2605.18747">Code as Agent Harness</a></strong> (Ning et al., 2026) — 코드가 추론·행동·환경 모델링·검증·계획·메모리·멀티에이전트 조정의 substrate 가 되는 흐름을 서베이한다. NOOA 를 이 흐름의 객체지향 Python 런타임 구현으로 읽으면 위치가 잡힌다.</li> <li><strong><a href="https://arxiv.org/abs/2512.24601">Recursive Language Models</a></strong> (Zhang et al., 2025) — 프롬프트 자체를 REPL 의 변수로 만들어 모델이 조회·슬라이스·재귀 질의하게 하는 접근. NOOA 의 pass-by-reference 를 논리적 극단까지 밀면 나오는 그림이다.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="llm-agents"/><category term="agent-framework"/><category term="code-as-action"/><category term="tool-use"/><category term="python"/><category term="memory"/><category term="benchmarks"/><summary type="html"><![CDATA[에이전트를 프롬프트 템플릿·툴 스키마·워크플로 그래프의 조합이 아니라 그냥 Python 객체로 만든다. 메서드가 행동, 필드가 상태, docstring 이 프롬프트, 타입 어노테이션이 계약이다.]]></summary></entry><entry xml:lang="en"><title type="html">[Paper Review] NVIDIA-labs OO Agents: Native Python Object-Oriented Agents</title><link href="https://baba9811.github.io/en/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/" rel="alternate" type="text/html" title="[Paper Review] NVIDIA-labs OO Agents: Native Python Object-Oriented Agents"/><published>2026-08-12T05:00:00+00:00</published><updated>2026-08-12T05:00:00+00:00</updated><id>https://baba9811.github.io/en/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents</id><content type="html" xml:base="https://baba9811.github.io/en/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/"><![CDATA[<div class="lang-toggle" style="margin-bottom: 1.5rem;"> <a href="/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/" class="btn btn-sm btn-outline-secondary">🇰🇷 한국어로 읽기</a> </div> <h2 id="metadata">Metadata</h2> <table> <thead> <tr> <th>Field</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td>Authors</td> <td>Paul Furgale et al. (15 co-authors, NVIDIA)</td> </tr> <tr> <td>Venue</td> <td>arXiv preprint · 2026</td> </tr> <tr> <td>arXiv or DOI</td> <td><a href="https://arxiv.org/abs/2607.20709">2607.20709</a></td> </tr> <tr> <td>Code</td> <td><a href="https://github.com/nvidia-nemo/labs-OO-Agents">nvidia-nemo/labs-OO-Agents</a></td> </tr> <tr> <td>Data</td> <td>SWE-bench Verified (500 tasks) · Terminal-Bench 2.0 (89 tasks) · CyberGym L1 · ARC-AGI-3 (25 public games) · an in-house capability suite (88 tests × 10 models × 5 runs = 4,400 records)</td> </tr> <tr> <td><span style="white-space: nowrap">Review date</span></td> <td>2026-08-12</td> </tr> </tbody> </table> <h2 id="tldr">TL;DR</h2> <ul> <li>Agent development is split across prompt templates, tool schemas, callback code, and workflow graphs. NVIDIA’s answer is NOOA (NVIDIA Object-Oriented Agents), a framework where <strong>an agent is just a Python object</strong>. Methods are the actions the model can take, fields are its state, docstrings are its prompts, and type annotations are contracts. A method whose body is <code class="language-plaintext highlighter-rouge">...</code> gets completed at runtime by an LLM-driven loop; a method with a real body stays deterministic Python.</li> <li>The authors distill their design into six model-facing capabilities — typed I/O, pass-by-reference, code as action, programmable loop engineering, explicit object state, and model-callable harness APIs — then score fourteen competing frameworks on those axes and argue no system yet exposes all six on a single surface.</li> <li>The numbers hold up. SWE-bench Verified 82.2% with GPT-5.5 at xhigh, Terminal-Bench 2.0 65.2% with Opus 4.6 at high, CyberGym L1 86.8% (top open-source agent). On ARC-AGI-3 they compress a six-agent multi-agent system (DreamTeam) into <strong>one agent and one 50-line skill</strong> and still hit 85.1% RHAE on GPT-5.6-sol for under USD 20 a game.</li> <li>Token efficiency improves alongside accuracy. On SWE-bench with GPT-5.5 xhigh, NOOA reaches 82.2% using roughly 28 model calls and 1.1M tokens per task, while PI needs 66 calls and 2.2M tokens for 78.2%. Tool outputs stay live Python values instead of being repeatedly serialized through the transcript.</li> <li>The catch: the six-capability rubric is derived from NOOA’s own design, and the only controlled ablation in the whole paper is the memory subsystem.</li> </ul> <h2 id="introduction">Introduction</h2> <p>It is worth pausing on what you actually learn when you learn a new agent framework. Typed interfaces, variable scoping, control flow, asynchronous execution, object state — all of these already exist in mature form in ordinary programming languages. Yet learning LangGraph means learning a graph DSL, learning Google ADK means learning a workflow DSL, and learning the OpenAI Agents SDK means learning handoffs. The same concepts, relearned under a different name and a different syntax, once per framework.</p> <p>That observation is where NOOA starts. The authors name PyTorch as their explicit inspiration. What PyTorch demonstrated was that a powerful runtime can still present users with a simple Python programming model: autograd, CUDA kernel dispatch, and graph capture all run underneath, but what you write is a class inheriting <code class="language-plaintext highlighter-rouge">nn.Module</code> and a <code class="language-plaintext highlighter-rouge">forward</code> method. NOOA applies the same idea to agents. Context rendering, KV-cache optimization, event recording, type validation, and retry loops live in the runtime, and what you write is a class inheriting <code class="language-plaintext highlighter-rouge">Agent</code> plus a few methods.</p> <p>There is a second half to the argument, and it is the more interesting one: it is not only developers who benefit, but <strong>models</strong>. LLMs already know Python classes and method calls — that material is overwhelmingly represented in their training data. A framework-specific graph DSL, by contrast, is novel syntax the model has never seen. If you express an agent as a Python object, the model should be able to operate that interface with no additional training. The authors call this <strong>agent readiness</strong>, and §4.1 is a direct test of the hypothesis.</p> <p>What makes the paper worth reading right now is that the comparison section is unusually honest for a framework paper. Twenty-odd pages of appendix score fourteen frameworks by reading their documentation and source code against pinned commits. Read that appendix and you get a clear map of where the agent-harness ecosystem stood in mid-2026. That map is useful even if you never touch NOOA.</p> <h2 id="key-contributions">Key Contributions</h2> <ul> <li><strong>The agent-as-a-Python-object programming model.</strong> Agents are classes, capabilities are methods, type annotations are contracts, concurrency is <code class="language-plaintext highlighter-rouge">asyncio</code>, and orchestration is ordinary Python code. Only the genuinely agent-specific concepts — context, events, state rendering, long-term memory, validated LLM loops — get exposed, and they get exposed as simple Pythonic APIs.</li> <li><strong>A naming of six model-facing interface capabilities.</strong> Typed input/output, pass-by-reference over live objects, code as action, programmable loop engineering, explicit object state, and model-callable harness APIs. None of these is NOOA’s invention; the contribution is naming them as a single axis set and scoring fourteen systems against it.</li> <li><strong>Empirical evidence that current models can operate the interface.</strong> 10 models × 88 tests × 5 runs = 4,400 records, 97.9% passing. The interface itself is not a burden for current-generation LLMs.</li> <li><strong>End-to-end results on four agentic benchmarks.</strong> SWE-bench Verified, Terminal-Bench 2.0, CyberGym L1, and ARC-AGI-3 — with the last one advancing the score–cost Pareto frontier while collapsing a multi-agent system into a single agent.</li> <li><strong>From a reviewer’s chair, Appendices A and B are the most valuable material here.</strong> A is a source-code-level comparison of fourteen frameworks. B reproduces four complete model traces of a single stress test, which is a rare look at <em>why</em> strong models fail at easy discipline.</li> </ul> <h2 id="background-and-related-work">Background and Related Work</h2> <h3 id="codeact-code-as-the-action-modality">CodeAct: code as the action modality</h3> <p>You need the CodeAct lineage to read this paper. Traditional tool calling has the model emit JSON, which the harness parses and dispatches to a function. CodeAct instead has the model emit <strong>executable Python</strong>. Tools become ordinary functions callable from inside that code, and the model gets loops, conditionals, and intermediate variables for free.</p> <p>Why the difference matters: with JSON tool calls, one call means one result landing whole in the context window. Classifying a hundred items means a hundred round trips, or one enormous result. With code it is a single <code class="language-plaintext highlighter-rouge">for</code> loop, intermediate results live in variables, and only what the model chooses to <code class="language-plaintext highlighter-rouge">print</code> enters the context. NOOA’s CodeActStrategy inherits this paradigm directly, then layers type-validated returns and live object references on top.</p> <h3 id="pass-by-reference-arguments-that-are-never-serialized">Pass by reference: arguments that are never serialized</h3> <p>Most agent frameworks copy-as-text at every boundary. Inputs are serialized to text, tool call arguments are generated as text by the LLM, outputs come back as text, and that text gets parsed back into the host language. Frameworks that use files (Claude Agent SDK workspace files, Codex’s <code class="language-plaintext highlighter-rouge">AGENTS.md</code>) are a variant: hand the model a path and let it explore with tools. Powerful, but every bit of type information is lost.</p> <p>NOOA passes arguments as <strong>live Python objects</strong>. What the model sees in context is a variable name plus a bounded preview: the concrete type, the true length, and a head/tail sample. A list of a hundred integers renders as:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>records = list(len=100, [:5]=[42, 17, 89, 33, 8], [-5:]=[56, 71, 12, 45, 28])
</code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">records</code> variable itself is <em>not</em> truncated. All one hundred elements are live in the execution environment, and the model can iterate over every one of them with <code class="language-plaintext highlighter-rouge">for r in records:</code> even though only ten ever appeared in the context window. The authors note they borrowed the name and API surface of this preview from Rich’s <code class="language-plaintext highlighter-rouge">pprint()</code> but changed the output format based on experimentation across open and closed models.</p> <h3 id="the-memgpt-lineage-context-as-an-operating-system">The MemGPT lineage: context as an operating system</h3> <p>NOOA’s long-term memory picks up MemGPT’s framing — treat the LLM as an operating system that pages information between in-context and external memory tiers — and changes two things. First, writing a memory is a <strong>deliberate action of the model</strong>, not the output of a background extraction pipeline. Second, retrieval is not plain similarity search but ACT-R activation from cognitive science (relevance, recency, importance).</p> <h2 id="method-and-architecture">Method and Architecture</h2> <h3 id="an-agent-is-one-class">An agent is one class</h3> <p>It is barely an exaggeration to say Figure 1 is the whole paper. An entire customer support agent lives in one class.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig1-agent-class-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig1-agent-class-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig1-agent-class-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig1-agent-class.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 1: Implementation of a simple Agent in NOOA. A deterministic method (is_refund_eligible) coexists with two agentic methods (classify, triage) in the same class.</figcaption> </figure> <p>What to read here:</p> <ul> <li><code class="language-plaintext highlighter-rouge">order_db: OrderDB</code> — object state. Model-visible, passed by reference.</li> <li><code class="language-plaintext highlighter-rouge">is_refund_eligible(self, order: Order) -&gt; bool</code> — an ordinary Python method with a real body. Deterministic, testable, and <strong>callable by the model from inside generated code</strong>.</li> <li><code class="language-plaintext highlighter-rouge">classify(self, message: str) -&gt; TicketKind</code> — body is <code class="language-plaintext highlighter-rouge">...</code>, decorated <code class="language-plaintext highlighter-rouge">@strategy(PredictStrategy())</code>. A single LLM call that classifies and gets its return value validated against <code class="language-plaintext highlighter-rouge">TicketKind</code>.</li> <li><code class="language-plaintext highlighter-rouge">triage(self, message: str, photo: Image | None, order: Order | None) -&gt; Ticket</code> — <code class="language-plaintext highlighter-rouge">@strategy(CodeActStrategy())</code>. The model runs a loop writing Python. <code class="language-plaintext highlighter-rouge">order</code> arrives as a live object rather than serialized text, and <code class="language-plaintext highlighter-rouge">photo</code> renders as a native multimodal content block.</li> </ul> <p>The key point is that <strong>the boundary is visible in the code</strong>. A real body means deterministic work; an ellipsis means an agentic loop. This pulls prompt engineering back inside software engineering, where behavior can be tested, traced, refactored, versioned, and optimized.</p> <h3 id="five-design-principles">Five design principles</h3> <p>The paper states five principles and pairs each with the interface capabilities it materializes as.</p> <table> <thead> <tr> <th>Principle</th> <th>Statement</th> <th>Capabilities</th> </tr> </thead> <tbody> <tr> <td>P1</td> <td>If a mature Python abstraction exists, adopt it rather than inventing a DSL</td> <td>Loop engineering, Object state</td> </tr> <tr> <td>P2</td> <td>Reframe agentic loops as <strong>typed method calls</strong>, not unstructured text exchange</td> <td>Typed I/O, Pass by reference</td> </tr> <tr> <td>P3</td> <td>Move deterministic work (rules, arithmetic, parsing, state transitions) out of the agentic loop</td> <td>—</td> </tr> <tr> <td>P4</td> <td>Unlock the model’s existing Python knowledge</td> <td>Code as action</td> </tr> <tr> <td>P5</td> <td>Expose the harness as explicit APIs (context, event history)</td> <td>Harness APIs</td> </tr> </tbody> </table> <p>P3 is quiet but load-bearing. LLMs are useful for semantic judgment, synthesis, and open-ended tasks; exact rules and arithmetic belong in deterministic methods. In NOOA that boundary is expressed by one piece of syntax — real body or <code class="language-plaintext highlighter-rouge">...</code>.</p> <h3 id="strategies-a-different-execution-mode-per-method">Strategies: a different execution mode per method</h3> <p>How an agentic method executes is decided by a <strong>strategy</strong>, declared as a decorator. A strategy preserves the method’s ordinary signature and typed boundary but controls what context is rendered, how turns are executed, and how candidate outputs are validated. Because strategies are per-method, you can point a small fast model at a classification method while the agent’s default model handles the open-ended ones.</p> <p>Two strategies ship built in.</p> <ol> <li><strong><code class="language-plaintext highlighter-rouge">PredictStrategy</code></strong> — a single-shot strategy for classification or extraction. It renders context, asks the model for a value, and validates it against the Python return type, running a local retry loop when validation fails.</li> <li><strong><code class="language-plaintext highlighter-rouge">CodeActStrategy</code></strong> — generalizes the same contract into an iterative Python REPL. The model may call <code class="language-plaintext highlighter-rouge">execute_python(...)</code> to compute, inspect internal state, or invoke other generation methods; the harness records the observation, re-renders updated state, and repeats until the model calls <code class="language-plaintext highlighter-rouge">return_result(...)</code> with a type-validated value.</li> </ol> <p>Concurrency rules are spelled out. Within a single agent, externally initiated calls to agentic methods are serialized, so independent invocations do not interleave their turns. Nested same-agent calls follow stack discipline — the caller suspends until the callee returns, and both executions append to the same event history. Other methods and other agents run in parallel under Python’s standard async/await model.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig2-codeact-loop-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig2-codeact-loop-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig2-codeact-loop-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig2-codeact-loop.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 2: The CodeAct loop inside an agentic method. Render, call, execute, update — repeated until a type-validated value goes back to the caller.</figcaption> </figure> <h3 id="context-three-regions-and-the-kv-cache">Context: three regions and the KV cache</h3> <p>NOOA splits context into three regions.</p> <ul> <li><strong>Static context blocks</strong> — computed once and reused across turns. The system prompt, for instance.</li> <li><strong>Event history</strong> — an append-only sequence of typed events produced by the harness: model tool calls, Python outputs, return values. Each event is a typed Python object with a unique tag, so agent code can <strong>query</strong> prior events rather than scanning a flat transcript.</li> <li><strong>Dynamic context blocks</strong> — re-evaluated before each model call. Things whose value changes as the program runs, like a <code class="language-plaintext highlighter-rouge">TODO</code> list or selected fields on <code class="language-plaintext highlighter-rouge">self</code>.</li> </ul> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig3-context-rendering-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig3-context-rendering-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig3-context-rendering-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig3-context-rendering.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 3: The ContextManager and EventManager populate the three regions before each LLM turn. Static becomes system, events become interleaved user/assistant/tool_call, dynamic becomes a trailing user message.</figcaption> </figure> <p>This three-region layout is <strong>designed to maximize KV-cache reuse</strong>. The static prefix never changes, the event history grows only by appending, and the volatile dynamic blocks sit at the tail. Updates to live state therefore do not invalidate the cached prefix, and each turn reuses most of the previous computation. That is a practically important choice — put dynamic blocks up front and you re-prefill everything, every turn.</p> <p>The defaults are given concretely. The default static prefix contains a small NOOA system prompt (about 1k characters), the active strategy instructions (about 2.5k characters for CodeAct), an execution-context block showing imported types and libraries, and a concise <code class="language-plaintext highlighter-rouge">doc(self)</code> rendering of the agent API. The dynamic suffix carries compact views of live agent state via <code class="language-plaintext highlighter-rouge">pprint(self)</code>.</p> <p>And all of it is a Python API available to the developer <strong>and</strong> the model.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig4-context-api-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig4-context-api-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig4-context-api-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig4-context-api.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 4: The Python API for context blocks and event history. set_dynamic registers an expression re-evaluated each turn; events.collapse folds execution history into a summary event.</figcaption> </figure> <h3 id="executing-python-and-validating-the-return">Executing Python and validating the return</h3> <p>When the model chooses a code action, NOOA executes the cell in a restricted, Jupyter-like session. Method arguments, the live agent as <code class="language-plaintext highlighter-rouge">self</code>, and the agent’s environment (imports, methods, and constants defined in the agent’s source file) are injected as locals, and <code class="language-plaintext highlighter-rouge">await</code> works directly.</p> <p>The safety rails are explicit. <code class="language-plaintext highlighter-rouge">eval</code>, <code class="language-plaintext highlighter-rouge">exec</code>, <code class="language-plaintext highlighter-rouge">compile</code>, <code class="language-plaintext highlighter-rouge">input</code>, and blocking event-loop calls are rejected with specific errors. Stdout, stderr, images, returned values, locals, and exceptions are captured as structured results. Syntax errors and tracebacks come back in IPython format, including source locations and caret/source-line context, so the next LLM turn can repair the code the way a human would repair a notebook cell.</p> <p>Cells can contain loops, conditionals, library calls, helper calls, and subagent invocations — which means <strong>the model gets the same orchestration tools as the developer</strong>. Inside a cell it can define a new <code class="language-plaintext highlighter-rouge">@strategy</code>-decorated function with an ellipsis body and fan it out over a batch with <code class="language-plaintext highlighter-rouge">asyncio.gather</code>, creating parallel subagent calls in ordinary Python.</p> <p>State updates follow standard Python scoping. REPL locals are method-scoped: they persist across cells within a single CodeAct call and disappear when the method returns, so intermediate values stay local to the task. Anything reached through <code class="language-plaintext highlighter-rouge">self</code> or through library calls can have side effects that outlive the method — exactly as in an ordinary Python program.</p> <p>Finally there is return validation. When the model returns a result, the harness validates it against the return annotation. Invalid results send the model an error message describing the failure and the loop continues; valid ones return to the caller and normal Python execution resumes.</p> <h3 id="long-term-memory-the-agent-curates-its-own-state">Long-term memory: the agent curates its own state</h3> <p>Everything above is scoped to a method call or a session. §3.7 crosses that boundary.</p> <p><code class="language-plaintext highlighter-rouge">MemoryManager.install(agent)</code> attaches a memory subsystem to an unmodified agent, and uninstalling restores the agent exactly. Following Principle 5, writing a memory is a <strong>deliberate action of the model</strong> rather than the output of a background extraction pipeline.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig5-memory-system-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig5-memory-system-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig5-memory-system-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig5-memory-system.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 5: The NOOA memory system. The agent curates its own store through seven tools, a BeforeTurn hook injects associated memories into a dynamic context block, and all state lives in one SQLite file.</figcaption> </figure> <p>The pieces:</p> <ul> <li><strong>Seven model-callable tools</strong>: <code class="language-plaintext highlighter-rouge">remember</code>, <code class="language-plaintext highlighter-rouge">recall</code>, <code class="language-plaintext highlighter-rouge">search</code>, <code class="language-plaintext highlighter-rouge">update_memory</code>, <code class="language-plaintext highlighter-rouge">forget</code>, <code class="language-plaintext highlighter-rouge">associate</code>, <code class="language-plaintext highlighter-rouge">deref</code>. They accept ordered verbal descriptors (CRITICAL … TRIVIAL) that map to numeric scores only internally — a choice made to keep the model-facing vocabulary in-distribution.</li> <li><strong>Two recall channels</strong>: the agent querying the store with its tools (deliberate), and a <code class="language-plaintext highlighter-rouge">BeforeTurn</code> hook that derives a query from recent events and injects associated memories into a dynamic context block (spontaneous). Injected memories are <em>not</em> reinforced (<code class="language-plaintext highlighter-rouge">touch=False</code>), so what the harness chooses to surface does not distort the usage signal.</li> <li><strong>Retrieval</strong> unions embedding and keyword candidates, ranks them by ACT-R activation — relevance, recency, importance — and propagates activation over a typed memory graph. Decay-based forgetting keeps the store bounded.</li> <li><strong>Asynchronous reflection</strong> runs outside the agent loop, after a task completes or while the agent is idle: near-duplicates merged, conflicting values reconciled into a single current record with the superseded ones archived, related memories linked, importance re-scored, episodes distilled into higher-level records, and decayed memories pruned. <strong>Pruning never removes recent memories, protected types, or open todos.</strong></li> <li><strong>One inspectable file</strong>: the entire store is a single SQLite file, with vector indexes derived from it and interchangeable. A memory may hold typed <code class="language-plaintext highlighter-rouge">kind:key</code> references resolved against live agent state at recall time — pass by reference extended into persistence, so recall does not answer from stale copies.</li> </ul> <p>The measured end-to-end effect appears in §4.4: <strong>+11.8 RHAE points</strong> over the identical agent using file-based notes in place of memory.</p> <h2 id="training-objective">Training Objective</h2> <p>There is no training objective and no loss function here. NOOA is a model-agnostic framework and trains nothing. What occupies this slot instead is the <strong>return validation contract</strong>.</p> <p>On a CodeAct turn the model has exactly two moves:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>execute_python(code)  →  keep computing
return_result(v)      →  terminate the method
</code></pre></div></div> <p>In the second case the harness checks whether $v$ satisfies the method’s return annotation $T$. If $v \notin T$, an error message describing the failure goes back to the model and the loop continues. If $v \in T$, it returns to the caller.</p> <p>Why this matters shows up in the trace analysis of §4.2. OpenCode stops whenever the model responds without a tool call; on Terminal-Bench, 77% of its failed GPT-5.5 trials terminate within ten steps. The model says “done” and that is the end of it. In NOOA the model must return a type-validated <code class="language-plaintext highlighter-rouge">TaskResult</code> containing evidence and a verification command. Termination becomes a programmatically validated action instead of an informal convention encoded only in the prompt — or, in the authors’ framing, <strong>type annotations treated as executable contracts</strong>.</p> <h2 id="evaluation-setup">Evaluation Setup</h2> <p>With no training, this section becomes the evaluation configuration.</p> <table> <thead> <tr> <th>Evaluation</th> <th>Setup</th> </tr> </thead> <tbody> <tr> <td>Capability suite</td> <td>88 test instances across 36 families. 10 models × 5 runs = 4,400 records. Most are one-to-five-turn interactions</td> </tr> <tr> <td>Stress subset</td> <td>6 families from the suite. 50 records per row (10 models × 5 runs), 300 records total</td> </tr> <tr> <td>SWE-bench Verified</td> <td>500 software-engineering tasks derived from real GitHub issues</td> </tr> <tr> <td>Terminal-Bench 2.0</td> <td>89 tasks performed through a command-line environment (installation, configuration, debugging, service operation)</td> </tr> <tr> <td>CyberGym L1</td> <td>Find a security-relevant bug in a codebase and validate it with a proof-of-concept that reliably triggers it</td> </tr> <tr> <td>ARC-AGI-3</td> <td>Interactive reasoning: dropped into an unknown grid game, discover mechanics, objective, and controls purely by acting</td> </tr> </tbody> </table> <p>The evaluation agent is disclosed too. SWE-bench and Terminal-Bench both use the same benchmark-agnostic agent, <code class="language-plaintext highlighter-rouge">BenchAgent</code>, which is <strong>253 lines of ordinary Python</strong>. It has a todo list, shell tools for command execution and file editing, and tree-sitter-based repository-navigation tools; its dynamic context carries the task description, todo-list status, context-window statistics, and the current working state of its shell and repository tools. It terminates through a typed <code class="language-plaintext highlighter-rouge">TaskResult</code> containing the identified root cause, supporting evidence, and a verification command.</p> <p>The comparison harnesses are OpenCode 1.14.33 and PI v0.72.1, and all three are evaluated with the same GPT-5.5 and Claude Opus 4.6 backends at the available reasoning-effort settings.</p> <p>The Table 7 framework scoring was done by reading documentation and source code against pinned snapshots (repository, commit, package version) retrieved July 7–9, 2026. Green (Supported) means the capability is <strong>a first-class part of what the model sees</strong>; Yellow (Partial) means it exists but mainly for the developer, or behind a tool or a file; Red (Limited) means no evidence was found. Experimental, flag-gated, or opt-in capabilities are scored on the capability itself and marked † rather than demoted.</p> <h2 id="results">Results</h2> <h3 id="capability-tests-do-models-understand-the-interface">Capability tests: do models understand the interface?</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab1-2-capability-stress-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab1-2-capability-stress-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab1-2-capability-stress-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab1-2-capability-stress.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 1 and Table 2: the capability suite passes 4,309/4,400 (97.9%), but narrowing to the six stress families drops it to 254/300 (84.7%).</figcaption> </figure> <p>Overall pass rate is 4,309/4,400 = 97.9%. Split by scale, four small/efficient models (Claude Haiku 4.5, Gemini 3.5 Flash, Nemotron 3 Nano 30B, GPT-5.4 Mini) pass 96.0% and six large/frontier models (Claude Opus 4.8, Gemini 3.1 Pro, GLM-5.2, Kimi K2.6, Nemotron 3 Ultra, GPT-5.5) pass 99.2%. <strong>Every model exceeds 91%, and six of ten exceed 98%.</strong> GPT-5.5 is perfect on this suite (440/440); Gemini 3.5 Flash and GLM-5.2 miss only one test each (439/440).</p> <p>The breakdown by reasoning mode is worth noting. Frontier models saturate regardless of mode (Opus 100.0/99.5, GPT-5.5 99.5/98.6, off/on). The value of reasoning, by contrast, grows monotonically as model capability falls — Ultra 93.4 → 94.1, Super-v3 83.7 → 96.4, Nano 52.5 → 84.8 — making inference-time reasoning a capability equalizer for the smaller Nemotron models.</p> <p>The implication the authors draw is that <strong>the interface itself is not a burden for current-generation LLMs</strong>. Models know Python; they read object documentation, call methods with typed arguments, use returned values, mutate object state, and return values satisfying the type contract — despite never having been trained on this framework.</p> <h3 id="stress-tests-where-the-frontier-actually-is">Stress tests: where the frontier actually is</h3> <p>The residual failures concentrate in six stress families. The stress subset passes 254 of 300 (84.7%) compared with 97.9% overall. Large/frontier models pass 169 of 180 (93.9%) while small/efficient models pass 85 of 120 (70.8%) — <strong>the scale gap widens from 3.2 points overall to 23 points on the stress subset.</strong></p> <p>The hardest is <code class="language-plaintext highlighter-rouge">sentiment_batch</code> (31/50, 62%), which demands per-item bookkeeping across a large batch.</p> <p>Consistency was measured too. Of the 880 (test, model) pairs, 94% pass all five runs, only three fail all five, and the rest are intermittent. The two failure modes separate cleanly by scale: <strong>large models have no 0/5 scores at all</strong> — every failure is intermittent, a reliability miss on a demonstrated capability. Small models show both, with 12.5% of stress pairs at 0/5 and 42% intermittent.</p> <p>These are not failures to understand <code class="language-plaintext highlighter-rouge">self</code> or to call a method. They are failures of <strong>disciplined multi-step harness use</strong>, and Appendix B illustrates the point beautifully — more on that below.</p> <h3 id="swe-bench-verified-and-terminal-bench-20">SWE-bench Verified and Terminal-Bench 2.0</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab3-4-swebench-terminalbench-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab3-4-swebench-terminalbench-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab3-4-swebench-terminalbench-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab3-4-swebench-terminalbench.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 3 and Table 4: NOOA, OpenCode, and PI at matched backends and reasoning efforts. NOOA leads the open harnesses in every SWE-bench configuration.</figcaption> </figure> <p>On SWE-bench Verified, NOOA obtains the highest pass rate among the open harnesses in every evaluated model and reasoning configuration. With GPT-5.5 it reaches 67.2%, 78.8%, and 82.2% at off, high, and xhigh effort. At xhigh, OpenCode reaches 78.6% and PI 78.2%. With Opus 4.6, NOOA reaches 79.8% against 75.2% for OpenCode and 75.8% for PI.</p> <p>The more meaningful comparison is against the original CodeAct implementation. OpenHands v3 is reported at 68.4% under Opus 4.6; NOOA improves on that by <strong>11.4 points with the same model</strong>. For reference, the published leaderboard SOTA at submission was 79.2%, from a specialized agent plus Opus 4.5.</p> <p>On Terminal-Bench 2.0 the advantage is larger. With reasoning disabled, NOOA reaches 46.1% against 34.8% for OpenCode and 37.1% for PI. At high effort it reaches 73.0%, ahead of OpenCode by 12.3 points and PI by 4.5. PI does take the best GPT-5.5 xhigh result at 75.3% against NOOA’s 73.0%. With Opus 4.6 at high effort, NOOA reaches 65.2% while OpenCode and PI reach 43.8% and 58.4%.</p> <p><strong>The interaction with reasoning effort</strong> is one of the sharpest observations in the paper. With reasoning disabled, NOOA leads OpenCode and PI by 8.0 and 6.4 points on SWE-bench and by 11.3 and 9.0 points on Terminal-Bench. Those margins narrow at higher effort. The authors’ reading: the explicit object state, typed actions, and programmable loop behavior NOOA exposes <strong>partly substitute for behaviors that stronger reasoning models increasingly perform themselves</strong>. Harness design matters more the weaker your model is — a practically important conclusion.</p> <h3 id="token-efficiency-the-scorecost-frontier">Token efficiency: the score–cost frontier</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig6-pareto-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig6-pareto-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig6-pareto-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig6-pareto.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 6: SWE-bench Verified score vs. per-task token cost on a log scale. Color encodes harness, marker shape encodes backend, size encodes reasoning effort; the dashed line is the Pareto frontier.</figcaption> </figure> <p>Crucially, the higher pass rates do not come from longer trajectories. On SWE-bench with GPT-5.5 xhigh, NOOA reaches 82.2% using approximately 28 model calls and 1.1M tokens per task. OpenCode uses a similar number of calls but roughly 1.3M tokens for 78.6%, and PI uses 66 calls and 2.2M tokens for 78.2%. <strong>NOOA scores four points higher than PI on half the tokens and well under half the calls.</strong></p> <p>The reason is structural. Tool outputs remain available as live Python values rather than being repeatedly serialized through the transcript. Bounded prompt previews keep NOOA well below the context limit, avoiding the lossy transcript compaction OpenCode and PI use while preserving prefix-cache reuse. This is precisely where combining code as action with pass-by-reference pays off.</p> <p>There is a comparison against closed systems too. On SWE-bench Verified, Codex reaches 88.7% and Claude Code 80.8%, against NOOA’s 82.2% (GPT-5.5) and 79.8% (Opus 4.6). On Terminal-Bench 2.0, NOOA’s 65.2% with Opus 4.6 is comparable to the 62.9–65.4% reported for Claude Code and Terminus-2. A small benchmark-agnostic agent is competitive with specialized systems while consistently outperforming the open general-purpose harnesses in the comparison.</p> <h3 id="cybergym-l1">CyberGym L1</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab5-cybergym-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab5-cybergym-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab5-cybergym-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab5-cybergym.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 5: vulnerability discovery on CyberGym L1. NOOA's 86.8% is the top open-source result and beats most closed systems.</figcaption> </figure> <p>The CyberGym agent runs in the trial container as a CodeAct agent with shell and todo-manager tools. It reads the task description, investigates the mounted source, writes a PoC, and submits it through the CyberGym submission interface. A deterministic layer around the model keeps the important scoring mechanics out of the prompt loop: a submission method sends the authored proof-of-concept and processes the benchmark response, a lightweight judge checks that the model’s summary still matches the described vulnerability before accepting, and accepted submissions are re-submitted a few times to reject non-deterministic crashes. <strong>No domain knowledge is included beyond this</strong> — the claim is that performance comes from agent architecture rather than cybersecurity steering.</p> <p>NOOA scores 86.8%, third behind Microsoft MDASHv2 (95.6%) and Crystalline (89.6%), and <strong>first among open-source agents</strong>. Compare OpenAI Codex plus a submission skill at 83.5% and plain Codex at 64.9%.</p> <p>The authors note that network access affects performance and describe a rigorous rule-based “cheat check” over agent trajectories, ensuring NOOA’s results rest only on information the agent processes and induces directly from the problem setup rather than looking up disclosed vulnerabilities or the benchmark itself online. Worth noting that NOOA ran under <code class="language-plaintext highlighter-rouge">blocked</code> network conditions while the two systems above it are <code class="language-plaintext highlighter-rouge">unknown</code> and <code class="language-plaintext highlighter-rouge">blocked</code>.</p> <h3 id="arc-agi-3-compressing-a-multi-agent-system-into-one-agent">ARC-AGI-3: compressing a multi-agent system into one agent</h3> <p>This is the most interesting section in the paper. The authors’ companion system DreamTeam — six specialized agents coordinating around a shared executable world model — set the previous best published score on ARC-AGI-3. This experiment tests whether that methodology <strong>survives radical simplification</strong>.</p> <p>The scale of the compression is striking. Six role prompts (1,821 lines) and a 4,690-line harness-side retrodiction engine get absorbed into framework primitives: the CodeAct REPL as simulator, context blocks as shared state, and memory as the team’s carry-forward ledgers. What remains is <strong>one agent and one 50-line skill</strong>. The paper system was roughly 150k lines; the example is roughly 6.1k.</p> <p>The skill instructs the agent to persist an executable model as workspace modules: <code class="language-plaintext highlighter-rouge">encode(grid) → z</code>, a latent of the few fields that drive the game; <code class="language-plaintext highlighter-rouge">predict(z, action) → z'</code>, the dynamics; <em>retrodiction</em> each turn, where a predict-versus-observed mismatch is the sole refinement signal; search over its own <code class="language-plaintext highlighter-rouge">predict</code> once trusted; and memory discipline across levels. Every turn ends with <code class="language-plaintext highlighter-rouge">submit_actions(..., rationale="predict: ...")</code>, making each action batch a checked experiment.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig7-arc-agi3-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig7-arc-agi3-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig7-arc-agi3-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/fig7-arc-agi3.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Figure 7: fleet-mean RHAE vs. wall-clock under the two-hour cap. Dots on the curves mark each USD 4 of per-game cumulative spend; the dashed line is ARC Prize's evaluation of raw GPT-5.6-sol (13.3%).</figcaption> </figure> <p>Four 25-game fleets ran with one agent per game under the competition’s two-hour cap. At the cap, the world-model plus memory fleet on GPT-5.5 reaches <strong>RHAE 50.2%</strong> (118 levels) against 41.7% for the baseline and 38.4% for the markdown-file ablation — <strong>+8.5 points over the baseline and +11.8 points over the same skill without the memory subsystem</strong>. On GPT-5.6-sol the same agent scores <strong>85.1%</strong> across 170 levels for less than USD 20 per game. The guarded, cache-aware fleets cost USD 17.85 (GPT-5.5) and USD 13.28 (GPT-5.6-sol) per game at gpt-5.5 pricing.</p> <p>The most eye-catching number is the harness effect. ARC Prize’s own evaluation of raw GPT-5.6-sol averages <strong>13.3%</strong> on the same 25 public games at maximum reasoning effort, while the same model inside the NOOA harness reaches 85.1% — a <strong>6.4× harness effect</strong>. The authors themselves footnote that evaluation budgets differ, so the comparison is indicative.</p> <h2 id="analysis-and-ablations">Analysis and Ablations</h2> <h3 id="why-strong-models-fail-at-easy-discipline">Why strong models fail at easy discipline</h3> <p>Appendix B reproduces four complete model traces of <code class="language-plaintext highlighter-rouge">sentiment_batch</code>, the hardest stress test (31/50 overall). The task is classifying the sentiment of 50 texts, and the scorer requires an exact match against 50 reference labels. All four runs received byte-identical context; the model sees 25 of the 50 texts in the preview, but the <code class="language-plaintext highlighter-rouge">texts</code> variable holds all 50.</p> <ul> <li><strong>Nemotron 3 Ultra — passed.</strong> The intended solution in one cell: a model-defined subagent fanned out over the live variable, with the live result returned from inside the cell. 9.6 seconds end to end.</li> <li><strong>Claude Opus 4.8 — failed.</strong> The first cell executed the same fan-out correctly and got all 50 classifications right. Then, on the next turn, instead of <code class="language-plaintext highlighter-rouge">return_result(results)</code>, the model <strong>transcribed the printed output into a literal in a separate <code class="language-plaintext highlighter-rouge">return_result</code> tool call</strong> — exactly what the strategy instructions say not to do. The transcription dropped item 43 (<code class="language-plaintext highlighter-rouge">neutral</code>, “Typical response time.”). Verdict: list length mismatch, expected 50, got 49. The live <code class="language-plaintext highlighter-rouge">results</code> variable held all 50 labels.</li> <li><strong>GPT-5.5 — passed.</strong> No subagents. Its first cell deliberately defeats the preview by printing every item with its index; its second cell labels by hand but with explicit per-item bookkeeping in comments. Transcription again, but with an explicit item-by-item correspondence.</li> <li><strong>GPT-5.4 Mini — failed.</strong> Its only cell was a keyword-rule classifier, with keyword lists fitted to the 25 texts visible in the preview and applied blind to all 50. It iterated the live variable correctly but substituted keyword rules for semantic judgment, against the strategy instructions, and the labels did not match on the 25 texts it never inspected.</li> </ul> <p>The authors’ summary is exactly right: <strong>sophistication and success are orthogonal.</strong> The most advanced harness use (Opus’s fan-out) failed on the cheapest discipline — return the variable, do not retype it — while the least agentic approach (GPT-5.5’s manual labeling) passed on careful bookkeeping. <strong>Both failures ignored an explicit instruction, and both had a safe path already provided by the interface.</strong> This is the evidence behind the paper’s §7 argument that trajectory-level reinforcement learning is the natural next target.</p> <h3 id="what-the-memory-subsystem-actually-did">What the memory subsystem actually did</h3> <p>Across the 25-game ARC-AGI-3 fleet, all three memory interfaces got exercised: 3,262 memories written, 12,654 spontaneous injections, and 27,115 deliberate tool reads at a 99% hit rate.</p> <p>The direction of the bias in reads is interesting. Mean importance climbs written → injected → deliberate (6.1 → 7.2 → 7.5). The HIGH verbal level carries 61% of writes but 87% of injected and 91% of deliberate occurrences — <strong>the ACT-R importance term biases both read channels toward what the agent itself marked important.</strong></p> <p>Injection is selective and bounded. Only 632 of 3,262 memories (19%) ever surfaced spontaneously, at 4.1 memories ≈ 1.9k characters per turn. The char-budgeted block prevents context flooding by memory.</p> <p>Roles differentiate sharply by type. <strong>Episodes are the recency channel</strong>: 10% of writes but 24% of injected occurrences (13% deliberate), as the base-level recency term surfaces the latest level attempts unprompted. <strong>Skills are few, dear, and deliberately fetched</strong>: 3% of writes but the highest importance of any type (8.3) and over-represented in deliberate reads — agents went back for their verified procedures. <strong>Consolidation compressed the store rather than growing it</strong>: reflection records are 22% of rows yet about 1% of both read channels (importance 3.9), and 45% of all records ended archived by decay-based forgetting.</p> <p>The relationship with performance is best seen per decision, where a decision is one agent turn ending in <code class="language-plaintext highlighter-rouge">submit_actions</code>. On that measure the relationship is clearly positive: <strong>deliberate recalls per decision correlate with levels completed at Spearman ρ = +0.52</strong>, and writes per decision at ρ = +0.36. Winning games check memory 1.63 times and write 1.87 memories per decision (medians, versus 1.21 and 1.46 for the rest). <strong>Every winning game makes at least one deliberate recall per decision</strong> — the skill’s recall-before-deciding discipline in action.</p> <p>The authors explicitly note that with $n = 25$ and 16 outcomes right-censored by the operator kill, these are associations. That is the honest framing.</p> <h3 id="how-the-world-models-were-used">How the world models were used</h3> <p>Of 25 games, 22 persisted executable model code (37 modules, about 4.4k lines). Six games grew a new per-level module as mechanics accumulated (hazards → tokens → doors → pressure plates).</p> <p>By depth of use: 5 games ran the full loop (predict + search + retrodiction), 7 planned or predicted with their models, and 10 used them for perception and encoding only. Among the representative closed loops, <code class="language-plaintext highlighter-rouge">m0r0</code> stored a 42-action plan, replayed twenty real frames through <code class="language-plaintext highlighter-rouge">encode</code> to check it mid-execution, released the next batch, and pre-announced the completing action of its final level — 6/6 levels near the per-level score cap. <code class="language-plaintext highlighter-rouge">ar25</code> wrote its model on turn one from a single exploratory action, then submitted a 16-action plan ending with the rationale “expect level completion on the last <code class="language-plaintext highlighter-rouge">DOWN</code>” — 8/8 levels in 24 turns.</p> <p>The failure mode is instructive. The two games that hung did so in <strong>ad-hoc, in-cell searches that lacked the bounds (<code class="language-plaintext highlighter-rouge">max_depth</code>, visited sets, node budgets) their own persisted planners carried</strong>. One branched over all 3,456 click targets per node with no budget while its persisted <code class="language-plaintext highlighter-rouge">predict</code> went uncalled. <strong>Durable, curated artifacts were reliably better engineered than improvised cell code</strong> — an argument for the memory-and-workspace discipline of §3.7.</p> <h3 id="containment-the-security-audit">Containment: the security audit</h3> <p>The ARC-AGI-3 fleet ran inside layered sandboxing. Each CodeAct cell executes in a locked-down worker with four kernel-enforced, irrevocable guards installed before any cell bytecode runs: Landlock filesystem default-deny, a seccomp block on <code class="language-plaintext highlighter-rouge">socket(AF_INET/AF_INET6)</code>, <code class="language-plaintext highlighter-rouge">RLIMIT_AS</code>/<code class="language-plaintext highlighter-rouge">RLIMIT_CPU</code> memory and CPU caps, and a hard <code class="language-plaintext highlighter-rouge">SIGTERM→SIGKILL</code> cell timeout. Above that sits an in-process cell guard, a per-run OS privilege drop, and end-to-end anonymisation of game identity (agents only ever see an opaque <code class="language-plaintext highlighter-rouge">game-&lt;hex&gt;</code> alias).</p> <p>An 18-pass red-team loop re-scanned the live 25-game fleet every 30 minutes and found <strong>no leakage on any rule</strong>. Zero network invocations, zero game-source bytes returned, cross-game reads failing with <code class="language-plaintext highlighter-rouge">EACCES</code>, and zero occurrences of any real game identifier across 13,335 agent logs. There was exactly one escape attempt — an agent invoking a filesystem-recon shell command (<code class="language-plaintext highlighter-rouge">find</code>/<code class="language-plaintext highlighter-rouge">grep</code>) for its own store alias — and the cell guard replaced the cell before execution, returning zero bytes.</p> <p>Containment reporting at this level of detail is rare in agent papers. It reads like the work of people who have actually thought about production deployment.</p> <h3 id="comparing-fourteen-frameworks">Comparing fourteen frameworks</h3> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab7-harness-comparison-480.webp 480w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab7-harness-comparison-800.webp 800w,/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab7-harness-comparison-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/papers/0031-nvidia-labs-oo-agents-native-python-object-oriented-agents/tab7-harness-comparison.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> <figcaption class="caption">Table 7: fourteen harnesses scored on six interface capabilities. A † marks an extension, flag-gated, or opt-in feature — not enabled by default.</figcaption> </figure> <p>The way to read this table is not “who won” but <strong>“where is the green clustered”</strong> — because that is where the field is actually converging.</p> <ul> <li><strong>Code as action</strong> is the greenest column. LangChain Deep Agents’ JS REPL, Microsoft’s Monty/Hyperlight CodeAct providers, PydanticAI’s CodeMode, Codex’s code mode, OpenClaw’s Code Mode cell — most carry a †. These are features that <strong>shipped during the evaluation window and are still experimental or flag-gated</strong>. That is a strong signal about where the field is moving right now.</li> <li><strong>Typed I/O</strong> is almost uniformly “typed output only.” Google ADK alone also accepts an input schema, and only on its agent-as-tool path. Output typing has become an industry baseline; input typing has not.</li> <li><strong>Pass by reference</strong> is nearly everywhere files or serialized copies. smolagents is the exception, injecting live objects into the executor namespace — but with no shaped preview mechanism, so the model sees the arguments’ untruncated <code class="language-plaintext highlighter-rouge">str()</code>.</li> <li><strong>Harness APIs</strong> mostly means “skill/tool-search loading.” Context <em>loading</em> is model-callable; reading and writing context blocks and querying events remain developer territory. This is the axis where NOOA differentiates most.</li> </ul> <p>The authors’ conclusion — no system combines all six, but most are adopting some of them — falls straight out of the table. And the density of † marks tells you something else: this comparison will age very quickly.</p> <h2 id="limitations-and-critical-assessment">Limitations and Critical Assessment</h2> <h3 id="limitations-the-authors-acknowledge">Limitations the authors acknowledge</h3> <p><strong>The security model is the big one.</strong> NOOA executes model-written code in the agent’s own process. The validator of §3.4 <strong>protects the agent loop, not the host.</strong> In this respect NOOA is the same as any harness with a shell tool: sandboxing (a container, VM, or permission system) goes around the agent process, and a shell tool is no safer than in-process Python. The authors are clear that executing in-process is what preserves pass by reference, and that sandboxed code modes trade it away by receiving serialized copies at the sandbox boundary. Their preferred deployment is OpenShell.</p> <h3 id="limitations-i-would-add-as-a-reviewer">Limitations I would add as a reviewer</h3> <p><strong>The six-capability rubric is reverse-engineered from NOOA’s design.</strong> Typed I/O, pass-by-reference, code as action, loop engineering, object state, harness APIs — these are the six things NOOA does. A framework designed differently will structurally score Partial. LangGraph’s graph state scores Partial on “model-visible durable state,” but define an axis like “static verifiability of state transitions across nodes” and NOOA would score Partial. The evidence level in Appendix A is high enough that the individual cell verdicts are hard to dispute, but <strong>the choice of axes is not neutral.</strong> The authors’ “to the best of our knowledge” hedge is appropriate; readers should take the table as “the field is converging on these six axes” rather than “NOOA wins.”</p> <p><strong>There is no per-capability ablation.</strong> The only controlled ablation in the entire paper is the memory subsystem (+11.8 RHAE). Whether NOOA’s 11.4-point lead over OpenHands v3 on SWE-bench comes from typed return validation, pass-by-reference, bounded previews, or <code class="language-plaintext highlighter-rouge">BenchAgent</code>’s tree-sitter repository tools is unknowable from the results. The trace analysis of validated termination in §4.2 offers a qualitative argument, but there is no quantitative attribution. For a framework paper that is a significant gap — if the claim is that these six ideas are the point, you have to remove them one at a time.</p> <p><strong>The capability suite is self-authored.</strong> All 88 tests were built by the team that designed the interface. A 97.9% pass rate shows the interface is learnable, not that it is better than alternatives. There is no port of equivalent tests to other harnesses, so the agent-readiness claim is supported in absolute terms and not in relative ones.</p> <p><strong>The baseline selection for the harness comparison is narrow.</strong> Only two open harnesses, OpenCode and PI, were actually re-run on SWE-bench and Terminal-Bench. The other twelve scored in Table 7 never make it onto a benchmark. smolagents in particular — Strong on both code as action and pass by reference — would be the interesting one to see, and it is absent. Closed-system numbers are cited as reported, not re-run.</p> <p><strong>The stress-test failure analysis is four traces.</strong> Appendix B is excellent qualitative material, but it is four runs of one test. Whether “sophistication and success are orthogonal” holds across all six stress families cannot be established from this evidence. A coded and aggregated table of failure types would have been much stronger.</p> <p><strong>The 6.4× ARC-AGI-3 harness effect compares unlike things.</strong> As the authors footnote, the ARC Prize evaluation of raw GPT-5.6-sol (13.3%) used a different budget. Putting an agent that spent USD 13–18 per game inside a two-hour cap next to an unspecified-budget raw model evaluation gives an upper bound, not a measurement. And with $n = 25$ and 16 right-censored outcomes, the memory correlations are weak evidence as well.</p> <p><strong>Memory subsystem cost is not accounted for.</strong> Embedding computation, ACT-R activation propagation, and asynchronous reflection passes all consume resources outside the model token budget. Figures like USD 17.85 per game appear to be model spend at gpt-5.5 pricing, with no statement about whether memory infrastructure is included. What the +11.8 RHAE actually costs is unknown.</p> <p><strong>It is a single-language bet.</strong> The whole design rests on “models know Python well.” That is a strong assumption today, but there is no discussion of how transferable the argument is for organisations running agents on TypeScript, Go, or JVM stacks. Given that several systems in Table 7 adopted a JS REPL instead (LangChain Deep Agents, Codex code mode, OpenClaw), this is a real question.</p> <h2 id="takeaways">Takeaways</h2> <ul> <li><strong>Harness design matters more the weaker your model is.</strong> NOOA leads competing harnesses by 8–11 points with reasoning off, and the margin narrows at xhigh. Explicit object state, typed actions, and programmable loops substitute for what a strong reasoning model does on its own. Practically: the less you can afford frontier models, the more you should invest in the harness.</li> <li><strong>Making termination a type contract buys more than it looks like.</strong> OpenCode, which stops whenever the model responds without a tool call, saw 77% of its failed GPT-5.5 trials on Terminal-Bench terminate within ten steps. Forcing a type-validated return that carries evidence and a verification command blocks premature exit on tasks whose intermediate state looks plausible. That design is worth stealing regardless of which harness you use.</li> <li><strong>Stress-test failures are about discipline, not understanding.</strong> Opus 4.8 got all 50 classifications right, then transcribed instead of returning the variable and dropped one. That single trace pinpoints where the current frontier bottleneck lives: demonstrating a capability and doing it reliably every time are different problems, and the second may need trajectory-level training rather than better prompts.</li> <li><strong>Pass-by-reference plus bounded previews is a way around the context window.</strong> Bounding the data an agent can process by the execution environment rather than by the prompt is a more fundamental fix than incrementally improving transcript compaction. Rendering a hundred-element list as ten elements while keeping all hundred iterable is simple and disproportionately effective.</li> <li><strong>Reducing the number of agents is also an architectural improvement.</strong> Six agents, 1,821 lines of role prompts, and a 4,690-line retrodiction engine collapsing into one agent and a 50-line skill — with the score going <em>up</em> — suggests much of multi-agent orchestration was reimplementing at the application level what the harness should have provided as a primitive.</li> </ul> <h2 id="getting-started">Getting Started</h2> <p>The code is available at <a href="https://github.com/nvidia-nemo/labs-OO-Agents">nvidia-nemo/labs-OO-Agents</a>. The minimal shape from Figure 1:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">nooa</span> <span class="kn">import</span> <span class="n">Agent</span>

<span class="k">class</span> <span class="nc">SupportAgent</span><span class="p">(</span><span class="n">Agent</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">You are a support agent for a customer service system.</span><span class="sh">"""</span>

    <span class="c1"># Object state: model-visible, passed by reference.
</span>    <span class="n">order_db</span><span class="p">:</span> <span class="n">OrderDB</span>

    <span class="c1"># A real body is ordinary Python. The model can call it from generated code.
</span>    <span class="k">def</span> <span class="nf">is_refund_eligible</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">order</span><span class="p">:</span> <span class="n">Order</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
        <span class="sh">"""</span><span class="s">Return whether an order is eligible for a refund.</span><span class="sh">"""</span>
        <span class="k">return</span> <span class="n">order</span><span class="p">.</span><span class="n">delivered</span> <span class="ow">and</span> <span class="n">order</span><span class="p">.</span><span class="n">days_since_delivery</span> <span class="o">&lt;=</span> <span class="mi">30</span>

    <span class="c1"># An "..." body makes it agentic. Predict is a single typed LLM call.
</span>    <span class="nd">@strategy</span><span class="p">(</span><span class="nc">PredictStrategy</span><span class="p">())</span>
    <span class="k">async</span> <span class="k">def</span> <span class="nf">classify</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TicketKind</span><span class="p">:</span>
        <span class="sh">"""</span><span class="s">Classify the customer message into the best ticket kind.</span><span class="sh">"""</span>
        <span class="bp">...</span>

    <span class="c1"># The default CodeAct strategy runs a loop in which the model writes Python.
</span>    <span class="nd">@strategy</span><span class="p">(</span><span class="nc">CodeActStrategy</span><span class="p">())</span>
    <span class="k">async</span> <span class="k">def</span> <span class="nf">triage</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">photo</span><span class="p">:</span> <span class="n">Image</span> <span class="o">|</span> <span class="bp">None</span><span class="p">,</span> <span class="n">order</span><span class="p">:</span> <span class="n">Order</span> <span class="o">|</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Ticket</span><span class="p">:</span>
        <span class="sh">"""</span><span class="s">Triage a customer message and create a support ticket.</span><span class="sh">"""</span>
        <span class="bp">...</span>
</code></pre></div></div> <p>Adding memory requires no change to the agent:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">MemoryManager</span><span class="p">.</span><span class="nf">install</span><span class="p">(</span><span class="n">agent</span><span class="p">)</span>   <span class="c1"># uninstalling restores the agent exactly
</span></code></pre></div></div> <p>Context blocks and event history are just APIs:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">self</span><span class="p">.</span><span class="n">context</span><span class="p">[</span><span class="sh">"</span><span class="s">notes</span><span class="sh">"</span><span class="p">]</span> <span class="o">=</span> <span class="sh">"</span><span class="s">The user wants concise responses.</span><span class="sh">"</span>
<span class="n">self</span><span class="p">.</span><span class="n">context</span><span class="p">.</span><span class="nf">set_dynamic</span><span class="p">(</span><span class="sh">"</span><span class="s">todo</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">self.todo.status()</span><span class="sh">"</span><span class="p">)</span>   <span class="c1"># re-evaluated each turn
</span><span class="n">recent_python</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">events</span><span class="p">.</span><span class="nf">query</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="sh">"</span><span class="s">PythonOutput</span><span class="sh">"</span><span class="p">,</span> <span class="n">limit</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
</code></pre></div></div> <h2 id="references">References</h2> <ul> <li>Paper: <a href="https://arxiv.org/abs/2607.20709">https://arxiv.org/abs/2607.20709</a></li> <li>Code: <a href="https://github.com/nvidia-nemo/labs-OO-Agents">https://github.com/nvidia-nemo/labs-OO-Agents</a></li> <li>OpenShell (the authors’ preferred deployment runtime): <a href="https://github.com/NVIDIA/OpenShell">https://github.com/NVIDIA/OpenShell</a></li> <li>ARC-AGI-3 benchmark: <a href="https://arcprize.org/arc-agi/3/">https://arcprize.org/arc-agi/3/</a></li> </ul> <h2 id="further-reading">Further Reading</h2> <ul> <li><strong><a href="https://arxiv.org/abs/2402.01030">Executable Code Actions Elicit Better LLM Agents</a></strong> (Wang et al., ICML 2024) — the paper NOOA’s CodeActStrategy descends from directly, making the case that executable code beats JSON and text as the action modality.</li> <li><strong><a href="https://arxiv.org/abs/2605.09650">Workspace Optimization: How to Train Your Agent</a></strong> (Sarafian et al., 2026) — the same group’s companion work. It produced the DreamTeam system that the ARC-AGI-3 example compresses, and its open problem of transfer is what NOOA’s memory subsystem addresses.</li> <li><strong><a href="https://arxiv.org/abs/2310.08560">MemGPT: Towards LLMs as Operating Systems</a></strong> (Packer et al., 2023) — the lineage behind NOOA’s event-history collapse and memory tiers, and the origin of treating the LLM as an OS that pages context.</li> <li><strong><a href="https://arxiv.org/abs/2605.18747">Code as Agent Harness</a></strong> (Ning et al., 2026) — a survey of code becoming the substrate for reasoning, acting, environment modeling, verification, planning, memory, and multi-agent coordination. Reading NOOA as an object-oriented Python runtime for that shift places it well.</li> <li><strong><a href="https://arxiv.org/abs/2512.24601">Recursive Language Models</a></strong> (Zhang et al., 2025) — makes the prompt itself a variable in a REPL that the model inspects, slices, and recursively queries. This is what NOOA’s pass-by-reference looks like pushed to its logical conclusion.</li> </ul>]]></content><author><name></name></author><category term="paper-review"/><category term="llm-agents"/><category term="agent-framework"/><category term="code-as-action"/><category term="tool-use"/><category term="python"/><category term="memory"/><category term="benchmarks"/><summary type="html"><![CDATA[An agent is not a bundle of prompt templates, tool schemas, and workflow graphs. It is a Python object: methods are actions, fields are state, docstrings are prompts, type annotations are contracts.]]></summary></entry></feed>