유사도만 넘고 그대로 겹친 구간이 없는 후보를 채택하지 않는다. 같은 주제를
다룬 글은 임베딩 유사도가 함께 오르므로 유사도 단독 판정은 오탐이 된다.
실데이터 106건 중 29건이 연속 일치 0자 또는 35자 미만이었고, 현장 검토에서
31건이 오탐으로 판정됐다. 이 조건을 걸면 106 -> 77건이 되어 그 29건이
빠진다. 반대로 새로 놓치는 건은 없다(미탐지 7,680건 재판정 결과 0건).
persistent_min_exact_span 기본값도 80 -> 35 로 내린다. 9어절 = 공백 포함
35자이며, 어절 3~9 스윕과 문서쌍 전수 대조로 정한 값이다. 이전 80은 근거
없이 잡힌 초기값이었다.
정밀도 지표(성능지표 #4)를 정면으로 겨냥한 변경이다. 오탐을 줄이는 방향이
정밀도 목표와 일치한다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획서 p.24 가 No.3/4/7 의 평가환경을 python 3.9 로 못박았는데, 실제로는
성능지표 평가 스크립트 3종이 전부 3.9 에서 임포트조차 되지 않았다.
python:3.9-slim 컨테이너에서 재현·수정·재검증했다.
원인: config.py 와 schemas.py 가 `from __future__ import annotations` 없이
`str | None` (PEP 604) 을 썼다. 3.10 부터의 문법이라 클래스 본문이 실행되는
순간 인터프리터가 평가하며 TypeError 로 죽는다. 이 두 파일을 타고 detector /
extractor / clustering / taxonomy / jobs.store / routes / main 이 연쇄로 깨졌다.
No.7 eval_rouge.py → summarizer → core.config
No.3 eval_metadata_f1.py → extractor → api.schemas
No.4 evaluate_pairs.py → detector → api.schemas
개발환경이 3.14 라 로컬에서는 전혀 드러나지 않았다. 정답셋을 받아 측정하는
시점에 발견했다면 일정이 밀렸을 문제다.
수정은 두 가지가 모두 필요하다. future 임포트만 넣으면 pydantic 이 문자열
'str | None' 을 해석하지 못하고("Unable to evaluate type annotation"),
eval_type_backport 만 넣으면 인터프리터가 먼저 죽는다.
검증: 3.9 에서 eval_rouge.py / eval_metadata_f1.py 가 정상 실행되고 수치가
3.14 와 동일하다(ROUGE-1 recall 0.5778). evaluate_pairs.py 와 app.main 임포트도
통과. 3.14 회귀 없음.
재발 방지로 tests/test_py39_compat.py 를 추가했다. Pydantic 모델을 정의하는
모듈에 future 임포트가 있는지 AST 로 검사하므로 3.14 에서도 회귀를 잡는다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
AI 생성 표본이 없어 정확도를 측정할 수 없는 상태에서, 규칙 기반 휴리스틱을
실제로 쓸 수 있게 만든다. 점수의 의미를 "AI일 확률"에서 "등록 코퍼스의 인간
저작물 대비 문체 이례도"로 재정의해, 라벨 없이도 참인 진술이 되도록 했다.
덤으로 high 배지 비율이 정의상 고정되어 검토 부하가 예측 가능해진다.
- ai_detector: low_cut/high_cut 주입 지원. 둘 다 주어질 때만 적용하고,
적용되면 model_version 에 +corpus-percentile 을 붙여 컷 출처를 드러낸다.
is_stub 은 여전히 true — 컷을 맞췄을 뿐 학습된 모델이 아니다.
- calibrate_cuts/percentile/score_text_heuristic 순수 함수 추가.
- scripts/calibrate_ai_detector_cuts.py: 코퍼스 표본의 점수 분포에서 백분위
컷을 산출하고 .env 두 줄을 출력한다.
- 규칙 점수가 상단에서 clip 되어 p90=p98 이 되면 그 컷은 high 배지를 영원히
0건으로 만든다. 이 경우 .env 를 출력하지 않고 exit 3 으로 중단하며
saturated_share/distinct_scores 진단을 남긴다. 유효 표본 100건 미만은 exit 2.
- kiwipiepy 유무가 점수를 바꾸므로 실제 사용 여부를 리포트에 기록하고 경고한다.
기본값은 그대로 비활성(AI_DETECTOR_ALLOW_HEURISTIC=false)이라 켜지 않으면
동작이 바뀌지 않는다. 컷 미설정 시에는 자리표시자임을 note 로 경고한다.
테스트 180건 통과 (신규 13건).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
컴북스 데이터 수령 전 가능한 작업을 선행 구현. 데이터 도착 즉시
학습·검증에 착수할 수 있도록 알고리즘·평가 하니스·문서를 준비.
알고리즘/파이프라인:
- engine/clustering.py: 군집화 기반 부분 표절(요소 교체) 판별,
detect 응답에 partial_signal 필드 노출 (계획서 2단계 표절검출 고도화)
- engine/summarizer.py + POST /v1/summary: TextRank 추출적 요약 +
통합(LLM) 골격 (과제2 ② 스토리 요약/분석)
- engine/preference.py + scripts/build_preference_dataset.py:
Human Feedback 선호학습(DPO) 데이터 파이프라인 골격
평가 하니스 (정답셋 도착 즉시 측정):
- engine/rouge.py + scripts/eval_rouge.py: 요약 ROUGE (지표 No.7)
- engine/metadata_eval.py + scripts/eval_metadata_f1.py: 메타 추출 F1
(지표 No.3, KLUE NER 호환)
- engine/case_coverage.py + scripts/analyze_case_coverage.py:
39 케이스 갭 분석 → 컴북스 데이터 요청 목록 (정밀도 97% 근거)
문서:
- docs/DATA_REQUEST_SPEC.md: 요청 데이터 스펙 + 요약 정답셋/HF 라벨 가이드
- docs/INTEGRATION_INTERFACE.md: 2단계 통합 인터페이스
- docs/SW_COPYRIGHT_REGISTRATION.md: SW 저작권 등록 준비
- docs/PHASE2_PROGRESS.md, docs/CASE_COVERAGE.md
테스트 31 → 67건 전부 통과.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- config.Settings에 host/port/log_level/reload 필드 추가
- app/main.py에 main() + __main__ 진입점 추가 (python -m app.main)
- Dockerfile: python:3.13-slim 베이스로, CMD를 python -m app.main 으로 변경
- docker-compose: env_file 사용, ports를 ${PORT} 변수화
- 환경변수 PORT=N 으로 override 가능 (uvicorn 직접 실행도 그대로 지원)