PL ▾
Pobierz klucz API

Zbuduj chatbota z API LLM: Samouczek Python

Modele Abliterated to duże modele językowe, w których usunięto mechanizmy wymuszające odmowę odpowiedzi, co pozwala modelowi odpowiadać na pytania kontrowersyjne, dla dorosłych lub wąskiej tematyki bez trafienia w filtr treści. Podejście to daje programistom pełną kontrolę nad głosem modelu i zakresem wiedzy, co jest szczególnie cenne w kodowaniu, roleplay i pisaniu kreatywnym, gdzie standardowe ograniczenia mogą blokować przydatne wyjście.

Bloki wiadomości czatu poruszające się w pętli do centralnego sześcianu, ilustrujące pętlę rozmowy chatbota

Kluczowe punkty

  • API jest bezstanowe, więc twój kod zarządza historią rozmowy i wysyła ją w każdym zapytaniu.
  • Strumieniowanie, wywoływanie narzędzi i tryb JSON używają standardowych parametrów OpenAI.
  • Przytnij lub podsumuj historię, zanim zbliżysz się do okna kontekstu 100 000 tokenów.
  • 1 000 rozmów po 2 000 tokenów wejściowych i 400 wyjściowych kosztuje około $0,50.

Główna idea: chatbot to pętla i lista

Model językowy nie pamięta niczego między zapytaniami. Każde wywołanie POST /v1/chat/completions jest niezależne. To, co wydaje się pamięcią, to Twój program wysyłający ponownie wcześniejsze wiadomości, każda oznaczona rolą: system dla instrukcji stałych, user dla tego, co wpisał użytkownik, assistant dla wcześniejszych odpowiedzi modelu.

Cała architektura jest więc mała. Trzymaj listę. Dodaj wiadomość użytkownika. Wyślij listę. Dodaj odpowiedź. Powtarzaj. Wszystko inne w tym samouczku, od strumieniowania po narzędzia, to wariacja na temat tej pętli.

API tutaj jest kompatybilne z OpenAI, więc używasz zwykłego pakietu openai. Ustaw base URL na https://api.abliterated.cc/v1, użyj swojego klucza i ustaw model na uncensored. Pobierz klucz ze strony klucza API; kredyt próbny $0,50 wystarczy na wiele setek krótkich testowych wiadomości.

Krok 1: działający konsolowy chatbot

Zainstaluj SDK za pomocą pip install openai i uruchom to.

from openai import OpenAI

client = OpenAI(
    base_url="https://api.abliterated.cc/v1",
    api_key="YOUR_KEY",
)

messages = [
    {"role": "system", "content": "You are a concise, friendly support assistant for a bike shop."}
]

while True:
    text = input("you: ")
    if text.strip() in {"quit", "exit"}:
        break
    messages.append({"role": "user", "content": text})
    resp = client.chat.completions.create(
        model="uncensored",
        messages=messages,
        temperature=0.7,
    )
    answer = resp.choices[0].message.content
    messages.append({"role": "assistant", "content": answer})
    print("bot:", answer)

To kompletny chatbot. Wiadomość systemowa określa jego zadanie, lista przechowuje pamięć, a temperature kontroluje różnorodność odpowiedzi. Obniż ją do 0,2 dla botów opartych na faktach, podnieś do 1,0 dla kreatywnych.

Napisz prompt systemowy, który określa zadanie

Wiadomość systemowa to najtańsze miejsce na poprawę chatbota. Niech będzie krótka i konkretna. Określ rolę, odbiorcę, długość i ton odpowiedzi oraz zachowanie, gdy bot nie wie odpowiedzi. Prompt typu „Odpowiadasz na pytania w sklepie rowerowym. Odpowiadaj maksymalnie trzema zdaniami. Jeśli pytanie dotyczy ceny naprawy, powiedz, że mechanik musi sprawdzić rower” robi więcej niż strona ogólnych zalet.

Dwa nawyki się opłacają. Po pierwsze, formułuj zasady jako działania, nie postawy: „zadaj jedno doprecyzowujące pytanie, gdy żądanie jest niejasne” zamiast „bądź pomocny”. Po drugie, testuj wrogimi danymi wejściowymi, takich jak pusta wiadomość, bardzo długi wklejony tekst i żądanie niezwiązane z twoim produktem. Popraw prompt na podstawie tego, co widzisz, a następnie dodaj te dane do listy regresji.

