인프런 챌린지 채점 시스템, 디스코드 봇으로 구현했습니다: 심화 미션을 받고 유사도로 판정하기까지
이 글의 독자인프런 챌린지나 사내 자동화 공모전처럼 제출물을 받아 피드백해야 하는 운영자, 그리고 지난 n8n 챌린지에서 채점봇을 겪어 본 참여자
한줄 요약: n8n 6주 완독 챌린지의 심화 미션은 디스코드 봇이 받았습니다. 그 봇은 제출된 워크플로 27건을 저장하지 않고 버렸고, 저는 라이브 방송 전날에야 그걸 알았습니다. 봇의 구조는 단순합니다. 참여자가 슬래시 커맨드로 JSON 파일을 올리면 책 원본과 유사도를 재서 원본 그대로면 인증만, 조금 바꿨으면 AI 코멘트, 많이 바꿨으면 AI 코멘트에 운영자 호출까지 세 갈래로 처리합니다. 이 글은 그 봇을 어떻게 만들었고 무엇을 잘못했는지 적은 기록입니다.
목차
- 챌린지에 채점봇이 왜 필요했나
- 첫 설계를 버렸다: 웹사이트에서 디스코드 봇으로
- 전체 구조 한 장
- 채점 방식: 책 원본과 유사도를 잰다
- 사람들은 어떻게 반응했나
- 사고: 제출된 워크플로를 저장하지 않았다
- 다음에 비슷한 걸 만든다면
1. 챌린지에 채점봇이 왜 필요했나
앞선 글에서 다룬 챌린지의 구조는 이렇습니다. 매주 책의 진도에 맞춰 기본 미션과 심화 미션이 나갑니다. 기본 미션은 책을 따라 만들고 블로그에 인증하면 끝이고, 인프런 챌린지 페이지가 출석과 완주를 관리합니다. 심화 미션은 같은 뼈대를 자기 일상에 응용하는 것인데, 여기에는 두 가지 문제가 있었습니다.
| 문제 | 상황 |
|---|---|
| 복붙 제출 | 책의 예제 워크플로가 깃허브에 공개되어 있어 그대로 내도 티가 안 남 |
| 저자 두 명의 한계 | 신청 319명. 디스코드 봇에만 1주 차에 19명이 워크플로 21건을 올림. JSON을 하나씩 열어 볼 시간이 없음 |
| 피드백 지연 | 사람이 보면 며칠 뒤에 답이 감. 응용을 시도한 사람일수록 바로 반응이 필요 |
그래서 처음 세운 목표는 셋이었습니다. 워크플로를 제출하면 AI가 1차 피드백을 즉시 달 것, 책 원본을 그대로 낸 것과 직접 응용한 것을 구분할 것, 저자는 응용한 사람에게만 시간을 쓸 것. 2026년 4월 17일, 이 세 줄로 설계를 시작했습니다.
2. 첫 설계를 버렸다: 웹사이트에서 디스코드 봇으로
처음 만든 것은 제출 웹사이트였습니다. 이메일로 로그인 링크를 받아 들어와서 JSON 파일과 스크린샷을 올리면, 서버리스 함수 다섯 개가 저장, AI 피드백, 이메일 발송, 관리자 화면을 나눠 맡는 구조였습니다. 4월 21일에 동작하는 상태까지 갔습니다.
그리고 일주일 뒤에 통째로 접었습니다.
v1. 제출 웹사이트 (4월 17일 착수, 4월 28일 보관 처리)
출석 관리까지 떠안은 별도 시스템. 인프런이 이미 하는 일
v2. 디스코드 봇 (4월 28일 전환, 같은 날 테스트 통과)
출석은 인프런, 피드백은 디스코드. 봇은 피드백만 맡는다
3. 전체 구조 한 장
운영한 구조를 한 장으로 그리면 아래와 같습니다. 참여자가 만지는 것은 디스코드뿐이고, 나머지는 서버리스 함수 하나가 바깥 서비스 세 곳을 호출합니다.
디스코드 서버는 이렇게 생겼습니다. 공지, 수다, welcome 세 채널은 누구나 보고, 자물쇠가 붙은 나머지 채널은 인증을 마친 학습자만 봅니다. 주차별 채널 여섯 개가 봇이 동작하는 자리입니다.
채팅창에 슬래시를 치면 봇의 명령어 두 개가 뜹니다. 시작하기는 인프런 닉네임으로 학습자 권한을 받는 것이고, 피드백은 워크플로 파일을 올리는 것입니다.
처음에는 피드백 명령에 옵션이 넷이었습니다. 파일, 주차, 유형(기본인지 심화인지), 메모. 테스트해 보니 채팅창에서 네 칸을 채우는 게 번거로웠고, 따져 보면 주차는 채널이 이미 말해 주고 유형은 봇이 유사도로 판정할 수 있었습니다. 그래서 옵션을 파일 하나로 줄였습니다. 참여자가 고를 것이 없을수록 제출이 늘어납니다.
4. 채점 방식: 책 원본과 유사도를 잰다
이 봇의 핵심은 “책을 그대로 따라 만든 것인지, 자기 것을 만든 것인지”를 사람 손 없이 가르는 부분입니다. AI에게 물어볼 수도 있었지만, 그러면 제출마다 AI 호출이 나가고 판정도 흔들립니다. 대신 책 원본 워크플로 여섯 개를 봇 안에 넣어 두고, 제출된 JSON과 직접 비교했습니다.
n8n 워크플로 JSON은 노드의 목록입니다. 노드마다 종류(type)와 설정값(parameters)이 있습니다. 비교는 세 층으로 했습니다.
| 층 | 재는 것 | 계산 | 가중치 |
|---|---|---|---|
| 노드 수 | 원본과 제출본의 노드 개수 | 작은 쪽 ÷ 큰 쪽 | 20% |
| 노드 종류 | 같은 종류의 노드가 얼마나 겹치는가 | 겹치는 수 ÷ 많은 쪽 개수 | 30% |
| 설정값 | 같은 종류끼리 짝지어 설정값을 하나씩 대조 | 일치한 값 ÷ 전체 값 | 50% |
세 값을 가중 평균한 것이 유사도입니다. 설정값에 절반을 준 이유는, 노드 종류가 같아도 RSS 주소나 검색 키워드, 이메일 수신자를 바꿨다면 그건 자기 것을 만든 것이기 때문입니다. 반대로 노드를 몇 개 더 붙였더라도 설정값이 원본 그대로라면 응용이 아닙니다.
유사도가 나오면 세 갈래로 나눕니다.
| 유사도 | 판정 | 봇이 하는 일 | AI 호출 |
|---|---|---|---|
| 95% 이상 | 책 원본 그대로 | 인증 처리 메시지만. “응용을 시도하면 다시 올려 보세요” | 없음 |
| 70% 이상 95% 미만 | 조금 바꿈 | 기본 미션 톤으로 요약과 개선 제안 1개 | 있음 |
| 70% 미만 | 많이 바꿈 | 심화 톤으로 요약과 제안 + @운영자 태그로 저자 호출 | 있음 |
AI 피드백은 Gemini 2.5 Flash를 썼고, 생각 모드(thinking)는 껐습니다. 답은 자유 문장이 아니라 정해진 JSON 형식으로 받습니다. 요약 한 단락, 원본 대비 바꾼 흔적 최대 3개, 개선 제안 2개에서 3개, 복붙 위험도(low, mid, high). 채널에는 이 중 요약과 제안 하나만 서너 줄로 보여 줍니다. 처음 버전은 이보다 길었는데, 채팅창에서 긴 답글은 아무도 읽지 않습니다.
5. 사람들은 어떻게 반응했나
1주 차 채널의 실제 화면입니다. 봇의 답글은 체크 표시, 닉네임, 노드 수와 유사도, 요약, 제안 하나, 그리고 노란 @운영자 태그 순서로 나갑니다. 이 태그가 저자 호출입니다. 개인정보 보호를 위해 참여자 닉네임과 프로필 사진은 가렸습니다.
1주 차에 노드가 50개를 넘는 워크플로가 올라왔습니다. 처음 올린 판이 55개, 손봐서 다시 올린 판이 54개였고, 책 예제는 9개입니다. 봇은 두 번 다 유사도 12%를 매기고 저자를 호출했고, 두 번째 답글 아래 스레드가 열렸습니다.
“노드가 50개요..?🤯🤯” (저자 임정, 스레드 첫 답글)
“아 네.. 총 9군데인데 8개 rss뉴스와 1개의 html 스크래핑해서 merge해서 하다보니 그런거 같네요..” (참여자 강*이 님)
“자동 피드백으로는 loop기능활용하라는데 아직거기까진 안배워서요 ㅎㅎ” (참여자 강*이 님)
“AI가 잘모르고 말하는거같네요 ㅋㅋ loop는 없고 batch는 있어요. 요거 수정해보겠습니다. 한번 워크플로우 스크린샷 찍어주실래요?” (저자 임정)
여기서 AI 피드백의 한계와 쓸모가 동시에 드러납니다. 봇은 “반복되는 노드를 하나로 묶으라”는 방향은 맞게 짚었지만, 참여자가 그 주에 배운 범위를 모릅니다. 저자가 스레드에서 그 간극을 메웠습니다. 며칠 뒤 참여자가 워크플로 화면을 올렸고, 대화는 이렇게 이어졌습니다.
“아하! 댓글 달아야 보실수 있는거군요. 스크린샷남겼읍니다. 저도 노드 수를 줄이고 싶긴한데.. 데이터를 재정제해서 합치는 것과 요약해서 재정리 하다보니 다른 노드가 있는지도 모르겠네요 결국 코드로..” (참여자 강*이 님)
“지금 머지 노드가 여러단계인데 이전 limit 결과값을 통일하여서 merge-append하면 여러개 통합할수 있을 것 같네요!” (저자 임정)
“아니면 코드노드 쓰셔도 무방하구요 복잡한 로직아니니” (저자 임정)
반응이 다 좋았던 것은 아닙니다. 봇을 처음 보는 사람은 어디에 무엇을 내야 하는지 몰랐습니다. 첫 제출자는 슬래시 커맨드 대신 노션 링크를 채널에 붙이고 “이렇게 제출하는게 맞는 것인지 모르겠네요”라고 썼고, 일주일 뒤 다른 참여자도 같은 문장을 남겼습니다. 안내 메시지를 채널 상단에 고정해 두었어도 처음 온 사람은 읽지 않습니다. 두 번 다 저자가 직접 “슬래시를 치고 피드백을 고르면 자동으로 됩니다”라고 답했습니다.
1주 차 기간(5월 11일부터 17일까지)에 봇이 참여자에게 단 답글을 유사도 구간별로 세면 이렇습니다.
| 구간 | 판정 | 1주 차 건수 |
|---|---|---|
| 95% 이상 | 책 원본 그대로 | 0건 |
| 70% 이상 95% 미만 | 조금 바꿈 | 0건 |
| 70% 미만 | 많이 바꿈, 저자 호출 | 21건 (19명) |
심화 미션을 굳이 디스코드까지 와서 내는 사람은 이미 자기 것을 만든 사람이었습니다. 복붙을 걸러내려고 만든 첫 번째 갈래는 1주 차에 한 번도 쓰이지 않았고, 저자는 21건을 전부 봤습니다.
6. 사고: 제출된 워크플로를 저장하지 않았다
봇은 5월 11일 1주 차 시작과 함께 돌았고, 5월 23일 두 번째 라이브에서 1, 2주 차 제출작 중 재미있는 것을 골라 화면에 띄우며 리뷰할 계획이었습니다. 큐레이션을 준비하려고 채널 메시지를 내려받다가 알았습니다. 봇이 받은 JSON 파일이 어디에도 없었습니다.
원인은 단순했습니다. 봇은 첨부 파일을 디스코드 서버에서 내려받아 AI에 보내고, 답글을 달고, 끝냈습니다. 파일 자체는 저장하지 않았습니다. 디스코드가 봇에게 주는 첨부 파일 주소는 24시간이 지나면 만료됩니다. 2주간 쌓인 제출 27건이 그렇게 사라졌습니다. 봇의 요약 텍스트는 채널에 남아 있었지만, 캔버스에 열어 볼 워크플로는 없었습니다.
| 시점 | 상태 |
|---|---|
| 4월 28일 봇 완성 | 파일 내려받기, 마스킹, AI 호출, 답글까지 테스트 통과. 저장 단계 없음 |
| 5월 11일 1주 차 시작 | 제출이 쌓이지만 파일은 매번 버려짐 |
| 5월 22일 라이브 준비 | 채널 메시지를 수집하다 원본 JSON이 없음을 발견 |
| 5월 23일 수정 배포 | Supabase Storage에 마스킹된 JSON 저장 추가. 이전 27건은 복구 불가 |
라이브에서는 봇의 요약과 유사도를 근거로 후보를 고른 뒤, 해당 참여자에게 스레드로 워크플로를 다시 보내 달라고 부탁했습니다. 앞 절의 55노드 워크플로도 참여자가 스레드에 올린 캔버스 화면으로만 볼 수 있었습니다.
7. 다음에 비슷한 걸 만든다면
인프런 챌린지든 사내 자동화 공모전이든, 제출물을 받아 자동 피드백을 다는 시스템을 만든다면 이 순서를 권합니다.
| 순서 | 할 일 | 이번에 배운 이유 |
|---|---|---|
| 1 | 출석과 피드백의 담당을 가른다 | 인프런이 출석을 맡는 순간 별도 제출 사이트는 이중 작업이 됐다 |
| 2 | 참여자가 이미 쓰는 앱에 봇을 넣는다 | 새 웹사이트의 로그인보다 슬래시 커맨드 하나가 제출 장벽이 낮다 |
| 3 | 제출물을 먼저 저장하고 그다음 처리한다 | 첨부 파일 주소는 만료된다. 27건을 잃었다 |
| 4 | 비밀값 마스킹을 AI 호출과 저장 앞에 둔다 | 워크플로 JSON에는 API 키가 들어 있을 수 있다 |
| 5 | 원본이 있으면 AI 전에 규칙으로 유사도를 잰다 | 판정이 안정적이고, 원본 그대로인 제출에는 AI 비용이 0이다 |
| 6 | 사람을 부르는 기준을 숫자로 둔다 | 저자는 70% 미만만 봤다. 기준은 한 줄 상수라 언제든 조정 가능 |
| 7 | 옵션을 줄인다 | 네 칸에서 한 칸으로 줄이자 제출이 편해졌다 |
| 8 | 첫 제출 안내는 봇이 답글로 한다 | 고정 메시지는 읽지 않는다. 두 명이 같은 질문을 했다 |
봇을 만드는 데 쓴 재료는 이 블로그의 다른 글에 따로 정리되어 있습니다. 디스코드 쪽 연결은 디스코드 웹훅 가이드, 서버리스 함수 배포는 Supabase Edge Function 배포 가이드, 키 종류의 차이는 Supabase 키 가이드를 보시면 됩니다. 챌린지 자체가 어떻게 흘러갔는지는 앞선 글에 있습니다.
댓글