diff --git a/config.py b/config.py index a1d00ed..2189800 100644 --- a/config.py +++ b/config.py @@ -59,7 +59,7 @@ class Config(BaseSettings): whisper_model_size: str = "small" tts_voice: str = "Yuna" # macOS say 명령어 한국어 음성 - system_prompt: str = """모든 응답과 내부 사고 과정을 반드시 한국어로 작성하세요. + system_prompt: str = """모든 사고 과정(thinking)과 답변은 반드시 한국어로만 작성하세요. 영어 사용 절대 금지. 당신의 이름은 '율봇'입니다. 친절하고 따뜻한 한국어 상담 도우미입니다. 육아와 금융 두 분야를 전문으로 합니다. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 27ef1ec..ad2e55b 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -393,6 +393,22 @@ cd youlbot-webui && python app.py --- +## ✅ Phase 25 — RAG 출처 전용 접기/펼치기 박스 + +**배경**: RAG 검색 출처가 사고 과정(thinking)과 같은 `__meta` 토큰으로 섞여 "💭 분석 완료" 박스 안에 표시되던 문제. + +**구현 내용**: +- `agent_service.py`: 출처를 `{"__meta": "..."}` 개별 토큰 대신 `{"__sources": [{filename, page}, ...]}` 단일 토큰으로 yield +- `youlbot-webui/app.py`: + - `_sources_html()` 헬퍼 추가 — `
` 기반 접기/펼치기 + - chatbot 바로 아래 `source_box = gr.HTML()` 컴포넌트 추가 + - `respond()`에서 `__sources` 토큰 처리 → 답변 완료 후 "📄 출처 (N개)" 박스 표시 +- `youlbot-telegram/bot.py`: `__sources` 토큰 skip 처리 추가 + +**난이도**: 하 | **임팩트**: 중간 (UX 개선 — 출처와 사고 과정 분리) + +--- + ## Phase 20 — RAG 품질 자동 평가 (RAGAS) ★☆☆ **배경**: 청킹 전략·검색 파라미터·Reranker 변경 시 답변 품질이 실제로 나아졌는지 수치로 확인할 방법이 없다. @@ -484,6 +500,7 @@ Phase 20 RAGAS 평가 → Phase 15 (모델선택) → Phase 16 (Docke | Phase 22 REST API | ✅ 완료 | — | — | — | | Phase 23 WebUI 분리 | ✅ 완료 | — | — | — | | Phase 24 사고 과정 UI 분리 | ✅ 완료 | — | — | — | +| Phase 25 RAG 출처 전용 박스 | ✅ 완료 | — | — | — | | Phase 20 RAGAS 평가 | 🔲 신규 | 중간 | 중간 | 1순위 | | Phase 15 모델 선택 | 🔲 미완 | 중간 | 중간 | 4순위 | | Phase 16 Docker | 🔲 미완 | 높음 | 중간 | 5순위 | diff --git a/services/agent/agent_service.py b/services/agent/agent_service.py index 33eae66..146649f 100644 --- a/services/agent/agent_service.py +++ b/services/agent/agent_service.py @@ -79,7 +79,12 @@ class AgentService: async def call_model(state: MessagesState, config: RunnableConfig) -> dict: from datetime import date - system_content = f"오늘 날짜: {date.today().isoformat()}\n\n" + self._system_prompt + system_content = ( + "【언어 규칙】모든 사고 과정(thinking)과 답변을 반드시 한국어로 작성하세요. " + "영어 사용 금지. Think in Korean only.\n\n" + f"오늘 날짜: {date.today().isoformat()}\n\n" + + self._system_prompt + ) if self._profile_repo: profile = self._profile_repo.get_all(self._user_id) if profile: @@ -367,11 +372,13 @@ class AgentService: print(f"[Agent] 대화 저장 실패: {e}") if self._rag_show_sources and self._source_buffer: - yield {"__meta": "\n\n[참고 문서]\n"} + sources = [] for src in self._source_buffer: - filename = os.path.basename(src["source"]) - page = f" {src['page']}페이지" if "page" in src else "" - yield {"__meta": f"- {filename}{page}\n"} + entry = {"filename": os.path.basename(src["source"])} + if "page" in src: + entry["page"] = src["page"] + sources.append(entry) + yield {"__sources": sources} def reset(self) -> None: """새 thread_id로 대화 히스토리를 초기화한다."""