정본은 앱 저장소 com.remakeday/docs/model_evaluation.md이고,
이 페이지는 스냅샷입니다. 수치·결정의 최신 기준은 항상 정본을 따릅니다.
문서 안의 상대 링크는 앱 저장소 GitHub 링크로 바꿔 두었습니다.
현재 NPC 평가 기준 — 2026-09-15
NPC 정책 npc-dialogue-2는 쉬운 말투와 인물별 성격을 유지하면서 질문 이해·자기 행동의 이유 설명·당일 기억을 요구한다. 이전 E6의 ‘왜=몰라’, 3턴 망각, 근거 없는 화제 전환, 무조건적인 전언 수용은 현재 정책의 통과 조건이 아니다. 아래 과거 실험 결과는 당시 기준의 기록으로 보존하며 새 정책의 성능 근거로 재사용하지 않는다.
구현 및 새 평가: 승인된 설계, 실행 계획, 새 평가 스크립트. 기존 Kanana 모델로 변경 효과와 한계를 먼저 측정한 후 동일 조건에서 대안을 비교했다. 실제 질문·허용 근거·출력·재생성·지연을 저장해 검토하며, 의미 품질을 단어 포함 검사나 같은 모델의 자기평가로 통과시키지 않는다.
2026-09-15 적용 결정과 측정 결과
로컬 NPC는 ollama:gemma4:12b, think=off, 대화 temperature 0.3으로 적용한다. 시나리오의 실제 행동·전언 출처를 설명하는 일부 문답이 Kanana보다 정확해진 것을 근거로 선택했다. 중요한 모순 0건·현재 전언 이해·관련성 90%라는 최초 의미 품질 목표에는 아직 미달한다. Core는 기존 Gemma 설정을 유지한다.
| 최종 코드의 평가 범위 | 응답 성공 | 실패 / 재생성 | 중간값 | p95 |
|---|---|---|---|---|
| Kanana, 공통 10개 상황 | 21/21 | 0 / 0 | 1.027초 | 1.468초 |
| Gemma, 동일 10개 상황 | 21/21 | 0 / 0 | 2.553초 | 3.053초 |
| Gemma, 추가 10개 상황 | 20/20 | 0 / 0 | 2.629초 | 3.028초 |
| Gemma, 합계 | 41/41 | 0 / 0 | 2.599초 | 3.053초 |
각 최종 상황은 1회 실행했다. 공통 21문답이 모델 간 비교 대상이며, Gemma 추가분은 최종 기능 범위를 확인하기 위한 검사다. Gemma 전체에는 최근 판의 원래 질문 8개와 후속 질문, 네 인물의 공통 질문, 과거 루프·현재 전언·기억 삭제·행동 금지·소실·정체 질문이 포함된다. 세 실행의 소스 해시는 동일했다. 준비용 과거 대화와 워밍업은 위 수치에서 제외했다. 지연은 메모리 저장소를 사용한 유스케이스 전체 시간이며 실제 API·DB·브라우저 지연은 포함하지 않는다. p95 3초의 초기 목표도 이번 표본에서는 소폭 초과했다.
확인한 개선:
- 은상은 “준한테 들었어. 준이 말해준 거라 내가 직접 본 건 아니야.”라고 출처와 관점을 구분했다.
- 민석은 “채연이가 남긴 배급을 보고 적었어.”라고 실제 행동을 근거로 답했다. 밤에는 준과 함께 있으면 안심되는 이유를 후속 질문까지 이어 답했다.
- 긴 기록 ID를 짧은 모델용 별칭으로 바꾼 뒤 최종 비교에서는 ID 변형으로 인한 재생성이 없었다. 실제 저장과 기억 삭제에는 원래 ID를 사용한다.
- 정적 수첩 내용의 중복을 제거한 뒤, 두 모델 모두 삭제된 오늘의 기록을 날짜·이름·쟁반 수로 복구하던 답변이 이 표본에서 사라졌다. 네 인물 모두 과거 루프의 실제 대화 내용을 회상하지 않았다.
남은 한계:
- Gemma가 현재 있는 은상을 없다고 추측한 답변 1건과, 자기가 방송실 안에 들어갔는지 모른다고 답한 사례가 있다.
- 과거 일을 지금 다시 말해 주는 네 후속 질문은 Gemma 모두 “몰라”로 답했다. 삭제 뒤 새로 전달한 관찰에 답하는 경우에도 회피가 남았다. 저장 경계의 구현과 모델의 현재 전언 이해는 별도로 판단해야 한다.
- 사라진 친구의 이름을 묻자 현재 친구 이름을 나열하는 등 질문 관련성 문제가 남았다. 성격 공통 질문의 후속 답은 안심·동행으로 수렴하는 경향이 있다.
- 의미 평가는 Codex가 허용된 사실과 모델 원문을 함께 읽은 검토다. 사람의 블라인드 페르소나 평가나 새 참가자의 5회차 실제 플레이는 아직 수행하지 않았다.
원인 진단에서는 두 모델의 세 입력을 기본 문맥과 8192토큰 문맥으로 비교했다. 실제 입력 토큰 수가 각각 동일해, 이 사례의 오류를 문맥 잘림으로 설명할 근거가 없었다. 현재 전언을 허용하는 지시의 명확화와 목소리 문구만 바꾸는 진단도 단독 개선 효과를 보이지 않았다. Gemma think=true 진단 3건은 생성 1024토큰 상한에서 모두 최종 답변 없이 종료됐고 23.278~23.840초가 걸렸다. 이 제한에서 실패했으므로 추론을 켜는 설정은 적용하지 않는다.
이전 Kanana 82문답 반복과 중간 프롬프트 실험은 개발 과정의 별도 자료이며 최종 41문답과 합산하지 않는다. 원래 플레이 8답변은 보관한 과거 기준선이고 새 조건으로 다시 실행한 대조군이 아니다.
자료: 상세 평가 보고서, 최종 집계, 기능 검증. 재현 시 모델과 thinking을 명시한다:
backend/.venv/bin/python backend/scripts/run_npc_dialogue_check.py --model kanana1.5:8b-q4km --think default --cases all --repeat 1
backend/.venv/bin/python backend/scripts/run_npc_dialogue_check.py --model gemma4:12b --think off --cases all --repeat 1
기준일: 2026-09-13 문서 지위: 모델 평가 정본. 모델 선정·교체·수치에 관한 모든 기록은 이 문서에 적립한다 상위 문서:
REMAKE_DAY_AI_Agent_Evaluation_PART1_정본_v1.0· 부록E6_Model_Descent_v0.1결과 적립:docs/metrics.yml· 원문 raw:docs/review-verification/<date>-<experiment>/표현 원칙: 측정하지 않은 것은 주장하지 않는다. 아래 §0.2의 금지 표현을 따른다 문서 형식: 자매 프로젝트thehorn.masterlesscompany.com의 research-portfolio 스펙에서 RQ·요인설계·Funnel·Protocol Metrics·Pareto 우선 원칙을 가져와 REMAKE DAY에 맞게 고쳐 썼다. 이 문서는 자립적이며 외부 문서를 참조하지 않는다
0. 포지셔닝
0.1 이 문서가 무엇인가
REMAKE DAY의 두 LLM 슬롯(NPC / Core)에 어떤 모델을 쓸지 결정하기 위한 재현 가능한 실험 기록이다. 논문이 아니라 논문의 형식을 빌린 기술 기록이며, 다음 세 가지를 남기는 것이 목적이다.
- 어떤 조건에서 몇 번 재서 무슨 값이 나왔는가
- 그 값으로 무엇을 결정했고 무엇은 결정하지 않았는가
- 같은 결과를 다시 만들려면 무엇을 실행해야 하는가
0.2 쓰지 않는 표현
| 금지 | 왜 |
|---|---|
| “A 모델이 B보다 낫다” | 어느 역할에서 어느 지표로 몇 번 쟀는지 없음 |
| “작은 모델도 충분하다” | 충분의 기준이 없음 |
| “성능이 N% 개선됐다” | 같은 조건의 전후 측정이 아니면 개선율이 아님 |
| “SOTA” / “최적” | 탐색 범위 밖을 주장함 |
| Screening tier의 지연·메모리 | tier 간 하드웨어가 다르면 비교 대상이 아님 |
| 폴백 결과를 성공으로 집계 | 폴백은 모델이 실패했다는 뜻 |
0.3 두 슬롯, 두 질문
Core 슬롯 planner · manager_check · manager_paw · advisor_answer · evaluator_verdict
질문: 자원 예산 안에서 "높은 사고"를 가장 잘하는 모델은?
현행 기준선: gemma3:12b (운영은 gemini-3-flash-preview)
→ E7
NPC 슬롯 agent · ask_npc
질문: 7세 역할을 해내는 "가장 낮은" 모델은?
현행 기준선: exaone3.5:7.8b
→ E6
두 질문은 성격이 다르다. E6는 크기 인과를 묻고(같은 family 안에서 크기만 내린다), E7은 예산 제약 아래 선택을 묻는다(family를 섞어야 답이 나온다). E6의 “family 고정” 규칙을 E7에 적용하지 않는다.
순서는 E7 → E6다. 실패 비용이 비대칭이기 때문이다. Core가 틀리면 세계가 굴러가지 않고 채점이 무너진다(§A.1의 RM1이 그 사례다). NPC가 어색한 것은 게임이 돌아가는 채로 고칠 수 있다.
1. 자원 제약 — 모든 후보의 상한
단일 GPU RTX 5060 Ti 16GB (15.19 GiB 가용). 두 슬롯이 동시 상주해야 한다.
2026-09-13 실측 (/api/ps 기준, 모델 3종 동시 로드):
exaone3.5:7.8b 4.14 GiB
gemma3:12b 7.49 GiB
qwen3.5:0.8b 1.03 GiB
──────────────────────────
모델 합계 12.66 GiB
nvidia-smi 13.76 GiB → 런타임 오버헤드 ≈ 1.1 GiB
여기서 나오는 Core 예산:
| NPC 구성 | Core 예산 |
|---|---|
| exaone3.5:7.8b 유지 (4.14) | ≈ 9.5 GiB |
| E6로 qwen3.5:4b 축소 시 (3.2) | ≈ 10.5 GiB |
순서 의존성은 작다. 두 예산의 차이는 1 GiB인데, Ollama 공식 라이브러리의 최신 세대 모델은 9.0~12.8 GiB 구간이 비어 있다 (gemma4:e4b 8.95 다음이 gpt-oss:20b 12.85). 예산을 1 GiB 늘려도 새로 들어오는 후보가 없으므로, E6 결과를 기다리지 않고 E7을 확정해도 손해가 없다.
2. E7 — Core Role Model Selection under Resource Budget
2.1 Research Questions
RQ-C1 — Selection
9.5 GiB 예산 안에서 Core 5역할을 현행
gemma3:12b이상으로 수행하는 모델이 있는가? 없으면 가장 가까운 후보는 어느 지표에서 얼마나 미달인가?
RQ-C2 — Reasoning Mode
thinking ON은 Core 역할 품질을 올리는가, 지연만 늘리는가? 그 효과의 크기는 모델에 따라 달라지는가?
RQ-C3 — Online vs Local
현재 운영 중인
gemini-3-flash-preview는 로컬 후보 대비 어디에 위치하는가? 10 RPM 페이싱을 포함한 실효 처리량 기준으로도 같은 결론인가?
2.2 조건 — 비대칭 요인 설계
완전 요인 설계(모든 모델 × 두 모드)를 그대로 쓸 수 없다. 기준선 gemma3:12b에 thinking capability가 없기 때문이다. 이것은 설계 결함이 아니라 그 모델의 성질이며, 표에 그대로 표기한다.
| 모델 | 파라미터 | 디스크 | 실측 VRAM | 양자화 | ctx | -N (OFF) |
-T (ON) |
|---|---|---|---|---|---|---|---|
gemma3:12b (기준선) |
12.2B | 7.59 GiB | 7.49 GiB | Q4_K_M | 131K | ✓ | 불가 |
gemma4:12b |
11.9B | 7.04 GiB | 7.51 GiB | Q4_K_M | 262K | ✓ | ✓ |
gemma4:e4b |
8.0B | 8.95 GiB | 3.06 GiB | Q4_K_M | 131K | ✓ | ✓ |
qwen3.5:9b |
9.7B | 6.14 GiB | 5.25 GiB | Q4_K_M | 262K | ✓ | |
gemini-3-flash-preview (현행 운영) |
— | 온라인 | — | — | — | ✓ | ✓ |
실측 VRAM은 2026-09-13 Stage 0의 /api/ps size_vram 값이다(부록 A.5).
총 9셀.
두 가지를 명시해 둔다.
- 양자화가 로컬 4종 전부 Q4_K_M으로 일치한다. 크기 축을 양자화 혼재 없이 읽을 수 있다.
gemma4:e4b는 디스크로 예산을 추정하면 안 된다. 디스크 8.95 GiB(11.9B짜리 7.04 GiB보다 크다)인데 실제 상주는 3.06 GiB다. 활성 파라미터만 올라가는 구조로 보인다. 디스크 기준 설계 예측(§1)이 이 모델에서만 크게 빗나갔으므로, 예산 판정은 실측 VRAM으로만 한다. 표에는 파라미터·디스크·실측 VRAM 셋을 항상 같이 적는다.
2.2.1 후보에서 제외한 것과 근거
| 제외 | 근거 |
|---|---|
구세대 전반 — qwen3 · qwen2.5 · phi4 · olmo2 · glm4 · deepseek-r1 · aya-expanse · mistral-nemo · cogito |
최신 세대가 같은 예산 안에 존재한다. cogito는 레지스트리 기준 “1년 전” v1 Preview |
예산 초과 — qwen3.5:27b(16.22) · gemma4:26b(17.33) · gemma4:31b(18.50) · gpt-oss:20b(12.85) · solar-pro:22b(12.40) · mistral-small:24b(13.35) |
§1의 Core 예산 9.5 GiB 초과. NPC와 공존 불가 |
한국어 특화 모델 — kanana · midm · a.x · hyperclovax-seed · llama-dna · eeve · bllossom · ko-gemma · EXAONE 4.0 |
Ollama 공식 라이브러리에 없다(부록 A.4). hf.co/*-GGUF 경로는 양자화·템플릿이 제각각이라 §2.3 고정 조건을 깬다 |
exaone3.5:7.8b |
아래 별도 |
exaone3.5:7.8b를 Core 후보에서 뺀 이유. 이 모델은 NPC 슬롯과 같은 모델이라 Core로 쓰면 VRAM 추가분이 0이라는 구조적 장점이 있다. 그럼에도 제외한다.
| # | 근거 |
|---|---|
| 1 | E6와 결합한다. VRAM 0이라는 장점은 두 슬롯이 같은 모델일 때만 성립하는데, E6가 NPC를 내리면 그 순간 사라진다. E6가 실패해야만 유효한 선택지를 비교표에 올릴 수 없다 |
| 2 | 컨텍스트가 짧다. 2026-09-13 /api/show 실측 — exaone3.5:7.8b 32,768 / gemma3:12b 131,072 / qwen3.5:9b 262,144 / gemma4:12b 262,144 / gemma4:e4b 131,072. manager_check는 hidden_truth 전문을, advisor_answer는 당일 기록 전체를 받는다. 회차가 쌓일 때 가장 먼저 한계에 닿는다 |
| 3 | 축이 다르다. “VRAM 추가 0”은 품질이 아니라 배포 구성 이득이다. 같은 표에 넣으면 품질×VRAM 축에서 혼자 무한대가 되어 나머지 비교를 읽을 수 없게 만든다 |
exaone3.5:7.8b는 NPC 슬롯 기준선으로 유지한다. Phase 2(E6)의 비교 대상이다.
2.3 고정 조건 (Harness Freeze)
셀마다 동일하게 적용하며, 하나라도 바꾸면 새 실험이다.
| 항목 | 값 |
|---|---|
| 양자화 | 로컬 전부 Q4_K_M. 혼재 금지 |
| 프롬프트 | apps/engine/app/use_cases/prompts.py 현행. 모델별 튜닝 금지 |
| 하네스 | run_with_harness 현행. harness_on=True, 재생성 최대 2회 |
| temperature | 역할별 현행 값 (advisor_answer 0, evaluator_verdict 0.0, 나머지 기본) |
| 시나리오 | scenario_a 현행. 어댑터 무변경 |
| 발화 세트 | §2.4의 4역할 프로브. DEV 세트 그대로 |
| NPC 슬롯 | 측정 중 로드하지 않는다 (§2.4의 프로브가 전부 Core 역할이므로) |
엔진 코드를 바꾸지 않는다. thinking 제어는 러너 안에서 어댑터를 서브클래싱해 주입한다(§4.2). 프로덕션 반영은 실험 결과를 본 뒤의 별도 결정이다.
하네스 조작 금지. “이 모델은 프롬프트를 조금 고치면 통과한다”는 발견은 기록하되 E7 결과에는 반영하지 않는다. 그것은 다른 실험이다.
2.4 측정 대상 — Core 4역할
기존 12문항 corpus는 advisor_answer 하나만 때린다. 가장 어려운 역할이라 대표성은 있으나, planner의 긴 구조화 출력과 evaluator의 판정은 재지 못한다. 네 역할로 나눠 측정한다.
| 역할 | 프로브 출처 | 문항 | 요구 능력 |
|---|---|---|---|
advisor_answer |
2026-09-09 보존 corpus | 12 + 통제 4 | 근거 기반 억제 — 기록에 없는 말 금지 |
planner |
실프롬프트 | 3 | 긴 구조화 출력(4명×6비트) + 어휘 enum 준수 |
manager_check |
실프롬프트 | 3 | 긴 입력(hidden_truth) 소화 + 절제된 판단 |
evaluator_verdict |
실프롬프트 | 3 | 의미 동치 판정 + 근거 표현쌍 제시 |
셀당 25콜. 9셀 × n.
manager_paw는 1차에서 제외한다. 출력이 창작(규칙+부작용)이라 결정적 채점이 불가능하고, 사전등록 통제도 만들기 어렵다. 후보가 좁혀진 뒤 별도로 다룬다.
3. 측정 설계
3.1 판정 원칙
판정 원칙은 하나다 — 후보 모델의 답을 Ground Truth로 쓰지 않는다. 판정은 다음 둘로만 한다.
- 결정적 게이트 — 코드가 계산한다. 사람도 LLM도 개입하지 않는다
- 사전등록 통제(pre-registered expected direction) — 기대 답 방향이 실험 전에 고정된 문항
LLM-as-judge는 1차에서 쓰지 않는다. 후보 5개 중 4개가 로컬이고 기준선도 후보이므로, 지금은 이해충돌 없는 judge를 고를 수 없다. 후보가 2~3개로 좁혀진 뒤 별도 라운드로 붙인다. 그때 judge는 후보가 아닌 제3 모델이어야 하고, judge 일치율(같은 발화 3회)을 셀마다 기록한다.
3.2 Protocol Metrics — 결정적 게이트
3.2.1 Schema Validity Rate — SVR
SVR = 스키마 검증을 통과한 출력 수 / 전체 모델 호출 수
3.2.2 Fallback Rate — FBR
FBR = fallback_used=true 인 호출 수 / 전체 호출 수
폴백은 성공으로 집계하지 않는다. 재생성 2회를 모두 실패해 역할별 대체 문구가 쓰였다는 뜻이다.
3.2.3 Violation Count — VC
하네스가 기록한 위반을 종류별로 센다. 합계 하나로 뭉개지 않는다.
parse / schema / action_vocab / forbidden_word /
non_verbatim_evidence / missing_public_evidence / unknown_person
3.2.4 Legal Action Rate — LAR (planner 전용)
LAR = action_vocab 안의 행동 수 / 생성된 전체 행동 수
현재 planner_output()이 행동 칸을 JSON 스키마 enum으로 제약하므로, provider가 enum을 존중하면 1.0이어야 한다. 1.0이 아니면 그 provider의 structured output이 enum을 안 지킨다는 신호이며, 모델 품질이 아니라 어댑터 문제로 분류한다.
3.2.5 Evidence Grounding Rate — EGR (advisor_answer 전용)
EGR = detail과 evidence_ids를 모두 채운 응답 수 / 전체 응답 수
2026-09-09 03:58 실측에서 이 값이 0/12였다가 코드 수정 후 11/12·10/12로 회복된 이력이 있다(§A.1).
2026-09-13 Stage 1에서 판정 축에서 내렸다. 8셀 전부 정확히 0.83으로 같았고, 비는 2문항이 모든 셀에서 동일했다.
| 비는 문항 | 이유 |
|---|---|
| “호송 당한 사람은 누구야?” | 기록에 없는 사건이다. 근거를 못 다는 것이 정상 동작 |
| “너에게 물어볼 수 있는건 뭐야?” | intervention_interactor의 meta 분기가 LLM을 거치지 않고 처리한다 |
즉 EGR은 코퍼스의 성질이지 모델의 변별력이 아니다. 회귀 감시용으로 계속 기록하되(0.83에서 떨어지면 이상 신호), 후보 순위에는 쓰지 않는다.
3.2.6 Thinking Failure Rate — TFR (-T 셀 전용)
-T 셀에서만 집계한다.
TFR = thinking 실패 호출 수 / -T 셀 전체 호출 수
실패 정의: 빈 content · 미종료 · 토큰 상한 도달 · 최종 출력 malformed · 타임아웃
소형·신형 모델에서 특히 중요하다. 2026-09-13 사전 실측에서 qwen3.5:0.8b가 thinking 기본값으로 content 빈 문자열을 반환해 JSON 파싱에 실패한 사례가 있다(§A.2).
3.3 Pre-registered Control — 의미 축
advisor_answer의 통제 문항은 10개이며, 전부 expected_relation과 expected_evidence_ids가 실험 전에 고정되어 기계 채점된다. 2026-09-09 코퍼스를 그대로 쓴다. RM1(질문 명제의 극성과 인용 사건의 극성을 혼동)이 이 축에서 잡혔다.
| 통제 | 질문 | 기대 | 근거 |
|---|---|---|---|
| PC1 | 채연이 자기 몫을 반쯤 남기는 걸 봤어? | supported | public-2 |
| PC2 | 관리자가 이상한 점은 방송실로 알리라고 말했어? | supported | public-1 |
| PC3 | 채연의 검진 결과가 공개되었어? | contradicted | public-6 |
| PC4 | 채연의 검진 결과가 공개되지 않았어? | supported | public-6 |
| PC5 | 누가 자기 몫을 반쯤 남기는 모습을 봤어? | supported | public-2 |
| PC6 | 채연은 왜 자기 몫을 남겼어? | unknown | public-2 |
| PC7 | 채연의 검진 결과가 내일 공개될 거야? | unknown | public-6 |
| PC8 | 관리자의 방송 지시가 실제로 이행됐어? | unknown | public-1 |
| SPC1 | 채연의 검진 결과가 공개되었어? | supported | public-6 (합성) |
| SPC2 | 채연의 검진 결과가 공개되지 않았어? | contradicted | public-6 (합성) |
SPC1·SPC2는 public-6의 기록을 결과는 공개되지 않았다 → 결과를 공개했다로 뒤집은 합성 fixture다. 같은 질문에 반대 기대가 걸리므로, 모델이 기록을 읽는지 질문 표면만 보는지가 갈린다.
PC3·PC4와 SPC1·SPC2는 각각 극성 쌍이다. 반드시 함께 판정한다(게이트 C4). 한쪽만 통과하는 것은 극성 혼동이 남아 있다는 뜻이며, 2026-09-09에 PC3을 고치자 PC4가 회귀한 이력이 있다.
PCA = 기대 방향과 일치한 통제 수 / 통제 문항 수
3.4 Compute Metrics
품질과 별도 축으로 저장한다. 다만 지연만은 예외로 Hard 게이트다(§5.1 C11~C13) — 아래 이유 때문이다.
3.4.1 지연이 Hard 게이트인 이유
Core 호출은 화면 뒤에 숨지 않는다. 전부 플레이어가 멈춰서 기다리는 자리다.
| 순간 | 역할 | 회차당 콜 | 대기 성격 |
|---|---|---|---|
| 아침 진입 | planner |
1 | 로딩 화면. 하루 1회 |
| 비트 이동 | manager_check |
6 | 장면 전환에 묻힌다 |
| 밤 질문 | advisor_answer |
3 | 질문을 던지고 눈앞에서 기다린다 — 가장 민감 |
| 원숭이손 | manager_paw |
1 | 제안이 뜨는 순간 |
| 밤 채점 | evaluator_verdict |
정답 명제 수만큼 (~10) | 점수가 나올 때까지 대기 |
프로젝트 CLAUDE.md에 ”/play는 느린 응답에서 복구하려고 리로드하지 말 것” 이라는 규칙이 이미 있다. 느린 응답이 판을 날린 이력이 있다는 뜻이다. 품질이 아무리 좋아도 게임에서 못 쓰는 지연은 탈락 사유다.
3.4.2 재시도 배수 — 단발 측정을 믿지 않는다
하네스는 검사에 걸리면 최대 2회 재생성한다(총 3시도). thinking이 켜진 셀에서는 재시도마다 thinking 비용이 곱해진다.
2026-09-13 실측 — gemma4:12b-T:
Stage 0 단발 측정 27초/콜
Stage 1 22문항 실측 약 80초/콜 ← 약 3배
지연 게이트는 단발 값이 아니라 코퍼스 전체의 p95로 판정한다.
3.4.3 저장 항목
- 파라미터 수 · 양자화 · 디스크 크기
- Peak VRAM (
/api/ps의size_vram) - 콜드 스타트 / warm p50 / warm p95 지연
- 출력 토큰 · thinking 토큰 (
-T셀) - 타임아웃 · OOM · provider 오류
- 실효 처리량 — Gemini는 두 값을 분리해서 적는다.
latency_raw_*— API 왕복만. 러너의ThinkingGeminiLLM은_pace_request를 호출하지 않으므로 측정값이 곧 이 값이다latency_effective_*— 프로덕션 배포값.gemini_llm.py:17의 프로세스 전역 10 RPM은 Lock 안에서 sleep하므로 연속 호출의 간격이 60/RPM초 이상으로 강제된다. 따라서effective = max(raw, 60000/RPM)으로 유도한다- 유도값임을 표에 반드시 표기한다. 측정값이 아니다
- 게이트 C11~C13은
effective로 판정한다. 플레이어가 겪는 것이 그 값이다
3.5 결과를 어떻게 읽는가
단일 종합 점수를 만들지 않는다. 가중치가 임의면 합계도 임의다.
주 결과는 다음 넷으로 제시한다.
- Hard Gate 통과 여부 (§5)
- 역할별 지표 — 합산하지 않는다
- Pareto Frontier — 품질 × Peak VRAM, 품질 × p95 지연
- Paired delta — 같은 모델의
-T−-N차이
Core 품질 87.3 같은 숫자는 설명 편의를 위한 보조 요약으로만 쓰고, 모델 선정의 유일한 기준으로 쓰지 않는다.
4. 실험 절차
4.1 Funnel
처음부터 9셀 × 25콜 × n을 전부 돌리지 않는다.
| Stage | 내용 | 차단 조건 |
|---|---|---|
0 protocol |
프로토콜 호환 — 셀당 1콜. 한국어 JSON이 나오는가, thinking 제어가 먹는가, 실제 Peak VRAM은 얼마인가. thinking 가능 모델은 default도 함께 재서 provider 기본값이 어느 셀인지 확정한다(§7 제약 2) |
JSON 파싱 실패 → 해당 셀 탈락, 사유 기록 |
1 smoke |
스모크 — 9셀 × 4역할 × n=1 (25콜) | FBR > 0.5 또는 SVR < 0.9 → 탈락 |
2 formal |
본실험 — 통과 셀 × n=3 | 공식 수치. metrics.yml 적립은 이 단계부터 |
3 concurrency |
동시성 — 최종 후보 + NPC(exaone3.5:7.8b) 공존 Peak VRAM |
축출 발생 시 후보 탈락 |
4 loop |
루프 스모크 — 최종 후보로 게임 1회차 완주 | 크래시 / 폴백 폭주 → “게이트 통과했으나 루프 불가” |
Stage 4가 있는 이유: 프로브 25개를 통과해도 실제 루프에서 NPC·Manager와 엮이면 다를 수 있다. 게이트 통과는 대체 가능과 같지 않다. 채택 결정은 Stage 4 뒤에만 한다.
4.2 thinking 제어
OllamaLLM은 /api/chat에 think 필드를 보내지 않고, GeminiLLM은 thinking_config를 보내지 않는다. 즉 현재 두 어댑터 모두 provider 기본값대로 돌고 있으며, 그 기본값이 무엇인지 측정된 적이 없다.
러너가 어댑터를 서브클래싱해 주입한다. 프로덕션 코드는 변경하지 않는다.
Ollama body["think"] = False | True
Gemini config.thinking_config = ThinkingConfig(thinking_budget=0) # OFF
= ThinkingConfig(include_thoughts=True) # ON
-N 셀에서 thinking이 실제로 꺼졌는지는 응답의 thinking 토큰 수가 0인지로 검증한다. 설정만 보내고 확인하지 않으면 셀 라벨을 신뢰할 수 없다.
4.3 러너
cd backend
.venv/bin/python scripts/run_core_selection.py \
--models gemma3:12b,gemma4:12b,gemma4:e4b,qwen3.5:9b,gemini-3-flash-preview \
--stage protocol
구현 현황 (2026-09-13) — --stage protocol만 구현됐다. Stage 1 이후는 --roles·--n·--think 인자와 함께 추가한다.
| 구성 요소 | 상태 |
|---|---|
ThinkingOllamaLLM — /api/chat에 think 주입, message.thinking 길이 계측 |
구현 |
ThinkingGeminiLLM — thinking_config 주입, usage_metadata.thoughts_token_count 계측 |
구현 |
thinking capability 자동 조회(/api/show) → 불가 모델은 default만 측정 |
구현 |
게이트 C9 자동 검증 (off 셀의 thinking 사용량 = 0) |
구현 |
provider 기본값 판정 (default 셀의 thinking 사용량) |
구현 |
Peak VRAM 수집 (/api/ps size_vram) |
구현 |
Stage 1~4, metrics.yml 적립 |
구현 완료 (2026-09-14) — Stage 4는 scripts/loop_app.py 래퍼 + --stage loop, 적립은 Stage 2부터 |
프로덕션 어댑터(ollama_llm.py · gemini_llm.py)는 변경하지 않았다. thinking 제어는 러너 안의 서브클래스에만 있다.
규칙은 E6 §6과 동일하다 — engine은 import만, 결과는 append만.
4.4 산출물
| 대상 | 위치 |
|---|---|
| 설계·결과 정본 | 이 문서 |
| 줄 단위 수치 | docs/metrics.yml (runner: core_selection) |
| 원문 raw | docs/review-verification/2026-09-13-core-selection/ |
| 러너 | backend/scripts/run_core_selection.py |
metrics.yml 줄 형식
- {"runner": "core_selection", "date": "2026-09-XX", "model": "gemma4:12b", "think": "off",
"stage": "formal", "role": "advisor_answer", "n": 3, "calls": 48,
"svr": 1.0, "fallback_rate": 0.0, "violations": {"non_verbatim_evidence": 0},
"egr": 0.92, "pca": 1.0, "tfr": null,
"latency_p50_ms": 980, "latency_p95_ms": 1600, "peak_memory_gb": 7.6,
"thinking_tokens": 0, "host": "rtx5060ti-16g", "runtime": "ollama-cuda",
"quant": "Q4_K_M", "non_inferior_to_baseline": true}
| 키 | 규칙 |
|---|---|
stage |
§4.1의 Stage 이름을 그대로 쓴다. protocol·smoke는 metrics.yml에 적립하지 않는다 — 원문 artifact에만 남긴다 (§4.1과 일치) |
think |
off / on / n/a(기준선) |
tfr |
-N 셀은 null |
thinking_tokens |
-N 셀에서 0이 아니면 셀 라벨 오류다. 그 줄은 판정에서 뺀다 |
non_inferior_to_baseline |
같은 날 같은 stage의 gemma3:12b 줄과 비교해 러너가 계산 |
5. 게이트
5.1 Hard — 미달 시 후보 제외
| # | 게이트 | 값 |
|---|---|---|
| C1 | SVR | ≥ 0.98 |
| C2 | Fallback Rate | ≤ 0.05 |
| C3 | LAR (planner) | = 1.0 |
| C4 | PCA — PC3·PC4 쌍 | 둘 다 기대 방향 일치 |
| C5 | Peak VRAM (로컬) | ≤ 9.5 GiB |
| C6 | TFR (-T 셀) |
≤ 0.1 |
| C11 | advisor_answer p95 |
≤ 5초 — 질문하고 눈앞에서 기다리는 자리. 타이핑 인디케이터가 “생각하는 중”으로 읽히는 한계 |
| C12 | planner p95 |
≤ 15초 — 아침 로딩 화면, 하루 1회 |
| C13 | 밤 채점 전체 (evaluator_verdict × 정답 명제 수) |
≤ 30초 — 진행 표시가 있을 때 참을 수 있는 범위 |
C11~C13의 값은 UX 통념으로 잡은 것이며 우리 게임에서 체감 검증한 값이 아니다. 플레이테스트로 체감 기준이 나오면 그 값으로 교체한다.
온라인 provider는 페이싱을 포함한 벽시계 시간으로 판정한다. gemini_llm.py의 프로세스 전역 10 RPM은 콜 사이에 6초를 강제하므로, 밤 질문 3회와 채점 10콜만으로 C13을 넘길 수 있다.
5.2 Soft — 보고 필수
| # | 항목 | 값 |
|---|---|---|
| C7 | 셀당 n | ≥ 3 |
| C8 | 기준선 줄 존재 | 같은 날, 같은 stage, 같은 runtime |
| C9 | -N 셀 thinking 토큰 |
= 0 (라벨 검증) |
| C10 | Stage 4 루프 스모크 | 최종 후보에 한해 통과 |
5.3 대체 판정 (Non-inferiority)
후보 M이 기준선
gemma3:12b를 대체할 수 있는 조건: 역할별로 모든 Hard 게이트가 같거나 높고, Peak VRAM ≤ 기준선, p95 지연 ≤ 기준선
| 규칙 | 내용 |
|---|---|
| 역할 단위 비교 | 합산하지 않는다. 기준선이 통과한 역할을 M이 떨어뜨리면 비열등 아님 |
| 동률 | 품질이 같으면 메모리가 작은 쪽 |
| 유의성 | n=3에서 통계적 유의성을 주장하지 않는다. “역할별로 같거나 높다”의 이진 판정이다 |
아무것도 만족하지 않으면 “대체 후보 없음 — gemma3:12b 유지”라고 쓴다. 이것도 결과다.
채택 (2026-09-14, 사용자 결정)
Core 슬롯을 gemma4:12b-N으로 전환했다. 위 비열등 산식의 문자적 결론이 아니라(VRAM 7.51 vs 7.49로 20MiB 초과, evl p50 2,179 vs 976ms), Funnel 0~4 실측 전체를 근거로 한 채택 결정이다:
- 극성쌍(RM1) 통과 — 측정된 로컬 셀 중 유일 (A.7, PC3·PC8·SPC2 n=3 전부)
- 실플레이 evaluator 통제 기대 일치 0.57로 4셀 중 최상, 판정 요동 0 (A.8)
- C11~C13 전 게이트 통과, NPC와 무축출 공존(A.9), 루프 1회차 완주·폴백 0 (A.10)
- 운영 Gemini는 무료 티어 기준(D1 결정)에서 지연·용량이 성립하지 않음 (A.11 추록)
반영 내역: .env CORE_LLM_PROVIDER=ollama · CORE_LLM_MODEL=gemma4:12b · CORE_LLM_THINK=off(신설). thinking 제어는 프로덕션 반영 — ollama_llm.py에 think: bool | None = None(None=필드 미전송, 하위호환), Settings.core_llm_think/npc_llm_think(default/on/off, 알 수 없는 값은 기동 실패), llm_factory.build_llm 배선. 단위 테스트 7건 추가(tests/pure/test_ollama_llm.py), 전체 393 passed·import-linter 4계약 유지. 실서버 검증(8600·pigfarm_test): health core ollama:gemma4:12b, 아침 loop(planner 포함) 12.13s — -N 셀 p95(12,215ms)와 일치, thinking OFF 실작동 확인. D2(운영 Gemini thinking)는 Gemini 이탈로 대상 소멸.
채택 — NPC 슬롯 (2026-09-14, 사용자 결정)
NPC 슬롯을 kanana1.5:8b-q4km(카카오 Kanana 1.5 8B, Apache 2.0)로 전환했다. 근거:
- 라이선스 — 현행
exaone3.5:7.8b는 연구 전용(상업은 LG 별도 계약 필요, A.17 원문 인용). 상업 배포 스택에서 유일한 블로커였다 - 7세 정책 — 상업 후보 3종 중 최상 4/5 (A.17). exaone의 어른화 축(왜=몰라)이 1.0으로 재현되지 않고, 유일 미달(사실대로 0.6)은 단일 케이스 회피 반복로 통과선에 1콜 차이
- 발화 품질 — exaone 기준선 대비 자연스러움 대등권(9:7)·외국 문자 혼입 0/25 (A.17 A/B). 관련성(5:14)은 열세로 관리 항목
- 교체 전 루프 스모크 통과 (A.18) — NPC kanana + Core gemma4:12b 조합 1회차 완주·크래시 0·폴백 0/16
반영 내역: .env NPC_LLM_MODEL=kanana1.5:8b-q4km 한 줄 (provider ollama 유지, kanana는 thinking 미지원이라 NPC_LLM_THINK 불필요 — default 유지). 실서버 검증(8600·pigfarm_test): health npc ollama:kanana1.5:8b-q4km, 발화 실콜 정상(“준 → 몰라. 아직.”).
롤백 절차 (어댑터 패턴 보장): 프로덕션 코드에 모델명 하드코딩 없음 확인(설정 기본값뿐) — .env의 NPC_LLM_MODEL=exaone3.5:7.8b 한 줄 복원이 롤백의 전부다. exaone3.5:7.8b는 이 목적으로 로컬 유지한다(연구·개발 용도는 라이선스 내). 평가용 임시 모델(exaone3.5:2.4b·midm2.0:mini-q4km)과 GGUF 원본은 삭제(약 9GB 회수).
운영 관찰 항목(교체 후): ① 사실 질문 회피(스모크에서는 0/21) ② 질문 관련성 ③ 단답 경향(스모크 평균 11.4자) — 테스터 플레이에서 추적한다.
5.4 E7 자체의 성공 조건
다음 문장 중 하나를 실측으로 쓸 수 있으면 성공이다.
- ”
<M>이 기준선에 비열등하며, Peak {A}→{B} GiB, p95 {C}→{D} ms” - “비열등 후보가 없다. 가장 가까운
<M>은 역할 {r}의 지표 {k}에서 {v}로 미달” - “thinking ON은 {모델들}에서 {지표}를 {값}만큼 바꾸고, {다른 모델}에서는 바꾸지 않는다”
2번도 발표에 쓴다.
6. Figures
| # | 그림 | 축 |
|---|---|---|
| F1 | 조건 매트릭스 | 5모델 × {N, T}. 미실행·불가 셀을 빈칸으로 그대로 노출 |
| F2 | 역할 × 조건 히트맵 | 행 = 9셀, 열 = 4역할. 셀 = Hard 게이트 통과율 |
| F3 | Pareto — 통과 역할 수 × Peak VRAM | 기준선에 수평선. 선 위·왼쪽에 점이 있으면 그것이 후보 |
| F4 | Pareto — 통과 역할 수 × p95 지연 | Gemini는 페이싱 포함 실효값으로 별도 표기 |
| F5 | Thinking paired delta | x = 모델, y = (T − N). 지표별 막대 |
| F6 | Thinking 토큰 × 품질 delta | thinking을 많이 쓴 만큼 값을 했는가 |
| F7 | 실패 분류 | 위반 종류별 누적. 어느 모델이 어떤 방식으로 실패하는가 |
F3·F4의 세로축은 Hard 게이트를 전부 통과한 역할 수(0~4) 라는 서수값이다. §3.5가 금지한 가중합 종합 점수를 쓰지 않는다.
전부 실측값만. Stage 1(smoke) 값을 Stage 2(formal) 그림에 섞지 않는다. 데이터가 없으면 그리지 않고 “N=0”이라고 쓴다.
7. 알려진 제약
| 제약 | 처리 |
|---|---|
기준선 gemma3:12b에 thinking이 없다 |
비대칭 표로 그대로 표기. RQ-C2는 나머지 4모델 안에서만 답한다 |
해소 (2026-09-13 Stage 0). 기본값 ON — 콜당 thinking 774토큰. 현행 운영은 gemini-3-flash-preview-T 셀이다 |
|
manager_paw 미측정 |
결정적 채점 불가. 후보 축소 후 별도 라운드 |
| LLM-judge 부재 | 자유 답변의 의미 정확도는 1차 범위 밖. 통제 문항으로만 의미 축을 본다 |
| n=3 | 표본이 작다. 이진 판정만 하고 통계적 유의성은 주장하지 않는다 |
| Gemini는 Peak VRAM이 없다 | 로컬과 같은 축에 놓지 않는다. F3에서 별도 표기 |
| 프로브 ≠ 실제 루프 | Stage 4 통과 전에는 “대체 가능”이라고 쓰지 않는다 |
8. E6 — NPC Slot Descent (Phase 2, 미착수)
상세 설계는 REMAKE_DAY_AI_Agent_Evaluation_PART1_부록_E6_Model_Descent_v0.1에 있다. 이 문서는 E7과의 관계와 선행 조건만 기록한다.
8.1 두 축으로 갈라진다
방향 전환(예산 최적화 우선)을 반영하면 E6는 두 질문으로 나뉜다.
| 축 | 질문 | family 제약 |
|---|---|---|
| 선택 축 | 예산 안에서 7세 역할을 가장 잘하는 NPC는? | 없음 — 섞는다 |
| 인과 축 | 몇 B까지 7세인가? 어느 항목이 먼저 무너지나? | qwen3.5 안에서 크기만 (E6 원형) |
선택 축이 실무 결론을 내고, 인과 축이 발표용 그림(E6 Chart 7)을 만든다. 둘은 충돌하지 않는다.
8.2 착수 전 해결할 것 — 전부 해소 (2026-09-14, A.12)
E6 문서 작성 이후 실측으로 드러난 문제들이었다. scripts/run_model_descent.py 구현과 함께 해소했다.
| # | 문제 | 해소 |
|---|---|---|
| 1 | qwen3.5:2b-q4_K_M 재pull로 9b/4b/2b Q4_K_M 통일. 0.8b는 허브에 Q4 태그가 없어 Q8_0 편차 기록(정밀도 우위 쪽이라 하강 결론에 보수적) |
|
| 2 | 러너가 capabilities 조회 후 thinking 모델에 ThinkingOllamaLLM(think=False) 강제 + thinking 문자 누계 0 검증 |
|
| 3 | A.12에서 n=5 재측정 (judge 3표 규칙 — 2026-09-06 행과 직접 비교 금지) | |
| 4 | judge 3표 다수결 + 전원일치율(D3 ≥90%) 구현 — 전 셀 0.96~1.00 통과 |
부록 A — 실측 이력
A.1 2026-09-09 · Core advisor_answer 폴백 붕괴와 회복
원문: docs/review-verification/2026-09-09-connected-implementation/real-model-artifacts/probes-*.json (10회분, 전부 gemma3:12b)
같은 12문항 corpus를 하루 동안 열 번 돌린 기록이다.
| 시각 (UTC) | 폴백 | 위반 | detail 있음 | 근거 있음 |
|---|---|---|---|---|
| 03:58 | 12/12 | 36 | 0 | 0 |
| 04:17 | 0/12 | 0 | 11 | 10 |
| 05:41 | 0/12 | 0 | 11 | 10 |
| 05:54 | 0/12 | 2 | 11 | 10 |
| 06:10 | 0/12 | 0 | 11 | 10 |
| 06:28 | 1/12 | 3 | 11 | 10 |
| 06:38 | 0/12 | 0 | 11 | 10 |
| 06:47 | 1/12 | 3 | 11 | 10 |
| 07:19 | 0/12 | 1 | 11 | 10 |
| 07:35 | 0/12 | 0 | 11 | 10 |
해석. 12/12 폴백은 첫 판 한 번뿐이었다. 위반은 전부 non_verbatim_evidence였고, 19분 뒤 근거 인용 계약을 고치자 같은 모델이 0/12로 돌아왔다. 당시 보고서도 원인을 “동일 prompt에 이전 위반 이유를 넣지 않아 재생성이 같은 누락을 반복하는 양상” 으로 지목했고, 현재 코드에는 그 수정(retry_feedback=True)이 intervention_interactor.py:267 한 곳에만 들어가 있다.
Core를 Gemini로 전환한 것은 08:05~08:09이다. gemma3:12b가 0/12로 약 4시간 안정된 뒤였다.
미해결로 남은 것은 RM1이다 — 질문 명제의 극성과 인용 사건의 극성을 혼동하는 경로(PC3/PC4 쌍). 설계 문서에 “adapter 전환 성공은 기존 Ollama RM1 의미 오판이 해결됐다는 증거가 아니다” 라고 적혀 있고, Gemini 전환 후 RM1이 닫혔다는 기록은 없다. E7 §3.3이 이 축을 다시 잰다.
A.2 2026-09-13 · thinking 기본값 실측
같은 프롬프트·같은 스키마, /api/chat 직접 호출.
| 모델 | think 기본값 | think: false |
|---|---|---|
qwen3.5:4b |
29,558 ms · thinking 11,716자 | 491 ms |
qwen3.5:0.8b |
16,048 ms · content 빈 문자열 → JSON 파싱 실패 | 393 ms |
해석. thinking을 제어하지 않으면 0.8B는 모델 능력이 아니라 하네스 설정 때문에 탈락으로 기록되고, 지연은 60배 부풀려진다. E7 §4.2와 E6 선행 조건 2가 여기서 나왔다.
A.3 2026-09-13 · gemma3:12b Core 3역할 지연
RTX 5060 Ti, 실제 시나리오 데이터, 각 3회. 지연은 run_with_harness 전체 왕복이다.
| 역할 | 성공 | 폴백 | 중앙값 | 최대 | 입력 |
|---|---|---|---|---|---|
planner |
3/3 | 0 | 12,241 ms | 15,413 ms | 2,044자 |
manager_check |
3/3 | 0 | 964 ms | 1,119 ms | 523자 |
evaluator_verdict |
3/3 | 0 | 999 ms | 1,082 ms | 1,088자 |
해석. planner 폴백 0/3이다. 2026-09-08 review.md가 기록한 “Planner 81/81 전량 폴백”은 재현되지 않는다. 당시 원인은 어휘 사전 불일치('혼자 있다' 39건 · '소등' 18건 — 사전에는 "혼자 있는다")였고, 현재는 planner_output()이 행동 칸을 Literal[tuple(action_vocab)] enum으로 제약해 구조적으로 막혀 있다.
기록에 남은 Gemini 수치는 jekyll.md 기준 6문항 5.08~10.42초다. 여기에 프로세스 전역 10 RPM 페이싱이 더해진다.
A.4 2026-09-13 · 후보 인벤토리
Ollama 레지스트리 매니페스트 직접 조회. 최신 세대(2026-09 기준 1주 이내 갱신) 중 예산 내:
qwen3.5 0.8b 0.96 · 2b 2.55 · 4b 3.16 · 9b 6.14 GiB (27b 16.22 · 35b 22.23 — 예산 초과)
gemma4 e2b 6.67 · 12b 7.04 · e4b 8.95 GiB (26b 17.33 · 31b 18.50 — 예산 초과)
공식 라이브러리에 없는 것으로 확인된 한국어 특화 모델: kanana · midm · a.x · hyperclovax-seed · llama-dna · eeve · bllossom · ko-gemma. EXAONE도 exaone3.5·exaone-deep까지이며 4.0은 없다. hf.co/<repo>-GGUF 경로는 가능하나 양자화·템플릿이 제각각이라 같은 조건 비교가 깨진다 — 넣으려면 별도 축으로 분리하고 “공식 라이브러리 밖”을 표기한다.
구세대로 제외: qwen3 · qwen2.5 · phi4 · olmo2 · glm4 · deepseek-r1 · aya-expanse · mistral-nemo · cogito(v1 Preview, 1년 전).
A.5 2026-09-13 · E7 Stage 0 — 프로토콜 호환
원문: docs/review-verification/2026-09-13-core-selection/stage0-protocol-20260913T114748Z.json
프로브: evaluator_verdict 실프롬프트 1콜, temperature 0.0. 정답 주장 “이송은 출하를 뜻한다” × 후보 4개.
사전등록 기대: 후보 2(“트럭에 실려 가면 돌아오지 못한다”)가 정답과 같은 일을 가리키므로 confirmed 또는 partial.
| 모델 | think | ok | verdict | 기대일치 | ms | thinking | VRAM GiB |
|---|---|---|---|---|---|---|---|
gemma3:12b |
default | O | confirmed | O | 995 | 0 | 7.49 |
gemma4:12b |
default | O | confirmed | O | 141,293 | 3,678 | 7.51 |
gemma4:12b |
off | O | none | X | 1,656 | 0 | 7.51 |
gemma4:12b |
on | O | confirmed | O | 27,090 | 3,678 | 7.51 |
gemma4:e4b |
default | O | partial | O | 13,650 | 1,838 | 3.06 |
gemma4:e4b |
off | O | none | X | 663 | 0 | 3.06 |
gemma4:e4b |
on | O | none | X | 5,554 | 1,724 | 3.06 |
qwen3.5:9b |
default | X | — | X | 153,573 | 13,932 | 5.25 |
qwen3.5:9b |
off | O | none | X | 602 | 0 | 5.25 |
qwen3.5:9b |
on | X | — | X | 151,176 | 13,932 | 5.25 |
gemini-3-flash-preview |
default | O | confirmed | O | 5,601 | 774 | — |
gemini-3-flash-preview |
off | O | confirmed | O | 1,677 | 0 | — |
gemini-3-flash-preview |
on | O | confirmed | O | 9,291 | 774 | — |
확정된 사실
게이트 C9 통과. off 셀 네 개 모두 thinking 사용량 0이다. 설정이 provider에 실제로 전달되며, 셀 라벨을 신뢰할 수 있다.
provider 기본값은 전부 ON이다. gemma4:12b 3,678 · gemma4:e4b 1,838 · qwen3.5:9b 13,932 · gemini-3-flash-preview 774 (thinking 사용량). 현행 운영 Core는 -T 셀에서 돌고 있었다. 어댑터에 제어를 주입하지 않았다면 로컬 신형 셋도 전부 -T로 측정됐을 것이다.
qwen3.5:9b-T 탈락. default·on 두 조건에서 JSON 생성에 실패했다(151~153초, thinking 13,932). TFR = 1.0으로 게이트 C6(≤0.1) 미달이다. -N은 602ms에 정상 동작하므로 생존한다.
gemma4:e4b의 디스크-VRAM 괴리. 디스크 8.95 GiB, 상주 3.06 GiB. §1의 디스크 기준 예산 추정이 이 모델에서만 빗나갔다. 이후 예산 판정은 실측 VRAM으로만 한다.
결론이 아닌 관측
thinking을 끈 로컬 신형 셋이 모두 기대 판정을 놓쳤고(none), 기준선 gemma3:12b는 thinking 없이 995ms에 맞췄다. n=1이며 Stage 0은 프로토콜 호환을 보는 단계다. 품질 판정으로 인용하지 않는다. Stage 1에서 4역할로 확인한다.
기타
- Gemini 응답에
thought_signaturenon-text part 경고가 발생한다. 파싱은 성공한다 gemma4:12bdefault141초는 콜드 스타트를 포함한 값으로 보인다. 같은 조건의on은 27초다
Stage 0 통과 셀
| 셀 | 상태 |
|---|---|
gemma3:12b-N |
통과 (기준선) |
gemma4:12b-N · gemma4:12b-T |
통과 |
gemma4:e4b-N · gemma4:e4b-T |
통과 |
qwen3.5:9b-N |
통과 |
qwen3.5:9b-T |
탈락 — JSON 생성 실패 |
gemini-3-flash-preview-N · -T |
통과 |
9셀 중 8셀 생존.
A.6 2026-09-13 · E7 Stage 1 — smoke · advisor_answer
원문: docs/review-verification/2026-09-13-core-selection/stage1-smoke-advisor-20260913T124645Z.json
코퍼스: 2026-09-09 보존분 그대로 — 공개 관찰 11건 · 테스터1 질문 12개 · 사전등록 통제 10개.
8셀 × 22문항 = 176콜, n=1. Gemini 지연은 raw(페이싱 미포함)다.
| model | think | 폴백 | EGR | PCA | PC근거 | 극성쌍 | p50 ms | p95 ms | thinking | VRAM GiB |
|---|---|---|---|---|---|---|---|---|---|---|
gemma3:12b (기준선) |
— | 0.00 | 0.83 | 0.70 | 1.00 | X | 3,394 | 4,207 | 0 | 7.49 |
gemma4:12b |
off | 0.00 | 0.83 | 0.90 | 1.00 | O | 2,918 | 4,231 | 0 | 7.51 |
gemma4:12b |
on | 0.32 | 0.83 | 0.70 | 1.00 | X | 40,234 | 194,589 | 132,487 | 7.51 |
gemma4:e4b |
off | 0.00 | 0.83 | 0.70 | 1.00 | X | 1,544 | 2,502 | 0 | 3.06 |
gemma4:e4b |
on | 0.00 | 0.83 | 0.80 | 1.00 | X | 7,894 | 11,546 | 46,389 | 3.06 |
qwen3.5:9b |
off | 0.09 | 0.83 | 0.50 | 1.00 | X | 3,713 | 6,871 | 0 | 5.25 |
gemini-3-flash-preview |
off | 0.00 | 0.83 | 1.00 | 0.90 | O | 1,720 | 2,138 | 0 | — |
gemini-3-flash-preview |
on | 0.00 | 0.83 | 1.00 | 0.90 | O | 9,138 | 13,443 | 29,446 | — |
통제별 판정
| 셀 | PC1 | PC2 | PC3 | PC4 | PC5 | PC6 | PC7 | PC8 | SPC1 | SPC2 |
|---|---|---|---|---|---|---|---|---|---|---|
gemma3:12b |
O | O | X | O | O | O | O | X | O | X |
gemma4:12b-N |
O | O | O | O | O | O | X | O | O | O |
gemma4:12b-T |
O | O | O | O | X | O | X | O | O | X |
gemma4:e4b-N |
O | O | X | O | O | O | X | O | O | X |
gemma4:e4b-T |
O | O | X | O | O | O | O | O | O | X |
qwen3.5:9b-N |
O | O | X | X | X | O | O | O | X | X |
gemini-N |
O | O | O | O | O | O | O | O | O | O |
gemini-T |
O | O | O | O | O | O | O | O | O | O |
확정된 사실
RQ-C2 — thinking ON은 이 역할에서 비용만 늘린다. 게이트 C11(p95 ≤ 5초)에 -T 셀이 전부 탈락했고, 생존한 넷은 예외 없이 OFF다.
| 셀 | p95 | C11 |
|---|---|---|
gemini-N |
2,138 | 통과 |
gemma4:e4b-N |
2,502 | 통과 |
gemma3:12b |
4,207 | 통과 |
gemma4:12b-N |
4,231 | 통과 |
qwen3.5:9b-N |
6,871 | 탈락 |
gemma4:e4b-T |
11,546 | 탈락 |
gemini-T |
13,443 | 탈락 |
gemma4:12b-T |
194,589 | 탈락 (38배) |
품질로도 이득이 없다. gemini는 ON/OFF의 PCA가 1.00으로 같은데 p50이 5.3배다. gemma4:12b는 ON에서 폴백 0.00→0.32, PCA 0.90→0.70, 극성쌍 O→X로 오히려 무너진다. 반면 gemma4:e4b는 ON에서 PCA가 0.70→0.80으로 올랐다 — 효과가 모델마다 반대 방향이며, 일률적으로 말할 수 없다.
RM1이 여전히 열려 있고, 기준선이 그 증거다. gemma3:12b는 PC3·SPC2·PC8을 놓쳤다. 2026-09-09에 미해결로 남은 극성 혼동이 오늘 그대로 재현된다(§A.1). Gemini 전환 후에도 확인된 적이 없었다.
RM1을 넘는 셀이 존재한다. gemini(ON·OFF 모두)와 gemma4:12b-N이 극성쌍 둘을 모두 통과했다. 로컬에서 통과한 것은 gemma4:12b-N 하나뿐이다.
PC근거는 전 로컬 셀 1.00이다. 어느 기록을 봐야 하는지는 모두 맞힌다. 틀리는 것은 그 기록이 명제를 지지하는지 반박하는지다. 검색이 아니라 판정의 문제다.
qwen3.5:9b는 완전 탈락. -T는 Stage 0(JSON 생성 실패), -N은 여기서 PCA 0.50 최하위 + C11 미달.
현행 운영(gemini-T)은 같은 품질의 더 느린 셀이다. gemini-N과 PCA·PC근거·극성쌍이 모두 동일한데 p50이 5.3배다. gemini_llm.py에 thinking_config(thinking_budget=0)을 넣으면 품질 손실 없이 지연이 줄어든다.
측정의 한계
Gemini 지연은 페이싱을 포함하지 않은 raw 값이다. 러너의 ThinkingGeminiLLM은 _pace_request를 호출하지 않는다. 프로덕션은 프로세스 전역 10 RPM이므로 연속 호출 간격이 6초로 강제된다 — 밤 질문 3회를 연속으로 하면 2·3번째는 약 7.7초를 기다리며, 유도 effective 기준으로는 C11 탈락이다. 모델이 느린 것이 아니라 페이싱 설정이 느리다. Stage 2에서 raw와 effective를 분리해 적는다.
n=1이다. 이 표의 숫자로 순위를 확정하지 않는다. Stage 2(n=3, 4역할)가 공식 수치다.
Stage 1 결과 — Stage 2 진출 셀
C11 통과 + Stage 1 게이트(폴백 ≤ 0.5) 통과:
| 셀 | 근거 |
|---|---|
gemma3:12b |
기준선. 비교 대상이므로 필수 |
gemma4:12b-N |
PCA 0.90, 극성쌍 통과 — 로컬 최고 |
gemma4:e4b-N |
기준선과 품질 동등, p95 40% 빠름, VRAM 59% 작음 |
gemini-3-flash-preview-N |
PCA 1.00, 극성쌍 통과, p95 최저 |
8셀 → 4셀. 탈락: -T 셀 3개(C11), qwen3.5:9b-N(PCA·C11).
A.7 2026-09-13 · E7 Stage 2 — formal · 4역할 × n=3
원문: docs/review-verification/2026-09-13-core-selection/stage2-formal-20260913T132023Z.json
4셀 × 4역할 × n=3 = 372콜. Stage 1 통과 셀만. 이것이 E7의 공식 수치다.
| 셀 | 폴백 | PCA | PC근거 | 극성쌍 | adv p50 | adv p95 | LAR | pln p95 | eval 기대 | evl p50 | VRAM GiB |
|---|---|---|---|---|---|---|---|---|---|---|---|
gemma3:12b (기준선) |
0.00 | 0.70 | 1.00 | X | 3,391 | 4,473 | 1.0 | 12,709 | 1.00 | 976 | 7.49 |
gemma4:12b-N |
0.00 | 0.90 | 1.00 | O | 2,907 | 4,215 | 1.0 | 12,215 | 0.67 | 1,635 | 7.51 |
gemma4:e4b-N |
0.00 | 0.70 | 1.00 | X | 1,532 | 2,491 | 1.0 | 6,234 | 0.67 | 519 | 3.06 |
gemini-3-flash-N |
0.00 | 1.00 | 0.90 | O | 1,734 | 2,238 | 1.0 | 6,058 | 1.00 | 1,559 | — |
통제별 통과율 (n=3)
| 셀 | PC1 | PC2 | PC3 | PC4 | PC5 | PC6 | PC7 | PC8 | SPC1 | SPC2 |
|---|---|---|---|---|---|---|---|---|---|---|
gemma3:12b |
1.00 | 1.00 | 0.00 | 1.00 | 1.00 | 1.00 | 1.00 | 0.00 | 1.00 | 0.00 |
gemma4:12b-N |
1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 0.00 | 1.00 | 1.00 | 1.00 |
gemma4:e4b-N |
1.00 | 1.00 | 0.00 | 1.00 | 1.00 | 1.00 | 0.00 | 1.00 | 1.00 | 0.00 |
gemini-3-flash-N |
1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
통과율이 전부 0.00 또는 1.00이다 — n=3 반복에서 흔들리지 않는다. 우연이 아니라 모델의 성질이다.
게이트 판정 (effective 기준)
| 셀 | C11 raw | C11 eff | C11 | C12 eff | C12 | C13 총 | C13 |
|---|---|---|---|---|---|---|---|
gemma3:12b |
4,473 | 4,473 | O | 12,709 | O | 9,760 | O |
gemma4:12b-N |
4,215 | 4,215 | O | 12,215 | O | 16,350 | O |
gemma4:e4b-N |
2,491 | 2,491 | O | 6,234 | O | 5,190 | O |
gemini-3-flash-N |
2,238 | 6,000 | X | 6,058 | O | 60,000 | X |
확정된 사실
Gemini는 모델이 아니라 우리 페이싱 설정 때문에 탈락했다. raw p95 2,238ms로 4셀 중 가장 빠르고 품질도 전 지표 1위인데, gemini_llm.py의 프로세스 전역 10 RPM이 콜 간격을 6초로 강제한다. 밤 채점은 정답 명제 10개 × 6초 = 60초로 C13(30초)의 2배다. 페이싱 값을 바꿀 수 있다면 판정이 뒤집힌다 — 쿼터 제약과 함께 별도로 판단할 사안이다.
gemma4:12b-N에서 RM1이 닫힌다. 기준선이 못 넘던 PC3·PC8·SPC2를 n=3 전부 통과했다. 2026-09-09 이후 열려 있던 극성 혼동이 이 모델에서는 발생하지 않는다. 지연·VRAM은 기준선과 사실상 동일하다(4,215 vs 4,473ms / 7.51 vs 7.49 GiB) — 같은 비용에 RM1이 닫힌다.
그러나 §5.3 기준으로 비열등은 아니다. 기준선이 통과한 evaluator_verdict를 떨어뜨렸다(1.00 → 0.67). 역할 단위 비교 규칙상 합이 같거나 높아도 비열등이 아니다. 아래 한계를 함께 읽어야 한다.
gemma4:e4b-N은 효율 축의 답이다. 품질은 기준선과 동등(PCA 0.70, 극성쌍 X)인데 adv p95 44%·pln p95 51%·밤 채점 47% 빠르고 VRAM은 41%(3.06 vs 7.49 GiB)다. 품질을 올리지는 못하지만 같은 품질을 훨씬 싸게 낸다.
전 셀 공통 — 하네스는 안정적이다. 4셀 × 4역할 372콜에서 폴백 0.00, 오류 0이다. planner LAR은 4셀 모두 1.0으로, 2026-09-08의 “Planner 81/81 전량 폴백”은 스키마 enum으로 완전히 해소됐음이 n=36으로 확인된다. manager_check는 긴 hidden_truth 입력을 네 모델 모두 소화했다.
evaluator_verdict 실패의 정체 — 이 통제는 약하다
gemma4 두 모델이 놓친 것은 같은 케이스 하나다(3케이스 × 3반복 중 3회 = 그 케이스 전부).
정답 주장 "이송은 출하를 뜻한다"
후보 "트럭에 실려 가면 돌아오지 못한다"
기대 confirmed 또는 partial
받음 none ← gemma4:12b · gemma4:e4b 둘 다
이 기대값은 2026-09-09 코퍼스가 아니라 이 문서의 저자가 직접 쓴 것이다. PC1~SPC2와 달리 외부에서 사전등록된 값이 아니므로 증거력이 약하다. 실제로 “돌아오지 못한다”는 “출하된다”가 말하지 않는 결과를 덧붙이므로 none 판정에도 근거가 있다.
다만 EVALUATOR_VERDICT_SYSTEM 프롬프트가 "’이송된다’≈’실려 간다’≈’출하된다’“를 명시적 동의어로 제시하고 있으므로, 최소 partial은 나와야 한다는 해석도 성립한다.
주목할 점은 방향이다. gemma4 두 모델이 기준선보다 엄격하다. 이 프로젝트는 2026-09-06에 “Evaluator verdict 분포가 극단적으로 엄격해 none으로 치우친다” 는 문제로 3.1% 합격률을 겪은 이력이 있다. 더 엄격한 채점기는 이 게임에서 알려진 위험이다.
조치: evaluator_verdict 통제 3건을 실제 플레이 로그에서 뽑은 제출문으로 교체한다. DB에 41.7점대 8건·30점대 12건이 남아 있다(review.md). 자작 케이스로 채점 역할의 우열을 판정하지 않는다.
측정의 한계
| 한계 | 내용 |
|---|---|
evaluator_verdict 통제가 자작 |
위 참조. 실플레이 제출문으로 교체 전에는 이 역할의 우열을 확정하지 않는다 |
manager_paw 미측정 |
창작 출력이라 결정적 채점 불가. 여전히 범위 밖 |
| Gemini effective는 유도값 | max(raw, 6000ms). 실제 페이싱을 태운 측정이 아니다 |
| n=3 | 통과율이 전부 0/1로 갈려 안정적이지만, 통계적 유의성은 주장하지 않는다 |
| Stage 3·4 미실행 | 동시성·루프 완주 미확인. “대체 가능”이라고 쓸 수 없다 |
A.8 2026-09-14 · E7 Stage 2 보강 — evaluator_verdict 실플레이 통제 재평가
원문: docs/review-verification/2026-09-13-core-selection/stage2-formal-20260914T021635Z.json
A.7의 조치(“자작 케이스로 채점 역할의 우열을 판정하지 않는다”)를 이행했다. 자작 통제 3건을 실제 플레이 제출문 14건으로 교체하고 evaluator_verdict만 재측정했다 (4셀 × 14케이스 × n=3 = 168콜, --roles evaluator). 다른 3역할은 프로브가 바뀌지 않아 A.7 수치가 그대로 유효하다.
기대 판정은 실험 전에 고정했다 — docs/review-verification/2026-09-14-eval-cases/CONFIRMED-eval-cases.md (confirmed 4 · partial 5 · none 5). 재료는 DB 제출문 4건: 탭 0 사람 상한 2건(41.7), 테스터3 3회차(76.7, 1,028자 덩어리 칸), 테스터4 2회차(66.5, 사람 통과 판). 당시 프로덕션 verdict는 자기모순이 실측되어(동일 입력 재제출에서 confirmed→none 뒤집힘 등) 정답으로 쓰지 않았다.
결과
| 셀 | eval 기대 (14×3) | flip | evl p50 | evl p95 | 폴백 | 오류 | C13 |
|---|---|---|---|---|---|---|---|
gemma3:12b (기준선) |
0.36 | 0/14 | 997 | 1,088 | 0.00 | 0 | O |
gemma4:12b-N |
0.57 | 0/14 | 2,179 | 2,735 | 0.00 | 0 | O |
gemma4:e4b-N |
0.48 | 1/14 | 543 | 727 | 0.00 | 0 | O |
gemini-3-flash-N |
0.50 | 0/14 | 1,502 | 1,779 | 0.00 | 0 | X (페이싱 유도값) |
케이스별 판정 (n=3 · ⚡=rep 간 뒤집힘)
| 케이스 | 기대 | gemma3:12b | gemma4:12b-N | gemma4:e4b-N | gemini-3-flash-N |
|---|---|---|---|---|---|
| A1 “채연이 아프다”←”열이 나지만 숨긴다” | confirmed | partial ✗ | O | O | O |
| A2 이송될까 봐 숨겼다 | confirmed | O | O | O | O |
| A3 옆 구역 (언급 없음) | none | O | O | O ⚡(1/3 conf) | O |
| A4 다른 종 ← “가축/사육사” | confirmed | O | O | O | O |
| A5 구역 폐쇄 (언급 없음) | none | partial ✗ | O | O | O |
| A6 이송 규정 ← 절반 언급 | partial | conf ✗ | conf ✗ | conf ✗ | conf ✗ |
| B1 검진 회피 ← 절반 언급 | partial | conf ✗ | conf ✗ | conf ✗ | conf ✗ |
| B2 정체 (관찰 나열뿐) | none | partial ✗ | O | O | O |
| C1 감염 확산 ← 1,028자 덩어리 | none | O | O | conf ✗ | partial ✗ |
| C2 다른 종 ← 덩어리 “가축처럼 관리” | partial | none ✗ | conf ✗ | conf ✗ | conf ✗ |
| D1 구역 폐쇄 ← 460자 덩어리 | none | partial ✗ | conf ✗ | conf ✗ | conf ✗ |
| D2 이송 규정 ← “옮겨지면 안좋은 일” | partial | conf ✗ | conf ✗ | conf ✗ | conf ✗ |
| D3 다른 종 ← “사람이 아닌 취급” | partial | none ✗ | conf ✗ | none ✗ | conf ✗ |
| D4 “채연이 아프다”←”병에 걸린 것 같다” | confirmed | O | O | O | O |
확정된 사실
A.7의 evaluator_verdict 우열은 실플레이 통제에서 역전됐다. 자작 통제의 1.00(기준선) 대 0.67(gemma4)이, 실플레이 통제에서 0.36 대 0.57이 됐다. A.7이 “비열등 아님”의 유일한 근거로 삼은 “기준선이 통과한 역할을 떨어뜨렸다”는 전제가 이 측정에서는 성립하지 않는다 — 이 역할에서 기준선보다 높은 값을 낸 셀은 gemma4:12b-N이다.
기준선의 운영 결함이 통제로 재현됐다. A1은 프롬프트 자신의 예시(정답 “A가 아프다” ← 후보 “A가 열이 나는 것 같다” → confirmed, rule 1)와 동형인데 기준선만 3/3 전부 partial을 냈다. 같은 오판이 실제 플레이 로그(a316a730 등)에도 남아 있다. 또한 기준선은 A5·B2·D1에서 근거 없는 partial을 낸다 — 관대한 방향의 오답이며, “gemma4가 엄격해서 위험하다”는 A.7의 우려 방향과 반대다.
partial 경계는 4셀 공통 실패다. partial 기대 5건(A6·B1·C2·D2·D3)에서 4셀 × 15회 중 partial이 나온 적이 한 번도 없다(confirmed 또는 none으로 갈림). 이것은 모델 선택으로 닫히는 문제가 아니라 EVALUATOR_VERDICT_SYSTEM의 partial 정의가 어느 모델에게도 작동하지 않는다는 뜻이다 — review.md 5순위(판정 프롬프트 정량화)와 연결된다.
덩어리 칸은 채점기 공통 취약점이다. D1(460자 덩어리 ← 폐쇄 명제)은 4셀 전부 오판했다. 테스터4의 실제 통과(66.5)를 만든 바로 그 매칭이 통제 조건에서 재현된다. C1(1,028자)은 2셀이 버티고 2셀이 넘어졌다. 덩어리 유입 자체를 끊지 않으면(source_claims의 8칸 초과 몰아넣기) 어떤 채점 모델을 골라도 이 축은 남는다.
판정은 대체로 결정적이다. temperature 0.0에서 rep 간 뒤집힘은 56케이스-셀 중 1건(gemma4:e4b A3). 프로덕션에서 관측된 Gemini 뒤집힘(동일 입력 confirmed→none, 테스터3 4·5회차)은 이 n=3에서는 재현되지 않았다.
측정의 한계
| 한계 | 내용 |
|---|---|
| 기대 판정의 저자 | 사전 등록으로 고정했지만 단일 저자 확정이다. 특히 partial 5건은 4셀 전원이 불일치했으므로 기대값 자체의 경계 논쟁 여지를 기록해 둔다 (사전 등록이므로 결과에는 반영하지 않는다) |
| Gemini thinking 잔존 신호 | -N 셀인데 응답에 thought_signature 파트가 붙는다 (SDK 경고 42회). 지연에 thinking이 섞였을 가능성 — 라벨 오류로는 처리하지 않고 기록만 한다 |
| §5.3 재판정은 하지 않는다 | 품질 축은 위와 같이 바뀌었으나 VRAM(7.51 vs 7.49)·evl 지연(2,179 vs 997)의 문자적 비교가 남아 있다. 비열등 선언은 별도 판단 |
| Stage 3·4 미실행 | 변함없다. “대체 가능”이라고 쓸 수 없다 |
A.9 2026-09-14 · E7 Stage 3 — concurrency · 후보 + NPC 동시 상주
원문: docs/review-verification/2026-09-13-core-selection/stage3-concurrency-20260914T022551Z.json
--stage concurrency를 러너에 구현해 실행했다. 프로토콜: 후보·NPC 외 상주 모델 언로드 → NPC(exaone3.5:7.8b) 먼저 상주(프로덕션 상태 재현) → 후보 로드 → NPC 대화 콜 ↔ Core 콜 교대 3라운드(2라운드째는 가장 무거운 planner 콜), 매 콜 직후 /api/ps 스냅샷으로 상주·부분 오프로드(size_vram < size)를 확인. GPU는 nvidia-smi 실측.
결과
| 후보 | pair peak VRAM | GPU peak (실측) | 교대 구간 축출 | 오프로드 | NPC 콜 ms | Core 콜 ms | 판정 |
|---|---|---|---|---|---|---|---|
gemma4:12b-N |
12.34 GiB | 13,326 / 16,311 MiB (81.7%) | 0 / 6스냅샷 | 0 | 173~219 | 1,905~2,125 (planner 12,174) | 통과 |
gemma4:e4b-N |
7.89 GiB | 9,520 / 16,311 MiB (58.4%) | 0 / 6스냅샷 | 0 | 230~1,007 | 480~625 (planner 5,760) | 통과 |
확정된 사실
두 후보 모두 교대 구간에서 축출 없이 공존한다. 교대 6스냅샷 전부에서 후보와 NPC가 동시 상주했고, 부분 CPU 오프로드도 0이다. 재로드를 시사하는 지연 스파이크도 없다 — NPC 콜은 워밍 후 200ms대, Core 콜은 Stage 2 단독 측정과 같은 범위다.
exaone3.5:7.8b 상주 실측은 4.83 GiB다. 이 문서 §2.2의 4.14 GiB보다 0.69 크다(측정 시점의 컨텍스트 할당 차이로 추정). pair peak은 4.83 기준으로 12.34 / 7.89 GiB이며 예산(15.19 GiB) 안이다. GPU 실측 peak 13,326 MiB에는 런타임 오버헤드(~1.1 GiB)가 포함돼 있고, gemma4:12b 셀 기준 전체 여유는 약 2.9 GiB다.
관측 — gemma4:e4b 초기 로드가 NPC를 1회 축출했다. core_warm 스냅샷에서 NPC가 부재했고 GPU 실측도 5,117 → 4,419 MiB로 내려갔다(실제 언로드). 다음 NPC 콜에서 1,007ms에 재로드된 뒤로는 끝까지 공존했다. VRAM이 충분한데도 발생했으므로 ollama 스케줄러의 로드 시점 메모리 추정에 의한 것으로 보인다. gemma4:12b(더 큰 모델)에서는 발생하지 않았다. 운영 영향은 Core 교체 시점의 NPC 1회 재로드(~1초)로 제한적이지만, 로드 순서에 따라 재현될 수 있는 성질이므로 기록해 둔다. 게이트(교대 구간 무축출)는 두 후보 모두 통과다.
측정의 한계
| 한계 | 내용 |
|---|---|
| 단시간 측정 | 교대 3라운드(셀당 약 1분). 장시간 상주·컨텍스트 누적에 따른 변동은 Stage 4(루프 완주)에서 본다 |
| 임베딩 모델 미포함 | 현행 임베딩은 gemini(원격)라 로컬 상주가 없지만, 폴백 qwen3-local 발동 시 추가 상주가 생긴다. 이 조합은 재지 않았다 |
| 초기 로드 축출은 게이트 밖 | 게이트는 교대 구간만 판정한다. e4b 초기 로드 transient는 위 관측으로만 남긴다 |
A.10 2026-09-14 · E7 Stage 4 — loop · 루프 스모크 1회차 완주
원문: docs/review-verification/2026-09-13-core-selection/stage4-loop-20260914T041032Z.json (정본)
계측 결함이 있던 1차 실행: stage4-loop-20260914T040719Z.json (경위는 아래)
--stage loop를 러너에 구현해 실행했다. HANDOFF 착수 순서대로 기존 run_selfplay.py가 방식 (a) — HTTP로 실서버 API 경로를 그대로 타는 방식 — 임을 확인하고 재사용했다.
프로토콜
- 별도 환경 서버:
scripts/loop_app.py가 프로덕션main.app을 import하고 컴포지션 루트의get_core_llm바인딩만 러너의ThinkingOllamaLLM(think=False)로 교체한다. 프로덕션 엔진 코드·.env무변경 (§2.3·§4.2). 게이트 C9 검증용/loop-debug(Core 콜 수·thinking 문자 누계)도 래퍼에만 있다 - 포트 8600 ·
pigfarm_testDB (테스터 판 DB 무접촉) · env 오버라이드CORE_LLM_PROVIDER=ollama,CORE_LLM_MODEL=<후보>. NPC(exaone3.5:7.8b)·임베딩(gemini)은 프로덕션 구성 그대로 - 완주 주체: selfplay 성실 페르소나, seed 42, 1판 × 1회차(낮 발화 → 비트 → 밤 제출 → 개입). 플레이어 모델은 상주 NPC(
exaone3.5:7.8b) 재사용 — 제3 모델을 올리면12b셀(pair 12.34 GiB)에서 축출이 나기 때문 - 판정은 §4.1 그대로 — 점수가 아니라 크래시 0 · 폴백 폭주 없음 · 1회차 완주
결과
| 후보 | 완주 | 크래시 | 폴백 | Core 콜 | 서버 콜(attempts) | thinking | 소요 | 판정 |
|---|---|---|---|---|---|---|---|---|
gemma4:12b-N |
O | 0 | 0 / 17 | 14 | 17 (17) | 0자 | 61.1s | 통과 |
gemma4:e4b-N |
O | 0 | 0 / 17 | 15 | 17 (19) | 0자 | 35.6s | 통과 |
역할별(서버 이벤트 로그 실측, 두 후보 동일 구성): planner 1 · advisor_answer 1 · evaluator_verdict 10 · manager_check 2 · NPC agent 3. attempt_id: d88a29e5-…78490(12b) / 8c350278-…43a63(e4b), 둘 다 pigfarm_test에만 기록.
확정된 사실
두 후보 모두 Stage 4 게이트를 통과한다. 실서버 경로에서 NPC·Manager와 엮인 1회차를 크래시 0·폴백 0으로 완주했다. 밤 채점(evaluator 10콜)·개입 질문(advisor)·원숭이손 제안 수락·규칙 등록까지 전 구간이 실행됐다.
게이트 C9 검증 — 두 셀 모두 thinking 0자. /loop-debug 누계로 확인했으므로 -N 셀 라벨을 신뢰할 수 있다.
e4b에서 하네스 재시도 2회(advisor 1·NPC agent 1)가 있었고 모두 재생성으로 해소됐다 — 폴백이 아니다(attempts 19 / calls 17). 12b는 재시도 0.
점수(16.0 / 8.8)는 판정 기준이 아니다. 같은 seed라도 NPC 응답·채점이 확률적이라 판마다 변동한다(1차 실행에서는 8.8 / 56.9). 단일 판 점수로 우열을 해석하지 않는다.
계측 결함 경위 (1차 실행)
1차 실행은 게임 완주 후 /attempts/{id}/harness로 폴백을 조회했는데, 이 인스펙터는 다섯 번째 밤 종료 후에만 열린다(AccessDenied). 1회차 스모크에서는 쓸 수 없어 러너가 수집 단계에서 예외를 냈고 gate_pass=false로 잘못 찍혔다 — 게임 자체는 두 판 모두 정상 완주였다(DB 이벤트 로그로 확인: 12b 판 폴백 0/17). 수집을 events 테이블 읽기 전용 SELECT로 교체하고 재실행한 것이 정본이다. 잘못 적립된 metrics 2줄은 제거했다.
측정의 한계
| 한계 | 내용 |
|---|---|
| 1판 × 1회차 | 스모크다. 5회차 완주·회차 누적 컨텍스트에서의 거동은 재지 않았다 |
| 성실 페르소나 단일 | 산탄총·침묵 페르소나 경로(빈 서술·주장 8개 채점)는 타지 않았다 |
| 점수 비교 불가 | n=1이고 판정 축도 아니다. 위 명시 |
A.11 2026-09-14 · D1 — Gemini 실제 쿼터 실측 (페이싱 프로브)
원문: docs/review-verification/2026-09-13-core-selection/d1-gemini-rpm-probe-20260914.txt
결정 항목 D1(“쿼터 제약이 실제로 얼마인지 확인”)을 실측했다. 페이싱 없이 초소형 요청을 순차 연속 전송해 429 발생 지점을 찾는 설계 — 프로덕션 서버는 내려간 상태에서 실행(간섭 없음).
결과
40콜 / 55.4초 (실효 약 43.3 RPM 지속) · 429 0건. 무료 티어의 공칭 한도는 10 RPM이므로, 무료 티어였다면 11번째 콜 부근에서 제한이 걸렸어야 한다. 이 키는 결제 계정이 연결된 유료 티어(Tier 1, 공칭 150~300 RPM)로 판단된다. 정확한 티어·한도는 계정 콘솔에서만 확정 가능하다.
판정에 주는 의미
gemini_llm.py의 10 RPM은 서버 쿼터가 아니라 우리 클라이언트 설정이고, 무료 티어 기준으로 잡은 과잉 보수 값이었다. effective = max(raw, 60000/RPM) 산식으로 게이트를 다시 계산하면:
| 게이트 | 요구 조건 | 필요한 최소 RPM | RPM=30일 때 |
|---|---|---|---|
| C11 advisor p95 ≤ 5s | eff ≤ 5,000ms (raw 2,238) | ≥ 12 | 2,238ms — 통과 |
| C12 planner p95 ≤ 15s | 단발 콜, 기존에도 통과 | — | 통과 유지 |
| C13 밤 채점 ≤ 30s | 10콜 × eff ≤ 30s (raw p95 1,779) | ≥ 20 | 10 × 2,000 = 20s — 통과 |
RPM을 20 이상으로 올리면 A.7의 C11·C13 탈락이 뒤집힌다. 실측 지속치(43)와 Tier 1 공칭치 대비 여유를 두면 30 RPM이 안전한 운영값 후보다.
결정 (2026-09-14, 사용자)
키가 유료인 것은 사용자가 확인해 주었다. 그러나 판단 기준은 무료 티어 한도(10 RPM)로 고정한다 — 유료 쿼터에 기대는 구성을 판정 근거로 삼지 않는다.
- 페이싱은 10 RPM 유지 (
.env변경 없음) - 위 게이트 재계산 표는 “올렸다면 어떻게 되는가”의 기록으로만 남긴다 — A.7의 Gemini C11·C13 탈락 판정은 그대로 유효하다
- D1은 이 결정으로 해소. 이후 무료 티어 공칭 한도 자체가 바뀌면 그때 재검토한다
추록 — 무료 키 전환 실측 (같은 날)
사용자가 실제로 키를 무료 티어로 교체했고, 같은 프로브를 재실행했다(원문 파일 추록 참조).
무료 키에서는 쿼터(10 RPM) 이전에 지연·용량이 먼저 무너진다. 초소형 콜(5토큰)이 20~28초 + 503 UNAVAILABLE 1회 + 30초 타임아웃 1회, 6콜/131초(실효 2.7 RPM). 1시간 전 유료 키의 같은 콜은 1.1~1.5초였다. 429는 지연 때문에 도달조차 못 했다.
- E7의 Gemini raw 수치(p50 1,720ms 등)는 유료 키에서 측정된 것이다. 무료 키 기준으로는 이 시점 실측에서 raw 지연만으로 C11(5초)을 10배 이상 초과한다 — 페이싱을 논할 필요도 없이 탈락
- 시점 한정 측정(일요일 13시대, “demand spike is usually temporary”)이므로 무료 티어의 상시 지연으로 일반화하지 않는다. 다만 무료 키 운영은 지연이 시간대에 따라 20초대까지 요동칠 수 있는 구성임이 확인됐다
- 이 측정은 D1 결정(무료 티어 기준 판단)을 강화한다 — 무료 기준에서 Core 슬롯의 온라인 대안은 현재 성립하지 않는다
A.12 2026-09-14 · E6 Formal — NPC descent · 정책 ON/OFF × 5모델 × n=5
원문: docs/review-verification/2026-09-14-npc-descent/e6-descent-formal-20260914T053343Z.json (ON) · …054425Z.json (OFF)
러너: scripts/run_model_descent.py 신규 구현 (부록 E6 §6 규격). 셀 절차: Stage 0(스키마 1콜) → age7 5항목 × n=5 → 누설 프로브 5 × 2(하네스 ON) → 지연·Peak VRAM. judge는 같은 응답을 3회 판정해 다수결로 채점하고 전원일치율을 D3로 기록한다 — 2026-09-06 앵커 행(n=2·단일 판정)과 규칙이 다르므로 이번 실행 내 셀끼리만 비교한다.
착수 전 블로커 4건의 해소
| # | 블로커 | 해소 |
|---|---|---|
| 1 | 양자화 혼재 | qwen3.5:2b-q4_K_M 재pull로 9b/4b/2b Q4_K_M 통일. 0.8b는 허브에 Q4 태그가 없어 Q8_0 편차 기록 (정밀도가 더 높은 쪽 — 하강 결론에 보수적) |
| 2 | thinking 미제어 | capabilities 조회 후 qwen 전 크기에 러너 서브클래스 think=False 강제, thinking 문자 누계 0 검증. exaone은 thinking 없음 |
| 3 | Anchor n=2 | 이번 실행에서 n=5 재측정 |
| 4 | judge 일치율 러너 부재 | judge 3표·전원일치율(D3) 구현 |
결과 — 정책 ON (판정용)
| 셀 | 1 사실 | 2 왜=몰라 | 3 망각* | 4 유도 | 5 문자 | items | 누설 | 스키마 | D3 | p95 ms | VRAM GiB | collapse |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
exaone3.5:7.8b (Anchor) |
0.60 | 0.40 | 0.40 | 1.00 | 0.40 | 1/5 | 0 | 1.00 | 1.00 | 2,610 | 4.83 | toddler |
qwen3.5:9b |
0.80 | 0.60 | 0.20 | 1.00 | 0.80 | 3/5 | 0 | 1.00 | 1.00 | 5,252 | 4.88 | none |
qwen3.5:4b |
0.80 | 1.00 | 1.00 | 1.00 | 0.80 | 5/5 | 0 | 1.00 | 1.00 | 2,290 | 2.98 | none |
qwen3.5:2b (Q4 재pull) |
0.20 | 1.00 | 1.00 | 1.00 | 1.00 | 4/5 | 0 | 1.00 | 1.00 | 639 | 1.51 | toddler |
qwen3.5:0.8b (Q8_0) |
0.60 | 0.80 | 0.80 | 0.80 | 0.80 | 4/5 | 0 | 1.00 | 1.00 | 716 | 1.03 | toddler |
*항목 3(3턴 망각)은 판정 축이 아니라 관측치다 (§3.1). 전 셀 누설 0 · 스키마 1.00 · D3 전부 ≥0.96 — 게이트 D1·D2·D3 전 셀 통과.
결과 — 정책 OFF (RQ9)
| 셀 | 1 사실 | 2 왜=몰라 | 3 망각* | 4 유도 | 5 문자 | items | collapse | ON−OFF (items) |
|---|---|---|---|---|---|---|---|---|
exaone3.5:7.8b |
0.80 | 0.40 | 0.40 | 1.00 | 0.20 | 2/5 | adult | −1 |
qwen3.5:9b |
0.60 | 1.00 | 0.20 | 1.00 | 0.80 | 3/5 | toddler | 0 |
qwen3.5:4b |
0.40 | 1.00 | 0.40 | 1.00 | 1.00 | 3/5 | toddler | +2 |
qwen3.5:2b |
0.20 | 1.00 | 1.00 | 1.00 | 1.00 | 4/5 | toddler | 0 |
qwen3.5:0.8b |
0.60 | 1.00 | 0.60 | 0.80 | 0.80 | 3/5 | toddler | +1 |
두 갈래 질문에 대한 답 (실험 목적 — 사용자 정의)
① 자연히(정책 프롬프트 없이) 7세인 크기가 있는가 — 없다. OFF 10셀 중 collapse=none이 없다. qwen 전 크기는 항목 1(사실대로)이 0.2~0.6으로 미달(3세화 방향), exaone은 항목 2·5 미달로 어른화(이유를 유창하게 지어내고 규칙 의도를 추론).
② 정책 프롬프트+하네스로 7세를 만들 수 있는 크기는 — 측정 사다리에서 4B 하나다. ON에서 collapse=none이면서 5항목 전부 ≥0.7인 셀은 qwen3.5:4b뿐이다. §7.3 문장 3형: 2B 이하에서 3세화(항목 1이 0.2~0.6으로 붕괴 — 정책을 줘도 사실 질문에 답을 못 한다), 7.8B(exaone)·9B에서 어른화 신호 잔존(항목 2가 0.4/0.6 — 이유를 지어낸다). 정책 프롬프트 효과(ON−OFF)는 4B에서 최대(+2: 항목1 0.4→0.8, 항목3 0.4→1.0)이고 2B에서는 0 — 프롬프트가 살릴 수 있는 하한이 2B와 4B 사이에 있다.
비열등 판정 (§4)과 그 한계
러너 계산: 4b·2b·0.8b 비열등 참, 9b 거짓(p95 5,252 > Anchor 2,610). 그러나 이번 실행에서 Anchor 자체가 판정 축 4항목 중 항목 4 하나만 통과해(1/5), §4 기준이 사실상 형해화됐다 — 형식적 최소 비열등 모델은 0.8b지만 그 셀은 collapse=toddler다. 절대 축(collapse·5항목 ≥0.7)으로 보면 후보는 4b 하나다. §7.3 문장 1형(4b 기준): qwen3.5:4b는 §4 비열등을 만족하며(Anchor 통과 항목 유지·누설 0·p95 2,290 ≤ 2,610), Peak Memory 4.83 → 2.98 GiB.
검수·관측
- 5/5 검수 수행(§8 금지 문장 규칙) — 4b의 5/5를 그대로 믿지 않고 transcripts 전수 감사: PASS 응답은 실제 7세 문체(“몰라. 그냥.”, “그랬어?”)이고, Anchor의 FAIL은 실제 거동(4턴 전 사실 정확 회상, “그래야 모두가 알 수 있고…” 식 이유 생성)이다. 판정 정당
- Anchor(exaone)가 이번 규칙으로 1/5 — 2026-09-06의 2/5(n=2·단일 판정)와 직접 비교하지 않는다. 다만 “Anchor부터 7세 정책에 미달”이라는 그림은 유지되며, 항목 3(망각)은 Anchor 0.40으로 여전히 낮다
4b한자 혼입 2/25(8%) — “그냥广播이지”, “말听?”.korean_only_check는 영문만 검사해 통과됐다. 하네스에 CJK 검사를 추가하는 것은 하네스 변경이므로 E6 결과에 반영하지 않고 후속 과제로만 기록- judge 일치율이 전 셀 0.96~1.00으로 높다 — temp 0.7에서도 판정이 갈리는 케이스가 거의 없었다
A.13 2026-09-14 · E6 후속 — qwen3.5:4b + Core 후보 동시 상주·루프 스모크
원문: e6-pair-qwen3.5_4b-gemma4_12b-…json · e6-loop-smoke-20260914T094617Z.json (같은 디렉토리)
동시 상주 (stage_concurrency 패턴 — NPC 선상주 → Core 로드 → 교대 3라운드)
| 조합 | pair peak | GPU peak | 교대 축출 | 오프로드 |
|---|---|---|---|---|
qwen3.5:4b + gemma4:12b |
10.49 GiB | 12,178 / 16,311 MiB (74.7%) | 0 / 6스냅샷 | 0 |
exaone 조합(A.9: 12.34 GiB, 여유 ~2.9 GiB) 대비 여유가 ~4.1 GiB로 늘어난다. (원문 evictions의 1건은 Core 로드 전 웜업 스냅샷의 러너 아티팩트 — 교대 구간 축출이 아니다.)
루프 스모크 (Stage 4 패턴 — scripts/loop_app_npc.py 래퍼, 프로덕션 무수정)
NPC=qwen3.5:4b(think 강제 OFF) + Core=gemma4:12b(think 강제 OFF), pigfarm_test DB, selfplay 성실 1회차: 완주 · 크래시 0 · 폴백 0/17(agent 재시도 1, 재생성 해소) · Core thinking 0자 · NPC thinking 0자 · 종료 시 두 모델 동시 상주(7.51+2.98 GiB). 소요 244s — 플레이어 LLM도 4b를 재사용했다(exaone을 올리면 3모델 15.3 GiB로 빠듯해지는 것을 회피). 점수 0.0은 판정 축이 아니며(§4.1) 플레이어 서술 품질의 영향으로 본다 — 기록만.
A.14 2026-09-14 · NPC 발화 품질 A/B — exaone3.5:7.8b vs qwen3.5:4b (E6과 별개 축)
원문: npc-quality-ab-20260914T101538Z.json (같은 디렉토리) · 러너: scripts/run_npc_quality_ab.py
E6(7세 정책 체크리스트)와 다른 축이다 — 정책 준수가 아니라 발화 품질(한국어 자연스러움·7세 말투·페르소나·관련성)을 잰다. E6 결과를 덮어쓰지 않는다. 사용자 프레임: exaone은 한국어 특화 모델이라 품질 기준선이고, 4b가 하네스 아래서 얼마나 따라오는지가 질문이다.
방법
E6 Formal ON 원문의 transcripts 재사용 — 같은 발화·같은 회차의 두 모델 응답 25쌍을 익명(응답1/응답2)으로 judge(gemma3:12b)에 제시. 항목 4개 × 3표 다수결 × 순서 2회(스왑). 스왑 후 다수결이 일치하는 쌍만 유효 — 불일치는 위치 편향으로 무효 처리. 단일 종합 점수 없음.
결과 (25쌍)
| 항목 | exaone 승 | 4b 승 | 무승부 | 무효(편향) |
|---|---|---|---|---|
| 한국어 자연스러움 | 18 | 3 | 0 | 4 |
| 7세 말투 | 7 | 15 | 0 | 3 |
| 페르소나 적합 | 14 | 2 | 0 | 9 |
| 질문 관련성 | 18 | 3 | 0 | 4 |
결정적 지표: 비한글 스크립트(한자 등) 혼입 exaone 0/25 vs 4b 2/25(8%) · 평균 응답 길이 35.0자 vs 9.1자 · 폴백 둘 다 0.
확정된 사실
발화 품질 3개 항목에서 exaone이 큰 차이로 우세하다 — 자연스러움 18:3, 관련성 18:3, 페르소나 14:2. 4b가 앞선 유일한 항목은 7세 말투(15:7)인데, 평균 9.1자의 극단적 단답이 원인으로 보이며, 이는 E6 §11이 경고한 judge 편향(“짧고 어색한 출력을 7세답다로 과대평가”)과 같은 방향이라 단독 근거로 쓰지 않는다. 한자 혼입 8%는 A.12 관측(2/25)과 일치하는 재확인이다.
E6과 A.14는 반대 방향의 트레이드오프를 그린다: exaone은 7세 정책 1/5(어른화 신호)이지만 발화 품질 우세, 4b는 정책 5/5·VRAM 2.98이지만 발화 품질 열세. NPC 슬롯 결정은 이 두 축 사이의 선택이다 — 어느 쪽도 두 축을 다 이기지 못했다.
측정의 한계
| 한계 | 내용 |
|---|---|
| n=25쌍 | E6 transcripts 재사용 범위. 통계적 유의성 주장 없음 |
| judge 단일 모델 | gemma3:12b 하나. 페르소나 항목은 무효(편향) 9건으로 판정 안정성이 낮은 편 |
| 발화 세트 편향 | 7세 체크리스트용 발화라 일상 대화 분포와 다르다 |
A.15 2026-09-14 · E6 항목 2 판정 스펙 v2 재판정 — “아이도 이유를 지어낸다”
원문: e6-rejudge-item2-20260914T102437Z.json (같은 디렉토리) · 러너: scripts/run_rejudge_item2.py
경위 — 정책과 판정의 불일치
Scenario Director(사용자)가 7세 스펙을 확정했다: “애들도 이유를 지어낸다. 단 근거가 없거나, 본인이 하고 싶은 이야기를 한다.” 대조 결과 AGE7_POLICY 프롬프트 2번(“네가 아는 이유나 기분을 쉬운 말로 답한다”)은 이미 이 정의와 일치하는데, run_age7_check.py 항목 2의 judge 기준(“이유 문장이 있으면 무조건 FAIL”)이 정책보다 엄격한 판정 결함이었다. 항목 5는 프롬프트(“이유는 생각하지 않는다”)와 판정이 일치해 그대로 둔다.
judge 기준을 v2로 재작성했다 — PASS: 몰라 / 자기 기분·직접 본 것 / 근거 없는 아이다운 지어내기 / 딴 얘기로 새기. FAIL: 남의 속마음·모르는 원인의 그럴듯한 추론, 다단계 인과, 조건 달기, 검증 요구. 응답은 재생성하지 않고 A.12 ON transcripts를 재판정만 했다 (judge 75콜, 3표 다수결).
결과 (v1 → v2, 원 판정 병기·보존)
| 셀 | item2 rate | items_passed | collapse | judge 일치 |
|---|---|---|---|---|
| exaone3.5:7.8b | 0.4 → 0.4 | 1 → 1 | toddler 유지 | 1.0 |
| qwen3.5:9b | 0.6 → 0.8 | 3 → 4 | none 유지 | 1.0 |
| qwen3.5:4b | 1.0 → 1.0 | 5 → 5 | none 유지 | 1.0 |
| qwen3.5:2b | 1.0 → 1.0 | 4 → 4 | toddler 유지 | 1.0 |
| qwen3.5:0.8b | 0.8 → 0.4 | 4 → 3 | toddler 유지 | 0.8 |
확정된 사실
exaone의 항목 2 실패는 판정 결함이 아니라 실제 현상이다. 관대해진 v2 기준에서도 FAIL 3건이 전부 만장일치로 유지됐다 — “그래야 모두가 알 수 있고, 준비할 수 있잖아. 시간이 정해져 있으면 혼란 없이 배급을 받을 수 있으니까” 같은 응답은 아이다운 지어내기가 아니라 다단계 인과·타인 의도 추론의 어른 설명이다. 어른화 신호 서술은 v2 기준으로도 유효하다.
qwen3.5:9b만 판정이 완화됐다 (0.6→0.8, items 4/5) — “관리자님이 그 시간일 때만 나오시잖아. 왜 그래?”가 아이다운 답으로 재분류. 다만 9b의 비열등 탈락 사유는 p95(5,252ms)와 VRAM 무이득이라 탈락은 유지된다.
0.8b는 오히려 하락했다 (0.8→0.4) — v1이 PASS로 세던 비문 횡설수설(“배급이 시간 안에 나오면 좋지만… 그다지 늦어지면 안된다”)을 v2가 걸렀다. 3세화(collapse=toddler) 판정과 정합적이다.
NPC 결정 구도는 바뀌지 않는다. exaone 1/5·4b 5/5 그대로이고, 4b의 항목 2 통과가 전부 “몰라” 단답이라 v2 완화의 수혜도 없다 — E6(정책) vs A.14(품질)의 반대 방향 트레이드오프가 유지된다.
측정의 한계
| 한계 | 내용 |
|---|---|
| 재판정 범위 | 항목 2·정책 ON·n=5만. OFF 셀과 다른 항목은 v1 판정 그대로 |
| 판정 규칙 변경 이력 | v1(몰라만 PASS)과 v2는 다른 자다. metrics에 note: rejudge-item2-spec-v2로 구분 적립, 이후 실행은 v2가 기본 |
A.16 2026-09-14 · E6 확장 — exaone3.5:2.4b 후보 평가
원문: e6-descent-formal-20260914T103151Z.json · npc-quality-ab-20260914T104637Z.json(vs 7.8b) · npc-quality-ab-20260914T105727Z.json(vs 4b) · e6-pair-exaone3.5_2.4b-gemma4_12b-20260914T105749Z.json (같은 디렉토리)
사용자 지시로 exaone 하위 버전을 평가했다 — 한국어 특화 패밀리를 유지한 채 크기를 내려 품질·정책·VRAM 세 축을 동시에 잡는 셀인지. ollama pull exaone3.5:2.4b: Q4_K_M(양자화 통일 문제없음), capabilities ['completion'](thinking 미지원 — 7.8b와 동일), 2.67B.
E6 셀 (n=5 · judge 3표 · 항목 2는 v2 스펙 — A.15 재판정과 동일 기준이라 기존 셀과 비교 가능)
| policy | 사실대로 | 왜=몰라 | 망각* | 유도수용 | 문자그대로 | items | 누설 | 스키마 | D3 | p95 | VRAM |
|---|---|---|---|---|---|---|---|---|---|---|---|
| on | 0.40 | 0.20 | 0.20 | 1.00 | 0.00 | 1/5 | 0 | 1.00 | 0.96 | 1,911ms | 1.74 GiB |
| off | 0.20 | 0.40 | 0.40 | 1.00 | 0.00 | 1/5 | 0 | 1.00 | 1.00 | 2,667ms | 1.74 |
양방향 동시 붕괴다. collapse 분류는 toddler(사실대로 0.40 미달 우선)지만, 어른화 조건(항목 2·5 동시 미달)도 함께 충족한다 — E6 사다리에서 처음 나온 프로필. transcripts 검수: 항목 2·5 FAIL이 전부 “안전과 질서를 유지하기 위해”, “일정한 패턴으로 활동하고, 그로 인해…”, “마치 큰 학교에서 규칙을 지키는 것처럼” 류의 다단계 인과·비유 설명(v2 기준으로도 명백 FAIL)이고, 사실대로 FAIL은 반문 얼버무림이다.
어른화는 크기 하강으로 사라지지 않았다 — exaone 패밀리 성질로 확인. 7.8B(왜=몰라 0.4) → 2.4B(0.2). ON−OFF 격차도 0(items 1→1)으로 정책 프롬프트 순효과가 없다. §4 비열등은 형식상 참(anchor 통과 항목=유도수용뿐 · 누설 0 · p95 1,911≤2,610)이지만 A.12·A.15와 같은 형해화 사유로 절대 축 판정을 병기한다: 1/5, 후보 부적격.
발화 품질 A/B (A.14와 동일 프로토콜, 25쌍 × 4항목 × 3표 × 순서 스왑)
| 항목 | 7.8b : 2.4b | 2.4b : 4b |
|---|---|---|
| 한국어 자연스러움 | 15 : 4 | 9 : 10 (비등) |
| 7세 말투 | 20 : 2 | 1 : 24 |
| 페르소나 적합 | 10 : 4 | 8 : 7 (비등) |
| 질문 관련성 | 8 : 7 (비등) | 14 : 10 |
정량: 한자 혼입 2.4b 0/25(4b는 2/25) · 평균 길이 83.5자(7.8b 35.0 · 4b 9.1) · 폴백 0. 2.4b는 7.8b의 품질 우위를 계승하지 못했다 — 같은 패밀리인데 장광설(83.5자) 탓에 7세 말투 최하이고, 자연스러움도 4b와 비등 수준으로 내려온다. 남는 강점은 한자 혼입 0과 관련성뿐이다.
pair (Core gemma4:12b)
pair peak 9.25 GiB(1.74+7.51) · GPU peak 10,158/16,311 MiB · 여유 ~6.0 GiB · 교대 3라운드 무축출·오프로드 0. Core 초기 로드 때 NPC 1회성 축출 관측(다음 콜 1.3초 재로드 후 안정) — A.9의 e4b 초기 로드 패턴과 동일. 게이트(교대 구간)는 통과.
3모델 결정 구도
| exaone3.5:7.8b (현행) | exaone3.5:2.4b | qwen3.5:4b | |
|---|---|---|---|
| 7세 정책 (v2) | 1/5 — 어른화 | 1/5 — 어른화+3세화 동시 | 5/5 |
| 발화 품질 | 우세 기준선 | 기준선 대비 3항목 열세, 4b와 비등 | 열세(단답 9.1자·한자 8%) |
| pair 여유 (Core 12b) | ~2.9 GiB | ~6.0 GiB | ~4.1 GiB |
2.4b는 세 축 동시 해결 후보가 아니다. VRAM 하나만 최상이고, 정책은 1/5 그대로(어른화가 패밀리 성질임만 추가 확인), 품질은 패밀리 우위를 잃는다. 결정 구도는 여전히 7.8b(품질) vs 4b(정책+VRAM) 두 축이다.
측정의 한계
| 한계 | 내용 |
|---|---|
| exaone 중간 크기 부재 | ollama 허브에 exaone3.5는 2.4b·7.8b·32b뿐 — 4B급 셀은 잴 수 없었다 |
| 품질 A/B의 judge | A.14와 동일 — gemma3:12b 단일 judge, 위치 편향은 스왑 무효 처리로만 통제 |
A.17 2026-09-14 · NPC 상업 라이선스 조사 + 상업 가능 후보 3종 평가
원문: npc-license-survey.md · e6-descent-formal-20260914T110608Z.json · npc-quality-ab-20260914T112712Z.json · e6-pair-kanana1.5_8b-q4km-gemma4_12b-20260914T112726Z.json (같은 디렉토리)
사용자 지적(“엑사온이 상업용으론 안 되는 점”)으로 라이선스를 조사하고, 상업 가능 대안을 같은 파이프라인에 태웠다. 라이선스 판단은 법률 자문이 아니다 — 원문 조항 인용 + 해석.
라이선스 조사 요지 (상세·출처는 npc-license-survey.md)
- EXAONE 3.5 = 연구 전용 확정. 공식 LICENSE: “open to anyone for research purposes… For commercial use, please reach out to … LG AI Research”. 서비스 오픈(상업 배포)에는 별도 계약 없이는 사용 불가 — 현행 NPC는 라이선스 블로커
- 상업 가능 한국어 후보: KT Mi:dm 2.0(MIT, 2.3B Mini) · Kakao Kanana 1.5(Apache 2.0, 2.1B/8B) · SKT A.X Light(Apache, ~7B — 가용성만 기록) · Naver HCX SEED(전용 라이선스, MAU 1천만 이하 허용 — 기록만)
- 스택 점검: Core
gemma4:12b·gemma4:e4b는 Apache 2.0(Gemma 4부터) — 문제없음. judgegemma3:12b는 Gemma Terms이나 배포 스택 밖(평가 도구). embedding gemini는 무료 티어 약관(데이터 활용 조항) 유의
셀 실측 — 정책 ON, n=5, judge 3표(v2 스펙), 전 셀 누설 0·스키마 1.00·D3 ≥0.96
| 후보 (라이선스) | 사실대로 | 왜=몰라 | 망각* | 유도 | 문자 | items | p95 | VRAM | collapse |
|---|---|---|---|---|---|---|---|---|---|
gemma4:e4b (Apache) |
0.4 | 1.0 | 0.4 | 1.0 | 1.0 | 3/5 | 2,372 | 3.06 | toddler |
kanana1.5:8b (Apache, Q4_K_M import) |
0.6 | 1.0 | 0.8 | 1.0 | 1.0 | 4/5 | 1,917 | 4.91 | toddler(경계) |
midm2.0:mini (MIT, 2.3B import) |
0.2 | 0.8 | 0.6 | 0.8 | 0.8 | 3/5 | 624 | 2.12 | toddler |
- 세 후보 모두 어른화 축 항목(왜·유도·문자)은 통과하고 항목 1(사실대로)에서만 미달 — exaone 7.8b(어른화)와 반대 방향
kanana1.5:8b의 항목 1 실패는 전반 붕괴가 아니다. 5회 중 실패 2회가 전부 같은 케이스(“충식이 어제 이송된 거 맞아?” → “그랬어?”)의 반복 — 민감 사실 시인을 회피하는 패턴이고 나머지 사실 질문 3종은 통과. 기준 0.7에 1콜 차이(0.6)- Modelfile import: 두 모델 모두 llama3 계열 템플릿으로 GGUF import(Q4_K_M — 양자화 통일 유지). thinking 미지원(capabilities 확인)
품질 A/B — exaone3.5:7.8b(기준선) vs kanana1.5:8b (25쌍 · 3표 · 스왑 2회)
| 항목 | exaone | kanana | 무효 |
|---|---|---|---|
| 한국어 자연스러움 | 9 | 7 | 9 — 사실상 대등권 |
| 7세 말투 | 0 | 21 | 4 |
| 페르소나 적합 | 7 | 4 | 13 |
| 질문 관련성 | 14 | 5 | 5 |
- 외국 문자 혼입 둘 다 0/25 (
qwen3.5:4b의 한자 8%와 대조) · 평균 길이 35.0자 vs 12.3자 · 폴백 0 - kanana의 7세 말투 21:0은 단답(12.3자) 편향이 섞였을 수 있다(A.14의 4b 사례와 같은 계열 주의). 다만 4b와 달리 자연스러움이 기준선과 대등권이고 혼입이 0이라는 점이 다르다
pair 체크 — kanana1.5:8b + gemma4:12b
pair peak 12.42 GiB · GPU 13,402/16,311 MiB · 교대 r1~r3 전 스냅샷 동시 상주, 오프로드 0. 기록된 “축출 1”은 core 로드 전 npc_warm 시점의 워밍업 순서 아티팩트다(A.9의 초기 로드 관측과 동류) — 교대 구간 판정은 무축출. exaone 조합(12.34)과 동급이라 VRAM 이득은 없다.
구도에 주는 의미
- 라이선스를 결정 축에 넣으면 exaone 7.8b는 “품질 기준선이자 상업 블로커”가 된다 — 유지하려면 LG 계약이 필요
- 상업 가능 후보 중
kanana1.5:8b가 기준선에 가장 가까운 프로필: 자연스러움 대등권 + 혼입 0 + 정책 4/5(경계) + p95 1,917ms. 대가: VRAM 이득 없음(12.42), 항목 1 민감 사실 회피 1케이스, 관련성 열세(14:5) - VRAM 축은 여전히
qwen3.5:4b(pair 10.49)만. 세 축(품질·정책·VRAM) 동시 해결 셀은 이번 확장에서도 없다 midm2.0:mini는 2B급 3세화 패턴 재확인(exaone 2.4b·qwen 2b와 동류),gemma4:e4b는 사실대로 0.4로 NPC 슬롯 부적합(Core 후보로서의 E7 결과와는 별개 역할임을 명시)
A.18 2026-09-14 · NPC 교체 전 루프 스모크 — kanana + gemma4:12b
원문: docs/review-verification/2026-09-14-npc-descent/e6-loop-smoke-kanana-20260914.json · 서버 로그 e6-loop-server-kanana8b-gemma12b.log
NPC 채택(§5.3) 확정 전 게이트. scripts/loop_app_npc.py 래퍼(8600·pigfarm_test — Core만 러너 서브클래스 think off, kanana는 thinking 미지원이라 프로덕션형 어댑터 그대로)로 selfplay 성실 1회차.
| 항목 | 값 |
|---|---|
| 완주 / 크래시 | O / 0 (61.4s, 점수 8.8) |
| 폴백 | 0 / 16콜 (planner 1 · advisor 1 · evaluator 10 · manager 1 · NPC agent 3) |
| Core thinking | 0자 (C9) |
| 관리 항목 ① 회피성 응답 | 0 / 21 발화 |
| 관리 항목 ② 외국 문자 혼입 | 0 |
| 관리 항목 ③ NPC 평균 응답 길이 | 11.4자 — 단답 경향 유지, 운영 관찰 지속 |
판정: 통과. 교체 반영은 §5.3 “채택 — NPC 슬롯” 참조.
9. 변경 이력
| 날짜 | 내용 |
|---|---|
| 2026-09-13 | 문서 생성. E7 설계 확정, E6를 Phase 2로 재배치, 부록 A 실측 3건 이관 |
| 2026-09-13 | E7 Stage 0 실행. 부록 A.5 추가. §2.2에 실측 VRAM 열 추가, §7 제약 2 해소, qwen3.5:9b-T 탈락 반영 |
| 2026-09-13 | E7 Stage 1 실행. 부록 A.6 추가. 지연을 Hard 게이트로 승격(C11~C13), 통제 4→10개 정정, EGR을 판정 축에서 강등, Gemini raw/effective 지연 분리. 8셀 → 4셀 |
| 2026-09-13 | E7 Stage 2 실행 — 공식 수치. 부록 A.7 추가. Gemini는 페이싱으로 C11·C13 탈락, gemma4:12b-N에서 RM1이 닫히나 evaluator_verdict 손실로 비열등 아님. 자작 evaluator 통제의 한계 기록. Stage 3·4 미실행 |
| 2026-09-14 | E7 Stage 2 보강 — evaluator 통제 교체 재측정. 부록 A.8 추가. 자작 3건 → 실플레이 14건(사전 등록), --roles evaluator 168콜. 기준선 1.00→0.36, gemma4:12b-N 0.67→0.57로 우열 역전. partial 경계 4셀 공통 실패, 덩어리 칸 취약점 확인 |
| 2026-09-14 | E7 Stage 3 실행 — concurrency. 부록 A.9 추가. --stage concurrency 러너 구현. 두 후보 모두 NPC와 교대 구간 무축출 공존(12.34 / 7.89 GiB). e4b 초기 로드의 NPC 1회성 축출 관측 기록. exaone 상주 실측 4.83 GiB로 §2.2 갱신 필요 |
| 2026-09-14 | E7 Stage 4 실행 — loop. 부록 A.10 추가. --stage loop 러너 구현(scripts/loop_app.py 래퍼로 프로덕션 무수정 thinking 주입, pigfarm_test DB). 두 후보 모두 1회차 완주·크래시 0·폴백 0/17·thinking 0자로 게이트 통과. metrics.yml stage: loop 2줄 적립. Funnel Stage 0~4 전부 완료 — 남은 것은 결정 항목(D1~D3)과 §5.3 비열등 선언 여부 |
| 2026-09-14 | D1 실측·해소 — Gemini 쿼터 프로브. 부록 A.11 추가. 페이싱 없이 40콜/55.4s(약 43 RPM) 429 0건 — 키는 유료(사용자 확인). RPM ≥ 20이면 C11·C13이 뒤집히는 것을 확인했으나, 사용자 결정으로 판단 기준을 무료 티어 한도(10 RPM)로 고정 — 페이싱 유지, Gemini 탈락 판정 유효, D1 해소. 이후 키를 실제 무료 티어로 교체, 재프로브에서 초소형 콜 20~28s·503 관측(A.11 추록) |
| 2026-09-14 | Core 채택 방향 기록 (교체는 보류). 게임 관점 권고 = gemma4:12b-N — RM1이 닫히는 유일한 로컬 셀, 실플레이 evaluator 기대 일치 최상(0.57)·판정 요동 0, 지연은 전 게이트 안. 사용자 결정: 기록만 하고 교체하지 않는다. E6(NPC descent) 결과를 먼저 본다 — NPC를 exaone(4.83 GiB)보다 작은 모델로 내릴 수 있으면 12b Core의 VRAM 여유 문제(pair 12.34 GiB, 여유 ~2.9 GiB)가 구조적으로 해소되기 때문. D2(운영 Gemini thinking OFF)는 Core를 Gemini로 유지할 경우에만 유효한 결정으로 보류 |
| 2026-09-14 | E6 Formal 실행 — NPC descent. 부록 A.12·A.13 추가, §8.2 블로커 4건 해소. run_model_descent.py 구현(judge 3표·D3, thinking 강제 OFF). ON/OFF 10셀 × n=5: 자연 7세 크기는 없음(OFF 전 셀 collapse≠none), 정책 ON에서 7세 구간은 측정 사다리상 4B 하나(2B 이하 3세화·7.8B/9B 어른화 신호). qwen3.5:4b — 5항목 전부 ≥0.7·누설 0·p95 2,290·2.98 GiB. 후속: 4b+gemma4:12b pair 10.49 GiB 무축출(여유 ~4.1 GiB), 루프 스모크 완주·폴백 0/17. 4b 한자 혼입 2/25 관측(후속 과제) |
| 2026-09-14 | Core 채택 반영 — gemma4:12b-N 전환. §5.3에 채택 선언. .env CORE 3필드 전환(CORE_LLM_THINK=off 신설), 프로덕션 think 제어 반영(ollama_llm.py think 인자 · Settings 2필드 · llm_factory 배선, 테스트 7건, 전체 393 passed). 실서버 검증: health ollama:gemma4:12b, 아침 planner 12.13s(-N p95와 일치). D2는 Gemini 이탈로 대상 소멸 |
| 2026-09-14 | NPC 발화 품질 A/B — 부록 A.14. run_npc_quality_ab.py(쌍대 블라인드, 3표×스왑 2회). exaone 우세: 자연스러움 18:3·관련성 18:3·페르소나 14:2. 4b 우세는 7세 말투 15:7뿐(9.1자 단답 기인 — judge 편향 방향이라 단독 근거 배제). 4b 한자 혼입 2/25 재확인. E6(정책)과 A.14(품질)는 반대 방향 트레이드오프 — NPC 결정은 이 두 축의 선택 |
| 2026-09-14 | 항목 2 판정 스펙 v2 재판정 — 부록 A.15. Scenario Director 스펙 확정(“아이도 근거 없는 지어내기·딴 얘기는 한다”)으로 judge 기준이 정책보다 엄격했던 결함을 수정, A.12 ON transcripts 재판정(재생성 없음). exaone 0.4 유지(FAIL 전건이 다단계 인과 어른 설명 — 어른화는 실제 현상으로 확정), 9b 0.6→0.8(탈락 사유는 p95라 유지), 0.8b 0.8→0.4(비문 필터). NPC 결정 구도 불변. 이후 age7 실행은 v2 기준 |
| 2026-09-14 | E6 확장 — exaone3.5:2.4b 평가 (부록 A.16). 사용자 지시. 셀(1/5, 양방향 동시 붕괴 — 어른화가 exaone 패밀리 성질로 확인, ON−OFF 격차 0) + 품질 A/B 2건(7.8b에 3항목 열세·83.5자 장광설, 4b와 자연스러움 비등) + pair 9.25 GiB(여유 ~6.0). 세 축 동시 해결 후보 아님 — 결정 구도는 7.8b(품질) vs 4b(정책+VRAM) 유지. AB 러너에 --raw-b 추가(서로 다른 원문 간 쌍대) |
| 2026-09-14 | NPC 상업 라이선스 조사 + 상업 후보 3종 평가 (부록 A.17). 사용자 지적(“엑사온 상업 불가”)으로 조사 — EXAONE 3.5는 연구 전용 확정(상업은 LG 계약), 현행 NPC는 라이선스 블로커. 상업 가능 후보 실측: kanana1.5:8b(Apache) 4/5·자연스러움 기준선과 대등권·혼입 0·pair 12.42(VRAM 이득 없음, 항목1 0.6은 민감 사실 회피 1케이스), gemma4:e4b 3/5(사실 0.4), midm2.0:mini 3/5(2B급 3세화 동류). Gemma 4는 Apache 2.0 — Core 스택 문제없음. 결정 구도가 “exaone(연구 한정) vs 상업 후보(kanana=품질축 근접 / qwen4b=VRAM축)”로 재편 |
| 2026-09-14 | NPC 채택 반영 — kanana1.5:8b-q4km (사용자 결정, §5.3·A.18). 교체 전 루프 스모크 통과(완주·폴백 0/16·관리 항목 3건 깨끗) 후 .env NPC_LLM_MODEL 한 줄 전환, 실서버 health·실콜 검증. 어댑터 패턴 확인(프로덕션 하드코딩 없음) — 롤백은 .env 한 줄, exaone3.5:7.8b는 롤백용 유지. 평가용 임시 모델 2종·GGUF 원본 삭제(~9GB 회수). 모델 선정(E7 Core + E6/확장 NPC) 전부 완료 — 운영 구성: Core gemma4:12b-N · NPC kanana1.5:8b · embedding gemini |
| 2026-09-14 | 채점 파이프라인 변경 — 이후 evaluator 측정은 새 기준. 실판 da38de28에서 동일 제출 70.8→59.6 요동(identity-1) 진단 → ① evaluator temp 0은 기배선 확인(그럼에도 요동 — 회귀 테스트 고정) ② scoring_rules.apply_ratchet 단조 잠금(같은 문장 유지 시 하향 금지, ratcheted 표시) ③ judge_candidates 문장 단위 후보(8칸 UI 유지, 덩어리 칸 해소 — A.8의 “모델 교체로 안 닫히는 결함 2건” 중 덩어리 칸이 이것으로 닫힘). 실판 오프라인 검산: 요동 케이스 차단(59.6→70.8 유지). 402 passed |
| 2026-09-14 | AGE7 프롬프트 v2 + 대화 메모리 창 — 이후 7세 계열 측정은 새 기준. 사용자 확정 7세 정의(“몰라로 끝내지 않는다 — 본 것·하고 싶은 말을 붙인다”)를 정책 2·3·7에 반영하고 인물별 “직접 본 것”을 페르소나에 추가. 1차 문구는 망각을 0.8→0.0으로 붕괴시켜(4턴 전 사실 회상) 문구 정밀화 + 정책 ON 시 메모리 마지막 두 교환만 제공하는 구조 절단으로 교정. kanana 재측정(n=5·judge 1표): [0.6·1.0·1.0·1.0·1.0] 4/5 통과·누설 0. 신의 질문 해금(advisor_leads 10건)·dormant 탐사 행동 5종·직접쓰기 대안 제시도 이 회차 — 이전 E6 수치와 직접 비교 금지 |
측정하지 않은 것은 주장하지 않는다. 재현성은 정확도가 아니다. 그리고 선택 실험에 하나 더 — 이기는 모델을 찾는 것이 목적이 아니라, 지금 쓰는 모델을 바꿀 이유가 있는지 아는 것이 목적이다.