Skip to content

[Fix] 자기소개서 소제목을 첨삭 평가 대상에서 제외 - #241

Closed
whc9999 wants to merge 1 commit into
devfrom
fix/ignore-cover-letter-subheadings
Closed

[Fix] 자기소개서 소제목을 첨삭 평가 대상에서 제외#241
whc9999 wants to merge 1 commit into
devfrom
fix/ignore-cover-letter-subheadings

Conversation

@whc9999

@whc9999 whc9999 commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

✨ 어떤 이유로 PR를 하셨나요?

  • feature 병합
  • 버그 수정(아래에 issue #를 남겨주세요)
  • 코드 개선
  • 코드 수정
  • 배포
  • 기타(아래에 자세한 내용 기입해주세요)

📋 세부 내용 - 왜 해당 PR이 필요한지 작업 내용을 자세하게 설명해주세요

  • 단일 패스: 소제목을 questionAnalyses, keyStrengths, keyWeaknesses, 점수 근거에서 제외
  • 1차 후보: 소제목에 행동·성과가 없다는 이유로 후보 생성 금지
  • 2차 검토: 잘못 유입된 소제목 후보는 NOT_ACTIONABLE로 거절
  • 소제목은 바로 뒤 문단의 주제와 흐름을 이해하는 보조 맥락으로만 사용
  • 소제목의 요약 품질 자체도 별도 첨삭 대상으로 만들지 않음

📸 작업 화면 스크린샷

⚠️ PR하기 전에 확인해주세요

  • 로컬테스트를 진행하셨나요?
  • 머지할 브랜치를 확인하셨나요?
  • 관련 label을 선택하셨나요?

🚨 관련 이슈 번호 [ ]

Summary by CodeRabbit

  • 개선 사항
    • 분석 결과 생성 시 입력과 관련된 예시를 동적으로 반영해 응답 품질을 높였습니다.
    • 동적 예시를 사용할 수 없는 경우 기존 방식으로 자동 대체됩니다.
    • 대괄호로 표시된 한 줄 소제목이 문장, 첨삭 대상 또는 강점 후보로 잘못 분류되지 않도록 개선했습니다.

- 단일 패스: 소제목을 questionAnalyses, keyStrengths, keyWeaknesses, 점수 근거에서 제외
- 1차 후보: 소제목에 행동·성과가 없다는 이유로 후보 생성 금지
- 2차 검토: 잘못 유입된 소제목 후보는 NOT_ACTIONABLE로 거절
- 소제목은 바로 뒤 문단의 주제와 흐름을 이해하는 보조 맥락으로만 사용
- 소제목의 요약 품질 자체도 별도 첨삭 대상으로 만들지 않음
@whc9999 whc9999 self-assigned this Jul 31, 2026
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AnalysisAiClient에 동적 few-shot 검색과 대체 처리가 추가되었습니다. 단일 패스 및 후보 검증 프롬프트는 대괄호 소제목을 분석 대상에서 제외합니다. 테스트는 선택 사례와 소제목 처리 규칙을 검증합니다.

Changes

AnalysisAiClient 프롬프트 변경

Layer / File(s) Summary
동적 few-shot 선택과 프롬프트 적용
src/main/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClient.java
FewShotPropertiesFewShotSearchService를 주입합니다. 설정이 활성화되면 입력 기반 검색 쿼리와 topK로 사례를 선택합니다. 결과가 없거나 예외가 발생하면 고정 few-shot 프롬프트를 사용합니다.
소제목 제외 규칙과 검증
src/main/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClient.java, src/test/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClientTest.java
대괄호로 감싼 한 줄을 본문 문장, 첨삭 대상, 강점·약점 후보로 분류하지 않습니다. 최종 검증에서는 해당 소제목을 평가한 후보를 NOT_ACTIONABLE로 거절하도록 안내합니다. 테스트는 동적 사례 삽입과 관련 프롬프트 규칙을 확인합니다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant 입력
  participant AnalysisAiClient
  participant FewShotSearchService
  participant AI모델
  입력->>AnalysisAiClient: 분석 입력 전달
  AnalysisAiClient->>FewShotSearchService: FewShotSearchQuery로 관련 사례 검색
  FewShotSearchService-->>AnalysisAiClient: 선택된 few-shot 사례 반환
  AnalysisAiClient->>AI모델: 동적 사례와 소제목 제외 규칙을 포함한 프롬프트 전달
  AI모델-->>AnalysisAiClient: 분석 결과와 후보 반환
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 자기소개서 소제목을 첨삭 평가 대상에서 제외하는 핵심 변경을 간결하게 설명합니다.
Description check ✅ Passed 변경 목적과 세부 동작을 설명하고 테스트 및 브랜치 확인 항목을 표시했으며, 스크린샷과 이슈 번호는 비어 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ignore-cover-letter-subheadings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClient.java`:
- Around line 223-230: 한 줄 전체가 대괄호로 감싸진 소제목을 서버에서 식별하고 모든 후보 경로에서 제외하도록 수정하세요.
analyzeSinglePass의 결과와 sanitizeStrengthCandidates, sanitizeAnalysisCandidates의
원문 부분 문자열 검증에 해당 판별을 적용하고, buildRecheckPrompt 및 recheckValidationFailure를 포함한
recheckWhenAllCandidatesRejected 복원 경로에서도 소제목이 다시 추가되지 않게 하세요.
- Line 1209: Update the few-shot prompt construction in the relevant analysis
flow around selectedFewShots so it uses an API actually exposed by
FewShotPromptProvider. Prefer the existing getPrompt() method, or add
buildPromptBlock(List<SelectedFewShotCase>) to FewShotPromptProvider if that
behavior is required, ensuring the code compiles and preserves the intended
prompt output.

In
`@src/test/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClientTest.java`:
- Around line 309-343: Expand
buildPromptUsesSelectedFewShotsWhenDynamicSelectionEnabled around
resolveFewShotPromptBlock to cover both an empty searchRelevantFewShots result
and an exception from that service, asserting each fallback prompt contains the
fixed few-shot block. Also verify searchRelevantFewShots is called with
fewShotProperties.getSearch().getTopK() as its top-k argument, while preserving
the existing successful-selection assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d49b004d-92df-4eea-8441-34f1091ae523

📥 Commits

Reviewing files that changed from the base of the PR and between dab6c12 and 3980524.

📒 Files selected for processing (2)
  • src/main/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClient.java
  • src/test/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClientTest.java

Comment on lines +223 to +230
[소제목 처리 규칙]
- 답변에서 한 줄 전체가 대괄호로 감싸진 형식(예: [문제를 기회로 바꾼 경험])은 본문 문장이 아니라 소제목이다.
- 소제목 자체를 EXPERIENCE, PLAN, MOTIVATION, COMPETENCY 문장으로 분류하거나 questionAnalyses의 sentence로 반환하지 않는다.
- 소제목 자체를 keyStrengths의 quote 또는 keyWeaknesses의 근거로 반환하지 않는다.
- 소제목에 행동, 역할, 방법, 성과가 없다는 이유로 구체성이 부족하다고 판단하거나 점수를 감점하지 않는다.
- 소제목은 바로 뒤 문단의 주제와 흐름을 이해하는 보조 맥락으로만 사용하고, 실제 평가는 본문 문장을 기준으로 한다.
- 소제목이 문단 내용을 요약하는 표현인지 여부는 문단 이해에만 참고하며, 소제목 문구 자체를 별도 첨삭 대상으로 만들지 않는다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

소제목 제외를 서버 검증으로 강제하세요.

현재 규칙은 프롬프트에만 있습니다. analyzeSinglePass는 모델 응답을 바로 반환합니다. sanitizeStrengthCandidatessanitizeAnalysisCandidates도 대괄호 소제목을 원문 부분 문자열로 인정합니다.

또한 2차 검토가 소제목 후보를 거절해도 recheckWhenAllCandidatesRejected가 이를 재검증 단계에서 다시 복원할 수 있습니다. buildRecheckPromptrecheckValidationFailure에는 소제목 차단 규칙이 없습니다.

한 줄 전체가 대괄호로 감싸진 항목을 식별하는 서버 측 판별을 추가하세요. 이 판별을 single-pass 결과, 1차 strength/analysis 후보, 재검증 복원 경로에 모두 적용하세요. 그렇지 않으면 모델 응답에 따라 PR 목표와 달리 소제목이 첨삭 또는 강점으로 노출됩니다.

Also applies to: 688-695, 867-867

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClient.java`
around lines 223 - 230, 한 줄 전체가 대괄호로 감싸진 소제목을 서버에서 식별하고 모든 후보 경로에서 제외하도록 수정하세요.
analyzeSinglePass의 결과와 sanitizeStrengthCandidates, sanitizeAnalysisCandidates의
원문 부분 문자열 검증에 해당 판별을 적용하고, buildRecheckPrompt 및 recheckValidationFailure를 포함한
recheckWhenAllCandidatesRejected 복원 경로에서도 소제목이 다시 추가되지 않게 하세요.

selectedFewShots.stream().map(item -> "%.4f".formatted(item.score())).toList(),
fewShotProperties.getDatasetVersion()
);
return fewShotPromptProvider.buildPromptBlock(selectedFewShots);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

