Skip to content

feat: add metadata first chatbot responses and optimize rule_book dir… - #103

Merged
Yu-JeSeung merged 3 commits into
mainfrom
feat/chatbot_timeout
May 4, 2026
Merged

feat: add metadata first chatbot responses and optimize rule_book dir…#103
Yu-JeSeung merged 3 commits into
mainfrom
feat/chatbot_timeout

Conversation

@Yu-JeSeung

@Yu-JeSeung Yu-JeSeung commented May 4, 2026

Copy link
Copy Markdown
Contributor

관련 이슈

Close #102

🎯 배경

  • 챗봇 학사일정 질의에서 시험기간, 종강, 졸업식/학위수여식 관련 답변이 사용자 의도와 다르게 검색되거나 OSS 응답으로 넘어가는 문제가 있었습니다.
  • OSS 호출이 느릴 때 짧은 추가 입력까지 로딩 상태로 쌓이는 현상을 완화할 필요가 있었습니다.

🔍 주요 내용

  • 시험기간 질의가 중간고사와 기말고사를 함께 반환하도록 일정 태그 규칙을 보강했습니다.
  • 종강 질의는 기말고사 종료일 기준으로 응답하도록 처리했습니다.
  • 졸업식/학위수여식 질의에서 후기 학위수여식을 뒤로 정렬하고, 일정 검색을 우선하도록 조정했습니다.
  • 종업식 오타를 졸업식 의도로 처리하도록 추가했습니다.
  • OSS 호출을 별도 executor로 분리하고, 2글자 이하 짧은 OSS 입력은 즉시 안내 응답하도록 개선했습니다.
  • 일정명 안의 시간 표기(11:00) 때문에 포맷터가 일정을 누락하던 정규식 문제를 수정했습니다.
  • 25년도 졸업식 알려줘 회귀 케이스를 추가했습니다.

변경 요약

챗봇이 메타데이터 기반 응답을 우선하고, 시험/졸업식 관련 스케줄 처리와 OSS 호출 흐름을 개선했습니다. 정규식 버그 수정과 회귀 테스트도 추가되었습니다.

주요 변경점

  • "종업식" 오타를 졸업식 의도로 매핑해 동의어로 처리(CEREMONY_RE, schedule_rules)
  • 메타데이터 우선 응답 도입: metadata_direct_answer(), confident_search_answer()로 연락처·학점 등 직접 추출
  • OSS 호출 분리 및 비동기화: call_oss_async() 추가, 2자 이하 입력은 바로 인사/안내로 처리해 블로킹 방지
  • 스케줄 규칙 강화: 중간/기말 키워드 확장 및 시험 쿼리 시 MIDTERM+FINAL 동시 반환, 종강은 기말 종료일 사용
  • 정규식 개선: SCHED_LINE_PATTERN 타이틀 캡처를 non-greedy로 변경해 시간 표기(예: "11:00")로 인한 파싱 누락 해결
  • rule_book 및 검색 로직 개선: 직접 답변 우선화, LLM 타임아웃/토큰 제한 추가, 검색 기반 구조화 폴백 응답 제공
  • 회귀 테스트 추가: "25년도 졸업식 알려줘" 케이스(2025-02-21 포함)

주의/리스크

  • non-greedy 타이틀 캡처로 인해 일부 타이틀 분할이 달라질 수 있음(콜론 위치 의존)
  • 메타데이터 기반 응답은 인덱스된 문서 품질에 따라 오답 위험 존재
  • OSS 비동기/타임아웃 변화로 동시성·타임아웃 엣지케이스 모니터링 필요

다음 액션

  • 졸업식/종업식 관련 실제 쿼리로 응답 순서 및 후기 학위수여식 배치 검증
  • 메타데이터 추출(학점·연락처) 정확도와 인덱스 품질 점검
  • OSS 짧은 입력 안내 메시지 UX 적합성 검토 및 필요 시 안내 문구 조정

@Yu-JeSeung Yu-JeSeung self-assigned this May 4, 2026
@Yu-JeSeung Yu-JeSeung added the feat label May 4, 2026
@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ee274d6a-6735-4f40-9e00-7a538bd7bc7c

📥 Commits

