汎用LLM・AI開発⭐ リポ 21品質スコア 78/100
discord-support-bot
disccliを使用してDiscordのサポート・ヘルプデスクボットを構築できます。チケットごとのスレッド管理、FAQ自動応答、ナレッジベース検索、チケットルーティング、ステータス追跡、定型文応答などの機能を備えています。AI駆動型とルールベース型の両方のアプローチに対応しています。
description の原文を見る
Build Discord support/helpdesk bots with discli. Thread-per-ticket systems, FAQ auto-responders, knowledge base search, ticket routing, status tracking, and canned responses. Works with AI or rule-based approaches.
SKILL.md 本文
Discord サポートボットビルダー
discli を使用して、ユーザーの質問に対応し、チケットスレッドを作成し、問題をルーティングし、自動応答を提供するサポートおよびヘルプデスクボットを構築します。
使用時機
以下の場合にこのスキルを使用してください:
- Discord 上にサポートチケットシステムを構築したい
- FAQ ボットやナレッジベースレスポンダーを作成したい
- スレッド単位のチケットワークフロー付きヘルプデスクを構築したい
- 質問を適切なチームにルーティングするボットを作成したい
- コミュニティ向けの AI 搭載の Q&A アシスタントを構築したい
パターン 1: スレッド単位のチケットシステム
各サポートリクエストは独自のスレッドを取得します。整理され、検索可能です。
import asyncio
import json
from datetime import datetime
SUPPORT_CHANNEL_ID = "YOUR_CHANNEL_ID" # The channel where users ask for help
TRIGGER_WORDS = ["help", "support", "issue", "bug", "problem", "question"]
# Track open tickets: user_id -> thread_id
open_tickets: dict[str, str] = {}
async def handle_support_request(event: dict, send) -> None:
author = event["author"]
author_id = event["author_id"]
channel_id = event["channel_id"]
message_id = event["message_id"]
content = event["content"]
# Check if user already has an open ticket
if author_id in open_tickets:
thread_id = open_tickets[author_id]
await send("thread_send", thread_id=thread_id,
content=f"New message from {author}:\n> {content}")
await send("reaction_add", channel_id=channel_id, message_id=message_id, emoji="📨")
return
# Create new support thread
ticket_name = f"Support: {author} — {datetime.utcnow().strftime('%m/%d %H:%M')}"
await send("thread_create",
channel_id=channel_id,
message_id=message_id,
name=ticket_name,
content=f"**New support ticket from {author}**\n\n"
f"> {content}\n\n"
f"A team member will respond shortly.")
# React to confirm ticket creation
await send("reaction_add", channel_id=channel_id, message_id=message_id, emoji="🎫")
# Note: thread_id comes back in the response event — track it
async def close_ticket(user_id: str, thread_id: str, send) -> None:
"""Close a support ticket."""
await send("thread_send", thread_id=thread_id,
content="This ticket has been resolved and will be archived.",
embed={"title": "Ticket Closed", "color": "57F287",
"footer": f"Closed at {datetime.utcnow().isoformat()[:19]}"})
await send("thread_archive", thread_id=thread_id, archived=True)
open_tickets.pop(user_id, None)
パターン 2: FAQ 自動応答
質問をナレッジベースと照合し、自動的に応答します。
FAQ = [
{
"keywords": ["install", "setup", "get started", "download"],
"title": "Installation",
"answer": "Install with `pip install discord-cli-agent`. See our [setup guide](https://example.com/setup).",
},
{
"keywords": ["token", "bot token", "authentication", "login"],
"title": "Bot Token Setup",
"answer": "1. Go to Discord Developer Portal\n2. Create a bot\n3. Copy the token\n4. Run `discli config set token YOUR_TOKEN`",
},
{
"keywords": ["permission", "permissions", "access denied", "not allowed"],
"title": "Permissions",
"answer": "Make sure your bot has the required permissions. Enable all privileged intents in the Developer Portal.",
},
{
"keywords": ["error", "crash", "not working", "broken"],
"title": "Troubleshooting",
"answer": "1. Check `discli config show` for valid token\n2. Ensure bot is in the server\n3. Check permissions\n4. Try `discli server list` to verify connection",
},
]
def find_faq_match(content: str) -> dict | None:
content_lower = content.lower()
best_match = None
best_score = 0
for entry in FAQ:
score = sum(1 for kw in entry["keywords"] if kw in content_lower)
if score > best_score:
best_score = score
best_match = entry
return best_match if best_score > 0 else None
async def handle_faq(event: dict, send) -> bool:
"""Try to answer from FAQ. Returns True if answered."""
match = find_faq_match(event["content"])
if not match:
return False
await send("reply",
channel_id=event["channel_id"],
message_id=event["message_id"],
content="",
embed={
"title": match["title"],
"description": match["answer"],
"color": "5865F2",
"footer": "From our FAQ — was this helpful? React with 👍 or 👎",
})
return True
パターン 3: AI 搭載のコンテキスト付きサポート
FAQ を LLM と組み合わせて、FAQ でカバーされていない質問に対応します。
import anthropic
api = anthropic.Anthropic()
KNOWLEDGE_BASE = """
# Product Documentation
- Installation: pip install discord-cli-agent
- Configuration: discli config set token YOUR_TOKEN
- Commands: See discli --help
# Known Issues
- Windows: Use Python 3.10+
- Rate limits: Built-in 5 calls/5s limiter
"""
SYSTEM = f"""You are a support agent. Answer questions using this knowledge base:
{KNOWLEDGE_BASE}
Rules:
- Be concise (under 300 words)
- If you don't know, say so and suggest opening a GitHub issue
- Include relevant command examples when applicable
- Format with Discord markdown (bold, code blocks, lists)
"""
async def ai_support(event: dict, send) -> None:
"""Answer using AI when FAQ doesn't match."""
# Try FAQ first
if await handle_faq(event, send):
return
# Fall back to AI
await send("typing_start", channel_id=event["channel_id"])
response = api.messages.create(
model="claude-sonnet-4-20250514",
system=SYSTEM,
messages=[{"role": "user", "content": event["content"]}],
max_tokens=512,
)
answer = response.content[0].text
await send("typing_stop", channel_id=event["channel_id"])
await send("reply",
channel_id=event["channel_id"],
message_id=event["message_id"],
content=answer)
パターン 4: サポート用スラッシュコマンド
[
{"name": "ticket", "description": "Open a support ticket", "params": [
{"name": "issue", "type": "string", "description": "Describe your issue"}
]},
{"name": "close", "description": "Close the current support ticket"},
{"name": "faq", "description": "Search the FAQ", "params": [
{"name": "query", "type": "string", "description": "What are you looking for?"}
]},
{"name": "status", "description": "Check your ticket status"}
]
パターン 5: エンベッド付きチケットステータス
STATUS_COLORS = {
"open": "FEE75C", # yellow
"in_progress": "5865F2", # blue
"resolved": "57F287", # green
"closed": "99AAB5", # grey
}
async def send_ticket_status(ticket: dict, channel_id: str, send) -> None:
await send("send", channel_id=channel_id, embed={
"title": f"Ticket #{ticket['id']}",
"color": STATUS_COLORS.get(ticket["status"], "99AAB5"),
"fields": [
{"name": "Status", "value": ticket["status"].replace("_", " ").title(), "inline": True},
{"name": "Created by", "value": ticket["author"], "inline": True},
{"name": "Created at", "value": ticket["created_at"], "inline": True},
{"name": "Description", "value": ticket["description"][:1024], "inline": False},
],
"footer": "React with ✅ to close this ticket",
})
完全なサポートボットスケルトン
async def handle_event(event: dict, send) -> None:
etype = event.get("event")
if etype == "message" and not event.get("is_bot"):
if event.get("mentions_bot"):
# Try FAQ, then AI, then create ticket
if not await handle_faq(event, send):
await ai_support(event, send)
elif any(w in event["content"].lower() for w in TRIGGER_WORDS):
if event["channel_id"] == SUPPORT_CHANNEL_ID:
await handle_support_request(event, send)
elif etype == "slash_command":
await handle_slash_command(event, send)
elif etype == "reaction_add":
if event["emoji"] == "✅":
# Check if this is a ticket thread, close it
pass
elif etype == "component_interaction":
# Handle button clicks on ticket embeds
pass
ガイドライン
- スレッドはサポート専用チャンネルに作成し、どこにでも作成しない
- クローズ時にスレッドをアーカイブすることで、検索可能でありながら雑然とさせない
- 受領を確認するためにリアクションを付ける(新規チケットは 🎫、既存チケットは 📨)
- スレッド名にチケット ID / タイムスタンプを含めて簡単に参照できるようにする
- 構造化された情報(ステータス、FAQ の回答)にはエンベッドを使用する
- スタッフがチケットを解決できるように
/closeコマンドを設定する - 解決されたチケットをログに記録して分析する(応答時間、解決率)
- チケット作成をレート制限して悪用を防ぐ
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- DevRohit06
- リポジトリ
- DevRohit06/discli
- ライセンス
- MIT
- 最終更新
- 2026/4/16
Source: https://github.com/DevRohit06/discli / ライセンス: MIT