최종 측정 — 발표·제출에 쓸 수치를 한 번에 고정한다

무엇을

코드 동결 뒤 하네스를 마지막으로 한 번 돌려 발표·최종 문서에 쓸 수치를 고정한다. 검색(오류 없음 / 10%) · C-5 누락 · 오류 내성 곡선 · 환각 · 컴플라이언스 · 콜 가드 전부.

왜 따로 티켓인가

수치가 문서 여러 곳에 서로 다른 날의 값으로 흩어져 있다(09-09 · 09-15 로컬 · 09-21 운영 구성). 발표 자료가 그중 좋은 것을 골라 쓰면 같은 슬라이드에 서로 다른 커밋의 값이 섞인다. 한 커밋 · 한 명령 · 한 날로 고정하고, 그 밖의 값은 「그때의 값」으로만 인용한다.

완료 조건


동결 때 그대로 돌릴 절차 (2026-09-22 준비 — 실행은 안 했다)

09-22 에 두 구성을 이미 재 봤다 — 판정용 정본은 run_id 8(운영 실구성: 규칙+NER · KoE5 dense, **리랭커 없음)·run_id 9(BM25 기준선), 커밋 5b2b4c4 · 골든셋 v1-150.2(295건) · 내보내기 data/processed/eval-export/2026-09-22-run-8-9.json (w6-model-config-remeasure). 그 앞의 run_id 1·2(121157e)·3·4(e966b62)·5·6 은 옛 판이다. **run 8·9 도 동결 전 값이다 — 이 티켓의 값으로 쓰지 않는다. 동결 커밋에서 아래를 한 번에 다시 돌린다.

⚠ 이름을 가른다 — 「운영 구성」이라는 말을 쓰지 않는다. BM25 기준선(규칙 + BM25·nori, NER 끔)과 운영 실구성(규칙+NER + KoE5 dense, 리랭커 없음, B-6 문턱 꺼짐 — 09-22 12:10 부터 운영, decisions/124) 둘로 부른다.

0. 동결 커밋을 정한다 — git rev-parse --short HEAD 를 여기 적는다. 워킹트리가 깨끗해야 한다 (09-22 에는 추적 안 되는 .claude/worktrees/ 때문에 -dirty 가 찍혔다 — 지우거나 다른 클론에서 돌린다).

1. 인프라 (infra/README.md 「로컬 개발」)

docker start callguard-elasticsearch callguard-postgres   # 없으면 README 의 docker run 두 줄
# ⚠ 5432 를 다른 프로젝트가 쓰면 Postgres 는 127.0.0.1:5434 로 띄운다(09-22 에 그랬다)
.venv/bin/python scripts/index_knowledge_base.py --to-es --recreate --embed-model models/koe5
export ELASTICSEARCH_URL=http://127.0.0.1:9200
export DATABASE_URL=postgresql://callguard:callguard-dev@127.0.0.1:5434/callguard   # 프로세스 환경변수로만. .env 를 고치지 않는다

2. 두 구성 — 각 3회 최저, 기록 (절대 원칙 4)

.venv/bin/python scripts/run_eval.py --runs 3 --no-ner --retriever bm25 --record          # BM25 기준선
.venv/bin/python scripts/run_eval.py --runs 3 --retriever dense --record                  # 운영 실구성 — ⚠ rerank-dense 가 아니다

⚠ --retriever rerank-dense 를 쓰지 않는다. 운영에는 리랭커가 없다(decisions/124 — NER·KoE5 만 운영 노드 CPU 에 싣는다). 리랭커를 켠 값은 운영에 없는 구성의 값이라 「로컬 참고치」로만 실을 수 있다. 판정·발표에 쓰는 열은 --retriever dense 다.

3. 생성(B-4) — Ollama 에 kanana 가 등록돼 있을 때만(decisions/207)

.venv/bin/python scripts/run_eval.py --runs 3 --retriever dense --record \
  --ollama-url http://localhost:11434 --generation-model kanana-1.5-2.1b-instruct:q4_k_m
.venv/bin/python scripts/eval_generation.py        # 원출력 환각은 하네스 밖에서만 잰다(포트가 원출력을 주지 않는다)

4. 오류 내성 곡선 — scripts/measure_error_tolerance.py (시드 3개, 두 구성 한 번에)

5. A-5 — 하네스로는 늘 측정 불가다. scripts/measure_a5_proficiency.py 결과를 그 날짜·커밋 그대로 따로 싣는다(STT 캡 확인).

