Files
variet-agent/docs/design_document.md

10 KiB

AI Agent Team — 최종 설계서

C:\Users\CafeVariet-GL552VW\Desktop\source_diff


1. 해결할 문제

문제 원인
컨텍스트 포화 → 멈춤/유실 Gemini CLI Context Rot (20~50%에서 발생)
전체 프로젝트 스캔 → Rate Limit 무차별 파일 읽기
추상적 명령 처리 불가 단일 에이전트의 작업 분해 한계
수동 Git/CI 워크플로우 자동화 없음

2. 아키텍처

┌─ Interface Layer ────────────────────┐
│  Discord Adapter ←→ API Server (FastAPI)
│  Web UI Adapter  ←→   ↕
│  (CLI Adapter)   ←→ REST + SSE/WebSocket
└──────────────────────┬───────────────┘
                       │
┌──────────────────────▼───────────────┐
│  Orchestrator                         │
│                                       │
│  ┌─────────────┐  ┌────────────────┐ │
│  │Project Index │  │Context Manager │ │
│  │구조/import/  │  │파일 선별       │ │
│  │시그니처 캐시 │  │토큰 예산 제어  │ │
│  └──────┬──────┘  └───────┬────────┘ │
│         └────────┬────────┘          │
│         ┌────────▼────────┐          │
│         │  Task Pipeline   │          │
│         │  Plan → Code     │          │
│         │  → Review → Test │          │
│         │  → Ship          │          │
│         └────────┬────────┘          │
│         ┌────────▼────────┐          │
│         │ Rate Limiter     │          │
│         │ Session Manager  │          │
│         └────────┬────────┘          │
└──────────────────┼───────────────────┘
         ┌─────────┼─────────┐
    ┌────▼───┐ ┌───▼────┐ ┌──▼───────┐
    │Gemini  │ │Gitea   │ │Vikunja   │
    │CLI -p  │ │API     │ │API       │
    │headless│ │PR/CI   │ │태스크    │
    └────────┘ └────────┘ └──────────┘

3. 핵심 컴포넌트

3.1 API Server

# api/server.py — FastAPI
POST /projects              # 프로젝트 목록 (Gitea 레포 조회)
POST /projects/{id}/select  # 작업 대상 설정
POST /tasks                 # 작업 요청
GET  /tasks/{id}/status     # 진행 상황 (SSE 스트림)
POST /tasks/{id}/confirm    # 승인/거부
GET  /tasks/history         # 이력

Discord Bot과 Web UI 모두 이 API를 호출. Orchestrator는 인터페이스를 모름.

3.2 Context Manager (핵심 차별화)

Gemini CLI의 Context Rot를 구조적으로 해결:

class ContextManager:
    def __init__(self, project_index: ProjectIndex):
        self.index = project_index
        self.token_budget = 50_000  # 호출당 토큰 예산

    def gather(self, task: str) -> str:
        """태스크에 필요한 파일만 선별하여 컨텍스트 생성"""
        # 1. 태스크에서 언급된 파일/함수 추출
        targets = self.index.find_relevant(task)

        # 2. import/caller 관계로 관련 파일 확장
        related = self.index.expand_dependencies(targets, depth=2)

        # 3. 토큰 예산 내에서 관련도 순 포함
        context_files = self.fit_budget(related, self.token_budget)

        # 4. 프롬프트 형식으로 조합
        return self.format_context(context_files)

3.3 Project Indexer

최초 1회 프로젝트 구조 분석 → 캐시:

class ProjectIndex:
    files: dict[str, FileInfo]      # 파일별 메타 (크기, 언어, 라인수)
    imports: dict[str, list[str]]   # import 관계 그래프
    signatures: dict[str, list]     # 함수/클래스 시그니처
    structure: str                  # 요약된 디렉토리 구조

    def find_relevant(self, task: str) -> list[str]:
        """태스크 설명에서 관련 파일 추출"""

    def expand_dependencies(self, files, depth) -> list[str]:
        """import 관계로 관련 파일 확장"""

3.4 Task Pipeline

class TaskPipeline:
    async def execute(self, user_request: str, project: str):
        ctx = self.context_manager

        # Plan
        plan_ctx = ctx.gather(f"프로젝트 구조 파악: {user_request}")
        plan = await gemini_call("planner", plan_ctx + user_request)
        await self.notify("plan", plan)  # Discord/Web에 보고
        await self.wait_confirm()        # 사용자 승인 대기

        # Code + Review (태스크별)
        for task in plan.tasks:
            code_ctx = ctx.gather(task.description)
            code = await gemini_call("coder", code_ctx + task)

            review_ctx = ctx.gather(f"리뷰: {task.description}")
            review = await gemini_call("reviewer", review_ctx + code)
            if not review.passed:
                code = await gemini_call("coder", code_ctx + review.feedback)

        # Test
        test_ctx = ctx.gather("테스트 관련")
        await gemini_call("tester", test_ctx + changes)

        # Ship
        pr = await self.gitea.create_pr(changes)
        ci = await self.gitea.wait_ci(pr.id)
        await self.vikunja.complete_tasks(plan.tasks)
        await self.notify("complete", pr, ci)