Reviewing files that changed from the base of the PR and between bae0e78 and 80f0728.

📒 Files selected for processing (2)
  • LLM/sub_model/query_index.py
  • LLM/sub_model/schedule_rules.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • LLM/sub_model/query_index.py

📝 Walkthrough

Walkthrough

종업식 키워드가 스케줄/행사 인식에 추가되고, 메타데이터 기반 직접 답변(연락처·졸업학점)과 신뢰도 기반 검색 답변이 도입되며, OSS 비동기 호출 경로 및 규칙책/스케줄 파싱·정렬 로직이 개선되었습니다.

Changes

메타데이터 기반 직접 답변 및 서비스 통합

Layer / File(s) Summary
데이터 및 헬퍼 추가
LLM/sub_model/query_index.py
직접 답변용 상수(DIRECT_SNIPPET_MAX_CHARS, CONFIDENT_SCORE_THRESHOLD, CONFIDENT_SCORE_GAP) 및 텍스트/쿼리 유틸리티(_compact, _query_terms, _clean_snippet, _source_suffix) 추가.
메타데이터 직접 답변 로직
LLM/sub_model/query_index.py
_metadata_contact_answer(), _metadata_grad_answer() 구현 및 이를 호출하는 metadata_direct_answer() 추가.
신뢰도 기반 검색 응답
LLM/sub_model/query_index.py
confident_search_answer(query, top_k=3) 추가: 하이브리드 검색 결과의 점수 기준과 top-vs-2nd 갭 검증 후 소스 포함 단답 반환.
서비스 계층 통합 (비동기 OSS 포함)
LLM/OSS/service.py
_oss_executor 스레드풀과 call_oss_async() 추가, call_oss()timeout 명시. chat_with_oss()에서 compact 입력 길이 기반 greet 분기, metadata_direct_answerconfident_search_answer 사용으로 여러 모드(fast, policy, grad, oss)에서 조기 반환 로직 도입. OSS 융합 호출을 call_oss_async(..., max_tokens=96, timeout=45)로 변경.
스케줄/행사 키워드 확장
LLM/OSS/modes.py, LLM/sub_model/schedule_rules.py
CEREMONY_RE, SCHEDULE_HINTS_BASE, looks_like_schedule()COMMENCEMENT 규칙에 종업식 추가; MIDTERM/FINAL 키워드 확장.
테스트 추가
tests/regression/chatbot_regression_cases.json
“25년도 졸업식 알려줘” 회귀 케이스 추가 (expect 2025-02-21, engine: fast).

규칙 책 및 스케줄/패턴 개선

Layer / File(s) Summary
정규식·패턴 변경
LLM/patterns.py
SCHED_LINE_PATTERNtitle 캡처를 (?P<title>.+?):로 비탐욕 매칭으로 변경.
스케줄 태그 규칙 확장
LLM/sub_model/schedule_rules.py
MIDTERM, FINALquery_keywords/title_pattern 확대; tags_for_query()가 쿼리에 시험/고사 포함 시 MIDTERM·FINAL을 자동 추가.
스케줄 검색 정렬·출력 개선
LLM/sub_model/schedule_index.py
commencement_query, semester_end_query 플래그 적용, 후기(후기 졸업식) 고려 정렬 키 추가 및 학기말 쿼리의 출력 포맷(“종강(기말고사 종료일)”) 특수 처리.
규칙책(그래프) 개선
LLM/rule_book/graph.py
re·설정 상수(LLM_TOP_K, LLM_MAX_TOKENS, LLM_TIMEOUT_SECONDS) 추가, 쿼리·텍스트 처리 헬퍼, 청크 기반 결정론적 직접 답변 및 폴백 생성 추가. generate()는 직접 답변 시도 → 상위 K 청크로 LLM 호출(타임아웃 적용) → 예외 시 청크 폴백 반환으로 변경.

Sequence Diagram

