Blog
chatbotragai-agentfine-tuningenterprisellmai
엔터프라이즈 AI 챗봇 구축 가이드 - RAG + Agent + Fine-Tuning 통합
RAG, AI Agent, Fine-Tuning을 결합한 엔터프라이즈 AI 챗봇 구축 방법을 정리합니다. 아키텍처 설계, 대화 관리, 도구 연동, 평가, 운영 모니터링까지 실전 가이드를 제공합니다.
Data Dynamics2026年4月16日8 min read
This post is not yet translated. The original Korean version is shown below.
엔터프라이즈 AI 챗봇은 단순한 Q&A를 넘어, 사내 문서 검색, 업무 자동화, 시스템 연동까지 수행하는 종합 AI 어시스턴트입니다. 이 글에서는 RAG + Agent + Fine-Tuning을 결합한 프로덕션 수준의 챗봇 구축 방법을 다룹니다.
1. 엔터프라이즈 챗봇의 요구사항
| 요구사항 | 설명 | 기술 |
|---|---|---|
| 사내 문서 검색 | 위키, Confluence, 기술 문서 검색 | RAG |
| 시스템 연동 | Jira, Slack, DB, 모니터링 연동 | Agent + Tool Use |
| 도메인 특화 응답 | 사내 기술 스택에 맞는 정확한 응답 | Fine-Tuning |
| 대화 맥락 유지 | 멀티턴 대화에서 문맥 유지 | 메모리 관리 |
| 접근 제어 | 사용자 권한에 따른 정보 접근 | ACL + 메타데이터 필터 |
| 안전성 | 할루시네이션 방지, 유해 콘텐츠 차단 | 가드레일 |
2. 아키텍처
통합 아키텍처
[엔터프라이즈 AI 챗봇 아키텍처]
사용자 (Slack / Web / Teams)
↓
┌────────────────────────────────────────────┐
│ API Gateway (인증, 속도 제한) │
└───────────────┬────────────────────────────┘
↓
┌────────────────────────────────────────────┐
│ 대화 관리 서비스 │
│ ├─ 세션 관리 (Redis) │
│ ├─ 의도 분류 → 라우팅 │
│ └─ 대화 이력 관리 │
└───────────────┬────────────────────────────┘
↓
┌────────────────────────────────────────────┐
│ AI 엔진 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ RAG │ │ Agent │ │ Fine- │ │
│ │ 검색 │ │ 도구 │ │ Tuned │ │
│ │ 파이프 │ │ 실행 │ │ 모델 │ │
│ │ 라인 │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ↓ ↓ │
│ [벡터 DB] [Jira, Slack, │
│ DB, 모니터링] │
└───────────────┬────────────────────────────┘
↓
┌────────────────────────────────────────────┐
│ 가드레일 (입력 검증 + 출력 필터링) │
└───────────────┬────────────────────────────┘
↓
응답 반환
의도 분류 → 라우팅
def route_query(user_message: str, context: dict) -> str:
"""사용자 질의를 적절한 파이프라인으로 라우팅"""
classification = classify_intent(user_message)
if classification == "document_search":
return rag_pipeline(user_message, context)
elif classification == "system_action":
return agent_pipeline(user_message, context)
elif classification == "general_chat":
return chat_pipeline(user_message, context)
elif classification == "data_query":
return text_to_sql_pipeline(user_message, context)
else:
return "죄송합니다. 질문을 이해하지 못했습니다. 다시 질문해주세요."3. RAG 파이프라인 (문서 검색)
사내 문서 인덱싱
# 다양한 소스에서 문서 수집 및 인덱싱
sources = {
"confluence": ConfluenceLoader(url="https://wiki.company.com"),
"github": GitHubLoader(repos=["company/docs", "company/runbook"]),
"notion": NotionLoader(token="..."),
"slack_history": SlackLoader(channels=["#engineering", "#incidents"]),
}
all_docs = []
for source_name, loader in sources.items():
docs = loader.load()
for doc in docs:
doc.metadata["source"] = source_name
doc.metadata["access_level"] = get_access_level(doc)
all_docs.extend(docs)
# 청킹 + 임베딩 + 벡터 DB 저장
chunks = text_splitter.split_documents(all_docs)
vectorstore = Chroma.from_documents(chunks, embeddings)접근 제어 통합 검색
def secure_rag_search(query: str, user: dict) -> str:
"""사용자 권한에 따른 RAG 검색"""
# 사용자 권한으로 필터 구성
access_filter = {
"access_level": {"$in": user["allowed_levels"]},
"department": {"$in": user["departments"]}
}
# 필터링된 검색
docs = vectorstore.similarity_search(
query, k=5, filter=access_filter
)
# LLM으로 응답 생성
context = format_docs_with_sources(docs)
response = rag_chain.invoke({"context": context, "question": query})
return response4. Agent 파이프라인 (업무 자동화)
from langchain_core.tools import tool
@tool
def search_jira(query: str) -> str:
"""Jira에서 이슈를 검색합니다."""
issues = jira_client.search_issues(query, maxResults=5)
return format_issues(issues)
@tool
def create_jira_ticket(title: str, description: str, priority: str) -> str:
"""Jira 티켓을 생성합니다. 사용자 확인 후 실행됩니다."""
issue = jira_client.create_issue(
project="ENG", summary=title, description=description, priority=priority
)
return f"티켓 생성 완료: {issue.key}"
@tool
def query_grafana(metric: str, time_range: str) -> str:
"""Grafana에서 메트릭을 조회합니다."""
data = grafana_client.query(metric, time_range)
return format_metrics(data)
@tool
def send_slack(channel: str, message: str) -> str:
"""Slack 채널에 메시지를 전송합니다."""
slack_client.chat_postMessage(channel=channel, text=message)
return f"메시지 전송 완료: {channel}"
# Agent 구성
agent = create_react_agent(
llm=fine_tuned_llm, # Fine-Tuned 모델 사용
tools=[search_jira, create_jira_ticket, query_grafana, send_slack, search_docs],
prompt="당신은 Data Dynamics의 AI 어시스턴트입니다..."
)5. Fine-Tuned 모델 통합
[Fine-Tuning 효과]
기반 모델 응답: "Spark에서 OOM이 발생하면 메모리를 늘리세요."
Fine-Tuned 모델 응답: "Spark executor OOM 해결 방법:
1. spark.executor.memory를 8g → 16g로 조정 (Airflow DAG: etl_daily.py 수정)
2. 사내 표준 설정: conf/spark-defaults.conf 참고
3. 데이터 스큐 의심 시: #data-team 채널의 '스큐 해결 가이드' 참고
4. 긴급 시: @oncall-data 멘션으로 당직자 호출"
→ 사내 맥락, 도구, 프로세스를 반영한 응답
6. 대화 관리
멀티턴 대화
class ConversationManager:
def __init__(self, max_history: int = 20):
self.sessions = {} # Redis 기반 세션 관리
self.max_history = max_history
def get_context(self, session_id: str) -> list:
"""대화 이력 조회 (요약 포함)"""
history = self.sessions.get(session_id, [])
if len(history) > self.max_history:
# 오래된 대화 요약
old = history[:-10]
summary = llm.invoke(f"다음 대화를 3줄로 요약: {old}")
history = [{"role": "system", "content": f"이전 대화 요약: {summary}"}] + history[-10:]
self.sessions[session_id] = history
return history
def add_message(self, session_id: str, role: str, content: str):
if session_id not in self.sessions:
self.sessions[session_id] = []
self.sessions[session_id].append({"role": role, "content": content})7. 운영 및 모니터링
핵심 지표
| 지표 | 설명 | 목표 |
|---|---|---|
| 응답 정확도 | 정확한 답변 비율 | > 85% |
| 1차 해결률 | 추가 질문 없이 해결 | > 70% |
| 응답 시간 | 평균 응답 지연 | < 5초 |
| 사용자 만족도 | 피드백 긍정 비율 | > 80% |
| 할루시네이션율 | 부정확한 응답 비율 | < 5% |
| DAU | 일 활성 사용자 수 | 증가 추세 |
피드백 루프
[지속적 개선 사이클]
1. 사용자 피드백 수집 (좋아요/싫어요 + 코멘트)
↓
2. 부정 피드백 분석
├─ 검색 실패 → 문서 추가, 청킹 조정
├─ 잘못된 응답 → 프롬프트 개선, Fine-Tuning 데이터 추가
└─ 기능 부재 → 새 도구/API 연동
↓
3. 개선 적용 (RAG/프롬프트/모델 업데이트)
↓
4. A/B 테스트로 효과 검증
↓
5. 반복
참고: 엔터프라이즈 챗봇은 "한 번 구축하고 끝"이 아닙니다. 사내 문서가 업데이트되고, 시스템이 변경되며, 사용자의 기대 수준이 높아지므로, 지속적인 개선 체계가 핵심입니다.
References
- LangChain Documentation — https://python.langchain.com/docs/
- LangGraph Documentation — https://langchain-ai.github.io/langgraph/
- Anthropic. "Building Effective Agents" — https://www.anthropic.com/research/building-effective-agents
— Data Dynamics 엔지니어링 팀