Index
2026-06-23 · Scene-Mem API track

over-advance의 진짜 원인은 메모리가 아니라 STATE 윈도였다 — --state-align leadup 보정

gemini-3.5-flash · control/m3/m2 · 5 cells (15 rows) · chunk vs leadup A/B · 게이트웨이 정확비용 로깅

TL;DR

0.00→0.80
control slot_acc
0.00→0.80
control action_acc
0.20→0.33
m2 slot_acc (악화)
$0.0192
실측 per-call

1배경 — 무슨 문제였나 (왜)

벤치는 "로봇이 긴 영상으로 여러 task를 수행한 뒤, 메모리를 반영해 다음 fine sub-task를 내보내는 능력"을 측정한다. oracle 세그먼트를 순회하다 타깃 세그먼트에서 fine-step을 walk하고, target_fine_idx(tfi) 스텝의 예측만 GT와 slot match(action∧object∧place)로 채점한다.

1·2차 측정에서 메모리 메서드(control / m1 / m2 / m3)를 한꺼번에 돌렸더니, 강모델일수록 M3(텍스트 running-notes)가 slot=0으로 붕괴했다. 사용자 직관은 "M3 메모리가 ...Now closing the freezer처럼 다음 동작을 미리 적어버려서 계속 틀린다"였다. 이번엔 메서드를 하나씩 손보기로 했고, M3(TEXT)부터 들어갔다.

증상(gemini-3.5-flash, n=298, chunk mode): GT action이 298/298 전부 place인데 control·m3 둘 다 place를 단 한 번도 예측하지 않음. 항상 Close the door 류를 출력. place_acc≈0.59는 살아있는데 action_acc≈0.00.

2가설 검증 — 메모리가 원인인가? (control vs m3 row-join)

같은 (scenario, test_id)끼리 control(메모리 0)과 m3(텍스트 메모리)의 예측을 맞대어 비교했다. 메모리가 원인이라면 m3가 control보다 더 심하게 over-advance해야 한다.

gemini-3.5-flash (n=298)해석
control도 close 예측 (both)182메모리 0인데도 over-advance
control만 close6
m3만 close (메모리가 민 것)13순효과 +7 (≈2.3%)
control과 글자까지 동일 예측239 / 298 (80%)메모리가 답을 바꾸는 일 자체가 드뭄
결론: 텍스트 메모리는 over-advance를 +2.3% 더 밀 뿐, 주범이 아니다. M3 노트 "Now closing the freezer"모델이 잘못된 STATE를 보고 쓴 증상일 뿐 — 예측과 노트가 같은 STATE에서 파생된 쌍둥이라 상관은 높지만 인과는 아니다. control이 이 교란을 끊어준다(메모리 0, 같은 STATE, 같은 오류).

3무엇이 다른가 — chunk vs leadup (이게 핵심)

데이터에는 세그먼트 경계만 있고 fine-subtask별 프레임 경계는 없다. 그래서 runner가 타깃 세그먼트를 fine 개수 K균등 비율분할한다. 예: combo_002_..._0006의 seg0=[0,724), K=4, tfi=1:

seg0 = frames [0, 724) (2Hz) k=0 [0,181) "Pick up the steak" k=1 [181,362) "Place the steak in the freezer" ← TARGET(tfi=1), 여기만 채점 k=2 [362,543) "Close the freezer door" k=3 [543,724) "Close the fridge door"

채점 스텝에서 chunk 모드chunk[tfi]=[181,362)를 STATE로 보여준다. 이 윈도의 마지막 프레임(~362)은 place가 이미 끝난 장면이다. "다음에 뭘 할까?"를 물으면서 행동 완료 장면을 주니, 모델은 정상적으로 그 다음 fine인 Close the freezer door(=실제 tfi+1)를 답한다. leadup 모드는 윈도를 한 칸 당겨 chunk[tfi-1]=[0,181)을 보여준다 — 마지막 프레임이 place 직전이라 "다음 행동"이 곧 타깃 Place the steak가 된다.

