6adbc2a6fa
일반 에이전트 채팅이 큰 코드베이스 리뷰를 단일 호출로 처리하다 약한 로컬 모델에서 빈 응답으로 무너지던 문제를, /meet 의 검증된 map-reduce 로 우회. - /review <디렉터리|파일> [초점] 신설 (코어 채팅 경로 무수정) - Map: 파일별 독립 리뷰(라인 인용 근거), callLmSynthesis 재시도/붕괴감지 활용, 한 파일 실패해도 부분 리뷰로 진행 - Reduce: 노트 통합 + hierarchical fold 로 reduce 입력을 약한 모델 한도(16K) 안 유지 - 의존성/빌드 산출물 제외, 파일 30개·400KB 상한, 결과 wiki 저장 - 신규 reviewPrompt.ts / reviewFiles.ts, 테스트 +5건(전체 667 통과) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
94 lines
5.0 KiB
TypeScript
94 lines
5.0 KiB
TypeScript
/**
|
|
* 코드 리뷰 map-reduce 프롬프트.
|
|
*
|
|
* 일반 에이전트 채팅은 코드 리뷰처럼 입력이 큰 작업을 단일 호출로 처리하다
|
|
* 약한 로컬 모델에서 빈 응답(첫 토큰 EOS)으로 무너진다. /review 는 /meet 와 같은
|
|
* map-reduce 로 이를 우회한다:
|
|
* - Map : 파일 하나씩 독립 리뷰 → 파일별 발견사항(근거 인용)
|
|
* - Reduce: 파일별 노트를 통합 → 우선순위가 매겨진 최종 리뷰 보고서
|
|
* 입력이 작게 쪼개지므로 약한 모델도 끝까지 생성할 수 있고, lost-in-the-middle 도 준다.
|
|
*/
|
|
|
|
/** [Map] 파일 1개를 리뷰해 발견사항만 추출. 근거(라인/코드 인용) 필수, 날조 금지. */
|
|
export function buildReviewFilePrompt(relPath: string, content: string, idx: number, total: number, focus: string): string {
|
|
const focusBlock = focus.trim()
|
|
? `\n# 리뷰 초점 (사용자 지정 — 우선 점검)\n${focus.trim()}\n`
|
|
: '';
|
|
// 라인 번호를 붙여 모델이 정확한 위치를 인용하게 한다(환각 위치 방지).
|
|
const numbered = content.split('\n').map((l, i) => `${String(i + 1).padStart(4, ' ')}| ${l}`).join('\n');
|
|
return `# 임무
|
|
당신은 시니어 코드 리뷰어다. 아래 **단일 파일**(${idx}/${total}번째)을 리뷰해 발견사항만 추출하라.
|
|
최종 보고서는 나중에 모든 파일 노트를 합쳐 작성하므로, 여기서는 이 파일에 대한 사실 기반 발견사항을 **누락 없이** 뽑는 것이 임무다.
|
|
${focusBlock}
|
|
# 점검 항목
|
|
- **버그/오류**: 논리 오류, 경계 조건, null/undefined, 예외 미처리, 경쟁 조건, 자원 누수
|
|
- **보안**: 입력 검증 누락, 인젝션, 비밀정보 하드코딩, 안전하지 않은 역직렬화/권한
|
|
- **성능**: 불필요한 반복·할당, N+1, 동기 블로킹, 비효율 자료구조
|
|
- **설계/구조**: 책임 분리, 결합도, 중복, 추상화 누락/과잉
|
|
- **가독성/유지보수**: 네이밍, 죽은 코드, 매직 넘버, 주석/타입 부재
|
|
|
|
# 규칙 (할루시네이션 방지 — 반드시 준수)
|
|
- **이 파일에 실제로 있는 코드만** 근거로 삼는다. 없는 함수·호출·취약점을 지어내지 말 것.
|
|
- 각 발견사항에는 **위치(라인 번호)** 와 **근거가 되는 코드 일부(짧게 인용)** 를 붙인다.
|
|
- 확실하지 않으면 단정하지 말고 "확인 필요"로 표시한다.
|
|
- 이 파일이 전반적으로 양호하면 발견사항을 억지로 만들지 말고 "특이사항 없음"이라고 적는다.
|
|
- 다른 파일·외부 맥락을 가정하지 말 것(이 파일만 본다).
|
|
|
|
[파일 경로] ${relPath}
|
|
|
|
[파일 내용 — "라인번호| 코드" 형식]
|
|
\`\`\`
|
|
${numbered}
|
|
\`\`\`
|
|
|
|
# 출력 형식 (이 파일에 해당 항목이 없으면 "없음")
|
|
## 파일: ${relPath}
|
|
### 발견사항
|
|
- [심각도: 높음|중간|낮음] [분류: 버그|보안|성능|설계|가독성] (L<라인>) 설명 — 근거: "코드 일부"
|
|
· 개선 제안: 구체적으로 무엇을 어떻게 바꿀지
|
|
(특이사항이 없으면 "- 특이사항 없음")
|
|
### 한줄 요약
|
|
이 파일의 역할과 전반 상태를 한 문장으로.`;
|
|
}
|
|
|
|
/** [Reduce] 파일별 노트를 통합해 우선순위가 매겨진 최종 코드 리뷰 보고서 작성. */
|
|
export function buildReviewReducePrompt(notes: string, projectLabel: string, fileCount: number, focus: string): string {
|
|
const focusBlock = focus.trim() ? `\n# 리뷰 초점 (사용자 지정)\n${focus.trim()}\n` : '';
|
|
return `# 임무
|
|
아래는 \`${projectLabel}\` 의 파일 ${fileCount}개를 파일별로 리뷰한 노트다. 이 노트만 근거로 **통합 코드 리뷰 보고서**를 작성하라.
|
|
${focusBlock}
|
|
# 규칙
|
|
- **노트에 있는 발견사항만** 사용한다. 노트에 없는 문제를 새로 지어내지 말 것.
|
|
- 여러 파일에 공통으로 나타나는 문제는 묶어서 "공통/구조적 이슈"로 정리한다.
|
|
- 심각도와 영향 범위를 기준으로 **우선순위**를 매긴다(높은 심각도·넓은 영향 우선).
|
|
- 각 이슈에는 파일·라인 위치를 유지한다(근거 추적 가능하게).
|
|
- 비판만 하지 말고 잘 설계된 점도 짚는다.
|
|
|
|
[파일별 리뷰 노트]
|
|
${notes}
|
|
|
|
# 출력 형식 (정확히 이 구조, 한국어)
|
|
|
|
# 코드 리뷰 보고서 — ${projectLabel}
|
|
|
|
## 1. 총평
|
|
전반적 품질·구조·주요 위험을 3~5줄로 요약. 비참석자도 상태를 파악할 수 있게.
|
|
|
|
## 2. 우선 개선 사항 (Top 우선순위)
|
|
가장 시급한 것부터 번호 매겨 정리. 각 항목: [심각도] 문제 — 위치(파일:라인) — 개선 방향.
|
|
|
|
## 3. 분류별 발견사항
|
|
### 🐞 버그/오류
|
|
### 🔒 보안
|
|
### ⚡ 성능
|
|
### 🧩 설계/구조 (공통 이슈 포함)
|
|
### 📖 가독성/유지보수
|
|
(각 항목에 파일:라인 + 한 줄 개선 제안. 해당 분류에 발견사항이 없으면 "발견사항 없음".)
|
|
|
|
## 4. 잘된 점
|
|
유지·강화할 가치가 있는 설계·패턴.
|
|
|
|
## 5. 권장 다음 단계
|
|
실행 가능한 조치를 우선순위 순 체크리스트로.`;
|
|
}
|