Categoría: Bots de Discord

Crear un bot de Discord#9¡Integra la IA (API de Claude y ChatGPT)! (ejemplo en Python)

Esta entrada es una traducción del original en coreano.

Índice8 secciones

¡Hola! Soy Mojangcam 😎

En el #8 aprendimos a decorar los mensajes del bot con embeds (Embed). En este episodio por fin llega la función que muchos estaban esperando: ¡conectar la IA a tu bot! Vamos a crear un bot al que le escribes /ai 질문 (tu pregunta) y te responde Claude o ChatGPT.

Los miembros del servidor pueden preguntarle lo que quieran a la IA, y además un solo bot puede encargarse de explicar las reglas del servidor, traducir o responder dudas de código, así que es súper útil.

※ La imagen de arriba no es una captura de ejecución real. Como todavía no he recargado créditos de la API, en lugar del resultado real adjunto una imagen de ejemplo hecha de forma provisional. ¡Cambiaré la captura real cuando recargue créditos!

⚠️ Una cosa antes de empezar: a diferencia del bot o de las librerías, las API de IA son un servicio de pago que cobra pequeñas cantidades según el uso. Aun así, para un bot de un servidor personal, con un modelo ligero cuesta apenas unos cientos de wones al mes (menos de un dólar), así que la carga es pequeña.

📌 Lo que necesitas

  • Python 3.8 o superior
  • discord.py 2.x
  • La librería anthropic (para la API de Claude) o la librería openai (para ChatGPT)
  • API key: la de Claude se obtiene en platform.claude.com y la de ChatGPT en platform.openai.com (hay que recargar un poco de crédito)
mipsasm
pip install -U discord.py anthropic python-dotenv

En este artículo trabajaremos con la API de Claude, y al final también te mostraré la versión de ChatGPT (OpenAI).

📌 Paso 1 - Guarda la API key de forma segura en .env

Igual que con el token del bot, la API key de IA es una clave vinculada a cobros, así que si se filtra tendrás un problema serio. Sepárala siempre en un archivo .env.

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

📌 Paso 2 - Llamar a Claude con el comando /ai

Python
import discord
from discord import app_commands
from anthropic import AsyncAnthropic

ai = AsyncAnthropic()  # Detecta automáticamente la variable de entorno ANTHROPIC_API_KEY

@tree.command(name="ai", description="Hacerle una pregunta a la IA")
async def ai_command(interaction: discord.Interaction, 질문: str):
    await interaction.response.defer()  # ⭐ ¡Clave! Mira la explicación de abajo
    result = await ai.messages.create(
        model="claude-haiku-4-5",
        max_tokens=1000,
        system="Eres un asistente amable de un servidor de Discord. Responde de forma concisa.",
        messages=[{"role": "user", "content": 질문}],
    )
    answer = result.content[0].text
    await interaction.followup.send(answer[:2000])

Vamos a verlo parte por parte 💡

  • AsyncAnthropic : discord.py funciona de forma asíncrona (async), así que tienes que usar sí o sí el cliente asíncrono. Si usas el Anthropic() normal, ¡todo el bot se congela mientras la IA responde!
  • defer() : Discord da por fallido un slash command si no respondes en 3 segundos. Las respuestas de la IA suelen tardar más de 3 segundos, así que defer, que pospone la respuesta con el estado "Pensando...", es imprescindible
  • model : en el ejemplo uso claude-haiku-4-5, que es rápido y barato. Si necesitas respuestas más inteligentes, cámbialo por claude-sonnet-5 (el precio sube)
  • system : la parte que define la personalidad y el papel del bot. Cámbiala libremente para que encaje con el estilo de tu servidor
  • [:2000] : los mensajes de Discord tienen un máximo de 2000 caracteres, así que hay que recortarlos para que no dé error

📌 Paso 3 - Hacer que recuerde la conversación (opcional)

Con el código de arriba cada mensaje es una conversación nueva, así que no recuerda la pregunta anterior. Vamos a hacer que recuerde los últimos 10 mensajes de cada canal.

