BYEORI

CASE STUDY/askline

Askline

문의를 비공개 스레드로 접수하고, AI가 만든 답변 초안을 담당자가 승인해 보내는 디스코드 봇

결과물접수부터 기록까지 9장

봇은 서버에 초대해야 동작하므로 웹 데모 대신 실제 화면을 순서대로 올립니다.

디스코드 채널에 상시 게시된 문의 접수 패널. 파란 임베드에 접수 안내와 문의 유형 선택 드롭다운이 있다
1 — 채널에 상시 게시되는 접수 패널. 유형을 고르면 바로 다음 단계로 넘어갑니다
기타 문의 접수 모달. 제목과 내용 입력란이 있고 전송 버튼이 있다
2 — 제목과 내용만 받습니다. 유형은 앞 단계에서 이미 골랐습니다
티켓-0009 상태 카드. 제목·문의자·접수 시각과 함께 상태가 초안 준비됨, 근거 FAQ 8번으로 표시되고 해결됨으로 닫기 버튼이 있다
3 — 비공개 스레드가 열리고 상태 카드 한 장이 생깁니다. 이 카드는 새 메시지를 쌓지 않고 제자리에서 갱신됩니다
담당자 DM으로 온 답변 초안 카드. 문의 원문과 답변 초안, 근거 FAQ 번호가 있고 그대로 보내기·고쳐 보내기 버튼이 있다
4 — 초안은 담당자 DM으로만 갑니다. 스레드에 올리면 문의자가 승인 전 초안을 먼저 보게 됩니다
담당자가 승인한 답변이 스레드에 게시되고 상태 카드가 답변 완료로 바뀐 화면
5 — 담당자가 버튼을 눌러야 답변이 나갑니다. 자동으로 보내는 경로는 없습니다
종료된 티켓. 상태 카드가 종료됨으로 바뀌고 대화 전문 텍스트 파일이 첨부되었으며 처리 시간 3분, 첫 응답 128초, AI 초안 채택이 요약으로 표시된다
6 — 닫으면 대화 전문이 파일로 첨부되고, 처리 시간과 첫 응답이 함께 남습니다
구글 시트 티켓기록 탭. 티켓 번호·유형·접수·첫응답·종료·소요시간·AI초안 채택 여부·근거 FAQ·요약이 행으로 쌓여 있다
7 — 종료된 상담은 시트에 한 줄씩 쌓입니다. AI 초안을 채택했는지 안 했는지도 함께 기록됩니다
상태가 근거 없음, 담당자가 직접 확인합니다로 표시된 회색 티켓 카드
8 — FAQ에 근거가 없으면 초안을 만들지 않고 사람을 부릅니다. 카드도 회색으로 내려앉습니다
구글 시트 FAQ 탭. 번호·유형·질문·답변·사용 열에 여덟 줄의 FAQ가 들어 있다
9 — 봇의 지식은 코드가 아니라 이 시트에 있습니다. 한 줄 추가하면 1분 안에 답변이 달라집니다
문제어떤 문제를 풀었나

작은 팀의 고객 문의는 공개 채널과 DM으로 흩어집니다. 누가 언제 무엇을 물었는지, 얼마 만에 답했는지가 남지 않고 같은 질문에 매번 처음부터 답하게 됩니다. 그렇다고 AI에 맡기자니 이번엔 다른 걱정이 생깁니다. 봇이 없는 사실을 지어내면 그건 회사가 한 말이 되고, 잘못 나간 답변은 주워담을 수 없습니다.

Askline은 그 둘 사이를 갈랐습니다. AI는 초안까지만 만들고 담당자에게 DM으로 보냅니다. 발송 버튼을 누르는 것은 사람이고, 자동으로 보내는 경로는 아예 없습니다. 그리고 근거로 삼을 FAQ가 없으면 답을 지어내지 않고 사람을 부릅니다.

구현어떻게 만들었나

Python과 discord.py로 만들었고, 티켓 원장은 SQLite, 답변 초안은 Groq, 지식과 기록은 구글 시트를 씁니다. 티켓은 채널을 새로 만들지 않고 비공개 스레드로 열어 문의자와 담당자만 보게 했습니다. 접수 패널과 각 티켓의 버튼은 봇을 다시 켜도 그대로 동작합니다.

AI를 통제하는 방식이 이 작업의 중심입니다. 형식은 모델이 지키고, 근거는 코드가 검증합니다. 출력 JSON은 모델이 스키마를 벗어날 수 없도록 강제하지만, 스키마로는 "이 FAQ 번호가 실제로 존재하는가"를 막을 수 없습니다. 없는 번호는 스키마상 완벽히 유효한 정수이기 때문입니다. 그래서 근거 검증은 순수 함수로 따로 두고, 존재하지 않는 번호를 인용하면 근거 없음으로 강등하고 근거 없이 나온 초안은 버립니다. 이 규칙들은 단위 테스트로 고정되어 있습니다.

모델로 나가는 문의 본문에는 마스킹을 겁니다. 전화번호·이메일·카드번호·주민등록번호를 가린 사본만 보내고, 담당자가 보는 화면과 대화 전문에는 원문을 그대로 둡니다. 보내지 않은 데이터는 샐 수 없습니다. 계좌번호는 은행마다 자릿수가 달라 오탐이 커서 다루지 않았습니다.

기록은 SQLite가 원본이고 구글 시트는 운영자용 사본입니다. 시트 적재가 실패해도 기록은 유실되지 않고 경고만 남습니다. 같은 이유로 모델 호출이 실패해도 접수·상담·종료는 그대로 동작합니다 — 키를 일부러 틀린 값으로 바꿔 확인했습니다. 초안이 없을 뿐입니다.

운영자가 코드를 몰라도 답변을 바꿀 수 있어야 인수인계가 끝납니다. FAQ는 시트에 있고 봇은 그것을 1분 간격으로 다시 읽습니다. 시트에 한 줄 추가하면 배포 없이 답변이 달라지고, 사용 열을 비우면 그 항목만 잠시 끌 수 있습니다.

기술 스택사용한 기술
Pythondiscord.pySQLiteGroqGoogle Sheets API테스트 70개
← 작업물 색인으로