셀프호스팅 AI 도구를 고객에게 팔 때 — n8n의 내부 업무 목적과 Open WebUI의 50명이 갈리는 자리
셀프호스팅 AI 도구 다섯 개의 라이선스 원문을 직접 받아 읽었어요. n8n은 용도로, Dify는 구성으로, Open WebUI는 브랜딩 제거에 인원 임계로 선을 그어요. 선의 종류가 서로 달라요.
AI 기술을 누구나 쉽게 활용할 수 있도록 실전 가이드를 작성합니다. ChatGPT, Claude, AI 자동화, SEO 분야를 전문으로 다룹니다.
디스코드 서버가 커지면 모더레이터가 먼저 지쳐요. 욕설·스팸 신고를 하루 종일 붙잡고 있다 보면 정작 커뮤니티를 키우는 일을 못 하거든요. 사람을 더 뽑기 전에 반복 판정부터 자동으로 걸러내는 게 순서예요.
이 글은 그 봇을 처음부터 만드는 7단계예요. Claude API + OpenAI Moderation API + discord.py 조합. 단순 욕설 차단이 아니라 의미 이해·맥락 판별·한국어 안내까지 자동화하는 구조. 호스팅은 Oracle Cloud Free tier를 쓰면 별도 비용이 안 들고, 무료 Moderation API로 1차 필터를 걸면 AI 호출량도 크게 줄어요.

