Agent 2.0 exdev 서버 배포 스택

- server-dev start/stop/deploy 및 Gitea push 자동 배포
- local-dev 로컬 개발 환경

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Macbook
2026-07-21 22:57:30 +09:00
commit 4b86b2a660
344 changed files with 45787 additions and 0 deletions
@@ -0,0 +1,193 @@
"""
제안 핸들러 모듈
──────────────
낮은 신뢰도 시 대안 질문 제안
"""
from typing import List, Dict, Any, Optional
SUGGESTION_BLOCK_MARKER = "💡 혹시 이런 것을 찾으셨나요?"
SUGGESTION_BLOCK_MARKER_ALT = "혹시 이런 것을 찾으셨나요?"
def strip_suggestion_block(text: Optional[str]) -> str:
"""LLM 이력용: 추천 블록(및 LLM 모방 블록) 제거, FAQ 본문만 반환"""
if not text:
return text or ""
indices = []
for marker in (SUGGESTION_BLOCK_MARKER, SUGGESTION_BLOCK_MARKER_ALT):
idx = text.find(marker)
if idx != -1:
indices.append(idx)
if not indices:
return text
return text[: min(indices)].rstrip()
def has_suggestion_block(text: Optional[str]) -> bool:
if not text:
return False
return any(marker in text for marker in (SUGGESTION_BLOCK_MARKER, SUGGESTION_BLOCK_MARKER_ALT))
class SuggestionHandler:
"""낮은 신뢰도 답변에 대한 대안 질문 제안"""
# 신뢰도 임계값 (기본값 — Config.from_env / LOW_CONFIDENCE_THRESHOLD 로 override)
DEFAULT_LOW_CONFIDENCE_THRESHOLD = 0.65
DEFAULT_HIGH_CONFIDENCE_THRESHOLD = 0.75
def __init__(
self,
low_confidence_threshold: float = DEFAULT_LOW_CONFIDENCE_THRESHOLD,
high_confidence_threshold: float = DEFAULT_HIGH_CONFIDENCE_THRESHOLD,
):
"""
Args:
low_confidence_threshold: 낮은 신뢰도 기준 (기본 0.65, env LOW_CONFIDENCE_THRESHOLD)
high_confidence_threshold: 높은 신뢰도 기준 (기본 0.75, env HIGH_CONFIDENCE_THRESHOLD)
"""
self.low_confidence_threshold = low_confidence_threshold
self.high_confidence_threshold = high_confidence_threshold
def is_low_confidence(self, top_score: Optional[float]) -> bool:
"""신뢰도가 낮은지 판단
Args:
top_score: 최상위 검색 결과의 점수
Returns:
낮은 신뢰도 여부
"""
if top_score is None:
return True
return top_score < self.low_confidence_threshold
def generate_suggestions(
self,
top_results: List[Dict[str, Any]],
top_scores: List[float],
max_suggestions: int = 3
) -> Optional[str]:
"""대안 질문 제안 생성
Args:
top_results: 검색 결과 리스트
top_scores: 검색 점수 리스트
max_suggestions: 최대 제안 개수 (기본 3개)
Returns:
제안 문자열 또는 None
"""
if not top_results or not top_scores:
return None
# 최상위 점수가 충분히 높으면 제안 불필요
if not self.is_low_confidence(top_scores[0]):
return None
# 1위 포함 상위 max_suggestions개 질문 제안 (번호 1부터)
suggestion_count = min(max_suggestions, len(top_results))
if suggestion_count <= 0:
return None
suggestions = []
for i in range(suggestion_count):
question = top_results[i]["q"]
score = top_scores[i] if i < len(top_scores) else None
suggestions.append({
"index": i + 1,
"question": question,
"score": score,
})
if not suggestions:
return None
# 제안 텍스트 생성
suggestion_text = f"\n\n{SUGGESTION_BLOCK_MARKER}\n"
for suggestion in suggestions:
# 점수가 있으면 신뢰도 표시 (선택적)
# suggestion_text += f"{suggestion['index']}. {suggestion['question']} (유사도: {suggestion['score']:.2f})\n"
suggestion_text += f"{suggestion['index']}. {suggestion['question']}\n"
suggestion_text += "\n위 질문 중 하나를 선택하시면 정확한 답변을 드리겠습니다."
return suggestion_text
def enhance_answer_with_suggestions(
self,
answer: str,
top_results: List[Dict[str, Any]],
top_scores: List[float],
max_suggestions: int = 3
) -> str:
"""답변에 제안 추가
Args:
answer: 원본 답변
top_results: 검색 결과
top_scores: 검색 점수
max_suggestions: 최대 제안 개수
Returns:
제안이 추가된 답변 (또는 원본)
"""
if has_suggestion_block(answer):
return answer
suggestions = self.generate_suggestions(top_results, top_scores, max_suggestions)
if suggestions:
return answer + suggestions
return answer
def get_confidence_level(self, score: Optional[float]) -> str:
"""점수를 신뢰도 레벨로 변환
Args:
score: 검색 점수
Returns:
"high", "medium", "low" 중 하나
"""
if score is None:
return "low"
if score >= self.high_confidence_threshold:
return "high"
elif score >= self.low_confidence_threshold:
return "medium"
else:
return "low"
def should_show_confidence_warning(self, top_score: Optional[float]) -> bool:
"""신뢰도 경고를 표시해야 하는지
Args:
top_score: 최상위 점수
Returns:
경고 표시 여부
"""
if top_score is None:
return True
# 매우 낮은 신뢰도 (0.50 미만)
return top_score < 0.50
def generate_confidence_warning(self) -> str:
"""신뢰도 경고 메시지 생성"""
return (
"\n\n⚠️ **정확도 안내**\n"
"질문과 정확히 일치하는 정보를 찾기 어려웠습니다.\n"
"더 구체적으로 질문하시거나, 아래 옵션을 참고해 주세요.\n"
"정확한 답변이 필요하시면 한국도로공사 콜센터(1588-2504)로 문의해 주세요."
)