chunk vs leadup STATE window comparison
동일 시나리오의 두 채점 윈도 마지막 프레임. 좌(leadup, ~frame 180): 스테이크를 든 채 냉동고 앞 — 넣기 직전 → 모델 예측 Place the steak ✓. 우(chunk, ~frame 360): 그리퍼가 비었고 스테이크는 이미 냉동고 안 → 모델 예측 Close the freezer door ✗ (over-advance).

지표가 찍은 over-advance의 지문

over-advance는 fixture(freezer)는 그대로 두고 action만 한 칸 앞서간다. 그래서 place_ok(freezer 일치)는 살아남고 action_ok(place→close)만 죽는다. 측정에서 본 place_acc≈0.59 / action_acc≈0.00 패턴이 정확히 "딱 +1칸 over-advance"의 지문이다.

4어떻게 테스트했나

# 키 주의: 기존 'Letsur:' 키는 COST 한도 소진 → 'Letsur_qualcomm:' 사용 KEY=$(grep '^Letsur_qualcomm:' ~/envs/api_keys.txt | cut -d: -f2- | tr -d ' ') OPENAI_API_KEY=$KEY OPENAI_BASE_URL=https://gw.letsur.ai/v1 \ python -m scene_mem_api.runner --model gemini-3.5-flash \ --method <control|m3|m2> --stage full --limit 5 --state-align leadup

5결과 — chunk → leadup (gemini-3.5-flash, 15 rows)

methodslotactionplaceleadup 비용
control (메모리 없음)0.000.800.00 → 0.800.60 → 1.00$0.23*
m3 (텍스트 메모리)0.000.800.00 → 0.800.67 → 1.00$1.13
m2 (시각 keyframe)0.20 → 0.330.33 → 0.330.60 → 0.73$1.59

*control은 캐시된 증분 측정만 $0.23. 풀 5셀(60 calls)은 ~$1.15. per-call ≈ $0.0192, prompt ≈ 9.1k tok/call(이미지가 초기 추정의 2배), per-scenario(3 tests) ≈ $0.23.

① leadup이 구조적 over-advance를 제거. control(메모리 0)이 slot 0.00→0.80으로 회복 → STATE 윈도 off-by-one이 1차 원인임이 실측 확정. Close the freezer door(action❌) → Place the steak(slot✅).
② m3 = control, 정확히 동일(0.80). 윈도를 고치니 텍스트 메모리의 control 대비 순이득 0. M3의 "효과도 붕괴도" 전부 윈도 아티팩트였고, 텍스트 메모리 표현 자체는 이 셋에서 신호가 없다. (m3v2가 .003에 그쳤던 것도 구조 바닥에 가려졌던 것으로 설명됨.)
③ m2(시각 keyframe)는 오히려 악화(0.33 < 0.80). chunk에선 "M2 best"였는데 윈도를 고치니 꼴찌. per-row를 보면 over-advance가 아니라 under-advance/혼란(Navigate to the oven, Pick up the bowl) — 주입된 과거 keyframe 이미지가 모델을 이전 상태로 끌어당긴다. 기존 "M2 best"는 모두가 over-advance하던 깨진 측정 하의 착시였을 가능성이 크다.

6결과 영상 — 윈도 한 칸 차이가 예측을 가른다

같은 타깃 세그먼트(steak) 재생. 타임라인의 초록 마커(~181)=leadup이 채점하는 지점(넣기 직전 → Place the steak ✓), 파란 마커(~362)=chunk가 채점하는 지점(이미 넣은 뒤 → Close the door ✗). 두 마커 사이 구간이 chunk가 추가로 보여주는, place가 완료되는 장면이다.

7해석 & caveats

⚠️ 유효 표본이 작다. 5개 시나리오가 전부 combo_002_L29_S48_* 같은 템플릿 변종 — 사실상 3개 test 타입 × 거의 동일한 1개 구조. OvenBroilFish는 m2에서 5/5 전부 Navigate to the oven으로 동일 실패(구조적이지만 다양성 0). 결론 확정 전 다른 시나리오 패밀리 + 큰 n 필요.
⚠️ RestockBowls 잔존 over-advance. leadup 후에도 RestockBowls는 일부 Close the cabinet door로 틀린다 — context의 알려진 데이터 tfi 버그 클래스로, 윈도 보정과 별개로 데이터 수정이 필요하다.
⚠️ 비용 추정 8× 교훈. 초기 토큰-단가 추측($0.1–0.2)이 실측(~$1.15)의 6–8× 과소였다. 이제 게이트웨이 estimated_cost를 ground truth로 매 run이 출력하므로 본런 전 단가가 사전확인된다.

