IT ▾
Ottieni la chiave API

Costruire un Chatbot da un'API LLM: Tutorial Python

I modelli Abliterated sono modelli linguistici di grandi dimensioni in cui i meccanismi che impongono i rifiuti di sicurezza sono stati rimossi, consentendo al modello di rispondere a domande controverse, per adulti o di nicchia senza attivare un filtro sui contenuti. Questo approccio offre agli sviluppatori il controllo completo sulla voce e sul cutoff di conoscenza del modello, il che è particolarmente utile per il coding, il roleplay e la scrittura creativa dove i guardrail standard potrebbero bloccare output utili.

Blocchi di messaggi di chat che si muovono in un loop verso un cubo centrale, illustrando il ciclo di conversazione di un chatbot

Punti chiave

  • L'API è stateless, quindi il tuo codice gestisce la cronologia delle conversazioni e la invia in ogni richiesta.
  • Streaming, chiamata di funzioni e modalità JSON usano tutti i parametri standard OpenAI.
  • Riduci o riassumi la cronologia prima che si avvicini alla finestra di 100.000 token.
  • 1.000 chat da 2.000 token di input e 400 di output costano circa $0,50.

L'idea di base: un chatbot è un loop e una lista

Un modello linguistico non ricorda nulla tra una richiesta e l'altra. Ogni chiamata a POST /v1/chat/completions è indipendente. Ciò che sembra memoria è il tuo programma che invia di nuovo i messaggi precedenti, ciascuno contrassegnato con un ruolo: system per le istruzioni di sistema, user per ciò che ha digitato l'utente, assistant per le risposte precedenti del modello.

Quindi l'architettura è molto semplice. Tieni una lista. Aggiungi il messaggio dell'utente. Invia la lista. Aggiungi la risposta. Ripeti. Tutto il resto in questo tutorial, dallo streaming agli strumenti, è una variazione di questo loop.

L'API qui è compatibile con OpenAI, quindi usi il pacchetto openai standard. Imposta la base URL su https://api.abliterated.cc/v1, usa la tua chiave e imposta il modello su uncensored. Ottieni una chiave dalla pagina delle chiavi API; il credito di prova da $0,50 è sufficiente per diverse centinaia di messaggi di test brevi.

Passo 1: un chatbot console funzionante

Installa l'SDK con pip install openai ed esegui questo.

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)

Questo è un chatbot completo. Il messaggio di sistema ne definisce il compito, la lista gestisce la memoria e temperature controlla la varietà delle risposte. Abbassala verso 0,2 per bot di supporto basati sui fatti, alzala verso 1,0 per quelli creativi.

Scrivi un prompt di sistema che definisca il compito

Il messaggio di sistema è il modo più economico per migliorare un chatbot. Tienilo breve e specifico. Indica il ruolo, il pubblico, la lunghezza e il tono delle risposte e cosa fare quando il bot non sa la risposta. Un prompt come "Rispondi alle domande per un negozio di biciclette. Rispondi al massimo tre frasi. Se la domanda riguarda il prezzo di una riparazione, dì che un meccanico deve ispezionare la bici" fa più di una pagina di virtù generali.

Due abitudini ripagano. Primo, metti le regole sotto forma di azioni, non di atteggiamenti: "fai una domanda chiarificatrice quando la richiesta è ambigua" invece di "sii utile". Secondo, testa con input ostili, come un messaggio vuoto, un testo incollato molto lungo e una richiesta che non c'entra con il tuo prodotto. Correggi il prompt in base a ciò che vedi, poi tieni quegli input come lista di regressione.

Poiché il messaggio di sistema viene inviato di nuovo ogni turno, ogni parola in esso è fatturata in ogni richiesta. Un prompt da 400 token in 1.000 chat da 5 turni ciascuna aggiunge 2.000.000 token di input, o 2 x $0,15 = $0,30. È una cifra piccola, ma mostra perché prompt gonfiati si accumulano su larga scala.

Passo 2: stream della risposta

Aspettare una risposta completa sembra lento in una finestra di chat. Imposta stream: true e stampa i pezzi mentre arrivano. Lo stream usa eventi server-sent e termina con un blocco di utilizzo, quindi puoi registrare i conteggi dei token.

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)

Ricorda di aggiungere la reply assemblata alla tua cronologia, altrimenti il turno successivo non saprà cosa ha detto il bot.

Passo 3: gestisci il contesto prima che cresca

