본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 05. 25. 01:12

코드 그래프 × AI 에이전트로 '리팩터링 자동화'를 구축하는 구현 패턴

요약

AI 에이전트가 코드베이스의 의존 관계를 파악할 수 있도록 코드 그래프를 활용한 리팩터링 자동화 구현 패턴을 소개합니다. AST 추출과 MCP를 통해 에이전트에게 코드 구조라는 '지도'를 제공하여 리팩터링 후보 추출부터 단계별 자동화 전략을 제안합니다.

핵심 포인트

  • 코드 그래프를 통해 에이전트의 코드베이스 이해도 향상
  • Tree-sitter와 MCP를 활용한 그래프 쿼리 구현
  • 중심성, 복잡도, 변경 빈도를 결합한 리팩터링 후보 선정
  • 단계별 자동화 설계를 통한 리스크 관리 전략

리팩터링을 스스로 하는 시대는 곧 끝날지도 모릅니다. 적어도 제 체감으로는, 2026년에 들어선 이후 몇 달 동안 AI 에이전트의 '코드베이스 이해'가 한 단계 깊어졌습니다.

이유는 간단합니다. AI 에이전트가 코드를 그래프 (Graph) 로 다루기 시작했기 때문입니다. grep과 임베딩 벡터 (Embedding Vector)만으로는 닿을 수 없었던 '변경 영향 범위'나 '의존 관계의 핵심'을 에이전트가 쿼리 (Query)를 통해 추출할 수 있게 되었습니다.

본 기사에서는 그 구현 패턴을 기술합니다. 코드를 그래프화하는 기초는 별도의 기사에 맡기고, 여기서는 'AI 에이전트 × 코드 그래프'의 조합으로 어떻게 리팩터링을 반자동화할지에 집중하겠습니다.

コードグラフとAIエージェントの連携全体像

왜 '코드 그래프 × AI'인가

저는 줄곧 리팩터링을 '감'으로 해왔습니다. "이 함수, 왠지 느낌이 안 좋아" 같은 것이죠. 그래서 몇 번은 정답을 맞혔고, 몇 번은 틀리기도 했습니다.

최근 Claude Code와 같은 에이전트에게 "리팩터링 후보를 내줘"라고 부탁하면 나름대로 답을 돌려줍니다. 하지만 근거가 빈약합니다. 에이전트는 눈앞의 파일만 읽을 뿐, 코드베이스 전체의 구조를 파악하지 못한 채 제안을 합니다.

여기서 효과를 발휘하는 것이 코드 그래프 (Code Graph) 입니다. Tree-sitter로 AST (추상 구문 트리)를 추출하고, 함수·클래스·모듈을 노드 (Node)로, 호출·상속·import를 에지 (Edge)로 하는 그래프를 만듭니다. 에이전트는 그 그래프를 MCP를 통해 쿼리하여, "어떤 함수가 중심에 있는가", "어디를 바꾸면 무엇이 망가지는가"를 데이터로 파악한 상태에서 움직일 수 있습니다.

저는 이것을 "에이전트에게 지도를 건네주는 것"이라고 부릅니다. 지도가 없는 탐험가는 감으로 길을 선택할 수밖에 없습니다. AI 에이전트도 마찬가지입니다.

자동화하고 싶은 플로우를 3단계로 나누기

리팩터링 자동화라고 한마디로 말해도, 자동화할 수 있는 범위에는 단계가 있습니다. 제가 지금 실행하고 있는 것은 이 3단계입니다.

단계내용자동화 수준
1. 후보 추출"고쳐야 할 함수"를 그래프에서 선택완전 자동
...

완전 자동화가 가능한 것은 1단계뿐입니다. 2단계는 제안의 질에 편차가 생기므로 리뷰가 필요합니다. 3단계를 완전 자동화하고 싶은 유혹은 강렬하지만, 저는 현재로서는 손을 대지 않고 있습니다. CI에서 모든 테스트를 통과시킨다 하더라도, 테스트가 망라하지 못한 영역에서 버그가 잠자고 있을 가능성을 AI에게 맡기는 것은 두렵기 때문입니다.

인간이 손을 떼도 되는 곳과, 손을 떼면 치명적인 곳을 나누는 것. 이것이 AI 자동화 설계의 핵심이라고 생각합니다.

단계 1: 그래프에서 후보를 추출하기

첫 번째 단계는 "어떤 함수부터 리팩터링할 것인가"를 결정하는 것입니다. 여기서 중심을 잃으면 AI는 하류 단계에서 길을 잃게 됩니다.

저는 점수를 세 가지 축으로 계산합니다.

  • 중심성 점수 (Centrality Score): 해당 함수를 호출하는 함수의 수 (입차수, In-degree)
  • 복잡도 점수 (Complexity Score): 순환 복잡도 (Cyclomatic Complexity)나 행 수
  • 변경 빈도 점수 (Change Frequency Score): git log에서 가져올 수 있는 지난 6개월간의 변경 횟수