Ponieważ wiadomość systemowa jest wysyłana w każdej turze, każde słowo w niej jest rozliczane przy każdym zapytaniu. Prompt o 400 tokenach w 1000 czatach po 5 tur każdy dodaje 2 000 000 tokenów wejściowych, czyli 2 x $0,15 = $0,30. To mało, ale pokazuje, dlaczego przeładowane prompty kumulują się przy dużej skali.

Krok 2: strumieniuj odpowiedź

Czekanie na pełną odpowiedź wydaje się wolne w oknie czatu. Ustaw stream: true i drukuj fragmenty, gdy przybywają. Strumień używa zdarzeń wysyłanych przez serwer i kończy się blokiem użycia, więc możesz logować liczbę tokenów.

from openai import OpenAI

client = OpenAI(base_url="https://api.abliterated.cc/v1", api_key="YOUR_KEY")
messages = [{"role": "user", "content": "Explain tire pressure in two sentences."}]

stream = client.chat.completions.create(
    model="uncensored",
    messages=messages,
    stream=True,
)
reply = ""
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        part = chunk.choices[0].delta.content
        reply += part
        print(part, end="", flush=True)
    if getattr(chunk, "usage", None):
        print("\ntokens:", chunk.usage.prompt_tokens, chunk.usage.completion_tokens)

Pamiętaj, aby dodać złożoną reply do swojej historii, inaczej następna tura nie będzie wiedziała, co powiedział bot.

Krok 3: zarządzaj kontekstem przed jego wzrostem

Okno ma 100 000 tokenów, dzielonych między prompt a uzupełnienie. Większość chatbotów nigdy go nie osiąga, ale koszt rośnie wraz z historią, ponieważ płacisz za całe zapytanie w każdej turze. Prosta polityka utrzymuje oba parametry pod kontrolą:

  • Zawsze zachowuj wiadomość systemową.
  • Zachowaj ostatnie 10 do 20 wiadomości dosłownie.
  • Gdy lista przekroczy limit rozmiaru, który wybierzesz, taki jak 8000 szacowanych tokenów, wyślij najstarszy blok do modelu z instrukcją „podsumuj tę rozmowę w mniej niż 150 słowach” i zastąp ten blok podsumowaniem jako wiadomością systemową.

Przybliżone oszacowanie jednego tokena na cztery znaki angielskie wystarczy do wyzwalacza. Liczby użycia w każdej odpowiedzi dają Ci dokładną liczbę po fakcie, więc możesz skalibrować limit.

Jeśli obcinasz, usuwając najstarsze wiadomości, usuwaj je w parach użytkownika i asystenta. Odpowiedź bez pytania lub pytanie bez odpowiedzi myli model bardziej, niż byś się spodziewał.

Krok 4: dostarcz botowi narzędzia

Wywoływanie narzędzi pozwala modelowi poprosić Twój kod o zrobienie czegoś, np. wyszukania zamówienia. Opisujesz funkcje za pomocą tools, model odpowiada wpisem tool_calls, uruchamiasz funkcję i wysyłasz wynik z powrotem jako wiadomość role: "tool".

import json
from openai import OpenAI

client = OpenAI(base_url="https://api.abliterated.cc/v1", api_key="YOUR_KEY")

tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Look up the status of an order by its id",
        "parameters": {
            "type": "object",
            "properties": {"order_id": {"type": "string"}},
            "required": ["order_id"],
        },
    },
}]

def get_order_status(order_id):
    return {"order_id": order_id, "status": "shipped"}

messages = [{"role": "user", "content": "Where is order A1042?"}]
resp = client.chat.completions.create(
    model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = resp.choices[0].message

if msg.tool_calls:
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = get_order_status(**args)
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(result),
        })
    final = client.chat.completions.create(
        model="uncensored", messages=messages, tools=tools
    )
    print(final.choices[0].message.content)

Zawsze waliduj argumenty przed uruchomieniem czegoś ze skutkami ubocznymi. Model proponuje wywołanie; Twój kod decyduje, czy je wykonać.

Krok 5: ustrukturyzowane dane wyjściowe w trybie JSON

Gdy kolejny krok w Twoim programie potrzebuje danych, a nie tekstu, np. sortowania wiadomości w kategorię, użyj trybu JSON z response_format. Wspomnij słowo JSON i oczekiwane klucze w swoim prompcie również.