vim
from collections import defaultdict

history = defaultdict(list)  # Historial de conversación por ID de canal

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="Eres un asistente amable de un servidor de Discord.",
        messages=history[channel_id][-10:],  # Solo envía los 10 más recientes
    )
    answer = result.content[0].text
    history[channel_id].append({"role": "assistant", "content": answer})
    return answer

Vamos a verlo parte por parte 💡

  • history[channel_id][-10:] : si envías toda la conversación, el costo en tokens no para de crecer. ¡Recortar a los últimos 10 es el truco para ahorrar!
  • Guardar el rol assistant : también hay que meter las respuestas de la IA en el historial para que funcionen conversaciones encadenadas como "sobre lo que dijiste antes..."

📌 Código completo (puedes copiar y pegar)

Python
# discord.py 2.x / anthropic última versión / 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} ha iniciado sesión!")

@tree.command(name="ai", description="Hacerle una pregunta a la IA")
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="Eres un asistente amable de un servidor de Discord. Responde de forma concisa.",
            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"⚠️ Ocurrió un error: {e}")

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

💡 ¿Quieres usar ChatGPT (OpenAI)? Solo tienes que cambiar la parte de la llamada así (pip install openai, variable de entorno OPENAI_API_KEY).

makefile
from openai import AsyncOpenAI
ai = AsyncOpenAI()

result = await ai.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "system", "content": "Eres un asistente amable."},
              {"role": "user", "content": 질문}],
)
answer = result.choices[0].message.content

La única diferencia es que en OpenAI el mensaje system también va dentro de messages; por lo demás, la estructura es casi igual.

📌 Resultado

Ejecuta el bot y escribe /ai 파이썬이 뭐야? ("¿qué es Python?") en el servidor: aparecerá un momento el indicador "Pensando..." y luego la respuesta de la IA se publicará en el canal. Si sigues preguntando en el mismo canal, ¡responderá recordando la conversación anterior!

※ Esta imagen de la conversación también es un ejemplo hecho de forma provisional por el costo de la API. (No es una captura de ejecución real)

📌 Errores frecuentes

  1. 404 Not Found o Unknown interaction — Causa: llamaste directamente a response.send_message sin haber respondido en 3 segundos. Solución: haz siempre primero defer() → y responde con followup.send()
  2. authentication_error (401) — Causa: la API key tiene una errata, falta o caducó. Solución: revisa de nuevo la key en .env y comprueba también el saldo de créditos en la consola
  3. HTTPException: Must be 2000 or fewer in length — Causa: la respuesta de la IA pasa de 2000 caracteres. Solución: recórtala con [:2000] como en el ejemplo o, si es larga, divídela en varios mensajes
  4. rate_limit_error (429) — Causa: llegan muchas solicitudes en poco tiempo. Solución: conviene ponerle un cooldown al comando. ¡Cómo implementar el cooldown lo veremos en el próximo episodio!

📌 Para terminar

Hoy conectamos las API de Claude y ChatGPT al bot para crear un verdadero "bot de IA". Si esquivas el límite de 3 segundos con defer y añades memoria de conversación por canal, la experiencia de uso mejora muchísimo. En el próximo episodio veremos cooldowns y gestión de permisos para evitar el abuso de los comandos de IA. ¡No te lo pierdas! 🙌

📚 Serie Crear un bot de Discord

  • #1 ~ #4 Lo básico
  • #5 Interacciones con botones (Button)
  • #6 Menús desplegables (Select Menu)
  • #7 Pedir texto con un modal (Modal)
  • #8 Decorar embeds (Embed) con imágenes y campos
  • #9 Integrar la IA (API de Claude y ChatGPT) ← ¡estás leyendo este!
  • Extra: guía completa de hosting gratis 24 horas

Serie · Parte 9 de 32

