Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
e2e27cb
refactor: 원문 인용 검증 유틸리티 분리
2-dayeon Oct 21, 2026
9a66d38
refactor: 깊이 채점에 공통 인용 검증 적용
2-dayeon Oct 21, 2026
8ac2c8f
feat: 면접 역량 목록과 판정 경계 정의
2-dayeon Oct 21, 2026
f76786f
feat: 직무와 질문 카테고리별 역량 매핑 구현
2-dayeon Oct 21, 2026
a22be31
feat: 역량별 원문 근거 검증과 등급 계산 구현
2-dayeon Oct 21, 2026
0767d6d
feat: 응답 상한과 관측 역량 점수 집계 구현
2-dayeon Oct 21, 2026
1b89b5a
feat: 역량 채점 콜백 모델 정의
2-dayeon Oct 21, 2026
9e417c7
feat: 역량 근거 추출과 응답 적중 기준 정의
2-dayeon Oct 21, 2026
1361b84
feat: 역량 채점 제출 도구 스키마 구현
2-dayeon Oct 21, 2026
563f34f
feat: 직무별 역량 채점 프롬프트 구성
2-dayeon Oct 21, 2026
e6145f9
feat: 역량 채점 응답과 모순 인용 검증 구현
2-dayeon Oct 21, 2026
1df71db
feat: 역량 채점 호출과 누락 재시도 구현
2-dayeon Oct 21, 2026
8ed89e3
feat: 문항별 역량 결과와 신뢰성 널 허용
2-dayeon Oct 21, 2026
131fcef
feat: 피드백 카테고리 수신과 부모 상속 연결
2-dayeon Oct 21, 2026
fffead1
feat: 설정에 따른 피드백 채점 버전 선택
2-dayeon Oct 21, 2026
4d074cb
feat: 다대일 비기술 질문 카테고리 표준화
2-dayeon Oct 21, 2026
16e5e26
feat: 일대일 역량 채점 결과와 콜백 연결
2-dayeon Oct 21, 2026
f3ce1e5
feat: 다대일 역량 채점과 면접관별 점수 연결
2-dayeon Oct 21, 2026
f8a1ec2
feat: 역량 채점 검증용 공통 응답 구성
2-dayeon Oct 21, 2026
cef3938
feat: 직무별 역량 매핑과 카테고리 상속 검증
2-dayeon Oct 21, 2026
2043213
feat: 역량 근거 등급 경계와 정확성 상한 검증
2-dayeon Oct 21, 2026
551b29f
feat: 역량 점수 집계와 미관측 역량 처리 검증
2-dayeon Oct 21, 2026
b5fc9fd
feat: 역량 응답 누락과 잘못된 원문 인용 검증
2-dayeon Oct 21, 2026
8c238d2
feat: 비기술 질문 카테고리와 미등록 값 처리 검증
2-dayeon Oct 21, 2026
ab97b19
feat: 역량 콜백과 기존 채점 호환성 검증
2-dayeon Oct 21, 2026
e699503
feat: 개발 직군 일대일 역량 프롬프트 기준 추가
2-dayeon Oct 21, 2026
15c63ac
feat: 개발 직군 다대일 역량 프롬프트 기준 추가
2-dayeon Oct 21, 2026
6cd5886
feat: 일반 직군 일대일 역량 프롬프트 기준 추가
2-dayeon Oct 21, 2026
0874ed1
feat: 일반 직군 다대일 역량 프롬프트 기준 추가
2-dayeon Oct 21, 2026
c94d950
feat: 역량 프롬프트와 제출 도구 회귀 검증
2-dayeon Oct 21, 2026
1771165
feat: 역량 채점 비교 평가 사례 37건 추가
2-dayeon Oct 21, 2026
4ac8bab
feat: 역량 일치도와 반복 안정성 지표 구현
2-dayeon Oct 21, 2026
2bf68a3
feat: 역량 채점 전환 초기 기준 검증 구현
2-dayeon Oct 21, 2026
26b7d4d
feat: 운영 파서를 사용하는 역량 평가 연결
2-dayeon Oct 21, 2026
0d953e6
feat: 평가 도구에 운영 채점 재시도 정책 적용
2-dayeon Oct 21, 2026
4680211
feat: 버전별 역량 평가 비교 보고서 구현
2-dayeon Oct 21, 2026
4f30456
feat: 평가 실행에 채점 버전과 근거 기록 추가
2-dayeon Oct 21, 2026
4f8841c
feat: 평가 보고서의 복수 채점 버전 비교 지원
2-dayeon Oct 21, 2026
c0a5561
feat: 평가 지표와 전환 검증 도구 회귀 검증
2-dayeon Oct 21, 2026
b26966a
docs: 역량 채점 요청과 결과 연동 계약 정리
2-dayeon Oct 21, 2026
79b3aff
docs: 피드백 역량 채점 버전과 설정 안내
2-dayeon Oct 21, 2026
ea08250
docs: 역량 비교 검증과 운영 전환 절차 안내
2-dayeon Oct 21, 2026
96bf97c
feat: 역량 평가 양식과 확장 사례 검증 보강
2-dayeon Oct 21, 2026
23f6936
fix: 면접관 미관측 점수와 평가 누락 재시도 수정
2-dayeon Oct 21, 2026
e62e1a3
fix: 미관측 면접관 점수 구분 회귀 검증
2-dayeon Oct 21, 2026
6c757f6
fix: 평가 문항 누락 재시도 회귀 검증
2-dayeon Oct 21, 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
21 changes: 21 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1017,3 +1017,24 @@ PDF 프로세스 간 복사 비용과 기존 그림 의미 분석의 중복 호
- 기업 평가는 strict 도구 제출을 사용하고 잘못된 제출만 최대 한 번 다시 생성한다. 두 호출은 하나의 `COMPANY_FIT_TIMEOUT_SECONDS` 예산을 공유한다.
- API 오류·토큰 잘림·시간 초과에는 추가 재시도하지 않는다. 기업 평가가 실패해도 일반 채점은 유지한다.
- `company_fit.*` 로그의 `job_id`로 요청을 구분한다. 완료 로그에는 적용 여부·시도·종료 사유·출력 토큰·경과 시간이 있고 원문은 기록하지 않는다.