중심성만 높은 함수는 "설계의 요체"이며, 변경 빈도까지 높으면 "불이 붙은 요체"가 됩니다. 두 가지 모두 높은 함수가 우선순위 리스트의 상위에 오르게 됩니다.

구현은 의외로 소박합니다. CodeGraphContext나 code-review-graph와 같은 도구로 만든 그래프에 git log 유래의 메타데이터를 추가하기만 하면 됩니다. Cypher를 사용한다면 다음과 같이 작성할 수 있습니다.

// 중심성 × 변경 빈도 스코어링
MATCH (f:Function)<-[:CALLS]-(caller:Function)
WITH f, COUNT(caller) AS in_degree
...

이 쿼리로 나오는 상위 20개가 AI에게 전달할 "리팩터링 후보 리스트"입니다.

제가 처음 자신의 리포지토리에서 이것을 돌렸을 때, 상위 3개 중 2개는 예상대로였습니다. 나머지 1개는 지난 반년 동안 한 번도 언급되지 않았던 수수한 유틸리티 함수였습니다. 10년 동안 쌓아온 감이 Cypher 쿼리 하나에 절반은 패배한 순간입니다. 분한 마음에 "아니 그래도 감이 절반은 맞았어"라고 스스로를 다독였습니다.

단계 2: AI 에이전트에게 변경안을 작성하게 하기

후보 리스트가 나오면, AI 에이전트에게 "이 함수의 리팩터링 안을 내줘"라고 부탁합니다. 여기서 코드 그래프가 힘을 발휘합니다.

에이전트에게 전달하는 프롬프트 (Prompt)는 대략 다음과 같은 형태입니다.

다음 함수의 리팩터링 안을 제시해 주세요.
【대상 함수】
service/user.py:update_user
...

주목해야 할 점은 「호출처: 14곳」이라는 정보를 에이전트에게 사전에 전달하고 있다는 점입니다. 이 정보가 있으면 에이전트는 "인수를 늘려도 되는지", "반환값(Return value)의 타입을 변경해도 되는지"를 판단할 수 있습니다.

지도가 없는 탐험가에게 "다리를 놓아달라"고 부탁해도 어디에 놓아야 할지 알 수 없습니다. 그래프에서 추출한 "다리를 건너는 사람의 수"를 전달해 두면, 에이전트는 무리한 변경을 제안하지 않게 됩니다.

여기서 사용하는 에이전트는 저의 경우 Claude Code입니다. MCP를 통해 코드 그래프(Code Graph) 도구를 연결하면, 에이전트 스스로 쿼리를 던져 문맥(Context)을 가져옵니다. GitNexus나 code-review-graph는 이 용도에 최적화되어 있으며, 22개 전후의 MCP 도구를 제공합니다.

ast-grep으로 「타입이 있는 치환」을 수행하기

AI 에이전트가 처음부터 다시 작성하면, 변경 사항이 너무 커서 리뷰가 불가능해지는 경우가 있습니다. 이를 방지하기 위해 저는 ast-grep을 병용하고 있습니다.

ast-grep은 Rust로 제작된 구조적 검색 및 치환 도구로, AST(Abstract Syntax Tree) 패턴을 사용하여 코드를 재작성할 수 있습니다. 2026년 5월 기준으로 0.42 계열이 출시되어 있으며, CLI와 MCP 서버 양쪽 모두에서 동작합니다.

예를 들어 "모든 print(...)logger.info(...)로 교체하기"를 AI에게 맡기지 않고 구조적인 규칙으로 처리합니다.

# rules/print-to-logger.yml
id: print-to-logger
language: python
...

이를 ast-grep scan -r rules/로 실행하면 코드베이스 전체에 대해 차분(Diff)을 생성해 줍니다. AI 에이전트는 "규칙을 작성하는" 역할을 맡고, 실제 치환은 ast-grep이라는 결정론적(Deterministic)인 도구에 맡깁니다. 이러한 분업이 효과적으로 돌아갑니다.

AI는 창의적이지만 불안정합니다. 결정론적인 도구는 융통성이 없지만 신뢰할 수 있습니다. 양자를 결합하면 불안정한 창의성을 신뢰할 수 있는 틀 안에 가둘 수 있습니다. 저는 이를 "AI에 레일을 깔아준다"라고 표현합니다.

단계 3: 적용과 검증은 파이프라인화하기

리팩터링 안이 리뷰를 통과하면, 적용과 검증은 CI/CD 파이프라인에 태웁니다.

저의 구성은 다음과 같습니다.

1. AI 에이전트가 브랜치를 생성
2. ast-grep 규칙 또는 직접 편집으로 변경 사항 적용
3. CodeLayers와 같은 도구로 영향 범위(Blast radius) 재계산
...

