Slash 指令可讓使用者透過 Discord 內建的命令介面與機器人互動。你在任何頻道輸入 /,就會看到機器人的指令,並附帶說明、參數提示與自動補完。

運作方式

  1. 你在 JSON 檔案中定義指令
  2. 將檔案傳給 discli serve --slash-commands commands.json
  3. discli 啟動時會向 Discord 註冊這些指令
  4. 當使用者叫用指令時,會收到 slash_command 事件
  5. 你使用 interaction_followup 回應

步驟 1:定義指令

建立一個描述 Slash 指令的 JSON 檔案:

[
{
"name": "ask",
"description": "向機器人提問",
"params": [
{
"name": "question",
"type": "string",
"description": "你的問題",
"required": true
}
]
},
{
"name": "status",
"description": "檢查機器人狀態"
},
{
"name": "search",
"description": "搜尋近期訊息",
"params": [
{
"name": "query",
"type": "string",
"description": "搜尋關鍵字",
"required": true
},
{
"name": "limit",
"type": "integer",
"description": "最大結果數(預設 10)",
"required": false
}
]
}
]

指令結構

每個指令物件支援:

欄位類型是否必填說明
namestring指令名稱(小寫,不能有空格,1–32 字)
descriptionstring指令用途(1–100 字)
paramsarray參數清單

參數結構

每個參數支援:

欄位類型是否必填說明
namestring參數名稱
typestringstringintegernumber、或 boolean
descriptionstring參數用途
requiredboolean預設值:true

步驟 2:以 Slash 指令啟動 serve

Terminal window
discli serve --slash-commands commands.json

啟動後,discli 會:

  1. 連線到 Discord 並送出 ready 事件
  2. 在機器人加入的每個伺服器中註冊 Slash 指令
  3. 註冊完成後送出 slash_commands_synced 事件
{"event": "ready", "bot_id": "123456", "bot_name": "MyBot#1234"}
{"event": "slash_commands_synced", "count": 3, "guilds": 2}
Note

discli 會將指令逐個同步到每個伺服器,達到即時可用。若改用全域註冊(未指定伺服器),Discord 可能要花到 1 小時才能完成傳播。透過直接逐伺服器同步,指令會在 slash_commands_synced 事件之後立即可用。

步驟 3:處理 Slash 指令事件

當使用者叫用 Slash 指令時,你會收到 slash_command 事件:

{
"event": "slash_command",
"command": "ask",
"args": {
"question": "What is discli?"
},
"channel_id": "444555666",
"user": "alice#1234",
"user_id": "777888999",
"guild_id": "111222333",
"interaction_token": "abc-123-def",
"is_admin": false
}

主要欄位:

欄位說明
commandSlash 指令名稱
args參數名稱到值的字典(字串)
interaction_token用來回應該互動的唯一 token
is_admin是否為叫用者有伺服器管理員權限
channel_id指令叫用的頻道
user / user_id呼叫者身份

步驟 4:回應互動

使用者叫用指令時,互動會自動顯示「思考中」提示。你可用以下三種行為回應互動:

interaction_followup

送出一則可見回覆。支援 embed 與組件:

{"action": "interaction_followup", "interaction_token": "abc-123-def", "content": "Here's your answer!"}
{"action": "interaction_followup", "interaction_token": "abc-123-def", "content": "", "embed": {"title": "Results", "description": "Found 5 matches", "color": 5865F2}, "components": [{"type": "action_row", "components": [{"type": "button", "style": "primary", "label": "Next Page", "custom_id": "next_page"}]}]}

interaction_respond

送出僅供叫用者可見的暫時訊息:

{"action": "interaction_respond", "interaction_token": "abc-123-def", "content": "只有你能看到這則訊息", "ephemeral": true}

interaction_edit

編輯原始互動回覆,常見於按鈕或內容在使用者操作後更新:

{"action": "interaction_edit", "interaction_token": "abc-123-def", "content": "Updated!", "components": []}
Danger

互動 token 會在 15 分鐘後過期。 若你沒有在 15 分鐘內送出 followup,互動會失敗,使用者會看到「應用程式未回應」。無論成功與否都應盡速回應,哪怕只是回報已收到。

完整可執行範例