## 피드백 역량 채점 버전

`FEEDBACK_SCORING_VERSION`은 `axis-v4`(기본값) 또는 `competency-v1`이며
SOLO와 MULTI에 함께 적용된다. 상세 요청·성공·실패 계약은
[역량 채점 계약](feedback-scoring-contract-v2.md)을 따른다.

두 피드백 요청의 `questions[].category`는 선택 문자열이다. 공백 제거·소문자화 후
스네이크케이스 1~64자만 사용하며 잘못된 값은 거부하지 않고 미분류로 처리한다.
FOLLOW에 유효한 값이 없으면 부모 카테고리를 상속한다.

competency-v1 콜백의 `overall.scoreBreakdown.axes`는 고정 순서의 5역량이며
각 축에 verdict·evidenceCount가 추가된다. response·motivation·credibility는 별도 지표다.
`overall.reliabilityScore`는 답변 1개면 null이다.
문항별 `responseLevel`·`axisScores`·`competencies`로 등급과 원문 근거를 제공한다.
관측하지 않은 역량의 null은 평가한 역량의 0점과 구별한다.

기본 axis-v4의 콜백 형태는 유지한다. API 서버와 웹 호환 배포 및
오프라인 비교를 확인한 뒤 버전을 전환한다. 롤백은 설정을 axis-v4로 되돌린다.
서로 다른 scoringVersion의 점수는 같은 기준의 점수로 비교하지 않는다.
109 changes: 109 additions & 0 deletions docs/feedback-scoring-contract-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# 역량 채점 계약 competency-v1

