ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 코드 위키의 마지막 퍼즐, 모듈 문서 — AI 에이전트가 함수를 이해하는 방법
    IT 2026. 4. 26. 22:00
    코드 위키의 마지막 퍼즐, 모듈 문서 — AI 에이전트가 함수를 이해하는 방법

    코드 위키 시리즈를 마무리하며

    이 시리즈에서 지금까지 다룬 문서들이 있다:

    • architecture.md — 레이어 구분, HLD, 데이터 모델, 외부 의존성, 설정 관리
    • data-pipeline.md — 파이프라인 흐름도, 단계별 입출력, 캐시 전략
    • ADR — 설계 결정의 맥락과 트레이드오프

    이 문서들이 프로젝트의 을 보여준다면, 이번에 다룰 모듈 문서나무를 보여준다. 개별 모듈이 무엇을 하고, 어떤 함수가 핵심이며, 어떤 패턴으로 외부 자원을 사용하는지를 정리하는 문서다.

    모듈 문서가 필요한 이유

    "코드를 읽으면 되지, 왜 따로 문서를 쓰나?"라는 반론이 있을 수 있다. 사실 대부분의 모듈은 코드와 docstring만으로 충분하다. 모듈 문서가 필요한 건 다음 조건에 해당하는 모듈이다:

    • 파이프라인의 진입점 — 전체 흐름의 시작이 되는 모듈
    • 핵심 로직이 복잡한 모듈 — 알고리즘, 규칙 기반 분기, 다단계 처리
    • 가장 큰 파일 — 500줄 이상이면 코드만으로 파악이 느려짐
    • 고유한 외부 연동 패턴이 있는 모듈 — GPU 스케줄링, LLM 호출, 외부 API

    15개 모듈이 있는 프로젝트에서 전부 문서를 쓸 필요는 없다. 핵심 모듈 5~6개만 골라서 쓰는 것이 현실적이다.

    모듈 문서의 구조

    실전에서 효과적인 모듈 문서는 다음 6가지 섹션으로 구성된다:

    1. 한 줄 요약 + 목적

    파일 이름과 역할을 한 줄로 요약하고, 2~3문장으로 목적을 서술한다.

    # Narrator — LLM 내러티브 생성
    > narrator.py — vLLM을 통해 각 이벤트에 자연어 내러티브를 생성한다.
    
    ## 목적
    이벤트별 사진 메타데이터를 LLM에 제공하여, 가족 앨범에 어울리는
    따뜻한 내러티브 텍스트를 자동 생성한다. 프로젝트에서 가장 큰 모듈(883줄).

    왜 LLM에게 중요한가: 에이전트가 "내러티브 생성 로직을 수정해줘"라는 요청을 받으면, 프로젝트 내 수십 개 파일 중 어느 파일을 열어야 하는지 한 줄 요약만으로 즉시 판단한다. "883줄"이라는 정보는 에이전트에게 "이 파일은 크니까 전체를 읽지 말고 필요한 함수만 찾아라"는 힌트가 된다.

    2. 주요 함수 목록

    모든 함수를 나열하는 게 아니라, 외부에서 호출하는 공개 함수만 정리한다. 함수 시그니처, 파라미터 의미, 반환 타입을 적는다.

    ## 주요 함수
    
    ### detect_events(records, gap_hours, min_photos) → list[PhotoEvent]
    핵심 클러스터링 함수. 2단계 알고리즘:
    1. 시간 간격 분리: 인접 사진 간 gap_hours 이상이면 별도 클러스터
    2. 소규모 병합: min_photos 미만은 "일상" 버퍼에 병합
    
    ### group_by_year(records) → dict[int, list[PhotoRecord]]
    연도별로 사진을 분류한다.

    왜 LLM에게 중요한가: 에이전트가 새 기능을 추가할 때 기존 함수를 재사용할지, 새로 만들지를 판단하는 핵심 근거다. 함수 목록이 없으면 에이전트는 코드 전체를 grep하면서 비슷한 함수를 찾아야 하고, 이미 있는 기능을 중복 구현할 확률이 높아진다.

    3. 핵심 알고리즘/규칙

    코드만으로는 "왜 이 규칙인지" 알기 어려운 비즈니스 로직을 표로 정리한다.

    조건 결과 예시
    dominant scene 존재 {년} {월} {scene} "2024년 5월 생일파티"
    scene 없고 dominant tag 존재 {년} {월} {tag} "2024년 5월 공원"
    둘 다 없음 {년} {월} 일상 "2024년 5월 일상"

    왜 LLM에게 중요한가: 규칙이 표로 정리되어 있으면 에이전트는 규칙을 수정하거나 확장할 때 기존 패턴을 유지한다. "계절 정보도 라벨에 넣어줘"라는 요청이 오면, 기존 3가지 규칙에 자연스럽게 4번째를 추가할 수 있다. 코드에 if-elif 체인으로만 있으면 에이전트가 패턴을 놓치고 다른 스타일로 분기를 추가할 수 있다.

    4. 외부 연동 패턴

    GPU 스케줄링, LLM 호출, 외부 API 등 이 모듈만의 고유한 연동 방식이 있으면 코드 스니펫으로 보여준다.

    ## GPU 연동 패턴
    def _gpu_acquire():
        subprocess.run([str(GPU_SCHEDULER), "acquire", GPU_JOB_NAME], ...)
    
    def _gpu_release():
        subprocess.run([str(GPU_SCHEDULER), "release", GPU_JOB_NAME], ...)
    
    GPU_JOB_NAME = "ollama" — vLLM과 Ollama가 같은 GPU를 공유하므로 동일 job name 사용.

    왜 LLM에게 중요한가: 에이전트가 GPU를 사용하는 새 기능을 추가할 때, 이 패턴을 따라 acquire/release를 반드시 포함시킨다. 패턴이 문서화되어 있지 않으면 에이전트가 GPU 스케줄러를 건너뛰는 코드를 작성할 수 있고, 이는 다른 작업과의 GPU 충돌로 이어진다.

    5. 캐시 전략

    이 모듈이 사용하는 캐시 파일, 캐시 키 형식, 캐시 hit 조건을 정리한다.

    ## 캐시 전략
    - 캐시 파일: narrative_cache.json
    - 캐시 키: t{trip_id}|{날짜}|{순서} (예: t0|2024-05-15|0)
    - 캐시 hit이면 LLM 호출을 건너뛰어 GPU 시간 절약

    왜 LLM에게 중요한가: 캐시 키 형식을 알면 에이전트가 "캐시를 무효화하는 변경"과 "캐시에 영향 없는 변경"을 구분할 수 있다. 예를 들어 trip_id 생성 로직을 바꾸면 기존 캐시가 전부 무효화된다는 것을 미리 알 수 있다.

    6. 의존성과 설정값

    이 모듈이 import하는 내부/외부 의존성과 주요 상수를 표로 정리한다.

    상수 설명
    EVENT_GAP_HOURS 48 이벤트 분리 기준 시간
    MIN_EVENT_PHOTOS 3 이 수 미만이면 "일상"으로 병합
    LLM_MODEL google/gemma-4-26B-A4B-it vLLM 모델

    왜 LLM에게 중요한가: "이벤트 분리 기준을 24시간으로 바꿔줘"라는 요청에 에이전트가 이 표에서 상수명과 현재 값을 찾아 정확히 변경한다. 상수명이 코드에만 흩어져 있으면 에이전트가 잘못된 변수를 수정하거나 하드코딩된 값을 놓칠 수 있다.

    모듈 문서 작성 체크리스트

    섹션 핵심 질문 LLM에게 주는 효과
    한 줄 요약 이 파일이 무엇을 하는가? 올바른 파일을 즉시 찾음
    주요 함수 외부에서 뭘 호출할 수 있는가? 기존 함수 재사용, 중복 방지
    핵심 규칙 어떤 조건에서 어떤 결과가 나오는가? 규칙 확장 시 기존 패턴 유지
    외부 연동 GPU, API 등 어떤 패턴으로 연동하는가? 새 연동 시 기존 패턴 따름
    캐시 전략 무엇이 캐시되고 언제 무효화되는가? 캐시 영향 변경 사전 감지
    설정값 조정 가능한 값은 무엇인가? 정확한 상수 변경

    모든 모듈에 문서가 필요하지는 않다

    15개 모듈이 있는 프로젝트에서 전부 문서를 쓰는 건 과잉이다. 다음 기준으로 5~6개만 선별하면 된다:

    선별 기준 이유 예시
    파이프라인 진입점 전체 흐름의 시작, 파라미터가 시스템 전체에 영향 extractor.py
    복잡한 비즈니스 로직 조건 분기가 많아 코드만으로는 규칙 파악 어려움 grouper.py, narrator.py
    가장 큰 파일 (500줄+) 코드 탐색에 시간이 오래 걸림 server.py (2,000줄)
    고유한 외부 연동 GPU, LLM 등 특수한 패턴이 있는 모듈 narrator.py (GPU + vLLM)

    나머지 모듈은 함수 docstring과 타입 힌트만으로 충분하다. 모듈 문서도 유지보수 대상이므로, 쓸수록 좋은 게 아니라 유지할 수 있는 만큼만 쓰는 게 맞다.

    모듈 문서 vs docstring: 어디까지 문서에 쓰는가

    모듈 문서와 docstring의 역할은 다르다:

      모듈 문서 (modules/*.md) docstring (코드 내)
    대상 사람 + AI 에이전트 개발자 (IDE에서 바로 봄)
    범위 모듈 전체의 목적, 함수 간 관계, 외부 연동 개별 함수의 파라미터, 반환 타입
    정보 "왜 이 모듈이 이렇게 구성되었는가" "이 함수를 어떻게 호출하는가"
    유지보수 모듈 구조가 바뀔 때만 업데이트 함수 시그니처가 바뀔 때마다 업데이트

    쉽게 말하면, docstring은 "이 함수가 무엇을 하는가"이고, 모듈 문서는 "이 함수들이 왜 이렇게 구성되어 있는가"다. 둘은 보완적이지 대체 관계가 아니다.

    코드 위키 전체 구조 — 완성된 그림

    이 시리즈에서 다룬 모든 문서를 디렉토리 구조로 보면 이렇다:

    docs/
    ├── architecture.md        # 시스템의 숲 — 레이어, HLD, 의존성
    ├── data-pipeline.md       # 데이터의 여정 — 단계별 흐름과 캐시
    ├── adr/                   # 설계 결정의 맥락
    │   ├── 0001-photo-backend.md
    │   ├── 0002-local-llm.md
    │   └── 0003-event-clustering.md
    ├── modules/               # 핵심 모듈의 깊은 이해
    │   ├── extractor.md
    │   ├── grouper.md
    │   ├── narrator.md
    │   └── server.md
    └── contributing.md        # 개발 가이드

    각 문서가 AI 에이전트에게 제공하는 맥락을 정리하면:

    • architecture.md → "이 시스템이 어떻게 구성되어 있는가" (구조)
    • data-pipeline.md → "데이터가 어떤 단계를 거치는가" (흐름)
    • ADR → "왜 이런 선택을 했는가" (의도)
    • modules/*.md → "이 모듈의 함수와 규칙이 어떻게 동작하는가" (구현)

    숲에서 나무까지, 의도에서 구현까지. 이 네 가지가 갖춰지면 AI 에이전트는 프로젝트를 처음 보는 상태에서도 의미 있는 코드를 작성할 수 있는 맥락을 갖게 된다.


    이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.

Designed by Tistory.