본문 바로가기
AI2026년 4월 26일12분 읽기

AI 코드 리뷰 자동화 파이프라인 — GitHub Actions + Claude API

YS
김영삼
조회 1
AI 코드 리뷰 자동화 파이프라인 — GitHub Actions + Claude API

핵심 요약

모든 PR에 인간 리뷰어 + AI 리뷰어 병행. AI는 24/7 즉시·일관성 우선, 인간은 비즈니스 맥락·아키텍처 판단. 둘 결합 시 PR 머지 속도 + 품질 동시 향상.

  • 매일 50~200 PR — 인간 리뷰만으로는 한계
  • Claude API로 평균 리뷰 비용 PR당 $0.30~$2
  • false positive 관리가 도입 성공 핵심

1. 기본 워크플로

# .github/workflows/ai-review.yml
name: AI Code Review
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      
      - name: Get diff
        run: |
          git diff origin/${{ github.base_ref }}...HEAD > pr.diff
          cat pr.diff | head -c 100000 > pr.diff.trimmed  # 100K char 한도
      
      - name: Run Claude review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          python .github/scripts/review.py \
            --diff pr.diff.trimmed \
            --output review.md
      
      - name: Post review comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs')
            const review = fs.readFileSync('review.md', 'utf8')
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: review
            })

2. 리뷰 스크립트

# .github/scripts/review.py
import os, sys, anthropic

client = anthropic.Anthropic()

SYSTEM_PROMPT = """
당신은 시니어 코드 리뷰어입니다. PR diff를 검토하고:

1. 보안 이슈 (SQL injection, XSS, secret leak)
2. 성능 문제 (N+1, 메모리 leak)
3. 버그 가능성
4. 가독성·명명 개선

각 발견은 다음 JSON 형식:
{
  "file": "경로:줄",
  "severity": "critical|high|medium|low",
  "category": "security|performance|bug|style",
  "message": "설명",
  "suggestion": "개선 코드"
}

모든 발견을 JSON array로 반환. 문제 없으면 [].
중요: 확실한 것만. 모호한 의심은 제외.
"""

def review(diff: str) -> list:
    response = client.messages.create(
        model="claude-opus-4-7",
        max_tokens=4000,
        system=SYSTEM_PROMPT,
        messages=[{
            "role": "user",
            "content": f"PR diff:\n\n```diff\n{diff}\n```"
        }]
    )
    return parse_findings(response.content[0].text)

def format_markdown(findings):
    if not findings:
        return "✅ 자동 리뷰: 발견된 문제 없음."
    
    md = ["## 🤖 AI 코드 리뷰\n"]
    by_severity = {"critical": [], "high": [], "medium": [], "low": []}
    for f in findings:
        by_severity[f["severity"]].append(f)
    
    for sev in ["critical", "high", "medium", "low"]:
        if not by_severity[sev]: continue
        emoji = {"critical": "🔴", "high": "🟠", "medium": "🟡", "low": "🔵"}[sev]
        md.append(f"\n### {emoji} {sev.upper()} ({len(by_severity[sev])})\n")
        for f in by_severity[sev]:
            md.append(f"**{f['file']}**: {f['message']}")
            if f.get("suggestion"):
                md.append(f"```\n{f['suggestion']}\n```\n")
    return "\n".join(md)

if __name__ == "__main__":
    diff = open(sys.argv[1]).read()
    findings = review(diff)
    md = format_markdown(findings)
    open(sys.argv[2], "w").write(md)

3. 비용 최적화

Prompt Caching

# 시스템 프롬프트는 cache_control
response = client.messages.create(
    model="claude-opus-4-7",
    system=[
        {
            "type": "text",
            "text": SYSTEM_PROMPT,
            "cache_control": {"type": "ephemeral"}
        }
    ],
    messages=[...]
)

같은 시스템 프롬프트 반복 → 90% 비용 절감.

모델 라우팅

def select_model(diff: str):
    lines = diff.count("\n")
    if lines < 50:
        return "claude-haiku-3-5"  # 작은 변경
    elif lines < 500:
        return "claude-sonnet-4-6"  # 일반
    else:
        return "claude-opus-4-7"  # 큰 변경

4. False Positive 관리

잘못된 리뷰 표시

PR 작성자가 AI 리뷰 코멘트에 reaction: 👎 → 학습 데이터 수집.

주간 false positive 리뷰

# cron: 매주 월요일
# 지난 주 reactions 분석
# false positive 패턴 식별 → 시스템 프롬프트 개선

특정 패턴 화이트리스트

SYSTEM_PROMPT_ADDITIONS = """
다음은 우리 팀에서 의도적으로 사용하는 패턴이니 지적하지 마세요:
- forEach + await (배치 처리 의도)
- raw SQL (성능 critical 영역)
- console.log (디버깅 한정 디렉토리)
"""

5. 단계별 적용

  1. Week 1-2: 모든 PR에 코멘트만, 차단 안 함
  2. Week 3-4: false positive 패턴 식별·수정
  3. Month 2: critical 등급은 머지 차단 (require-resolved)
  4. Month 3+: 자동 fix suggestion (Copilot Workspace 통합)

6. 보안 — secret 노출 방지

def sanitize_diff(diff: str) -> str:
    # API key 패턴 마스킹
    patterns = [
        (r'sk-[A-Za-z0-9]{40,}', '[REDACTED]'),
        (r'ghp_[A-Za-z0-9]{40}', '[REDACTED]'),
        # ...
    ]
    for pattern, replacement in patterns:
        diff = re.sub(pattern, replacement, diff)
    return diff

7. 다국어 코드베이스

def detect_language(diff):
    if '.py' in diff: return 'Python'
    if '.tsx' in diff or '.ts' in diff: return 'TypeScript'
    if '.go' in diff: return 'Go'
    return 'mixed'

# 언어별 시스템 프롬프트 보강

8. 메트릭

지표측정 방법
PR당 AI 리뷰 비용API usage / PR 수
false positive율👎 reactions / 전체 발견
인간 리뷰 시간 단축도입 전후 PR 머지 시간
실제 버그 발견율AI 발견 → 인간 합의 비율

9. 한계

  • 큰 PR (5000줄 이상)은 chunking 필요
  • 비즈니스 로직 검증 못 함
  • 아키텍처 결정 못 함
  • 코드베이스 컨벤션 학습 어려움

10. 도구 비교

도구특징
자체 구축 (이 글)완전 control, 비용 최저
GreptileSaaS, 코드베이스 학습
CodeRabbitSaaS, 한국어 약함
GitHub Copilot Code ReviewGitHub 통합, 단순

실측 — 도입 효과

지표beforeafter
PR당 인간 리뷰 시간25분10분
버그 머지 비율2.4%0.8%
리뷰 대기 시간4시간5분 (AI) + 2시간 (인간)
월 비용0$400 (200 PR)

자주 묻는 질문

인간 리뷰를 완전 대체?아니다. 비즈니스 맥락·아키텍처는 인간 필수. AI는 보조.

private 코드의 보안?Claude API는 enterprise 옵션에서 학습 데이터 미사용 보장. SOC2·ISO 27001 인증.

다국어 코드베이스 효과?주력 언어 1~2개에 집중하면 정확도 높음. 5개 이상 섞이면 false positive 늘어남.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록