기존 계약과 결과는 `axis-v4`로 유지한다. 이 계약은
`FEEDBACK_SCORING_VERSION=competency-v1`일 때 SOLO와 MULTI에 함께 적용한다.
기본값은 `axis-v4`다.

## 요청

`POST /feedback/solo`, `POST /feedback/multi`의 각 `questions[]`에
선택 필드 `category: string | null`을 추가한다.

- 공백 제거와 소문자 변환 뒤 `^[a-z][a-z0-9_]{0,63}$` 형식만 사용한다.
- 형식이 잘못되거나 값이 없어도 422로 거부하지 않는다.
- FOLLOW에 유효한 카테고리가 없으면 부모 카테고리를 상속한다.
- 직무별 매핑을 먼저 선택한다. 같은 `performance`도 DBA와 경영기획에서 다르다.
- MULTI 비TECH는 비기술 매핑만 사용하며 직무 지식을 주·보조로 평가하지 않는다.
- 미분류는 모델이 주 역량 하나를 추론한다. 추론하지 못하면 응답 적중만 집계한다.

매핑과 슬롯의 단일 기준은 `src/app/core/common/feedback/competency/`다.

## 점수

| 축 순서 | 가중치 |
|---|---:|
| PROBLEM_SOLVING | 30 |
| KNOWLEDGE | 25 |
| OWNERSHIP | 25 |
| COLLABORATION | 10 |
| GROWTH | 10 |

주 역량은 항상 채점한다. 보조 역량은 검증된 근거로 계산한 등급이 1 이상일 때만 집계한다.
모델은 원문 슬롯을 제출하고 서버가 등급을 계산한다.
응답 적중과 직무 지식의 정확성만 모델이 등급을 정한다.

| response | 주 역량 상한 | 보조 역량 |
|---|---:|---|
| 0 | 0 | 제외 |
| 1 | 1 | 제외 |
| 2 | 3 | 검증된 근거 등급 그대로 |
| 3 또는 4 | 4 | 검증된 근거 등급 그대로 |

등급은 25를 곱해 점수로 바꾼다. 역량별 평균을 0.5 올림으로 표시 정수화한 뒤
관측된 축의 `Σ(score × weight) / Σ(weight)`를 같은 방식으로 반올림해 종합을 계산한다.

**0점과 null:** 주 역량에서 응답 0을 받은 문항도 관측 문항으로 집계하므로
그 역량은 0점이고 근거 문항 수는 증가한다. 채점 문항이 없는 역량만
`score`, `weight`, `verdict`가 null이고 `evidenceCount`가 0이다.
원안의 “응답이 모두 0이면 모든 축 null” 문장은 상세 계산 알고리즘과 달라 적용하지 않는다.
관측된 역량이 전혀 없으면 종합은 0이다.

판정은 반올림 전 평균 등급 기준이다:
3.5 이상 STRONG, 2.5 이상 SOLID, 1.5 이상 BORDERLINE, 나머지 WEAK.
초기 가중치와 판정 경계는 오프라인 검증 대상이다.

## 성공 콜백

`overall.scoreBreakdown`과 `personas[].scoreBreakdown`에 다음 필드를 보존한다.

| 필드 | 내용 |
|---|---|
| scoringVersion | competency-v1 |
| axes | 위 순서의 5개 항목 axis·score·weight·verdict·evidenceCount |
| consistencyScore | consistency 등급 × 25 답변 1개면 null |
| response | score·hitCount·gradedCount 응답 등급 평균 × 25 hit는 등급 3 이상 |
| motivation | score·verdict·evidenceCount 해당 문항이 없으면 null |
| credibility | score·issues 면접관별 결과에서는 null |

