chore: 프로젝트 초기 구조 + .agent 워크플로우 + 설계 문서
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.agent/
|
||||||
|
sessions/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.env
|
||||||
32
README.md
Normal file
32
README.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Variet Agent
|
||||||
|
|
||||||
|
AI Agent Team — Gemini CLI 기반 자동화 개발 에이전트 시스템
|
||||||
|
|
||||||
|
## 목표
|
||||||
|
|
||||||
|
사용자가 디스코드에서 추상적 명령을 주면, AI Agent Team이 작업을 분석/분해/실행하고, Gitea CI로 PR/빌드/배포까지 수행.
|
||||||
|
|
||||||
|
## 핵심 특징
|
||||||
|
|
||||||
|
- **Context Manager**: Gemini CLI의 Context Rot 문제 해결 (관련 파일만 선별 주입)
|
||||||
|
- **역할별 Headless 호출**: `gemini -p`로 매번 독립 컨텍스트
|
||||||
|
- **API 추상화**: Discord / Web UI 동일 파이프라인
|
||||||
|
- **Gitea + Vikunja 연동**: PR/CI/태스크 자동 관리
|
||||||
|
|
||||||
|
## 구조
|
||||||
|
|
||||||
|
```
|
||||||
|
api/ # FastAPI 서버 + Discord Bot
|
||||||
|
core/ # Orchestrator, Context Manager, Pipeline
|
||||||
|
integrations/ # Gitea, Vikunja, CI
|
||||||
|
prompts/ # 역할별 프롬프트
|
||||||
|
sessions/ # 작업 로그
|
||||||
|
docs/ # 설계 문서
|
||||||
|
```
|
||||||
|
|
||||||
|
## 환경
|
||||||
|
|
||||||
|
- Python 3.12 (`C:\ProgramData\miniforge3\envs\quant`)
|
||||||
|
- Gemini CLI v0.32+ (AI Ultra)
|
||||||
|
- Gitea: git.variet.net
|
||||||
|
- Vikunja: plan.variet.net/projects/7
|
||||||
209
docs/architecture_critique.md
Normal file
209
docs/architecture_critique.md
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
# v7 아키텍처 엄밀 비판
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 보안 비판
|
||||||
|
|
||||||
|
### 🔴 1. 정보 예산이 추적하는 것이 잘못됨
|
||||||
|
|
||||||
|
현재 `InformationBudget`은 **노출된 함수명 수, 모듈명 수**를 센다.
|
||||||
|
하지만 진짜 정보 유출은 **이름이 아니라 로직**에서 발생:
|
||||||
|
|
||||||
|
```
|
||||||
|
"TABLE_A에서 DATE와 TENOR로 인덱싱된 금리 커브를 조회하고,
|
||||||
|
보간법으로 중간 만기를 추정한 뒤, HW 모델 파라미터로 변환"
|
||||||
|
```
|
||||||
|
|
||||||
|
→ 함수명 0개, 테이블 원명 0개 노출. **정보 예산 카운터: 0**.
|
||||||
|
→ 하지만 이 문장만으로 **DB 스키마 + 비즈니스 로직의 핵심이 노출됨**.
|
||||||
|
|
||||||
|
**문제: 이름을 세는 건 무의미. 로직의 깊이/구체성을 측정해야 함.**
|
||||||
|
|
||||||
|
> 대응: 정보 예산을 "추상화 레벨"로 전환 — 허용 수준 정의
|
||||||
|
> - Level 1: "이 모듈은 평가를 담당한다" (허용)
|
||||||
|
> - Level 2: "금리 커브 조회 → 보간 → 모델 계산" (주의)
|
||||||
|
> - Level 3: "DATE+TENOR 인덱싱, 선형보간, mean-reversion 파라미터" (위험)
|
||||||
|
> - Level 4: 소스 원문 (절대 금지)
|
||||||
|
>
|
||||||
|
> 각 라운드의 응답을 별도 LLM이나 규칙으로 레벨 분류
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🔴 2. 정규식 필터는 시맨틱 유출을 못 막음
|
||||||
|
|
||||||
|
정규식이 잡는 것: `swap_curve`, `192.168.x.x`, `user@company.com`
|
||||||
|
정규식이 못 잡는 것:
|
||||||
|
|
||||||
|
```
|
||||||
|
"수익률 곡선 데이터를 날짜와 기간으로 인덱싱해서 가져온다"
|
||||||
|
```
|
||||||
|
|
||||||
|
→ 키워드 없음 → 필터 통과 → **하지만 DB 스키마 의미가 그대로 전달됨**
|
||||||
|
|
||||||
|
**정규식은 구문(syntax) 필터이지 의미(semantic) 필터가 아님.**
|
||||||
|
|
||||||
|
> 대응: 정규식은 1차 방어선(키워드 차단)으로만 사용.
|
||||||
|
> 2차 의미 필터는 로컬 LLM 프롬프트의 추상화 레벨 규칙에 의존할 수밖에 없음.
|
||||||
|
> **결국 보안의 최종 책임은 로컬 LLM의 판단력에 있음** → 이 한계를 수용해야 함.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🟡 3. 추상화-검증 순환 오류
|
||||||
|
|
||||||
|
로컬 LLM이 **추상화도 하고 검증도 함**:
|
||||||
|
|
||||||
|
```
|
||||||
|
[오류 시나리오]
|
||||||
|
LLM이 소스를 잘못 이해: "함수 A가 B를 호출한다" (실제: A→C→B)
|
||||||
|
↓
|
||||||
|
Analyst(Gemini): "A→B 호출에서 B 진입 시 검증 누락"
|
||||||
|
↓
|
||||||
|
Critic(LLM): 소스 재확인 → 같은 오해 반복 → "맞아, A→B야. LGTM"
|
||||||
|
```
|
||||||
|
|
||||||
|
**자기가 만든 추상화를 자기가 검증하면, 같은 실수를 반복할 수 있음.**
|
||||||
|
|
||||||
|
> 대응:
|
||||||
|
> - 검증 시 **다른 관점으로 소스 재독**: "A가 호출하는 함수 목록을 나열해"처럼 구체적 질문
|
||||||
|
> - Worker가 **반문**할 수 있게 허용: "정말 A→B인가? A→C→B는 아닌가?" → LLM이 재확인
|
||||||
|
> - 완전 해결은 불가 — 로컬 LLM 능력의 한계
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 구조 비판
|
||||||
|
|
||||||
|
### 🔴 4. Mode A와 B의 품질 격차가 클 것
|
||||||
|
|
||||||
|
| | Mode A | Mode B |
|
||||||
|
|---|--------|--------|
|
||||||
|
| Analyst | Gemini (강) | Gemini (강) |
|
||||||
|
| Critic | **Qwen 3.5 (약)** | **Gemini (강)** |
|
||||||
|
| 소스 접근 | 추상화 경유 (정보 손실) | 직접 (무손실) |
|
||||||
|
|
||||||
|
**Mode A의 품질은 가장 약한 고리(로컬 LLM)에 의해 결정됨.**
|
||||||
|
Critic이 약하면:
|
||||||
|
- 잘못된 반론 → Analyst 혼란
|
||||||
|
- 부실한 검증 → 오류 통과
|
||||||
|
- 과도하거나 부족한 추상화 → Analyst 분석 품질 저하
|
||||||
|
|
||||||
|
**솔직히: Mode A의 분석 품질은 Mode B의 50~70% 수준일 가능성이 높음.**
|
||||||
|
|
||||||
|
> 수용: 이것은 보안 비용. 보안을 지키면서 100% 품질은 원리적으로 불가능.
|
||||||
|
> 완화: 분석 유형별로 모드 선택 — 민감하지 않은 분석은 Mode B로.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🟡 5. 대화의 주도권이 불명확
|
||||||
|
|
||||||
|
**누가 다음 질문을 결정하는가?**
|
||||||
|
|
||||||
|
- **Analyst(Gemini)가 주도**: "다음으로 caller를 확인해줘" → 정보 흐름을 Gemini가 통제 → **보안 위험** (원하는 방향으로 유도 가능)
|
||||||
|
- **Critic(LLM)이 주도**: "다음은 이 부분을 분석해" → Gemini의 분석력이 과소 활용 → **품질 저하**
|
||||||
|
|
||||||
|
현재 설계는 이 주도권이 정의되지 않음.
|
||||||
|
|
||||||
|
> 대응: **턴제 혼합**
|
||||||
|
> - 홀수 턴: Critic이 주제 설정 ("이 함수를 분석해줘")
|
||||||
|
> - 짝수 턴: Analyst가 후속 질문 ("다음 확인 사항은?")
|
||||||
|
> - Critic은 Analyst의 질문에 **거부권** 보유: "그 정보는 제공 불가"
|
||||||
|
> → Critic이 게이트, Analyst가 추진력
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🟡 6. Analyst↔Critic 교착(Deadlock) 처리 없음
|
||||||
|
|
||||||
|
```
|
||||||
|
Analyst: "이건 버그다"
|
||||||
|
Critic: "아니다, 정상이다"
|
||||||
|
Analyst: "아니, 0 나누기 발생한다"
|
||||||
|
Critic: "호출 경로상 0은 들어오지 않는다"
|
||||||
|
... 10라운드 → 결론 없음
|
||||||
|
```
|
||||||
|
|
||||||
|
`max_rounds` 도달 시 어떻게 되는가? 현재 설계에 정의 없음.
|
||||||
|
|
||||||
|
> 대응:
|
||||||
|
> - **교착 감지**: 3라운드 연속 결론 변화 없으면 교착 선언
|
||||||
|
> - **사용자 중재**: 교착 시 양쪽 주장을 사용자에게 제시 → 방향 결정
|
||||||
|
> - **합의 불가 마킹**: "이 분석은 확정되지 않음" 태그 부착
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🟢 7. "파이프라인 공유" 주장이 실제보다 과장됨
|
||||||
|
|
||||||
|
| 컴포넌트 | 정말 공유? |
|
||||||
|
|---------|-----------|
|
||||||
|
| 대화 루프 프로토콜 | △ — Mode A는 LLM↔CLI, Mode B는 CLI↔CLI. 인터페이스만 같고 구현 다름 |
|
||||||
|
| MCP 서버 | ❌ — Mode B 전용. Mode A는 MCP 안 씀 |
|
||||||
|
| Worker Runner | ✅ — `gemini -p` 호출은 동일 |
|
||||||
|
| Rate Limiter | ✅ |
|
||||||
|
| Session Manager | ✅ (세션 격리 전제) |
|
||||||
|
|
||||||
|
**실제 코드 공유율은 100%가 아니라 ~60%에 가까움.**
|
||||||
|
|
||||||
|
> 수용: 과장을 제거하고 현실적으로 서술. 공유되는 것과 안 되는 것 구분.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 실용성 비판
|
||||||
|
|
||||||
|
### 🟡 8. Mode A에서 Gemini 투입 가치가 있는가?
|
||||||
|
|
||||||
|
Mode A에서 Analyst(Gemini)는 **추상화된 정보만** 받음.
|
||||||
|
추상화 과정에서 정보 손실이 필연적 → Gemini의 분석 품질 제한.
|
||||||
|
|
||||||
|
**그렇다면:** 로컬 LLM이 직접 분석하는 것 대비 Gemini 투입의 실익은?
|
||||||
|
|
||||||
|
| 접근법 | 장점 | 단점 |
|
||||||
|
|--------|------|------|
|
||||||
|
| 로컬 LLM 단독 분석 | 소스 전체 접근, 보안 완벽 | 분석 품질 낮음 |
|
||||||
|
| 로컬 LLM + Gemini 협력 (현재) | Gemini 추론력 활용 | 추상화 비용, 복잡성, RPD 소비 |
|
||||||
|
|
||||||
|
> **Gemini 투입이 정당화되는 경우:**
|
||||||
|
> - 수백 줄 이상의 복잡한 로직 추론 (LLM 단독 한계)
|
||||||
|
> - 알려진 패턴/안티패턴 매칭 (Gemini 학습 데이터 활용)
|
||||||
|
> - 코드 리뷰 관점 (보안 취약점, 성능 이슈)
|
||||||
|
>
|
||||||
|
> **정당화 안 되는 경우:**
|
||||||
|
> - 단순 함수 설명, 호출 추적 → LLM 단독으로 충분
|
||||||
|
> → **Complexity Router가 이 판단을 해야 함**:
|
||||||
|
> Simple/Medium → 로컬 LLM 단독, Complex → Gemini 투입
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🟢 9. Mode B에서 Critic의 독립성
|
||||||
|
|
||||||
|
Mode B의 Critic은 **별도 Gemini CLI 인스턴스**.
|
||||||
|
하지만 **같은 모델(Gemini)**이 Analyst와 Critic.
|
||||||
|
→ 같은 모델이 같은 소스를 보고 → 같은 편향 공유 가능.
|
||||||
|
|
||||||
|
> 이것은 v4 비판의 "자기 선호 편향"과 유사하나,
|
||||||
|
> **별도 프롬프트 + 별도 컨텍스트**이므로 단일 자기 평가보다는 낫다.
|
||||||
|
> 완전 독립 검증은 아니지만 현실적 타협점.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 종합
|
||||||
|
|
||||||
|
| # | 이슈 | 심각도 | 해결 가능? |
|
||||||
|
|---|------|--------|-----------|
|
||||||
|
| 1 | 정보 예산이 로직 깊이를 못 셈 | 🔴 | △ 추상화 레벨 분류로 전환 |
|
||||||
|
| 2 | 정규식은 의미 유출 못 막음 | 🔴 | ✗ LLM 판단에 의존할 수밖에 없음 |
|
||||||
|
| 3 | 추상화-검증 순환 오류 | 🟡 | △ Analyst 반문 + 다른 관점 재독 |
|
||||||
|
| 4 | Mode A/B 품질 격차 | 🔴 | ✗ 보안 비용으로 수용 |
|
||||||
|
| 5 | 대화 주도권 미정의 | 🟡 | ◎ 턴제 + 거부권으로 해결 |
|
||||||
|
| 6 | 교착 처리 없음 | 🟡 | ◎ 교착 감지 + 사용자 중재 |
|
||||||
|
| 7 | 파이프라인 공유 과장 | 🟢 | ◎ 현실적 서술로 수정 |
|
||||||
|
| 8 | Mode A Gemini 투입 가치 | 🟡 | ◎ Complexity Router에서 분류 |
|
||||||
|
| 9 | Mode B Critic 독립성 한계 | 🟢 | △ 별도 프롬프트로 완화 |
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> **이번 비판의 핵심 메시지:**
|
||||||
|
>
|
||||||
|
> 이전 비판의 🔴 이슈였던 "자기 평가 불신뢰"와 "과잉 동원"은 v7에서 **해결됨**.
|
||||||
|
> 하지만 새로운 🔴가 등장:
|
||||||
|
> - **보안의 최종 방어선이 LLM의 판단력**이라는 구조적 한계
|
||||||
|
> - **Mode A 품질이 Mode B보다 본질적으로 낮다**는 트레이드오프
|
||||||
|
>
|
||||||
|
> 이 두 가지는 **구조로 해결할 수 없는 원리적 한계**이며,
|
||||||
|
> "어디까지 수용할 것인가"의 정책 결정이 필요합니다.
|
||||||
277
docs/design_document.md
Normal file
277
docs/design_document.md
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 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를 구조적으로 해결:
|
||||||
|
|
||||||
|
```python
|
||||||
|
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회 프로젝트 구조 분석 → 캐시:
|
||||||
|
|
||||||
|
```python
|
||||||
|
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
|
||||||
|
|
||||||
|
```python
|
||||||
|
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
|
||||||
|
|
||||||
|
```python
|
||||||
|
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 실행 |
|
||||||
193
docs/vega_handoff.md
Normal file
193
docs/vega_handoff.md
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# VEGA 확장 — Gemini CLI 보안 분석 모듈 설계 핸드오프 문서
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 배경 및 논의 경과
|
||||||
|
|
||||||
|
### 출발점
|
||||||
|
로컬 LLM(Qwen 3.5)만으로는 소스 분석 품질에 한계가 있어, Gemini CLI의 분석력을 활용하되 **내부 소스 보안을 유지**하는 시스템을 설계.
|
||||||
|
|
||||||
|
### 핵심 논의 과정 (v1 → v8)
|
||||||
|
|
||||||
|
| 버전 | 논의 | 결론 |
|
||||||
|
|------|------|------|
|
||||||
|
| v1~v2 | API vs CLI, 멀티 워커 | Gemini CLI 사용, 역할별 워커 |
|
||||||
|
| v3~v4 | Rate Limit, 반복 루프 | AI Ultra 120RPM/2000RPD, Plan→Execute→Reflect 루프 |
|
||||||
|
| v4 비판 | 자기평가 불신뢰, 과잉동원 | 연구 기반 5개 약점 발견 |
|
||||||
|
| v5~v6 | MCP 도구, Verifier, 보안 | Source Mediator 패턴, Verifier를 Critic으로 전환 |
|
||||||
|
| v7 | 보안 원칙 확정, Critic 협력자 | 소스 원문 금지, 로직 설명 허용, LLM 앞단+검증자 |
|
||||||
|
| **v8** | **Mode B 가치 재검토** | **Gemini CLI 자체가 완전한 에이전트 → Mode B는 추가 개발 불필요** |
|
||||||
|
|
||||||
|
### 최종 결론
|
||||||
|
|
||||||
|
```
|
||||||
|
Mode B (외부/범용): Gemini CLI를 그대로 쓰면 됨
|
||||||
|
→ VS Code Agent Mode 또는 터미널 gemini -i
|
||||||
|
→ 추가 개발 불필요
|
||||||
|
|
||||||
|
Mode A (내부/보안): VEGA 확장으로 구현해야 하는 부분
|
||||||
|
→ 로컬 LLM이 내부 소스를 읽고 추상화
|
||||||
|
→ Gemini CLI(선생님)와 대화로 분석
|
||||||
|
→ 로컬 LLM이 결과를 소스와 대조 검증
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. VEGA에서 구현할 것: Mode A
|
||||||
|
|
||||||
|
### 구조
|
||||||
|
|
||||||
|
```
|
||||||
|
User ↔ VEGA Web UI
|
||||||
|
│
|
||||||
|
Local LLM (프롬프트 A: 앞단)
|
||||||
|
│ 도구: 내부 파일/RAG/DB
|
||||||
|
│ 소스 읽고 추상화/마스킹
|
||||||
|
▼
|
||||||
|
Gemini CLI (-p, --approval-mode yolo)
|
||||||
|
│ 추상화된 정보로 분석
|
||||||
|
│ 질문 → LLM 답변 → 분석 (대화 루프)
|
||||||
|
▼
|
||||||
|
Local LLM (프롬프트 B: 검증자, 별도 호출)
|
||||||
|
│ Gemini 결과 vs 실제 소스 대조
|
||||||
|
▼
|
||||||
|
User에게 검증된 결과 전달
|
||||||
|
```
|
||||||
|
|
||||||
|
### 보안 정책
|
||||||
|
|
||||||
|
| 허용 ✅ | 금지 ❌ |
|
||||||
|
|---------|---------|
|
||||||
|
| 학술적 알고리즘 설명 (HW, LSMC 등) | 소스코드 원문 |
|
||||||
|
| 함수 로직/흐름 설명 | 테이블/컬럼 구조 |
|
||||||
|
| 호출 관계 개괄 | 실제 값, 파라미터 수치 |
|
||||||
|
| 개별 함수 입출력 의미 | 내부 URL, 인증정보 |
|
||||||
|
|
||||||
|
LLM 추상화 후 **정규식 2단계 필터**로 금지어 자동 치환.
|
||||||
|
|
||||||
|
### Student ↔ Teacher 모델
|
||||||
|
- LLM(학생)이 소스를 읽고 설명 → Gemini(선생님)가 분석/조언
|
||||||
|
- LLM이 문제 정립 못 해도 → Gemini가 질문으로 끌어냄
|
||||||
|
- LLM이 헛소리해도 → Gemini가 교정
|
||||||
|
- 앞단(프롬프트 A)과 검증자(프롬프트 B)는 **별도 호출** → 순환 오류 방지
|
||||||
|
|
||||||
|
### Gemini CLI 호출 방식
|
||||||
|
```bash
|
||||||
|
# 역할별 headless 호출 (서브에이전트 풀 불필요)
|
||||||
|
gemini -p "분석 요청" --system "분석가 프롬프트" -o json --approval-mode yolo
|
||||||
|
gemini -p "리뷰 요청" --system "리뷰어 프롬프트" -o json --approval-mode yolo
|
||||||
|
```
|
||||||
|
매 호출이 **독립 컨텍스트** → 컨텍스트 포화 없음 → 풀 관리 불필요.
|
||||||
|
|
||||||
|
### VEGA 기존 인프라 활용
|
||||||
|
- **Ollama API**: 로컬 LLM 호출 (이미 존재)
|
||||||
|
- **FastAPI + SSE**: Web UI (이미 존재)
|
||||||
|
- **RAG/벡터DB**: 내부 문서 검색 (이미 존재)
|
||||||
|
- **추가 필요**: `gemini -p` subprocess 호출 모듈, 마스킹 필터, 대화 루프
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 새로운 목표 — AI Agent Team
|
||||||
|
|
||||||
|
### 진짜 최종 목표
|
||||||
|
|
||||||
|
위 Mode A/B 논의는 더 큰 목표의 **일부**였음:
|
||||||
|
|
||||||
|
> **사용자가 디스코드로 추상적 명령을 주면,
|
||||||
|
> AI Agent Team이 스스로 작업을 분석/분해/실행하고,
|
||||||
|
> 샌드박스에서 코드를 실행/테스트하고,
|
||||||
|
> Gitea CI로 컴파일/배포까지 수행하며,
|
||||||
|
> 사용자는 디스코드로 확인/컨펌만 하는 시스템.**
|
||||||
|
|
||||||
|
### 왜 이 구조가 필요한가
|
||||||
|
|
||||||
|
| 현재 문제 | 원인 | 해결 방향 |
|
||||||
|
|----------|------|----------|
|
||||||
|
| **컨텍스트 초과** | 한 에이전트가 긴 작업 → 컨텍스트 포화 → 멈춤/유실 | 작업을 역할별로 분할, 각 에이전트는 짧은 컨텍스트 |
|
||||||
|
| **추상적 명령 처리** | "이거 고쳐줘" → 어디를? 뭘? | 작업 분석 에이전트가 구체적 태스크로 분해 |
|
||||||
|
| **실행/테스트 불가** | 분석만 하고 실제 실행 못 함 | 샌드박스 + CI 연동 |
|
||||||
|
| **확인의 어려움** | 결과를 보려면 IDE 열어야 | 디스코드로 중간 보고 + 컨펌 |
|
||||||
|
|
||||||
|
### 제안 아키텍처: AI Agent Team
|
||||||
|
|
||||||
|
```
|
||||||
|
Discord (사용자 인터페이스)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ Coordinator Agent │
|
||||||
|
│ (Gemini CLI 또는 로컬 LLM) │
|
||||||
|
│ │
|
||||||
|
│ 역할: │
|
||||||
|
│ - 사용자 명령 해석 │
|
||||||
|
│ - 작업 분해 (추상 → 구체) │
|
||||||
|
│ - 에이전트에게 작업 배분 │
|
||||||
|
│ - 결과 종합 → 디스코드 보고 │
|
||||||
|
└──┬──────────┬──────────┬────────────────┘
|
||||||
|
│ │ │
|
||||||
|
┌──▼──┐ ┌───▼───┐ ┌───▼───┐
|
||||||
|
│분석 │ │구현 │ │테스트 │ ... 역할별
|
||||||
|
│Agent │ │Agent │ │Agent │
|
||||||
|
└──┬──┘ └───┬───┘ └───┬───┘
|
||||||
|
│ │ │
|
||||||
|
└──────────┼──────────┘
|
||||||
|
│
|
||||||
|
┌─────────▼─────────┐
|
||||||
|
│ 실행 환경 │
|
||||||
|
│ - 샌드박스 (코드) │
|
||||||
|
│ - Gitea Runner │
|
||||||
|
│ - CI/CD 파이프라인 │
|
||||||
|
└───────────────────┘
|
||||||
|
│
|
||||||
|
디스코드로 결과 보고 + 사용자 컨펌
|
||||||
|
│
|
||||||
|
배포 / 완료
|
||||||
|
```
|
||||||
|
|
||||||
|
### 이 목표를 이루기 위한 프로젝트 분해
|
||||||
|
|
||||||
|
| 프로젝트 | 설명 | 의존성 |
|
||||||
|
|---------|------|--------|
|
||||||
|
| **P1: Discord Bot** | 사용자 ↔ 시스템 인터페이스 | 없음 |
|
||||||
|
| **P2: Task Decomposer** | 추상 명령 → 구체 태스크 목록 | Gemini CLI |
|
||||||
|
| **P3: Agent Runner** | 역할별 `gemini -p` headless 호출 | Gemini CLI |
|
||||||
|
| **P4: Sandbox** | 코드 실행/테스트 환경 | Docker 또는 로컬 격리 |
|
||||||
|
| **P5: Gitea CI 연동** | PR 생성 → Runner 실행 → 결과 수집 | Gitea API |
|
||||||
|
| **P6: 보안 분석 (Mode A)** | VEGA 확장, 내부 소스 보안 분석 | P3 + VEGA |
|
||||||
|
|
||||||
|
### 접근 전략
|
||||||
|
|
||||||
|
**단계적 구축 (작은 것부터 동작하게):**
|
||||||
|
|
||||||
|
```
|
||||||
|
Step 1: Discord Bot + gemini -p 호출
|
||||||
|
"디스코드로 질문 → Gemini 답변 → 디스코드로 반환"
|
||||||
|
→ 가장 작은 동작 단위. 기초 인프라 검증.
|
||||||
|
|
||||||
|
Step 2: Task Decomposer
|
||||||
|
"이 모듈 리팩토링해줘" → 구체 태스크 3개로 분해
|
||||||
|
→ Gemini CLI의 plan mode 활용
|
||||||
|
|
||||||
|
Step 3: Agent Runner + 파일 접근
|
||||||
|
분해된 태스크를 순차 실행, 파일 수정, 결과 보고
|
||||||
|
→ gemini -p --approval-mode yolo
|
||||||
|
|
||||||
|
Step 4: Sandbox 실행
|
||||||
|
수정된 코드를 샌드박스에서 실행/테스트
|
||||||
|
→ Docker 컨테이너 또는 gemini --sandbox
|
||||||
|
|
||||||
|
Step 5: Gitea CI 연동
|
||||||
|
수정 완료 → Gitea PR 생성 → Runner 실행 → 결과를 디스코드로
|
||||||
|
→ Gitea API + Webhook
|
||||||
|
|
||||||
|
Step 6: 보안 분석 (Mode A)
|
||||||
|
VEGA와 통합, 내부 소스 보안 분석 파이프라인
|
||||||
|
```
|
||||||
|
|
||||||
|
### 핵심 원칙
|
||||||
|
|
||||||
|
1. **Gemini CLI가 에이전트 엔진** — 자기가 이미 파일 읽기/쓰기/실행 가능
|
||||||
|
2. **headless 호출로 컨텍스트 분할** — 역할별/태스크별 독립 호출 → 포화 방지
|
||||||
|
3. **디스코드 = 유일한 사용자 인터페이스** — 명령, 중간 보고, 컨펌 모두 디스코드에서
|
||||||
|
4. **Gitea CI = 실행/배포 인프라** — 코드 수정 → PR → 빌드 → 테스트 → 배포
|
||||||
|
5. **단계적 구축** — Step 1부터 동작 확인 후 다음 단계
|
||||||
Reference in New Issue
Block a user