[UI] 사용자와 소통하는 챗봇 화면 구성하기
이번 토이프로젝트에선 화면 구성에 신경을 안써서...
핵심 코드: src/main.py (사고 과정 시각화)
Streamlit의 expander를 활용해 AI의 속마음을 보여줍니다.
import os
import sys
import streamlit as st
# [설정 가이드]
# 프로젝트 루트 경로를 sys.path에 추가하여 src 패키지를 인식하게 합니다.
# 이 코드가 없으면 'from src.chain...' 호출 시 모듈을 찾을 수 없는 에러가 발생할 수 있습니다.
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.chain import ask_question
from src.utils.logger import get_logger
# 웹 페이지의 기본 정보를 설정합니다 (탭 제목, 아이콘 등).
st.set_page_config(
page_title="CDocs Agent - 지능형 사내 문서 비서",
page_icon="🤖",
layout="wide"
)
logger = get_logger("StreamlitApp")
# [상태 관리: session_state]
# Streamlit은 사용자가 상호작용할 때마다 스크립트가 처음부터 다시 실행됩니다.
# 따라서 대화 내역(messages)을 유지하려면 st.session_state라는 특수 저장소를 써야 합니다.
if "messages" not in st.session_state:
st.session_state.messages = []
# 사이드바 구성: 앱의 설명이나 초기화 버튼을 둡니다.
with st.sidebar:
st.title("🤖 CDocs Agent")
st.info("노션, 웹, 로컬 파일을 통합 검색하여 답변합니다.")
if st.button("대화 내용 초기화"):
st.session_state.messages = []
st.rerun()
st.title("지능형 에이전트 Q&A")
# 1. 기존 대화 내역 출력
# 사용자(user)와 비서(assistant)의 메시지를 구분하여 화면에 그립니다.
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# 답변 시 저장해둔 '사고 과정'이 있다면 다시 보여줍니다.
if "thoughts" in message and message["thoughts"]:
with st.expander("지난 사고 과정 (Thought Process)"):
for idx, step in enumerate(message["thoughts"]):
st.write(f"**Step {idx+1}: {step['tool']} 호출**")
st.caption(f"결과 요약: {step['observation']}")
# 2. 새로운 질문 입력 처리
if prompt := st.chat_input("궁금한 사내 규정이나 업무 내용을 물어보세요"):
# 사용자의 질문을 화면에 표시하고 이력에 저장
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
# 3. AI의 답변 생성 및 시각화
with st.chat_message("assistant"):
# st.status: AI가 생각하는 동안 '진행 중'임을 알려주는 멋진 UI 요소입니다.
with st.status("에이전트가 최적의 답변을 위해 고민 중입니다...", expanded=True) as status:
# chain.py에 정의된 에이전트 호출 (질문과 이전 대화 이력 전달)
result = ask_question(prompt, chat_history=[])
status.update(label="분석 완료!", state="complete", expanded=False)
full_response = result["answer"]
thoughts = result["thoughts"]
# AI의 최종 답변 출력
st.markdown(full_response)
# [사고 과정 시각화]
# 에이전트가 어떤 도구(노션 검색, 웹 검색 등)를 썼는지 투명하게 보여줍니다.
# 신뢰도를 높이는 가장 좋은 방법입니다.
if thoughts:
with st.expander("에이전트 사고 과정 (Thought Process)", expanded=False):
for idx, step in enumerate(thoughts):
st.write(f"**Step {idx+1}: {step['tool']} 도구 활용**")
if step['thought']:
st.text(step['thought']) # AI의 내부 판단 근거
st.caption(f"도구 실행 결과: {step['observation']}")
# 답변 내용과 사고 과정을 세션에 저장하여 페이지가 새로고침되어도 유지되게 합니다.
st.session_state.messages.append({
"role": "assistant",
"content": full_response,
"thoughts": thoughts
})