カテゴリー: Discordボット開発

Discordボット開発#9AI(Claude・ChatGPT API)と連携する! (Pythonサンプル付き)

この記事は韓国語の原文から翻訳したものです。

目次8項目

こんにちは!Mojangcamです 😎

前回の#8では埋め込み(Embed)でボットのメッセージをきれいに飾る方法を学びましたね。今回はいよいよ、多くの方が待っていた機能、ボットにAIを連携してみます!/ai 질문(질문は「質問」の意味)のように入力すると、ClaudeやChatGPTが答えてくれるボットを作ります。

サーバーのメンバーが自由にAIに質問したり、サーバールールの案内・翻訳・コードの質問への回答などをボット1つでこなせるので、本当に活用の幅が広いです。

※ 上の画像は実際の実行画面ではありません。まだAPIクレジットをチャージしていないため、実際の呼び出し結果の代わりに仮で作ったサンプル画像を載せています。実際の実行スクリーンショットは、クレジットをチャージしたあとに差し替えます!

⚠️ 始める前にひとつだけ: AI APIはボットやライブラリと違って、使った分だけ少額が課金される有料サービスです。とはいえ個人サーバー用のボット程度なら、軽量モデルで月に数百ウォン(数十円)程度なので、負担は小さいほうです。

📌 準備するもの

  • Python 3.8以上
  • discord.py 2.x
  • anthropicライブラリ (Claude API用) または openaiライブラリ (ChatGPT用)
  • APIキー: Claudeはplatform.claude.comで、ChatGPTはplatform.openai.comで発行 (少額のクレジットのチャージが必要)
mipsasm
pip install -U discord.py anthropic python-dotenv

この記事はClaude APIを基準に進め、最後にChatGPT(OpenAI)版もお見せします。

📌 ステップ1 - APIキーを.envで安全に保管する

ボットトークンもそうですが、AI APIキーは有料課金にひもづいたキーなので、漏れたら本当に大変なことになります。必ず.envファイルに分けておきましょう。

INI
# .env
DISCORD_TOKEN=봇토큰
ANTHROPIC_API_KEY=sk-ant-...

📌 ステップ2 - /aiコマンドでClaudeを呼び出す

Python
import discord
from discord import app_commands
from anthropic import AsyncAnthropic

ai = AsyncAnthropic()  # ANTHROPIC_API_KEY 環境変数を自動で認識

@tree.command(name="ai", description="AIに質問する")
async def ai_command(interaction: discord.Interaction, 질문: str):
    await interaction.response.defer()  # ⭐ ここがポイント!下の説明を参照
    result = await ai.messages.create(
        model="claude-haiku-4-5",
        max_tokens=1000,
        system="あなたはDiscordサーバーの親切なアシスタントです。簡潔に答えてください。",
        messages=[{"role": "user", "content": 질문}],
    )
    answer = result.content[0].text
    await interaction.followup.send(answer[:2000])

ひとつずつ見ていきましょう 💡

  • AsyncAnthropic : discord.pyは非同期(async)で動くので、必ず非同期クライアントを使う必要があります。ふつうのAnthropic()を使うと、AIが答えている間ボット全体が止まってしまいます!
  • defer() : Discordはスラッシュコマンドに3秒以内に応答しないと失敗扱いにします。AIの応答はたいてい3秒を超えるので、「考え中...」の状態に先送りするdeferが必須です
  • model : サンプルでは速くて安いclaude-haiku-4-5を使いました。もっと賢い答えが必要ならclaude-sonnet-5に変えればOKです (料金は上がります)
  • system : ボットの性格・役割を決める部分です。サーバーのコンセプトに合わせて自由に変えてみてください
  • [:2000] : Discordのメッセージは最大2,000文字なので、切ってから送らないとエラーになります

📌 ステップ3 - 会話を覚えさせる (任意)

上のコードは毎回新しい会話なので、直前の質問を覚えていません。チャンネルごとに直近の会話10件を覚えるようにしてみましょう。

vim
from collections import defaultdict

history = defaultdict(list)  # チャンネルIDごとの会話履歴

async def ask_ai(channel_id: int, 질문: str) -> str:
    history[channel_id].append({"role": "user", "content": 질문})
    result = await ai.messages.create(
        model="claude-haiku-4-5",
        max_tokens=1000,
        system="あなたはDiscordサーバーの親切なアシスタントです。",
        messages=history[channel_id][-10:],  # 直近10件だけ渡す
    )
    answer = result.content[0].text
    history[channel_id].append({"role": "assistant", "content": answer})
    return answer

