오류 내성 곡선 — 모델 계열(dense · 리랭커 · 규칙+NER)을 같은 그림에 얹는다 + 모델 구성 하네스 참고치
무엇을
2026-09-21 정성윤 님이 운영 구성(규칙 + BM25) 으로 낸 STT 오류 내성 곡선(jekyll/assets/error-tolerance-2026-09-21.png)에는
모델 계열이 없었다 — 그 머신에 모델 파일이 없어 meta.skipped 로 남겼다. 모델이 다 있는 이 맥에서 같은 조건(시드 3개 ·
오류율 0/5/10/15/20% · 골든셋 v1-150)으로 dense · dense+리랭커 · 규칙+NER 을 재어 운영 계열과 한 그림에 얹고,
decisions/121 §5 가 정한 대로 모델 구성 하네스 값을 로컬 측정 참고치로 나란히 적는다.
왜
- 성공 조건 1번(STT 오류 내성 실험)은 운영 곡선으로 처음 그림이 나왔지만, 운영에 무엇을 더 켤지(
decisions/208— NER·임베딩 먼저, 리랭커는 미룸)를 판단하려면 같은 축 위에서 모델 계열과 비교해야 한다. - 규칙 마스킹이 오류 5% 부터 뚫리는 것(누락 0→2→3→4→4)이 NER 이 필요한 근거였는데, 09-15 로컬 값(0/0/1/1/1)은 골든셋·시드가 달랐다. 같은 조건으로 다시 재야 비교가 된다.
완료 조건
- 모델 3계열이 운영 2계열과 한 JSON·한 그림에 있다 —
jekyll/assets/error-tolerance-2026-09-21-models.json·.png(운영 파일error-tolerance-2026-09-21.*은 덮어쓰지 않았다) - 운영 계열이 재현된다 — 이 실행의 bm25·rule 행이 09-21 운영 JSON 과 점마다 동일(시드별 값·누락 항목 ID 까지)
- 모델 구성 하네스 3회 최저치(retrieval · masking)
- 측정일·커밋·명령·표본 수 + 낙관 요인을 결과 옆에 적었다
측정 조건 (§5 — 값에 붙는 넷)
| 측정일 | 2026-09-21 |
| 커밋 | 97f7b25 — 곡선 측정 시점에 작업 트리가 깨끗했다. 하네스 실행 시점에는 측정 코드 무수정, 트리에는 그림 스크립트(plot_error_curve.py, 그리기만) 수정과 산출물만 있었다 |
| 골든셋 | v1-150.json 의 시작 시점 스냅샷(md5 fb3436ea…, 다른 세션이 F-2 항목을 넣는 중이라 사본으로 고정) — meta.golden_set 에 v1-150-snapshot.json 으로 찍혀 있다 |
| 곡선 명령 | ELASTICSEARCH_URL=http://localhost:9200 .venv/bin/python scripts/measure_error_tolerance.py --device mps --golden-set <스냅샷> (83초) |
| 그림 명령 | .venv/bin/python scripts/plot_error_curve.py --json jekyll/assets/error-tolerance-2026-09-21-models.json --out jekyll/assets/error-tolerance-2026-09-21-models.png |
| 하네스 명령 | .venv/bin/python scripts/run_eval.py --runs 3 --retriever rerank-dense --device mps --golden-set <스냅샷> (22초) · 같은 명령 --retriever dense (9초). NER 은 기본값(models/koelectra-ner)으로 켜졌다. --record 는 하지 않았다(기록 DB 없음) |
| 표본 | 검색 B 항목 96 · C-5 판정 24(주입 말뭉치는 고객 발화 전부) · 하네스 masking n 28 · 시드 20260914/15/16 |
| 어디서 | Apple M5 맥, torch 2.13 mps, ES 9.5.1 도커(callguard-kb-single 98조항 + KoE5 1024-d 임베딩 적재 상태) |
결과 — 오류 내성 곡선 (시드 3개, 검색은 최저·마스킹은 최대. 괄호는 시드 중 최대·최소)
검색 Recall@5 / MRR (n 96)
| 목표 오류율 | 실제 WER | bm25 (운영) | dense | dense+리랭커 |
|---|---|---|---|---|
| 0% | 0.000 | 0.833 / 0.666 | 0.979 / 0.885 | 0.979 / 0.919 |
| 5% | 0.051~0.052 | 0.823 (최대 0.833) / 0.658 | 0.979 (최대 0.990) / 0.878 | 0.979 (최대 0.990) / 0.914 |
| 10% | 0.100~0.102 | 0.812 (최대 0.833) / 0.653 | 0.979 (최대 0.990) / 0.878 | 0.979 (최대 0.990) / 0.908 |
| 15% | 0.151 | 0.812 (최대 0.833) / 0.644 | 0.979 / 0.869 | 0.979 / 0.910 |
| 20% | 0.200 | 0.792 (최대 0.823) / 0.621 | 0.969 (최대 0.979) / 0.873 | 0.969 (최대 0.979) / 0.898 |
C-5 누락 건수 (판정 24, 음성 과잉 0/4 전 구간)
| 목표 오류율 | 실제 WER | 규칙 (운영) — 최대 (최소) | 규칙+NER — 최대 (최소) |
|---|---|---|---|
| 0% | 0.000 | 0 | 0 |
| 5% | 0.050 | 2 (0) — GS-033·GS-415 (P7 주소) | 0 (0) |
| 10% | 0.101~0.102 | 3 (1) — + GS-056 (P6 이름) | 0 (0) |
| 15% | 0.151 | 4 (1) — GS-033 · GS-037·GS-412·GS-413 (P6) | 1 (0) — GS-037 (P6) / 시드 15 는 GS-415 (P7) |
| 20% | 0.200 | 4 (1) | 1 (0) — 15% 와 같은 항목 |
결과 — 하네스 모델 구성, 3회 최저치 (참고치, decisions/121 §5)
| 구성 | retrieval Recall@5 / MRR (n 96) | masking 누락 / 오분류 / 과잉 (n 28) |
|---|---|---|
| 운영: 규칙 + bm25 (09-21 정성윤, 같은 골든셋) | 0.833 / 0.666 | 0 / 0 / 0.0 |
| NER + dense | 0.979 / 0.885 | 0 / 0 / 0.0 |
| NER + dense + 리랭커 (bge-reranker-v2-m3) | 0.979 / 0.919 | 0 / 0 / 0.0 |
3회가 전부 같은 값이었다(모델 추론이 결정적이고 ES 인덱스가 고정이라 흔들릴 요소가 없다). compliance·call_guard 는 1.0/1.0 으로 운영 구성과 같다(자기충족 — 상한). closure_gate·trigger 는 그대로 측정 불가.
운영 곡선 대비 무엇이 달라졌나
- 검색: dense 가 bm25 보다 전 구간 +0.15 안팎 높고(0.979 vs 0.833), 20% 까지 0.969 를 지킨다 — 오류가 늘수록 bm25 는 0.04 떨어지는데 dense 는 0.01 이다.
리랭커는 Recall@5 를 한 건도 더 맞히지 못하고(히트 수가 점마다 같다) MRR 만 +0.03 올린다 — 5개 안에 있던 정답을 위로 올리는 효과뿐이다.
decisions/208(리랭커는 미룬다)과 방향이 같다. - C-5: 규칙+NER 은 10% 까지 누락 0, 15% 부터 1건(P6 이름 또는 P7 주소, 시드에 따라 다르다). 규칙만은 5% 에서 이미 2건이다. 09-15 로컬 값(0/0/1/1/1)과 같은 모양이다. 「누락 0」이 오류 있는 전사에서도 성립하는 구성은 NER 을 켠 쪽뿐이고, 그것도 10% 까지다.
낙관 요인 — 이 숫자를 옮길 때 같이 옮긴다
- 주입기가 실측 STT 편집의 46.9%(환청·의미 붕괴)를 흉내 내지 못한다 — 같은 WER 에서 실제보다 덜 파괴적이라 곡선 전체가 낙관 쪽이다(그림 안에도 박혀 있다).
- 골든셋은 규칙·모델 구성을 만든 사람이 본 뒤의 값이다 — 상한이지 일반화 성능이 아니다. 특히 C-5 판정 24건은 표본이 작아 1건 = 4%p 다.
- 이 맥(Apple M5, mps)에서 잰 것이라 지연·메모리는 운영(t3.large /
decisions/121의 전용 GPU EC2)과 무관하다 — 여기서는 품질 값만 쓴다. - 리랭커·dense 는 지금 운영에 켜져 있지 않다(
decisions/121·208). 운영 기준선은 여전히 규칙 + bm25 행이다.
고친 것
scripts/plot_error_curve.py— 그리기만 두 군데. ① 두 계열이 같은 끝점에 닿으면(dense · rerank-dense 가 실제로 그랬다) 끝점 라벨을 한 줄 아래로 비킨다(점 위치는 그대로). ② 명령 문자열이 길면 하단 스탬프가 잘려 §5 의 「명령」이 그림에서 사라지므로 줄바꿈해 전부 남긴다. 운영 JSON 으로 다시 그려 회귀 없음을 확인했다. 두 JSON 을 합치는 옵션은 만들지 않았다 — 측정 스크립트 한 번에 운영 2계열이 같이 나오고 값이 09-21 과 동일해서 합칠 것이 없었다.matplotlib을.venv에만 깔았다(스크립트 독스트링대로requirements.txt에는 넣지 않는다).
남은 것
- 이 값을 운영으로 옮기려면
decisions/121의 전용 GPU EC2 가 먼저다 — 거기서 같은 명령을 돌려 지연까지 재고 이 티켓 값과 나란히 적는다. - C-5 15% 이상에서 NER 이 놓치는 P6(
GS-037)·P7(GS-415)은w5-c5-masking-gaps소관으로 넘긴다 — 여기서는 규칙·모델을 고치지 않았다.