Bot Discord AI do kodowania: Zbuduj go z API LLM
Bot Discord AI do kodowania odpowiada na pytania programistyczne na Twoim serwerze, używając modelu językowego za pośrednictwem API. Ten samouczek buduje go w około 70 liniach Pythona i omawia elementy, które zwykle powodują błędy.
Zaktualizowano

Kluczowe punkty
- Bot wymaga discord.py, pakietu openai, tokena bota i klucza API LLM.
- Włącz uprawnienie Message Content w portalu deweloperskim Discorda, w przeciwnym razie bot będzie widział puste wiadomości.
- Przechowuj krótką historię na kanał i ją przycinaj, ponieważ model nie pamięta niczego między wywołaniami.
- Dziel odpowiedzi na fragmenty po 2000 znaków i ogranicz równoległe wywołania, aby mieścić się w limicie 8 równoległych zapytań.
Co będzie robił bot
Celem jest bot Discord AI do kodowania, który reaguje na wzmianki. Użytkownik pisze „@helper dlaczego moja list comprehension zwraca None?”, bot wysyła wiadomość do modelu, a odpowiedź modelu wraca jako odpowiedź na tym samym kanale. Bot pamięta też kilka ostatnich zwrotów każdego kanału, dzięki czemu pytania dodatkowe działają.
Projekt składa się z trzech elementów. discord.py obsługuje połączenie z Discordem. Python SDK OpenAI komunikuje się z API LLM, które działa tutaj, ponieważ API jest kompatybilne z OpenAI. Mały słownik przechowuje historię rozmowy. Nie potrzebujesz bazy danych na start.
Potrzebujesz Pythona 3.9 lub nowszego, konta Discord pozwalającego na tworzenie aplikacji oraz klucza API ze strony klucza API. Nowe konta mogą jednorazowo zaksięgować $0,50 kredytu próbnego jednym kliknięciem, co wystarczy do zbudowania i przetestowania tego bota.
Krok 1: utwórz aplikację Discord
- Otwórz portal deweloperski Discorda i utwórz nową aplikację.
- W sekcji Bot utwórz użytkownika bota i skopiuj jego token. Traktuj go jak hasło.
- Na tej samej stronie włącz Message Content Intent w sekcji Privileged Gateway Intents. Bez tego bot odbierze wiadomości z pustym tekstem, a Ty spędzisz godzinę zastanawiając się, dlaczego nic nie odpowiada.
- W OAuth2 wygeneruj link zaproszenia z zakresem
boti uprawnieniami do odczytu i wysyłania wiadomości. Otwórz link i dodaj bota do testowego serwera.
Zainstaluj biblioteki i ustaw dwie zmienne środowiskowe.
pip install discord.py openai
export DISCORD_TOKEN="your-discord-bot-token"
export LLM_API_KEY="your-llm-api-key"
# quick check that the LLM key works, using model uncensored
curl -s https://api.codingllmapi.com/v1/chat/completions \
-H "Authorization: Bearer $LLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"uncensored","messages":[{"role":"user","content":"ping"}],"max_tokens":5}'Krok 2: kod bota
Zapisz to jako bot.py. Odpowiada na wzmianki, przechowuje dwanaście wiadomości historii na kanał, pokazuje wskaźnik pisania podczas oczekiwania i dzieli długie odpowiedzi.
import asyncio
import os
import discord
from openai import AsyncOpenAI, RateLimitError, APIError
llm = AsyncOpenAI(
base_url="https://api.codingllmapi.com/v1",
api_key=os.environ["LLM_API_KEY"],
)
SYSTEM = (
"You are a helpful programming assistant in a Discord server. "
"Answer briefly. Put code in fenced blocks. Say so when you are unsure."
)
MAX_TURNS = 12
history = {} # channel id -> list of messages
slots = asyncio.Semaphore(6) # stay under the 8 concurrent request cap
intents = discord.Intents.default()
intents.message_content = True
bot = discord.Client(intents=intents)
def split_reply(text, limit=1900):
parts = []
while len(text) > limit:
cut = text.rfind("\n", 0, limit)
if cut < limit // 2:
cut = limit
parts.append(text[:cut])
text = text[cut:].lstrip("\n")
parts.append(text)
return parts
@bot.event
async def on_message(message):
if message.author.bot or bot.user not in message.mentions:
return
question = message.clean_content.replace(f"@{bot.user.display_name}", "").strip()
if not question:
await message.reply("Ask me a coding question after the mention.")
return
log = history.setdefault(message.channel.id, [])
log.append({"role": "user", "content": question})
del log[:-MAX_TURNS]
async with message.channel.typing():
try:
async with slots:
resp = await llm.chat.completions.create(
model="uncensored",
messages=[{"role": "system", "content": SYSTEM}] + log,
temperature=0.4,
max_tokens=900,
)
except RateLimitError:
await message.reply("The model is busy. Try again in a few seconds.")
log.pop()
return
except APIError:
await message.reply("The model call failed. Try again shortly.")
log.pop()
return
answer = resp.choices[0].message.content or "(empty reply)"
log.append({"role": "assistant", "content": answer})
for part in split_reply(answer):
await message.reply(part)
bot.run(os.environ["DISCORD_TOKEN"])
Uruchom go poleceniem python bot.py, a następnie wspomnij bota na swoim serwerze testowym. Pierwsza odpowiedź powinna nadejść w ciągu kilku sekund.
Dlaczego kod jest napisany w ten sposób
Historia jest celowo przycinana
Model nie ma pamięci, więc każde wywołanie wysyła ostatnie zwroty. Bez del log[:-MAX_TURNS] lista rosłaby w nieskończoność. W końcu osiągnęłaby okno 100 000 tokenów, a koszty rosłyby z każdą wiadomością. Dwanaście wpisów wystarczy na rozmowę o jednym błędzie. Na serwerze z długimi wątkami zwiększ tę liczbę lub podsumuj starsze zwroty.
Limit 2000 znaków Discorda
Discord odrzuca wiadomości dłuższe niż 2000 znaków, a odpowiedzi z kodem trafiają w ten limit szybko. Pomocnik split_reply dzieli tekst przy nowej linii w pobliżu limitu. Nie zna znaczników kodu, więc blok może zostać ucięty w środku. Jeśli to Cię irytuje, dodaj logikę zamykającą znacznik na końcu jednej części i otwierającą go na początku kolejnej.
Semafor dla równoległości
Pełny klucz pozwala na 8 równoległych zapytań, a klucz próbny na 2. Na obciążonym serwerze może pojawić się kilka pytań naraz. Semafor kolejkuje dodatkowe wywołania wewnątrz Twojego procesu zamiast wysyłać je i otrzymywać błąd 429 z kodem błędu concurrency. Jeśli nadal korzystasz z klucza próbnego, zmień Semaphore(6) na Semaphore(2).
Błędy nie są rozliczane
Nieudane lub odrzucone zapytania nie są rozliczane, więc ponowna próba po błędzie nie podwaja kosztu. Kod usuwa zwrot użytkownika z historii przy błędzie, więc ponowna próba nie pozostawia wiszącego pytania, które model widział już dwukrotnie.
Poprawa jakości odpowiedzi
Gdy podstawowa pętla działa, kilka małych zmian znacznie ją poprawia.
- Strumieniuj odpowiedź. Przekaż
stream=Truei edytuj wiadomość bota mniej więcej co sekundę, wstawiając dotychczasowy tekst. Nie edytuj przy każdym tokenie, ponieważ Discord stosuje własne limity zapytań do edycji wiadomości. Żądanie strumieniowe zajmuje slot równoległości do końca, więc trzymaj semafor wokół całego strumienia. - Używaj poleceń slash. Polecenie takie jak
/askunika parsowania wzmianek i w ogóle nie wymaga uprawnienia Message Content, co również ułatwia weryfikację bota później, jeśli wyrośnie poza małą liczbę serwerów. - Historia na użytkownika. Grupuj historię według kanału i użytkownika, jeśli kilka osób zadaje niepowiązane pytania na jednym kanale.
- Dostosuj prompt systemowy. Wymień języki używane przez Twoją społeczność, poproś o krótkie odpowiedzi i powiedz modelowi, aby zadał pytanie doprecyzowujące, gdy problem jest niejasny. Zmiany promptu są darmowe i często lepsze niż zmiany modelu.
- Obniż temperaturę. Dla kodu wartości między 0,2 a 0,4 dają stabilniejsze wyniki niż domyślne.
Rozwiązywanie typowych problemów
Gdy nowy bot milczy, przyczyną jest prawie zawsze jedna z poniższych pozycji. Sprawdź je w tej kolejności.
- Bot jest online, ale nigdy nie odpowiada. Uprawnienie Message Content jest wyłączone w portalu deweloperskim lub w kodzie brakuje
intents.message_content = True. Obie muszą być ustawione. - Odpowiada tylko na niektórych kanałach. Botowi brakuje uprawnień do odczytu lub wysyłania wiadomości na pozostałych. Sprawdź nadpisywania uprawnień kanału, a nie tylko rolę na poziomie serwera.
- Każda odpowiedź to komunikat „busy”. Prawdopodobnie trafiasz w limit 429. Wypisz raz treść wyjątku. Jeśli kod to
rate_limited, przekroczono limit 300 zapytań na minutę dla pełnego klucza lub 60 dla klucza próbnego. Jeśli toconcurrency, zmniejsz rozmiar semafora. - Błąd uwierzytelnienia pojawia się przy pierwszym wywołaniu. Brakuje klucza LLM w środowisku procesu uruchamiającego bota. Klucz wyeksportowany w jednej karcie terminala nie jest widoczny dla usługi uruchomionej gdzie indziej.
- Odpowiedź jest ucięta.
max_tokens=900w przykładzie zatrzymuje długie odpowiedzi. Zwiększ go lub usuń, ponieważmax_tokensjest opcjonalne, a uzupełnienie może użyć reszty okna. - Bot odpowiada na własne wiadomości. Ta pętla występuje, jeśli usuniesz sprawdzenie
message.author.bot. Zostaw je.
Do debugowania loguj wartość X-Request-Id dla każdego wywołania. W przypadku użycia OpenAI SDK możesz ją odczytać z surowej odpowiedzi, wywołując llm.chat.completions.with_raw_response.create(...), a następnie odczytując .headers. Jeśli skontaktujesz się z działem wsparcia w sprawie konkretnej awarii, ten identyfikator pozwoli im znaleźć dokładne zapytanie.
Ile to kosztuje
Ceny to $0,15 za 1 mln tokenów wejściowych i $0,50 za 1 mln tokenów wyjściowych, bez subskrypcji. Weźmy typowy przykład: prompt systemowy plus dwanaście wpisów z historii to około 2500 tokenów wejściowych, a odpowiedź to około 400 tokenów.
Wejście: 2500 x $0,15 / 1 000 000 = $0,000375. Wyjście: 400 x $0,50 / 1 000 000 = $0,0002. Jedna odpowiedź kosztuje około $0,000575. Społeczność, która zadaje 500 pytań dziennie, wyda 500 x $0,000575 = $0,2875, czyli nieco mniej niż 30 centów. Twoje liczby będą inne przy dłuższych wklejaniach kodu, więc loguj resp.usage przez tydzień i odczytaj rzeczywiste średnie. Strona ceny pokazuje opcje doładowania: dowolna kwota całkowita od $20 do $500, z +5% od $50, +10% od $100 i +15% od $200, płatna kartą lub kryptowalutami.
Aby ograniczyć nadużycia, dodaj cooldown na użytkownika i limit długości pytania. Te dwa sprawdzenia lepiej chronią Twój stan konta niż jakiekolwiek inne dodatki.
Uwagi dotyczące hostingu i bezpieczeństwa
Bot to proces długotrwały. Wystarczy mała maszyna wirtualna lub host kontenerów, ponieważ ciężka praca odbywa się po stronie API. Uruchom go pod menedżerem procesów, aby restartował się po awarii, i przechowuj oba tokeny w zmiennych środowiskowych lub w magazynie sekretów, nigdy w repozytorium.
Zastanów się, na na na co pozwala Twój serwer. Model jest dostrojony do odpowiadania bez odmów treści dla zgodnego z prawem użytku przez dorosłych, więc będzie omawiał testy bezpieczeństwa lub odważną fikcję, które ściślejszy asystent mógłby odrzucić. Jeśli Twoja społeczność obejmuje młodszych członków, ustaw zasady w promptie systemowym, ogranicz bota do określonych kanałów i pamiętaj, że regulamin Discorda dotyczy również Twojego bota. Treści seksualizujące nieletnichchch są zabronione w tym API bez wyjątku.
Pełne szczegóły parametrów, takie jak stop, seed i wywoływanie funkcji, znajdziesz w dokumentacji API. Jeśli chcesz, aby bot uruchamiał kod lub czytał repozytoria, wywoływanie funkcji jest właściwą drogą, a Ty decydujesz, jakie funkcje model może żądać. Dla użycia tego modelu skupionego na programowaniu, zobacz stronę o modelu AI bez cenzury do kodowania.
Więcej przewodników
Pytania i odpowiedzi
Czy potrzebuję uprawnienia Message Content?
Tak, jeśli bot czyta zwykłe wiadomości i wzmianki. Jeśli używasz tylko poleceń slash, nie jest to potrzebne.
Czy bot może strumieniować odpowiedzi?
Tak. Ustaw stream=True i edytuj wiadomość Discord w spokojnym interwale, np. raz na sekundę, aby pozostać w granicach własnych limitów Discorda.
Co się stanie, jeśli zbyt wiele osób zapyta jednocześnie?
Powyżej 8 równoległych zapytań dla pełnego klucza API zwraca HTTP 429 z kodem concurrency. Semafor w Twoim kodzie kolejkuje dodatkowe pytania.
Czy bot zapamięta rozmowy po restarcie?
Nie przy użyciu słownika używanego tutaj. Przechowuj historię w SQLite lub Redis, jeśli potrzebujesz, aby przetrwała restarty.
Czy klucz API jest bezpieczny w bocie Discord?
Tak, jeśli pozostaje na Twoim serwerze w zmiennej środowiskowej. Nigdy nie publikuj go na kanale ani nie dodawaj do publicznego repozytorium.
Twój klucz jest o jeden formularz stąd
Utwórz konto, skopiuj klucz, zmień bazowy URL. To cała konfiguracja.
Pobierz klucz API