뒤로가기
AI 코드 리뷰를 팀에 도입해봤다

November 3, 2025

aidevopsfrontend

코드 리뷰가 병목이었다. PR을 올리면 리뷰어가 볼 때까지 반나절에서 하루. 리뷰어도 바쁘니까 꼼꼼하게 보기 어렵다. "LGTM" 한 줄로 승인되는 PR이 늘어났다. 리뷰의 질이 떨어지고 있다는 건 다들 알고 있었는데, 뾰족한 수가 없었다.

AI 코드 리뷰를 붙여보자는 아이디어가 나왔다. 사람 리뷰를 대체하는 게 아니라, 1차 필터로 쓰자는 거다. AI가 기본적인 것들을 잡아주면 사람 리뷰어가 로직과 설계에 집중할 수 있지 않을까.

어떻게 붙였나#

GitHub Action으로 PR이 열리면 자동으로 AI 리뷰가 달리게 했다. diff를 추출해서 Claude API에 보내고, 리뷰 코멘트를 PR에 남기는 방식이다.

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

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

      - name: Get diff
        run: git diff origin/${{ github.base_ref }}...HEAD > diff.txt

      - name: AI Review
        run: node scripts/ai-review.js
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ github.event.pull_request.number }}

리뷰 스크립트에서 중요한 건 프롬프트였다. 처음에는 "이 코드를 리뷰해줘"라고 했더니 모든 줄에 코멘트를 달았다. 변수명 제안, 스타일 지적, 심지어 칭찬까지. 노이즈가 너무 많았다.

프롬프트를 구체적으로 바꿨다:

text
아래 diff를 리뷰해주세요. 다음 항목만 코멘트하세요:
1. 버그 또는 잠재적 런타임 에러
2. 보안 취약점
3. 성능 문제 (불필요한 리렌더링, N+1 쿼리 등)
4. 누락된 에러 처리

스타일, 네이밍, 포맷팅은 코멘트하지 마세요.
문제가 없으면 빈 배열을 반환하세요.

이렇게 바꾸니까 코멘트 수가 PR당 평균 12개에서 2~3개로 줄었고, 유의미한 지적의 비율이 올라갔다.

AI가 잘 잡아낸 것#

1. 누락된 에러 처리

typescript
// AI가 지적한 코드
const response = await fetch('/api/users');
const data = await response.json(); // response.ok 체크 없음

이런 건 사람 리뷰에서 자주 놓치는데 AI는 거의 100% 잡아냈다. 기계적으로 패턴을 체크하는 데 강하다.

2. 옵셔널 체이닝 누락

typescript
// AI가 지적한 코드
const userName = user.profile.name;
// user.profile이 null일 수 있는 타입인데 옵셔널 체이닝 없음

TypeScript strict mode에서 잡히는 것도 있지만, any나 타입 단언으로 우회한 경우에는 타입 체커가 놓치고 AI가 잡아내는 경우가 있었다.

3. useEffect 의존성 배열 문제

typescript
// AI가 지적한 코드
useEffect(() => {
  fetchData(userId);
}, []); // userId가 의존성에 빠져 있음

ESLint exhaustive-deps 규칙으로도 잡히지만, 이미 disable 주석이 달려 있는 경우에 AI가 "이 disable이 정당한가?"를 물어봤다.

AI가 놓친 것#

1. 비즈니스 로직 오류

할인율 계산에서 퍼센트와 소수점을 혼동한 코드가 있었다. discount * 100을 해야 하는데 discount를 그대로 쓴 건데, AI는 이걸 지적하지 못했다. 코드 자체는 문법적으로 완벽했으니까. 도메인 지식이 필요한 버그는 여전히 사람의 몫이다.

2. 아키텍처 판단

"이 로직이 여기 있는 게 맞는가?", "이 추상화가 적절한가?" 같은 설계 수준의 질문은 AI가 하지 않았다. 현재 diff만 보니까 전체 코드베이스의 맥락을 모른다.

3. 팀 컨벤션

"우리 팀은 이런 경우 커스텀 훅으로 빼는데"라든가, "이 패턴은 지난번에 문제가 생겨서 안 쓰기로 했는데" 같은 팀 고유의 맥락은 AI가 알 수 없다.

팀 반응#

처음 2주는 반응이 갈렸다.

긍정적: "기본적인 실수를 잡아줘서 리뷰할 때 로직에 집중할 수 있다", "PR 올리기 전에 셀프 체크 리마인더가 되는 느낌"

부정적: "뻔한 걸 지적해서 거슬린다", "이거 고치라는 건지 참고하라는 건지 모르겠다"

부정적 반응의 원인은 대부분 노이즈였다. 프롬프트를 다듬고, 심각도를 나눠서 표시하게 바꾸니 불만이 줄었다. "bug"는 빨간색, "suggestion"은 회색으로 라벨을 달았다.

3개월이 지나자 팀에서 자연스럽게 받아들여졌다. AI 코멘트가 달리면 훑어보고, 맞는 지적이면 반영하고, 아니면 무시한다. 존재감은 낮은데 가끔 유용한, 딱 그 정도의 포지션을 찾은 것 같다.

비용#

Claude API 비용은 월 2만 원 정도였다. PR이 하루 평균 3~4개, diff 크기는 보통 수백 줄. 토큰 비용이 크지 않다. 사람 리뷰어의 시간 절약을 생각하면 충분히 합리적이다.

사람 리뷰를 대체하려 하면 실패한다. AI 코드 리뷰는 린터의 연장선에 가깝다. 린터가 문법을 잡듯이, AI는 패턴 수준의 실수를 잡는다. 설계와 맥락은 여전히 사람이 봐야 한다.