# opik_prompt_audit — Opik 역추적 프롬프트 감사 도구

실제로 모델에 나간 프롬프트(Opik trace)에서 출발해 비대의 원인을 거꾸로
찾는다. 파일이 아니라 **발송분이 SOT** — 팩을 아무리 읽어도 조립·주입 후
실물은 다르다.

## 무엇을 재는가

1. **스텝별 발송량** — 호출 수 × system/user 크기, 총 문자량 순위.
2. **정적 비율** — 같은 스텝 호출 간 공통 줄(매번 반복되는 템플릿)의
   바이트 비중. 높을수록 "호출마다 새로 실을 이유가 없는" 부분이 크다.
3. **교차 스텝 중복** — 여러 스텝에 똑같이 주입되는 문장(전역 보일러
   플레이트). 어느 조각이 몇 개 스텝에 복제되는지.
4. **팩 귀속·성장 추이** — 발송 줄이 어느 팩(module/version/stem)에서
   왔는지 + 버전 디렉토리 타임스탬프 기준 크기 성장 곡선(다이어트 이후
   재비대를 날짜로 짚는다).

## 사용

```bash
cd backend && ./.venv/bin/python -m tools.opik_prompt_audit.main --help
# 또는 저장소 루트에서
backend/.venv/bin/python -m tools.opik_prompt_audit.main \
  --since 2026-08-14T18:33:00 --out artifact/20260815_opik_prompt_audit
```

출력: `<out>/report.html` (자체 완결 HTML, 8940 정적 서버 서브패스로 열람).

## 자료 원천 주의 (2026-08-17 Codex 리뷰 반영)

- **DB `llm_call_log` 는 원문이 아니다** — `llm_logger.MAX_PROMPT_CHARS` 가
  프롬프트를 10,000자에서 절단한다(한 주행 실측: 판정 계열 38% 해당).
  감사·시뮬의 대조군은 반드시 **Opik trace 의 input(전문)** 에서 뽑는다.
- **④의 성장 추이는 "버전 디렉토리 합"이다** — 서로 다른 호출이 선택적으로
  쓰는 상호 배타 stem 이 함께 더해지므로, 디렉토리 합의 증가 ≠ 호출 노출량
  증가. 호출 단위 실증가는 같은 stem 끼리 대조할 것.
## 캐시 실측 (cache_baseline.py)

축 A1(조립 순서 재배열)의 효과 판정 SOT. 시간 창의 trace 별 usage 에서
`prompt_tokens` 와 캐시 적중 토큰을 스텝별로 모아 표(JSON+stdout)로 낸다.

```bash
backend/.venv/bin/python tools/opik_prompt_audit/cache_baseline.py \
  --since 2026-08-15T00:00:00 --label before
backend/.venv/bin/python tools/opik_prompt_audit/cache_baseline.py \
  --compare artifact/…/cache_before.json artifact/…/cache_after.json
```

- 캐시 항목이 usage 에 **없으면 0% 가 아니라 "미보고"** 로 적는다. 둘을
  섞으면 거짓 기준선이 남는다.
- 재배열 전/후는 같은 제공사·같은 시간 간격·같은 호출 순서에서 잰 두 창을
  대조할 때만 효과로 읽는다.
- 스텝 이름은 기존 리포트와 같은 `step_of`(metadata.trace_name) 를 먼저 쓰고,
  주행 태그가 없어 이름이 안 잡히면 스텝 사전에 있는 trace 태그를 쓴다.

## 설계 원칙

- 판단은 수치와 원문 대조로만 — 특정 어휘·작품 고유명사 기반 판정 없음.
- 프롬프트 원문은 리포트에 발췌(줄 단위)로만 싣는다.
- Opik 접속 정보는 backend 설정(.env)의 `OPIK_URL_OVERRIDE`/`OPIK_WORKSPACE`
  를 그대로 읽는다.