import json
import subprocess
import threading
from queue import Queue
class SlashBot:
def __init__(self, commands_file):
self.proc = subprocess.Popen(
["discli", "serve", "--slash-commands", commands_file, "--events", "messages"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
text=True,
)
self.events = Queue()
self.pending = {}
self._counter = 0
threading.Thread(target=self._reader, daemon=True).start()
def _reader(self):
for line in self.proc.stdout:
data = json.loads(line.strip())
rid = data.get("req_id")
if rid in self.pending:
self.pending[rid].put(data)
else:
self.events.put(data)
def send(self, action, wait=False):
self._counter += 1
rid = f"r{self._counter}"
action["req_id"] = rid
if wait:
q = Queue()
self.pending[rid] = q
self.proc.stdin.write(json.dumps(動作) + "\n")
self.proc.stdin.flush()
if wait:
result = q.get(timeout=15)
del self.pending[rid]
return result
return None
def followup(self, token, content):
"""送出 slash command 互動的 followup 回覆。"""
self.send({
"action": "interaction_followup",
"interaction_token": token,
"content": content,
})
# 定義指令處理函式
def handle_ask(bot, event):
question = event["args"].get("question", "")
# 實際環境中可接 AI 模型呼叫
answer = f"你問了:{question}\n\nAI 回覆內容可在這裡產生。"
bot.followup(event["interaction_token"], answer)
def handle_status(bot, event):
servers = bot.send({"action": "server_list"}, wait=True)
count = len(servers.get("servers", []))
bot.followup(
event["interaction_token"],
f"已上線,正在監控 {count} 個伺服器。",
)
def handle_search(bot, event):
query = event["args"].get("query", "")
limit = int(event["args"].get("limit", "10"))
result = bot.send({
"action": "message_search",
"channel_id": event["channel_id"],
"query": query,
"limit": limit,
}, wait=True)
messages = result.get("messages", [])
if not messages:
bot.followup(event["interaction_token"], f"找不到符合『{query}』的訊息。")
return
lines = [f"找到 {len(messages)} 則結果,條件為『{query}』:\n"]
for msg in messages[:10]:
lines.append(f"**{msg['author']}**: {msg['content'][:100]}")
bot.followup(event["interaction_token"], "\n".join(lines))
HANDLERS = {
"ask": handle_ask,
"status": handle_status,
"search": handle_search,
}
def main():
bot = SlashBot("commands.json")
# 等待 ready
while True:
event = bot.events.get()
if event.get("event") == "ready":
print(f"Ready as {event['bot_name']}")
break
# 等待指令同步完成
while True:
event = bot.events.get()
if event.get("event") == "slash_commands_synced":
print(f"已註冊 {event['count']} 組指令到 {event['guilds']} 個伺服器")
break
# 避免無限等待
if event.get("event") == "error":
print(f"錯誤:{event.get('message')}")
break
# 主事件迴圈
while True:
event = bot.events.get()
if event.get("event") == "slash_command":
handler = HANDLERS.get(event["command"])
if handler:
try:
handler(bot, event)
except Exception as e:
bot.followup(
event["interaction_token"],
f"發生錯誤:{e}",
)
else:
bot.followup(
event["interaction_token"],
f"未知指令:{event['command']}",
)
if __name__ == "__main__":
main()

串流式 Slash 指令回應

較長回應可改成串流輸出,不需一次傳回全部結果。透過 interaction_token 使用 stream_start

def handle_ask_streaming(bot, event):
question = event["args"].get("question", "")
# 開始可回應 slash 互動的串流
result = bot.send({
"action": "stream_start",
"channel_id": event["channel_id"],
"interaction_token": event["interaction_token"],
}, wait=True)
if "error" in result:
bot.followup(event["interaction_token"], f"錯誤:{result['error']}")
return
stream_id = result["stream_id"]
# 從 LLM 串流回傳
for chunk in call_llm(question):
bot.send({
"action": "stream_chunk",
"stream_id": stream_id,
"content": chunk,
})
bot.send({"action": "stream_end", "stream_id": stream_id})

詳情請見 串流回應

註冊時機

Tip

discli 在啟動時會對每個伺服器分別同步指令,因而可立即可用。若機器人執行中加入新伺服器,新的伺服器會在你重新啟動 discli serve 後才有 Slash 指令。

指令何時出現

方法時機
僅同步到伺服器(discli 行為)立即
僅全域註冊最多 1 小時

指令更新時機

若你修改 commands.json,請重啟 discli serve 以重新註冊更新後的指令。

僅限管理員指令

slash_command 事件包含 is_admin 欄位。可用來保護敏感指令:

def handle_admin_command(bot, event):
if not event["is_admin"]:
bot.followup(
event["interaction_token"],
"此指令需要管理員權限。",
)
return
# ... 繼續執行管理動作

參數類型對應表

JSON 類型Python 類型Discord 類型
stringstr字串選項
integerint整數選項
numberfloat數值選項
booleanbool布林值選項

可選參數(requiredfalse)在使用者未提供時,args 字典中不會出現。

下一步