TH ▾
รับคีย์ API

บอท Discord แบบโอเพนซอร์สพร้อม LLM แบบไม่เซ็นเซอร์

บอท Discord แบบโอเพนซอร์สที่ใช้ LLM ในการสนทนาประกอบด้วยโค้ด Python ประมาณแปดสิบบรรทัด คู่มือนี้ให้โค้ด ขีดจำกัดที่คุณต้องปฏิบัติตาม และต้นทุนต่อคำตอบ โดยใช้ API ที่เข้ากันได้กับ OpenAI พร้อมโมเดลที่ไม่ปฏิเสธคำขอจากผู้ใหญ่ที่ถูกต้องตามกฎหมาย

ภาพประกอบไอโซเมตริกของบอทที่ทำจากลูกบาศก์เรืองแสงในหน้าต่างแชทที่เชื่อมต่อกับต้นไม้โค้ดแบบแยกสาขา

อัปเดต

ประเด็นสำคัญ

  • discord.py รวมกับ OpenAI SDK ก็เพียงพอแล้ว; ชี้ SDK ไปที่ https://api.openrouternsfw.com/v1 และใช้โมเดล uncensored
  • เปิดใช้งาน Message Content intent ในพอร์ทัลผู้พัฒนา Discord หรือบอทจะเห็นข้อความว่าง
  • ใช้เซมิโฟร์ที่ต่ำกว่า 8 เพื่อให้อยู่ภายในขีดจำกัดการทำงานพร้อมกัน และเก็บเนื้อหาผู้ใหญ่ไว้ในช่องที่ระบุว่าเป็นช่องจำกัดอายุ
  • การตอบกลับที่มี 1,500 โทเคนอินพุตและ 300 โทเคนเอาต์พุตมีค่าใช้จ่าย $0.000375 ดังนั้นประมาณ $3.75 ต่อการตอบกลับ 10,000 ครั้ง

ไม่ต้องใช้บัตร หลังสมัคร ให้รับเครดิตทดลองใช้ฟรี $0.50 ด้วยคลิกเดียว (หนึ่งครั้งต่อคน)

รับคีย์ API

สิ่งที่คุณกำลังสร้าง

บอทด้านล่างจะตอบเมื่อมีคนกล่าวถึงมัน มันเก็บประวัติสั้นๆ ต่อช่อง ส่งไปยังเอนด์พอยต์ chat completions และโพสต์คำตอบกลับ เป็นโค้ด Python ธรรมดา อนุญาตภายใต้ MIT และไม่มีฐานข้อมูล คุณสามารถอ่านโค้ดทั้งหมดได้ในครั้งเดียว ซึ่งเป็นจุดประสงค์ของโปรเจกต์โอเพนซอร์ส: คนอื่นสามารถ fork โค้ดนี้ไปและเข้าใจมันได้

โมเดลเบื้องหลังคือโมเดลข้อความแบบเปิดน้ำหนักเดียวที่ให้บริการโดยผู้ให้บริการอิสระและปรับแต่งมาให้ตอบโดยไม่มีการปฏิเสธเนื้อหาสำหรับการใช้งานผู้ใหญ่ที่ถูกต้องตามกฎหมาย สิ่งนี้เหมาะกับชุมชน Discord ที่สร้างขึ้นรอบนิยาย การสวมบทบาท หรือการสนทนาสำหรับผู้ใหญ่ มีกฎสองข้อที่ใช้ได้ทันที ประการแรก เนื้อหาทางเพศที่เกี่ยวข้องกับผู้เยาว์ไม่อนุญาตผ่าน API และไม่ควรเป็นส่วนหนึ่งของการออกแบบบอทของคุณ ประการที่สอง Discord มีกฎเกณฑ์และการตั้งค่าช่องที่จำกัดอายุเป็นของตัวเอง และคุณมีหน้าที่ต้องปฏิบัติตาม เก็บเนื้อหาสำหรับผู้ใหญ่ไว้ในช่องที่ระบุไว้เท่านั้น และในเซิร์ฟเวอร์ที่สมาชิกเป็นผู้ใหญ่

