开源 Discord 机器人搭配无审查 LLM
一个通过 LLM 进行对话的开源 Discord 机器人大约需要八十行 Python 代码。本指南提供代码、你必须遵守的限制以及每次回复的成本,使用 OpenAI 兼容 API 和一个不拒绝合法成人请求的模型。

要点
- discord.py 加上 OpenAI SDK 即可;将 SDK 指向 https://api.openrouternsfw.com/v1 并使用模型 uncensored。
- 在 Discord 开发者门户中开启消息内容意图,否则机器人将收到空消息。
- 使用低于 8 的信号量以保持在并发限制内,并将成人内容放在标记为年龄限制的频道中。
- 包含 1,500 个输入 token 和 300 个输出 token 的回复成本为 $0.000375,即每 10,000 次回复约 $3.75。
无需绑卡。注册后,一键领取 $0.50 免费试用额度(每人限领一次)。
获取 API 密钥你正在构建的内容
下面的机器人会在有人提及它时回复。它按频道保留简短历史记录,将其发送到聊天补全接口,并发布回复。它是纯 Python 代码,符合 MIT 许可,且没有数据库。你可以一次性阅读所有代码,这正是开源项目的意义所在:其他人可以分叉它并理解它。
背后的模型是一个单一的开放权重文本模型,由独立提供商运行,经过调整以在回答时不拒绝内容,适用于合法的成人用途。这非常适合围绕小说、角色扮演或成人对话建立的 Discord 社区。从一开始就有两条规则。首先,API 不允许涉及未成年人的性内容,且不得包含在你的机器人设计中。其次,Discord 有自己的规则和年龄限制频道设置,你有责任遵守这些规则。将成人内容限制在标记为成人的频道中,以及所有成员均为成人的服务器中。
设置 Discord 和你的密钥
- 打开 Discord 开发者门户并创建一个应用,然后为其添加一个机器人。
- 在机器人设置下,启用消息内容意图。没有它,机器人将收到空文本的消息。
- 复制机器人令牌。将其视为密码。
- 使用 OAuth2 URL 生成器,邀请机器人以在你选择的频道中读取和发送消息的权限。
- 从密钥页面获取 API 密钥。新用户只需点击一下即可领取 $0.50 的试用额度,无需支付信息,有效期为 7 天。
将这两个密钥存储为环境变量,不要放在仓库中。对于开源项目来说,这一点尤为重要,因为代码是公开的。
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 提及,从自动完成列表中选择,因为带有机器人名称的纯文本不会出现在message.mentions中。终端会打印 API 错误,所以错误的密钥会在那里显示为身份验证失败。
代码为何这样设计
历史记录故意很小
上下文窗口为 100,000 个 token,所以你可以发送很多。但每个输入 token 都会在每次调用时计费,而 Discord 聊天主要是短行。十二轮对话保持回复连贯,而不会使每条消息变成大额账单。对于连续性重要的故事频道,可以提高maxlen。
信号量保护你的密钥
完整密钥允许 8 个并发请求和每分钟 300 个请求。试用密钥仅允许 2 个和 60 个。如果十个人同时提及机器人,你发送十个请求,额外的请求将收到带有concurrency错误代码的 HTTP 429。信号量将它们排队在你的进程中。在使用试用密钥时,将其设置为 2。如果你开启流式输出,请记住流式请求会占用其槽位,直到流结束。
重试来自 SDK
OpenAI Python SDK 在遇到 429 错误时会重试,并尊重 Retry-After 头,服务在临时过载时会发送 Retry-After: 5。将 max_retries 设置为 4 可以覆盖短期峰值。失败或被拒绝的请求不会收费,因此当重试失败时,它们不会消耗你的 token。
共享一个角色
系统提示词在每个调用中首先出现。按频道的角色是一个小扩展:保持一个从频道 ID 到提示词的字典,并在ask中查找它。
使其成为一个好的开源项目
代码可以工作,但公共仓库在陌生人可以使用之前需要一些额外的内容。
- 许可证。MIT 或 Apache 2.0 是小规模机器人的常用选择。将文件添加到仓库根目录。
- .env.example 文件。列出
DISCORD_TOKEN和API_KEY并填入占位值,以便他人知道需要设置哪些内容。 - 可配置的 Base URL。从环境变量中读取
BASE_URL和MODEL,默认使用上述值。任何分叉该项目的用户都可以使用任何兼容 OpenAI 的服务器。 - Dockerfile。基于 Python slim 镜像的简短文件,复制
bot.py、安装三个包并运行脚本,让用户可以在任何地方托管它。 - 包含意图警告的 README。缺少 Message Content 意图是每个 Discord 机器人最常见的支持问题。
将你自己的令牌和密钥保留在 Git 历史之外。如果其中一个泄露,请在 Discord 门户或 API 密钥页面撤销它并发行一个新的。
托管和成本
机器人是一个长期运行的进程,CPU 使用量轻。小型 VPS、备用机器或容器平台就足够了。没有要暴露的 Web 服务器,因为机器人连接到 Discord。
API 成本很容易计算。典型的回复使用 1,500 个输入 token(系统提示词加上十二个短轮)和 300 个输出 token。
- 输入: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。
下一步操作
三项升级值得付出努力。通过编辑单条消息并在块到达时进行流式输出,但请注意 Discord 的编辑速率限制。添加一个斜杠命令以重置频道历史。添加工具调用功能,使机器人能够掷骰子或查询角色卡;API 支持 tools、tool_choice 以及 OpenAI 格式中的 role: "tool" 结果。
API 文档列出了所有支持的参数,Hermes API 文章介绍了无审查模型在项目中的行为方式。发送给 API 的提示词不用于训练,如果成员询问,建议在服务器规则中说明这一点。
更多指南
问答
机器人需要消息内容意图吗?
是的。在 Discord 开发者门户中启用它,并在代码中将 intents.message_content 设置为 true。否则机器人看到的消息为空。
机器人能同时处理多少条回复?
完整密钥允许 8 个并发请求和每分钟 300 个;试用密钥允许 2 个和 60 个。机器人中的信号量可确保请求量保持在限制之下。
我可以发布机器人的代码吗?
是的,只要 Discord token 和 API 密钥不包含在仓库中即可。从环境变量中读取它们,并附带一个 .env.example 文件。
是否允许使用成人主题?
仅适用于符合 Discord 规则及其年龄限制频道设置的合法成人用途。涉及未成年人的性内容始终禁止。
运行成本是多少?
1,500 个输入 token 和 300 个输出 token 的回复成本为 $0.000375,即每 10,000 次回复约 $3.75,加上托管进程的成本。
只需填写一个表单即可获得密钥
创建账户,复制密钥,更改基础 URL。这就是全部设置。
获取 API 密钥