여러분이 직접 할 필요 없도록 코드베이스를 읽는 AI 에이전트를 만들었습니다
요약
GitHub 저장소를 분석하여 아키텍처 요약과 의존성 그래프를 제공하는 AI 에이전트 'CodeNarrator' 개발 과정을 다룹니다. 에이전트가 코드베이스를 탐색할 때 발생하는 탐색 편향 문제와 패키지 루트 인식 오류를 해결하며 성능을 개선한 사례를 소개합니다.
핵심 포인트
- Qwen2.5-Coder를 활용한 에이전트 루프 구현
- 도구(tools) 기반의 자율적 코드 탐색 방식 채택
- 탐색 깊이 편향 문제를 해결하기 위한 점수 산정 시스템 개선
- 의존성 그래프 시각화를 위한 패키지 루트 인식 로직 수정
모든 개발자가 한 번쯤은 느껴본 경험입니다. 새로운 프로젝트에 합류하면, 누군가 GitHub 저장소(repo)를 가리키며 "그냥 코드 좀 살펴보세요"라고 말합니다. 두 시간 뒤에도 여러분은 어떤 파일이 어떤 파일과 통신하는지, 실제 로직은 어디에 있는지, 그리고 왜 "manager"라고 불리는 것이 네 개나 되는지 파악하려고 파일을 하나씩 읽고 있을 뿐입니다.
이런 상황에 지쳤습니다. 그래서 이 문제를 해결할 무언가를 만들었습니다.
아이디어는 간단했습니다. 실행은 그렇지 않았지만 말이죠.
GitHub URL을 입력하면, 에이전트가 저장소를 클론(clone)하고, 아키텍처(architecture)를 파악하며, 모든 요소가 어떻게 맞물려 돌아가는지에 대한 자연어 요약과 함께 대화형 의존성 그래프(dependency graph)를 제공합니다.
단순한 아이디어입니다. 하지만 — 어떻게 하면 시니어 엔지니어처럼 코드베이스를 이해하도록 기계에게 실제로 가르칠 수 있을까요?
규칙을 작성하는 것이 아닙니다. 도구(tools)를 주고 스스로 탐색하게 만드는 것입니다.
에이전트
CodeNarrator의 핵심은 에이전트 루프(agentic loop)입니다. Ollama를 통해 실행되는 로컬 호스팅 LLM(Large Language Model)인 Qwen2.5-Coder 7B에게 다섯 가지 도구가 주어집니다:
read_file — 소스 파일 열기
follow_import — 현재 파일이 임포트(import)하는 파일로 이동하기
search_for_pattern — 저장소 전체에서 패턴 검색(grep)
mark_architecture_insight — 발견한 통찰 기록하기
stop_analysis — 분석 완료 시 종료하기
모델은 무엇을 읽을지, 무엇을 따라갈지, 그리고 언제 충분히 확인했는지를 스스로 결정합니다. 하드코딩된 순회(traversal) 로직은 없습니다. 어떤 파일이 중요한지에 대한 수동으로 작성된 규칙도 없습니다. 에이전트가 스스로 알아냅니다.
적어도, 이론상으로는 그랬습니다.
문제 1: 에이전트가 게을렀습니다
모델을 그냥 내버려 두면, main.py나 App.tsx를 찾은 뒤 하나의 임포트 체인 (import chain)을 끝까지 따라가고는 작업이 끝났다고 판단했습니다. 44개의 파일이 있는 저장소 (repo)에서 단 10개의 파일만 탐색하고는 승리를 선언한 것입니다.
의존성 그래프 (dependency graph)는 마치 졸라맨처럼 보였습니다.
해결책은 명확하지 않았습니다. 후보 파일들의 순위를 매기는 점수 산정 시스템 (scoring system)이 깊이 (depth)에 편향되어 있었습니다. 현재 임포트 체인에 있는 파일들이 탐색되지 않은 디렉토리의 파일들보다 더 높은 점수를 받았습니다. 에이전트는 넓게 탐색하기보다 깊게 파고드는 것에 대해 보상을 받고 있었던 것입니다.
저는 점수 산정 방식을 다시 구축했습니다. 이제 방문하지 않은 디렉토리에 보너스를 부여합니다. 에이전트가 아직 건드리지 않은 폴더의 파일들을 드러낼 수 있도록 유도 로직 (nudge logic)을 다시 작성했습니다. 시스템 프롬프트 (system prompt)에는 "같은 디렉토리에서 2~3개의 파일을 확인한 후에는 반드시 새로운 곳으로 가라"라고 명시적으로 지시했습니다.
그래프가 실제 아키텍처 (architecture)처럼 보이기 시작했습니다.
문제 2: Python 저장소에는 엣지 (edge)가 하나도 없었습니다
FastAPI 프로젝트에 CodeNarrator를 실행했더니 아름다운 그래프가 나왔습니다. 아무것도 없는 그래프 말입니다. 모든 노드 (node)가 연결되지 않은 채 떠 있었습니다. 내부 엣지가 0개였습니다.
버그는 _detect_python_package_roots 함수에 있었습니다. 모든 패키지가 backend/ 또는 src/ 래퍼 (wrapper) 안에 들어 있는 저장소의 경우, 이 함수가 패키지 루트 (package root)로 backend 대신 .을 반환하고 있었습니다. 그래서 임포트 추출기 (import extractor)가 import db.database를 해석하려고 할 때 잘못된 위치를 찾게 되었습니다. 모든 내부 임포트가 조용히 외부 임포트로 취급되었습니다.
세 번의 함수 호출 깊숙이 묻혀 있던 단 하나의 잘못된 가정이, 수많은 실제 Python 프로젝트에 대해 전체 그래프를 무용지물로 만들고 있었습니다.
해결했습니다. 다음 실행에서는 엣지가 0개에서 35개 이상으로 늘어났습니다.
문제 3: TypeScript 컴포넌트가 보이지 않았습니다
파일 스캐너 (file scanner)의 확장자 맵 (extension map)에 .tsx가 없었습니다. 모든 TypeScript 프로젝트의 모든 React 컴포넌트가 조용히 건너뛰어지고 있었습니다. 스캔은 되었지만 탐색되지는 않았고, 그래프에서는 회색 유령 노드로만 나타났습니다.
단 한 줄이 빠져 있었을 뿐인데, 수백 개의 파일이 보이지 않았습니다.
2계층 설계 (Two-layer design)
제가 가장 자랑스럽게 생각하는 것은 단일 수정 사항이 아닙니다. 바로 아키텍처 (Architecture)입니다.
CodeNarrator는 완전히 독립적인 두 개의 계층을 가지고 있습니다. 파일 스캐닝 (File scanning), 임포트 추출 (Import extraction), 의존성 그래프 계산 (Dependency graph computation)을 수행하는 **결정론적 계층 (Deterministic layer)**은 LLM 없이 순수 Python으로 실행됩니다. 이 계층은 항상 결과물을 만들어냅니다. 그 위에 위치한 **에이전트 계층 (Agentic layer)**은 우선순위 지정, 아키텍처 추론, 자연어 요약과 같은 지능을 더합니다.
만약 LLM이 타임아웃(Time out)되거나, 충돌(Crash)하거나, 쓰레기 값(Garbage)을 생성하더라도 보고서는 여전히 렌더링됩니다. 결정론적 계층이 이미 그래프를 구축해 놓았기 때문입니다. AI는 강화 요소이지
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기