LLM이 코드를 이해하고 리뷰 피드백을 생성하는 원리를 분석하고, AI 코드 리뷰 시스템의 아키텍처를 설계합니다.
AI 코드 리뷰 시스템을 구축하기 전에, LLM이 코드를 이해하는 방식을 먼저 파악해야 합니다. LLM은 코드를 토큰(Token) 단위로 처리합니다. 하나의 토큰은 코드의 한 단어, 연산자, 또는 기호에 해당합니다. 모델은 사전 학습 과정에서 수십억 줄의 코드를 학습하며, 코드의 구문(Syntax), 의미(Semantics), 관용적 패턴(Idiomatic Patterns)을 내재화합니다.
코드 리뷰에서 LLM이 수행하는 추론 과정을 단계별로 살펴봅니다.
LLM의 코드 리뷰 추론 과정:
1단계 - 구문 분석:
- 언어 식별 (TypeScript, Python 등)
- 코드 구조 파악 (함수, 클래스, 모듈)
- 타입 정보 추론
2단계 - 의미 분석:
- 변수명과 함수명에서 의도 추론
- 제어 흐름 분석 (분기, 반복, 예외)
- 데이터 흐름 추적
3단계 - 맥락 매칭:
- 학습된 코드 패턴과 비교
- 알려진 안티패턴 식별
- 보안 취약점 패턴 매칭
4단계 - 피드백 생성:
- 문제점의 심각도 분류
- 개선 방안 제안
- 근거와 설명 생성AI 코드 리뷰의 품질은 모델에 제공하는 맥락(Context)의 범위와 품질에 크게 좌우됩니다. 맥락은 크게 세 가지 수준으로 구분합니다.
변경 수준 맥락(Diff-level Context): PR의 변경 사항(diff) 자체입니다. 어떤 줄이 추가되고, 삭제되고, 수정되었는지를 보여줍니다. 가장 기본적인 수준의 맥락이지만, 변경 사항만으로는 전체 그림을 파악하기 어렵습니다.
파일 수준 맥락(File-level Context): 변경된 파일의 전체 내용입니다. 변경된 함수가 속한 클래스의 전체 구조, 임포트 관계, 같은 파일 내의 관련 함수를 포함합니다. 변경 사항의 맥락을 이해하는 데 필수적입니다.
프로젝트 수준 맥락(Project-level Context): 프로젝트의 전체 구조, 코딩 컨벤션, 아키텍처 패턴, 기존 유사 구현 등을 포함합니다. 프로젝트의 관례에 맞는 리뷰를 수행하는 데 필요합니다.
맥락 범위와 리뷰 품질의 관계:
변경 수준만 제공:
- 구문 오류, 명백한 버그 식별 가능
- 비즈니스 로직 오류 식별 불가
- 프로젝트 컨벤션 준수 여부 판단 불가
파일 수준 추가:
- 함수 간 관계, 타입 일관성 검증 가능
- 같은 파일 내 중복 코드 식별 가능
- 클래스/모듈의 응집도 평가 가능
프로젝트 수준 추가:
- 아키텍처 패턴 준수 여부 판단 가능
- 프로젝트 전체의 일관성 검증 가능
- 기존 유틸리티 활용 제안 가능LLM의 컨텍스트 윈도우(Context Window)는 유한합니다. Claude 3.5 Sonnet은 200K 토큰, GPT-4o는 128K 토큰의 컨텍스트를 지원합니다. 대규모 PR에서는 변경된 파일 전체를 모델에 전달하는 것이 불가능할 수 있습니다.
이 문제를 해결하기 위한 전략을 설계합니다.
// 맥락 최적화 전략
interface ContextStrategy {
// 1단계: 변경 파일 분류
classifyFiles(diff: FileDiff[]): ClassifiedFiles
// 2단계: 우선순위별 맥락 수집
gatherContext(classified: ClassifiedFiles): ReviewContext
// 3단계: 토큰 예산 내 맥락 축소
trimToTokenBudget(context: ReviewContext, budget: number): ReviewContext
}
interface ClassifiedFiles {
// 비즈니스 로직 변경 - 최우선 리뷰 대상
businessLogic: FileDiff[]
// 인프라/설정 변경 - 중요도 높음
infrastructure: FileDiff[]
// 테스트 변경 - 비즈니스 로직과 함께 리뷰
tests: FileDiff[]
// 스타일/포맷 변경 - 낮은 우선순위
formatting: FileDiff[]
}파일을 분류한 뒤, 우선순위에 따라 맥락을 수집합니다. 비즈니스 로직 파일은 전체 파일 맥락을 제공하고, 포맷 변경 파일은 diff만 제공하는 방식으로 토큰 예산을 관리합니다.
실제 AI 코드 리뷰 시스템의 아키텍처를 설계합니다. 시스템은 크게 네 개의 계층으로 구성됩니다.
PR이 생성되거나 업데이트되면 GitHub Webhook이 이벤트를 발생시킵니다. 이벤트 수신기는 이 이벤트를 받아 리뷰 파이프라인을 시작합니다.
// 이벤트 수신기 핵심 로직
interface PullRequestEvent {
action: "opened" | "synchronize" | "reopened"
pullRequest: {
number: number
title: string
body: string
baseBranch: string
headBranch: string
}
repository: {
owner: string
name: string
}
}
function shouldReview(event: PullRequestEvent): boolean {
// 리뷰 대상 필터링 조건
const skipPatterns = [
/^(chore|style|docs):/, // 리뷰 불필요한 커밋 타입
/\[skip-review\]/, // 명시적 스킵 표시
]
const title = event.pullRequest.title
return !skipPatterns.some(pattern => pattern.test(title))
}변경 분석기는 PR의 diff를 가져와 구조화된 형태로 변환합니다. 단순히 텍스트 diff를 전달하는 것보다, 변경의 성격을 분류하여 전달하면 리뷰 품질이 향상됩니다.
interface FileChange {
filename: string
status: "added" | "modified" | "deleted" | "renamed"
additions: number
deletions: number
patch: string // unified diff 형식
language: string // 파일 확장자 기반 언어 식별
category: ChangeCategory
}
type ChangeCategory =
| "business-logic" // 핵심 비즈니스 로직
| "api-endpoint" // API 엔드포인트
| "database" // 스키마, 마이그레이션, 쿼리
| "test" // 테스트 코드
| "config" // 설정 파일
| "dependency" // 패키지 의존성
| "documentation" // 문서
| "style" // 코드 포맷팅
function categorizeChange(file: FileChange): ChangeCategory {
const path = file.filename.toLowerCase()
if (path.includes("test") || path.includes("spec")) return "test"
if (path.includes("migration")) return "database"
if (path.match(/\.(json|ya?ml|toml|env)$/)) return "config"
if (path.match(/package.*\.json|requirements|go\.mod/)) return "dependency"
if (path.match(/\.md$/)) return "documentation"
if (path.match(/route|controller|handler|endpoint/)) return "api-endpoint"
return "business-logic"
}맥락 수집기는 변경된 파일뿐 아니라 관련 파일의 맥락도 수집합니다. 변경된 함수가 호출하는 함수, 변경된 타입을 사용하는 코드, 관련 테스트 파일 등을 포함합니다.
interface ReviewContext {
// PR 메타데이터
prTitle: string
prDescription: string
// 변경 파일과 diff
changes: FileChange[]
// 관련 파일의 전체 내용 (변경된 파일 + 참조 파일)
fullFiles: Map<string, string>
// 프로젝트 맥락
projectContext: {
codeStyle: string // 코딩 컨벤션 문서
architecture: string // 아키텍처 가이드
recentReviews: string // 최근 리뷰 히스토리
}
}
async function gatherContext(
event: PullRequestEvent,
changes: FileChange[]
): Promise<ReviewContext> {
const fullFiles = new Map<string, string>()
// 변경된 파일의 전체 내용 수집
for (const change of changes) {
if (change.status !== "deleted") {
const content = await fetchFileContent(
event.repository,
event.pullRequest.headBranch,
change.filename
)
fullFiles.set(change.filename, content)
}
}
// 관련 파일 수집 (임포트 분석)
for (const change of changes) {
const content = fullFiles.get(change.filename)
if (content) {
const imports = extractImports(content)
for (const importPath of imports) {
if (!fullFiles.has(importPath)) {
const importContent = await fetchFileContent(
event.repository,
event.pullRequest.headBranch,
importPath
)
if (importContent) {
fullFiles.set(importPath, importContent)
}
}
}
}
}
return {
prTitle: event.pullRequest.title,
prDescription: event.pullRequest.body,
changes,
fullFiles,
projectContext: await fetchProjectContext(event.repository),
}
}프롬프트 구성기는 수집된 맥락을 LLM에 전달할 프롬프트로 변환합니다. 프롬프트 설계는 리뷰 품질에 직접적인 영향을 미치므로 신중하게 구성해야 합니다.
function buildReviewPrompt(context: ReviewContext): string {
const systemPrompt = `당신은 시니어 소프트웨어 엔지니어입니다.
PR의 코드 변경을 리뷰하고, 문제점과 개선 사항을 식별해야 합니다.
리뷰 기준:
1. 정확성: 로직 오류, 엣지 케이스 누락, 타입 안전성
2. 보안: 인젝션, 인증 우회, 민감 정보 노출
3. 성능: 불필요한 연산, 메모리 누수, N+1 쿼리
4. 가독성: 네이밍, 구조, 복잡도
5. 유지보수성: 결합도, 응집도, 확장 가능성
응답 형식:
각 피드백은 다음 JSON 형식으로 제공하세요.
- file: 파일 경로
- line: 해당 줄 번호
- severity: critical | warning | suggestion | praise
- category: bug | security | performance | readability | maintainability
- comment: 구체적인 피드백 내용
- suggestion: 개선된 코드 (선택)`
const userPrompt = buildUserPrompt(context)
return systemPrompt + "\n\n" + userPrompt
}프롬프트에 구체적인 응답 형식을 지정하면, LLM의 출력을 프로그래밍적으로 파싱하기 쉬워집니다. JSON 형식을 지정하고, 각 필드의 가능한 값을 열거형으로 제한하면 일관된 출력을 얻을 수 있습니다.
LLM이 생성한 피드백을 그대로 PR에 게시하면 노이즈가 발생할 수 있습니다. 피드백 필터는 중복 제거, 심각도 기반 필터링, 이전 리뷰와의 중복 확인을 수행합니다.
interface ReviewFeedback {
file: string
line: number
severity: "critical" | "warning" | "suggestion" | "praise"
category: string
comment: string
suggestion?: string
}
function filterFeedback(
feedbacks: ReviewFeedback[],
options: FilterOptions
): ReviewFeedback[] {
let filtered = feedbacks
// 1. 심각도 기반 필터링
if (options.minSeverity) {
const severityOrder = ["praise", "suggestion", "warning", "critical"]
const minIndex = severityOrder.indexOf(options.minSeverity)
filtered = filtered.filter(f => {
return severityOrder.indexOf(f.severity) >= minIndex
})
}
// 2. 중복 제거 (같은 파일, 같은 줄, 유사한 코멘트)
filtered = deduplicateFeedbacks(filtered)
// 3. 이전 리뷰와 중복 확인
if (options.previousReviews) {
filtered = removeAlreadyReviewed(filtered, options.previousReviews)
}
// 4. 최대 피드백 수 제한
if (options.maxFeedbacks) {
filtered = prioritizeAndLimit(filtered, options.maxFeedbacks)
}
return filtered
}AI 코드 리뷰의 품질은 프롬프트 설계에 크게 좌우됩니다. 효과적인 프롬프트를 구성하기 위한 핵심 전략을 정리합니다.
프롬프트의 시작에서 모델에게 명확한 역할과 리뷰 기준을 부여합니다. 추상적인 지시보다 구체적인 체크리스트가 더 일관된 결과를 생성합니다.
자유 형식의 텍스트 출력보다 구조화된 형식(JSON, XML)을 요청하면, 후속 처리가 용이해지고 출력 일관성이 높아집니다.
코드 리뷰에서도 Chain-of-Thought 방식이 효과적입니다. 모델에게 먼저 코드의 목적을 이해하고, 그 다음 잠재적 문제를 식별하도록 유도하면 더 정확한 피드백을 얻을 수 있습니다.
프롬프트 구조 권장 순서:
1. 역할 정의: "당신은 10년 경력의 백엔드 엔지니어입니다"
2. 작업 설명: "PR의 코드 변경을 리뷰하세요"
3. 리뷰 기준: 정확성, 보안, 성능, 가독성 체크리스트
4. 맥락 제공: 프로젝트 구조, 코딩 컨벤션
5. 코드 변경: diff + 관련 파일
6. 출력 형식: JSON 스키마 명시
7. 제약 조건: "추측하지 말 것", "근거를 제시할 것"AI 코드 리뷰 시스템의 실용성은 비용과 지연 시간에 달려 있습니다.
비용 추정 (2026년 기준, 대략적 수치):
소규모 PR (변경 100줄 이하):
- 입력 토큰: 약 3,000-5,000
- 출력 토큰: 약 1,000-2,000
- 예상 비용: $0.01-0.03 (Claude Sonnet 기준)
중규모 PR (변경 100-500줄):
- 입력 토큰: 약 10,000-30,000
- 출력 토큰: 약 2,000-5,000
- 예상 비용: $0.05-0.15
대규모 PR (변경 500줄 이상):
- 입력 토큰: 약 30,000-100,000
- 출력 토큰: 약 5,000-10,000
- 예상 비용: $0.15-0.50
월간 비용 추정 (팀 5명, 일일 PR 3개):
- 월간 PR 수: 약 300개
- 월간 예상 비용: $15-45리뷰 결과가 PR 생성 후 수 분 이내에 제공되어야 개발 흐름을 방해하지 않습니다.
지연 시간 최적화 전략:
병렬 처리:
- 파일별로 독립적인 리뷰 요청을 병렬 실행
- 맥락 수집과 이전 리뷰 조회를 병렬 수행
캐싱:
- 프로젝트 맥락 (코딩 컨벤션, 아키텍처 문서) 캐싱
- 변경되지 않은 파일의 리뷰 결과 캐싱
점진적 리뷰:
- 첫 번째 패스: critical/warning 피드백만 빠르게 제공
- 두 번째 패스: suggestion/praise 피드백 추가 제공이 장에서는 AI 코드 리뷰 시스템의 원리와 아키텍처를 다루었습니다. LLM이 코드를 이해하는 방식, 맥락의 중요성, 시스템의 전체 아키텍처, 프롬프트 전략, 비용과 지연 시간 고려 사항을 살펴보았습니다.
핵심 내용을 정리합니다.
다음 장에서는 이 아키텍처를 실제로 구현합니다. GitHub Actions를 활용하여 PR에 자동으로 AI 코드 리뷰를 수행하는 시스템을 직접 구축합니다.
이 글이 도움이 되셨나요?
GitHub Actions를 활용하여 PR에 자동으로 AI 코드 리뷰를 수행하는 시스템을 직접 구축하고, 실전에서 활용 가능한 수준으로 완성합니다.
AI가 소프트웨어 개발의 각 단계를 어떻게 혁신하는지 전체 그림을 조망하고, 코드 리뷰, 테스트, 문서화, CI/CD 자동화의 핵심 개념을 정리합니다.
코드 변경을 분석하여 단위 테스트와 통합 테스트를 자동으로 생성하는 시스템을 구축하고, 테스트 품질을 검증하는 방법을 다룹니다.