Crear un bot de Discord

  1. #1Crear un bot de Discord - ¡Domina por completo los Slash Commands!
  2. #2¡Añade opciones (argumentos) a tus Slash Commands!
  3. #3¡Añade subcomandos (Subcommand) a tus Slash Commands!
  4. #4¡Envía embeds con Slash Commands!
  5. #5¡Implementa interacciones con botones (Button)!
  6. #6¡Implementa menús desplegables (Select Menu)!
  7. #7Pide texto al usuario con un modal (Modal) (ejemplo en Python)
  8. #8Decora embeds (Embed) con imágenes y campos (ejemplo en Python)
  9. #9¡Integra la IA (API de Claude y ChatGPT)! (ejemplo en Python)Estás aquí
  10. #10¡Añade soporte multilingüe (i18n)! (ejemplo en Python)
  11. #11¡Crea un panel web con Flask! (ejemplo en Python)
  12. #12¡Gestiona los cooldowns y permisos de tus comandos! (ejemplo en Python)
  13. #13¡Administra tu servidor automatizando roles y canales! (ejemplo en Python)
  14. #14¡Guarda tus datos! JSON vs SQLite (ejemplo en Python)
  15. #15슬래시 명령어 그룹(Group)으로 명령어 정리하기! (파이썬 예제) (en coreano)
  16. #16리마인더·알림 기능 만들기! 봇이 먼저 말 걸게 하기 (파이썬 예제) (en coreano)
  17. #17RAG로 문서 기반 답변봇 만들기! 우리 서버 전용 FAQ 봇 (파이썬 예제) (en coreano)
  18. #18투표(Poll) 기능 만들기! 다수결로 정하는 서버 규칙 (파이썬 예제) (en coreano)
  19. #19Cog로 코드 쪼개기! 1000줄 봇도 안 더러워지는 구조 (파이썬 예제) (en coreano)
  20. #20자동 환영 메시지·온보딩 만들기! 규칙 동의 버튼으로 자동 역할 부여 (파이썬 예제) (en coreano)
  21. #21키워드 자동응답·금지어 필터 만들기! 경고 누적으로 자동 제재까지 (파이썬 예제) (en coreano)
  22. #22슬래시 명령어 자동완성(Autocomplete) 만들기! 금지어를 골라서 추가·삭제 (파이썬 예제) (en coreano)
  23. #23aiosqlite로 비동기 DB 제대로 설계하기! JSON 탈출 (파이썬 예제) (en coreano)
  24. #24채널 난독화(Channel Obfuscation) 대응하기! 11/16부터 안 보이는 채널이 생겨요 (파이썬 예제) (en coreano)
  25. #25봇이 죽지 않게! 에러 핸들링·로깅 체계 잡기 (파이썬 예제) (en coreano)
  26. #26티켓(Ticket) 문의 시스템 만들기! 버튼 하나로 1:1 상담 채널 자동 생성 (파이썬 예제) (en coreano)
  27. #27티켓 담당자 배정·우선순위 만들기! 스태프가 여러 명이어도 안 꼬이게 (파이썬 예제) (en coreano)
  28. #28레벨·경험치(XP) 시스템 만들기! 채팅할수록 레벨업, 랭킹판까지 (파이썬 예제) (en coreano)
  29. #29화폐·상점(Economy) 시스템 만들기! 코인 벌어서 아이템 사기 (파이썬 예제) (en coreano)
  30. #30¡Crea un bot de encuestas y votaciones (Poll)! Encuestas nativas + botones con recuento en tiempo real (ejemplo en Python) 🗳️
  31. #32¡Crea un canal de registros y auditoría (Audit Log) del servidor! Registra automáticamente mensajes borrados y editados, entradas, salidas y expulsiones (ejemplo en Python) 🕵️
  32. #33임시 음성방 확장, 파티방 만들기! 방장 위임·강퇴·초대 전용(비공개) 방 + 전용 채팅방 자동 생성 (파이썬 예제) 🎉 (en coreano)
Ver las 32Contraer

Autor

Mojangcam

Un registro práctico de desarrollo e IT: código que escribo, servidores que mantengo y los errores que resuelvo por el camino.