프로덕션 환경에서 챗봇을 운영하는 모든 팀은 결국 동일한 벽에 부딪힙니다. IT 헬프데스크 챗봇을 구축하여 실제 트래픽에 배포하면, 불과 첫 주 만에 사용자들은 챗봇에게 시를 써달라거나, 개인 파이썬 스크립트를 디버깅해 달라거나, 사워도우 스타터가 왜 부풀지 않는지 설명해 달라고 요청하기 시작합니다.
이를 방치할 경우, 챗봇의 범위 이탈(scope creep)은 단순한 성가심을 넘어 법적·운영적 책임(liability) 문제로 번집니다. IT 챗봇이 회사 정책에 대한 인사(HR) 자문을 제공하기 시작하면 법적 리스크가 됩니다. 헬스케어 챗봇이 도메인을 벗어난 질문에 답하면 규제 당국의 악몽이 됩니다. 고객 지원 챗봇이 자신의 도메인 밖에서 환각(hallucination)을 일으키며 답변하면 제품 전체에 대한 신뢰가 무너집니다.
그렇다면 질문은 이것입니다: “어떤 기술을 사용해야 챗봇을 의도된 도메인 내에 엄격히 유지할 수 있을까요?” 그 해답은 다층 방어 아키텍처(layered architecture)로 수렴합니다. 이는 단 하나의 단편적인 분석으로는 온전히 담아낼 수 없는 체계입니다. 본 글에서는 여러 분석과 실무진의 합의점, 이견, 그리고 대부분의 팀이 간과하는 핵심 기술 한 가지를 종합하여 정리합니다.
보편적 합의: 단 하나의 계층만으로는 부족합니다 (The universal agreement: no single layer is enough)
아키텍처적 결론은 매우 명확합니다. 바로 다층 방어 전략(layered defense strategy) 이 반드시 필요하다는 점입니다. 단 하나의 기술만으로는 절대 작동하지 않습니다. 시스템 프롬프트 하나만으로는 버틸 수 없습니다. 의도 분류기(intent classifier) 하나만으로도 막을 수 없습니다. UI 제약만으로도 한계가 있습니다.
업계에서 합의된 아키텍처는 다음과 같습니다:
User Input (사용자 입력)
→ [Layer 1] UI/UX Constraints (인터페이스 단계에서 주제 이탈 방지)
→ [Layer 2] Intent Classification Gate (LLM 전달 전 주제 이탈 쿼리 차단)
→ [Layer 3] System Prompt Boundaries (LLM의 동작 범위 가이드)
→ [Layer 4] RAG Knowledge Restriction (LLM이 접근할 수 있는 지식 제한)
→ [Layer 5] Output Guardrail Check (응답 전송 전 결과 검증)
→ [Layer 6] Graceful Fallback (거절 및 리다이렉트의 우아한 처리)
각 계층을 하나씩 살펴보겠습니다.
계층 1: 시스템 프롬프트 (6/6 합의) (Layer 1: The system prompt)
시스템 프롬프트는 언제나 첫 번째 혹은 가장 중요한 기술로 꼽힙니다. 하지만 이번 분석에서 도출된 합의에는 대부분의 팀이 놓치는 결정적인 주의사항이 있었습니다.
일반적인 조언은 *“봇의 페르소나와 작업 범위를 정의하라”*는 것입니다. 하지만 이것만으로는 충분하지 않습니다. 훨씬 더 강력한 지시가 필요합니다:
“’답을 알고 있더라도 절대 답변하지 말라’고 명시하십시오. 그렇지 않으면 LLM은 본능적으로 도움을 주려(helpful) 답변을 내놓을 것입니다.”
LLM은 사용자를 돕도록(helpful) 훈련되었습니다. 봇이 무엇을 할 수 있는지만 명시하면, 도메인을 벗어난 질문이라도 모델의 가중치에 내장된 ‘도움 성향’ 때문에 어떻게든 답변하려고 시도합니다. 따라서 명시적인 부정 제약 조건(negative constraints)이 반드시 필요합니다:
You are a strict IT Helpdesk Assistant for Acme Corp.
ALLOWED TOPICS:
- IT asset management (laptops, monitors, peripherals)
- IT ticket creation and status
- Password resets and account access
- Software requests and installations
- Network and connectivity issues
FORBIDDEN TOPICS:
- HR policies, payroll, benefits
- Company strategy, financials
- General knowledge, creative writing
- Personal advice unrelated to IT
RULES:
1. If a user asks about anything outside allowed topics, you MUST refuse.
2. Do NOT answer forbidden topics even if you know the answer.
3. Your fallback response: "I can only assist with IT-related inquiries.
How can I help with your tech assets or tickets today?"
프롬프트 내에 올바른 거절 동작을 보여주는 퓨샷(few-shot) 예시를 포함하면 큰 효과를 볼 수 있습니다. 모델에게 모범적인 거절 방식이 어떤 것인지 구체적으로 보여주십시오.
계층 2: 의도 분류 게이트 (6/6 합의) (Layer 2: Intent classification)
이 계층은 장난감 수준의 챗봇과 상용 프로덕션 시스템을 가르는 결정적인 차이점입니다. 일관된 권장 사항은 메인 LLM 앞단에 수문장(gatekeeper) 역할을 하는 경량 분류기를 배치하는 것입니다.
개념은 단순합니다. 사용자의 메시지가 비싸고 느리며 창의적인 메인 LLM에 도달하기 전에, 빠르고 저렴한 분류기가 범위 내(in-scope)인지 범위 외(out-of-scope)인지를 이진 결정(binary decision)으로 판별합니다. 범위 밖의 쿼리는 하드코딩된 리다이렉트 메시지를 즉시 반환받습니다. 메인 모델에 도달하지 않으므로 토큰을 소모하지도 않고, 환각을 일으킬 여지도 전혀 없습니다.
┌── in-scope ──→ [Main LLM + RAG]
user ──→ [Classifier] ┤
└── out-of-scope ──→ "I can only help with IT issues."
구현 옵션은 단순한 방식부터 고도화된 방식까지 다양합니다:
| 접근 방식 (Approach) | 지연 시간 (Latency) | 정확도 (Accuracy) | 비용 (Cost) |
|---|---|---|---|
| 키워드 / 정규식 매칭 (Keyword/regex matching) | <1ms | 낮음 (취약함) | 무료 |
| 임베딩 유사도 임계값 (Embedding similarity threshold) | ~10ms | 보통 | 낮음 |
| 파인튜닝된 소형 모델 (Fine-tuned small model - BERT) | ~20ms | 높음 | 낮음 |
| 판별자 LLM (LLM-as-judge - GPT-4o-mini) | ~200ms | 높음 | 중간 |
한 분석에서는 범용 모델을 사용하는 대신 도메인 특화 분류기를 미세 조정(fine-tuning) 할 것(예: 자체 IT 헬프데스크 말뭉치로 학습한 BERT)을 강력히 권장하며, 특정 사용 사례에서 30% 이상 더 높은 정확도를 얻을 수 있다고 강조했습니다. 레이블링된 학습 데이터가 있다면 이는 충분히 투자할 가치가 있습니다.
여기서 핵심 파라미터는 신뢰도 임계값(confidence threshold) 입니다. 기준을 0.7로 설정하고, 그 미만은 거절하도록 구성하십시오. 이 값은 조정 가능한 제어 다이얼입니다. 임계값을 낮추면 오탐 거절(false rejection: 마땅히 도와야 할 사용자를 “도울 수 없다”고 거부하는 문제)이 줄어들고, 높이면 오탐 허용(false accept: 주제를 벗어난 질문이 통과되는 문제)을 줄일 수 있습니다.
계층 3: UI/UX 제약 (5/6 합의) (Layer 3: UI/UX constraints)
분석 결과에서는 백엔드뿐만 아니라 인터페이스 자체를 제한할 것을 강력히 권장합니다. 그 이유는 인간의 행동 심리에 기인합니다. 바로 비어 있는 텍스트 입력창은 자유로운 탐색을 유도한다는 점입니다. 적극적으로 가이드하지 않으면 사용자들은 챗봇을 ChatGPT처럼 취급합니다.
반복적으로 언급된 핵심 기법들은 다음과 같습니다:
빠른 답장 버튼(Quick reply buttons). 처음 로드될 때 열린 텍스트 입력창 대신 클릭 가능한 옵션을 제공합니다:
- 🔘 티켓 상태 확인 (Check Ticket Status)
- 🔘 신규 하드웨어 신청 (Request New Hardware)
- 🔘 비밀번호 재설정 (Reset Password)
- 🔘 장애 신고 (Report an Issue)
도메인 범위를 강조하는 플레이스홀더 텍스트(Placeholder text). “메시지를 입력하세요…” 대신 “IT 자산 또는 티켓에 대해 문의하세요…“를 사용하십시오.
경계를 설정하는 웰컴 메시지(Welcome message). 사용자가 보는 첫 메시지에서 봇이 지원할 수 있는 업무와 지원할 수 없는 업무를 명확히 선언하십시오.
구조화된 흐름을 위한 입력 마스킹(Input masking). 사용자가 “티켓 상태 확인”을 선택했다면 자유로운 텍스트 입력 대신 특정 형식(예: TKT-XXXXX)을 요구하도록 입력을 제한하십시오.
이 계층의 근본 원칙은 명확합니다: 주제 이탈 쿼리가 백엔드에 도달하기 전에 인터페이스 수준에서 사전에 차단하는 것입니다. 이는 구현 비용이 가장 저렴하면서도 단순한 호기심으로 인한 범위 이탈을 막는 데 가장 효과적인 방어책입니다.
계층 4: RAG 지식베이스 격리 (5/6 합의) (Layer 4: RAG knowledge restriction)
검색 증강 생성(RAG, Retrieval-Augmented Generation)을 사용하고 있다면, 지식베이스 자체가 자연스러운 도메인 경계 역할을 수행합니다. 이는 널리 권장되는 전략입니다.
핵심 기법은 자체 도메인 태그가 지정된 문서만 인덱싱하는 것입니다(예: Department: IT). 사용자가 치과 보험에 대해 질문하면, 검색기(retriever)는 관련된 청크를 단 하나도 찾지 못합니다. LLM은 빈 컨텍스트를 전달받아 “해당 주제에 대한 정보를 찾을 수 없습니다”라고 답할 수밖에 없습니다. 별도의 복잡한 가드레일 로직 없이도 자연스럽고 정직한 거절이 이루어지는 것입니다.
이는 단순한 보안 조치를 넘어 비용 최적화이기도 합니다. 검색된 무관한 청크 하나하나는 모두 낭비된 임베딩 연산 비용이자 낭비된 컨텍스트 윈도우 공간입니다.
메타데이터 필터링 접근 방식:
# IT 태그가 지정된 문서에서만 검색 수행
results = vector_store.similarity_search(
query=user_query,
filter={"department": "IT", "category": {"$in": [
"hardware", "software", "networking", "access", "tickets"
]}},
k=5
)
if not results:
return "I don't have information on that topic in my IT knowledge base."
여기에 중요한 세부 사항이 하나 추가됩니다: 관련 콘텐츠가 검색되지 않으면 쿼리를 즉시 ’범위 외(out of scope)’로 처리하십시오. 모델이 정보의 공백을 메우기 위해 사전 학습된 일반 상식에 의존하여 지어내도록 내버려두어서는 안 됩니다. RAG 파이프라인은 오픈 실패(fail-open)가 아닌 폐쇄 실패(fail-closed) 방식으로 설계되어야 합니다.
계층 5: 출력 가드레일 (4/6 합의) (Layer 5: Output guardrails)
출력 가드레일은 챗봇의 응답이 생성된 직후, 그리고 사용자에게 전달되기 직전에 응답의 유효성을 검증하는 기법입니다. 이는 시스템 프롬프트가 미처 차단하지 못한 누수를 잡아내는 안전망 역할을 합니다.
기본 패턴:
User query → LLM generates response → [Output Guardrail] → Deliver or replace
가드레일은 시맨틱 유사도 검사처럼 간단하게 구성할 수 있습니다: “생성된 응답이 IT 주제와 관련이 있는가?” 응답과 IT 기준 참조 문서 간의 코사인 유사도(cosine similarity)가 임계값 미만이라면, 해당 응답을 사전에 정의된 폴백 템플릿으로 대체합니다.
def guard_response(bot_reply: str) -> str:
relevance = cosine_similarity(
embed(bot_reply),
embed(IT_HELPDESK_REFERENCE)
)
if relevance < 0.6:
return FALLBACK_REDIRECT_MESSAGE
return bot_reply
이 방식은 특정한 실패 모드를 효과적으로 포착합니다. 바로 LLM이 첫 문장에서는 정중히 거절해 놓고, 바로 다음 문장에서 도메인을 벗어난 질문에 얼떨결에 답변해 버리는 현상입니다. 소형 모델일수록 이런 오류에 취약하여, “저는 IT 봇이지만, 인사 정책에 대해 아는 바를 말씀드리자면…“이라며 말끝을 흐리며 답변을 흘리는 실수를 저지릅니다.
계층 6: 우아한 폴백 및 에스컬레이션 (6/6 합의) (Layer 6: Graceful fallback and escalation)
거절 여부 못지않게 ’어떻게 거절하는가’도 중요합니다. “답변할 수 없습니다”라는 투박한 한마디는 대화의 막다른 골목(dead end)입니다. 잘 설계된 리다이렉트는 또 다른 해결책으로 향하는 가교가 됩니다.
합의된 권장 패턴:
- 사용자의 쿼리를 인정하기(Acknowledge) — 질문이 없었던 것처럼 무시하지 마십시오.
- 적절한 채널로 안내하기(Redirect) — “인사 관련 문의는 hr@company.com으로 문의해 주십시오.”
- 유효한 대안 제시하기(Alternative) — “대신 비밀번호 재설정이나 기술 지원이 필요하시다면 도와드릴 수 있습니다.”
3진 아웃 에스컬레이션(3-strike escalation) 패턴:
| 단계 (Strike) | 응답 방식 (Response) |
|---|---|
| 1차 이탈 | 부드러운 안내: “저는 IT 문제 해결을 위해 설계되었습니다. [주제] 관련 문의는 [채널]을 이용해 주십시오.” |
| 2차 이탈 | 단호한 안내: “저는 IT 정보에만 접근 권한이 있습니다. IT 자산이나 티켓 관련 내용만 질문해 주십시오.” |
| 3차 이탈 | 상담원 연결: “해당 요청은 제가 처리할 수 없는 것으로 보입니다. 전문 상담원(인간 상담사)에게 연결해 드리겠습니다.” |
한 분석에서는 이 에스컬레이션을 업무 완료 기회로 전환할 것을 제안했습니다: “HR 팀에 지원 티켓을 생성하고 현재 대화 내용을 전달해 드릴까요?” 이는 단순한 실패를 원활한 업무 이관(handoff)으로 바꿔줍니다. 봇은 도메인 밖의 답변을 거부함으로써 원래 목적을 지키면서도, 사용자에게는 여전히 실질적인 가치를 제공합니다.
대부분의 팀이 놓치는 기법: 유한 상태 머신(FSM) 대화 제어
더 널리 도입되어야 할 강력한 아키텍처 패턴이 있습니다. 바로 유한 상태 머신(FSM, Finite State Machine) 대화 제어입니다.
LLM이 대화 속에서 자유롭게 독주하도록 내버려두는 대신, 명시적인 상태(state)들을 정의합니다:
START → [greeting]
→ work_order_query_flow → [collect ticket ID] → [fetch status] → [display result]
→ asset_request_flow → [select asset type] → [collect details] → [submit request]
→ fault_reporting_flow → [describe issue] → [categorize] → [create ticket]
→ END
각 상태는 현재 프로세스와 관련된 입력만 수락합니다. 사용자가 “티켓 조회” 플로우를 진행하는 도중에 갑자기 “점심 메뉴로 뭘 먹을까?“라고 묻는다면, FSM은 이를 유효하지 않은 입력으로 판정하고 현재 진행 중인 IT 절차로 복귀하도록 안내합니다. 도메인 범위를 결정하는 주체는 LLM이 아니라 바로 상태 머신입니다.
각 단계에서 필요한 특정 데이터만 수집하는 슬롯 필링(slot filling) 및 턴 사이의 주제 이탈을 감지하는 컨텍스트 고정(context anchoring) 과 결합하면, FSM 제어는 대화를 사전에 정의된 비즈니스 프로세스 안에 완벽히 가두어 둡니다. LLM은 어느 상태로 이동할지 결정하는 주체가 아니라, 각 상태 내부에서 자연스러운 언어를 생성해 주는 도구로 격하됩니다.
이 방식은 다른 기법들에 비해 구현 공수가 많이 들지만, 구조화된 비즈니스 프로세스에 있어서는 가장 확실하고 신뢰할 수 있는 경계 제어 방법입니다.
툴 화이트리스트(Tool Whitelist) 패턴
또한 LLM이 사전에 정의된 도구만 호출할 수 있도록 제한하는 방식도 강력히 권장됩니다:
tools = [
{"name": "query_work_order", "description": "Check IT ticket status"},
{"name": "query_asset", "description": "Look up IT asset information"},
{"name": "submit_fault", "description": "Report a technical issue"},
{"name": "apply_permission", "description": "Request software access"},
]
사용자의 질문이 제공된 도구 중 어느 것과도 매핑되지 않는다면, LLM은 호출할 수 있는 도구가 없습니다. 실행할 도구가 없으므로 주제를 벗어난 답변 자체를 생성할 수 없습니다. 모델은 해당 쿼리를 처리 불가능한 것으로 자동 분류합니다.
이 방식은 제약의 성격을 “LLM이 답변해서는 안 된다(소프트 제약)“에서 “LLM이 구조적으로 답변할 수 없다(하드 제약)“로 전환하기 때문에, 모델 수준에서 적용할 수 있는 가장 신뢰성 높은 경계 제어 수단입니다.
구현 우선순위 (The implementation priority)
모든 계층을 출시 첫날부터 전부 도입할 필요는 없습니다. 권장되는 구현 순서는 다음과 같습니다:
| 우선순위 (Priority) | 기술 (Technique) | 공수 (Effort) | 영향력 (Impact) |
|---|---|---|---|
| 1 | 부정 제약 조건을 포함한 시스템 프롬프트 | 낮음 (Low) | 중간 (Medium) |
| 2 | 수문장 역할을 하는 의도 분류기 (Gatekeeper) | 중간 (Medium) | 높음 (High) |
| 3 | UI/UX 제약 (버튼, 웰컴 메시지 등) | 중간 (Medium) | 높음 (High) |
| 4 | RAG 지식베이스 격리 | 낮음 (Low) | 중간 (Medium) |
| 5 | 우아한 폴백 메시지 (Graceful fallback) | 낮음 (Low) | 중간 (Medium) |
| 6 | 출력 가드레일 (Output guardrails) | 중간 (Medium) | 중간 (Medium) |
| 7 | 툴 화이트리스트 (Tool whitelisting) | 중간 (Medium) | 높음 (High) |
| 8 | 3진 아웃 에스컬레이션 (3-strike escalation) | 낮음 (Low) | 낮음 (Low) |
| 9 | FSM 기반 대화 제어 | 높음 (High) | 높음 (High) |
| 10 | 시맨틱 임베딩 필터링 | 중간 (Medium) | 중간 (Medium) |
첫 번째 이터레이션에서는 15단계를 배포하십시오. 프로덕션 트래픽 데이터가 쌓이면 68단계를 추가하십시오. 엔지니어링 리소스에 여유가 생겼을 때 9~10단계에 투자하는 것이 바람직합니다.
가장 치명적인 제1의 실수 (만장일치) (The #1 mistake)
오직 시스템 프롬프트에만 의존하는 것.
아무리 강조해도 지나치지 않습니다. 시스템 프롬프트는 필수적이지만 그것만으로는 결코 충분하지 않습니다. LLM은 본질적으로 창의적이며, 사용자의 행동은 예측 불가능하며, 작정하고 파고드는 사용자는 언제나 예외 케이스(edge case)를 찾아냅니다. 강력한 차단 관문 역할을 하는 의도 분류기와 안전망 역할을 하는 출력 필터링이야말로 단순한 데모용 토이 프로젝트와 실제 프로덕션 시스템을 가르는 결정적인 차이입니다.
아무도 언급하지 않은 피드백 루프 (The feedback loop nobody mentioned)
모든 요소를 하나로 묶어주는 핵심 기법 하나가 종종 간과되곤 합니다. 바로 모든 거절 내역을 로깅하고 매주 검토하는 것입니다.
챗봇이 특정 쿼리를 “범위 외”로 분류하여 거절할 때마다, 이는 중요한 데이터 포인트가 됩니다. 이러한 거절 중 일부는 정당할 것입니다(예: 사용자가 날씨를 물어본 경우). 하지만 일부는 거짓 양성(false positive, 오탐)일 수 있습니다(사용자가 정당한 IT 질문을 던졌으나 분류기가 이를 오판하여 놓친 경우). 거절 로그를 정기적으로 검토하지 않는다면 이러한 문제를 결코 알아챌 수 없습니다.
권장 워크플로우:
- 분류기의 신뢰도 점수와 함께 거절된 모든 쿼리를 로깅합니다.
- 매주 거절 로그를 검토하여 거짓 양성(오탐) 사례를 선별합니다.
- 오탐 사례를 학습 데이터 세트나 허용 의도(allowed intent) 목록에 추가합니다.
- 분류기를 재학습하거나 업데이트합니다.
- 시간에 따른 오탐률(false-positive rate) 추이를 측정합니다. 이 수치는 점진적으로 감소해야 합니다.
이 과정을 거치면 가드레일 시스템은 단순한 고정된 벽에서 벗어나, 사용자와의 상호작용이 누적될수록 점점 더 정교해지는 학습형 시스템으로 진화합니다.
결론 및 요약 (The bottom line)
챗봇의 대화 주제를 정상 궤도에 유지하는 것은 프롬프팅의 문제가 아닙니다. 이것은 명백한 아키텍처의 문제입니다. 시스템 프롬프트는 1차 방어선에 불과하며, 프로덕션 환경에서 실제로 시스템을 지탱해 주는 것은 의도 분류기, UI 제약, RAG 필터링, 출력 가드레일, 그리고 에스컬레이션 프로토콜입니다.
그 어떤 단일 기술도 완벽할 수는 없습니다. 다층 방어 체계를 구축할 때 비로소 대화의 탈선은 구조적으로 어려워지며, 설령 탈선이 발생하더라도 이를 감지하고 수습하는 비용을 획기적으로 낮출 수 있습니다.
기법별 합의 점수를 포함한 전체 분석 내용은 [[Chatbot Scope Control - Multi-LLM Consensus|연구 노트]]에서 확인하실 수 있습니다.
Saram Consulting