IDEA-2/1/5/7: 스마트 알림, 대화 기반 RAG, CRAG, 파라미터 자동 튜닝

- IDEA-2 스마트 알림: td_reminders 테이블, set_reminder/list_reminders 도구,
  SchedulerService(asyncio 60초 루프, D-7/D-1/D-0 Telegram push),
  FastAPI lifespan 연동, GET /reminders/{user_id} 엔드포인트

- IDEA-1 대화 기반 RAG: IngestionService.store_text() 추가,
  AgentService._maybe_index_conversation() — 응답 후 LLM 판단 → Qdrant 저장
  (CONV_RAG_ENABLED=true 활성화, background task로 응답 속도 무관)

- IDEA-5 CRAG: AgentState에 crag_fallback_used 플래그 추가,
  crag_check LangGraph 노드 — search_documents 결과 없으면 web_search 자동 주입,
  route_after_crag으로 fallback 1회 루프 제어 (CRAG_ENABLED=true 활성화)

- IDEA-7 RAG Auto-Eval: eval/auto_tune.py — API 서버 없이 파라미터 조합별
  context_precision/recall 비교, 최적 설정 추천

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sal
2026-06-04 10:04:05 +09:00
parent c264573a67
commit 0b50444e43
11 changed files with 715 additions and 11 deletions
+12
View File
@@ -110,6 +110,18 @@ class DatabaseService:
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")
cursor.execute("""
CREATE TABLE IF NOT EXISTS td_reminders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
remind_date DATE NOT NULL,
message TEXT NOT NULL,
sent_d0 TINYINT(1) NOT NULL DEFAULT 0,
sent_d1 TINYINT(1) NOT NULL DEFAULT 0,
sent_d7 TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")
conn.commit()
self._migrate_schema(conn)
+57
View File
@@ -0,0 +1,57 @@
from __future__ import annotations
from datetime import date, timedelta
from services.db.mysql_service import DatabaseService
class ReminderRepository:
"""td_reminders 테이블을 통한 알림 저장소."""
def __init__(self, db: DatabaseService):
self._db = db
def add(self, user_id: str, remind_date: date, message: str) -> int:
return self._db.execute_write(
"INSERT INTO td_reminders (user_id, remind_date, message) VALUES (%s, %s, %s)",
(user_id, remind_date.isoformat(), message),
)
def get_upcoming(self, user_id: str, days_ahead: int = 30) -> list[dict]:
today = date.today()
limit = today + timedelta(days=days_ahead)
return self._db.execute(
"""SELECT id, remind_date, message
FROM td_reminders
WHERE user_id = %s AND remind_date >= %s AND remind_date <= %s
ORDER BY remind_date""",
(user_id, today.isoformat(), limit.isoformat()),
)
def get_due(self, today: date) -> list[dict]:
"""D-0(당일), D-1(내일), D-7(7일 후) 미발송 알림 반환."""
d1 = today + timedelta(days=1)
d7 = today + timedelta(days=7)
return self._db.execute(
"""SELECT *,
CASE
WHEN remind_date = %s THEN 'd0'
WHEN remind_date = %s THEN 'd1'
WHEN remind_date = %s THEN 'd7'
END AS notify_type
FROM td_reminders
WHERE (remind_date = %s AND sent_d0 = 0)
OR (remind_date = %s AND sent_d1 = 0)
OR (remind_date = %s AND sent_d7 = 0)""",
(
today.isoformat(), d1.isoformat(), d7.isoformat(),
today.isoformat(), d1.isoformat(), d7.isoformat(),
),
)
def mark_sent(self, reminder_id: int, notify_type: str) -> None:
col = {"d0": "sent_d0", "d1": "sent_d1", "d7": "sent_d7"}.get(notify_type)
if col:
self._db.execute_write(
f"UPDATE td_reminders SET {col} = 1 WHERE id = %s",
(reminder_id,),
)