Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
804a274
[Fix] 동적 Few-shot 후보 캐시와 평가 누수 방지 보강
whc9999 Sep 8, 2026
5a73891
[Fix] Few-shot 임베딩 캐시 동시성과 만료 정리 보강
whc9999 Sep 8, 2026
516bbf2
Merge pull request #285 from JobDri-Developer/fix/fewshot-selection-s…
whc9999 Sep 8, 2026
9e68720
[Fix] 동적 Few-shot 선택 모드 로깅 보강
whc9999 Sep 8, 2026
f3ba017
Merge pull request #287 from JobDri-Developer/fix/fewshot-selection-s…
whc9999 Sep 8, 2026
4bb9a1c
[Fix] Few-shot 검색 입력 정규화와 길이 제한 적용
whc9999 Sep 8, 2026
6e5af85
Merge pull request #288 from JobDri-Developer/fix/fewshot-selection-s…
whc9999 Sep 8, 2026
8fa1e0a
[Fix] Few-shot 유사도 임계값과 선택 품질 로그 추가
whc9999 Sep 8, 2026
8100601
Merge pull request #289 from JobDri-Developer/fix/fewshot-selection-s…
whc9999 Sep 8, 2026
fc85f5c
[Fix] Few-shot query embedding 캐시 추가
whc9999 Sep 8, 2026
1898c72
[Fix] Few-shot query embedding 캐시 정리 정책 보강
whc9999 Sep 9, 2026
79a5b5e
[Fix] Few-shot query embedding 캐시 대기 및 LRU 정책 보강
whc9999 Sep 9, 2026
458fbb5
Merge pull request #290 from JobDri-Developer/fix/fewshot-selection-s…
whc9999 Sep 9, 2026
c3e7ae7
[Fix] PM 검수 Few-shot CSV 적재 조건 및 필드 보존 개선
whc9999 Sep 14, 2026
2f383b5
[Feat] 지원관리 카드 도메인 및 등록 API 구현 (#301)
shinae1023 Sep 14, 2026
7552b20
[Test] 지원관리 카드 등록과 소유권 회귀 검증 추가 (#301)
shinae1023 Sep 14, 2026
c1bd5d9
Merge pull request #309 from JobDri-Developer/feat/#301-job-applicati…
shinae1023 Sep 14, 2026
80e7e34
[Feat] 지원관리 칸반 조회 및 카드 이동 구현 (#303)
shinae1023 Sep 14, 2026
7c3db62
[Test] 지원관리 칸반 조회와 이동 회귀 검증 추가 (#303)
shinae1023 Sep 14, 2026
89b86ef
[Docs] 지원관리 칸반 API 계약 정리 (#303)
shinae1023 Sep 14, 2026
af00dde
[Fix] 지원 카드 생성과 공고 삭제 잠금 순서 보강 (#301)
shinae1023 Sep 14, 2026
33a20f5
[Fix] 칸반 이동 응답 시각 정밀도 정합성 보강 (#303)
shinae1023 Sep 14, 2026
c415bfb
Merge pull request #310 from JobDri-Developer/feat/#303-job-applicati…
shinae1023 Sep 14, 2026
3dc04f9
[Feat] 지원관리 상세 데이터 저장 API 구현 (#302)
shinae1023 Sep 14, 2026
72dcc7f
[Test] 지원관리 상세 저장 회귀 검증 추가 (#302)
shinae1023 Sep 14, 2026
6954307
[Docs] 지원관리 상세 API 계약 정리 (#302)
shinae1023 Sep 14, 2026
679a9e0
[Fix] 상세 저장 롤백 테스트 예외 검증 안정화 (#302)
shinae1023 Sep 14, 2026
809682a
[Fix] 롤백 테스트 DB 환경 의존성 제거 (#302)
shinae1023 Sep 14, 2026
ea62348
[Feat] 지원관리 카드 보관함 및 삭제 구현 (#304)
shinae1023 Sep 14, 2026
56457c3
[Test] 지원관리 보관 복원 삭제 회귀 검증 추가 (#304)
shinae1023 Sep 14, 2026
cbc6ac4
[Docs] 지원관리 보관함 API 계약 정리 (#304)
shinae1023 Sep 14, 2026
a2961cd
Merge pull request #311 from JobDri-Developer/feat/#302-job-applicati…
shinae1023 Sep 14, 2026
5131e79
[Fix] 보관함 조회와 동시 복원 정합성 보강 (#304)
shinae1023 Sep 14, 2026
7f9004b
[Fix] 상세 저장 롤백 테스트 stale 분기 제거 (#302)
shinae1023 Sep 14, 2026
c892d33
Merge pull request #314 from JobDri-Developer/feat/#304-job-applicati…
shinae1023 Sep 14, 2026
ad7e968
[Fix] Few-shot 무효 행의 중복 ID 선점 방지
whc9999 Sep 14, 2026
36040aa
Merge pull request #299 from JobDri-Developer/fix/fewshot-selection-s…
whc9999 Sep 14, 2026
7b07906
[Feat] PM 검수 Few-shot 데이터 연결 및 적재 검증 강화
whc9999 Sep 15, 2026
29b90f6
Merge pull request #315 from JobDri-Developer/feat/fewshot-reviewed-d…
whc9999 Sep 15, 2026
e956c63
[Feat] 평가 실행별 Few-shot 선택 메타데이터 기록
whc9999 Sep 15, 2026
fe5b622
Merge pull request #316 from JobDri-Developer/feat/fewshot-evaluation…
whc9999 Sep 15, 2026
2c76e81
[Fix] Few-shot 비교 평가 실행 오류 수정 및 품질 결과 문서화
whc9999 Sep 16, 2026
e07d5ff
[Test] single-pass Judge 입력의 후보 개수 검증 보강
whc9999 Sep 16, 2026
657c087
Merge pull request #317 from JobDri-Developer/fix/fewshot-evaluation-…
whc9999 Sep 16, 2026
8564bb3
[Feat] Few-shot 비교 평가 사용량 계측 추가
whc9999 Sep 16, 2026
4568a2a
Merge pull request #318 from JobDri-Developer/feat/fewshot-evaluation…
whc9999 Sep 16, 2026
481c740
[Feat] 동적 Few-shot 선택 임계값 및 후보 수 튜닝
whc9999 Sep 16, 2026
cf5b07a
Merge pull request #319 from JobDri-Developer/feat/fewshot-selection-…
whc9999 Sep 16, 2026
59a24fe
[Feat] Few-shot 검색 입력 개인정보 마스킹 적용
whc9999 Sep 16, 2026
56d7f2f
Merge pull request #320 from JobDri-Developer/feat/fewshot-privacy-ma…
whc9999 Sep 16, 2026
b4778b0
[Feat] 동적 Few-shot 운영 모니터링 지표 추가
whc9999 Sep 16, 2026
4fe9cbf
Merge pull request #321 from JobDri-Developer/feat/fewshot-operation-…
whc9999 Sep 16, 2026
8e97662
[Feat] Few-shot 메모리 캐시 최대 크기 제한 적용
whc9999 Sep 16, 2026
fc7b815
[Fix] Few-shot 캐시 동시성 및 만료 처리 보강
whc9999 Sep 16, 2026
121cc7c
[Fix] Few-shot 캐시 정리 재실행 조건 개선
whc9999 Sep 16, 2026
c22026b
Merge pull request #322 from JobDri-Developer/feat/fewshot-cache-size…
whc9999 Sep 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions docs/evaluation/fewshot-static-dynamic-20260916.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# STATIC/DYNAMIC Few-shot 비교 평가 (2026-09-16)

## 결론

DYNAMIC은 20건 중 12건 개선, 4건 동일, 4건 악화였습니다. Judge의 평균 overall usefulness는
3.70에서 4.15로 0.45점(5점 척도) 상승했습니다. 품질 개선 신호는 분명하지만,
분석 평균 지연이 5,210ms에서 5,731ms로 약 10.0% 증가했고 4건이 악화됐으므로
운영 활성화가 아니라 4번 임계값·top-k 튜닝으로 진행합니다.

이번 결과만으로 기본 feature flag를 켜지 않습니다. 동일 조건 반복 평가와 악화 사례 분석 후
최종 운영 적용 여부를 결정합니다.

## 조건

- 평가일: 2026-09-16 (Asia/Seoul)
- holdout: `evaluation_cases_검수(2).csv`, EV-01~EV-20 총 20건
- 후보: `fewshot-pm-reviewed-20260914-v2`, 승인 후보 5건
- 후보와 holdout의 normalized input hash 정확 일치: 0건
- 분석 모델: `gpt-4o-mini`
- 분석 temperature: 0.2
- Judge 모델: `gpt-4o-mini`
- Judge temperature: 0.0
- 분석 모드: single-pass
- DYNAMIC 설정: minSimilarity=-1.0, topK=5, minimumSelectedCount=1
- STATIC/DYNAMIC 외 입력·모델·프롬프트 코드·Judge 조건 동일
- 분석 및 Judge: 양쪽 각 20/20 성공

LLM 출력은 비결정적이므로 이 평가는 단일 실행 비교입니다. 같은 조건이어도 재실행 결과가
달라질 수 있습니다.

## 요약

| 항목 | STATIC | DYNAMIC | 변화 |
| --- | ---: | ---: | ---: |
| Overall usefulness | 3.70 | 4.15 | +0.45 |
| Relevance | 4.00 | 4.50 | +0.50 |
| Problem validity | 3.39 | 4.13 | +0.74 |
| Reason correctness | 3.92 | 4.35 | +0.43 |
| Context awareness | 3.32 | 4.13 | +0.81 |
| Faithfulness | 4.13 | 4.55 | +0.42 |
| Usability | 4.08 | 4.35 | +0.27 |
| Missing keyword precision | 3.55 | 4.55 | +1.00 |
| Missing keyword coverage | 3.65 | 4.55 | +0.90 |
| 평균 분석 지연 | 5,210ms | 5,731ms | +521ms (+10.0%) |
| P95 분석 지연 | 7,454ms | 8,273ms | +819ms (+11.0%) |
| Judge 평균 지연 | 4,584ms | 4,122ms | -462ms |
| Fatal error rate | 0% | 0% | 동일 |
| Unsupported fact rate | 0% | 0% | 동일 |
| False positive analysis rate | 0% | 0% | 동일 |

Sentence type consistency는 4.11에서 4.50으로 상승했습니다. status별 정답률을 직접 계산할
별도 정답 라벨은 holdout에 없으므로, 이 값과 Judge의 problem validity를 status 품질의 대리
지표로 사용했습니다.

## 케이스 분류

분류 기준은 케이스별 Judge overall usefulness의 DYNAMIC-STATIC 차이입니다.

- 개선 12건: EV-01, EV-03, EV-04, EV-05, EV-08, EV-09, EV-10, EV-11,
EV-12, EV-13, EV-16, EV-20
- 동일 4건: EV-06, EV-07, EV-17, EV-19
- 악화 4건: EV-02, EV-14, EV-15, EV-18

가장 큰 개선은 EV-09·EV-11(+2), 가장 큰 악화는 EV-14(-2)였습니다.
EV-18은 STATIC의 `MISSED_MISSING_KEYWORD`가 DYNAMIC에서 `MISSED_ANALYSIS`로 바뀌었고,
DYNAMIC의 overall usefulness가 2점으로 내려갔습니다. 4번 튜닝에서 EV-02·14·15·18의
선택 후보와 similarity를 우선 분석합니다.

## 선택과 비용·호출량

- DYNAMIC 20건 모두 `EMBEDDING`, fallback 0건(0%).
- 전체 선택 similarity 평균: 0.4140
- 케이스별 top similarity 평균: 0.4778
- 케이스별 bottom similarity 평균: 0.3503
- minSimilarity=-1.0, topK=5라서 모든 케이스에 후보 5건이 들어갔습니다.
- 최초 품질 실행에서 예상한 Cohere 호출 수는 STATIC 0회, DYNAMIC 21회였습니다. 아래 계측
재실행에서 sidecar의 논리 호출 수가 같은 값임을 확인했습니다.
- Judge 토큰: STATIC input 116,728 / output 9,226,
DYNAMIC input 115,906 / output 8,278.
- 분석 usage와 케이스별 논리적 Cohere 호출 수 계측을 추가한 뒤 동일 입력·설정으로 분석만
재실행했습니다(양쪽 20/20 성공).

| 계측 재실행 | STATIC | DYNAMIC | 변화 |
| --- | ---: | ---: | ---: |
| 분석 input tokens | 160,941 | 311,081 | +150,140 (+93.3%) |
| 분석 output tokens | 10,438 | 9,903 | -535 (-5.1%) |
| 분석 total tokens | 171,379 | 320,984 | +149,605 (+87.3%) |
| Cohere 논리 호출 | 0 | 21 | +21 |
| 평균 분석 지연 | 5,511ms | 5,880ms | +369ms (+6.7%) |
| P95 분석 지연 | 8,344ms | 10,350ms | +2,006ms (+24.0%) |

논리적 Cohere 호출은 애플리케이션의 embedding 요청 횟수이며 HTTP 계층의 내부 재전송은
포함하지 않습니다. DYNAMIC의 첫 케이스는 query 1회와 document batch 1회, 이후 19건은
query 1회씩 호출됐습니다. 재실행은 사용량 계측 목적이라 Judge를 다시 실행하지 않았으며,
품질 수치는 앞선 동일 조건 20건 비교 결과를 사용합니다.

## 실행 중 발견하고 수정한 문제

1. Cohere v2 응답에는 `id`, `meta`, `response_type`, `texts`가 포함됩니다. DTO가 알 수 없는
필드를 거부해 모든 동적 선택이 LOCAL_FALLBACK 되던 문제를 수정했습니다.
2. single-pass 결과의 `sanitizedCandidateResponseJson` 값이 JSON `null`일 때 Judge 입력 생성이
NullPointerException으로 실패하던 문제를 수정했습니다.

각 문제에 실제 응답 형태 및 single-pass null 회귀 테스트를 추가했습니다.

## 산출물

로컬 원본 결과는 `build/evaluation/fewshot-comparison-20260916/full/`에 있습니다.

- `static-analysis.csv`, `dynamic-analysis.csv`
- 각 분석 CSV의 `*.fewshot.<runId>.jsonl` 선택 메타데이터
- `static-judge.csv`, `dynamic-judge.csv`
- `judge-comparison.csv`
- 각 실행 로그

사용량 계측 재실행 결과는 `build/evaluation/fewshot-comparison-20260916/usage-metrics/`의
`static-analysis.csv`, `dynamic-analysis.csv`, 각 sidecar와 로그에 있습니다.

`build/`는 Git 추적 대상이 아닙니다. 결과 재현이 필요하면 동일 holdout과 설정으로 다시
실행하거나, 개인정보 보관 정책을 확인한 후 별도 안전한 저장소에 보관해야 합니다.

## 다음 결정

3번의 품질·지연·토큰·Cohere 호출량 비교와 계측을 완료했습니다. DYNAMIC은 품질이 좋아졌지만
분석 input token이 93.3% 증가했으므로 그대로 운영 활성화하지 않습니다. 다음은 4번
`min-similarity`, `top-k`, `minimum-selected-count` 튜닝으로 품질 이득을 유지하면서 낮은 유사도
후보와 토큰 비용을 줄이는 실험입니다.
74 changes: 74 additions & 0 deletions docs/evaluation/fewshot-tuning-20260916.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 동적 Few-shot 선택값 튜닝 (2026-09-16)

## 결론

권장값은 다음과 같습니다.

```yaml
analysis:
few-shot:
search:
top-k: 5
min-similarity: 0.40
minimum-selected-count: 2
```

동적 선택 feature flag의 기본값은 계속 비활성입니다. 이 설정은 품질 평가와 단계적 운영 적용에
사용할 권장 검색값이며, 운영 활성화를 의미하지 않습니다.

## 평가 조건

- holdout: `evaluation_cases_검수(2).csv` 20건
- 후보 데이터셋: `fewshot-pm-reviewed-20260914-v2` 5건
- 분석·Judge 모델: `gpt-4o-mini`
- 분석 temperature: 0.2, Judge temperature: 0.0
- 분석 모드: single-pass
- 각 실험의 분석·Judge 성공: 20/20
- STATIC 품질과 TOPK5 품질은 기존 비교 평가 결과를 사용
- 튜닝 3개 설정은 각각 새 분석·Judge 실행

LLM 출력은 비결정적이므로 단일 실행 결과입니다. 운영 활성화 전에는 권장 설정을 같은 holdout과
신규 holdout에서 반복 평가해야 합니다.

## similarity 분포

TOPK5 실행에서 선택된 100개 점수의 범위는 0.2763~0.6075, 평균은 0.4140,
중앙값은 0.4115였습니다.

| 임계값 | 평균 통과 후보 수 | 0건 | 2건 미만 |
| ---: | ---: | ---: | ---: |
| 0.30 | 4.90 | 0 | 0 |
| 0.35 | 4.45 | 0 | 0 |
| 0.40 | 2.80 | 1 | 3 |
| 0.45 | 1.45 | 3 | 12 |
| 0.50 | 0.35 | 13 | 20 |

0.35는 비용 절감이 작고, 0.45부터는 fallback 의존도가 지나치게 높아 0.40을 실험값으로
선택했습니다.

## 결과

| 설정 | 품질 평균 | STATIC 대비 개선/동일/악화 | 평균 선택 수 | 총 분석 토큰 | 평균 지연 | P95 지연 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| STATIC | 3.70 | 기준 | 4.00 | 171,379 | 5,511ms | 8,344ms |
| TOPK5, 임계값 없음 | 4.15 | 12/4/4 | 5.00 | 320,984 | 5,880ms | 10,350ms |
| TOPK3, 임계값 없음 | 3.70 | 6/9/5 | 3.00 | 251,195 | 5,266ms | 6,663ms |
| TOPK5, 0.40, 최소 1 | 3.95 | 7/10/3 | 3.05 | 251,825 | 5,149ms | 6,955ms |
| **TOPK5, 0.40, 최소 2** | **4.10** | **10/8/2** | **3.45** | **265,266** | **5,469ms** | **7,471ms** |

권장값은 임계값 없는 TOPK5보다 총 분석 토큰을 55,718개(17.4%) 줄이면서 품질 평균은
0.05만 낮았습니다. STATIC 대비 품질은 0.40 높고, 악화 사례는 2건입니다.

`minimum-selected-count=2`에서는 17건이 EMBEDDING, 3건이 LOCAL_FALLBACK이었습니다.
Cohere 논리 호출은 모든 동적 설정에서 21회로 동일했습니다. 임계값은 프롬프트에 넣을 후보를
줄이지만 query/document embedding 호출 자체를 줄이지는 않습니다.

## 결정

- `top-k=3` 단독 적용은 품질 하락으로 제외합니다.
- `min-similarity=0.40`으로 낮은 유사도 후보를 제거합니다.
- 통과 후보가 2개 미만이면 로컬 fallback하여 지나치게 작은 예시 집합을 피합니다.
- 동적 선택 feature flag는 비활성으로 유지합니다.
- 신규 후보 추가 또는 embedding 모델 변경 시 분포와 임계값을 다시 평가합니다.

로컬 원본은 `build/evaluation/fewshot-tuning-20260916/`에 있으며 Git 추적 대상이 아닙니다.
45 changes: 45 additions & 0 deletions docs/fewshot-cache-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Few-shot 메모리 캐시 정책

## 기본값

| 캐시 | 최대 크기 | TTL |
| --- | ---: | ---: |
| selection | 1,000 | 30분 |
| query embedding | 1,000 | 30분 |
| document embedding | 5,000 | 30분 |

환경변수로 조정할 수 있습니다.

```text
ANALYSIS_FEW_SHOT_CACHE_TTL=30m
ANALYSIS_FEW_SHOT_SELECTION_CACHE_MAX_SIZE=1000
ANALYSIS_FEW_SHOT_QUERY_EMBEDDING_CACHE_MAX_SIZE=1000
ANALYSIS_FEW_SHOT_DOCUMENT_EMBEDDING_CACHE_MAX_SIZE=5000
ANALYSIS_FEW_SHOT_SELECTION_IN_FLIGHT_WAIT_TIMEOUT=20s
```

모든 최대 크기는 1 이상으로 보정합니다. selection과 document embedding 캐시는 접근할 때마다
만료 항목을 먼저 제거하고, 상한을 넘으면 마지막 접근 시각이 오래된 항목부터 제거합니다.
query embedding 캐시는 기존 주기적 정리와 LRU 제거를 유지합니다.

selection과 document embedding 생성이 진행 중인 키는 제거 대상에서 제외합니다. 생성이 끝나 in-flight 상태가
해제된 직후 다시 상한을 적용하므로, 동시에 한 batch가 완료되는 짧은 구간에는 상한을 일시적으로
넘을 수 있지만 장시간 초과 상태로 남지 않습니다. selection/query/document의 in-flight future는
캐시 제거와 별도로 유지되므로 동일 키의 동시 요청이 외부 API를 중복 호출하지 않습니다.

## 관측

`fewshot_cache_events_total`을 `cache`, `outcome` 태그로 나눠 확인합니다.

```promql
sum(rate(fewshot_cache_events_total[10m])) by (cache, outcome)

sum(rate(fewshot_cache_events_total{outcome="hit"}[10m])) by (cache)
/
sum(rate(fewshot_cache_events_total{outcome=~"hit|miss"}[10m])) by (cache)

sum(increase(fewshot_cache_events_total{outcome="evicted"}[1h])) by (cache)
```

eviction이 지속 증가하면서 hit 비율이 낮으면 캐시 상한을 늘리기 전에 고유 질의 수, 데이터셋 변경
빈도와 실제 메모리 사용량을 함께 확인합니다.
79 changes: 79 additions & 0 deletions docs/fewshot-evaluation-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Few-shot 평가 메타데이터

후속 이슈 2번의 선택 이력 기록입니다. 운영 API·DB·기존 평가 CSV 컬럼은 변경하지 않습니다.
`EvaluationAnalysisRunner`가 사용하는 배치 서비스에서 실행마다 별도 JSONL 파일을 생성합니다.

## 출력 및 연결

평가 출력이 `evaluation_ai_results.csv`라면 같은 폴더에
`evaluation_ai_results.csv.fewshot.<runId>.jsonl`이 생성됩니다.
정확한 경로는 배치 시작 로그의 `Few-shot evaluation metadata output`에 표시됩니다.
실행별 새 파일이므로 이전 메타데이터를 덮어쓰지 않습니다.

- 한 줄은 입력 CSV의 데이터 행 하나에 대응합니다.
- `rowIndex`: 헤더를 제외한 1부터 시작하는 행 번호.
- `caseId`: 평가 입력의 ID. 중복 ID는 `rowIndex`로 구분합니다.
- `runId`: 한 실행 내에서 동일한 UUID.
- `outcome`: SUCCESS 또는 FAILED.
- `metadataStatus`: RECORDED 또는 UNAVAILABLE.
- `captureStage`: SELECTION_OBSERVED 또는 UNAVAILABLE.
- `selections`: 이 행에서 관측한 선택 스냅샷 배열.
- `schemaVersion=1`, `recordedAt`: sidecar 형식 버전 및 UTC 기록 시각.

행 처리 직후 flush하므로 뒤 행에서 실패해도 앞 행의 메타데이터는 남습니다.
비정상 종료 시 sidecar는 부분 결과일 수 있으며, CSV 생성까지 완료되었다는 뜻은 아닙니다.
sidecar 저장 실패는 평가 실행 실패로 전파됩니다.

## 선택 스냅샷

| selectionMode | 의미 | scoreType |
| --- | --- | --- |
| STATIC | 동적 선택 비활성, 기존 정적 전체 예시 | NONE |
| EMBEDDING | 임베딩 검색 후보 사용(캐시 반환 포함) | COSINE_SIMILARITY |
| LOCAL_FALLBACK | 로컬 기준으로 선택한 후보 사용 | LOCAL_HEURISTIC |
| STATIC_FALLBACK | 빈 결과·검색 예외 등으로 정적 전체 예시 복귀 | NONE |
| NOT_APPLIED | two-pass 경로에는 Few-shot 미적용 | NONE |

- `selectedCases`: 실제 조립한 예시의 ID, source, score, 후보 datasetVersion.
- `topScore/bottomScore/avgScore`: 최종 선택 후보의 최대·최소·평균 점수.
프롬프트 순서와 최대·최소 점수 순서는 다를 수 있습니다.
- `datasetVersion/minSimilarity/topK/minimumSelectedCount`: 실행의 선택 설정.
topK는 설정한 요청 개수이며 실제 개수는 selectedCases 배열 길이입니다.
- `cohereApiCallCount`: 해당 프롬프트 선택 중 발생한 논리적 Cohere embedding 호출 수.
캐시 적중 시 0이며, SDK/HTTP 계층의 내부 재전송 횟수와는 구분합니다.
- `reason`: 정적 선택·fallback·미적용 사유 코드. 예외 메시지 원문은 넣지 않습니다.

정적 예시 ID는 기존 로더와 같은 `FS-FIXED-1..N`입니다.
정적 후보의 datasetVersion은 `static-resource`로 표시하며, 검색 설정의 datasetVersion과 구분합니다.
정적 선택은 유사도 계산이 없으므로 후보 점수와 점수 통계는 **0이 아니라 null**입니다.
LOCAL_HEURISTIC 점수는 코사인 유사도와 섞어 분포를 비교하면 안 됩니다.

## 실제 호출과의 관계

프롬프트 조립 시 검색을 한 번 수행하고 그 선택 결과를 기록합니다.
메타데이터 수집을 위한 추가 Cohere/OpenAI 호출은 없습니다.
기록은 외부 AI 호출 전에 전달되므로, 시간 초과나 응답 검증 실패 행에도 선택 이력이 남습니다.
따라서 RECORDED는 **프롬프트 선택을 관측했다는 뜻**이며, API 호출 성공이나 토큰 소비를 보장하지 않습니다.

single-pass는 한 선택을, hybrid-exact는 single-pass 하위 호출의 선택을 기록합니다.
two-pass는 NOT_APPLIED를 기록합니다.
선택 전에 실패했거나 메타데이터를 지원하지 않는 다른 generator는 UNAVAILABLE로 기록하며
STATIC으로 추정하지 않습니다.

선택 스냅샷에는 자소서 원문, JD, 프롬프트 본문, 임베딩 벡터를 넣지 않습니다.
기존 평가 CSV의 원문 보존 동작은 바꾸지 않았으므로 CSV 접근 권한은 기존대로 관리해야 합니다.

## 분석 사용량

평가 CSV의 `candidateInputTokens`, `candidateOutputTokens`, `finalInputTokens`,
`finalOutputTokens`, `totalInputTokens`, `totalOutputTokens`에는 OpenAI 응답 usage를 기록합니다.
single-pass 사용량은 final 컬럼에 기록되고 candidate 컬럼은 비어 있습니다. two-pass는 후보와
최종 검토를 나눠 기록하며, 선택적으로 실행되는 recheck 사용량은 final에 합산합니다.

## 검증

`./gradlew test --tests '*AnalysisAiClientTest' --tests '*Evaluation*' --tests '*fewshot.*' --tests '*FewShotMetadataPromptTest' --tests '*FewShotPromptProviderTest'`

192개 통과(실패·건너뜀 0). 선택 이력과 프롬프트의 일치, 로컬 점수 구분,
정적 fallback, 모드별 실패 전 기록, 실패 행 보존, 중복 caseId 행 구분,
기존 CSV 컬럼 유지 및 실행별 파일 분리를 확인했습니다. 외부 AI 호출은 수행하지 않았습니다.
Loading
Loading