Carl-bot·Dyno·YAGPDB가 10년 가까이 디스코드 모더레이션을 책임졌어요. 그런데 2026년 들어 한계가 뚜렷해졌거든요.
OpenAI Moderation API의 omni-moderation-latest는 13개 카테고리(harassment·hate·sexual·violence·self-harm 등) 점수를 0~1로 반환해요. 텍스트뿐 아니라 이미지도. Claude API는 그 점수 위에서 "어떤 톤의 한국어 안내를 보낼지", "이 맥락이 진짜 위협인지" 같은 후속 판단을 해요.
예를 들어 "너 진짜 죽고 싶냐"는 harassment 점수가 높게 나와요. 그런데 이게 게임 채널의 농담인지, 특정 유저를 향한 협박인지는 점수만으론 못 갈라내거든요. Claude에 채널 이름과 그 유저의 최근 발언을 같이 넘기면 "직전에 서로 장난치던 사이"라는 맥락을 읽고 무시로 판단해요. 반대로 처음 들어온 유저가 특정인을 지목했으면 timeout으로 올려요. 점수는 OpenAI가, 판단은 Claude가 나눠 맡는 구조예요.
다층 방어(Defense in Depth)는 보안 설계의 일반 원칙이에요. 분류기 하나에만 의존하면 그게 뚫릴 때 통째로 무너지거든요. 저는 이 원칙에 따라 ① 룰베이스 1차(이모지 도배·링크 스팸) ② OpenAI Moderation 2차 ③ Claude 3차 어필 검토 3단으로 짰어요.
Privileged Intents 3개 활성화 필수 — Server Members, Message Content, Presence. 이거 안 하면 메시지 본문 못 읽어요.
# Oracle Cloud Always Free: VM.Standard.A1.Flex 4 OCPU / 24GB RAM
# 영구 무료, 신용카드 인증만 필요
ssh ubuntu@your-oracle-ip
sudo apt update && sudo apt install python3-pip
pip3 install discord.py==2.4.0 anthropic openai python-dotenv
.env 파일 (절대 git 커밋 금지):
DISCORD_TOKEN=MTxxx...
ANTHROPIC_API_KEY=sk-ant-xxx
OPENAI_API_KEY=sk-xxx
GUILD_ID=123456789
LOG_CHANNEL_ID=123456789
from openai import OpenAI
client = OpenAI()
def moderation_score(text: str) -> dict:
resp = client.moderations.create(
model="omni-moderation-latest",
input=text
)
result = resp.results[0]
return {
"flagged": result.flagged,
"harassment": result.category_scores.harassment,
"hate": result.category_scores.hate,
"violence": result.category_scores.violence,
}
무료예요. 메시지가 하루 종일 고르게 흩어져 들어오는 커뮤니티라면 rate limit에 여유가 있는 편이에요. 다만 이벤트나 공지 직후처럼 순간적으로 몰릴 때를 대비해 재시도 로직은 넣어두세요.
Moderation 점수 0.7 이상 메시지만 Claude로 보내요. 비용 절감 + 정확도 향상.
from anthropic import Anthropic
anthropic = Anthropic()
def claude_analyze(message: str, channel_name: str, user_history: str) -> dict:
prompt = f"""당신은 한국어 디스코드 서버 모더레이터예요.
채널: {channel_name}
유저 최근 7일 발언 요약: {user_history}
현재 메시지: "{message}"
다음 JSON으로 답하세요:
- intent: "joke" | "insult" | "spam" | "threat"
- severity: 1-10
- action: "ignore" | "warn" | "timeout_10m" | "timeout_1h" | "ban"
- korean_dm: 유저에게 보낼 한국어 안내 메시지 (반말 X, 정중하게)
"""
resp = anthropic.messages.create(
model="claude-haiku-4-5",
max_tokens=300,
messages=[{"role": "user", "content": prompt}]
)
import json
return json.loads(resp.content[0].text)
채널 이름·유저 발언 요약을 같이 넘기는 게 핵심이에요. "농담인지 진짜 모욕인지"를 LLM이 맥락으로 판단.
import discord
from discord.ext import commands
bot = commands.Bot(command_prefix="!", intents=discord.Intents.all())
@bot.event
async def on_message(msg):
if msg.author.bot:
return
# 1차: 룰베이스 (링크 스팸·이모지 도배 등 — 별도 함수)
if rule_based_block(msg.content):
await msg.delete()
return
# 2차: OpenAI Moderation
score = moderation_score(msg.content)
if score["flagged"] is False:
return
# 3차: Claude 맥락 분석
history = await get_user_history(msg.author.id)
analysis = claude_analyze(msg.content, msg.channel.name, history)
# 자동 처벌
await execute_action(msg, analysis)
await log_to_mod_channel(msg, analysis)
자동 처벌 활성화 전 2주는 로그만. 모더레이터 채널에 "이 메시지가 처벌됐을 것"을 게시. 사람이 검수해서 false positive 비율을 측정하세요. 처음엔 오탐이 많이 잡히는 게 정상이에요. 임계값을 조금 올리고 다시 한 주 재보는 식으로 좁혀 가면, 우리 서버 말투에 맞는 선이 데이터로 드러나요.
DRY_RUN = True # 2주 후 False
if DRY_RUN:
await log_only(msg, analysis)
else:
await execute_action(msg, analysis)
자동 처벌된 모든 케이스는 #appeals 채널에 자동 게시 + 봇이 유저 DM에 "잘못된 처벌이라 생각하시면 #appeals에 글 남겨주세요" 안내. 1주일 내 모더레이터 1명이 검토 → 잘못이면 timeout 해제 + Claude 분석 로그를 학습 데이터로 누적.
저는 이 누적 로그를 매주 일요일에 Claude Sonnet 4.6으로 요약해요. "이번 주 false positive 패턴" 리포트 → 임계값 미세조정.
봇을 켜놓고 "잘 돌아가는 것 같다"고 넘기면 어느 순간 오탐이 쌓여도 모릅니다. 남의 서버 수치를 그대로 가져다 쓰는 것도 의미가 없어요. 서버 성격에 따라 정상 범위가 완전히 다르거든요. 대신 아래 항목을 우리 서버에서 직접 세면 판단 근거가 생겨요.
| 지표 | 왜 재는가 |
|---|---|
| 일평균 메시지 수 | 모든 비율의 분모예요. 먼저 잡아야 나머지가 해석돼요 |
| Moderation flagged 비율 | 갑자기 튀면 스팸 유입이나 임계값 문제 신호 |
| Claude 2차 분석 호출 수 | AI 비용에 직결돼요. 여기가 늘면 1차 필터를 조여야 해요 |
| 자동 timeout·ban 건수 | 과잉 차단 여부를 보는 지표 |
| 어필 접수 대비 인정 비율 | 인정률이 높으면 임계값이 너무 낮다는 뜻 |
| 모더레이터 처리 시간 | 자동화 전후를 비교해야 효과가 보여요 |
숫자를 모으는 방법은 어렵지 않아요. 봇이 판정할 때마다 타임스탬프·채널·Moderation 점수·최종 조치를 한 줄씩 로그 파일이나 시트에 남기게 해두면 끝이에요. 이 로그를 주 1회 집계해서 지표 흐름만 보면 충분해요.
비용 구조에서 기억할 것: 상위 모델을 모든 메시지에 붙이면 비용이 빠르게 불어요. 가벼운 모델로 1차 분석하고, 어필 검토처럼 판단이 무거운 곳에만 상위 모델을 쓰는 2모델 구조가 효율적이에요. 무료 Moderation API를 앞단에 두면 애초에 LLM까지 넘어가는 메시지 자체가 줄어들고요.
핵심은 하나의 숫자로 통일하지 않는 거예요. 한 값으로 고정하면 한쪽은 과잉 차단, 다른 쪽은 구멍이 뚫리거든요. 저는 서버를 세 가지 유형으로 나누고, 각 유형의 값은 데이터로 잡아요.
게임 서버는 트래시토크가 문화예요. "이 새끼 에임 뭐냐"가 애정 표현일 때가 많거든요. 그래서 게임 채널만 임계값을 0.9로 높이고, Claude 프롬프트에 "이 채널은 경쟁 게임 채널이라 거친 표현이 기본"이라고 맥락을 넣어요. 그러면 false positive가 확 줄어요.
스터디·정보 커뮤니티는 반대예요. 인신공격은 드물고, 홍보 스팸과 외부 링크 도배가 주적이거든요. 여기선 Moderation 임계값을 0.65까지 낮추고, 링크 스팸 룰베이스를 더 촘촘하게 걸어요.
판매·거래 서버는 사기와 계정 도용 유도가 제일 위험해요. "DM으로 시세 알려드려요" 같은 유인 문구는 Moderation 점수가 안 올라가거든요. 그래서 이런 서버는 AI보다 "DM 유도 + 외부 링크" 패턴 룰베이스를 1차 방어로 두는 게 나아요. 같은 코드라도 서버 유형만 바꿔서 임계값 프리셋을 세 벌 만들어두면 관리가 훨씬 편해져요.
각 유형의 구체적인 값은 감이 아니라 데이터로 잡아요. dry-run 2주 동안 쌓인 로그에 각 메시지의 Moderation 점수와 '사람이 봤을 때 진짜 처벌감인가'를 같이 기록해두세요. 2주 뒤 점수 구간별로 정답률을 뽑아보면 경계가 드러나거든요. 오탐이 몰리는 구간과 거의 다 진짜 처벌감인 구간이 갈리는데, 그 경계 바로 위를 기본 처벌 선으로 잡으면 돼요. 이 값도 고정이 아니에요. 은어와 밈이 계속 바뀌니까 새 우회 패턴이 보일 때마다 룰베이스에 추가하고 임계값을 조금씩 미세조정하면, 시간이 갈수록 봇이 서버 말투에 맞게 다듬어져요.
Discord는 GitHub Secret Scanning 파트너라 토큰이 public repo에 push되면 30분 안에 자동 revoke해요. 그 사이 누가 가져가서 도배 봇 만들면 서버 삭제 위험. .env + .gitignore + Oracle 환경변수에 직접 등록 3중 방어 필수.
Message Content 같은 Privileged Intents는 봇이 들어간 서버가 100개 미만이면 개발자 포털에서 토글만 켜면 돼요. 그런데 봇이 100개 서버를 넘는 순간부터는 Verified Bot 인증 + Intents 심사를 통과해야 그 권한을 유지할 수 있어요. 심사는 보통 2주 안팎 걸리거든요. 봇을 공개해서 여러 서버에 뿌릴 계획이면, 트래픽 몰리기 전에 미리 인증을 신청하세요. 심사 양식엔 왜 message content가 필요한지 영어로 적어야 해요.
Anthropic Tier 1은 분당 50 RPM. 중소 규모 서버는 여유가 있지만 인원이 크게 늘면 상위 Tier로 올려둬야 해요. 등급별 조건은 Anthropic 콘솔에서 확인하세요. 미리 안 풀어두면 정작 트래픽 급증 시 봇 다운.
자체 리트라이 큐(exponential backoff 1s → 30s)도 코드에 박아두세요.
봇을 실서버에 붙이기 전에 이것만 확인하세요.
이 여섯 개만 지키면 초기 2주에 터질 사고를 거의 다 막을 수 있어요.
Claude API 활용 자동화는 n8n + Claude API 자동화 5단계에서, GitHub Actions와 결합한 PR 리뷰 자동화는 GitHub Actions Claude Code PR 자동 리뷰 5단계에서 더 깊이 다뤘어요. AI 에이전트 개발 전반은 OpenAI Agents SDK 멀티스텝 가이드 함께 보시면 도움돼요.
디스코드 모더레이션은 사람이 24시간 보는 게 비효율이에요. AI 봇을 한 번 세팅해두면 반복 판정은 봇이 24시간 맡고, 사람은 어필 검토처럼 판단이 필요한 일만 챙기면 되거든요. 핵심은 룰베이스·OpenAI·Claude 3단 방어 + dry-run 2주 + 어필 채널 의무화. 이 세 가지만 지키면 false positive로 멀쩡한 유저 잃을 일 없어요.
한 가지 더 강조하고 싶은 건 자동 처벌의 투명성이에요. 봇이 timeout을 걸 때 그 이유와 함께 "이 결정은 AI가 내렸고, 잘못이라 생각하면 #appeals에 적어주세요" 안내가 자동으로 가야 해요. 이게 없으면 유저가 "왜 갑자기 막혔지" 화 내며 서버 떠나요. 모든 자동 처벌 메시지에 어필 경로를 명시하는 게 커뮤니티 신뢰의 핵심이에요. 안내를 붙이면 어필 접수는 늘어나지만, 그건 나쁜 신호가 아니에요. 말없이 떠나던 사람이 대화 창구로 들어왔다는 뜻이거든요. 운영 효율과 유저 신뢰는 양립 가능해요.
Carl-bot·Dyno·YAGPDB는 키워드 매칭이라 우회가 쉬워요. ㅅㅂ을 ㅅ ㅂ로 띄우면 못 잡거든요. AI 봇은 의미를 이해해서 띄어쓰기 우회·은어·맥락(게임 채널의 nice kill은 위협 아님)까지 판별해요. 저는 Carl-bot은 룰 기반 자동 처벌(스팸·이모지 도배)에 두고, 미묘한 인신공격·간접 욕설은 AI 봇이 잡는 2단 구조로 운영해요.
네, 2026년 5월 기준 omni-moderation-latest 엔드포인트는 완전 무료예요. rate limit은 있지만 계정 등급에 따라 달라요. 텍스트뿐 아니라 이미지도 분류해서 NSFW·증오·자해 등 13개 카테고리 점수를 0~1로 반환. 중소 규모 커뮤니티의 메시지량이면 rate limit에 걸릴 일이 드물지만, 서버가 커질수록 여유를 미리 확인해 두세요.
Moderation API는 분류만 해요. 점수 높으면 어떻게 대응할지(경고 메시지 한국어로·timeout 시간 결정·DM 안내문 작성)는 모델이 따로 필요. 가벼운 모델을 쓰면 부담이 크지 않은데, 정확한 단가는 Anthropic 공식 요금 페이지에서 확인하세요. omni-mod로 1차 필터 → score 0.7 이상만 Claude로 2차 분석 → 한국어 톤으로 안내. 분리해야 비용 안정돼요.
Python 친숙하면 discord.py 2.4 권장. Node 환경이면 discord.js v14(현행 안정 메이저). 저는 discord.py 골랐어요 — Anthropic SDK·OpenAI SDK 둘 다 Python이 1차 지원이라 의존성 관리가 단순. 단 Cloudflare Workers에 올릴 거면 discord.js + Hono가 유일한 선택지예요(Python은 Workers 미지원).
처음 2주는 dry-run 모드 추천이에요. 차단 대신 모더레이터 채널에 로그만 남겨서 '이거 자동 처벌됐을 메시지'를 사람이 검수. 점수 임계값(저는 0.85)을 데이터 기반으로 조정한 뒤 활성화. 또 모든 자동 처벌은 #appeals 채널에 자동 게시 + 1주일 내 사람 재검토 룰 박아두면 분쟁 거의 없어져요.
서버 메시지량과 모델 선택에 따라 달라져서 한 줄로 못 박기 어려워요. 다만 구조가 비용을 결정해요. 무료인 OpenAI Moderation으로 1차 필터를 걸고, 점수가 높은 소수만 Claude로 2차 분석하면 LLM 호출량 자체가 크게 줄거든요. 호스팅은 Oracle Cloud Free tier를 쓰면 별도 비용이 안 들고 Discord Bot 자체도 무료예요. 정확한 추산은 dry-run 2주 동안 실제 2차 분석 호출 건수를 세어보고 공식 요금표 단가를 곱하는 방식이 가장 확실해요.
Discord 봇 토큰은 즉시 무력화돼요(Discord가 GitHub Secret Scanning 파트너라 30분 안에 봇 token revoke + 새로 발급 강제). Anthropic 키도 같은 패턴이지만 그 사이 도용되면 크레딧 수백 달러 털릴 수 있어요. .env에 두고 .gitignore 필수, 배포는 Oracle/Render 환경변수에 직접 입력. 노출됐다면 즉시 발급기관 대시보드에서 revoke부터.