Discord 機器人程式設計 AI:使用 LLM API 建立
Discord 機器人編碼 AI 會透過 API 後端的語言模型,在你的伺服器內回答程式設計問題。本教學將教你如何用約 70 行 Python 程式碼建立一個機器人,並涵蓋通常會出錯的部分。
更新於

重點摘要
- 機器人需要 discord.py、openai 套件、機器人權杖和 LLM API 金鑰。
- 在 Discord 開發者入口網站啟用訊息內容意圖,否則機器人將看到空白的訊息。
- 保留每個頻道的簡短歷史並進行修剪,因為模型在每次呼叫之間不會記住任何內容。
- 在 2,000 個字元處拆分回覆,並限制並行呼叫,以保持在 8 個請求的並行上限之下。
機器人的功能
目標是建立一個 Discord 機器人程式設計 AI,當有人提及它時會做出反應。使用者輸入「@helper 為什麼我的列表推導式回傳 None?」,機器人將訊息傳送至模型,模型的回應則以回覆形式出現在同一頻道。機器人也會記住每個頻道最近的幾輪對話,以便進行後續提問。
設計包含三個部分。discord.py 處理與 Discord 的連線。OpenAI Python SDK 與 LLM API 通訊,由於 API 與 OpenAI 相容,因此可以在此運作。小型字典用於儲存對話歷史。你不需要資料庫即可開始。
你需要 Python 3.9 或更新版本、可建立應用程式的 Discord 帳戶,以及來自 API 金鑰頁面的 API 金鑰。新帳戶可以一鍵領取 $0.50 的免費試用額度,足以建立並測試此機器人。
步驟 1:建立 Discord 應用程式
- 開啟 Discord 開發者入口網站並建立新應用程式。
- 在機器人區塊中,建立機器人使用者並複製其權杖。將其視為密碼處理。
- 在同一頁面上,於「特權閘道意圖」下開啟 訊息內容意圖。若未開啟,機器人接收到的訊息文字為空,你會花一個小時困惑為何它從未回覆。
- 在 OAuth2 中,使用
bot範圍產生邀請連結,並賦予讀取訊息和傳送訊息的權限。開啟連結並將機器人新增至測試伺服器。
安裝函式庫並設定兩個環境變數。
pip install discord.py openai
export DISCORD_TOKEN="your-discord-bot-token"
export LLM_API_KEY="your-llm-api-key"
# quick check that the LLM key works, using model uncensored
curl -s https://api.codingllmapi.com/v1/chat/completions \
-H "Authorization: Bearer $LLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"uncensored","messages":[{"role":"user","content":"ping"}],"max_tokens":5}'步驟 2:機器人程式碼
將其儲存為 bot.py。它會在被提及時回覆,保留每個頻道十二則訊息的歷史,在等待時顯示輸入中指示器,並拆分長回覆。
import asyncio
import os
import discord
from openai import AsyncOpenAI, RateLimitError, APIError
llm = AsyncOpenAI(
base_url="https://api.codingllmapi.com/v1",
api_key=os.environ["LLM_API_KEY"],
)
SYSTEM = (
"You are a helpful programming assistant in a Discord server. "
"Answer briefly. Put code in fenced blocks. Say so when you are unsure."
)
MAX_TURNS = 12
history = {} # channel id -> list of messages
slots = asyncio.Semaphore(6) # stay under the 8 concurrent request cap
intents = discord.Intents.default()
intents.message_content = True
bot = discord.Client(intents=intents)
def split_reply(text, limit=1900):
parts = []
while len(text) > limit:
cut = text.rfind("\n", 0, limit)
if cut < limit // 2:
cut = limit
parts.append(text[:cut])
text = text[cut:].lstrip("\n")
parts.append(text)
return parts
@bot.event
async def on_message(message):
if message.author.bot or bot.user not in message.mentions:
return
question = message.clean_content.replace(f"@{bot.user.display_name}", "").strip()
if not question:
await message.reply("Ask me a coding question after the mention.")
return
log = history.setdefault(message.channel.id, [])
log.append({"role": "user", "content": question})
del log[:-MAX_TURNS]
async with message.channel.typing():
try:
async with slots:
resp = await llm.chat.completions.create(
model="uncensored",
messages=[{"role": "system", "content": SYSTEM}] + log,
temperature=0.4,
max_tokens=900,
)
except RateLimitError:
await message.reply("The model is busy. Try again in a few seconds.")
log.pop()
return
except APIError:
await message.reply("The model call failed. Try again shortly.")
log.pop()
return
answer = resp.choices[0].message.content or "(empty reply)"
log.append({"role": "assistant", "content": answer})
for part in split_reply(answer):
await message.reply(part)
bot.run(os.environ["DISCORD_TOKEN"])
使用 python bot.py 執行它,然後在測試伺服器中提及機器人。第一個回覆應在幾秒內到達。
程式碼撰寫方式的原因
歷史記錄是刻意修剪的
模型沒有記憶,因此每次呼叫都會傳送最近的對話輪次。若沒有 del log[:-MAX_TURNS],列表會無限增長。最終會達到 100,000 token 的上下文視窗,且你的成本會隨著每則訊息增加。十二筆條目足以進行單一錯誤的對話。對於擁有長線程的伺服器,可提高此數值或對較舊的輪次進行摘要。
Discord 的 2,000 個字元限制
Discord 會拒絕超過 2,000 個字元的訊息,而程式碼回覆很容易達到此限制。split_reply 輔助函數會在接近限制的新行處進行切割。它不知道程式碼圍欄,因此區塊可能會被切斷。如果這令你困擾,請新增邏輯,在一個部分的結尾關閉圍欄,並在下一個部分的開頭重新開啟。
並行控制的訊號量
完整金鑰允許 8 個並行請求,試用金鑰允許 2 個。繁忙的伺服器可能同時產生多個提問。訊號量會在你的程式內部將額外的呼叫排隊,而不是發送它們並收到錯誤碼為 concurrency 的 429 錯誤。如果你仍在使用試用金鑰,請將 Semaphore(6) 改為 Semaphore(2)。
錯誤不會計費
失敗或拒絕的請求不會計費,因此錯誤後的重試不會使成本加倍。程式碼會在失敗時從歷史中移除使用者輪次,因此重試不會留下模型已看過兩次的懸空問題。
改善回覆體驗
一旦基本迴圈運作,幾項小改動就能大幅改善體驗。
- 串流輸出答案。 傳遞
stream=True並每秒左右編輯機器人的訊息,顯示目前的文字。不要在每個 token 時編輯,因為 Discord 會對訊息編輯套用其自身的速率限制。串流請求會佔用其並行槽位直到結束,因此請讓訊號量涵蓋整個串流過程。 - 使用斜線指令。 類似
/ask的指令可避免提及解析,且完全不需要訊息內容意圖,這也使其在伺服器數量增加時更容易驗證。 - 按使用者區分的歷史。 若多個人在同一頻道提出不相關的提問,請以頻道和使用者為鍵儲存歷史。
- 調整系統提示詞。 列出社群使用的語言,要求簡短回答,並指示模型在問題模糊時提出澄清問題。提示詞調整是免費的,通常比更換模型更有效。
- 降低溫度。 對於程式碼,0.2 到 0.4 之間的值比預設值提供更穩定的結果。
常見故障排除
當新機器人保持沉默時,原因幾乎總是下列項目之一。請按此順序檢查。
- 機器人在線但從未回覆。 開發者入口網站中的訊息內容意圖已關閉,或程式碼中缺少
intents.message_content = True。兩者都必須設定。 - 僅在某些頻道回覆。 機器人在其他頻道缺乏讀取或傳送訊息的權限。請檢查頻道權限覆蓋,而不僅是伺服器範圍的角色。
- 每個回覆都是「忙碌」訊息。你很可能觸發了 429 錯誤。請列印一次例外狀況的回應主體。如果程式碼顯示
rate_limited,表示你已超過完整金鑰每分鐘 300 次請求或試用金鑰每分鐘 60 次請求的上限。如果顯示concurrency,請降低訊號量大小。 - 第一次呼叫時出現驗證錯誤。 LLM 金鑰缺失於執行機器人的程式環境中。在一個終端機分頁中匯出的金鑰,對在其他地方啟動的服務不可見。
- 答案被截斷。 範例中的
max_tokens=900會截斷長回覆。提高此數值,或將其移除,因為max_tokens是選填的,且補全內容可能會使用剩餘的上下文視窗。 - 機器人回覆自己的訊息。 若省略
message.author.bot檢查,就會發生此迴圈。請保留它。
除錯時,請為每次呼叫記錄 X-Request-Id 值。使用 OpenAI SDK 時,你可以透過呼叫 llm.chat.completions.with_raw_response.create(...) 從原始回應中讀取它,然後讀取 .headers。若就特定故障聯繫支援團隊,該 ID 可讓他們找到確切的請求。
運行成本
定價為每 100 萬個輸入 token $0.15,每 100 萬個輸出 token $0.50,無訂閱費。以典型情境為例:系統提示詞加上十二筆歷史記錄約為 2,500 個輸入 token,而回答約為 400 個 token。
輸入:2,500 x $0.15 / 1,000,000 = $0.000375。輸出:400 x $0.50 / 1,000,000 = $0.0002。一則回覆的成本約為 $0.000575。一個每天提出 500 個問題的社群,將花費 500 x $0.000575 = $0.2875,略低於 30 美分。由於程式碼貼上的長度不同,你的數字會有差異,因此請記錄 resp.usage 一週並讀取實際平均值。定價頁面 顯示儲值選項:$20 至 $500 之間的整數金額,儲值達 $50 時贈送 5%,達 $100 時贈送 10%,達 $200 時贈送 15%,可透過信用卡或加密貨幣付款。
為限制濫用,請加入每位使用者的冷卻時間並限制提問長度。這兩項檢查比你能新增的任何其他措施更能保護你的額度。
託管與安全注意事項
此機器人為長期執行的程序。小型虛擬機器或容器主機即可應付,因為繁重的工作在 API 端完成。請在程序管理器下執行,使其在崩潰後自動重啟,並將兩個權杖保留在環境變數或金鑰儲存庫中,切勿放在程式碼儲存庫內。
思考你的伺服器允許的內容。該模型經過調整,可在合法成人用途下無內容審查地回答問題,因此它會討論安全測試或邊緣小說,而較嚴格的助手可能會拒絕這些內容。如果你的社群包含未成年人,請在系統提示詞中設定規則,將機器人限制在特定頻道,並記住 Discord 自身的條款也適用於你的機器人。此 API 禁止任何涉及未成年人的性內容,無例外。
完整的參數詳細資訊,例如 stop、seed 和函式呼叫,請參閱 API 文件。如果你希望機器人執行程式碼或讀取儲存庫,應使用函式呼叫,並由你決定模型可以請求哪些函式。針對此模型的程式開發用途,請參閱關於 無審查 AI 程式碼模型的頁面。
更多指南
問答
我需要訊息內容意圖嗎?
是的,如果機器人讀取一般訊息和提及。如果你只使用斜線指令,則不需要。
機器人可以串流輸出回覆嗎?
可以。設定 stream=True,並以平穩的間隔(例如每秒一次)編輯 Discord 訊息,以便符合 Discord 自身的限制。
如果太多人同時提問會發生什麼事?
當完整金鑰的並行請求超過 8 個時,API 會回傳 HTTP 429 狀態碼,並附上錯誤碼 concurrency。你的程式碼應使用訊號量(semaphore)將額外的請求排入佇列。
重新啟動後機器人還會記得對話嗎?
使用此處的字典則不會。若需要重新啟動後仍保留歷史記錄,請將歷史記錄儲存至 SQLite 或 Redis。
API 金鑰在 Discord 機器人中安全嗎?
如果它保留在你的伺服器環境變數中,則是安全的。切勿將其發布在頻道中或提交到公開的程式碼儲存庫。
只差一張表單,即可取得金鑰
建立帳號、複製金鑰、更改基礎 URL。這就是整個設定過程。
取得 API 金鑰