TL;DR
- 지적이 실측으로 확인됨: 구 설계의 물체 리스트(
[uid] 이름, room N)는 정답 835개 중 556개(66.6%)를 그대로 노출했고, find_distractor는 400/400 = 100%였다 (안 움직인 물체라 초기 방 = 정답). 게다가 uid 접미사 자체가 방 번호라 표기를 지워도 누출이 남는다.
- 재설계: 에피소드별 물체 리스트를 폐기. 프롬프트에는 데이터셋 전역 어휘만 — 물체 카테고리 57종 / 방 4종+floor / 표면 15종. 이 집 안에 무엇이 있는지, 몇 개인지는 전혀 알려주지 않는다.
- 답 계약 전환: uid 선택 → "어디에 있는가"
{category, room|floor, surface}. 방 이름은 실측 커버리지 95.4%(733 이름 유도 + 64 floor / 38만 미유도)로 성립.
- 부수 효과: 개수 힌트 제거(multi는 memory로 세야 함), 초기 방 미끼 제거, blind chance가 1/5로 명확해짐. 인스턴스 판별은 (category, room, surface)로 사후 body-id 해소 —
twin_nearby 98건(12.9%)만 원리적 모호로 분리 보고.
1 무엇이 잘못됐나 — 누출 실측 (답 835개 전수)
구 설계가 프롬프트에 넣던 것
[Irishpotato_7c3f16774c3f2d6de70e09dd23897534_1_0_6] irish potato, room 6
[atomizer_e0cab0ef1fe80f6fe596048b9bc862a1_1_0_5] atomizer, room 5
[bowl_46a21212675e4d90993a86b1232e6f40_1_0_4] bowl, room 4
[bowl_6befd62f08fd322391939c2b44d3f839_1_0_7] bowl, room 7
[bowl_9087df6907f975021e5d8ac01d4c2557_1_0_6] bowl, room 6
[bread_ce14aa444cff8c5279772caf1fa3df7a_1_0_6] bread, room 6
… (24줄)
| 질의 종류 | 초기 방 = 최종 정답 위치 | 판정 |
| find_distractor (안 건드린 물체) | 400 / 400 | 100% 누출 — 정의상 안 움직이므로 초기 방이 곧 정답 |
| find_target (로봇이 옮긴 물체) | 156 / 435 | 35.9% 누출 — 같은 방 안에서만 옮긴 경우 |
| 전체 | 556 / 835 (66.6%) | 리스트만 읽어도 3분의 2가 정답 |
표기를 지워도 안 된다: uid 접미사가 방 번호다 (bowl_46a2…_1_0_4 → room 4). uid를 답으로 요구하는 한 방 정보가 따라온다. uid 기반 선택형 계약 자체를 버려야 누출이 끝난다.
추가로 누출되던 것들: ① 이 집에 어떤 물체가 몇 개 있는지(24줄 = 닫힌 집합) → multi 질의의 개수 힌트 ② 동일 카테고리 인스턴스 수 → 후보 폭 노출 ③ "여기 없는 물체는 답이 아니다"라는 배제 추론 무료 제공.
2 새 답 계약 — "무엇을 골라라"에서 "어디에 있나"로
{"reasoning": "...",
"selections": [{"category": "bowl", "room": "floor", "surface": null},
{"category": "bowl", "room": "living room", "surface": "dining table"}],
"abstain": false}
| 구 설계 (v1) | 새 설계 (v2) | 이유 |
| 물체 지목 | 에피소드 24개 uid 중 선택 | 카테고리 이름 (전역 어휘) | uid 선택은 방 누출 + 닫힌 집합 힌트 |
| 위치 | 방 번호 (리스트가 이미 알려줌) | 방 이름 또는 "floor" | 이게 메모리의 실제 내용 |
| 표면 | 없음 (누출 우려로 삭제) | 표면 카테고리 (전역 15종) | 전역 어휘라 누출 없음 + 인스턴스 해소에 필요 |
| 개수 | 리스트로 유추 가능 | 모델이 기억에서 판단 | multi 질의의 핵심 과제 |
즉 답은 "몇 개가, 어느 방 어떤 가구 위에 있는가"가 된다 — 로봇이 실제로 그 물체를 가지러 가려면 알아야 하는 바로 그 정보이고, 프롬프트가 미리 알려줄 수 없는 정보다.
3 프롬프트 전문
3.1 system_v3 — 에피소드 정보 0, 전역 어휘만
[system]
You are the memory module of a household robot. The earlier turns of this
conversation are your memory of one episode in this house — what the robot did
and saw. The final image is the robot's CURRENT view at the end of the episode.
The user will ask you to pick up an object, described by its category and by
what happened to it. Answer WHERE that object is now. The object is usually not
in the current view, and nobody will tell you what is in this house: recall it.
Output a single JSON object, nothing else:
{"reasoning": "...",
"selections": [{"category": "...", "room": "...", "surface": "..."}],
"abstain": false}
Rules:
- One entry in "selections" per object the query refers to. If the query says
"all the ...", decide how many there are from your memory. Otherwise give
exactly one.
- "room": one of bathroom | bedroom | kitchen | living room — or "floor" if the object
ended up lying on the floor rather than on a surface.
- "surface": the kind of thing it is resting on, from the surface list below.
Use null when the object is on the floor.
- Use the category and surface names exactly as spelled in the lists.
- If your memory genuinely cannot determine the answer, set "abstain": true.
Object categories:
CD | alarmclock | apple | atomizer | bar soap | baseballbat | basketball | boiler
bottle | bowl | box | bread | butter knife | candle | cell phone | coffeemaker
cooking pan | cup | desktopcomputer | egg | fabric | fork | house plant | irish potato
knickknack | knife | ladle | laptop | lettuce | microwaveoven | mug | newspaper
papertowel | pen | pencil | pepper shaker | pillow | plate | plunger | pot
remote control | safe | saltshaker | soapdispenser | spatula | sponge | spoon | statue
tablelamp | teddybear | tennisracket | tissue box | toaster | toilet tissue | tomato
vase | winebottle
Surfaces:
armchair | bed | cart | chair | clothes dryer | countertop | desk | dining table
dresser | shelf | sink | sofa | toilet | tv stand | washing machine
3.2 질의 턴 — 대폭 축소 (val_101__0 multi 질의)
[user] (질의 턴 — 메모리 턴 뒤)
<image: 마지막 프레임 (exo_camera_1, frame 13749)>
Query: "Pick up all the bowls I moved earlier"
Reply with the JSON object only.
구 설계에서 여기 붙던 24줄 물체 리스트 + 방 리스트가 전부 사라졌다. 어휘는 system에 한 번만 실리고(전 질의 공유·캐시 가능), 질의 턴은 이미지 1장 + 질의문뿐이다 — 토큰도 줄고 누출도 없다.
3.3 기대 출력 (GT 대응)
{"reasoning": "I moved two bowls. The first one I tried to put on the bed but
dropped it — it is on the floor. The second I carried from the kitchen countertop
to the dining table in the living room.",
"selections": [{"category": "bowl", "room": "floor", "surface": null},
{"category": "bowl", "room": "living room", "surface": "dining table"}],
"abstain": false}
이 에피소드 GT: bowl 2개 — 하나는 침대에 놓다 떨어뜨려 floor, 하나는 living room 식탁. 씬에는 bowl이 3개지만 모델은 그 사실조차 모른다: 몇 개를 옮겼는지, 어디로 옮겼는지 전부 기억에서 나와야 한다.
4 전역 어휘 — 프롬프트에 들어가는 유일한 리스트
물체 카테고리 57종 (데이터셋 153 eps 전체, 물체 3,346개에서 수집)
CD | alarmclock | apple | atomizer | bar soap | baseballbat | basketball | boiler
bottle | bowl | box | bread | butter knife | candle | cell phone | coffeemaker
cooking pan | cup | desktopcomputer | egg | fabric | fork | house plant | irish potato
knickknack | knife | ladle | laptop | lettuce | microwaveoven | mug | newspaper
papertowel | pen | pencil | pepper shaker | pillow | plate | plunger | pot
remote control | safe | saltshaker | soapdispenser | spatula | sponge | spoon | statue
tablelamp | teddybear | tennisracket | tissue box | toaster | toilet tissue | tomato
vase | winebottle
방 4종 + floor
bathroom | bedroom | kitchen | living room (+ "floor")
표면 15종
armchair | bed | cart | chair | clothes dryer | countertop | desk | dining table
dresser | shelf | sink | sofa | toilet | tv stand | washing machine
왜 이건 누출이 아닌가: 셋 다 데이터셋 전역이라 특정 에피소드에 무엇이 있는지 알려주지 않는다. 오히려 답의 표기법을 통일해 채점을 결정론적으로 만든다(모델이 "cell phone"과 "cellulartelephone" 중 무엇을 쓸지 고민할 필요 없음). 어휘 크기가 곧 chance 분모가 되어 G1 게이트가 정확히 계산된다.
5 메모리 턴 (전략별) — 변경 없음
메모리 주입 방식은 파일럿과 동일하다. 단 rollforward-v2의 ingest 프롬프트에서도 에피소드 인벤토리(uid 목록) 제공을 전역 어휘로 교체한다 — 기록 시점에 "이 집에 뭐가 있는지"를 알려주면 같은 누출이 재발한다.
[user] (textlog 메모리 턴 — val_101__0 실제 생성문)
Here is the record of what I did in this house during the episode:
[ 0s– 81s] I tried to move the bowl from the dining table in the bedroom to the bed in the bedroom, but I failed to place it.
[ 81s– 198s] I picked up the remote control from the dining table in the bedroom and placed it on the toilet in the bathroom.
[ 198s– 342s] I picked up the bowl from the countertop in the kitchen and placed it on the dining table in the living room.
[ 342s– 550s] I picked up the remote control from the toilet in the bathroom and placed it on the sofa in the living room.
첫 줄이 "…but I failed to place it"로 끝나 떨어진 bowl의 최종 위치는 안 알려준다 — floor 답을 맞히려면 로그 너머 추론이 필요하다(오라클 textlog의 자연 상한).
6 채점 · chance
| 지표 | 정의 | chance |
| loc_acc (헤드라인) | selections의 위치 집합 == GT 위치 집합 (single은 1개, multi는 개수까지 일치) | 1/5 (방4+floor) — 개수까지 맞춰야 하므로 multi는 더 낮음 |
| place_strict | 위치 ∧ 표면 일치 | ≈1/75 |
| count_acc | selections 개수 == 정답 개수 (multi 진단) | — |
| body-id 해소율 | (category, room, surface)가 유일 물체로 해소되는 비율 | 공식 지표 대응 — twin_nearby 98건(12.9%)은 원리적 모호로 분리 |
| 기권율 | 유효 질의 기권 = 오답 (A5 2×2) | — |
계층화 축: kind(target/distractor) × steps(single/multi) × misplaced(no/on_floor/wrong_surface) × twin_nearby × seen_s 분위 × 동일 카테고리 인스턴스 수. concealment/needs_open은 이번 릴리즈에서 퇴화(전부 seen/0건).
방 이름 미유도 38건(4.6%): 이벤트 조인으로 이름이 안 나오는 방 — 해당 답은 위치 채점에서 제외하고 별도 집계(조인 확장은 후속 개선). 조인 모순 에피소드 3건도 동일 처리.
7 남는 한계 (숨기지 않고 명시)
① 공식 body-id 채점과 간접 대응 — Tier A(심볼릭)는 "어디에"를 재고, 실제 잡은 body는 Tier B(실행형)에서 잰다. 사후 해소로 근사하되 twin 98건은 원리적으로 구분 불가임을 명시.
② 상식 누출은 남는다 — "knife는 kitchen"처럼 카테고리-방 상식으로 풀리는 질의가 있다. 이건 리스트 누출과 달리 blind 대조군이 정확히 측정해 주므로(공리 A1), 층화 보고에서 blind 대비 상승분만 메모리 신호로 읽는다.
③ 방 4종은 거친 해상도 — 같은 방 안 다른 위치는 표면으로만 구분된다. 표면이 null인 floor 답(64건)은 위치 해상도가 "floor"까지.
8 예산 · 구현
전략 5종 (blind / textlog / frames-uniform / rollforward-v2 / vis-pure) × 2모델
단계: S1 검증 3 eps ~$6 → S2 층화 파일럿 15 eps ~$35 → S3 전량 759질의 ~$155 (생존 조합, 승인 후)
질의 턴이 짧아져(리스트 삭제) 구 추정 대비 질의 토큰 ~30% 감소 — 위 금액은 보수적 유지
구현 변경 ① schema.py: selections[{category, room, surface}] ② vocab.py 신설: 전역 어휘 3종 + 표시명 매핑(데이터셋에서 1회 생성, 버전 고정) ③ candidates.py 폐기(에피소드 리스트 자체가 누출원) ④ query_runner.py: system_v3, 질의 턴 축소 ⑤ scorer.py: 위치 집합 일치 + 표면 + 개수 + body-id 사후 해소 ⑥ stratify.py: 계층화 라벨러 ⑦ rollforward-v2 ingest 프롬프트도 전역 어휘로 교체 ⑧ tests: 누출 회귀 테스트(프롬프트 문자열에 에피소드 uid·방번호가 등장하면 실패) 추가.