체크리스트

2026-10-01 — 동결 커밋 기준 (정성윤)

동결 커밋은 발표 전 마지막 main 머지 커밋이다(decisions/138). 발표 전에 못 돌리면 run 8·9 를 그대로 인용한다 — 새 측정을 급히 만들어 네 조건을 못 채우는 쪽이 더 나쁘다. 곡선 재측정도 이 티켓에서 같이.

2026-10-01 — done — 발표 정본은 run 8·9 (정성윤, decisions/138)

발표 전에 동결 커밋에서 다시 돌리지 않는다. 류준 로컬 ES·기록 DB 가 이 머신에 없고, 급히 만든 새 측정은 §5 네 조건을 못 채운다. 인용 정본: run_id 8·9 · 2026-09-22 · 커밋 5b2b4c4 · 골든셋 v1-150.2 295건 · 3회 최저 · --record(⚠ 로컬 기록 DB). 곡선은 e966b62·n 96 을 「한 세대 앞 판」으로 밝히고 인용. 측정 불가 목록·한계 넷·문구 셋은 판정문(_logs/2026-09-30-02)과 138 에 있다. 발표 뒤 시간이 있으면 같은 명령으로 동결 커밋에서 한 번 더 돌리고 run_id 를 138 에 적는다 — 그건 이 티켓이 아니라 새 티켓이다.

2026-10-01 — 최종 측정을 실제로 돌렸다 (정성윤) · done 유지

「정본 채택」으로 닫았던 것을 실측으로 바꿨다. 운영 노드에 측정 전용 파드(서버 이미지 0.1.44, 3Gi, 평가 하네스·골든셋·합성 대본을 tarball 에서 넣음)를 띄워 운영 ES·운영 RDS 에 붙여 돌렸다. 세 번 시도 — 하네스가 이미지에 없음(.dockerignore) → 대본 파일 없음 → 성공.

네 조건 — 측정일 2026-10-01 10:5x KST · 커밋 19b8400(main, PR #159 머지) · 명령 python scripts/run_eval.py --runs 3 --retriever dense --record(운영 실구성 — 규칙+NER · KoE5 dense · 리랭커 없음) / --runs 3 --no-ner --retriever bm25 --record(BM25 기준선) · 골든셋 golden-set/v1-150.json(내부판 v1-150.2, 295건) · 표본 수는 표에 · 운영 RDS eval_run run_id 1(dense)·2(bm25) — 로컬 기록 DB 가 아니다. 리포트 data/processed/eval-export/2026-10-01-final-dense.json·-bm25.json.

항목 운영 실구성 (run_id 1) BM25 기준선 (run_id 2) 09-22 run 8·9 와
B 검색 Recall@5 (n 102) 0.971 0.853 같음
B 검색 MRR (n 102) 0.875 0.686 같음
C-5 누락 (n 40 패턴 인스턴스) 0 · 오분류 0 · 과잉 0.0 0 · 0 · 0.0 같음
F-2 판정 (n 99) 1.0 1.0 같음 — 규칙표 안
B-6 정답 없음 기권 (n 23) 0 (문턱 꺼짐 215) · 1순위 점수 0.588~0.761 1 같음
컴플라이언스 (tp 14) · 콜 가드 (n 15) 1.0 / 1.0 같음 자기충족 상한
D-1 요약 핵심 항목 (10통화 · 60항목) 매크로 0.877 · 마이크로 0.883 · 유형 1.0 같음 09-22 는 0.35 — 09-23 규칙 보강(218) 뒤 처음 기록된 값

측정 불가 목록(리포트 문구 그대로) — trigger(모듈 미구현 — 일부러 채점하지 않는다) · domain_routing(폐기) · call_temperature(채점 대상 없음) · asr(하네스에 STT 포트 없음) · generation(생성 포트 안 꽂음). 오류 내성 곡선은 다시 재지 않았다 — measure_error_tolerance.py 는 이 파드에 안 넣었다. 곡선 인용은 그대로 e966b62·n 96 「한 세대 앞 판」. 한계 넷 — C-5 「누락 0」은 오류 없는 전사 한정 · 주입기 46.9% · 쌍둥이 조항(123) · 컴플라이언스·콜 가드·F-2 1.0 은 상한. 리랭커 값 없음(운영에 없는 구성).