Claude API로 코드 리뷰 자동화 만들기

게시일: 2025년 7월 4일 · 16분 읽기

시니어 리뷰어가 부족할 때

우리 팀은 PR은 많고 시니어 리뷰어는 적었다. 결국 리뷰 대기열이 길어졌고, 간단한 버그도 머지까지 하루 이상 걸렸다. 그래서 Claude API로 1차 리뷰 봇을 만들었다.

중요한 원칙은 "AI가 승인하지 않는다"였다. AI는 위험 신호를 먼저 찾고, 사람 리뷰어가 최종 판단한다. 이 구조로 바꾸자 리뷰 리드타임이 줄고, 기초 실수(널 처리, 에러 누락, 로깅 누락) 발견률이 올라갔다.

시스템 아키텍처

GitHub pull_request 이벤트
  -> Actions에서 diff 추출
  -> 파일 확장자/변경량 기반 필터링
  -> Claude API에 리뷰 프롬프트 전달
  -> 위험도(High/Medium/Low)로 정리된 코멘트 생성
  -> PR 코멘트 작성 + 체크 결과 아티팩트 저장

Workflow 예시

# .github/workflows/ai-review.yml
name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Build diff file
        run: |
          git fetch origin ${{ github.base_ref }} --depth=1
          git diff --unified=2 origin/${{ github.base_ref }}...HEAD > pr.diff
          echo "Diff size: $(wc -c < pr.diff) bytes"

      - name: Run AI review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          PR_TITLE: ${{ github.event.pull_request.title }}
          PR_BODY: ${{ github.event.pull_request.body }}
        run: |
          python scripts/ai_review.py --diff-file pr.diff --title "$PR_TITLE" --body "$PR_BODY"

      - name: Comment to PR
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const body = fs.readFileSync('ai-review.md', 'utf8');
            await github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body
            });

리뷰 스크립트 핵심

#!/usr/bin/env python3
import argparse
from anthropic import Anthropic

SYSTEM = """
너는 시니어 코드 리뷰어다.
1) 동작 버그
2) 보안 이슈
3) 성능/동시성 리스크
4) 테스트 누락
만 지적하고, 취향 논쟁은 하지 마라.
"""

def build_prompt(title: str, body: str, diff: str) -> str:
    return f"""
PR 제목: {title}
PR 설명: {body}

아래 diff를 검토하고, 심각도(High/Medium/Low)와 근거를 포함해 작성해줘.
가능하면 수정 예시를 짧게 제시해줘.

{diff}
"""

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--diff-file", required=True)
    ap.add_argument("--title", default="")
    ap.add_argument("--body", default="")
    args = ap.parse_args()

    diff = open(args.diff_file, "r", encoding="utf-8").read()
    client = Anthropic()
    msg = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=1200,
        system=SYSTEM,
        messages=[{"role": "user", "content": build_prompt(args.title, args.body, diff)}],
    )

    text = msg.content[0].text
    with open("ai-review.md", "w", encoding="utf-8") as f:
        f.write("## AI 1차 리뷰 결과\n\n")
        f.write(text)

if __name__ == "__main__":
    main()

프롬프트 설계에서 중요했던 점

처음에는 "전체 품질 피드백" 프롬프트를 썼는데, 결과가 길고 추상적이었다. 버그/보안/성능/테스트 4가지로 좁히니 리뷰 품질이 안정됐다.

운영하면서 생긴 문제와 해결

1) 큰 PR에서 비용 급증

해결: diff 800줄 초과 시 파일별 분할 리뷰로 전환하고, 문서/락파일은 제외했다.

2) 거짓 양성(false positive)

해결: 팀 규칙(예: 허용된 lint disable 패턴)을 시스템 프롬프트에 명시했다.

3) 비밀정보 유출 우려

해결: API 키/토큰 패턴 마스킹, 내부 경로 치환, 민감 파일(.env, secrets/) 사전 차단.

도입 효과 (8주 운영 기준)

지표도입 전도입 후
평균 1차 코멘트 시간3시간 10분12분
PR 머지 리드타임29시간17시간
머지 후 단순 회귀 버그주 6건주 3건

AI가 사람 리뷰를 대체하진 못한다. 하지만 사람 리뷰어가 중요한 판단에 집중하게 만들어 주는 건 확실했다.

결론

코드 리뷰 자동화의 핵심은 "정확한 범위 정의"다. AI를 만능 리뷰어로 쓰지 말고, 반복적이고 규칙 기반인 1차 검증에 제한하면 품질과 속도를 같이 잡을 수 있다.

iL
ian.lab

실무 개발자입니다. 현장에서 겪은 문제와 해결 과정을 기록합니다. 오류 제보는 연락처로 보내주세요.