Agent Skills by ALSEL
汎用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

本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: DevRohit06 · DevRohit06/discli · ライセンス: MIT