From e1d7e9cc216c36aacc52e6ff53579cad6546c7e4 Mon Sep 17 00:00:00 2001 From: sal Date: Wed, 27 May 2026 16:11:27 +0900 Subject: [PATCH] Merge ROADMAP.md and ROADMAP2.md into single roadmap - Combine Phase 4~7 history (ROADMAP.md) with Phase 9~14 and bug fixes (ROADMAP2.md) - Add bug 4 (age calculation) and Phase 13 Semantic Chunker to completed items - Remove ROADMAP2.md Co-Authored-By: Claude Sonnet 4.6 --- docs/ROADMAP.md | 216 ++++++++++++++++++++++++++++++++++++++++++--- docs/ROADMAP2.md | 224 ----------------------------------------------- 2 files changed, 206 insertions(+), 234 deletions(-) delete mode 100644 docs/ROADMAP2.md diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index b49836b..aa7e84b 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,17 +1,35 @@ # 율봇 개발 로드맵 -## 현재 구현 상태 (Phase 1~7 완료) +## 현재 구현 상태 | 영역 | 현황 | |------|------| -| LLM | Qwen2.5-7B-Instruct-4bit (MLX, Apple Silicon) | +| LLM | Qwen3-14B-4bit (MLX, Apple Silicon) | | Agent | LangGraph ReAct + Tool Calling + Thinking 모드 | -| RAG | Qdrant + BAAI/bge-m3 임베딩 | -| Tools | `search_documents`, `get_current_date`, `web_search`, `remember_user_info`, `recall_user_info` (5개) | -| UI | Gradio Web UI (`app.py`) + CLI (`main.py`) | -| Memory | LangGraph MemorySaver (세션 내) + MySQL (대화 영구 저장) + `td_user_profile` (장기 사용자 메모리) | +| RAG | Qdrant + BAAI/bge-m3 임베딩 + Semantic Chunking (`_SemanticSplitter`) | +| Tools | `search_documents`, `web_search`, `get_current_date`, `remember_user_info`, `recall_user_info` (5개) | +| UI | CLI + Gradio Web UI + 음성 입력(STT)/출력(TTS) | +| Memory | LangGraph MemorySaver (세션 내) + MySQL 대화 저장 + 장기 사용자 프로필 | +| Tracing | LangSmith 트레이싱 | | Streaming | 비동기 토큰 스트리밍 + `` 블록 파싱 | -| Tracing | LangSmith 트레이싱 설정 완료 (`.env`에서 활성화 가능) | +| History Compact | 대화 20턴 초과 시 오래된 절반을 LLM으로 자동 요약 (`CompactService`) | +| 나이 계산 | 시스템 프롬프트에 오늘 날짜 주입 + 한국 나이/만 나이 자동 계산 | + +--- + +## 버그 수정 현황 + +### ✅ 버그 1 — RAG 중복 수집 (수정 완료) +`IngestionService._delete_by_source()`를 구현해 같은 파일 경로로 저장된 기존 청크를 `ingest()` 시작 시 삭제한다. + +### ✅ 버그 2 — LangGraph MemorySaver와 MySQL 이력 미연동 (수정 완료) +`AgentService.__init__`에서 MySQL에 저장된 최근 10턴을 `_pending_history`로 불러온 뒤, 첫 `stream_response()` 호출 시 LangGraph 초기 메시지로 주입한다. + +### ✅ 버그 3 — 단일 사용자 전제 (수정 완료) +DB 스키마(`td_conversations.user_id`, `td_user_profile.user_id`)는 `_migrate_schema`로 자동 마이그레이션. `AgentService`에 `user_id` 파라미터 추가, 모든 Repository 호출에 전파. Gradio에 사용자 선택 드롭다운(아록/근혜/도율/하율) 추가 및 사용자별 에이전트 캐시 구현. + +### ✅ 버그 4 — 나이 계산 오류 (수정 완료) +LLM이 훈련 데이터 기준 연도로 나이를 계산하는 문제. `AgentService.call_model()`에서 매 호출 시 시스템 프롬프트 앞에 `오늘 날짜: {date.today().isoformat()}`를 주입. 프로필에서 생년월일/생년 값을 파싱해 한국 나이(현재연도-출생연도+1)와 만 나이(생일 기준 정확 계산)를 자동 계산해 시스템 프롬프트에 포함. --- @@ -47,10 +65,188 @@ --- -## Phase 8 — 멀티모달 이미지 이해 ★☆☆ +## ✅ Phase 9 — 문서 관리 -**배경**: 이유식 사진 → "이 재료로 만들 수 있는 이유식은?", 금융 서류 사진 → 내용 분석 등 이미지 기반 질문 처리. +- `IngestionService._delete_by_source()` — 파일 경로 기반 중복 청크 삭제 +- `RetrieverService.list_documents()` — Qdrant scroll로 고유 source 목록 반환 +- `RetrieverService.delete_document(source)` — source 기준 청크 전체 삭제 +- Gradio "문서 관리" 탭 — 목록 테이블 + 경로 입력 삭제 버튼 + 앱 로드 시 자동 새로고침 -**제약**: Qwen2.5-7B는 이미지 미지원 → `mlx-community/Qwen2.5-VL-7B-Instruct-4bit` 모델 교체 필요. +--- + +## ✅ Phase 10 — 멀티유저 지원 + +Bug 3 수정 및 Phase 9 작업과 함께 완전 구현됨. + +- DB 마이그레이션: `mysql_service._migrate_schema()`가 `td_conversations`, `td_user_profile` 양쪽에 `user_id` 컬럼 자동 추가 +- `ConversationRepository`: `create_conversation(user_id)` / `get_latest_conversation_id(user_id)` — user_id 기반 격리 +- `AgentService`: `user_id` 파라미터 추가, 모든 프로필·대화 조회에 전파 +- `make_memory_tools(profile_repo, user_id)`: remember/recall 도구가 올바른 사용자 데이터만 접근 +- Gradio: 사용자 선택 드롭다운(아록/근혜/도율/하율, 기본값 아록) + `_agent_cache` 사전으로 사용자별 에이전트 분리 + +--- + +## ✅ Phase 11 — 대화 이력 복원 + +버그 2와 함께 해결됨. `AgentService` 초기화 시 MySQL에서 최근 10턴을 `_pending_history`에 로드 → 첫 메시지와 함께 LangGraph에 주입. + +```python +turns = conversation_repository.load_turns_after(self._conv_id, None, limit=10) +# → HumanMessage / AIMessage 변환 후 _pending_history에 저장 +``` + +--- + +## Phase 12 — 답변 피드백 & 품질 개선 ★★☆ + +**배경**: 에이전트가 잘못된 답변을 해도 피드백 루프가 없어 개선이 어려움. + +**구현 범위**: +- Gradio 채팅 메시지마다 👍 / 👎 버튼 +- `td_feedback` 테이블에 메시지·평점 저장 +- LangSmith의 `run_id`와 연결해 피드백을 트레이스에 기록 (`langsmith.Client().create_feedback()`) + +```sql +CREATE TABLE td_feedback ( + id INT AUTO_INCREMENT PRIMARY KEY, + message TEXT, + response TEXT, + rating TINYINT, -- 1: 좋음, -1: 나쁨 + langsmith_run_id VARCHAR(100), + created_at DATETIME DEFAULT CURRENT_TIMESTAMP +); +``` + +**난이도**: 중간 | **임팩트**: 중간 (장기 품질 향상) + +--- + +## Phase 13 — RAG 품질 향상 ★★☆ (부분 완료) + +**배경**: 고정 크기 청킹 + 벡터 유사도 검색만으로는 관련 없는 청크가 섞일 수 있음. + +**✅ Semantic Chunker — 완료** +- `_SemanticSplitter` 클래스 직접 구현 (`services/rag/ingestion_service.py`) +- `langchain-experimental` 사용 없이 numpy + 기존 BAAI/bge-m3 임베딩으로 구현 +- 인접 문장 간 코사인 유사도 계산 → 유사도 하위 5% 지점에서 청크 분리 +- `config.py`에서 `rag_chunk_size` / `rag_chunk_overlap` 제거 → `semantic_breakpoint_threshold_type` 추가 + +**🔲 미완 — Reranker** +1. **Reranker 추가** — `cross-encoder/ms-marco-MiniLM-L-6-v2`로 검색 결과 재순위 +2. **top_k 조정** — 검색 후 rerank → 상위 3개만 LLM에 전달 + +> 기존 Qdrant 저장 문서는 재등록해야 새 청킹 방식이 적용됨. + +**난이도**: 중간 | **임팩트**: 중간 (답변 정확도 향상) + +--- + +## ✅ Phase 14 — 음성 인터페이스 + +**배경**: 육아 중에는 손이 자유롭지 않아 타이핑이 어려움. + +**구현 내용**: +- `openai-whisper` (small 모델) — 마이크 녹음 → 한국어 텍스트 변환, 지연 로딩 +- macOS `say -v Yuna` — 에이전트 응답을 음성으로 읽어줌 (aiff 파일 경유) +- Gradio "대화" 탭 확장 — 마이크 녹음 + "음성→텍스트 변환" 버튼 + "음성으로 답변 읽기" 체크박스 + TTS 오디오 플레이어 +- LLM/Agent 레이어 변경 없음 — 순수 I/O 어댑터로 구현 + +**config.py 추가**: `whisper_model_size = "small"`, `tts_voice = "Yuna"` + +**난이도**: 중간 | **임팩트**: 높음 (핵심 사용 시나리오) + +--- + +## Phase 15 — 예방접종·건강검진 알림 스케줄러 ★★☆ + +**배경**: 아이 생년을 기억하고 있으므로, 예방접종 일정(BCG, DTaP 등)을 자동 계산해 알림을 줄 수 있음. 율봇의 차별화 포인트. + +**구현 방식**: +- `td_user_profile`에서 아이 생년 조회 → 예방접종 스케줄 계산 Tool +- Gradio "건강 일정" 탭: 달력형 일정 표시 +- APScheduler로 당일 알림 (또는 Gradio 시작 시 오늘 일정 배너) + +```python +@tool +def get_vaccination_schedule(birth_year: int, birth_month: int) -> str: + """아이 생년월을 기반으로 예방접종 일정을 계산합니다.""" +``` + +**난이도**: 중간 | **임팩트**: 높음 (육아 특화 차별화) + +--- + +## Phase 16 — 모델 선택 (Claude API / OpenAI 옵션) ★☆☆ + +**배경**: 로컬 MLX 모델은 Apple Silicon 전용. 원격 접속 시나리오나 더 높은 품질이 필요할 때 Claude API/OpenAI를 선택할 수 있으면 유연성 확보. + +**구현 방식**: `config.py`에 `model_provider` 추가, `container.py`에서 provider별 chat_model 분기. + +```python +model_provider: str = "mlx" # "mlx" | "claude" | "openai" +``` + +**난이도**: 중간 | **임팩트**: 중간 + +--- + +## Phase 17 — Docker 컨테이너화 ★☆☆ + +**배경**: 현재 로컬 전용. 가족이나 지인도 쓸 수 있도록 서버 배포 가능한 형태로 패키징. + +**구현 범위**: +``` +docker-compose.yml +├── youlbot (Gradio app) +├── qdrant +└── mysql +``` + +> 주의: MLX는 Apple Silicon 전용이라 서버 배포 시 Phase 16(모델 선택)이 선행되어야 함. + +**난이도**: 높음 | **임팩트**: 중간 + +--- + +## Phase 18 — 멀티모달 이미지 이해 ★☆☆ + +**배경**: 이유식 사진 → 재료 분석, 금융 서류 사진 → 내용 해석 등. + +**제약**: Qwen3-14B는 이미지 미지원 → `mlx-community/Qwen2.5-VL-7B-Instruct-4bit` 교체 필요. **난이도**: 높음 | **임팩트**: 높음 (장기 과제) + +--- + +## 추천 진행 순서 + +``` +단기 (1~2주) 중기 (1개월) 장기 +──────────────── ────────────────── ────────────── +Phase 15 (알림) → Phase 13 Reranker → Phase 17 (Docker) +Phase 12 (피드백) Phase 16 (모델선택) Phase 18 (멀티모달) +``` + +### 우선순위 매트릭스 + +| Phase | 상태 | 난이도 | 임팩트 | 추천 순위 | +|-------|------|--------|--------|-----------| +| 버그 1 RAG 중복 | ✅ 완료 | — | — | — | +| 버그 2 이력 미연동 | ✅ 완료 | — | — | — | +| 버그 3 단일 사용자 | ✅ 완료 | — | — | — | +| 버그 4 나이 계산 오류 | ✅ 완료 | — | — | — | +| Phase 4 Web UI | ✅ 완료 | — | — | — | +| Phase 5 장기 사용자 메모리 | ✅ 완료 | — | — | — | +| Phase 6 웹 검색 | ✅ 완료 | — | — | — | +| Phase 7 LangSmith 트레이싱 | ✅ 완료 | — | — | — | +| Phase 9 문서 관리 | ✅ 완료 | — | — | — | +| Phase 10 멀티유저 | ✅ 완료 | — | — | — | +| Phase 11 이력 복원 | ✅ 완료 | — | — | — | +| Phase 13 Semantic Chunker | ✅ 완료 | — | — | — | +| Phase 14 음성 인터페이스 | ✅ 완료 | — | — | — | +| Phase 15 예방접종 알림 | 🔲 미완 | 중간 | 높음 | ⭐ 1순위 | +| Phase 12 피드백 | 🔲 미완 | 중간 | 중간 | 2순위 | +| Phase 13 Reranker | 🔲 진행 중 | 중간 | 중간 | 3순위 | +| Phase 16 모델 선택 | 🔲 미완 | 중간 | 중간 | 4순위 | +| Phase 17 Docker | 🔲 미완 | 높음 | 중간 | 5순위 | +| Phase 18 멀티모달 | 🔲 미완 | 높음 | 높음 | 6순위 | diff --git a/docs/ROADMAP2.md b/docs/ROADMAP2.md deleted file mode 100644 index 1e7fdb1..0000000 --- a/docs/ROADMAP2.md +++ /dev/null @@ -1,224 +0,0 @@ -# 율봇 개발 로드맵 2 - -## 현재 구현 상태 (Phase 1~11 + Phase 14 완료, 버그 1~3 수정 완료, 모델 업그레이드) - -| 영역 | 현황 | -|------|------| -| LLM | Qwen3-14B-4bit (MLX, Apple Silicon) | -| Agent | LangGraph ReAct + Tool Calling + Thinking 모드 | -| RAG | Qdrant + BAAI/bge-m3 임베딩 | -| Tools | `search_documents`, `web_search`, `get_current_date`, `remember_user_info`, `recall_user_info` (5개) | -| UI | CLI + Gradio Web UI | -| Memory | LangGraph MemorySaver (세션 내) + MySQL 대화 저장 + 장기 사용자 프로필 | -| Tracing | LangSmith 트레이싱 | -| Streaming | 비동기 토큰 스트리밍 + `` 블록 파싱 | -| History Compact | 대화 20턴 초과 시 오래된 절반을 LLM으로 자동 요약 (`CompactService`) | - ---- - -## 버그 수정 현황 - -### ✅ 버그 1 — RAG 중복 수집 (수정 완료) -`IngestionService._delete_by_source()`를 구현해 같은 파일 경로로 저장된 기존 청크를 `ingest()` 시작 시 삭제한다. - -### ✅ 버그 2 — LangGraph MemorySaver와 MySQL 이력 미연동 (수정 완료) -`AgentService.__init__`에서 MySQL에 저장된 최근 10턴을 `_pending_history`로 불러온 뒤, 첫 `stream_response()` 호출 시 LangGraph 초기 메시지로 주입한다. - -### ✅ 버그 3 — 단일 사용자 전제 (수정 완료) -DB 스키마(`td_conversations.user_id`, `td_user_profile.user_id`)는 `_migrate_schema`로 자동 마이그레이션. `AgentService`에 `user_id` 파라미터 추가, 모든 Repository 호출에 전파. Gradio에 사용자 선택 드롭다운(아록/근혜/도율/하율) 추가 및 사용자별 에이전트 캐시 구현. - ---- - -## ✅ Phase 9 — 문서 관리 (완료) - -- `IngestionService._delete_by_source()` — 파일 경로 기반 중복 청크 삭제 -- `RetrieverService.list_documents()` — Qdrant scroll로 고유 source 목록 반환 -- `RetrieverService.delete_document(source)` — source 기준 청크 전체 삭제 -- Gradio "문서 관리" 탭 — 목록 테이블 + 경로 입력 삭제 버튼 + 앱 로드 시 자동 새로고침 - ---- - -## ✅ Phase 10 — 멀티유저 지원 (완료) - -Bug 3 수정 및 Phase 9 작업과 함께 완전 구현됨. - -- DB 마이그레이션: `mysql_service._migrate_schema()`가 `td_conversations`, `td_user_profile` 양쪽에 `user_id` 컬럼 자동 추가 -- `ConversationRepository`: `create_conversation(user_id)` / `get_latest_conversation_id(user_id)` — user_id 기반 격리 -- `AgentService`: `user_id` 파라미터 추가, 모든 프로필·대화 조회에 전파 -- `make_memory_tools(profile_repo, user_id)`: remember/recall 도구가 올바른 사용자 데이터만 접근 -- Gradio: 사용자 선택 드롭다운(아록/근혜/도율/하율, 기본값 아록) + `_agent_cache` 사전으로 사용자별 에이전트 분리 - ---- - -## ✅ Phase 11 — 대화 이력 복원 (수정 완료) - -버그 2와 함께 해결됨. -`AgentService` 초기화 시 MySQL에서 최근 10턴을 `_pending_history`에 로드 → 첫 메시지와 함께 LangGraph에 주입. - -```python -# agent_service.py 초기화 (구현됨) -turns = conversation_repository.load_turns_after(self._conv_id, None, limit=10) -# → HumanMessage / AIMessage 변환 후 _pending_history에 저장 -``` - ---- - -## Phase 12 — 답변 피드백 & 품질 개선 ★★☆ - -**배경**: 에이전트가 잘못된 답변을 해도 피드백 루프가 없어 개선이 어려움. - -**구현 범위**: -- Gradio 채팅 메시지마다 👍 / 👎 버튼 -- `td_feedback` 테이블에 메시지·평점 저장 -- LangSmith의 `run_id`와 연결해 피드백을 트레이스에 기록 (`langsmith.Client().create_feedback()`) - -```sql -CREATE TABLE td_feedback ( - id INT AUTO_INCREMENT PRIMARY KEY, - message TEXT, - response TEXT, - rating TINYINT, -- 1: 좋음, -1: 나쁨 - langsmith_run_id VARCHAR(100), - created_at DATETIME DEFAULT CURRENT_TIMESTAMP -); -``` - -**난이도**: 중간 | **임팩트**: 중간 (장기 품질 향상) - ---- - -## Phase 13 — RAG 품질 향상 (Reranker + 청킹 개선) ★★☆ (부분 완료) - -**배경**: 현재 고정 크기 청킹 + 벡터 유사도 검색만으로는 관련 없는 청크가 섞일 수 있음. - -**✅ Semantic Chunker — 완료** -- `_SemanticSplitter` 클래스 직접 구현 (`services/rag/ingestion_service.py`) -- `langchain-experimental` 사용 없이 numpy + 기존 BAAI/bge-m3 임베딩으로 구현 -- 인접 문장 간 코사인 유사도 계산 → 유사도 하위 5% 지점에서 청크 분리 -- `config.py`에서 `rag_chunk_size` / `rag_chunk_overlap` 제거 → `semantic_breakpoint_threshold_type` 추가 - -**🔲 미완 — Reranker** -1. **Reranker 추가** — `cross-encoder/ms-marco-MiniLM-L-6-v2`로 검색 결과 재순위 -2. **top_k 조정** — 검색 후 rerank → 상위 3개만 LLM에 전달 - -> 기존 Qdrant 저장 문서는 재등록해야 새 청킹 방식이 적용됨. - -**난이도**: 중간 | **임팩트**: 중간 (답변 정확도 향상) - ---- - -## ✅ Phase 14 — 음성 인터페이스 (완료) - -**배경**: 육아 중에는 손이 자유롭지 않아 타이핑이 어려움. 음성으로 질문하고 답변을 들을 수 있으면 핵심 사용 시나리오 커버. - -**구현 내용**: -- `openai-whisper` (small 모델) — 마이크 녹음 → 한국어 텍스트 변환, 지연 로딩 -- macOS `say -v Yuna` — 에이전트 응답을 음성으로 읽어줌 (aiff 파일 경유) -- Gradio "대화" 탭 확장 — 마이크 녹음 + "음성→텍스트 변환" 버튼 + "음성으로 답변 읽기" 체크박스 + TTS 오디오 플레이어 -- LLM/Agent 레이어 변경 없음 — 순수 I/O 어댑터로 구현 - -```python -# app.py — STT -def transcribe_audio(filepath: str) -> str: - result = whisper.load_model("small").transcribe(filepath, language="ko") - return result["text"].strip() - -# app.py — TTS -def tts_speak(text: str, voice: str) -> str | None: - subprocess.run(["say", "-v", voice, "-o", tmp.name, text], ...) -``` - -**config.py 추가**: `whisper_model_size = "small"`, `tts_voice = "Yuna"` - -**난이도**: 중간 | **임팩트**: 높음 (핵심 사용 시나리오) - ---- - -## Phase 15 — 예방접종·건강검진 알림 스케줄러 ★★☆ - -**배경**: 아이 생년을 기억하고 있으므로, 예방접종 일정(BCG, DTaP 등)을 자동 계산해 알림을 줄 수 있음. 율봇의 차별화 포인트. - -**구현 방식**: -- `td_user_profile`에서 아이 생년 조회 → 예방접종 스케줄 계산 Tool -- Gradio "건강 일정" 탭: 달력형 일정 표시 -- APScheduler로 당일 알림 (또는 Gradio 시작 시 오늘 일정 배너) - -```python -@tool -def get_vaccination_schedule(birth_year: int, birth_month: int) -> str: - """아이 생년월을 기반으로 예방접종 일정을 계산합니다.""" -``` - -**난이도**: 중간 | **임팩트**: 높음 (육아 특화 차별화) - ---- - -## Phase 16 — 모델 선택 (Claude API / OpenAI 옵션) ★☆☆ - -**배경**: 로컬 MLX 모델은 Apple Silicon 전용. 원격 접속 시나리오나 더 높은 품질이 필요할 때 Claude API/OpenAI를 선택할 수 있으면 유연성 확보. - -**구현 방식**: `config.py`에 `model_provider` 추가, `container.py`에서 provider별 chat_model 분기. - -```python -model_provider: str = "mlx" # "mlx" | "claude" | "openai" -``` - -**난이도**: 중간 | **임팩트**: 중간 - ---- - -## Phase 17 — Docker 컨테이너화 ★☆☆ - -**배경**: 현재 로컬 전용. 가족이나 지인도 쓸 수 있도록 서버 배포 가능한 형태로 패키징. - -**구현 범위**: -``` -docker-compose.yml -├── youlbot (Gradio app) -├── qdrant -└── mysql -``` - -> 주의: MLX는 Apple Silicon 전용이라 서버 배포 시 Phase 16(모델 선택)이 선행되어야 함. - -**난이도**: 높음 | **임팩트**: 중간 - ---- - -## Phase 18 — 멀티모달 이미지 이해 ★☆☆ - -**배경**: 이유식 사진 → 재료 분석, 금융 서류 사진 → 내용 해석 등. - -**제약**: Qwen3-8B는 이미지 미지원 → `mlx-community/Qwen2.5-VL-7B-Instruct-4bit` 교체 필요. - -**난이도**: 높음 | **임팩트**: 높음 (장기 과제) - ---- - -## 추천 진행 순서 - -``` -단기 (1~2주) 중기 (1개월) 장기 -──────────────── ────────────────── ────────────── -Phase 14 (음성) → Phase 13 (RAG품질) → Phase 17 (Docker) -Phase 15 (알림) Phase 16 (모델선택) Phase 18 (멀티모달) -Phase 12 (피드백) -``` - -### 우선순위 매트릭스 - -| Phase | 상태 | 난이도 | 임팩트 | 추천 순위 | -|-------|------|--------|--------|-----------| -| 버그 1 RAG 중복 | ✅ 완료 | — | — | — | -| 버그 2 이력 미연동 | ✅ 완료 | — | — | — | -| 버그 3 단일 사용자 | ✅ 완료 | — | — | — | -| Phase 9 문서 관리 | ✅ 완료 | — | — | — | -| Phase 10 멀티유저 | ✅ 완료 | — | — | — | -| Phase 11 이력 복원 | ✅ 완료 | — | — | — | -| Phase 14 음성 인터페이스 | ✅ 완료 | — | — | — | -| Phase 15 예방접종 알림 | 🔲 미완 | 중간 | 높음 | ⭐ 2순위 | -| Phase 12 피드백 | 🔲 미완 | 중간 | 중간 | 3순위 | -| Phase 13 RAG 품질 (청킹 완료, Reranker 미완) | 🔲 진행 중 | 중간 | 중간 | 4순위 | -| Phase 16 모델 선택 | 🔲 미완 | 중간 | 중간 | 5순위 | -| Phase 17 Docker | 🔲 미완 | 높음 | 중간 | 6순위 | -| Phase 18 멀티모달 | 🔲 미완 | 높음 | 높음 | 7순위 |