ตั้งค่า Discord และคีย์ของคุณ

  1. เปิดหน้าเว็บผู้พัฒนา Discord และสร้างแอปพลิเคชัน จากนั้นเพิ่มบอตเข้าไป
  2. ภายใต้การตั้งค่าบอต ให้เปิดใช้งาน Message Content Intent หากไม่มีสิ่งนี้ บอตจะรับข้อความที่มีข้อความว่างเปล่า
  3. คัดลอกโทเคนของบอท ถือว่าเป็นรหัสผ่าน
  4. ใช้ตัวสร้าง URL ของ OAuth2 เพื่อเชิญบอทพร้อมสิทธิ์ในการอ่านและส่งข้อความในช่องที่คุณเลือก
  5. รับคีย์ API จาก หน้าคีย์ ผู้ใช้ใหม่สามารถรับเครดิตทดลองใช้มูลค่า $0.50 ได้ด้วยการคลิกหนึ่งครั้ง ไม่ต้องใส่รายละเอียดการชำระเงิน ใช้ได้เป็นเวลา 7 วัน

เก็บค่าลับทั้งสองนี้เป็นตัวแปรสภาพแวดล้อม (environment variables) อย่าเก็บไว้ใน repository สำหรับโปรเจกต์โอเพนซอร์ส สิ่งนี้สำคัญกว่าปกติ เพราะโค้ดเป็นสาธารณะ

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 แล้วกล่าวถึงบอทในช่องที่บอทสามารถอ่านได้ คำตอบแรกควรปรากฏภายในไม่กี่วินาที

หากไม่มีอะไรเกิดขึ้น ให้ตรวจสอบสามสิ่งตามลำดับ บอทต้องออนไลน์ในรายการสมาชิก ซึ่งหมายความว่าโทเคนนั้นถูกต้อง บอทต้องมีสิทธิ์ในการอ่านและส่งข้อความในช่องนั้น และการกล่าวถึงต้องเป็นการกล่าวถึง Discord จริงๆ ซึ่งเลือกจากรายการ autocomplete เพราะข้อความธรรมดาที่มีชื่อบอทจะไม่ปรากฏใน message.mentions เทอร์มินัลจะแสดงข้อผิดพลาด API ดังนั้นคีย์ที่ผิดจะแสดงเป็นข้อผิดพลาดการตรวจสอบสิทธิ์

เหตุผลที่โค้ดถูกออกแบบมาแบบนี้

ประวัติมีขนาดเล็กโดยเจตนา

หน้าต่างบริบทมีขนาด 100,000 โทเคน ดังนั้นคุณจึงสามารถส่งข้อมูลได้จำนวนมาก แต่โทเคนอินพุตทุกตัวจะถูกเรียกเก็บเงินในทุกการเรียกใช้ และแชท Discord ส่วนใหญ่เป็นข้อความสั้นๆ การสนทนา 12 รอบช่วยให้คำตอบมีความสอดคล้องกันโดยไม่ทำให้แต่ละข้อความกลายเป็นค่าใช้จ่ายที่สูง เพิ่ม maxlen สำหรับช่องเรื่องเล่าที่ความต่อเนื่องมีความสำคัญ

เซมาโฟร์ป้องกันคีย์ของคุณ

คีย์แบบเต็มอนุญาตให้ทำคำขอพร้อมกัน (parallel requests) ได้ 8 คำขอและ 300 คำขอต่อนาที คีย์ทดลองอนุญาตให้ทำคำขอพร้อมกันได้เพียง 2 คำขอและ 60 คำขอต่อนาที หากมีคนสิบคนกล่าวถึงบอทพร้อมกันและคุณส่งคำขอสิบครั้ง คำขอที่เหลือจะได้รับ HTTP 429 พร้อมรหัสข้อผิดพลาด concurrency เซมาโฟร์จะจัดคิวคำขอเหล่านี้ในกระบวนการของคุณเอง กำหนดค่าเป็น 2 ขณะที่คุณใช้คีย์ทดลอง หากคุณเปิดใช้งานสตรีมมิง จำไว้ว่าคำขอที่สตรีมจะครอบครองช่องของมันจนกว่าการสตรีมจะเสร็จสิ้น