La finestra è di 100.000 token, condivisa tra prompt e completamento. La maggior parte dei chatbot non ci arriva mai vicino, ma il costo cresce con la cronologia perché paghi per l'intero prompt in ogni turno. Una politica semplice tiene tutto sotto controllo:

  • Mantieni sempre il messaggio di sistema.
  • Mantieni gli ultimi 10-20 messaggi così come sono.
  • Quando la lista supera un limite di dimensione che scegli, come 8.000 token stimati, invia il blocco più vecchio al modello con l'istruzione "riassumi questa conversazione in meno di 150 parole" e sostituisci quel blocco con il riassunto come messaggio di sistema.

Una stima approssimativa di un token ogni quattro caratteri inglesi è sufficiente per il trigger. I numeri di utilizzo in ogni risposta ti danno la cifra esatta a posteriori, così puoi calibrare il limite.

Se tronchi eliminando i messaggi più vecchi, eliminali in coppie user e assistant. Una risposta senza domanda, o una domanda senza risposta, confonde il modello più di quanto ti aspetti.

Passo 4: fornisci strumenti al bot

La chiamata di funzioni permette al modello di chiedere al tuo codice di fare qualcosa, come cercare un ordine. Descrivi le funzioni con tools, il modello risponde con una voce tool_calls, esegui la funzione e invii il risultato indietro come messaggio 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)

Convalida sempre gli argomenti prima di eseguire qualsiasi cosa con effetti collaterali. Il modello propone una chiamata; il tuo codice decide se eseguirla.

Passo 5: output strutturato con modalità JSON

Quando il passo successivo nel tuo programma ha bisogno di dati invece che di testo, come ordinare un messaggio in una categoria, usa la modalità JSON con response_format. Menziona la parola JSON e le chiavi previste nel tuo prompt.

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."}
    ]
  }'

Avvolgi comunque json.loads in un blocco try. Se l'analisi fallisce, riprova una volta con il testo di errore allegato; le richieste fallite non vengono addebitate.

Note su errori, costi e deployment

Gestisci errori, retry e limiti di richiesta

Gli utenti reali inviano richieste in momenti scomodi e le reti falliscono. Avvolgi la chiamata in modo che una risposta errata non faccia crashare la conversazione.

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."

Una chiave completa permette 8 richieste concorrenti e 300 richieste al minuto; la chiave di prova ne permette 2 e 60. Se il tuo bot serve molti utenti contemporaneamente, metti le richieste in una coda con un limite di worker inferiore a 8 invece di affidarti ai retry. Poiché le richieste fallite non vengono addebitate, il retry non ha costo in token. Tieni il conteggio dei retry piccolo in modo che un guasto reale fallisca rapidamente.

Registra anche l'intestazione X-Request-Id con ogni turno di conversazione. Quando una risposta sembra sbagliata, l'id ti permette di trovare la richiesta esatta più tardi.

Costi e deployment

Il prezzo è $0,15 per 1M di token di input e $0,50 per 1M di token di output. Supponiamo che una chat di supporto usi 2.000 token di input in totale e 400 di output.

  • Input: 0,002M x $0,15 = $0,0003
  • Output: 0,0004M x $0,50 = $0,0002
  • Una chat: $0,0005, quindi 1.000 chat costano $0,50

Controlla i tassi attuali e i bonus di ricarica nella pagina dei prezzi. Per la produzione, tieni la chiave sul tuo server, mai nel codice del browser, e monitora l'intestazione di risposta X-Balance-USD per avvisarti prima che il credito si esaurisca. Una chiave completa permette 8 richieste concorrenti e 300 richieste al minuto, quindi accoda i picchi invece di inviarli tutti insieme. La documentazione elenca tutti i parametri supportati.

Domande e risposte

Serve un framework per costruire un chatbot?

No. L'SDK OpenAI e un elenco di messaggi bastano per un bot funzionante. Aggiungi un framework solo se ti servono le sue funzionalità extra.

L'API ricorda i messaggi precedenti?

No. Ogni richiesta è indipendente, quindi il tuo codice deve inviare di nuovo la cronologia ogni volta.

Come faccio a evitare che la cronologia diventi troppo lunga?

Mantieni il messaggio di sistema e gli scambi recenti, e riassumi quelli più vecchi in una breve nota una volta che la lista supera una dimensione che imposti tu.

Il bot può chiamare le mie funzioni?

Sì. Passa gli strumenti e tool_choice, esegui la funzione quando la risposta contiene tool_calls e restituisci il risultato come messaggio tool.

La tua chiave è a un modulo di distanza

Crea un account, copia la chiave, modifica l'URL di base. È tutta la configurazione.