ひとつずつ見ていきましょう 💡

  • history[channel_id][-10:] : 会話を全部送ると、トークン料金がどんどん増えていきます。直近10件に絞るのが料金節約のポイント!
  • assistantロールの保存 : AIの答えも履歴に入れておくことで、「さっき言ったあれだけど」のような続きの会話ができるようになります

📌 全体のコード (コピペOK)

Python
# discord.py 2.x / anthropic 最新 / Python 3.8+
import os
import discord
from discord import app_commands
from collections import defaultdict
from anthropic import AsyncAnthropic
from dotenv import load_dotenv

load_dotenv()

intents = discord.Intents.default()
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)
ai = AsyncAnthropic()
history = defaultdict(list)

@client.event
async def on_ready():
    await tree.sync()
    print(f"{client.user} ログイン完了!")

@tree.command(name="ai", description="AIに質問する")
async def ai_command(interaction: discord.Interaction, 질문: str):
    await interaction.response.defer()
    try:
        history[interaction.channel_id].append({"role": "user", "content": 질문})
        result = await ai.messages.create(
            model="claude-haiku-4-5",
            max_tokens=1000,
            system="あなたはDiscordサーバーの親切なアシスタントです。簡潔に答えてください。",
            messages=history[interaction.channel_id][-10:],
        )
        answer = result.content[0].text
        history[interaction.channel_id].append({"role": "assistant", "content": answer})
        await interaction.followup.send(answer[:2000])
    except Exception as e:
        await interaction.followup.send(f"⚠️ エラーが発生しました: {e}")

client.run(os.getenv("DISCORD_TOKEN"))

💡 ChatGPT(OpenAI)で使いたい場合は?呼び出し部分をこう変えるだけです (pip install openai、環境変数OPENAI_API_KEY)。

makefile
from openai import AsyncOpenAI
ai = AsyncOpenAI()

result = await ai.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "system", "content": "親切なアシスタントです。"},
              {"role": "user", "content": 질문}],
)
answer = result.choices[0].message.content

OpenAIはsystemメッセージもmessagesの中に入れるという点だけが違い、構造はほぼ同じです。

📌 実行結果

ボットを起動してサーバーで/ai 파이썬이 뭐야?(「Pythonって何?」)と入力すると、少しの間「考え中...」と表示されたあと、AIの答えがチャンネルに投稿されます。同じチャンネルで続けて質問すると、前の会話を覚えたうえで答えてくれます!

※ この会話の画像も、APIの費用の都合で仮に作ったサンプル画像です。(実際の実行画面ではありません)

📌 よくあるエラー

  1. 404 Not Found または Unknown interaction — 原因: 3秒以内に応答しないまま、いきなりresponse.send_messageを呼び出した場合。解決: 必ずdefer()を先に → followup.send()で返信してください
  2. authentication_error (401) — 原因: APIキーのタイプミス・未設定・期限切れ。解決: .envのキーをもう一度確認し、コンソールでクレジット残高も確認してください
  3. HTTPException: Must be 2000 or fewer in length — 原因: AIの答えが2,000文字を超えた。解決: サンプルのように[:2000]で切るか、長い場合は複数のメッセージに分けて送ってください
  4. rate_limit_error (429) — 原因: 短時間にリクエストが集中した。解決: コマンドにクールダウンをかけるのがおすすめです — クールダウンの実装は次回で扱います!

📌 まとめ

今回はボットにClaude・ChatGPT APIを連携して、本物の「AIボット」を作ってみました。deferで3秒制限を回避し、チャンネルごとの会話の記憶まで入れると、使い心地がぐっと良くなります。次回は、AIコマンドの乱用を防ぐクールダウンと権限管理を扱います。お楽しみに 🙌

📚 Discordボット開発シリーズ

  • #1 ~ #4 基礎編
  • #5 ボタン(Button)のインタラクション
  • #6 ドロップダウン(Select Menu)
  • #7 モーダル(Modal)で入力を受け取る
  • #8 埋め込み(Embed)を画像・フィールドで飾る
  • #9 AI(Claude・ChatGPT API)と連携する ← 今読んでいる記事!
  • 番外編: 24時間無料ホスティングまとめ