3.5 GeminiCaller

class GeminiCaller:
    async def call(self, role: str, context: str) -> str:
        prompt = load_role_prompt(role)
        cmd = [
            "gemini", "-p", context,
            "--system", prompt,
            "--approval-mode", "yolo",
            "-o", "json"
        ]
        proc = await asyncio.create_subprocess_exec(*cmd, ...)
        self.rate_limiter.record()
        return parse_result(proc.stdout)

4. 보안 정책 (Mode A 전환)

API Server에 mode 파라미터:

Mode Context 생성 Gemini 접근
general Context Manager가 원본 파일 전달 소스 직접 읽기 가능
secure 로컬 LLM이 추상화/마스킹 후 전달 소스 원본 접근 불가

→ VEGA 핸드오프 문서 참조 (docs/vega_handoff.md)


5. 디렉토리 구조

source_diff/
├── main.py                      # 진입점
├── config.py                    # 설정
├── requirements.txt             # fastapi, discord.py, httpx, pydantic, rich
├── api/
│   ├── server.py                # FastAPI 서버
│   ├── models.py                # 요청/응답 모델
│   └── discord_bot.py           # Discord Bot (API 클라이언트)
├── core/
│   ├── orchestrator.py          # 작업 흐름 제어
│   ├── context_manager.py       # 파일 선별 + 토큰 예산 (핵심)
│   ├── project_indexer.py       # 프로젝트 구조 분석/캐시
│   ├── gemini_caller.py         # gemini -p 역할별 호출
│   ├── task_pipeline.py         # Plan→Code→Review→Test→Ship
│   ├── rate_limiter.py          # 120 RPM / 2,000 RPD
│   └── session_manager.py       # WorkUnit 관리
├── integrations/
│   ├── gitea_client.py          # git.variet.net API
│   ├── vikunja_client.py        # plan.variet.net API
│   └── ci_monitor.py            # Woodpecker CI 결과 대기
├── prompts/
│   ├── planner.md               # 작업 분해
│   ├── coder.md                 # 코드 수정
│   ├── reviewer.md              # 코드 리뷰
│   └── tester.md                # 테스트 작성/실행
├── docs/
│   ├── design_document.md       # 이 문서
│   ├── vega_handoff.md          # VEGA 핸드오프
│   └── architecture_critique.md # 비판적 검토
└── sessions/                    # 작업 로그

6. 실전 테스트 계획

테스트 1: Context Manager 단독 효과

[비교 대상]
A: gemini -i --include-directories ./src (Gemini CLI 단독)
B: gemini -p + Context Manager (관련 파일 4개만 주입)

[테스트 시나리오]
기존 프로젝트에서 "interpolation.py의 선형보간을 큐빅스플라인으로 변경"

[측정]
- 응답 정확도 (관련 파일 잘 찾았는가)
- 수정 범위 정확도 (불필요한 수정 없는가)
- 토큰 사용량
- 응답 시간

테스트 2: Task Pipeline E2E

[시나리오]
"README에 설치 방법 섹션 추가해줘"

[검증 항목]
- Planner가 합리적으로 분해하는가
- Coder가 파일을 정확히 수정하는가
- Reviewer가 문제 발견 시 Coder 재호출이 작동하는가
- Git commit + PR 생성 성공하는가

테스트 3: 대규모 프로젝트 분석

[시나리오]
VEGA 프로젝트 (수백 파일)에서 "검색 로직 흐름을 설명해줘"

[비교]
A: gemini -i (전체 스캔 → Context Rot 예상)
B: Context Manager → 검색 관련 파일 10개 선별 → gemini -p

[측정]
- 분석 완료율 (A는 중간에 멈출 수 있음)
- 설명 정확도
- Rate Limit 소모량

7. 구현 순서 (실전 테스트 중심)

Step 작업 테스트
1 Project Indexer + Context Manager 테스트 1 실행
2 GeminiCaller (역할별 호출) 역할 전환 동작 확인
3 Task Pipeline (Plan→Code→Review) 테스트 2 실행
4 API Server + Discord Bot 디스코드→파이프라인 연결
5 Gitea 연동 (PR/CI) 테스트 2 E2E
6 Vikunja 연동 태스크 자동 등록/완료
7 대규모 테스트 테스트 3 실행