KO ▾
API 키 받기

무검열 LLM을 사용한 오픈 소스 디스코드 봇

LLM을 통해 대화하는 오픈 소스 디스코드 봇은 파이썬으로 약 80줄로 작성됩니다. 이 가이드는 코드, 준수해야 할 한도, 그리고 합법적인 성인 요청을 거부하지 않는 모델을 사용한 OpenAI 호환 API를 통한 응답당 비용을 제공합니다.

채팅 창과 가지치기 코드 트리가 연결된, 빛나는 큐브들로 구성된 봇의 등각 투영 일러스트레이션

업데이트

주요 포인트

  • discord.py와 OpenAI SDK면 충분합니다. SDK를 https://api.openrouternsfw.com/v1에 연결하고 uncensored 모델을 사용하세요.
  • 디스코드 개발자 포털에서 메시지 콘텐츠 권한을 활성화하세요. 활성화하지 않으면 봇이 빈 메시지를 받습니다.
  • 동시성 한도 내에 머무르기 위해 세마포어를 8 미만으로 설정하고, 성인 콘텐츠는 연령 제한 채널로 유지하세요.
  • 입력 토큰 1,500개와 출력 토큰 300개의 응답에는 $0.000375가 들며, 10,000회 응답당 약 $3.75가 듭니다.

카드가 필요 없습니다. 가입 후 한 번의 클릭으로 $0.50 무료 체험 크레딧을 받습니다(인당 한 번).

API 키 받기

빌드할 것

아래 봇은 사용자가 자신을 언급할 때 응답합니다. 채널별로 짧은 대화 기록을 유지하고, 이를 채팅 완성 엔드포인트로 전송한 후 응답을 게시합니다. 데이터베이스가 없는 순수한 파이썬 코드이며 MIT 라이선스에 적합합니다. 모든 코드를 한 번에 읽을 수 있으며, 이것이 오픈 소스 프로젝트의 핵심입니다: 다른 사람이 포크하여 이해할 수 있어야 합니다.

이 봇의 기반 모델은 독립적인 제공자가 운영하는 단일 오픈 웨이트 텍스트 모델로, 합법적인 성인 사용에 대해 콘텐츠 거부 없이 응답하도록 조정되었습니다. 이는 소설, 역할극 또는 성인 대화를 중심으로 한 디스코드 커뮤니티에 적합합니다. 두 가지 규칙이 처음부터 적용됩니다. 첫째, 미성년자가 관련된 성적 콘텐츠는 API에서 허용되지 않으며 봇의 설계에 포함되면 안 됩니다. 둘째, 디스코드에는 자체 규칙과 연령 제한 채널 설정이 있으며 이를 따르는 것은 사용자의 책임입니다. 성인 콘텐츠는 그렇게 표시된 채널과 구성원이 성인인 서버로 제한하세요.

디스코드 및 키 설정

  1. 디스코드 개발자 포털을 열고 애플리케이션을 생성한 후 봇을 추가하세요.
  2. 봇 설정에서 메시지 콘텐츠 의도를 활성화하세요. 이를 활성화하지 않으면 봇이 빈 텍스트가 있는 메시지를 수신합니다.
  3. 봇 토큰을 복사하세요. 비밀번호처럼 취급하세요.
  4. OAuth2 URL 생성기를 사용하여 선택한 채널에서 메시지 읽기 및 보내기 권한으로 봇을 초대하세요.
  5. 키 페이지에서 API 키를 받으세요. 신규 사용자는 결제 정보 없이 한 번의 클릭으로 7일 유효한 $0.50의 무료 체험 크레딧을 청구할 수 있습니다.

두 시크릿을 모두 환경 변수로 저장하고 저장소에는 저장하지 마세요. 오픈 소스 프로젝트의 경우 코드가 공개되므로 이 점이 평소보다 더 중요합니다.

pip install discord.py openai python-dotenv
printf 'DISCORD_TOKEN=your-discord-token
API_KEY=your-api-key
' > .env
echo ".env" >> .gitignore

봇 코드

이를 bot.py로 저장하세요. 주석은 자명하지 않은 결정들을 설명합니다.

import asyncio
import os
from collections import defaultdict, deque

import discord
from dotenv import load_dotenv
from openai import AsyncOpenAI

load_dotenv()

ai = AsyncOpenAI(
    base_url="https://api.openrouternsfw.com/v1",
    api_key=os.environ["API_KEY"],
    max_retries=4,          # the SDK retries 429 and honors Retry-After
)

SYSTEM = (
    "You are Vex, a sharp-tongued storyteller in a Discord server for adults. "
    "Stay in character, keep replies under 150 words, and never write "
    "anything sexual involving minors."
)

