코드리뷰 자동화

김키핑·2026년 9월 24일
post-thumbnail

매주 진행하던 스터디가 추석을 맞아 한 주 쉬어 가게 되었다.
쉬는 동안 스터디에 도움이 될 만한 게 뭐가 있을지 고민해 보았다.


대 AI 시대

오픈AI의 차세대 인공지능 모델이 90년간 풀리지 않던 세계 7대 수학 난제를 88시간 만에 풀었다.
수많은 수학자가 평생을 바쳐도 답을 찾지 못했던 문제를 AI는 사흘 남짓 만에 해법까지 내놓은 것이다.

이제 AI는 단순히 사람을 돕는 도구를 넘어, 사람이 오랫동안 넘지 못한 벽까지 넘어서고 있다.
이러한 기류에 맞춰 AI 시대는 피할 수 없는 흐름이 되었다.

중요한 건 AI를 두려워하거나 외면하는 게 아니라, AI를 얼마나 잘 활용하느냐다. AI 시대의 인재가 되기 위해서는 AI와 경쟁하는 사람이 아니라, AI에게 일을 맡기고 그 결과를 판단할 줄 아는 사람이 되어야 한다.

개발 현장도 마찬가지다.
코드를 짜는 속도는 빨라졌지만, 그 코드를 검토하는 일은 여전히 사람의 시간과 에너지를 많이 잡아먹는다.

그래서 이번 글에서는 AI를 활용해 코드 리뷰를 자동화하는 방법을 소개해 보려 한다.


코드 리뷰란

작성한 소스 코드에 리뷰를 적고, 동료와 피드백을 주고받는 과정.


코드 리뷰를 AI가 한다고?

전통적인 방식의 코드리뷰는 사람이 진행했다.
AI가 생성한 코드를 이해하고 검증하는 과정은 반드시 필요했지만, 내가 직접 작성한 코드를 검증하는 것보다 더 많은 시간이 걸리는 경우도 있었다.

이때 등장한 것이 CodeRabbit, Greptile, Kodus 같은 AI 솔루션과 도구다.
불과 1년 전, 스터디원들과 합숙하던 때만 해도 우리는 리뷰 다는 법을 배우고 있었다. 그런데 이제는 PR을 올리면 AI가 코드를 먼저 검토하고, 문제가 될 만한 부분에 댓글을 달거나 변경 사항을 요약해 준다.

사람이 작업의 의도와 접근 방식, 테스트 내용, 실패 가능성 등 서비스에 있어 더 중요한 부분들을 집중해서 볼 수 있게 된 것이다.


코드 최종 리뷰에 대한 논의 (사람 vs AI )

코드 최종 리뷰는 사람이 해야한다.

그렇지만 몇몇 개발자들은 AI 코드리뷰의 편리함을 인정하면서도 이 기능은 완벽한 것이 아니기 때문에
최종리뷰만큼은 맡길 수 없다고 한다.

AI가 문제가 될만한 PR을 최종승인한 경험이있거나,
검토할 양이 많으면 대충 읽고 LGTM을 준다고 생각하기 때문이다.


코드 최종 리뷰는 AI가 해도 된다.

사람의 리뷰도 온전히 신뢰할만한 것은 아니다.
최종리뷰까지 AI에게 맡기고, 다른 일에 집중하는 것이 좋을 듯하다는 의견도 있다.


스터디 과제 레포에 AI코드리뷰 도입기

어떤 의견에 더 동의하는가?
지금의 생각도 좋지만, 직접 경험해 보면 생각의 폭이 더 넓어질 것이다.
비용이 들지 않고 간편하게 쓸 수 있는 AI 코드 리뷰 기능을 도입해, 여러 방식으로 사용해 보자.

트리거 설정

PR을 처음 올렸을 때, 추가 커밋을 push 했을 때, 닫았던 PR을 다시 열었을 때 워크플로우가 실행되도록 트리거를 설정하고,
리뷰에 필요한 API 키와 토큰, PR 정보를 환경변수로 스크립트에 전달한다.

name: Gemini PR Review

on: pull_request

permissions:
  contents: read
  pull-requests: write

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

      - run: python .github/scripts/gemini_review.py
        env:
          GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}

API 키 등록

직접 발급이 필요한 제미나이 API 키는 깃허브에도 등록해준다.


diff 추출과 프롬프트 작성

base 커밋과 비교해 PR에서 변경된 내역을 확인하고,
변경내역을 오글거리는 프롬프트와 함께 제미나이에게 전달한다.

def get_diff() -> str:
    result = subprocess.run(
        ["git", "diff", f"{BASE_SHA}...{HEAD_SHA}"],
        capture_output=True,
        text=True,
        check=True,
    )
    diff = result.stdout
    if len(diff) > MAX_DIFF_CHARS:
        diff = diff[:MAX_DIFF_CHARS] + "\n\n... (diff truncated)"
    return diff


def call_gemini(diff: str) -> str:
    prompt = (
        "당신은 숙련된 코드 리뷰어입니다. 아래 git diff를 검토하고 한국어로 리뷰해 주세요.\n"
        "- 버그, 엣지 케이스, 잠재적 오류를 우선적으로 지적하세요.\n"
        "- 개선하면 좋을 점(가독성, 효율성, 네이밍)은 간단히 덧붙이세요.\n"
        "- 지금 코드보다 더 나은 대안이 없다면, 다른 말 없이 정확히 'LGTM' 한 단어만 출력하세요.\n"
        "- Markdown 형식으로, too-long 하지 않게 핵심만 작성하세요.\n\n"
        f"```diff\n{diff}\n```"
    )
    

PR 댓글 등록

1에서 전달한 정보로 리뷰 저장 위치를 탐색하고, payload에 담은 리뷰 내용을 PR 댓글로 등록한다.

def post_comment(body: str) -> None:
    url = f"https://api.github.com/repos/{REPO}/issues/{PR_NUMBER}/comments"
    payload = {"body": f"## 🤖 Gemini Code Review\n\n{body}"}
    req = urllib.request.Request(
        url,
        data=json.dumps(payload).encode("utf-8"),
        headers={
            "Authorization": f"Bearer {GITHUB_TOKEN}",
            "Accept": "application/vnd.github+json",
            "Content-Type": "application/json",
        },
        method="POST",
    )
    with urllib.request.urlopen(req) as resp:
            pass

아키텍처 다이어그램


마치며

경험에서 나오는 판단력은 AI시대에도 바래지 않는 가치를 가지고 있다.
많이 경험하고 , 많이 대화하면서 넓은 시각을 가진 사람이 되어 보자.
2026을 강타할 최고의 스터디 화이팅!

profile
양치기소녀

0개의 댓글