여기서 핵심은 영향을 받는 테스트만 실행하는 부분입니다. 코드 그래프가 있으면 "변경 파일 → 테스트 파일"의 홉(Hop)을 계산할 수 있습니다. 1만 개의 테스트를 전부 돌리지 않아도, 20개 정도의 관련 테스트만으로 충분한 경우가 많습니다.

저는 이전에 "일단 모든 테스트를 돌린다"는 운영 방식으로 CI에 30분이 소요되었습니다. 그래프 기반의 필터링을 도입했더니 평균 5분까지 단축되었습니다. 남은 25분은 커피를 내려 마시는 시간과 맞먹습니다. 저는 그 시간을 다른 리팩터링 안을 구상하는 데 사용하게 되었습니다. AI에게 일을 맡겼다고 생각했는데, 결국 제 일이 늘어난 셈입니다.

도구 선택은 「로컬 완결형 vs 클라우드형」으로 나누기

2026년 5월 기준으로, 코드 그래프 × AI 에이전트 조합에 사용할 수 있는 도구들이 늘어났습니다. 제가 사용해 본 것들을 간단히 정리합니다.

도구특징이런 경우에
GitNexusnpx 한 번으로 실행, 브라우저 내 그래프, Claude Code 통합우선 써보고 싶을 때
code-review-graphSQLite, 22개의 MCP 도구, 리뷰 특화PR마다 영향 범위 산출 시
CodeGraphContextNeo4j 선택 가능, 실시간 업데이트엔터프라이즈 운영
CodeLayersVS Code 확장, 홉별 컬러 표시에디터 내에서 완결하고 싶을 때
Graphify2패스(AST+LLM), 문서도 대상설계 의도까지 포함하고 싶을 때
ast-grep구조적 치환 CLI/MCP, 결정론적대량의 패턴 치환 시

선택 기준으로 가장 중요한 것은 "로컬에서 완결하고 싶은가, 아니면 클라우드에 맡겨도 되는가"라고 생각합니다. 보안성이 높은 코드를 다룬다면 AST 추출까지는 확실히 로컬에서 완결시켜야 합니다. GitNexus나 code-review-graph가 이 요구사항을 충족합니다.

Graphify와 같은 2-패스 아키텍처 (2-pass architecture)는 강력하지만, Pass 2에서 LLM에 보낼 내용의 범위를 신중하게 좁혀야 합니다. "시맨틱 추출 (Semantic extraction)에 사용하는 것은 주석과 README뿐이다"라고 정책을 정해두면 운영이 흔들리지 않습니다.

내가 빠졌던 3가지 함정

구현을 진행하면서 몇 가지 뼈아픈 경험을 했습니다. 같은 함정에 빠지는 사람이 줄어들기를 바라며 적어둡니다.

1. 동적 디스패치 (Dynamic dispatch)가 보이지 않음

Tree-sitter AST는 정적 분석 (Static analysis)이므로, Python의 getattr이나 JavaScript의 프록시 (Proxy)를 통한 호출은 추적할 수 없습니다. "호출처 0건"이라고 나와도, 실제로는 동적으로 호출되고 있을 가능성이 있습니다. 저는 한 번 이 문제로 인해 "불필요한 코드다"라고 판단하여 삭제했다가, 운영 환경에서 처참하게 망가뜨린 적이 있습니다. 동적 디스패치가 많은 코드베이스에서는 그래프 결과에 반드시 "최종 체크"를 위한 인간의 리뷰를 포함해야 합니다.

2. 모노레포 (monorepo)라면 그래프가 거대해짐

파일 수가 3만 개를 넘는 리포지토리에서, 최초 구축에 2시간이 걸렸습니다. 차분 업데이트 (Incremental update)를 지원하는 도구(CodeGraphContext의 감시 모드 등)를 사용하거나, 서브 디렉토리 단위로 분할해야 합니다. "처음부터 전부 다 하겠다"는 방식은 실패하기 쉽습니다.

3. AI 에이전트가 "그래프를 맹신"함

이것이 가장 까다로웠습니다. 그래프가 "이 함수는 사용되지 않음"이라고 반환하면, 에이전트는 아무런 망설임 없이 삭제 제안을 내놓습니다. 제가 "동적 디스패치로 사용되고 있을지도 모른다"라고 되물으면, "아, 그럴 가능성이 있겠네요"라며 순순히 인정합니다. 너무 순순해서 무서울 정도입니다.

에이전트에 대한 프롬프트 (Prompt)에 "그래프는 정적 분석의 결과이므로, 동적 호출은 포함되지 않을 가능성이 있다"라는 문장을 한 줄 넣어두어야 합니다. 이것을 넣지 않으면 에이전트는 수치를 절대적인 것으로 간주합니다.

"자동화"와 "자율화"를 섞지 말 것

마지막으로, 설계 사상에 대해 한 가지 적겠습니다.

AI 에이전트에게 맡길 때

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0