1 문제 정의
대규모 코드베이스(예: 20만 줄, 40개 리포지토리)를 분석하는 에이전트를 구축할 때, 다음과 같은 질문에 정확히 답할 수 있어야 한다:
“3번째 모듈의 메서드나 설정값을 바꾸면 97번째 모듈에 어떤 영향을 미칠까?”
이는 단순한 코드 검색이 아니라 의존성 그래프 탐색 문제다. 그런데 이 질문을 그냥 Copilot이나 Claude Code에 던지면 어떻게 될까?
2 Vanilla Agent의 한계: 왜 메타데이터가 필요한가
Copilot이나 Claude Code 같은 vanilla agent(별도의 코드 메타데이터 없이 기본 도구만 사용하는 agent)는 “지금 보고 있는 파일”에 대해서는 뛰어나다. 함수 설명, 코드 리뷰, 단일 파일 내 버그 탐색 등은 LLM의 코드 이해 능력만으로 충분하다.
그러나 “보지 않은 파일과의 관계”는 추측할 수밖에 없다. 20만 줄 40개 리포에서 agent가 모든 파일을 읽을 수는 없으므로, 질문의 복잡도가 올라갈수록 vanilla agent의 답변 신뢰도는 급격히 떨어진다.
| 질문 유형 | Vanilla Agent | 메타데이터를 갖춘 Agent | 성능 차이 |
|---|---|---|---|
| “이 함수 뭐 하는 거야?” | 파일 읽으면 답변 가능 | 동일 | 거의 없음 |
| “이 설정 바꾸면 어디 영향?” | 관련 파일을 찾아 읽어야 하며 운에 의존 | 온톨로지로 관련 파일 즉시 특정 | 중간 |
| “모듈 3 → 모듈 97 영향도?” | 구조적으로 불가능에 가까움 | 그래프 순회로 경로 추출 | 극명 |
| “40개 리포 간 순환 의존성 찾아줘” | 불가능 | 그래프 쿼리 한 방 | 불가 vs 가능 |
비유하면, 메타데이터 + 온톨로지는 agent에게 전체 지도를 주는 것이고, 없이 질문하는 것은 지도 없이 길을 찾으라고 하는 것이다. 동네 안(단일 파일이나 모듈)에서는 지도 없이도 찾아갈 수 있지만, 도시 전체(40개 리포 간 관계)를 물으면 지도 유무에 따른 차이가 극명해진다.
그렇다면 코드 메타데이터와 온톨로지는 필수다. 문제는 이 메타데이터를 어떤 아키텍처 위에서 소비하는가이다.
3 두 가지 아키텍처
이 글에서 비교하는 두 아키텍처는 다음을 공통 기반으로 둔다:
- 코드 메타데이터: AST 파싱으로 생성된 함수/클래스/모듈 정보
- 온톨로지: AST 기반으로 자동 생성된 개념 관계, 타입 계층, 의존성 그래프
- Skill-based Prompts: 온톨로지 그래프가 방대하므로, 질문에 따라 선택적 경로를 지정하는 스킬 설계
차이는 메타데이터를 소비하는 방식에 있다.
3.1 Architecture A: Copilot Agent + Skill
사용자 질문
↓
Skill Prompt (경로 지정)
↓
Copilot/Claude Code Agent
├── grep/read로 실제 파일 탐색
├── 온톨로지 메타데이터 참조 (텍스트로 주입)
└── LLM이 의존성을 추론하여 답변 생성
Agent가 스킬 프롬프트의 안내에 따라 파일을 직접 읽고, 코드를 이해하여 의존성을 추론한다. 온톨로지 정보는 프롬프트 컨텍스트에 텍스트로 주입된다.
3.2 Architecture B: Agentic RAG + GraphRAG + Skill
사용자 질문
↓
Skill Prompt (경로 지정)
↓
Agentic RAG Orchestrator
├── GraphRAG: 그래프 DB에서 의존성 경로 쿼리 (deterministic)
├── Vector RAG: 관련 코드 청크 검색 (semantic)
├── 반복 검색: 누락된 컨텍스트 자동 보완
└── LLM이 검색 결과를 자연어로 설명
의존성 추적은 그래프 쿼리로 수행하고, LLM은 결과를 설명하는 역할만 한다. Agentic RAG는 검색 결과가 불충분할 때 반복적으로 추가 검색을 수행한다.
4 환각(Hallucination) 비교
두 아키텍처의 환각 특성은 근본적으로 다르다. Skill 프롬프트 유무에 따라 나눠서 살펴본다.
4.1 Skill Prompt 없이 비교한 경우
Skill 프롬프트 없이 순수하게 비교하면, Architecture A는 파일을 읽으며 멀티홉 추론을 해야 하므로 환각 위험이 매우 높다.
| 항목 | Architecture A (Copilot) | Architecture B (GraphRAG) |
|---|---|---|
| 의존성 발견 방식 | LLM이 파일을 읽으며 추론 | 코드 메타데이터(AST/call graph)에서 조회 |
| 멀티홉 추적 | 파일 A→B→C→…→N 읽으며 추론, 홉마다 환각 누적 | 그래프 순회로 deterministic 추적, LLM은 결과 설명만 |
| 컨텍스트 한계 | 97개 모듈을 동시에 볼 수 없어 누락 또는 날조 발생 | 관련 노드만 정확히 retrieve |
| 환각 유형 | 존재하지 않는 의존성을 만들어냄 (false positive) | 그래프 품질에 의존, 그래프가 정확하면 환각 없음 |
| 실패 모드 | “A가 B를 호출한다” (실제로는 호출하지 않음) | 검색 누락(recall miss) 가능하나 날조는 아님 |
4.2 Skill Prompt를 적용한 경우
Skill 프롬프트가 “어디를 볼지”를 지정해주면 Architecture A의 환각이 상당히 줄어든다. Agent가 무작정 추론하는 것이 아니라 가이드된 탐색을 수행하기 때문이다.
| 항목 | Architecture A + Skill | Architecture B + Skill |
|---|---|---|
| 의존성 탐색 | 스킬이 방향 지정 → grep/read로 실제 코드 확인 → 추론 | 스킬이 방향 지정 → 그래프 쿼리로 경로 조회 → 설명 |
| 홉당 정확도 | 높음 (실제 파일을 읽으므로) | 매우 높음 (deterministic) |
| 멀티홉 누적 오류 | 홉이 길어지면 경로 누락 위험 (날조보다 누락이 주 실패 모드) | 없음 (그래프에 경로가 있으면 반드시 찾음) |
| 40개 리포 교차 추적 | 스킬이 리포 간 이동을 안내해도 모든 간접 경로를 발견하리라 보장 없음 | 그래프에 리포 간 edge가 있으면 완전 탐색 보장 |
| 환각 유형 변화 | “날조”는 크게 줄어듦, “누락”(false negative)이 주 문제 | 그래프 품질에만 의존 |
Skill 프롬프트 덕분에 Architecture A의 “날조” 환각은 크게 줄어든다. 그러나 “누락” 문제는 구조적으로 해결되지 않는다. 모듈 3에서 모듈 97까지의 경로가 3개 있는데 agent가 2개만 찾는 상황이 발생할 수 있다.
4.3 환각률 추정
| 질문 복잡도 | Architecture A (Skill 없음) | Architecture A (Skill 있음) | Architecture B |
|---|---|---|---|
| 단순 (1~2홉) | 15~25% | 5~10% | 5% 이하 |
| 중간 (3~5홉) | 30~50% | 15~25% | 5% 이하 |
| 복잡 (N홉, 리포 간) | 50%+ | 30~40% (주로 누락) | 5% 이하 |
앞서 vanilla agent와의 비교에서 보았듯이, 메타데이터 자체가 성능 차이의 가장 큰 원인이다. 그 위에 Skill 프롬프트가 추가되면 Architecture A의 환각이 줄어들지만, Architecture B와의 구조적 격차는 여전히 남는다.
5 온톨로지 활용 효율
AST 기반으로 온톨로지(개념 관계, 타입 계층, 의존성 그래프)를 자동 생성한다면, 핵심 질문은 “이 구조화된 데이터를 어떤 방식으로 소비하는가”이다.
| 항목 | Architecture A | Architecture B |
|---|---|---|
| 온톨로지 소비 방식 | 프롬프트에 텍스트로 주입 → LLM이 해석 | 그래프 쿼리로 직접 탐색 |
| 한계 | 온톨로지가 커지면 컨텍스트 초과, LLM이 관계를 누락/날조 | 없음, 그래프 크기와 무관하게 정확 |
| 온톨로지 가치 실현도 | 30~40% (구조 정보를 비구조적으로 소비) | 90%+ (구조 정보를 구조적으로 소비) |
AST 파싱 → 코드 메타데이터 + 온톨로지(개념 관계, 타입 계층, 의존성)
↓
Architecture A: 텍스트로 변환 → 프롬프트에 주입 → LLM이 해석
(구조화된 데이터를 비구조화된 방식으로 처리)
↓
Architecture B: 그래프 DB에 저장 → 쿼리로 탐색 → LLM이 결과 설명
(구조화된 데이터를 구조적으로 처리)
AST로 온톨로지까지 만들어놓고 Copilot Agent에 텍스트로 던지는 것은 구조화된 데이터의 낭비다. 20만 줄 40개 리포에서 생성되는 온톨로지는 그 자체로 방대하며, 이를 프롬프트 컨텍스트에 텍스트로 주입하는 것은 컨텍스트 윈도우의 한계에 부딪힌다.
6 규모별 성능 특성
코드베이스 규모가 커질수록 두 아키텍처의 성능 격차가 벌어진다.
정확도
| ━━━━━━━━━━━━━━━━━━━━━━━━ Architecture B (규모 무관)
|
| \
| \ Architecture A + Skill
| \
| \ <- 리포 수, 코드량 증가할수록 누락률 증가
| \
| \
+-------------------------------------> 코드베이스 규모
1리포 10리포 40리포
1만줄 5만줄 20만줄
Architecture B(GraphRAG)는 그래프의 완전성에만 의존하므로 코드베이스 규모와 무관하게 정확도가 일정하다. Architecture A는 규모가 커질수록 agent가 모든 경로를 탐색하지 못해 누락률이 증가한다. 이는 앞서 vanilla agent에서 관찰한 “지도 없이 도시 탐색” 문제의 연장선이다. Skill 프롬프트가 방향을 잡아주더라도, 도시 자체가 커지면 스킬이 안내하지 못하는 골목이 늘어난다.
7 구현 난이도
온톨로지를 AST로 자동 생성하는 전제 하에, 공통 구성 요소를 제외한 추가 구현 비용을 비교한다.
| 구성 요소 | Architecture A | Architecture B |
|---|---|---|
| AST 파싱 + 온톨로지 생성 | 공통 | 공통 |
| Skill Prompt 설계 | 공통 | 공통 |
| 온톨로지 저장 | JSON/파일 (스킬이 읽어서 프롬프트에 주입) | 그래프 DB (neo4j 등) |
| 쿼리 인터페이스 | 불필요 (agent가 직접 탐색) | Cypher 쿼리 or LLM→쿼리 변환 레이어 |
| Retriever 파이프라인 | 불필요 | 청킹 + 임베딩 + 벡터 DB + reranker |
| Agent 오케스트레이션 | 불필요 (Claude Code 내장) | LangGraph 등으로 직접 구축 |
| 추가 구현 비용 (상대) | 1x | 3~6x |
Architecture A는 스킬 프롬프트만 잘 설계하면 추가 인프라가 거의 필요 없다. Architecture B는 그래프 DB, 벡터 DB, retriever 파이프라인, 오케스트레이션 레이어를 구축해야 한다. 초기 비용만 보면 Architecture A가 압도적으로 유리하다.
그러나 이 초기 비용 우위는 유지보수 단계에서 역전된다.
8 유지보수 비용: 가장 결정적인 요인
40개 리포지토리가 산발적으로 독립 업데이트되는 환경에서 유지보수 비용 구조가 극적으로 달라진다. 이것이 아키텍처 선택에서 가장 결정적인 요인이다.
8.1 Architecture A의 유지보수 문제
Skill 프롬프트가 코드의 현재 상태를 하드코딩하고 있으면, 코드가 바뀔 때마다 스킬도 따라 바꿔야 한다.
| 변경 이벤트 | 필요한 작업 |
|---|---|
| 리포에 새 모듈 추가 | 스킬 프롬프트에 경로/모듈 정보 수동 반영 |
| 메서드명/시그니처 변경 | 스킬이 참조하는 메타데이터 수동 갱신 |
| 리포 간 새 의존성 생성 | 스킬의 “어디를 볼지” 로직 수동 수정 |
| 카테고리/폴더 구조 변경 | 스킬 라우팅 로직 수동 수정 |
40개 리포가 독립적으로 업데이트되면, 스킬 유지보수 자체가 본업이 되어버린다. 리포 A에서 메서드 시그니처가 바뀌었는데 스킬을 갱신하지 않으면, agent는 옛날 정보를 기반으로 잘못된 경로를 안내한다. 이는 메타데이터를 갖추고도 vanilla agent와 같은 실패 모드에 빠지는 것이다.
8.2 Architecture B의 유지보수
| 변경 이벤트 | 필요한 작업 |
|---|---|
| 리포 업데이트 | CI/CD에서 AST 재파싱 → 그래프 자동 갱신 |
| 새 의존성 생성 | 그래프에 자동 반영 |
| 구조 변경 | 그래프에 자동 반영 |
| 스킬 프롬프트 | 구조 독립적 설계 가능 (“영향도 분석해줘”만으로 충분) |
Architecture B는 CI/CD 파이프라인에 AST→그래프 갱신을 한 번 연결하면, 코드 변경이 자동으로 그래프에 반영된다. 스킬 프롬프트는 코드 구조에 의존하지 않으므로 코드 변경 시 수정이 불필요하다.
8.3 유지보수 비용 추이
유지보수
누적 비용
| / Architecture A (리포 수 x 업데이트 빈도에 비례)
| /
| /
| / ____________ Architecture B (CI/CD 파이프라인 구축 후 일정)
| / /
| / /
| // <- 손익분기점 (수 개월)
| /
+-------------------------------------> 시간
초기 3개월 6개월 1년
40개 리포가 주 단위로 업데이트되는 환경에서, 손익분기점은 수 개월 이내에 도달한다. 초기 구축 비용에서 Architecture A가 유리했던 것이 장기적으로 완전히 역전되는 구간이다.
9 질문 유형별 적합도
지금까지의 분석을 질문 유형별로 정리하면, 각 아키텍처가 커버하는 영역이 명확히 갈린다.
| 질문 유형 | 빈도 (추정) | Vanilla Agent | Architecture A | Architecture B |
|---|---|---|---|---|
| “이 함수 뭐 하는 거야?” | 높음 | 충분 | 충분 | 과잉 |
| “이 설정 바꾸면 어디 영향?” | 중간 | 운에 의존 | 대부분 커버, 간헐적 누락 | 완벽 |
| “모듈 3 → 모듈 97 전체 영향도” | 낮음 | 불가능에 가까움 | 누락 위험 높음 | 완벽 |
| “40개 리포 간 순환 의존성 찾아줘” | 낮음 | 불가능 | 구조적으로 불가능 | 가능 |
| “이 인터페이스 변경 시 영향받는 모든 서비스 목록” | 중간 | 불가능 | 누락 가능 | 완전 열거 보장 |
Vanilla Agent → Architecture A로의 전환은 메타데이터 도입이 만드는 차이이고, Architecture A → Architecture B로의 전환은 메타데이터 소비 방식이 만드는 차이다. 두 단계 모두 질문 복잡도가 높아질수록 격차가 벌어진다.
10 종합 가성비 비교
10.1 단기 (0~3개월)
| 항목 | Architecture A | Architecture B |
|---|---|---|
| 초기 구축 비용 | 낮음 | 높음 |
| 단순 질문 답변 품질 | 높음 | 높음 |
| 복잡 질문 답변 품질 | 중간 (누락 있음) | 높음 |
| 유지보수 부담 | 낮음 (아직 변경 누적 적음) | 낮음 (CI/CD 자동) |
| 단기 가성비 | 높음 | 중간 |
10.2 장기 (6개월~1년)
| 항목 | Architecture A | Architecture B |
|---|---|---|
| 누적 유지보수 비용 | 높음 (40리포 변경 추적 + 스킬 수정) | 낮음 (CI/CD 자동) |
| 기술 부채 | 누적 (스킬과 코드 간 불일치 증가) | 낮음 (자동 동기화) |
| 답변 신뢰도 | 하락 추세 (스킬 갱신 지연 시) | 일정 |
| 장기 가성비 | 낮음 | 높음 |
11 의사결정 프레임워크
11.1 Architecture A를 선택할 조건
- 코드베이스 규모가 작다 (5개 이하 리포, 5만 줄 이하)
- 리포 업데이트 빈도가 낮다 (월 1~2회)
- 복잡한 의존성 추적 질문이 드물다
- 빠른 프로토타이핑이 목적이다
- 인프라 구축 리소스가 부족하다
11.2 Architecture B를 선택할 조건
- 코드베이스 규모가 크다 (10개+ 리포, 10만 줄 이상)
- 리포가 독립적으로 수시 업데이트된다
- 리포 간 교차 의존성 분석이 핵심 요구사항이다
- 장기 운영을 계획한다
- “누락 없는 완전한 영향도 분석”이 중요하다
11.3 하이브리드 접근 (단계적 전환)
두 아키텍처는 상호 배타적이지 않다. 단계적으로 전환할 수 있다:
- Phase 1: Architecture A로 빠르게 시작, 단순 질문 커버. 동시에 “모듈 간 영향도” 수준의 질문이 실제로 얼마나 발생하는지 검증한다.
- Phase 2: AST→그래프 파이프라인 구축, CI/CD 연결. 이 시점부터 스킬 프롬프트의 수동 유지보수 부담이 줄어든다.
- Phase 3: GraphRAG retriever 연결, 복잡한 영향도 분석 커버. Architecture A에서 누락되던 리포 간 교차 분석이 가능해진다.
- Phase 4: Skill 프롬프트를 구조 독립적으로 리팩토링, Architecture A 의존성 제거.
12 결론
20만 줄, 40개 리포가 수시로 업데이트되는 환경에서의 codebase analyzer agent 아키텍처 선택은 세 가지 층위로 정리된다.
첫째, 메타데이터 없이 vanilla agent를 사용하는 것은 단일 파일 수준의 질문에서만 유효하다. 리포 간 관계나 멀티홉 의존성 분석에서는 구조적으로 한계가 있으며, 코드 메타데이터와 온톨로지는 선택이 아니라 필수다.
둘째, 메타데이터를 갖추더라도 소비 방식에 따라 성능이 갈린다. Architecture A(Copilot Agent + Skill)는 구조화된 데이터를 비구조적으로 소비하여 온톨로지 투자 대비 가치를 30~40%만 실현한다. Architecture B(Agentic RAG + GraphRAG)는 구조화된 데이터를 구조적으로 소비하여 90% 이상의 가치를 실현한다.
셋째, 40개 리포의 산발적 업데이트라는 운영 현실이 최종 판단을 결정한다. Architecture A는 초기 비용이 낮지만, 리포 변경에 따른 스킬 유지보수가 누적되어 수 개월 내에 비용이 역전된다. Architecture B는 초기 구축 비용이 높지만, CI/CD 기반 자동 갱신으로 장기 유지보수 비용이 일정하다. 복잡한 의존성 추적이 핵심 목적이라면, Architecture B가 유일하게 신뢰 가능한 선택이다.