감사 데이터 챗봇의 스트리밍 답변과 차트 화면
데이터 조회와 문서 검색 엔진을 만든 뒤에는 사용자가 질문하고 결과를 볼 화면을 붙였습니다. React·Vite 프론트엔드와 FastAPI 백엔드를 사용했고, Databricks의 모델·검색·SQL 자원과 연결했습니다.
답변을 모두 기다린 뒤 한 번에 보여주기보다 진행 상태와 생성 중인 내용을 전달하고, 조회 결과는 표와 차트로 볼 수 있도록 구성했습니다.
SSE 이벤트의 구분
SSE로 질문의 분류와 문서 출처, 생성한 SQL, 답변 내용과 완료·오류를 전달했습니다. 이벤트 이름을 나눠 프론트엔드가 진행 상태를 구분하게 했습니다.
| 이벤트 | 화면에서 처리할 내용 |
|---|---|
intent | 데이터·문서 경로 표시 |
sources, sql_query | 문서 근거와 조회 SQL |
token | 답변 내용 추가 |
chart_loading, data_table | 차트 준비 상태와 결과 |
done, error | 완료와 실패 처리 |
SSE 이벤트는 빈 줄로 구분합니다. 아래는 하나의 메시지를 인코딩하는 최소 예시입니다. event에는 서버가 정의한 이벤트 이름을 사용합니다.
import json
def encode_sse(event: str, payload: dict) -> str:
data = json.dumps(payload, ensure_ascii=False)
return f"event: {event}\ndata: {data}\n\n"실제 API에는 스트리밍 응답과 연결 종료·취소 처리가 더 필요합니다. POST로 질문을 전송하는 흐름에서는 fetch 응답 스트림을 사용했습니다. 브라우저의 기본 EventSource와 같은 호출 방식은 아닙니다.
스트림 청크와 이벤트 메시지
네트워크에서 읽은 청크 하나가 이벤트 한 개나 모델 토큰 하나와 일치하지는 않습니다. UTF-8 문자와 줄, 이벤트 메시지가 여러 청크에 걸쳐 나뉠 수 있습니다.
수신 측에서는 디코더 상태를 유지하고, 완성되지 않은 부분을 버퍼에 남겨야 합니다. data:가 여러 줄이면 합치고 빈 줄에서 메시지를 처리하는 식으로 SSE 규칙에 맞춰 파싱해야 합니다. 한 줄을 받자마자 무조건 JSON으로 파싱하는 예시로는 여러 청크로 나뉘어 도착하는 메시지를 처리하기 어렵습니다.
프록시의 버퍼링과 연결 제한도 봐야 했습니다. 앱이 스트림을 보냈는데 중간 프록시가 모아서 전달하면 화면에는 한 번에 나타날 수 있기 때문입니다.
답변과 차트 설정의 분리
조회 결과를 해석할 때 차트 종류와 축에 사용할 컬럼도 함께 제안하도록 했습니다. 초기 구현에서는 답변 뒤에 ---CHART_CONFIG--- 마커와 JSON 설정을 출력하는 방법을 사용했습니다.
마커도 청크 사이에서 나뉠 수 있어 약 30자 대기 버퍼를 두고 완성된 마커인지 확인했습니다. 설정을 읽는 동안 차트 준비 상태를 보내고, 파싱한 뒤 표와 차트 데이터를 전달했습니다.
차트 설정이 왔다고 바로 그릴 수는 없습니다. 허용한 차트 종류인지, 지정한 컬럼이 실제 결과에 있는지, 숫자·날짜 타입이 맞는지 확인해야 합니다. 사용할 수 없는 설정이면 표만 보여주는 등 실패 처리도 필요합니다. 설명 문장과 시각화 결과가 같은 데이터를 사용하는지도 함께 봐야 했습니다.
컨테이너 배포와 인증 정보
프론트엔드를 빌드한 정적 파일과 Python 백엔드를 하나의 컨테이너 이미지에 넣고, FastAPI에서 화면도 제공했습니다. 완성한 이미지는 사내 컨테이너 플랫폼에 배포했습니다.
ARM64 이미지로 구성하면서 실행 환경과 Python 의존성이 맞는지 확인해야 했고, Databricks 자격 증명은 시크릿 관리 경로에서 전달받도록 했습니다. 화면을 띄운 뒤에도 모델 호출·SQL 조회·문서 검색이 동작하는지 각각 확인해야 했습니다.
질문과 결과의 검증
프롬프트와 예시 쿼리를 바꾸면 같은 질문의 결과도 달라질 수 있습니다. 자주 사용하는 질문과 기대한 집계, 근거 문서를 함께 두고 변경 전후를 비교할 필요가 있었습니다.
숫자가 그럴듯하거나 차트가 보인다는 이유로 답변을 맞다고 볼 수는 없습니다. 잘못된 집계, 오래된 인덱스, 일부만 반환된 결과를 구분하고 오류는 화면에서도 실패 상태로 남겨야 했습니다.
이 작업으로 감사 데이터를 질문하고 스트리밍 답변과 차트로 확인하는 화면까지 연결했습니다. 다만 화면이 동작하는 것과 답변이 맞는지는 따로 확인해야 했습니다. 질문별 집계 결과와 근거 문서를 비교하는 검증, 데이터와 인덱스가 바뀔 때의 재확인은 계속 필요한 작업으로 남았습니다.
이후 Text-to-SQL 엔진을 바꾼 과정은 Genie 도입 글에 이어서 정리했습니다.