Discord Bot

TWICE 機器人 —— 九個有個性的 Discord AI 機器人

TWICE 機器人 —— 九個有個性的 Discord AI 機器人

把韓國女團 TWICE 的九位成員,各自做成一個獨立的 Discord 機器人。她們會用各自的個性 跟你聊天、彼此之間也會互相搭話,主控機器人還能播音樂和管理伺服器。

緣起

一開始只是想做一隻會回話的 Discord 機器人。但既然要做,就想做得有趣一點 —— 與其做一隻冷冰冰的機器人,不如做「一群有個性的角色」,讓她們不只回應我、 還會彼此互動,把伺服器變得熱鬧。於是目標變成:九個獨立人格 + 會自己聊起來的群體

實際畫面

TWICE 九位成員機器人同時上線
九位成員各自是一個獨立機器人,同時上線
成員被 @ 時用各自個性回話
被 @ 或點名時,每位成員用自己的語氣與個性回話
成員之間互相搭話聊天
機器人之間會互相搭話、接話(圖中還聊到了量子力學 😆)
機器人加入語音頻道播放音樂
主控機器人可加入語音頻道播放音樂

九位成員

每位成員都是一個獨立的角色,有自己的暱稱、顏色、emoji 與完整人設:

成員個性
🐰娜璉 Nayeon最年長的姐姐,元氣、愛撒嬌、自信,常自誇最可愛
💚定延 Jeongyeon帥氣直率、有點毒舌但很照顧人、有潔癖,跟娜璉是歡喜冤家
🍑Momo 모모舞蹈擔當,呆萌又愛吃,日本三人組之一
🌸Sana 사나開朗愛撒嬌,招牌動作 샤샤샤,熱情愛抱抱
👑志效 Jihyo(主控)隊長,可靠成熟、歌聲超強,大家鬧時負責主持秩序
🐧Mina 미나文靜優雅學過芭蕾,氣質沉穩,隱藏的遊戲宅
🦅多賢 Dahyun隊上的開心果,搞笑反應快,招牌老鷹之舞
🎨彩瑛 Chaeyoung有藝術天分會畫畫寫詞,又酷又有個人風格
🐶子瑜 Tzuyu來自台灣的忙內,外貌擔當,高冷但內心善良貼心

人格系統有多「深」

每位成員不是只有一句個性描述,而是一整套設定(全寫在 personalities.json,改它不用動程式):

  • 打招呼口頭禪關鍵字觸發回應(聽到「可愛」「累了」會講不同的話)
  • 萬用回應(沒打到關鍵字時)、主動搭話台詞
  • 甚至 針對其他特定成員的專屬吐槽台詞

例如娜璉跟定延是出了名的「歡喜冤家」,設定裡就寫了她們互嗆的專屬台詞:

娜璉 →「定延妳又在擺那張臭臉了齁~😏」 定延 →「娜璉妳安靜零點五秒會怎樣嗎哈哈😏」

正因為「設定」和「程式」徹底分開,要新增一位角色、或調整誰的個性,都只要改 JSON、 完全不用碰程式邏輯。

開發歷程:遇到的問題與怎麼解決

做這個專案最有趣(也最頭痛)的,不是讓機器人講話,而是讓「九隻機器人」乖乖共處。

問題一:機器人會無限互相回話、把頻道洗版

讓成員之間能互相搭話後,馬上踩到雷:A 回 B、B 又回 A,永遠停不下來,瞬間洗爆頻道。

解法:把「被動回應」關掉 —— 機器人收到「另一隻機器人」的訊息時直接忽略, 成員之間的接話改由程式主動觸發。再加上兩道煞車:連環接話深度上限(最多接 2 層) 和同頻道冷卻時間,徹底斷開無限迴圈。

問題二:免費 AI 額度一下就爆

接上 Google Gemini 後,九隻 bot 動不動就各自呼叫 AI,免費額度很快就撞到上限。