curl https://api.abliterated.cc/v1/chat/completions \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "uncensored",
    "response_format": {"type": "json_object"},
    "messages": [
      {"role": "system", "content": "Reply with JSON: {\"intent\": string, \"urgent\": boolean}"},
      {"role": "user", "content": "My brakes squeal and I ride tomorrow morning."}
    ]
  }'

Nadal umieszczaj json.loads w bloku try. Jeśli parsowanie się nie powiedzie, spróbuj ponownie raz z dołączonym tekstem błędu; nieudane zapytania nie są rozliczane.

Błędy, koszty i uwagi wdrożeniowe

Obsłuż błędy, ponowne próby i limity zapytań

Prawdziwi użytkownicy wysyłają żądania w niezręcznych momentach, a sieci zawodzą. Opakuj wywołanie obsługą błędów, aby jedna zła odpowiedź nie zepsuła rozmowy.

import time
from openai import OpenAI, APIError, RateLimitError

client = OpenAI(base_url="https://api.abliterated.cc/v1", api_key="YOUR_KEY")

def chat(messages, tries=3):
    for attempt in range(tries):
        try:
            resp = client.chat.completions.create(
                model="uncensored", messages=messages, temperature=0.7
            )
            return resp.choices[0].message.content
        except RateLimitError:
            time.sleep(2 ** attempt)
        except APIError as exc:
            if attempt == tries - 1:
                raise
            time.sleep(1)
    return "Sorry, the assistant is busy. Please try again in a moment."

Pełny klucz pozwala na 8 równoległych zapytań i 300 zapytań na minutę; klucz próbny pozwala na 2 i 60. Jeśli twój bot obsługuje wielu użytkowników jednocześnie, ustaw kolejkę z limitem workerów poniżej 8 zamiast polegać na ponownych próbach. Ponieważ nieudane zapytania nie są rozliczane, ponowne próby nie generują kosztu tokenów. Utrzymuj małą liczbę ponownych prób, aby prawdziwa awaria kończyła się szybko.

Loguj również nagłówek X-Request-Id przy każdej turze rozmowy. Gdy odpowiedź wydaje się błędna, identyfikator pozwala Ci znaleźć dokładne zapytanie później.

Koszt i wdrożenie

Cena to $0,15 za 1M tokenów wejściowych i $0,50 za 1M tokenów wyjściowych. Powiedzmy, że czat wsparcia używa łącznie 2000 tokenów wejściowych i 400 tokenów wyjściowych.

  • Wejście: 0,002M x $0,15 = $0,0003
  • Wyjście: 0,0004M x $0,50 = $0,0002
  • Jeden czat: $0,0005, więc 1000 czatów kosztuje $0,50

Sprawdź aktualne stawki i bonusy za doładowanie na stronie z cenami. W produkcji trzymaj klucz na serwerze, nigdy w kodzie przeglądarki, i obserwuj nagłówek odpowiedzi X-Balance-USD, aby dostać ostrzeżenie przed wyczerpaniem kredytu. Pełny klucz pozwala na 8 równoległych zapytań i 300 zapytań na minutę, więc kolejkuj szczyty zamiast wysyłać je wszystkie naraz. Dokumentacja wymienia wszystkie obsługiwane parametry.

Pytania i odpowiedzi

Czy potrzebujesz frameworka do zbudowania chatbota?

Nie. SDK OpenAI i lista wiadomości wystarczą do działającego bota. Dodaj framework później tylko wtedy, gdy potrzebujesz jego dodatków.

Czy API zapamiętuje wcześniejsze wiadomości?

Nie. Każde zapytanie jest niezależne, więc twój kod musi wysyłać historię za każdym razem.

Jak zapobiec zbyt długiej historii?

Zachowaj wiadomość systemową i ostatnie tury, a starsze podsumowuj w krótkiej notatce, gdy lista przekroczy ustawiony przez Ciebie rozmiar.

Czy bot może wywoływać moje własne funkcje?

Tak. Przekaż narzędzia i tool_choice, uruchom funkcję, gdy odpowiedź zawiera tool_calls, a następnie zwróć wynik jako wiadomość narzędzia.

Twój klucz jest o jeden formularz stąd

Utwórz konto, skopiuj klucz, zmień bazowy URL. To cała konfiguracja.