examples/robomme/subgoal_prediction/api_mem/ 신설. ApiMemModel이 PI Mem mt를 zero-shot Gemini API로 구현 — 2-step(detection Call A + reasoning Call B) 아키텍처로 완성.extra_body.thinking_config.thinking_budget=0 무시됨. flash-lite가 유일한 non-thinking 옵션. pro는 max_tokens≥4096 필수(2048이면 thinking이 전부 먹어 visible response 0).scripts/run_api_mem_one_episode.sh의 MAX_CLIENT_RESTARTS=10 loop으로 자동 회복.sbmr 10 "bash scripts/run_api_mem_one_episode.sh ..." --gres=gpu:2 -c 28 --mem=400GB --partition=sub --qos=core-on-sub. 2 GPU 필수(server uv .venv + client robomme conda).260505 분석 카드에서 BinFill 8-run 결과와 bottleneck 진단을 다뤘다. 본 카드는 그 과정에서 구현된 코드 아키텍처와 8-run을 거치며 발견한 인프라 트랩을 기록한다. 다음 세션(PatternLock 실험 등)에서 동일 인프라를 재사용할 때 같은 함정에 빠지지 않도록 engineering reference로 남긴다.
구현 원칙: gemini/, qwenvl/ 무수정. 모든 변경은 api_mem/ 신설 모듈 또는
eval.py/subgoal_predictor.py 최소 수정으로 한정.
| Call | 메서드 | Input | Output | 비고 |
|---|---|---|---|---|
| Call A (detection) | _call_detection(image) |
image | [{label, box_2d}] (1000-norm) |
detection-only system prompt. 1-step 모드에서는 skip |
| Call B (reasoning) | get_subgoal(image) |
image + detected_objects + prev_mt + prev_subgoal (+ ep0 demo video) | {scratchpad, memory_summary, subgoal} |
5-rule MEM system prompt. subgoal은 1000→256 rescale 후 반환 |
8 runs 전부에서 mt 메커니즘 자체 정상 작동 확인 (rule 2 idempotency, monotonic 진화, count compression, "task complete" emit).
| 파일 | 변경 내용 |
|---|---|
examples/robomme/eval.py | Args에 5개 필드 추가: use_api_mem, api_mem_provider, api_mem_model_name, api_mem_call_period, api_mem_image_upscale. setup_save_directory에 "api_mem" 브랜치 추가 |
examples/robomme/subgoal_predictor.py | ApiMemSubgoalPredictor 클래스 추가 + builder switch |
scripts/run_api_mem_one_episode.sh | 신규 — server(uv .venv pi0.5) + client(robomme conda + ApiMem) + Vulkan restart loop 10x. 4 args: <task> [model] [tag] [upscale] |
| 구성 | API call/ep | 50 ep sweep 비용 |
|---|---|---|
| 1-step (flash-lite) | ~27 | $0.10 |
| 2-step (flash-lite) | ~54 | $0.20 |
| 2-step (gemini-2.5-pro) | ~54 | $1–2 |
BinFill 평균 ~1300 sim steps, K=48 → 27 high-level tick/ep 기준.
| 모델 | Thinking | 주요 문제 | 권장 용도 |
|---|---|---|---|
gemini-2.5-flash-lite | ❌ non-thinking | 좌표 정확도 낮음, bbox 불안정 | 빠른 iteration, 비용 민감 sweep |
gemini-2.5-flash | ✅ thinking ON | thinking이 max_tokens 전부 소비 → response truncation 빈발 | 사용 비추천 |
gemini-2.5-pro | ✅ thinking ON | max_tokens < 4096이면 visible response 0 | 정확도 우선 실험. max_tokens=4096 필수 |
extra_body.thinking_config.thinking_budget=0을 무시한다.
flash와 pro 모두 thinking 비활성화 방법 없음. flash-lite가 유일한 non-thinking 옵션.
max_tokens=4096 이상 설정. detection call(A)도 마찬가지.
scripts/run_api_mem_one_episode.sh의 MAX_CLIENT_RESTARTS=10 loop이 자동 재시작으로 회복.
단, tee 파이프가 exit code를 가리는 알려진 한계 있음 — 실제 abort 여부는 progress.json episode 수로 확인.
api.py의 _rescale_coords()가 자동 처리하므로 외부에서 추가 변환 불필요.
이 fix가 run5(4429)에서 6%→8% (+2pp)의 유일한 실측 contributor였음.
runs/api_mem_smoke/<TASK>_<tag>/ 패턴. 동일 tag로 여러 task를 돌리면 progress.json race condition 발생.
script의 4번째 인자 [tag]로 실험별 구분.
~/envs/api_keys.txt (복수형 envs!).
global CLAUDE.md의 ~/env/는 오기. api.py의 _load_api_key()는 env var 우선, fallback으로 파일 읽기.
또는 ~/.bashrc의 export LETSUR_API_KEY=<key>.
run 초기에는 loop abort, parse_fail, Vulkan crash 등 다양한 failure mode가 있었다.
run 8c (job 6056, BinFill_2step_pro)에서 parse_fail 0 / loop 0 / empty_response 0 / errors 0
달성. 즉, 현재 api_mem/ + run_api_mem_one_episode.sh 조합은
production-grade robustness를 갖춘 상태.
동시에 분석 카드에서 결론냈듯이, robustness를 완성해도 BinFill SR은 4.3%에서 불변이었다. 이는 인프라 문제가 아닌 task-level alignment 문제임을 역설적으로 증명한다.
gemini/, qwenvl/ 무수정 원칙을 지켜 기존 closed-loop sweep 재현성에 영향 없이
ApiMem 전체 파이프라인을 추가했다. 다음 task(PatternLock)는 이 코드베이스를
그대로 사용하며 추가 구현 작업 없다.
코드 변경 없이 task 인자만 바꿔 실행. pro × 2-step이 LoRA 16%보다 ≥30% 달성하면 유의미한 finding.
max_tokens=4096 이상 설정 확인