8타이밍 — fine-subtask 실시간 vs API call 간격

"API를 너무 자주/드물게 부르는가?"를 데이터로 확인했다(다양한 셋 111개 타깃 세그먼트, 소스 20fps, 영상 디코딩 없이 세그먼트 경계 + fine 개수만 사용).

항목median범위 (min–max)
세그먼트 길이43초12 – 164초
K (세그먼트당 fine 수)52 – 8
fine-subtask 1개 실시간 (평균)11.8초3.3 – 82초
API call 1개가 커버하는 윈도 span11.8초3.3 – 82초
윈도당 보여주는 프레임 수 (cap 8)86 – 8
윈도 내 프레임 간격 dt1.5초0.5 – 10초
cadence는 맞다. proportional split이 구조적으로 1 API call = 1 fine-subtask로 강제하므로, 연속 call의 video-time 간격(≈11.8초) = fine-subtask 평균 길이(≈11.8초). 한 fine를 8프레임(≈1.5초 간격)으로 보여줘 해상도도 합리적. 정정: 181프레임은 20fps에서 9초지 90초가 아님
진짜 문제는 cadence가 아니다. (1) per-fine 실시간이 3초~82초로 천차만별인데 모든 K개를 동일 길이로 쪼갬 → chunk 경계가 실제 행동 경계와 어긋남(over-advance의 뿌리, leadup이 완화). (2) 긴 세그먼트는 dt가 최대 10초 → 빠른 pick/place(2~3초)가 1~2 프레임에만 잡히거나 누락.

9일반화 측정 — 다양한 12개 패밀리

§5의 5셀은 전부 combo_002 단일 템플릿이었다. 서로 다른 12개 패밀리(각 1 시나리오, --val-list)로 control/m3/m2를 전부 leadup으로 측정해 일반화를 확인했다. (chunk 베이스라인은 비용상 생략 → 메서드 간 비교.) gemini-3.5-flash, n=39.

methodslotactionplaceexact
control (메모리 없음)0.3330.3850.7180.128
m3 (텍스트 메모리)0.3330.3850.7180.103
m2 (시각 keyframe)0.1280.3080.5640.000
① m3 = control, 다양한 셋에서도 정확히 동일(0.333). 텍스트 메모리 무효과가 패밀리 전반으로 일반화.
② m2(시각 keyframe)는 control보다 더 나쁨(0.128 ≪ 0.333). matched 비교: m2-only-correct=2 vs control-only-correct=10(순 −8). m2 예측 action 분포 = place 12 / pick 11 / navigate 9 / close 5 (GT는 39/39 place) → 주입된 과거 keyframe이 모델의 시간 앵커를 앞(navigate/pick)·뒤(close)로 흩뜨린다.

"M2 best"는 깨진 측정의 착시였다

chunk 모드에서 M2가 1등이던 건, 모두가 over-advance하던 상황에서 keyframe이 우연히 덜 틀린 것이었다. 윈도를 고치자 메모리는 둘 다 control을 못 이기고, 시각 메모리는 오히려 net-negative다. 또한 combo_002의 0.80은 비대표적 — 다양한 패밀리 절대정확도는 control도 0.333으로, over-advance를 고쳐도 다른 실패모드(fine 경계 어긋남)가 남는다. 현재 결론: next-subtask 단일 프롬프트 + 약모델 조합에선 메모리 이득이 없다.

비용: control $3.31 + m3 $3.36 + m2 실제 ~$4.5 ≈ $11. (m2는 병렬 실행 중 게이트웨이 일시오류로 1셀 크래시 → 순차 재실행 복구; 코드 버그 아님(오프라인 정상). 교훈: 비싼 sweep은 순차로.)

10다음

소스 로그: claude/260623/analysis-m3_overadvance_leadup_fix.md · 커밋 4641d99 · 결과 results/gemini-3.5-flash__{control,m3,m2}__full__align_leadup.json