- `overall.totalScore`는 5역량 종합이다.
- `overall.intentAlignmentScore`는 `response.score`와 같다.
- `overall.reliabilityScore`는 `credibility.score`와 같고 답변 1개면 null이다.
- 응답 적중·동기·신뢰성은 종합 가중 평균에 넣지 않는다.
- 담당 답변이 없는 면접관은 `score`와 `scoreBreakdown` 모두 null이다.
- 담당 답변이 있어도 가중 역량이 관측되지 않으면 면접관 `score`만 null이다.
이때 `scoreBreakdown`은 유지해 동기·응답 지표를 제공한다. 관측된 역량의 0점은 그대로 보낸다.
- 면접관별 `consistencyScore`와 `credibility`는 항상 null이다.

문항 피드백은 다음을 추가한다. 기존 v4 콜백에는 추가 필드를 넣지 않는다.

| 필드 | 내용 |
|---|---|
| responseLevel | 0~4 |
| axisScores | 이 문항에서 집계한 5역량 코드 → 0~100 동기는 제외 |
| competencies | competency·role·level·score·evidence |
| competencies[].role | PRIMARY 또는 SECONDARY 주 역량 먼저 |
| competencies[].evidence | slot·quote 원문 인용 |

동기 문항은 competencies에 MOTIVATION으로 포함하지만 axisScores에는 넣지 않는다.
신뢰성 issue는 kind·questionIds·quotes를 갖고 서로 다른 두 문항의 실제 답변을 인용한다.
kind는 ROLE·TECH_CHOICE·CAUSE·DETAIL·OTHER 중 하나다.
꼬리질문 설명 부족이나 측정 방법을 모르는 것 자체는 모순이 아니다.
신뢰성 경고 때문에 종합 점수나 판정을 제한하지 않는다.

## 검증 실패

응답 등급 누락·범위 오류, 주 역량 그룹 누락·원문 인용 불일치는
한 번 재시도한다. 그래도 누락되면 기존 형식의 500 실패 콜백을 보낸다.
출력 토큰 제한으로 잘린 응답은 재시도하지 않는다.
잘못된 보조 그룹은 그 그룹만, 잘못된 모순은 그 issue만 버린다.
로그에는 답변·인용 원문 대신 사유 코드·숫자와 집계만 남긴다.

## 배포와 범위

API 서버의 카테고리·새 필드 저장 → 웹의 버전별 표시 → 분석 서버 코드 배포
→ 오프라인 전환 기준 검토 → 설정 전환 → 2주 운영 관찰 순서다.
웹의 과거 면접 비교와 통계는 같은 scoringVersion끼리만 계산해야 한다.
롤백은 설정을 axis-v4로 되돌린다. 저장된 v1 결과를 변환하거나 삭제하지 않는다.

채팅 서버 변경, 기업별 가중치, 서류 대조, 실제 합불 수집은 이번 구현에서 제외한다.
검증 실행과 미완료 절차는 `evaluation/README.md`를 참고한다.
51 changes: 51 additions & 0 deletions evaluation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,54 @@ uv run python evaluation/company_ab.py \
입력의 profile과 questions는 기존 재작성 요청과 같은 camelCase 필드를 사용한다.
기업 패키지는 schemaVersion 1이며 companyId는 code, factId는 파일 순서대로 f1부터 부여한다.
재작성 실패는 비교표에서 원질문 폴백으로 표시한다. 회사 이름이나 문장에 있는 표 구분 문자는 이스케이프한다.


## competency-v1 비교 및 전환 검증

코드는 기본값 axis-v4를 유지한다. API 서버와 웹의 호환 배포 및 아래 검증을
확인한 뒤에만 FEEDBACK_SCORING_VERSION=competency-v1로 전환한다.
상세 계약은 [역량 채점 계약](../docs/feedback-scoring-contract-v2.md)이다.

```sh
PYTHONPATH=src python -m evaluation.run_feedback --split holdout --repeats 5 --scoring axis-v4 --output /tmp/fb-v4.jsonl
PYTHONPATH=src python -m evaluation.run_feedback --split holdout --repeats 5 --scoring competency-v1 --output /tmp/fb-v1.jsonl
PYTHONPATH=src python -m evaluation.report_feedback --runs /tmp/fb-v4.jsonl --runs /tmp/fb-v1.jsonl --human /tmp/human-v1.csv --output /tmp/fb-report.md
```