intents = discord.Intents.default()
intents.message_content = True
bot = discord.Client(intents=intents)

slots = asyncio.Semaphore(6)                      # stay under 8 concurrent
history = defaultdict(lambda: deque(maxlen=12))   # last 12 turns per channel


async def ask(channel_id, user_text):
    turns = history[channel_id]
    turns.append({"role": "user", "content": user_text})
    messages = [{"role": "system", "content": SYSTEM}] + list(turns)
    async with slots:
        resp = await ai.chat.completions.create(
            model="uncensored",
            messages=messages,
            temperature=0.9,
            max_tokens=400,
        )
    reply = resp.choices[0].message.content or ""
    turns.append({"role": "assistant", "content": reply})
    return reply


@bot.event
async def on_ready():
    print(f"Logged in as {bot.user}")


@bot.event
async def on_message(message):
    if message.author.bot or bot.user not in message.mentions:
        return
    text = message.clean_content.replace(f"@{bot.user.display_name}", "").strip()
    if not text:
        return
    async with message.channel.typing():
        try:
            reply = await ask(message.channel.id, f"{message.author.display_name}: {text}")
        except Exception as exc:
            print("API error:", exc)
            await message.reply("The model is busy. Try again in a few seconds.")
            return
    for i in range(0, len(reply), 1900):          # Discord caps messages at 2000 chars
        await message.reply(reply[i:i + 1900])


bot.run(os.environ["DISCORD_TOKEN"])

python bot.py로 실행한 후, 봇이 읽을 수 있는 채널에서 봇을 언급하세요. 첫 번째 응답은 몇 초 후에 도착해야 합니다.

아무 일도 일어나지 않으면 순서대로 세 가지를 확인하세요. 봇이 멤버 목록에 표시되어야 하므로 토큰이 유효합니다. 해당 채널에서 메시지를 읽고 보내는 권한이 있어야 합니다. 그리고 언급은 봇 이름만 있는 일반 텍스트가 아니라 자동 완성 목록에서 선택된 실제 디스코드 언급이어야 합니다. 일반 텍스트는 message.mentions에 표시되지 않기 때문입니다. 터미널에는 API 오류가 출력되므로, 잘못된 키일 경우 인증 실패 메시지가 나타납니다.

코드가 이렇게 구성된 이유

기록은 의도적으로 작게 유지됩니다

컨텍스트 창은 100,000 토큰이므로 많은 양을 보낼 수 있습니다. 그러나 모든 입력 토큰은 모든 호출에 대해 청구되며, 디스코드 채팅은 주로 짧은 줄로 구성됩니다. 12회 턴은 각 메시지를 큰 청구로 만들지 않고도 응답의 일관성을 유지합니다. 연속성이 중요한 스토리 채널의 경우 maxlen을 높이세요.

세마포어가 키를 보호합니다

일반 키는 동시 요청 8개와 분당 300개의 요청을 허용합니다. 체험 키는 각각 2개와 60개만 허용합니다. 10명이 동시에 봇을 언급하고 10개의 요청을 보내면 추가 요청은 concurrency 오류 코드와 함께 HTTP 429를 받습니다. 세마포어는 이를 자체 프로세스 내에서 대기열에 넣습니다. 체험 키를 사용하는 동안 이를 2로 설정하세요. 스트리밍을 활성화하면 스트리밍 요청이 스트림이 완료될 때까지 슬롯을 유지한다는 점을 기억하세요.

재시도는 SDK에서 제공됩니다

OpenAI Python SDK는 429 오류 시 재시도하며, 서비스에서 일시적 과부하 시 Retry-After: 5로 보내는 Retry-After 헤더를 존중합니다. max_retries을 4로 설정하면 짧은 트래픽 급증을 처리할 수 있습니다. 실패하거나 거부된 요청은 요금이 청구되지 않으므로, 재시도가 실패하더라도 토큰 비용이 들지 않습니다.

공유된 페르소나 하나

시스템 프롬프트는 모든 호출의 첫 번째에 위치합니다. 채널별 페르소나는 작은 확장입니다: 채널 ID에서 프롬프트로 가는 딕셔너리를 유지하고 ask에서 이를 조회하세요.

좋은 오픈 소스 프로젝트로 만들기

