본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2026. 2. 1. · 7 Views
Evaluator-Optimizer 패턴으로 AI 에이전트 품질 높이기
AI 에이전트가 스스로 결과물을 평가하고 개선하는 Evaluator-Optimizer 패턴을 학습합니다. 자동 코드 리뷰 시스템 구축까지 실무 예제와 함께 단계별로 알아봅니다.
목차
1. Evaluator-Optimizer 개념
김개발 씨는 AI 에이전트를 만들어 코드를 자동 생성하는 프로젝트를 진행하고 있습니다. 그런데 AI가 만든 코드가 때로는 훌륭하고, 때로는 엉망이었습니다.
"어떻게 하면 AI가 일관되게 좋은 결과물을 만들게 할 수 있을까요?"
Evaluator-Optimizer 패턴은 AI가 생성한 결과물을 평가자(Evaluator)가 검토하고, 최적화기(Optimizer)가 피드백을 반영하여 개선하는 반복 구조입니다. 마치 원고를 쓰고 편집자에게 검토받아 수정하는 작가처럼, AI도 자신의 결과물을 검토받고 더 나은 버전을 만들어냅니다.
이 패턴을 적용하면 AI 에이전트의 출력 품질을 일관되게 높일 수 있습니다.
다음 코드를 살펴봅시다.
class EvaluatorOptimizer:
def __init__(self, generator, evaluator, max_iterations=3):
self.generator = generator # 결과물을 생성하는 AI
self.evaluator = evaluator # 결과물을 평가하는 AI
self.max_iterations = max_iterations
def run(self, task: str) -> dict:
result = self.generator.generate(task)
for i in range(self.max_iterations):
# 평가자가 결과물을 검토합니다
evaluation = self.evaluator.evaluate(result, task)
if evaluation["score"] >= 0.9: # 품질 기준 충족
return {"result": result, "iterations": i + 1}
# 피드백을 반영하여 결과물을 개선합니다
result = self.generator.improve(result, evaluation["feedback"])
return {"result": result, "iterations": self.max_iterations}
김개발 씨는 입사 2년 차 개발자입니다. 최근 회사에서 AI를 활용한 코드 생성 도구를 만들라는 과제를 받았습니다.
ChatGPT API를 연동해서 간단한 프로토타입을 만들었는데, 결과물의 품질이 들쭉날쭉했습니다. 어느 날은 완벽한 코드가 나오고, 어느 날은 버그투성이 코드가 나왔습니다.
김개발 씨는 고민에 빠졌습니다. "프롬프트를 아무리 다듬어도 한계가 있는 것 같아요." 선배 개발자 박시니어 씨가 다가와 물었습니다.
"혹시 Evaluator-Optimizer 패턴이라고 들어봤어요? AI 에이전트 설계에서 자주 쓰이는 방법이에요." 그렇다면 Evaluator-Optimizer 패턴이란 정확히 무엇일까요?
쉽게 비유하자면, 이 패턴은 마치 소설가와 편집자의 관계와 같습니다. 소설가가 원고를 쓰면, 편집자가 읽고 피드백을 줍니다.
"이 부분은 전개가 너무 빨라요. 독자가 따라가기 어려울 것 같아요." 소설가는 피드백을 반영해 원고를 수정합니다.
이 과정을 몇 번 반복하면 처음보다 훨씬 좋은 작품이 완성됩니다. AI 에이전트도 마찬가지입니다.
Generator가 결과물을 만들고, Evaluator가 품질을 검토하여 피드백을 제공합니다. Generator는 이 피드백을 반영해 더 나은 결과물을 만들어냅니다.
이 순환이 바로 Evaluator-Optimizer 패턴의 핵심입니다. 이 패턴이 없던 시절에는 어떻게 했을까요?
개발자들은 프롬프트 엔지니어링에만 의존했습니다. "좋은 코드를 작성해주세요"라는 지시를 아무리 정교하게 다듬어도, AI는 한 번에 완벽한 결과를 내놓기 어려웠습니다.
사람도 첫 번째 초안이 완벽하지 않은 것처럼, AI도 마찬가지입니다. 위의 코드를 살펴보겠습니다.
먼저 EvaluatorOptimizer 클래스는 생성자, 평가자, 최대 반복 횟수를 인자로 받습니다. run 메서드에서는 먼저 generator가 초기 결과물을 만듭니다.
그 다음 for 루프에서 evaluator가 결과물을 평가하고, 점수가 0.9 이상이면 성공으로 판단하여 반환합니다. 기준에 미달하면 피드백을 반영해 개선을 시도합니다.
실제 현업에서는 이 패턴을 다양하게 활용합니다. 코드 생성, 문서 작성, 번역, 데이터 분석 등 품질이 중요한 모든 AI 작업에 적용할 수 있습니다.
특히 자동 코드 리뷰 시스템에서 이 패턴은 거의 필수적으로 사용됩니다. 하지만 주의할 점도 있습니다.
반복 횟수가 너무 많으면 비용과 시간이 급격히 증가합니다. 또한 평가자의 기준이 모호하면 개선이 제대로 이루어지지 않습니다.
따라서 명확한 평가 기준과 적절한 반복 횟수 설정이 중요합니다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.
"그렇군요! AI 하나로만 해결하려고 했는데, 역할을 나누면 훨씬 체계적으로 품질을 관리할 수 있겠네요."
실전 팁
💡 - Generator와 Evaluator는 서로 다른 프롬프트나 모델을 사용하면 더 객관적인 평가가 가능합니다
- 최대 반복 횟수는 3~5회가 적당하며, 비용 대비 효과를 고려해 설정하세요
2. 품질 평가 메트릭
김개발 씨가 Evaluator-Optimizer 패턴을 적용하려고 보니, 한 가지 고민이 생겼습니다. "평가자가 '좋다' '나쁘다'만 말하면, 어떻게 개선해야 할지 모르겠는데요?" 박시니어 씨가 답했습니다.
"그래서 품질 평가 메트릭이 필요한 거예요."
품질 평가 메트릭은 결과물의 품질을 정량적으로 측정하는 기준입니다. 마치 학교 시험에서 채점 기준표가 있듯이, AI 평가자도 명확한 기준이 있어야 일관된 평가가 가능합니다.
정확성, 완성도, 가독성 등 여러 차원에서 점수를 매기면 어떤 부분을 개선해야 할지 명확해집니다.
다음 코드를 살펴봅시다.
class QualityMetrics:
def __init__(self):
self.weights = {
"correctness": 0.4, # 정확성 - 가장 중요
"completeness": 0.25, # 완성도
"readability": 0.2, # 가독성
"efficiency": 0.15 # 효율성
}
def evaluate(self, code: str, requirements: str) -> dict:
scores = {
"correctness": self._check_correctness(code, requirements),
"completeness": self._check_completeness(code, requirements),
"readability": self._check_readability(code),
"efficiency": self._check_efficiency(code)
}
# 가중 평균으로 총점 계산
total = sum(scores[k] * self.weights[k] for k in scores)
return {
"total_score": round(total, 2),
"details": scores,
"feedback": self._generate_feedback(scores)
}
김개발 씨는 평가자를 만들면서 고민에 빠졌습니다. "좋은 코드"의 기준이 뭘까요?
사람마다 의견이 다릅니다. 어떤 사람은 짧은 코드가 좋다고 하고, 어떤 사람은 읽기 쉬운 코드가 좋다고 합니다.
박시니어 씨가 화이트보드에 그림을 그리며 설명했습니다. "코드 품질은 여러 차원에서 봐야 해요.
마치 음식 맛을 평가할 때 맛, 온도, 플레이팅, 가격 대비 만족도 등 여러 기준을 고려하는 것처럼요." 품질 평가 메트릭은 이런 다차원적 평가를 가능하게 합니다. 코드의 경우 보통 네 가지 핵심 메트릭을 사용합니다.
첫 번째는 **정확성(Correctness)**입니다. 코드가 요구사항대로 동작하는지 확인합니다.
아무리 아름다운 코드라도 버그가 있으면 소용없습니다. 그래서 가중치를 가장 높게 설정합니다.
두 번째는 **완성도(Completeness)**입니다. 요구된 모든 기능이 구현되었는지 확인합니다.
절반만 구현된 코드는 반쪽짜리입니다. 세 번째는 **가독성(Readability)**입니다.
다른 개발자가 코드를 이해하기 쉬운지 평가합니다. 변수명이 명확한지, 주석이 적절한지, 구조가 깔끔한지 등을 봅니다.
네 번째는 **효율성(Efficiency)**입니다. 코드가 성능적으로 효율적인지 평가합니다.
불필요한 루프나 비효율적인 알고리즘이 있는지 확인합니다. 위의 코드를 보면, QualityMetrics 클래스는 각 메트릭에 가중치를 부여합니다.
정확성이 0.4로 가장 높고, 효율성이 0.15로 가장 낮습니다. 이 가중치는 프로젝트 특성에 따라 조정할 수 있습니다.
실시간 시스템이라면 효율성 가중치를 높이고, 유지보수가 중요한 시스템이라면 가독성 가중치를 높이면 됩니다. evaluate 메서드는 각 메트릭별 점수를 계산하고, 가중 평균으로 총점을 구합니다.
그리고 낮은 점수를 받은 영역에 대해 구체적인 피드백을 생성합니다. 실무에서 이 메트릭을 어떻게 측정할까요?
정확성은 테스트 케이스 통과율로 측정할 수 있습니다. 완성도는 요구사항 체크리스트 대비 구현율로 측정합니다.
가독성과 효율성은 정적 분석 도구나 LLM 기반 평가를 활용합니다. 중요한 점은 메트릭을 명시적이고 측정 가능하게 정의해야 한다는 것입니다.
"읽기 좋은 코드"라는 모호한 기준 대신, "함수 길이 20줄 이하", "변수명 3글자 이상" 같은 구체적인 기준을 세워야 합니다. 김개발 씨는 메모를 하며 말했습니다.
"채점 기준표가 명확해야 공정한 시험이 되는 것처럼, AI 평가자도 명확한 메트릭이 있어야 하는군요."
실전 팁
💡 - 메트릭 가중치는 프로젝트 특성에 맞게 조정하되, 정확성은 항상 가장 높게 유지하세요
- 메트릭별 점수뿐 아니라 구체적인 피드백 메시지를 함께 생성해야 개선에 도움이 됩니다
3. 피드백 루프 구현
메트릭을 정의했으니 이제 실제로 피드백을 주고받는 루프를 구현할 차례입니다. 김개발 씨가 물었습니다.
"점수만 알려주면 AI가 알아서 개선하나요?" 박시니어 씨가 고개를 저었습니다. "아니요, 구체적인 피드백과 그걸 반영하는 개선 로직이 필요해요."
피드백 루프는 평가 결과를 생성자에게 전달하고, 생성자가 이를 반영하여 개선된 결과물을 만드는 순환 구조입니다. 마치 선생님이 학생의 과제에 빨간 펜으로 코멘트를 달아주고, 학생이 그 코멘트를 보고 수정하는 과정과 같습니다.
피드백이 구체적일수록 개선 효과가 좋습니다.
다음 코드를 살펴봅시다.
class FeedbackLoop:
def __init__(self, llm_client):
self.llm = llm_client
def generate_feedback(self, code: str, metrics: dict) -> str:
weak_areas = [k for k, v in metrics["details"].items() if v < 0.7]
prompt = f"""
코드를 분석하고 개선점을 제시해주세요.
현재 코드:
{code}
낮은 점수 영역: {weak_areas}
상세 점수: {metrics["details"]}
각 문제 영역에 대해 구체적인 개선 방안을 제시해주세요.
"""
return self.llm.generate(prompt)
def apply_feedback(self, code: str, feedback: str) -> str:
prompt = f"""
피드백을 반영하여 코드를 개선해주세요.
원본 코드:
{code}
피드백:
{feedback}
개선된 코드만 출력해주세요.
"""
return self.llm.generate(prompt)
김개발 씨는 단순히 점수만 전달하는 시스템을 먼저 만들었습니다. "정확성 0.6점입니다"라고만 알려주니, AI가 무엇을 고쳐야 할지 몰라 엉뚱한 부분을 수정했습니다.
박시니어 씨가 웃으며 말했습니다. "그건 마치 시험지에 점수만 적어주고, 어디가 틀렸는지 표시 안 해주는 것과 같아요.
학생이 어떻게 공부해야 할지 모르잖아요." 피드백 루프의 핵심은 구체성입니다. 단순히 "가독성이 낮습니다"가 아니라, "함수명 'calc'가 무슨 기능인지 불명확합니다.
'calculate_total_price'처럼 명확하게 바꿔주세요"라고 알려줘야 합니다. 위의 코드에서 generate_feedback 메서드를 살펴보겠습니다.
먼저 점수가 0.7 미만인 영역을 찾습니다. 이 영역들이 개선이 필요한 부분입니다.
그 다음 LLM에게 해당 영역에 대한 구체적인 개선 방안을 요청합니다. apply_feedback 메서드는 원본 코드와 피드백을 함께 전달하여 개선된 코드를 생성합니다.
여기서 중요한 점은 피드백을 그대로 전달한다는 것입니다. LLM이 피드백 내용을 이해하고 반영할 수 있도록 명확하게 전달해야 합니다.
피드백 루프를 설계할 때 고려해야 할 사항이 있습니다. 첫째, 피드백의 우선순위입니다.
모든 문제를 한 번에 고치라고 하면 AI가 혼란스러워합니다. 가장 심각한 문제 2~3개에 집중하는 것이 효과적입니다.
둘째, 피드백의 형식입니다. "문제 - 원인 - 해결책" 구조로 피드백을 정리하면 AI가 이해하기 쉽습니다.
예를 들어 "문제: 무한 루프 발생 가능. 원인: 종료 조건 누락.
해결책: while 루프에 탈출 조건 추가"처럼 작성합니다. 셋째, 컨텍스트 유지입니다.
이전 반복에서 어떤 피드백을 받았고 어떻게 수정했는지 기록을 유지해야 합니다. 그래야 같은 실수를 반복하지 않습니다.
실무에서 흔히 발생하는 문제 중 하나는 피드백 충돌입니다. "코드를 더 짧게 만들어주세요"와 "가독성을 높여주세요"가 동시에 나오면 AI가 어떻게 해야 할지 모릅니다.
이럴 때는 명확한 우선순위를 제시해야 합니다. 김개발 씨가 물었습니다.
"피드백을 너무 자세하게 주면 그냥 정답을 알려주는 거 아닌가요?" 박시니어 씨가 답했습니다. "좋은 질문이에요.
핵심은 방향을 알려주되, 구체적인 구현은 AI가 스스로 하게 하는 거예요."
실전 팁
💡 - 피드백은 "문제 - 원인 - 해결 방향" 구조로 작성하면 AI가 이해하기 쉽습니다
- 한 번에 너무 많은 피드백을 주지 말고, 우선순위 높은 2~3개에 집중하세요
4. 반복 개선 전략
피드백 루프가 구현되었지만, 김개발 씨는 새로운 고민에 빠졌습니다. "매번 같은 방식으로 개선하면 한계가 있지 않나요?" 박시니어 씨가 고개를 끄덕였습니다.
"맞아요, 그래서 반복 개선 전략이 필요해요. 매 반복마다 다른 관점에서 접근하는 거죠."
반복 개선 전략은 여러 차례의 개선 반복에서 각기 다른 관점이나 방법을 적용하는 접근법입니다. 마치 옷을 수선할 때 처음에는 크기를 맞추고, 다음에는 모양을 다듬고, 마지막에는 마감 처리를 하는 것처럼, 단계별로 다른 목표에 집중하면 더 효과적입니다.
다음 코드를 살펴봅시다.
class IterativeImprover:
def __init__(self, llm_client):
self.llm = llm_client
self.strategies = [
{"focus": "correctness", "prompt": "버그와 논리 오류를 수정해주세요"},
{"focus": "structure", "prompt": "코드 구조와 설계를 개선해주세요"},
{"focus": "polish", "prompt": "가독성과 성능을 최적화해주세요"}
]
def improve(self, code: str, iteration: int, metrics: dict) -> str:
# 반복 횟수에 따라 다른 전략 적용
strategy = self.strategies[min(iteration, len(self.strategies) - 1)]
prompt = f"""
현재 코드:
{code}
평가 결과: {metrics}
이번 개선 목표: {strategy["focus"]}
지시사항: {strategy["prompt"]}
위 목표에 집중하여 코드를 개선해주세요.
"""
return self.llm.generate(prompt)
def should_continue(self, metrics: dict, prev_metrics: dict) -> bool:
# 개선이 멈췄는지 확인
improvement = metrics["total_score"] - prev_metrics["total_score"]
return improvement > 0.05 # 5% 이상 개선되어야 계속
김개발 씨가 처음 만든 시스템은 매번 "코드를 개선해주세요"라는 동일한 지시를 반복했습니다. 첫 번째 반복에서는 효과가 있었지만, 두 번째, 세 번째 반복에서는 거의 변화가 없었습니다.
박시니어 씨가 설명했습니다. "같은 말을 계속 반복하면 효과가 떨어져요.
사람도 그렇잖아요. '열심히 해'라고 열 번 말하는 것보다, '이번엔 이 부분에 집중해봐'라고 구체적으로 말하는 게 효과적이에요." 반복 개선 전략의 핵심 아이디어는 단계별 집중입니다.
위의 코드에서 strategies 배열을 보면 세 단계로 나뉘어 있습니다. 첫 번째 단계는 **정확성(correctness)**입니다.
코드가 일단 제대로 동작해야 합니다. 버그를 잡고, 논리 오류를 수정하는 데 집중합니다.
집을 지을 때 기초 공사부터 하는 것과 같습니다. 두 번째 단계는 **구조(structure)**입니다.
기능이 동작하면 이제 코드 설계를 개선합니다. 중복을 제거하고, 함수를 분리하고, 더 나은 패턴을 적용합니다.
집의 골조를 세우는 단계입니다. 세 번째 단계는 **마감(polish)**입니다.
구조가 잡히면 세부적인 품질을 높입니다. 변수명을 다듬고, 주석을 추가하고, 성능을 최적화합니다.
인테리어와 마감재를 선택하는 단계입니다. improve 메서드를 보면, 반복 횟수에 따라 다른 전략을 선택합니다.
첫 번째 반복에서는 정확성에 집중하고, 두 번째에서는 구조에, 세 번째에서는 마감에 집중합니다. 또한 should_continue 메서드가 있습니다.
이전 반복 대비 5% 이상 개선되지 않으면 더 이상 반복해도 효과가 없다고 판단합니다. 이것이 바로 수렴 감지입니다.
무한히 반복하는 것을 방지합니다. 실무에서는 프로젝트 특성에 따라 전략 순서를 조정할 수 있습니다.
예를 들어 프로토타입 개발에서는 정확성만 확보하고 끝낼 수 있습니다. 프로덕션 코드라면 마감 단계까지 철저히 진행해야 합니다.
주의할 점은 전략 간 충돌입니다. 구조 개선 단계에서 대규모 리팩토링을 하면, 이전에 수정한 버그가 다시 발생할 수 있습니다.
따라서 각 단계에서 이전 단계의 성과를 유지하도록 명시해야 합니다. 김개발 씨가 말했습니다.
"마치 여러 명의 전문가가 순서대로 검토하는 것 같네요. 버그 헌터, 아키텍트, 코드 리뷰어가 차례로 보는 거죠."
실전 팁
💡 - 반복 횟수가 늘어나면 점점 더 세부적인 개선에 집중하도록 전략을 설계하세요
- 각 전략에서 이전 단계의 성과를 유지하라는 지시를 포함하면 회귀 문제를 줄일 수 있습니다
5. 수렴 조건 설정
김개발 씨가 시스템을 돌려보니 예상치 못한 문제가 생겼습니다. 어떤 경우에는 10번 넘게 반복해도 끝나지 않고, 어떤 경우에는 충분히 좋아지기 전에 멈춰버렸습니다.
"언제 멈춰야 할지 어떻게 알 수 있죠?" 박시니어 씨가 말했습니다. "수렴 조건을 제대로 설정해야 해요."
수렴 조건은 반복 개선을 언제 멈출지 결정하는 기준입니다. 마치 요리할 때 "충분히 익었다"를 판단하는 기준이 필요하듯, AI 개선 루프도 멈출 시점을 정확히 알아야 합니다.
목표 품질 달성, 개선률 정체, 최대 반복 횟수 초과 등 여러 조건을 조합하여 사용합니다.
다음 코드를 살펴봅시다.
class ConvergenceChecker:
def __init__(self, config: dict):
self.target_score = config.get("target_score", 0.9)
self.min_improvement = config.get("min_improvement", 0.02)
self.max_iterations = config.get("max_iterations", 5)
self.patience = config.get("patience", 2) # 연속 정체 허용 횟수
self.history = []
def should_stop(self, current_score: float, iteration: int) -> tuple:
self.history.append(current_score)
# 조건 1: 목표 점수 달성
if current_score >= self.target_score:
return True, "목표 품질 달성"
# 조건 2: 최대 반복 횟수 초과
if iteration >= self.max_iterations:
return True, "최대 반복 횟수 도달"
# 조건 3: 개선 정체 (연속 patience회 이상)
if len(self.history) >= self.patience + 1:
recent = self.history[-self.patience - 1:]
improvements = [recent[i+1] - recent[i] for i in range(len(recent)-1)]
if all(imp < self.min_improvement for imp in improvements):
return True, "개선 정체"
return False, "계속 진행"
수렴 조건을 설정하지 않으면 두 가지 문제가 발생합니다. 첫 번째는 조기 종료 문제입니다.
아직 개선 여지가 있는데 멈춰버리면 최적의 결과를 얻지 못합니다. 마치 케이크를 반만 구워서 꺼내는 것과 같습니다.
두 번째는 과도한 반복 문제입니다. 더 이상 개선이 안 되는데 계속 반복하면 시간과 비용만 낭비됩니다.
API 호출 비용이 눈덩이처럼 불어나죠. 위의 코드에서 ConvergenceChecker 클래스는 세 가지 수렴 조건을 검사합니다.
첫 번째 조건은 목표 점수 달성입니다. 점수가 0.9 이상이면 충분히 좋은 품질이라고 판단합니다.
이것이 가장 이상적인 종료 조건입니다. 두 번째 조건은 최대 반복 횟수 초과입니다.
아무리 개선이 필요해도 무한히 반복할 수는 없습니다. 보통 3~7회 사이로 설정합니다.
이는 비용과 시간의 상한선 역할을 합니다. 세 번째 조건은 개선 정체입니다.
여기서 patience 개념이 등장합니다. 한 번 개선이 안 됐다고 바로 멈추지 않고, 연속으로 patience회 이상 정체되면 멈춥니다.
일시적인 정체와 진짜 수렴을 구분하기 위함입니다. min_improvement 값도 중요합니다.
0.85에서 0.86으로 올랐다면 개선이라고 볼 수 있을까요? 2% 미만의 변화는 노이즈일 수 있습니다.
따라서 의미 있는 개선의 최소 기준을 설정합니다. 실무에서 이 값들을 어떻게 정할까요?
target_score는 비즈니스 요구사항에 따라 결정합니다. 프로덕션 코드라면 0.9 이상, 프로토타입이라면 0.7도 충분할 수 있습니다.
max_iterations는 비용과 시간 제약에 따라 결정합니다. API 호출당 비용을 계산하고, 예산 내에서 가능한 최대 반복 횟수를 설정합니다.
patience는 보통 2~3으로 설정합니다. 너무 낮으면 일시적 정체에도 멈추고, 너무 높으면 리소스가 낭비됩니다.
김개발 씨가 물었습니다. "수렴 조건이 여러 개면 어떤 게 우선인가요?" 박시니어 씨가 답했습니다.
"목표 달성이 최우선이에요. 그 다음이 정체 감지, 마지막이 최대 반복이에요.
최대 반복은 안전장치 역할이죠."
실전 팁
💡 - patience 값은 2~3이 적당하며, API 비용이 부담되면 낮추세요
- 개선 정체 감지 시 점수뿐 아니라 피드백 내용의 변화도 함께 고려하면 더 정확합니다
6. 실전: 자동 코드 리뷰 시스템
모든 개념을 배운 김개발 씨가 드디어 실전 프로젝트에 도전합니다. 목표는 Pull Request가 올라오면 자동으로 코드를 리뷰하고, 문제가 있으면 개선안을 제시하는 시스템입니다.
"이제 모든 퍼즐 조각을 맞춰볼 시간이에요."
자동 코드 리뷰 시스템은 Evaluator-Optimizer 패턴의 대표적인 실전 적용 사례입니다. PR이 올라오면 코드를 분석하고, 품질 메트릭으로 평가하고, 문제점에 대한 개선안을 자동으로 코멘트로 남깁니다.
개발 팀의 코드 품질을 일관되게 유지하고, 리뷰어의 부담을 줄여줍니다.
다음 코드를 살펴봅시다.
class AutoCodeReviewer:
def __init__(self, llm_client, github_client):
self.metrics = QualityMetrics()
self.improver = IterativeImprover(llm_client)
self.convergence = ConvergenceChecker({
"target_score": 0.85,
"max_iterations": 3,
"patience": 2
})
self.github = github_client
async def review_pr(self, pr_number: int) -> dict:
files = await self.github.get_changed_files(pr_number)
reviews = []
for file in files:
code = file["content"]
evaluation = self.metrics.evaluate(code, file["context"])
if evaluation["total_score"] < 0.85:
# 개선안 생성
improved = self.improver.improve(code, 0, evaluation)
reviews.append({
"file": file["path"],
"score": evaluation["total_score"],
"issues": evaluation["feedback"],
"suggestion": improved
})
# GitHub에 코멘트 작성
await self.github.post_review(pr_number, reviews)
return {"reviewed_files": len(files), "issues_found": len(reviews)}
김개발 씨의 회사에서는 매일 수십 개의 PR이 올라옵니다. 시니어 개발자들이 모든 PR을 꼼꼼히 리뷰하기에는 시간이 부족했습니다.
사소한 실수들이 자주 놓치곤 했습니다. 박시니어 씨가 제안했습니다.
"자동 코드 리뷰 시스템을 만들어볼까요? 기본적인 품질 검사는 AI가 하고, 사람은 설계와 비즈니스 로직에 집중하면 돼요." 위의 AutoCodeReviewer 클래스는 지금까지 배운 모든 개념을 조합합니다.
먼저 QualityMetrics로 코드 품질을 평가합니다. 정확성, 완성도, 가독성, 효율성 점수를 계산합니다.
다음으로 IterativeImprover로 개선안을 생성합니다. 점수가 낮은 파일에 대해 구체적인 수정 제안을 만듭니다.
ConvergenceChecker는 이 시스템에서 조금 다르게 사용됩니다. 실시간 리뷰에서는 반복을 최소화해야 하므로, 한 번의 평가와 개선안 제시로 끝냅니다.
하지만 점수 임계값(0.85)은 여전히 사용하여, 기준 이상인 코드는 리뷰를 건너뜁니다. review_pr 메서드의 흐름을 따라가 봅시다.
먼저 GitHub API로 PR의 변경된 파일들을 가져옵니다. 각 파일에 대해 품질 평가를 수행합니다.
점수가 0.85 미만이면 개선안을 생성하고 리뷰 목록에 추가합니다. 마지막으로 GitHub에 리뷰 코멘트를 작성합니다.
실무에서 이 시스템을 운영할 때 고려할 점들이 있습니다. 첫째, 컨텍스트 제공입니다.
단순히 코드만 보면 올바른 평가가 어렵습니다. 해당 파일의 목적, 프로젝트 코딩 컨벤션, 관련 파일들의 정보를 함께 제공해야 합니다.
둘째, 오탐 관리입니다. AI가 잘못된 지적을 할 수 있습니다.
개발자가 "무시" 처리할 수 있는 기능을 만들고, 오탐 데이터를 수집하여 시스템을 개선합니다. 셋째, 점진적 도입입니다.
처음부터 모든 PR에 적용하지 않고, 특정 디렉토리나 파일 타입부터 시작합니다. 팀원들의 피드백을 받아가며 점차 확대합니다.
김개발 씨가 시스템을 배포한 후 한 달이 지났습니다. 팀의 코드 리뷰 시간이 30% 줄었고, 놓치던 사소한 실수들이 크게 감소했습니다.
무엇보다 시니어 개발자들이 더 중요한 설계 논의에 집중할 수 있게 되었습니다. 박시니어 씨가 말했습니다.
"AI가 사람을 대체하는 게 아니에요. 사람이 더 가치 있는 일에 집중할 수 있게 도와주는 거죠." 김개발 씨는 Evaluator-Optimizer 패턴을 통해 AI 에이전트 설계의 핵심을 배웠습니다.
생성, 평가, 피드백, 개선의 순환. 이 단순하지만 강력한 패턴은 다양한 AI 애플리케이션에 적용할 수 있습니다.
실전 팁
💡 - 실제 서비스에서는 평가 기준을 팀의 코딩 컨벤션과 맞춰 커스터마이징하세요
- AI 리뷰 결과에 대한 개발자 피드백을 수집하여 지속적으로 품질을 개선하세요
- 민감한 코드나 보안 관련 파일은 AI 리뷰 대상에서 제외하는 것이 좋습니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
vLLM 통합 완벽 가이드
대규모 언어 모델 추론을 획기적으로 가속화하는 vLLM의 설치부터 실전 서비스 구축까지 다룹니다. PagedAttention과 연속 배칭 기술로 GPU 메모리를 효율적으로 활용하는 방법을 배웁니다.
Web UI Demo 구축 완벽 가이드
Gradio를 활용하여 머신러닝 모델과 AI 서비스를 위한 웹 인터페이스를 구축하는 방법을 다룹니다. 코드 몇 줄만으로 전문적인 데모 페이지를 만들고 배포하는 과정을 초급자도 쉽게 따라할 수 있도록 설명합니다.
Sandboxing & Execution Control 완벽 가이드
AI 에이전트가 코드를 실행할 때 반드시 필요한 보안 기술인 샌드박싱과 실행 제어에 대해 알아봅니다. 격리된 환경에서 안전하게 코드를 실행하고, 악성 동작을 탐지하는 방법을 단계별로 설명합니다.
Voice Design then Clone 워크플로우 완벽 가이드
AI 음성 합성에서 일관된 캐릭터 음성을 만드는 Voice Design then Clone 워크플로우를 설명합니다. 참조 음성 생성부터 재사용 가능한 캐릭터 구축까지 실무 활용법을 다룹니다.
Tool Use 완벽 가이드 - Shell, Browser, DB 실전 활용
AI 에이전트가 외부 도구를 활용하여 셸 명령어 실행, 브라우저 자동화, 데이터베이스 접근 등을 수행하는 방법을 배웁니다. 실무에서 바로 적용할 수 있는 패턴과 베스트 프랙티스를 담았습니다.