連載 · 全32回中9回目

Discordボット開発

  1. #1Discordボット開発 - スラッシュコマンド(Slash Command)完全攻略!
  2. #2スラッシュコマンドにオプション(Arguments)を追加しよう!
  3. #3スラッシュコマンドにサブコマンド(Subcommand)を追加しよう!
  4. #4スラッシュコマンドで埋め込み(Embed)を送信しよう!
  5. #5ボタン(Button)のインタラクションを実装しよう!
  6. #6ドロップダウン(Select Menu)メニューを実装しよう!
  7. #7モーダル(Modal)で入力を受け取る方法 (Pythonサンプル付き)
  8. #8埋め込み(Embed)を画像・フィールドで飾る (Pythonサンプル付き)
  9. #9AI(Claude・ChatGPT API)と連携する! (Pythonサンプル付き)現在の記事
  10. #10多言語(i18n)に対応する! (Pythonサンプル付き)
  11. #11FlaskでWebダッシュボードを作る! (Pythonサンプル付き)
  12. #12コマンドのクールダウン(Cooldown)・権限(Permission)を管理しよう! (Pythonサンプル付き)
  13. #13ロール・チャンネルの自動化でサーバーを管理しよう! (Pythonサンプル付き)
  14. #14データを保存しよう!JSON vs SQLite (Pythonサンプル付き)
  15. #15슬래시 명령어 그룹(Group)으로 명령어 정리하기! (파이썬 예제) (韓国語)
  16. #16리마인더·알림 기능 만들기! 봇이 먼저 말 걸게 하기 (파이썬 예제) (韓国語)
  17. #17RAG로 문서 기반 답변봇 만들기! 우리 서버 전용 FAQ 봇 (파이썬 예제) (韓国語)
  18. #18투표(Poll) 기능 만들기! 다수결로 정하는 서버 규칙 (파이썬 예제) (韓国語)
  19. #19Cog로 코드 쪼개기! 1000줄 봇도 안 더러워지는 구조 (파이썬 예제) (韓国語)
  20. #20자동 환영 메시지·온보딩 만들기! 규칙 동의 버튼으로 자동 역할 부여 (파이썬 예제) (韓国語)
  21. #21키워드 자동응답·금지어 필터 만들기! 경고 누적으로 자동 제재까지 (파이썬 예제) (韓国語)
  22. #22슬래시 명령어 자동완성(Autocomplete) 만들기! 금지어를 골라서 추가·삭제 (파이썬 예제) (韓国語)
  23. #23aiosqlite로 비동기 DB 제대로 설계하기! JSON 탈출 (파이썬 예제) (韓国語)
  24. #24채널 난독화(Channel Obfuscation) 대응하기! 11/16부터 안 보이는 채널이 생겨요 (파이썬 예제) (韓国語)
  25. #25봇이 죽지 않게! 에러 핸들링·로깅 체계 잡기 (파이썬 예제) (韓国語)
  26. #26티켓(Ticket) 문의 시스템 만들기! 버튼 하나로 1:1 상담 채널 자동 생성 (파이썬 예제) (韓国語)
  27. #27티켓 담당자 배정·우선순위 만들기! 스태프가 여러 명이어도 안 꼬이게 (파이썬 예제) (韓国語)
  28. #28레벨·경험치(XP) 시스템 만들기! 채팅할수록 레벨업, 랭킹판까지 (파이썬 예제) (韓国語)
  29. #29화폐·상점(Economy) 시스템 만들기! 코인 벌어서 아이템 사기 (파이썬 예제) (韓国語)
  30. #30投票・アンケート(Poll)ボットを作ろう!ネイティブ投票+ボタンでリアルタイム集計まで(Pythonサンプル) 🗳️
  31. #32サーバーログ・監査ログ(Audit Log)チャンネルを作ろう!メッセージの削除・編集・入退室・キックまで自動記録(Pythonサンプル) 🕵️
  32. #33임시 음성방 확장, 파티방 만들기! 방장 위임·강퇴·초대 전용(비공개) 방 + 전용 채팅방 자동 생성 (파이썬 예제) 🎉 (韓国語)
全32回を表示閉じる

著者

Mojangcam

自分でコードを書き、サーバーを動かし、詰まったエラーを解決しながら学んだことを記録する開発・IT実践ブログ