FewShotPromptProvider에 없는 메서드를 호출합니다.

제공된 FewShotPromptProvider.java:13-43에는 getPrompt()만 있고 buildPromptBlock(List<SelectedFewShotCase>)가 없습니다. 이 호출은 컴파일되지 않습니다. FewShotPromptProvider에 해당 메서드를 구현하거나 기존 공개 API를 사용하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClient.java`
at line 1209, Update the few-shot prompt construction in the relevant analysis
flow around selectedFewShots so it uses an API actually exposed by
FewShotPromptProvider. Prefer the existing getPrompt() method, or add
buildPromptBlock(List<SelectedFewShotCase>) to FewShotPromptProvider if that
behavior is required, ensuring the code compiles and preserves the intended
prompt output.

Comment on lines +309 to +343
@Test
@DisplayName("dynamic few-shot이 활성화되면 선택된 예시만 single-pass 프롬프트에 포함한다")
void buildPromptUsesSelectedFewShotsWhenDynamicSelectionEnabled() {
fewShotProperties.setDynamicSelectionEnabled(true);
FewShotCase selectedCase = new FewShotCase(
"FS-DYNAMIC-1",
FewShotSource.CURATED,
FewShotReviewStatus.APPROVED,
true,
0,
"백엔드 개발",
"Backend Engineer",
List.of("API 개발"),
List.of("Spring Boot"),
"직무 경험",
"API를 개발했습니다.",
"{\"questionAnalyses\":[]}",
List.of("api"),
"fewshot-test-v1",
"## 예시 Z: 동적 선택 예시\n출력 중 문장/누락 관련 필드:\n{}"
);
when(fewShotSearchService.searchRelevantFewShots(org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyInt()))
.thenReturn(List.of(new SelectedFewShotCase(selectedCase, 0.91, "test")));

String prompt = analysisAiClient.buildPrompt(
mockJobPosting(),
List.of(mockQuestion()),
new RetrievalContext(List.of(), List.of()),
null
);

assertThat(prompt)
.contains("## 예시 Z: 동적 선택 예시")
.doesNotContain("## 예시 A: 좋은 근거가 있으면 보완 문장이 0개일 수 있음");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

빈 결과와 검색 실패 fallback을 테스트하세요.

이 테스트는 선택 성공 경로만 검증합니다. resolveFewShotPromptBlock의 빈 결과 및 예외 fallback은 프롬프트 생성 가능성을 보장하는 동작입니다.

searchRelevantFewShots가 빈 목록을 반환하는 경우와 예외를 던지는 경우를 추가하세요. 두 경우 모두 고정 few-shot 블록이 포함되는지 검증하세요. 또한 호출 인자가 fewShotProperties.getSearch().getTopK()와 같은지 검증하세요.

As per path instructions: "해피패스만 있는 경우 경계 조건과 회귀 위험을 지적하세요."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/jobdri/jobdri_api/domain/analysis/service/ai/AnalysisAiClientTest.java`
around lines 309 - 343, Expand
buildPromptUsesSelectedFewShotsWhenDynamicSelectionEnabled around
resolveFewShotPromptBlock to cover both an empty searchRelevantFewShots result
and an exception from that service, asserting each fallback prompt contains the
fixed few-shot block. Also verify searchRelevantFewShots is called with
fewShotProperties.getSearch().getTopK() as its top-k argument, while preserving
the existing successful-selection assertion.

Source: Path instructions

@whc9999 whc9999 closed this Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant