
자사의 리뷰 이력을 활용하여 AI 코드 리뷰어를 만드는 방법
요약
자사의 7년 치 Pull Request 리뷰 이력을 활용하여 조직 특유의 코드 스타일과 리뷰 규약을 반영한 맞춤형 AI 코드 리뷰어를 제작하는 방법을 소개합니다. 범용 AI 도구가 놓치기 쉬운 조직 내 암묵지와 '방언'을 학습시켜 실질적인 도움을 주는 에이전트 구축 과정을 다룹니다.
핵심 포인트
- 범용 AI 도구와 차별화된 조직만의 '코드 방언' 반영 가능
- 7년 치 리뷰 이력을 수집하여 AI가 참조할 리뷰 규약 추출
- 데이터 보안 및 개인정보 취급에 대한 사전 정의의 중요성
- 수집, 분석, 증류, 리뷰의 4단계 프로세스 제안
안녕하세요, 주식회사 estie(에스티)의 이사 CTO인 Nari (@tiwanari)입니다.
여러분은 코드 리뷰에 AI 도구를 활용하고 계신가요? 범용 AI 코드 리뷰 도구는 편리하지만, 자사의 코드 작성 스타일(書き振り)에 대응하거나 리뷰에서 어떤 지적을 할 것인지와 같은 부분까지는 모두 파악하지 못합니다.
estie에서는 창업 이후 7년 동안의 Pull Request(PR)에 대한 리뷰 코멘트를 집계하고, 이를 AI가 참조할 수 있는 「리뷰 규약」으로 변환함으로써 우리다운 지적을 반환하는 AI 리뷰어를 시도해 보았습니다.
이 기사에서는 같은 고민을 가진 분들이 직접 시도해 볼 수 있도록, 그 제작 방법과 잘 된 점, 아직 잘 되지 않는 점을 솔직하게 적고 있습니다.
수행한 작업은 심플합니다. 「7년 치의 리뷰 이력을 전부 모아서 읽히고, 거기서 규약을 추출한다」는 것입니다. 몇 년 전이었다면 비용을 고려했을 때 아무도 진지하게 제안하지 않았을 작업이라고 생각합니다. 그것이 Claude Code와 같은 AI 에이전트의 활용으로 현실적이 되었습니다. 다만, 효과가 있을지는 리뷰 이력의 양과 질에 상당히 의존합니다. 리뷰 코멘트에 설계 판단이나 지적의 강약이 남아 있는 조직이라면, 작게 시도해 볼 가치는 있다고 생각합니다.
먼저 이 기사에서 사용할 용어를 조금 통일해 두겠습니다. blocker는 머지(merge) 전에 수정해야 하는 중대한 지적, nit는 수정하면 좋지만 필수적이지는 않은 세세한 지적입니다. [want]나 [imo]는 estie에서 사용하고 있는 지적 강도의 접두사(prefix)입니다.
왜 범용 AI 리뷰만으로는 부족한가
세상에는 CodeRabbit이나 GitHub Copilot Code Review 등 뛰어난 AI 리뷰 도구가 많이 있으며, estie에서도 활용하고 있습니다. 범용 도구는 언어별 정석이나 잘 알려진 안티 패턴(anti-pattern) 등 일반적인 베스트 프랙티스(best practice)를 망라적으로 확인하는 데 능숙하며, 이는 그 자체로 충분히 도움이 됩니다.
반면, 코드베이스에는 그 회사의 '방언'이 나타나기 마련입니다. 명명(naming) 습관, 설계 선호도, 무엇을 꼼꼼하게 확인하고 무엇을 허용할 것인가. 어디서부터 blocker로 하고 어디를 nit로 남길 것인가. 리뷰 코멘트에는 그러한 암묵지(tacit knowledge)가 쌓여 있습니다. 실제로 estie의 코멘트를 분석해 보니, 의문형 지적이 3할 미만, 일본어와 영어가 섞인 방식이 8할, 코멘트 길이의 중앙값은 약 55자였습니다. 이 짧음과 질문이 많은 특성 자체가 estie의 방언입니다.
범용 도구는 일반론을 알고 있지만, 자사의 리뷰 이력만이 자신들의 방언을 알고 있습니다. 이 차이를 메우는 것이 이번에 만든 리뷰어입니다.
우선, 데이터 취급과 전제를 결정한다
손을 움직이기 전에 데이터 취급 방식을 결정하는 것이 가장 중요했습니다. 리뷰 이력에는 코드뿐만 아니라 개인 이름이나 고객명, 장애 대응 경위, 아직 공개하지 않은 사양(specification)이 포함될 수 있습니다. 우리는 어떤 리포지토리(repository)를 대상으로 할지, 어떤 정보를 AI에 전달해도 될지, 어떤 권한의 토큰으로 취득할지를 먼저 확인했습니다.
그 후에 다음 전제로 진행했습니다.
- 봇의 코멘트, 셀프 리뷰, 단순한 LGTM 등 분석에서 제외할 것을 결정한다
- 처음부터 전사 분량을 모으지 않고, 특정 리포지토리나 몇 개월 분량만으로 시도한다
- 나온 규약을 사람이 읽고 수정하는 시간을 갖는다
이 부분이 모호한 채로 시작하면, 데이터를 모은 뒤에 「이 코멘트를 규약으로 삼아도 되는가」, 「정말로 쓸 수 있는 것이 되는가」라는 문제로 멈추게 됩니다. 우선은 하나의 리포지토리, 짧은 기간, 사내에서 다룰 수 있는 범위부터 시작하는 것이 좋습니다.
만드는 방법은 수집·분석·증류·리뷰의 4단계
전제가 결정되면 크게 4가지 절차로 나뉩니다. 특별한 인프라는 필요하지 않았습니다.

1. 리뷰 이력을 모은다
이번에는 GitHub의 API를 사용하여 PR, 변경 파일, 리뷰 코멘트를 취득하여 JSONL로 저장했습니다. 리뷰 코멘트는 REST의 Pull request review comments(코멘트 본문, path, diff_hunk, line을 가져올 수 있습니다)나 GraphQL로 취득합니다.
GraphQL은 깊은 쿼리나 대량 취득 시 제한(limit)이나 타임아웃(timeout)에 걸리기 쉬우므로, 기간을 반년씩 나누어 수집하고, 레이트 리밋(rate limit)에 걸리더라도 중간부터 재개할 수 있도록 했습니다. 전부 모으는 데 몇 시간에서 반나절 정도 걸립니다.
나중에 분석하기 쉽도록 1코멘트 1행으로 다음과 같은 형태로 만들었습니다.
{
"repo": "example/repo",
"pr_number": 123,
...
모든 데이터를 깔끔하게 추출하려고 하면 매우 힘들기 때문에, 처음에는 repo, pr_number, path, body, diff_hunk, reviewer 정도부터 시작해도 충분합니다. 봇(Bot)과 셀프 리뷰(Self-review)는 다음 분석 단계에서 제외해 둡니다.
2. 경향을 분석하기
분석은 ① 집계만으로 볼 수 있는 단계와, ② AI에게 실제 코멘트를 읽히는 단계의 두 종류로 나누면 정리하기 쉽습니다.
집계에서는 코멘트를 하나씩 bug
・naming
・testing
・security
등의 카테고리로 분류하여, 리포지토리별・리뷰어별・언어별로 집계합니다. 또한 프리픽스(Prefix, blocker / nit 등)의 사용 방식, 코멘트의 길이, 의문문 비율, 수정 코드(Suggestion) 제시율도 측정했습니다.
그 결과, estie의 경우에는 코멘트 길이의 중앙값이 약 55자, 의문문이 약 3할, 기술 용어는 영어로 설명은 일본어로 이루어진 '일영 혼재(日英混在)'가 약 8할이라는 식으로, 우리만의 작성 습관이 숫자로 나타났습니다. 여기까지는 집계 스크립트만으로도 낼 수 있습니다.
반면, 집계만으로는 "무엇을 말하고 있는지"에 대한 의미까지는 알 수 없습니다. 그래서 실제 코멘트 본문을 AI에게 읽혀서, 언어별 빈출 패턴(Rust라면 unwrap 처리나 에러 설계, TypeScript라면 타입이나 Hooks 사용법 등)을 근거가 된 건수와 함께 추출합니다. 표현이 달라도 같은 내용을 말하는 지적을 정리하면, "여러 번 등장함 = 규칙으로 정해야 할 지적"이 드러나게 됩니다. 이러한 '의미' 차원의 집약이 다음 증류(Distillation) 단계의 재료가 됩니다.
(그 외에도 누가 어떤 지적을 하고 있는지 등 데이터를 다각도로 살펴보는 것만으로도 매우 흥미롭기 때문에, 저는 여기서 시간을 많이 보냈습니다 ㅎㅎ)
3. 규칙으로 증류하기
집계 결과를 Claude Code의 스킬에 읽혀서, 언어별 "리뷰 규칙" Markdown으로 변환합니다 (estie는 Rust 외에도 몇 가지 언어를 사용하고 있습니다). 규칙 파일은 대략 다음과 같은 형태로 만들었습니다.
## 예외 처리
### 지적 조건
외부 API 호출 시, 실패 시의 처리가 호출 측에 전달되지 않는 경우에는 지적한다.
...
이번에 조금 공을 들인 점은 각 항목에 "이 지적은 실적 ◯건"이라는 분석 결과를 반드시 덧붙인 것입니다. 숫자가 붙으면 AI가 생성한 규칙이라도 "정말로 우리 현장에서 일어나고 있는 일"이라고 신뢰할 수 있습니다. 중요한 것은 AI에게 그럴듯한 규칙을 만들게 하는 것이 아니라, 과거에 실제로 나왔던 지적과 그 강도를 남기는 것입니다. estie에서는 최종적으로 모든 언어 공통 규칙과 언어별 규칙을 합쳐 7개의 규칙 파일로 정리되었습니다.
4. 리뷰에 사용하기
리뷰를 할 때 변경된 파일의 언어에 대응하는 규칙을 읽히게 합니다. 방법은 다음 섹션에 적겠지만, 하나의 프롬프트로 전부 시키는 것보다 관점별로 담당을 나누는 것이 정밀도가 높았습니다.
리뷰어 설계: "한 명의 AI"보다 "역할을 나눈 여러 명의 AI"
처음에는 하나의 프롬프트로 전부 리뷰하게 했지만, 이것저것 욕심을 내다보니 정밀도가 떨어졌습니다. 그래서 인간의 리뷰 체제와 마찬가지로 관점별로 담당을 나누었습니다. estie에서는 Claude를 베이스로 하여 6개의 담당을 병렬로 구동하고 있습니다.

| 담당 | 모델 | 확인 내용 |
|---|---|---|
| 리포지토리 규칙 준수 | Sonnet | 변경 사항이 각 리포지토리의 규칙(CLAUDE.md)을 따르고 있는지 |
| ... |
각 담당에게는 PR의 diff와 관련 규칙, 필요하다면 git blame이나 과거의 PR 코멘트를 전달합니다. 돌려받는 형식은 통일했습니다.
{
"path": "app/models/example.rb",
"line": 42,
...
형식을 통일해 두면 나중에 중복을 제거하거나, 신뢰도에 따라 걸러내거나, Judge 역할에게 검증을 시키기가 쉬워집니다. 관점별로 모델을 다르게 사용하는 이유는 비용과 정밀도의 균형 때문입니다. 무거운 버그 탐지에는 똑똑한 모델을, 단순한 대조에는 가벼운 모델을 할당하고 있습니다.
각 담당의 지적에는 0~100의 신뢰도 점수를 부여하고, 분류별로 가중치를 적용하여(버그는 무겁게, 스타일은 가볍게) 일정 수준 미만은 버립니다. 마지막으로 "Judge" 역할을 하나 더 세워 행 번호나 변수명의 정확성, 수정안의 구체성, blocker가 과도하지 않은지, 중복이 없는지를 검증하게 한 뒤 남은 것들만 PR에 코멘트합니다. 즉, 넓게 수집하고 엄격하게 걸러내는 이단계 구조로 만들었습니다.
estie에서는 이 일련의 과정을 Claude Code의 사내 플러그인으로 만들어, 명령어 하나로 호출할 수 있도록 하고 있습니다. 하지만 플러그인화는 운영을 용이하게 하기 위한 방편일 뿐, 본질은 규약을 읽히고, 역할을 나누고, 스코어(Score)로 걸러낸 뒤, 마지막에 검증한다는 흐름에 있습니다.
estie제 리뷰어와 CodeRabbit을 비교해 보았다
만드는 과정에서 사내 검증도 진행해 보았습니다. 동일한 6개의 PR에 대해 estie제 리뷰어와 CodeRabbit을 모두 실행하여, 지적 사항을 대조해 본 것입니다. 샘플이 6개의 PR뿐이므로 제품 일반의 우열을 가리는 것은 아닙니다. 어디까지나 estie의 코드베이스와 리뷰 규약 관점에서 보았을 때 어떻게 다르게 보였는지에 대한 기록입니다.
먼저 지표의 의미를 말씀드리면, '실행 가능성'은 수정 코드 등을 포함한 지적의 비율, '커버리지 (Coverage)'는 지적이 있었던 파일의 비율, '오탐률 (False Positive Rate)'은 코드를 확인했을 때 타당하지 않았던 지적의 비율, 'must율'은 반드시 수정해야 한다고 판단된 지적의 비율입니다.
| 지표 | estie제 리뷰어 | CodeRabbit |
|---|---|---|
| 지적 건수 | 30건 | 10건 |
| ... | ... | ... |
우선 흥미로웠던 점은 양측의 지적 일치율이 14%밖에 되지 않았다는 것입니다. 같은 PR을 보더라도 지적 사항의 80% 이상이 겹치지 않았습니다. estie제는 넓고 깊게 설계나 diff 외부에 있는 영향 범위까지 살펴보기에 커버리지가 높고, 이번 6개의 PR에서는 오탐이 확인되지 않았습니다 (샘플이 작으므로 항상 적다고 단정할 수는 없습니다). 반면 "이 부분을 확인해 주세요" 수준에서 멈추는 지적이 많아, 수정 코드까지 파고드는 비율은 다소 낮습니다. CodeRabbit은 빠르고 구체적이며, diff 내부의 버그를 수정 코드와 함께 정확하게 지적합니다. 다만 diff 외부를 보는 능력은 떨어지며, 오탐도 조금 섞여 있습니다.
즉, 어느 쪽이 더 우월하다는 이야기가 아니라 상호 보완적이라는 것이 결론입니다. 만약 양쪽을 모두 사용할 수 있다면, 다음과 같은 순서가 적절했습니다.
- PR 생성
- CodeRabbit이 자동으로 리뷰
- 리뷰이 (리뷰를 받는 사람)가 대응
- 자체 제작 리뷰 실행 (CodeRabbit이 대응 완료한 지적은 제외)
- 인간은 설계 판단과 비즈니스 정합성에 집중
빠르고 구체적인 것을 먼저 처리하고, 넓고 깊은 것을 다음에 덮어씌운 뒤, 마지막으로 인간이 정말 인간만이 할 수 있는 판단에만 시간을 쓰는 분담 방식입니다.
솔직한 한계와 난관들
직접 만드려는 분들을 위해 잘 풀리지 않는 부분도 적어두겠습니다.
먼저, 이 방법이 효과를 보려면 리뷰의 내용이 뒷받침되어야 합니다. 리뷰가 형식적으로 흐르고 있다면, 아무리 데이터를 모아도 의미 있는 규약을 추출할 수 없습니다. estie의 경우, 프리픽스(Prefix)를 구분해서 사용하고, 제안하고, 토론하여 합의하는 방식을 7년간 지속해 온 축적이 토대가 되었습니다. 우선 자사의 이력이 "배울 가치가 있는가"를 먼저 살펴보는 것이 좋다고 생각합니다.
다음으로, 이번에 작성한 AI 리뷰어는 꽤 무겁습니다. 망라적으로 살펴보기 때문에 토큰 (Token)을 상당히 많이 사용합니다. 저 자신도 사용하면서 "망라적이지만 무겁다"고 느끼고 있어, 어느 타이밍에 실행할지는 선택하는 것이 좋아 보입니다. 애초에 제대로 개발하고 있는 멤버가 많다는 전제가 있기는 하지만, 실제 프로덕트에서 극적인 버그를 잡아냈다는 화려한 실적이 있는 것도 아닙니다. 이 점은 과장 없이 적어둡니다.
또한, 정밀도는 규약의 질에 따라 달라지기 때문에, 한 번 만들고 끝내는 것이 아니라 지속적으로 수정해 나간다는 전제하에 움직입니다. estie에서 이것을 만든 것이 3월 말이며, 지금은 실험을 거듭하며 정밀도와 설계 모두 estie에 더욱 최적화되도록 개선되고 있습니다.
예를 들어, 앞서 언급한 CodeRabbit과의 비교를 바탕으로 규약을 개선했습니다. blocker와 [want], [imo]에는 수정 코드를 필수화하고, blocker는 실제 버그와 파괴적 변경(Breaking Change)에 대해서만 엄격하게 적용하며 (설계 선호도는 [want]로 강등), CodeRabbit이 대응 완료한 지적은 제외하는 등의 변경을 수행했습니다. 이처럼 완전히 편해진 것은 아니며 손이 많이 가는 부분도 남아 있지만, 그 부분에 시간을 쏟아야 한다고 생각합니다.
마치며
범용 AI 리뷰는 어느 회사에서나 똑같은 일반론을 답변해 줍니다. 그것 나름대로 편리합니다.
하지만 우리만의 언어를 이해해 주는 리뷰어는, 자사가 오랜 기간 쌓아온 리뷰 이력을 규약으로 바꾸고 나서야 비로소 얻을 수 있었습니다. 지금까지라면 터무니없다고 느껴졌을 작업일수록, AI에게 맡겨볼 가치가 있다고 생각합니다.
수행할 작업은 데이터 처리 방식을 결정하고, GitHub API를 통해 PR(Pull Request)과 리뷰 코멘트를 수집하며, 이를 집계하여 경향성을 도출한 뒤, AI에게 읽혀서 규약(Convention) Markdown으로 증류(Distill)하고, 리뷰 시 해당 규약을 역할 분담에 따라 참조하게 하는 흐름입니다. 갑자기 전사적으로 도입하기보다는, 하나의 리포지토리와 수개월 분량의 데이터부터 작게 시작해 보는 것을 추천합니다. 자사에 리뷰 문화의 축적이 있다면, 상상 이상으로 큰 자산이 될 것이라고 생각합니다.
estie는 "산업의 진가를 더욱 개척한다."라는 목적(Purpose) 아래, 부동산이라는 모든 경제 활동이 이루어지는 "장(場)"을 대상으로 산업의 DX(Digital Transformation)에 힘쓰고 있습니다. 자사의 개발 문화를 AI로 어떻게 자산화할 것인가와 같은 주제로 깊이 있는 대화를 나누고 싶으신 분들은, 언제든 캐주얼하게 이야기 나누러 오세요.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기