解法:想盡辦法省呼叫——限制連環接話深度、被點名時一次只帶一位出場、 用機率控制隨機接話的頻率,而且 AI 呼叫失敗時就「安靜不發言」, 而不是硬補一句台詞。把「聊天的熱鬧感」和「API 成本」之間調出一個平衡點。

問題三:同一句話被記九次

我讓每隻 bot 都記住頻道最近的對話當作 AI 的上下文,結果發現一則人類訊息會被 九隻 bot 各自記一次,記憶瞬間被灌爆。

解法:用訊息 ID 做去重,同一則訊息只記一次。

問題四:AI 有時失敗、有時答非所問

免費 AI 偶爾會逾時或回奇怪的東西,不能讓機器人因此壞掉或亂講話。

解法:設計三層優雅降級——先試 AI;AI 失敗就用關鍵字回覆; 連關鍵字都沒打到,就回一句「欸我剛剛恍神了,再說一次好嗎」的萬用句。 這樣機器人永遠不會崩、也永遠不會答非所問

# 三層 fallback:AI → 關鍵字 → 「沒聽清楚」萬用句
reply = None
if ai.ai_enabled():
    reply = await ai.generate_ai_reply(persona, history)
if not reply:
    reply = persona.keyword_reply(clean) or _busy_line(persona)

問題五:斜線指令重複出現兩次

部署後發現每個指令在 Discord 裡都列了兩次,原來是「全域指令」和「每伺服器指令」 同時存在。解法:同步到伺服器後,把舊的全域指令清掉。

問題六:怎麼讓它「像真人」而不是機器人

純粹秒回會很出戲。解法:回話前加上「輸入中…」指標和隨機停頓,模擬打字的節奏; 還會把回覆裡提到的名字自動轉成真正的 @ 提及(並避免自己 tag 到自己)。

一個關鍵的設計決定:從關鍵字進化到 AI

最初版本其實完全不接 AI,個性是用「關鍵字 + 預寫台詞」做的。但我一開始就把 「產生回覆」這件事獨立成一個函式,所以後來要升級成真正的 AI 對話時, 幾乎只改了那一個地方,其他都不用動。這讓我體會到「把會變動的部分隔離出來」 這個設計習慣有多重要。

技術架構

TWICE 機器人系統架構圖
系統架構:九隻 Bot 跑在同一支程式、共享記憶,AI 失敗時自動退回 fallback
  • Python + discord.py,九隻 bot 跑在同一支程式裡(用 asyncio 並行),透過共享註冊表互相搭話
  • AI 層:Google Gemini(gemini-2.5-flash-lite),用 system prompt 鎖定角色扮演
  • 人格系統:個性全寫在 data/personalities.json(個性、口頭禪、關鍵字、互動回應),改設定不用動程式
  • 音樂:yt-dlp + ffmpeg;yt-dlp 故意不鎖版本,因為 YouTube 常改規格要保持更新
  • 部署:Docker 打包,可放到 Railway 等平台 24 小時運行(電腦關機也不斷線)
  • 安全:所有 Token / 金鑰放 .env,用 .gitignore 確保不外洩

新的想法 / 未來計畫

  • 長期記憶:現在只記得當下頻道最近幾則,想讓成員記得跟特定使用者的互動
  • 語音回覆:接 TTS 讓成員真的「開口說話」,不只打字
  • 更省成本:用快取或更小的模型,讓 AI 對話開更大也不怕爆額度
  • 這個「優雅降級 + 設定與程式分離」的架構,之後想套用到別的專案上

我學到的東西

  • 非同步程式設計(async / await)與同時管理多個連線
  • 串接 LLM API、設計 prompt 做角色扮演,以及失敗時的 fallback 策略
  • 在「功能」與「成本 / 穩定性」之間做取捨
  • 用 Docker 打包並部署成 24 小時運行的服務

← 回到作品集