AI 에이전트의 코드 탐색: 멀티 레포지토리 및 멀티 스택 프로젝트에서의 코드 내비게이션 엔지니어링
요약
실제 기업용 개발 환경에서 AI 에이전트가 직면하는 멀티 레포지토리 및 멀티 스택 코드 탐색의 어려움을 분석합니다. 레포지토리 발견, 교차 의존성 식별, 컨텍스트 구축이라는 세 가지 핵심 도전 과제를 제시합니다.
핵심 포인트
- 단일 레포지토리를 넘어선 멀티 레포지토리 구조의 복잡성 해결 필요
- 레포지토리 발견을 위한 체계적인 메타데이터 관리의 중요성
- 레포지토리 간 의존성 모델링을 통한 통합 수정 능력 확보
- 대규모 코드베이스를 위한 효율적인 컨텍스트 구축 전략
서문
대부분의 AI 코딩 어시스턴트 데모는 숨겨진 가정을 바탕으로 시작됩니다. 즉, 코드가 바로 그곳에 있으며, 에이전트(Agent)는 그저 코드를 읽고 수정하기만 하면 된다는 가정입니다.
하지만 실제 기업용 개발 환경에서는 이러한 가정이 성립하지 않는 경우가 많습니다.
한 자동차 소프트웨어 기업은 다음과 같은 구조를 유지할 수 있습니다. 각 Android 앱 모듈(설정, 에어컨(AC), 내비게이션 등)을 위한 수십 개의 독립적인 Git 레포지토리(Repository); repo 및 Manifest 파일로 관리되며 AOSP 스타일로 수백 개의 서브 레포지토리로 나뉜 Android 시스템 프레임워크; 자체 Manifest를 가진 QNX; 그리고 완전히 별개의 레포지토리에 있는 MCU 펌웨어(firmware).
AI 에이전트가 "Bluetooth 연결 끊김 버그를 수정해줘"와 같은 지시를 받았을 때, 에이전트의 첫 번째 질문은 "코드를 어떻게 수정할까"가 아니라 "코드가 어디에 있는가?"입니다. 이 질문의 난이도는 심각하게 저평가되어 있습니다.
세 가지 단계적 도전 과제
레벨 1: 레포지토리 발견 (Repo Discovery)
가장 명백한 어려움은 다음과 같습니다: 수십 개 또는 수백 개의 레포지토리가 있을 때, 에이전트는 어떤 레포지토리로 가야 하는지 어떻게 알 수 있을까요?
일부 팀은 각 레포지토리에 대해 자연어 설명을 작성하여 에이전트에게 해당 레포지토리가 무엇을 하는지 알려줍니다. 이는 합리적인 시작점이지만, 몇 가지 체계적인 한계가 있습니다:
- 자연어 설명은 정확하게 매칭하기 어렵습니다. 특히 작업 설명과 레포지토리 설명이 서로 다른 용어를 사용할 때 더욱 그렇습니다.
- 코드가 진화함에 따라 설명이 쉽게 오래된 정보(stale)가 되어 지속적인 유지보수 비용을 발생시킵니다.
- 구조화된 메타데이터(metadata)가 없으면 에이전트가 기술 스택(tech stack)이나 비즈니스 도메인(business domain)별로 필터링할 수 없습니다.
- 대규모 AOSP 스타일의 Manifest 레포지토리의 경우, "이 Manifest가 관리하는 것"과 "어떤 서브 레포지토리에 이 특정 기능이 포함되어 있는가" 사이에는 여전히 간극이 존재합니다.
레벨 2: 교차 레포지토리 의존성 식별 (Cross-Repo Dependency Identification)
실제 비즈니스 요구사항은 종종 여러 기술 스택에 걸쳐 여러 레포지토리에 걸쳐 있습니다. "에어컨(AC) 온도 설정" 기능은 다음과 같은 체인을 필요로 할 수 있습니다:
Android Settings App (application repo)
↕ IPC / AIDL
Android System Service (framework sub-repo)
...
만약 에이전트(Agent)가 애플리케이션 레포지토리(application repo)만 찾아내어 하위 계층의 인터페이스(interface) 또한 변경되어야 한다는 사실을 인지하지 못한 채 UI 로직만 수정한다면, 통합 테스트(integration testing)에서 실패하게 될 불완전한 수정안을 생성하게 됩니다.
이 문제는 단일 레포지토리(single-repo)에 대한 설명만으로는 해결할 수 없으며, 레포지토리 간의 의존성(dependencies)을 명시적으로 모델링해야 합니다.
Level 3: 레포지토리 페치(Repo Fetch) 및 컨텍스트 구축(Context Construction)
적절한 레포지토리를 찾은 후, 에이전트(Agent)는 실제로 "코드를 가져오는(get the code)" 작업이 필요합니다.
단일 애플리케이션 계층 레포지토리의 경우 git clone만으로 충분합니다. 하지만 AOSP 스타일의 코드베이스(codebases)의 경우, 프로세스는 다음과 같습니다:
- 매니페스트(Manifest) 레포지토리 페치(Fetch)
- 이 작업에 필요한 서브 레포지토리(sub-repositories)가 무엇인지 결정 (전체 동기화(full sync)는 시간, 저장 공간, 대역폭 측면에서 비용이 지나치게 많이 듭니다)
- 선별된 서브 레포지토리 목록을 사용하여
repo sync -c실행 - 서브 레포지토리 간의 코드 의존성(cross-sub-repo code dependencies) 이해
이는 단순한 git clone보다 에이전트(Agent)의 툴링(tooling)에 훨씬 더 많은 것을 요구합니다.
솔루션 방향 1: 구조화된 레포지토리 레지스트리(Structured Repo Registry)
현재의 자유 형식 텍스트(free-text) 설명을 각 레포지토리 항목이 YAML 객체인 구조화된 **레포지토리 레지스트리(Repo Registry)**로 업그레이드합니다:
repo_id: android-app-settings
display_name: Settings Application
tech_stack: android-app
...
구조화의 핵심 가치는 다음과 같습니다: 에이전트(Agent)가 방대한 양의 자연어(natural language)를 통해 퍼지 매칭(fuzzy-matching)을 수행하는 대신, tech_stack 및 business_domains를 기준으로 정밀하게 필터링할 수 있다는 점입니다. 또한 dependencies 필드는 레포지토리 간 연결(cross-repo linkage)을 위한 토대를 제공합니다.
크로스 스택 의존성 그래프(Cross-Stack Dependency Graph)
레포지토리 레지스트리(Repo Registry)를 기반으로, 레포지토리 간의 의존성 관계를 명시적으로 유지합니다. 에이전트(Agent)가 하나의 레포지토리를 찾아내면, 플랫폼은 자동으로 의존성 그래프(dependency graph)를 쿼리하여 변경이 필요할 수 있는 관련 레포지토리들을 제안할 수 있습니다.
의존성 관계는 두 가지 소스에서 옵니다:
- 수동 주석 (Manual annotation): 아키텍처를 이해하는 사람이 직접 표시 — 정확하지만 유지 관리 비용이 발생함
- 빌드 시스템 내보내기 (Build system export): AOSP 빌드 시스템은 어떤 모듈이 어떤 인터페이스에 의존하는지 알고 있으므로, 이론적으로 반자동 추출 (semi-automated extraction)이 가능함
표준화된 레포지토리 페치 프로토콜 (Standardized Repo Fetch Protocol)
"이 레포지토리를 어떻게 가져오는가"라는 문제를 자연어 수준에서 기계 실행 가능한 페치 명세 (fetch spec)로 격상시킵니다:
fetch_type: repo-manifest
manifest_repo: ssh://gerrit.example.com/platform/manifest
manifest_branch: main
...
에이전트 (Agent)는 플랫폼에서 제공하는 통합 페치 도구를 호출하며 repo_id를 전달합니다. 플랫폼은 페치 명세에 따라 실제 코드 페치를 실행하며, 에이전트에게는 하위의 git/repo 차이점을 숨깁니다.
솔루션 방향 2: 사전 채워진 워크스페이스 (Pre-Populated Workspace)
대안적인 접근 방식: 레포지토리 구조를 전혀 변경하지 않고, 에이전트가 직접 접근할 수 있는 공유 워크스페이스에 모든 레포지토리 코드를 미리 동기화(pre-sync)하는 것입니다. 에이전트가 시작될 때 아무것도 다운로드할 필요가 없으며, 로컬에서 직접 코드를 검색하고 수정할 수 있습니다.
이 접근 방식은 두 가지 문제를 해결합니다:
- 레포지토리 탐색 (repo discovery) 제거 — 모든 코드가 하나의 파일 시스템에 있어, 검색 도구가 모든 스택(stack)에 걸쳐 작동함
- 다운로드 대기 시간 제거 — 코드가 미리 채워져 있어 에이전트가 즉시 시작할 수 있음
하지만 토큰 소비 문제(token consumption problem)를 해결하지는 못합니다. 코드가 로컬에 있다고 해서 에이전트의 컨텍스트 윈도우 (context window)에 코드가 들어있는 것은 아닙니다. 에이전트는 여전히 관련 파일을 찾고 적은 양의 관련 코드 스니펫 (code snippets)을 선택적으로 로드하기 위해 코드 검색 도구가 필요합니다. 사전 채워진 접근 방식이나 멀티 레포지토리 접근 방식 모두 코드 검색 도구의 필요성은 동일합니다.
또 다른 직관에 반하는 문제는 검색 범위가 넓어질수록 노이즈(noise)도 많아진다는 점입니다. 멀티 레포지토리 접근 방식에서는 에이전트가 올바른 레포지토리로 범위를 좁힌 후에 검색을 수행하므로 후보군이 적습니다. 반면, 사전 채워진 접근 방식에서는 동일한 키워드가 전체 코드베이스에 걸쳐 수백 개의 파일에 걸릴 수 있습니다.
주요 엔지니어링 고려 사항 (Key Engineering Considerations)
각 Agent 인스턴스마다 수백 GB의 코드를 복사해서는 안 됩니다. 합리적인 아키텍처는 다음과 같습니다:
읽기 전용 공유 미러 (Read-only shared mirror, 전체 코드베이스)
↓ OverlayFS (Copy-on-Write 파일 시스템)
Agent 워크스페이스 (Agent workspace, 쓰기 작업의 차분(delta)만 저장하는 얇은 계층)
각 Agent 인스턴스는 코드를 읽기 위한 다운로드 비용이 전혀 들지 않으며, 쓰기 작업은 자체적인 얇은 계층(thin layer) 내에서 격리됩니다. 이 접근 방식은 Kubernetes 컨테이너 환경에서 성숙한 구현 경로를 가지고 있습니다.
**원본 리포지토리로 다시 제출(Submitting back to original repositories)**하려면 전용 설계가 필요합니다. Agent가 변경을 완료한 후, 플랫폼은 어떤 파일이 어떤 원본 리포지토리에 속하는지 식별하고, 변경 사항을 분할하여 각 리포지토리의 코드 리뷰 프로세스를 통해 제출해야 합니다.
접근 방식 비교 (Comparison of Approaches)
| 차원 (Dimension) | 멀티 레포지토리 + 구조화된 레지스트리 (Multi-Repo + Structured Registry) | 사전 채워진 워크스페이스 (Pre-Populated Workspace) |
|---|---|---|
| 리포지토리 탐색 (Repo Discovery) | 레지스트리를 통해 개선됨 | 완전히 제거됨 |
| ... |
핵심 결론: 두 방식 모두 우수한 코드 검색 및 내비게이션 도구에 대한 근본적인 필요성을 우회할 수는 없습니다.
솔루션 방향 3: 코드 지식 그래프 (Code Knowledge Graph)
리포지토리가 어떻게 구성되어 있든 상관없이, 코드 작업에서 Agent가 직면하는 근본적인 제약은 컨텍스트 윈도우 (Context window)가 대규모 코드베이스를 모두 담을 수 없다는 점입니다. 즉, 관련 코드 스니펫 (Code snippets)을 선택적으로 로드해야 합니다. 그 "선택" 자체만으로도 토큰 (Tokens)을 소비합니다.
코드 지식 그래프 접근 방식은 정적 분석 (Static analysis)을 사용하여 코드 구조적 관계의 데이터베이스를 선제적으로 구축하는 것입니다. 이를 통해 누가 누구를 호출하는지, 인터페이스가 어디에서 구현되는지, 모듈들이 서로 어떻게 의존하는지 등 많은 파일을 읽어야 추론할 수 있는 관계들을 직접 쿼리 가능한 구조화된 데이터로 변환합니다.
관리 가능한 비용을 통한 계층적 분석 (Layered Analysis with Manageable Costs)
분석 계층마다 비용이 매우 다릅니다:
| 분석 계층 (Analysis Layer) | 내용 (Content) | 도구 (Tools) | 비용 (Cost) |
|---|---|---|---|
| 심볼 인덱스 (Symbol index) | 함수/클래스/변수의 정의 위치 | tree-sitter, 매우 빠름 | 낮음 (Low) |
| ... |
수백 GB 규모의 코드에 대해 tree-sitter와 clangd를 사용하여 심볼 인덱싱 (Symbol indexing) + 호출 그래프 (Call graph) + 인터페이스 매핑 (Interface mapping)을 수행하면 분당 수백만 라인의 속도로 실행됩니다. 전체 분석에는 몇 시간이 걸릴 수 있지만, 이는 일회성 오프라인 비용입니다.
시맨틱 벡터 인덱싱 (Semantic vector indexing)의 경우, **선택적 커버리지 (Selective coverage)**를 사용하십시오. 공개 인터페이스 (Public interfaces), 헤더 파일 (Header files), 그리고 핵심 모듈 코드만 임베딩 (Embed)합니다. 구현 파일 (Implementation file)의 내부 로직은 필요할 때만 처리할 수 있습니다.
고가치 쿼리 시나리오 (High-Value Query Scenarios)
지식 그래프 (Knowledge graph)가 정확한 답변을 제공하고 방대한 양의 토큰 (Tokens)을 절약할 수 있는 시나리오입니다:
- "이 AIDL 인터페이스는 어떤 구현 클래스 (Implementation classes)를 가지고 있나요?" → 인터페이스 매핑 (Interface mapping)을 통해 직접 반환
- "어떤 모듈이 AudioFlinger::setStreamVolume을 호출하나요?" → 호출 그래프 (Call graph)를 통해 직접 반환
- "이 HAL 인터페이스가 수정되면 어떤 상위 모듈 (Upstream modules)이 영향을 받나요?" → 의존성 그래프 (Dependency graph) 역쿼리 (Reverse query)
- "이 함수는 어떤 파일의 몇 번째 라인에 정의되어 있나요?" → 심볼 인덱스 (Symbol index)를 통해 직접 반환
자동차 소프트웨어(전형적인 App → Framework → HAL → MCU 교차 계층 분석)의 경우, 지식 그래프는 특히 가치가 높습니다. AIDL/HIDL 인터페이스는 계층 간의 명시적인 계약 (Contracts)이며, 정적 분석 (Static analysis)을 통해 "인터페이스 정의 → 인터페이스 구현 → 인터페이스 호출자"로 이어지는 완전한 그래프를 정확하게 구축할 수 있습니다. 이는 에이전트 (Agents)가 계층 간 코드 수정 (Cross-layer code modifications)을 수행하는 데 정확히 필요한 요소입니다.
기술 스택 추천 (Technology Stack Recommendations)
| 기능 (Function) | 추천 도구 (Recommended Tool) | 근거 (Rationale) |
|---|---|---|
| C/C++ 심볼 및 호출 그래프 | clangd + bear (compilation database) | AOSP 시나리오에서 가장 성숙함 |
| ... |
해결되지 않은 문제들 (Unresolved Issues)
지속적인 메타데이터 유지보수 (Ongoing metadata maintenance): Repo Registry는 정적으로 유지되지만, 프로젝트가 진화함에 따라 레포지토리의 역할은 변화합니다. 이상적으로는 이 정보가 개발자 플랫폼 내에서 동적으로 유지되어야 하며, 에이전트(Agents)가 로컬 정적 파일을 유지하는 대신 MCP와 같은 프로토콜을 통해 쿼리(query)를 수행해야 합니다.
암묵적 지식의 외재화 (Externalizing tacit knowledge): 스택 간 의존성(특히 App 레이어에서 MCU 레이어까지의 전체 호출 체인)은 현재 주로 시니어 개발자들의 머릿속에 존재합니다. 이러한 암묵적 지식을 의존성 그래프(dependency graphs)로 구조화하여 인코딩하려면 각 기술 스택의 전문가적 입력이 필요하며, 이는 자동으로 해결될 수 있는 문제가 아닙니다.
멀티 레포지토리 작업에서의 에이전트 협업 (Multi-repo task Agent collaboration): 작업이 Android 애플리케이션, 시스템 프레임워크, 그리고 MCU 레포지토리에 걸쳐 있을 때, 이 세 가지 코드 변경을 단일 에이전트(single Agent)가 수행해야 할까요, 아니면 여러 전문화된 에이전트(multiple specialized Agents)가 수행한 후 결과를 통합해야 할까요? 이는 아직 명확한 답이 없는 에이전트 플랫폼(Agent Platform) 아키텍처 설계의 문제입니다.
요약 (Summary)
여러 레포지토리와 기술 스택을 가로지르는 코드 내비게이션은 AI 에이전트를 기업용 개발 환경에 도입할 때 가장 과소평가되는 엔지니어링 과제입니다. 해결책은 다음과 같이 세 가지 계층을 단계적으로 다룰 수 있습니다:
- 구조화된 레포지토리 레지스트리 (Structured Repo Registry): 자연어 설명을 기계가 처리 가능한 YAML 메타데이터로 업그레이드하고, 레포지토리 간 의존성을 명시적으로 구축합니다. 이는 가장 비용이 적게 드는 시작점입니다.
- 사전 채워진 워크스페이스 (Pre-populated workspace): 레포지토리 탐색 및 다운로드 대기 시간을 제거하며, 에이전트 작업 호출이 빈번한 시나리오에 적합합니다. 이를 위해서는 OverlayFS와 인프라 지원이 필요합니다.
- 코드 지식 그래프 (Code knowledge graph): 에이전트가 코드 관계에 접근하는 방식을 근본적으로 변화시켜, "추론을 위해 파일을 읽는 방식"을 "데이터베이스에 직접 쿼리하는 방식"으로 전환합니다.
어떤 방향을 선택하든 한 가지 사실은 변하지 않습니다: 에이전트가 관련 코드 세그먼트를 찾아내는 능력은 코드의 물리적 위치가 아니라, 검색 및 내비게이션 도구의 품질에 달려 있습니다.
PrimeSkills를 방문해 보세요 — 모든 콘텐츠가 실제 기업 워크플로우 (Enterprise Workflows)를 통해 검증된, 엄선된 AI 에이전트 및 기술 마켓플레이스입니다. 과장 없이, 실제로 작동하는 것만을 제공합니다.
더욱 실용적인 지식과 흥미로운 제품을 원하신다면, 저의 개인 홈페이지를 방문해 주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기