코드는 작동하지만, 공개 저장소는 타인이 사용할 수 있도록 몇 가지 추가 사항이 필요합니다.

  • 라이선스. 작은 봇의 경우 MIT 또는 Apache 2.0이 일반적인 선택입니다. 저장소 루트에 파일을 추가하세요.
  • .env.example 파일. DISCORD_TOKEN과 API_KEY에 실제가 아닌 예시 값을 넣어, 어떤 값을 설정해야 하는지 알 수 있도록 합니다.
  • 구성 가능한 Base URL. 환경에서 BASE_URL과 MODEL을 읽되, 위의 값으로 기본값을 설정하세요. 포크한 사람은 누구나 호환되는 OpenAI 서버를 사용할 수 있습니다.
  • Dockerfile. bot.py을 복사하고 세 가지 패키지를 설치한 후 스크립트를 실행하는 파이썬 슬림 이미지를 기반으로 한 짧은 파일로, 어디서든 호스팅할 수 있습니다.
  • 인텐트 경고가 포함된 README입니다. 메시지 콘텐츠 인텐트 누락은 모든 디스코드 봇에서 가장 많이 받는 지원 문의입니다.

자신의 토큰과 키를 Git 이력에서 제외하세요. 하나라도 유출되면 디스코드 포털이나 API 키 페이지에서 회수하고 새 키를 발급하세요.

호스팅 및 비용

봇은 CPU 사용량이 적은 단일 장기 실행 프로세스입니다. 작은 VPS, 여분의 컴퓨터 또는 컨테이너 플랫폼이면 충분합니다. 봇이 디스코드로 연결하므로 외부로 노출할 웹 서버는 없습니다.

API 비용은 계산하기 쉽습니다. 일반적인 응답은 시스템 프롬프트와 12회 짧은 턴을 합한 1,500개의 입력 토큰과 300개의 출력 토큰을 사용합니다.

  • 입력: 1,500 x $0.15 / 1M = $0.000225
  • 출력: 300 x $0.50 / 1M = $0.00015
  • 응답당: $0.000375

따라서 1,000회 응답에는 $0.375, 10,000회 응답에는 $3.75가 듭니다. $0.50 체험 크레딧은 약 1,333회 응답을 커버합니다. $20 충전은 53,000회 이상을 커버합니다. 충전은 $20부터 $500까지 가능하며, $50부터 +5%, $100부터 +10%, $200부터 +15%의 보너스가 제공됩니다. 크레딧은 만료되지 않으며 구독이 없으므로 조용한 서버는 거의 비용이 들지 않습니다. 자세한 내용은 가격 책정 페이지를 참조하세요. 결제는 TRC20의 USDT 또는 Base의 USDC를 사용한 암호화폐 전용입니다.

다음 단계

노력할 가치가 있는 세 가지 업그레이드가 있습니다. 청크가 도착할 때 단일 메시지를 편집하여 스트리밍을 추가하되, 디스코드의 편집 속도 제한에 유의하세요. 채널 기록을 초기화하는 슬래시 명령어를 추가하세요. 봇이 주사위를 굴리거나 캐릭터 시트를 조회할 수 있도록 도구 호출을 추가하세요. API는 OpenAI 형식의 tools, tool_choice 및 role: "tool" 결과를 지원합니다.

API 문서에는 지원되는 모든 파라미터가 나열되어 있으며, Hermes API 문서에서는 프로젝트 내에서 무검열 모델의 동작 방식을 설명합니다. API로 전송된 프롬프트는 학습에 사용되지 않으므로, 서버 구성원들이 질문할 경우 서버 규칙에 명시하는 것이 좋습니다.

질문과 답변

봇에 메시지 콘텐츠 권한이 필요한가요?

네. 디스코드 개발자 포털과 코드에서 intents.message_content를 true로 설정하여 활성화하세요. 그렇지 않으면 봇이 빈 메시지만 확인합니다.

봇이 동시에 처리할 수 있는 응답 수는 얼마인가요?

전체 키는 동시 요청 8개와 분당 300개를 허용하며, 체험 키는 각각 2개와 60개를 허용합니다. 봇의 세마포어가 한도 아래로 유지되도록 합니다.

봇의 코드를 공개할 수 있나요?

네, Discord 토큰과 API 키가 저장소에 포함되지 않는 한 가능합니다. 환경 변수에서 읽어오고 .env.example 파일을 제공하세요.

성인 테마를 사용해도 되나요?

디스코드의 규칙 및 연령 제한 채널 설정에 따라 합법적인 성인 용도로만 사용해야 합니다. 미성년자가 포함된 성적 콘텐츠는 절대 허용되지 않습니다.

실행 비용은 얼마인가요?

입력 토큰 1,500개와 출력 토큰 300개로 구성된 응답에는 $0.000375가 들며, 이는 10,000회 응답당 약 $3.75입니다. 여기에 프로세스 호스팅 비용이 추가됩니다.

키는 양식 하나만 채우면 받을 수 있습니다

계정을 생성하고 키를 복사한 후 기본 URL을 변경하세요. 설정은 이것으로 끝입니다.

API 키 받기