การลองซ้ำมาจาก SDK

OpenAI Python SDK จะลองซ้ำเมื่อได้รับ 429 และปฏิบัติตามส่วนหัว Retry-After ซึ่งบริการส่งเป็น Retry-After: 5 เมื่อโหลดเกินชั่วคราว การตั้งค่า max_retries เป็น 4 ครอบคลุมการเพิ่มขึ้นของโหลดแบบสั้นๆ คำขอที่ล้มเหลวหรือถูกปฏิเสธจะไม่ถูกเรียกเก็บเงิน ดังนั้นการลองซ้ำจึงไม่เสียโทเคนเมื่อล้มเหลว

บุคลิกภาพร่วมกันหนึ่งเดียว

คำสั่งระบบจะอยู่แรกสุดในทุกการเรียกใช้ บุคลิกภาพต่อช่องเป็นการขยายเพิ่มเติมเล็กน้อย: เก็บแมปจาก ID ช่องไปยังคำสั่งและเรียกดูใน ask

ทำให้มันเป็นโปรเจกต์โอเพนซอร์สที่ดี

โค้ดทำงานได้ แต่ repository สาธารณะต้องการส่วนเสริมเล็กน้อยก่อนที่คนแปลกหน้าจะสามารถใช้งานได้

  • ใบอนุญาต MIT หรือ Apache 2.0 เป็นตัวเลือกทั่วไปสำหรับบอทขนาดเล็ก เพิ่มไฟล์ที่ไดเรกทอรีรากของที่เก็บ
  • ไฟล์ .env.example ระบุ DISCORD_TOKEN และ API_KEY ด้วยค่าปลอมเพื่อให้ผู้คนรู้ว่าจะตั้งค่าอะไร
  • URL ฐานที่ปรับค่าได้ อ่านค่า BASE_URL และ MODEL จากตัวแปรสภาพแวดล้อม โดยกำหนดค่าเริ่มต้นตามค่าข้างต้น จากนั้นผู้ใช้ที่ fork โค้ดไปสามารถใช้งานเซิร์ฟเวอร์ที่เข้ากันได้กับ OpenAI ได้
  • ไฟล์ Dockerfile ไฟล์ขนาดสั้นที่ใช้ภาพพื้นฐานแบบ slim ของ Python โดยคัดลอก bot.py ติดตั้งแพ็กเกจทั้งสาม และรันสคริปต์ ช่วยให้ผู้คนสามารถโฮสต์ได้ทุกที่
  • ไฟล์ README พร้อมคำเตือนเรื่อง Intents การขาด Message Content intent เป็นคำถามด้านการสนับสนุนที่พบบ่อยที่สุดสำหรับบอต Discord ทุกตัว

เก็บโทเคนและคีย์ของคุณออกจากประวัติ Git หากมีการรั่วไหล ให้เพิกถอนคีย์นั้นในพอร์ทัล Discord หรือหน้าคีย์ API แล้วสร้างคีย์ใหม่

การโฮสต์และค่าใช้จ่าย

บอตเป็นกระบวนการที่ทำงานต่อเนื่องยาวนานและใช้ซีพียูเพียงเล็กน้อย เซิร์ฟเวอร์เสมือนขนาดเล็ก (VPS) เครื่องสำรอง หรือแพลตฟอร์มคอนเทนเนอร์ก็เพียงพอแล้ว ไม่ต้องมีเว็บเซิร์ฟเวอร์ที่ต้องเปิดเผย เพราะบอตจะเชื่อมต่อออกยัง Discord

