6. 평가 설계
⚠ 2026-08-28 방향 전환 — 이 페이지보다 결정 기록이 우선한다
도메인을 다산콜센터 하나로 줄이고 외국인 고객 지원을 차별점으로 세웠다
(_project/decisions/201, 비공개). 아래 본문의 금융보험·쇼핑·질병관리본부 서술은
그 시점의 사실이라 지우지 않았다 — 절대 원칙 8(“실패를 지운 기록은 기록이 아니다”)과
같은 이유로, 계획이 바뀐 사실 자체가 기록이다.
이 페이지에서 바뀐 것: ① B-0 도메인 분류 정확도 지표는 폐기됐다 ② F-2 채점 케이스가 0건이다 → 2026-09-22 f2_case 99건으로 채워졌다(필요서류 체크리스트, decisions/125) ③ 이전 실측치 Recall@5 0.857 / MRR 0.702 는 무효 — 4개 도메인 14건 기준이었다. 다산 기준 재측정 전까지 이 페이지에 숫자를 다시 적지 않는다(절대 원칙 2). ④ A-3 A-5(동시 통번역 — A-3 은 WebSocket 전달이다, 2026-09-28 오기 정정) 번역 품질을 무엇으로 채점할지 아직 정하지 않았다 — LLM 채점은 절대 원칙 1이 막는다. 1차 범위(서툰 한국어 전사)는 숙련도 4등급 WER 로 2026-09-21 실측했다(하네스 밖 scripts/measure_a5_proficiency.py).
6.1 지표
⚠ 오른쪽 실측 열은 2026-08-28 전부 무효가 됐다 — 4개 도메인 골든셋 14건으로 잰 값인데
도메인이 다산 하나로 줄었다(decisions/201). 지우지 않고 취소선으로 남긴다(절대 원칙 8) —
잰 사실 자체는 기록이고, 재측정 전까지 이 자리에 새 숫자를 넣지 않는다(절대 원칙 2).
| 영역 | 지표 | 목표 기준선 | |
|---|---|---|---|
| B-0 | 도메인 분류 정확도 (자동 분류, 3.2절) | ||
| 검색 | Recall@5 | ≥ 0.70 (오류 없음) / ≥ 0.60 (오류 10%) | eval_run run_id 1·2 · 커밋 19b8400 · 3회 최저)에서 같은 값 |
| 검색 | MRR | ≥ 0.55 | eval_run run_id 1·2 · 커밋 19b8400 · 3회 최저)에서 같은 값 |
| 트리거 | 적절 발동률 (종료 후 0~1,500ms) | ≥ 0.85 | |
| 트리거 | 조기 발동률 / 지연 발동률 | 각각 별도 집계 | |
| 트리거 | 발동 지연시간 분포 (p50/p95) | 측정·기록 (허용 창은 합/불 판정선일 뿐, 개선 추이는 이 분포로 본다) — ⚠ 하네스로는 채점하지 않는다(골든셋에 도착 시각이 없어 재면 가짜 만점이다). 운영 경로 값으로만 본다 | |
| 생성 | 환각 수치 발생 | 150문항 중 5건 이하 | |
| 생성 | 출처 표시율 | 100% | |
| 컴플라이언스 | 재현율 | ≥ 0.90 | |
| 컴플라이언스 | 정밀도 | ≥ 0.60 | |
| C-5 | P1~P7 패턴 마스킹 누락 | 0건 — 절대 규칙 | eval_run run_id 1·2 · 커밋 19b8400 · 3회 최저)에서 같은 값 |
| C-5 | 과잉 마스킹률 | 참고 기록 (목표 아님) | |
| C-5 | STT 오류율별 마스킹 재현율 | 곡선 기록 | |
| 성능 | 내부 처리 p95 | ≤ 1,000ms | |
| 성능 | E2E 체감 지연 | 측정·기록 — 2026-09-23 현재 미측정(w7-latency-budget, 수동 QA 게이트 뒤). 합성 통화 관찰값(첫 추천 1,352~3,300ms)은 STT 를 거치지 않아 E2E 가 아니다 |
|
| 성능 | 통화당 토큰 비용 | 측정·기록 — 생성 모델을 운영에 싣지 않아 해당 없음(decisions/124, 카드는 스니펫 폴백) |
|
| F-2 | 종결 요건 판정 정확도 → 필요서류 체크리스트(decisions/201·305) |
100% — 절대 규칙 (조건부 착수) | 1.0 (n=99, run_id 8·9 둘 다 — ⚠ 규칙표 상한, 자동 판정은 미측정. decisions/118 되돌림은 팀 판단) → 2026-10-01 최종 측정(운영 노드 측정 파드 · 운영 RDS eval_run run_id 1·2 · 커밋 19b8400 · 3회 최저)에서 같은 값 |
decisions/201) |
— | ||
decisions/132) |
— | ||
| G-2 | 자원 매칭 정확도 | ≥ 0.95 (여유 시 — 미구현 시 N/A) | |
| G-2 | 폐지·이전 기관 반환 | 0건 (여유 시 — 미구현 시 N/A) | |
| F-1 / G-1 | 탐지 성능 | 측정 불가 — 5.5절 |
부록 B의 H·I 지표는 착수 확정 시 이 표에 편입한다.
첫 실측 (2026-08-27, 잠정)
측정일 2026-08-27 · 커밋 39cbe68 기준 작업분 · 표본 golden-set/v1-50.json
(검색 B 케이스 14건 / 도메인 라벨 34건) · 재현:
# ES 기동 — 컴포즈는 2026-09-08 에 걷어냈다(decisions/107). 측정 당시 명령은
# `cd infra && docker compose up -d elasticsearch` 였고, 같은 이미지·같은 버전이다.
docker run -d --name callguard-elasticsearch -p 127.0.0.1:9200:9200 \
-e discovery.type=single-node -e xpack.security.enabled=false \
-e ES_JAVA_OPTS="-Xms512m -Xmx512m" seongyuna/callguard-es:9.5.1
export ELASTICSEARCH_URL=http://localhost:9200
.venv/bin/python scripts/index_knowledge_base.py --to-es --recreate
.venv/bin/python scripts/run_eval.py --golden-set golden-set/v1-50.json --runs 3
3회 실행 최저치가 1회 값과 같다 — BM25 도 검색 기반 도메인 판정도 결정적이라 흔들리지 않는다 (절대 원칙 4의 “최저치 고정”이 여기서는 자명하게 성립한다). 임베딩이 들어가는 4주차부터는 다시 본다.
이 값은 잠정이다. 공식 기준선은 3주차 골든셋 150건 재측정이고, CI 게이트로 고정하지 않는다
(w2-baseline-gate).
검색은 목표를 넘겼다. BM25(nori) 단독인데 Recall@5 0.857 · MRR 0.702 다.(2026-08-28 무효 — 4개 도메인 기준) 못 맞힌 2건은 둘 다 정답이TERM인데MANUAL이 상위를 채웠고, 다른 도메인 문서까지 섞였다 — 도메인 필터를 못 걸고 있어서다(미결).-
B-0 은 0.857 로 목표(0.95)에 못 미친다. 그리고 이 지표는 재는 방법 자체가 틀려 있었다.
처음에는 도메인 라벨이 있는 34건 전체로 재서 0.647 이 나왔다. 그런데 그중 20건이 C·C-5 항목(마스킹·컴플라이언스 시나리오)이고, 그 발화에는 도메인 단서가 아예 없다 — “본인 확인을 위해서 주민등록번호를 불러주시겠어요?” 가 어느 도메인인지는 텍스트만 보고 알 수 없다. 그 항목의
domain은 “어느 시나리오에 속하는가”를 적은 메타데이터지 발화에서 추론할 대상이 아니다. 실제로 그 20건에서는 어떤 방식으로도 0.45~0.50(사실상 찍기)이었다.B-0 은
decisions/007대로 통화 초반 고객 발화로 판정하는 것이므로 채점 대상을 B(검색) 항목 14건으로 좁혔다(harness.py). 그러자 0.857 이 됐다.채점 대상 검색 기반 v1 KcELECTRA 분류기 전체 34건 (틀린 방법) 0.647 0.588 B 14건 (바른 방법) 0.857 0.786 C·C-5 20건 0.500 0.450 -
⚠ 파인튜닝한 분류기가 검색 기반 v1 보다 낫지 않다. 학습을 키워도 그대로였다.
방식 AI Hub 검증 골든셋 (n=14) 검색 기반 v1 — 0.857 (12/14) 분류기 2 epoch 0.815 0.786 (11/14) 분류기 4 epoch + 초반턴 증강 13,204건 0.879 0.786 (11/14) AI Hub 는 +6.4%p 올랐는데 골든셋은 혼동 행렬까지 한 자리도 안 바뀌었다 — 틀린 3건이 완전히 같다. 학습을 키운 효과가 골든셋으로 전혀 전이되지 않았다.
틀린 3건은 전부
finance로 가고 신뢰도가 0.77~0.97 이다 — 헷갈리는 게 아니라 확신을 갖고 틀린다.발급·처리·비용이 AI Hub 금융 데이터에 압도적으로 많은 탓으로 보이고, 데이터를 더 넣고 더 오래 학습할수록 이 편향은 강해진다.반대로 v1 은 그 3건을 다 맞히고 다른 2건(GS-002·GS-019)을 틀린다 — 두 방식이 서로 다른 데서 틀린다. 합치면 둘 다 넘길 여지가 있다(RRF 병합 함수는 이미 있다,
decisions/021). 자세한 건 w1-domain-routing.기본값은 v1 이다. 분류기는
--domain-router model로 명시해야 쓰인다 — 더 나쁜 쪽이 조용히 끼어들면 안 된다. - ⚠ n=14 로는 애초에 “≥0.95” 를 판정할 수 없다. 14건에서 0.95 를 넘으려면 14/14 여야 한다(13/14 = 0.929). 즉 만점 말고는 통과가 없다. 두 방식의 차이(12/14 vs 11/14)도 한 건 이라 의미를 두기 어렵다. 3주차 골든셋 150건 확장 때 도메인 판정용 표본을 따로 늘려야 이 목표를 잴 수 있다.
- 나머지 지표는 모듈이 없어 “측정 불가 — 모듈 미구현” 으로 보고된다. 트리거는 구현이 있지만 일부러 꽂지 않았다 — 발동 시각을 상수로 모형화하고 있어 숫자가 나와도 측정이 아니다(w3-trigger-v1, 절대 원칙 10).
도메인 4종 반영 (2026-08-26) — Recall@5·MRR 등 검색 지표는 4개 도메인 전체 평균과 함께 도메인별로도 따로 집계한다. 도메인마다 지식베이스 크기·카테고리 수가 달라 평균값 하나로는 특정 도메인의 부진을 가릴 수 있다.
실측 (2026-09-22) — run_id 8·9
⚠ 「운영 구성」이라는 말을 쓰지 않는다. 2026-09-22 12:10 이전에는 그 말이 BM25 를 가리켰고 그 뒤로는 dense 를 가리켜, 같은 표 안에서 서로 다른 것을 뜻했다. 아래 두 이름만 쓴다.
이름 무엇 지금 운영에? BM25 기준선 규칙 마스킹 + BM25(nori), NER 끔 ❌ — 09-22 12:10 이전의 운영 구성. 지금은 dense 가 0건일 때의 대체 경로다 운영 실구성 규칙+NER(koelectra-ner) + KoE5 dense, 리랭커 없음, B-6 문턱 꺼짐 ✅ 09-22 12:10 부터( decisions/124)
모델 구성 값은 운영에 없는 구성이다(→ 2026-09-24 정정: 사실이 아니다.decisions/121).decisions/124가121(전용 GPU)을 대체해 NER·KoE5 임베딩을 운영 노드 CPU 에 실었고, 09-22 12:10 부터 운영/health의 spokes 에pii_ner·retrieval_dense가 있다. 운영에 없는 것은 리랭커뿐이다.
공통 조건 — 측정일 2026-09-22 17:08 KST · 커밋 5b2b4c4 · 골든셋 파일 golden-set/v1-150.json 내부판 v1-150.2(295건)
= B 102 · B-6 23 · F-2 99 · C-5 항목 36(패턴 인스턴스 40) · C-6 15 · D-1 10통화(golden-set/postcall-v1.json) ·
ES 인덱스 101청크(여권 TERM-4.23 포함 · nori 품사 필터 decisions/214) · device cpu · 각 3회 최저치 · --record(⚠ 로컬 기록 DB, 운영 RDS 아님).
류준이 run_eval.py --runs 3 --retriever dense --record(run_id 8)와 --runs 3 --no-ner --retriever bm25 --record(run_id 9)로 쟀다.
값의 출처는 _project/STATE.md 「실측값」.
| 지표 | 목표 | 운영 실구성 (run_id 8) | BM25 기준선 (run_id 9) |
|---|---|---|---|
| 검색 Recall@5 (n 102) | ≥ 0.70 | 0.971 ✅ (99/102) | 0.853 ✅ (87/102) |
| 검색 MRR (n 102) | ≥ 0.55 | 0.875 | 0.686 |
| C-5 누락 (n 40, 오류 0%) | 0건 | 0 ✅ | 0 ✅ |
| C-5 오분류 · 과잉 (n 40) | 참고 | 0 · 0.0 | 0 · 0.0 |
| F-2 판정 정확도 (n 99) | 100% | 1.0 ⚠ 규칙표 상한 | 1.0 |
| B-6 정답 없음 기권 (n 23) | 측정·기록 | 0 (문턱 꺼짐) | 1 |
| B-6 문턱 | 측정·기록 | dense 1순위 <0.67 기권을 채택했다가 같은 날 보류(대화체 60% 기권, decisions/215) — 기본값 꺼짐 |
해당 없음(눈금이 다르다) |
| 컴플라이언스(tp 14) · 콜 가드(n 15) | ≥0.90/0.60 | 1.0/1.0 ⚠ 자기충족 상한 | 같음 |
| D-1 요약 핵심 항목 (10통화 · 60항목) | 측정·기록 | 매크로 0.381 · 마이크로 0.35 (21/60) → 2026-10-01 최종 측정(run_id 1·2 · 커밋 19b8400): 매크로 0.877 · 마이크로 0.883 (53/60) |
같음 |
| D-2 문의 유형 정확도 | 측정·기록 | 측정 불가 — 유형이 null(이 커밋은 decisions/323 머지 전) → 2026-10-01 최종 측정(run_id 1·2 · 커밋 19b8400): 1.0 (n 10통화 · 유형 null 0 · 5종 중 3종 표본) |
같음 |
| 트리거 · D-5 통화 온도 · 생성 · A-5 | — | 측정 불가(의도적 미배선 · 음성 골든셋 0건 · 생성 포트 미장착) — D-5 는 발표 전 배선하지 않기로 확정(decisions/317) |
같음 |
STT 오류 내성 곡선 — ⚠ 한 세대 낡았다. 커밋 e966b62 · 골든셋 v1-150.1 · 검색 n 96 · C-5 판정 24 에서 잰 것이고,
5b2b4c4·v1-150.2 로는 아직 다시 재지 않았다. 위 표(n 102)와 같은 문장에서 섞어 쓰지 않는다.
(scripts/measure_error_tolerance.py, 시드 3 — 검색은 최저, C-5 누락은 최대)
| 오류율 | Recall@5 dense | BM25 | dense+리랭커 | C-5 누락 규칙만 | 규칙+NER |
|---|---|---|---|---|---|
| 0% | 0.969 | 0.812 | 0.969 | 0 | 0 |
| 5% | 0.969 | 0.812 | 0.969 | 1 | 0 |
| 10% | 0.969 ✅(기준 ≥0.60) | 0.792 | 0.969 | 2 | 0 |
| 15% | 0.969 | 0.802 | 0.969 | 4 | 2 |
| 20% | 0.969 | 0.792 | 0.969 | 4 | 2 |
읽을 때 붙이는 단서 —
- C-5 「누락 0」은 오류 없는 전사에서만 성립한다. 규칙만은 5% 오류에서 이미 1건·10%에서 2건이 새고, 운영 실구성이 쓰는 규칙+NER 도 15% 부터 2건(P7 주소)이다. 실제 통화는 STT 를 거치므로 절대 규칙을 「통과」로 인용할 때 반드시 이 한정을 붙인다.
- 주입기는 실측 STT 오류의 46.9% 를 흉내 내지 못한다 — 곡선 전체가 낙관 쪽이다. 골든셋은 규칙·구성 작성자가 본 뒤의 값이라 상한이다.
- 리랭커는 운영에 없다(
decisions/124) — Recall@5 를 한 건도 더 맞히지 못하고 MRR 만 올린다. - F-2 1.0 은 「코드가 규칙표를 그대로 따르는가」이지 「안내가 실제로 충분했는가」가 아니다(발화 → 근거 자동 판정은 미측정).
기록 DB 가 없어→ 풀렸다 — run_id 8·9 가 남았다. 남은 단서는 로컬 기록 DB라는 것 하나다.--record를 못 했다(run_id 없음).
그때의 값 — 2026-09-21 (골든셋 156건 · n 96 · 기록 DB 없음)
| 지표 | 규칙+BM25 | NER+dense | +리랭커 | |---|---|---|---| | 검색 Recall@5 (n 96) | 0.833 | 0.979 | 0.979 | | 검색 MRR (n 96) | 0.666 | 0.885 | 0.919 | | C-5 누락 (n 28) | 0 | 0 | 0 | BM25 쪽은 정성윤이 커밋 `261bce4-dirty` 로, 모델 계열은 류준이 커밋 `97f7b25`(Apple M5 mps)로 쟀다. 그림 [2계열](/assets/error-tolerance-2026-09-21.png) · [5계열](/assets/error-tolerance-2026-09-21-models.png). **표본이 달라 위 표와 항목 단위로 비교할 수 없다** — 그 뒤 여권 조항이 들어오고(`decisions/217`) nori 품사 필터가 붙었다(`decisions/214`).6.2 채점 원칙
- LLM을 채점자로 쓰지 않는다. 답을 만든 모델이 자기 답을 심판하면 순환이 된다. 모든 지표를 규칙으로 계산해 재현 가능하게 한다.
- 여러 번 실행한 값 중 최저치를 기준선으로 고정한다. 생성 모델은 같은 입력에도 답이 달라진다.
- 기준선 미달 시 CI 실패로 처리한다. 개선이 아니라 회귀 방지가 목적이다.
- C-5·F-2의 절대 규칙은 1건이라도 뚫리면 실패로 처리한다. 평균값으로 평가하지 않는다.
- 모든 지표는 정답 정의가 코드로 표현 가능해야 한다. 표현할 수 없는 지표는 지표가 아니다 (4.1절 트리거 허용 창이 그 예).