sequenceDiagram
    participant User
    participant Service as chat_with_oss()
    participant Meta as query_index\n(metadata_direct_answer)
    participant Conf as query_index\n(confident_search_answer)
    participant OSS as call_oss_async()
    participant Rule as rule_book\n(generate)

    User->>Service: 사용자 입력 (압축)
    alt metadata_direct_answer 반환
        Service->>Meta: metadata_direct_answer(query)
        Meta-->>Service: {text, url} 또는 None
        Service-->>User: engine: "fast" (metadata 답변)
    else confident_search 반환
        Service->>Conf: confident_search_answer(query)
        Conf-->>Service: {text, url} 또는 None
        Service-->>User: engine: "fast" (confident 검색)
    else OSS 융합생성
        Service->>OSS: call_oss_async(messages, max_tokens=96, timeout=45)
        OSS-->>Service: fused 텍스트
        alt 규칙책 폴백 필요
            Service->>Rule: generate(query)
            Rule-->>Service: direct 또는 fallback 텍스트
        end
        Service-->>User: engine: "oss" 또는 "fast" (fused/폴백)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 메타데이터 기반 응답 추가와 rule_book 최적화라는 주요 변경사항을 포함하지만, 잘려있어 완전하지 않고 여러 주요 개선사항(OSS 비동기 호출, 스케줄 태그 규칙 강화, 정규식 수정)을 명시하지 않습니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고, 이슈 번호, 배경, 주요 내용을 포함하며 변경사항을 한국어로 명확하게 설명합니다. 템플릿의 필수 섹션이 모두 충실하게 작성되어 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/chatbot_timeout

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@Yu-JeSeung Yu-JeSeung added the fix label May 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
LLM/OSS/service.py (1)

311-314: ⚡ Quick win

의식 키워드 목록은 여기서 다시 하드코딩하지 않는 편이 좋습니다.

같은 분기 기준이 이미 LLM/OSS/modes.py에 있는데, 여기서 별도 튜플로 한 번 더 관리하고 있습니다. 이번 PR처럼 둘을 같이 수정해야 하고, 다음에 한쪽만 바뀌면 모드 판별은 fast인데 이 shortcut만 안 타는 식으로 금방 어긋납니다. CEREMONY_RE나 공용 헬퍼를 재사용하는 쪽이 안전합니다.