ต้นทุน API คำนวณได้ง่าย คำตอบทั่วไปที่นี่ใช้โทเคนอินพุต 1,500 ตัว (พรอมต์ระบบรวมกับการสนทนาสั้นๆ 12 รอบ) และโทเคนเอาต์พุต 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 พร้อมโบนัส +5% เมื่อเติม $50, +10% เมื่อเติม $100 และ +15% เมื่อเติม $200 เครดิตไม่หมดอายุและไม่มีบริการแบบสมัครสมาชิก ทำให้เซิร์ฟเวอร์ที่ใช้งานน้อยมีค่าใช้จ่ายเกือบเป็นศูนย์ ดูรายละเอียดได้ที่ หน้าราคา การชำระเงินใช้คริปโตเท่านั้น โดยใช้ USDT บน TRC20 หรือ USDC บน Base

ขั้นตอนถัดไป

การอัปเกรดสามรายการคุ้มค่ากับความพยายาม เพิ่มสตรีมมิงโดยการแก้ไขข้อความเดียวเมื่อได้รับข้อมูลเป็นชิ้นส่วน แต่ให้ระวังขีดจำกัดอัตราในการแก้ไขของ Discord เพิ่มคำสั่งสแลชเพื่อล้างประวัติช่อง เพิ่มการเรียกใช้ฟังก์ชันเพื่อให้บอตสามารถทอยลูกเต๋าหรือค้นหาข้อมูลตัวละครได้ API รองรับ tools, tool_choice และผลลัพธ์ role: "tool" ในรูปแบบของ OpenAI

เอกสาร API ระบุพารามิเตอร์ที่รองรับทั้งหมด และบทความ Hermes API ครอบคลุมพฤติกรรมของโมเดลที่ไม่เซ็นเซอร์ภายในโปรเจกต์ พรอมต์ที่ส่งไปยัง API ไม่ถูกนำไปใช้ในการฝึกฝน ซึ่งเป็นเรื่องที่ควรระบุไว้ในกฎของเซิร์ฟเวอร์หากสมาชิกของคุณถามถึง

ถาม-ตอบ

บอตจำเป็นต้องใช้ Message Content intent หรือไม่?

จำเป็น เปิดใช้งานในพอร์ทัลนักพัฒนา Discord และในโค้ดโดยตั้งค่า intents.message_content เป็น true มิฉะนั้นบอตจะเห็นข้อความว่างเปล่า

บอตสามารถจัดการการตอบกลับได้พร้อมกันกี่ครั้ง?

คีย์แบบเต็มอนุญาตให้ทำคำขอพร้อมกัน 8 คำขอและ 300 คำขอต่อนาที; คีย์ทดลองอนุญาตให้ทำ 2 และ 60 ตามลำดับ เซมิโฟร์ในบอตจะช่วยให้คุณอยู่ภายใต้ขีดจำกัด

ฉันสามารถเผยแพร่โค้ดของบอตได้หรือไม่?

ได้ ตราบใดที่โทเคน Discord และคีย์ API ยังคงไม่อยู่ในที่เก็บข้อมูล อ่านค่าจากตัวแปรสภาพแวดล้อมและจัดส่งไฟล์ .env.example

อนุญาตให้ใช้ธีมสำหรับผู้ใหญ่หรือไม่?

อนุญาตเฉพาะสำหรับการใช้งานผู้ใหญ่ที่ถูกต้องตามกฎหมาย สอดคล้องกับกฎของ Discord และการตั้งค่าช่องที่จำกัดอายุ เนื้อหาทางเพศที่เกี่ยวข้องกับผู้เยาว์ไม่อนุญาตเด็ดขาด

ต้นทุนการใช้งานเป็นอย่างไร

การตอบกลับที่มี 1,500 input token และ 300 output token มีค่าใช้จ่าย $0.000375 ดังนั้นประมาณ $3.75 ต่อการตอบกลับ 10,000 ครั้ง บวกกับต้นทุนในการโฮสต์กระบวนการ

คีย์ของคุณอยู่ห่างแค่แบบฟอร์มเดียว

สร้างบัญชี คัดลอกคีย์ และเปลี่ยน base URL นั่นคือการตั้งค่าทั้งหมด

รับคีย์ API