실행에는 Anthropic API 키가 필요하며 호출 비용이 발생한다. 모델은 운영과 같게
`--model`로 지정한다. `--max-tokens` 미지정 시 SOLO/MULTI 운영 설정을 각각 읽는다.
`--dry-run`은 호출하지 않고 사례 형식과 계획 실행 횟수만 확인한다.
원문이 있는 JSONL은 0600 권한으로 저장한다. 보고서 공개 시 비식별 표본만 사용한다.

사례는 기존 10건과 추가 37건으로 총 47건이다. development와 holdout을 분리하고
프롬프트 조정에는 development만 쓴다. holdout의 10건은 5역량을 함께 확인하는
다문항 세션으로 구성해 역량 쌍의 상관을 측정할 수 있게 했다. expected는 합성 설계 기대값이며 사람 평가가 아니다.
원문에서 추출하는 슬롯의 의미 분류가 옳은지는 실제 모델 실행과 사람 평가로 검증해야 한다.

사람 평가에는 `human_ratings.competency-v1.template.csv`를 사용한다.
면접 경험자 2명 이상이 모델 출력과 버전 이름을 보지 않고 독립 평가한다.
primary는 실제 질문이 겨냥한 역량 코드다. 해당 없는 역량은 빈 칸으로 둔다.
조정 전과 후 CSV를 각각 보존하고 두 보고서를 별도로 만든다.

보고서는 버전·프롬프트별로 실패율, 역량별 반복 최빈 일치, 점수 표준편차,
이차 가중 카파, 정확·±1 일치, 매핑 일치, 세션 점수 상관 행렬, 토큰과 시간을 낸다.
각 사례의 반복 평균을 한 세션으로 보고 상관을 계산한다. 반복 수를 독립 표본으로 세지 않는다.
같은 정책으로 최대 2회 채점하며 누락만 재시도하고 잘린 출력은 재시도하지 않는다.
토큰·시간에는 재시도가 포함된다. 검증 실패 사유 코드와 targets.source도 JSONL에 남긴다.
비교 값이 없거나 상수 표본으로 카파·상관을 계산할 수 없으면 미측정이다.

전환 기준은 팀이 정한 초기값이다. 실패율은 기존 이하이면서 2% 이하,
반복 일치는 기존 깊이 이상, 총점 표준편차는 기존 이하, 주 역량 사람-모델 및
사람 간 가중 카파는 0.6 이상, 매핑 일치는 80% 이상, 역량 쌍 상관은 절댓값 0.8 미만,
필수 태그 기대 동작은 전부 통과, 토큰 제한 종료는 0건이어야 한다.
자동 표는 검토 보조이며 운영 설정을 바꾸지 않는다. 미측정을 통과로 처리하지 않는다.

### 현재 구현으로 자동 완료되지 않는 절차

- 실제 LLM 반복 비교: 실제 API 실행 결과로만 판단한다 로컬 스텁 테스트와 구분한다.
- 사람 평가: 평가자가 작성한 CSV가 없으면 미측정이며 일치도를 주장하지 않는다.
- 운영 전환 후 2주 관찰: 실패율 전환 전의 1.5배 초과, 특정 재시도 사유 5% 초과,
미분류 10% 초과, SOLO 관측 역량 1개 이하 20% 초과, 오프라인 평균과 10점 이상 차이,
N:1 목록 밖 카테고리 5% 초과를 초기 이상 기준으로 본다.
- 이상 신호가 있으면 FEEDBACK_SCORING_VERSION=axis-v4로 되돌리고 원인을 조사한다.
- 실제 합불 수집·보정은 별도 명세와 동의 검토가 필요한 후속 작업이다.
Loading
Loading