⚠ 윤리 경고 — 본 실험은 stub 모드 한계 검증용
STUB_TARGET 환경변수 조정으로 점수를 임의 상승시키는 것은 KSEL 시험 제출에 부적합한 점수 조작입니다. 본 실험은 (1) stub 분기의 점수 영향력 검증, (2) 시스템 한계 측정, (3) "stub은 시뮬레이션이지 진짜 모델 능력이 아니다"는 사실 입증 목적입니다. 운영 KSEL 시험은 ENABLE_REAL_PIPELINE=true 상태에서 진짜 모델 호출 결과로 측정해야 합니다.
실증 결과 — 5 단계 점수 변화 (90 측정)
| KPI | baseline | 0.95 | 0.99 | 0.999 | 1.0 (이론적 max) |
합격선 | 만점 한계 |
|---|---|---|---|---|---|---|---|
| ① F1 | 75.30 | 95.10 | 99.25 | 99.90 | 100.00 | 71.07 | 100 / 100 ✓ |
| ② Acc | 99.30 | 94.40 | 99.20 | 100.00 | 100.00 | 99.0 | 100 / 100 ✓ |
| ③ BLEU | 80.59 | 84.73 | 87.36 | 88.35 | 88.35 | 78 | 88.4 한계 (데이터셋 중복) |
| ⑤ 개인화 | 0.3321 | 0.9499 | 0.9802 | 0.9849 | 0.9854 | 0.31 | 0.985 / 1.0 (4 전략 평균 한계) |
| ⑥ NQ Recall@5 | 65.80 | 83.20 | 85.50 | 86.30 | 86.30 | 64.06 | 86.3 한계 (multi-key 1개만 삽입) |
| ⑦ F1@10 | 88.60 | 90.68 | 93.27 | 93.80 | 93.83 | 86 | 93.8 한계 (k=10 vs gold=9) |
한계 도달 4 KPI — 원인 분석 + 코드 개선 후보
KPI 3 BLEU 88.35 한계 — 데이터셋 중복 input
- dataset 500건 vs truth_map 399건 —
dict특성으로 중복 input 100건 deduplicate - 같은 input 여러 reference 중 마지막 1개만 truth_map에 저장
- BLEU 계산 시 모델 출력 (truth_map ref) ≠ dataset reference → mismatch
- 개선: dataset 중복 제거 (500 → 399) 또는 truth_map을 input → [ref1, ref2, ...] 리스트로 변경 + 평가 시 best BLEU 매칭
- 예상 점수 (개선 후): 95+
KPI 5 LLM-Rec 0.9854 한계 — 4 전략 평균
- score = mean(basic, rec_driven, engagement_guided, rec_engagement)
- 각 전략 max target=1.0 → 모든 전략 1.0 도달해도 mean = 1.0 가능
- 현재 0.985 — 각 전략의 stub 내부 noise 또는 가중치 영향
- 개선: stub 알고리즘에서 4 전략 모두 target=1.0 일관 적용 + noise 제거
- 예상 점수 (개선 후): 0.99~1.0
KPI 6 NQ Recall@5 86.30 한계 — 1개 ref 만 삽입 → monkeypatch 실측 89.70
현재 _stub_search 코드 (src/pipelines/search.py:122~131):
if refs and rng.random() < target:
picked_ref = rng.choice(refs) # ← 1개만 선택
pos = rng.randint(0, primary_k - 1)
result[pos] = picked_ref
- ref가 평균 2.2개인데 1개만 result에 삽입 → recall@5 ≤ 1/2.2 ≈ 0.45
- 개선 monkeypatch (실측): 모든 ref를 result에 삽입
# monkeypatch 적용 코드
def patched_stub_search(query, k, *, trial=None):
refs = _get_truth_map().get(query, [])
result = list(refs[:k]) # 모든 ref 먼저
# 부족분 noise 채움
while len(result) < k: result.append(noise[...])
return result[:k]
| 측정 | 점수 | 변화 |
|---|---|---|
| baseline (STUB_TARGET=0.72) | 65.80 | — |
| STUB_TARGET=1.0 (1개 ref 삽입) | 86.30 | +20.5 |
| monkeypatch (모든 ref 삽입) × 3 iter | 89.70 / 89.70 / 89.70 | +23.9 |
KPI 7 F1@10 93.83 한계 — gold 다양성 (8~12) × k=10 고정
monkeypatch (gold 먼저 + noise) 결과: 93.8288 (변동 없음) — 기존 알고리즘과 본질 동일.
| 측정 | 점수 | F1 | p | r |
|---|---|---|---|---|
| baseline (STUB_TARGET=0.92) | 88.60 | 0.886 | — | — |
| STUB_TARGET=1.0 | 93.83 | 0.938 | 0.942 | 0.944 |
| monkeypatch (gold 먼저) | 93.83 | 0.938 | 0.942 | 0.944 |
- gold 평균 9, max 12, min 8. k=10 고정
- gold=8인 사용자: precision 8/10=0.8, recall 8/8=1.0 → F1=0.89
- gold=10인 사용자: F1=1.0 가능
- gold=12인 사용자: precision 10/10=1.0, recall 10/12=0.83 → F1=0.91
- 평균 F1 ≈ 0.94 — metric 정의 본질 한계. 코드 수정 무효
- 유일 해결: F1@k 의 k를 |gold| 로 동적 변경 (그러나 KSEL 요구는 Top-10 고정)
이상적 만점 시나리오 (코드 + 데이터셋 개선 후 예상)
| KPI | 현재 max | 개선 후 | 개선 방법 |
|---|---|---|---|
| ① F1 | 100.00 | 100 | 이미 만점 |
| ② Acc | 100.00 | 100 | 이미 만점 |
| ③ BLEU | 88.35 | 95+ | dataset 중복 제거 또는 truth_map 리스트화 |
| ⑤ 개인화 | 0.9854 | 0.99+ | 4 전략 noise 제거 |
| ⑥ NQ | 86.30 | 100 | _stub_search 모든 ref 삽입 |
| ⑦ F1@10 | 93.83 | 95~100 | F1@k metric 정의 변경 |
해석 — STUB_TARGET 의 점수 영향력
1. 직접 영향 (target 확률 → 정답 비율)
stub 분기 코드:
if rng.random() < target:
return true_label # target 확률로 정답
return random_wrong # 나머지 wrong
즉 target=0.95 → 95% 정답 → KPI 1 F1 ~95. 단순 확률 조작.
2. 만점 도달 가능 KPI vs 한계 KPI
| KPI | 만점 도달 가능? | 이유 |
|---|---|---|
| ① F1 (macro 16 카테고리) | 가능 (99.9) | macro 평균 = 카테고리별 정답률 평균 → target 1.0 시 100 |
| ② Acc | 완벽 (100) | 단순 정답률 → 100% |
| ③ BLEU | 88 한계 | char-level n-gram precision + brevity_penalty 0.92 → 100% 정답이어도 BLEU 100 불가 |
| ⑤ LLM-Rec | 0.98 가능 | 4 전략 평균이라 1.0 도달 어려움 |
| ⑥ Recall@5 | 86 한계 | multi-keyword substring 매칭 (평균 2.2 키워드 모두 매칭 어려움) |
| ⑦ F1@10 | 93~94 한계 | Top-10 중 ground_truth (평균 9개) 모두 정확 추천 어려움 |
3. KPI 2 의 baseline (99.30) > target=0.95 (94.40) 현상
KPI 2 default STUB_TARGET = 0.995 가 0.95보다 높아서. 각 KPI default 값이 합격선 위에서 미세 조정되어 있음 — 의도된 합격 시뮬레이션 설계.
진짜 만점 도달 (real pipeline 개선)
stub 점수는 임의 조작이라 의미 X. 진짜 만점은 real pipeline 모델 개선:
| KPI | 현재 운영 (real) | real 만점 도달 방법 | 예상 점수 | 비용 |
|---|---|---|---|---|
| ① F1 | 72.42 | FinguAI-Chat-v1 → Claude/GPT-4 분류 prompt | 85~90 | API 비용 / 추론 시간 |
| ② Acc | 99.20 | 의도 분류 LoRA fine-tuning + 데이터 증강 | 99.7+ | GPU 학습 1일 |
| ③ BLEU | 81.68 | system prompt "3~5 문장" + 길이 강제 | 85+ | 30분 |
| ⑤ 개인화 | 0.3304 | LLM-Rec 평가 모델 GPT-4 → Claude 3.5 | 0.40+ | API 비용 |
| ⑥ NQ | 64.10 | FingUv2 → multilingual-e5-large + cross-encoder | 80~85 | 모델 다운 + 인덱스 빌드 1일 |
| ⑦ F1@10 | 89.08 | collaborative filtering 추가 + 카테고리 균형 | 92+ | 1일 |
실증 사이클 — 1초 단위 가능
# 1. STUB_TARGET 변경 (1초) export KPI1_STUB_TARGET=0.99 export KPI6_STUB_TARGET=0.95 # 2. 7 KPI × 3 iter 측정 (8초 총) .venv/bin/python /tmp/improve_test.py # 3. 점수 비교 (즉시 표시) # 결정성 검증 + raw 21건 저장
본 페이지의 72 측정도 총 약 20초 소요 (KPI 4 제외). 코드 변경 → 측정 → 검증 사이클은 1초~30초 단위로 무한 반복 가능.
결론 — KSEL 시험 권장
- STUB_TARGET 조작 금지 — 시험 제출 점수에 영향 주면 부정 행위
- 운영 환경 ENABLE_REAL_PIPELINE=true 재확인 — 시험관이 측정 시 진짜 모델 호출 보장
- 운영 5/12 측정값 (KPI 1 72.42) = real pipeline 점수 = KSEL 제출 가능
- 로컬 stub 점수 (75.30) = 시뮬레이션 = 내부 CI/검증용만
- 진짜 만점 도달 = real pipeline 모델 개선 (1주~1개월 작업, 시험 후 진행)