♻️ 한 가지 정리 방법
-from LLM.OSS.modes import (
+from LLM.OSS.modes import (
+    CEREMONY_RE,
     COUNCIL_KWS,
     GOVERNANCE_REMOVE_RE,
     GOVERNANCE_TARGET_RE,
     GREETING_RE,
     RELATIVE_DATE_KEYWORDS,
@@
-        if any(keyword in user_text for keyword in ("종강", "졸업식", "종업식", "학위수여식")):
+        if "종강" in user_text or CEREMONY_RE.search(user_text):
             schedule_only = schedule_search(user_text, top_k=8)
             if schedule_only:
                 return cache_and_return({"engine": "fast", "text": render_chatty_schedule(schedule_only, user_text)})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@LLM/OSS/service.py` around lines 311 - 314, Replace the hardcoded ceremony
keywords tuple in the conditional with the shared ceremony matcher used in modes
(reuse CEREMONY_RE or the public helper from LLM/OSS/modes.py); update the check
to use CEREMONY_RE.search(user_text) (or the exported helper function) so the
branch that calls schedule_search(top_k=8) and returns via
cache_and_return({"engine":"fast","text":render_chatty_schedule(...)}) stays
identical but centralizes the keyword list, and add the necessary import for
CEREMONY_RE/helper at the top of this module.
tests/regression/chatbot_regression_cases.json (1)

14-19: ⚡ Quick win

종업식 경로도 회귀 테스트로 묶어두는 편이 좋겠습니다.

이번 PR의 핵심 변경 중 하나가 종업식 오타 매핑인데, 현재 추가된 케이스는 정상 표기인 졸업식만 검증합니다. 그래서 LLM/OSS/modes.py, LLM/sub_model/schedule_rules.py, LLM/OSS/service.py 중 한 곳에서 다시 빠져도 이 테스트로는 못 잡습니다.

🧪 예시 케이스
   {
     "id": "schedule_commencement_25_calendar_year",
     "text": "25년도 졸업식 알려줘",
     "engine_in": ["fast"],
     "all_of_text_contains": ["2025-02-21"]
   },
+  {
+    "id": "schedule_commencement_typo_25_calendar_year",
+    "text": "25년도 종업식 알려줘",
+    "engine_in": ["fast"],
+    "all_of_text_contains": ["2025-02-21"]
+  },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/regression/chatbot_regression_cases.json` around lines 14 - 19, The
current regression case "schedule_commencement_25_calendar_year" only tests the
correct phrase "졸업식" but not the typo "종업식"; add a sibling test entry (e.g., id
"schedule_commencement_25_calendar_year_typo") that mirrors the existing case
but uses "종업식 알려줘" (or include both phrases in one case's inputs) with the same
engine_in and all_of_text_contains ["2025-02-21"] so the regression catches the
typo mapping change in LLM/OSS/modes.py, LLM/sub_model/schedule_rules.py, and
LLM/OSS/service.py.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@LLM/sub_model/query_index.py`:
- Around line 340-344: The confidence gate currently allows low absolute scores
to pass if the score gap is large because it uses a logical AND; change the
logic so both conditions must be satisfied to proceed: ensure the top result's
absolute score (top_score computed from hits.iloc[0]) is at or above
CONFIDENT_SCORE_THRESHOLD AND the gap (top_score - second_score, where
second_score comes from hits.iloc[1]) is at least CONFIDENT_SCORE_GAP before
calling confident_search_answer(); otherwise return None. Update the conditional
that references top_score, second_score, CONFIDENT_SCORE_THRESHOLD, and
CONFIDENT_SCORE_GAP accordingly so both checks are required.

In `@LLM/sub_model/schedule_rules.py`:
- Around line 59-60: The current expansion adds MIDTERM/FINAL whenever "시험"/"고사"
appears even if an explicit period tag like SEMESTER_END is already present;
change the condition so MIDTERM/FINAL are added only when no explicit
academic-period tags exist (e.g., ensure
tags.isdisjoint({"SEMESTER_END","SEMESTER_START","SEMESTER_BREAK","VACATION"})
before adding). Update the check around the tags update (the block using
tags.update({"MIDTERM","FINAL"}) and the existing isdisjoint call) to first
verify absence of those explicit period tags in addition to the current checks.

---

Nitpick comments:
In `@LLM/OSS/service.py`:
- Around line 311-314: Replace the hardcoded ceremony keywords tuple in the
conditional with the shared ceremony matcher used in modes (reuse CEREMONY_RE or
the public helper from LLM/OSS/modes.py); update the check to use
CEREMONY_RE.search(user_text) (or the exported helper function) so the branch
that calls schedule_search(top_k=8) and returns via
cache_and_return({"engine":"fast","text":render_chatty_schedule(...)}) stays
identical but centralizes the keyword list, and add the necessary import for
CEREMONY_RE/helper at the top of this module.

In `@tests/regression/chatbot_regression_cases.json`:
- Around line 14-19: The current regression case
"schedule_commencement_25_calendar_year" only tests the correct phrase "졸업식" but
not the typo "종업식"; add a sibling test entry (e.g., id
"schedule_commencement_25_calendar_year_typo") that mirrors the existing case
but uses "종업식 알려줘" (or include both phrases in one case's inputs) with the same
engine_in and all_of_text_contains ["2025-02-21"] so the regression catches the
typo mapping change in LLM/OSS/modes.py, LLM/sub_model/schedule_rules.py, and
LLM/OSS/service.py.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4626ea98-9d0e-48df-802b-c41bd84df7be

📥 Commits

Reviewing files that changed from the base of the PR and between 9c59b99 and bae0e78.

📒 Files selected for processing (8)
  • LLM/OSS/modes.py
  • LLM/OSS/service.py
  • LLM/patterns.py
  • LLM/rule_book/graph.py
  • LLM/sub_model/query_index.py
  • LLM/sub_model/schedule_index.py
  • LLM/sub_model/schedule_rules.py
  • tests/regression/chatbot_regression_cases.json

Comment thread LLM/sub_model/query_index.py
Comment thread LLM/sub_model/schedule_rules.py Outdated
@Yu-JeSeung
Yu-JeSeung merged commit 4be6b6c into main May 4, 2026
1 check passed
@Yu-JeSeung
Yu-JeSeung deleted the feat/chatbot_timeout branch May 4, 2026 12:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 챗봇 서버 타임아웃 개선

1 participant