Construye un chatbot con una API de LLM: Tutorial en Python
Los modelos Abliterated son modelos de lenguaje grandes donde se han eliminado los mecanismos que imponen las negativas de seguridad, lo que permite al modelo responder preguntas controversiales, para adultos o de nicho sin activar un filtro de contenido. Este enfoque da a los desarrolladores control total sobre la voz y el corte de conocimiento del modelo, lo cual es especialmente valioso para programación, roleplay y escritura creativa donde las barreras estándar podrían bloquear salidas útiles.
Actualizado

Puntos clave
- La API es stateless, por lo que tu código es dueño del historial de la conversación y lo envía en cada petición.
- El streaming, las llamadas a funciones y el modo JSON usan los parámetros estándar de OpenAI.
- Recorta o resume el historial antes de que se acerque a la ventana de 100.000 tokens.
- 1.000 chats de 2.000 tokens de entrada y 400 de salida cuestan aproximadamente $0,50.
La idea central: un chatbot es un bucle y una lista
Un modelo de lenguaje no recuerda nada entre peticiones. Cada llamada a POST /v1/chat/completions es independiente. Lo que parece memoria es tu programa reenviando los mensajes anteriores, cada uno etiquetado con un rol: system para instrucciones fijas, user para lo que escribió la persona, assistant para respuestas anteriores del modelo.
Así que toda la arquitectura es pequeña. Mantén una lista. Añade el mensaje del usuario. Envía la lista. Añade la respuesta. Repite. Todo lo demás en este tutorial, desde streaming hasta herramientas, es una variación de ese bucle.
La API aquí es compatible con OpenAI, por lo que usas el paquete regular openai. Establece la base URL en https://api.abliterated.cc/v1, usa tu clave y establece el modelo en uncensored. Obtén una clave desde la página de claves de API; el crédito de prueba de $0,50 es suficiente para cientos de mensajes de prueba cortos.
Paso 1: un chatbot de consola funcional
Instala el SDK con pip install openai y ejecuta esto.
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)
Eso es un chatbot completo. El mensaje de sistema establece su trabajo, la lista lleva la memoria y temperature controla qué tan variadas son las respuestas. Bájala hacia 0,2 para bots de soporte basados en hechos, súbela hacia 1,0 para los creativos.
Escribe un prompt del sistema que defina la tarea
El mensaje del sistema es el lugar más barato para mejorar un chatbot. Mantenlo corto y específico. Nombra el rol, la audiencia, la longitud y el tono de las respuestas, y qué hacer cuando el bot no sabe. Un prompt como "Respondes preguntas para una tienda de bicicletas. Responde en máximo tres oraciones. Si la pregunta es sobre el precio de una reparación, di que un mecánico debe inspeccionar la bicicleta" hace más que una página de virtudes generales.
Dos hábitos dan resultados. Primero, pon reglas en forma de acciones, no de actitudes: "haz una pregunta de aclaración cuando la petición sea ambigua" en lugar de "sé útil". Segundo, prueba con entradas hostiles, como un mensaje vacío, un pegado muy largo y una petición que no tenga nada que ver con tu producto. Corrige el prompt según lo que veas, luego mantén esas entradas como una lista de regresión.
Como el mensaje de sistema se reenvía en cada turno, cada palabra en él se cobra en cada petición. Un prompt de 400 tokens en 1.000 chats de 5 turnos cada uno añade 2.000.000 tokens de entrada, o 2 x $0,15 = $0,30. Eso es poco, pero muestra por qué los prompts inflados se acumulan a volumen.
Paso 2: transmite la respuesta
Esperar una respuesta completa se siente lento en una ventana de chat. Establece stream: true e imprime fragmentos a medida que llegan. El stream usa server-sent events y termina con un bloque de usage, por lo que puedes registrar los conteos de tokens.
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)
Recuerda añadir el reply ensamblado a tu historial, o el siguiente turno no tendrá idea de lo que dijo el bot.
Paso 3: gestiona el contexto antes de que crezca
La ventana es de 100.000 tokens, compartida entre prompt y completion. La mayoría de los chatbots nunca se acercan a ella, pero el costo crece con el historial porque pagas por todo el prompt en cada turno. Una política simple mantiene ambos bajo control:
- Mantén siempre el mensaje del sistema.
- Mantén los últimos 10 a 20 mensajes tal cual.
- Cuando la lista supera un límite de tamaño que elijas, como 8.000 tokens estimados, envía el bloque más antiguo al modelo con la instrucción "resume esta conversación en menos de 150 palabras" y reemplaza ese bloque con el resumen como mensaje de sistema.
Una estimación aproximada de un token por cada cuatro caracteres en inglés es suficiente para el activador. Los números de usage en cada respuesta te dan la cifra exacta después del hecho, por lo que puedes calibrar el límite.
Si truncas eliminando los mensajes más antiguos, elimínalos en pares de user y assistant. Una respuesta sin pregunta, o una pregunta sin respuesta, confunde al modelo más de lo que esperarías.
Paso 4: dale herramientas al bot
Las llamadas a funciones permiten que el modelo pida a tu código que haga algo, como buscar un pedido. Describes funciones con tools, el modelo responde con una entrada tool_calls, ejecutas la función y envías el resultado de vuelta como un mensaje 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)
Valida siempre los argumentos antes de ejecutar algo con efectos secundarios. El modelo propone una llamada; tu código decide si ejecutarla.
Paso 5: salida estructurada con modo JSON
Cuando el siguiente paso en tu programa necesita datos en lugar de texto, como clasificar un mensaje en una categoría, usa el modo JSON con response_format. Menciona la palabra JSON y las claves esperadas en tu prompt también.
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."}
]
}'
Aun así envuelve json.loads en un bloque try. Si el análisis falla, reintenta una vez con el texto de error añadido; las peticiones falladas no se cobran.
Errores, costos y notas de despliegue
Maneja errores, reintentos y límites de peticiones
Los usuarios reales envían peticiones en momentos incómodos y las redes fallan. Envuelve la llamada para que una mala respuesta no haga fallar la conversación.
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 clave completa permite 8 peticiones simultáneas y 300 peticiones por minuto; la clave de prueba permite 2 y 60. Si tu bot atiende a muchos usuarios a la vez, pon las peticiones en una cola con un límite de workers por debajo de 8 en lugar de confiar en reintentos. Como las peticiones fallidas no se cobran, reintentar no tiene costo de token. Mantén el conteo de reintentos pequeño para que un corte real falle rápido.
También registra el header X-Request-Id con cada turno de conversación. Cuando una respuesta parezca incorrecta, el id te permite encontrar la petición exacta más tarde.
Costos y despliegue
El precio es $0,15 por 1M de tokens de entrada y $0,50 por 1M de tokens de salida. Digamos que un chat de soporte usa 2.000 tokens de entrada en total y 400 tokens de salida.
- Entrada: 0,002M x $0,15 = $0,0003
- Salida: 0,0004M x $0,50 = $0,0002
- Un chat: $0,0005, por lo que 1.000 chats cuestan $0,50
Consulta las tarifas actuales y los bonos de recarga en la página de precios. Para producción, mantén la clave en tu servidor, nunca en el código del navegador, y vigila la cabecera de respuesta X-Balance-USD para alertarte antes de que se agote el crédito. Una clave completa permite 8 peticiones simultáneas y 300 peticiones por minuto, así que pon en cola los picos en lugar de enviarlos todos a la vez. La documentación enumera todos los parámetros compatibles.
Más guías
Preguntas y respuestas
¿Necesito un framework para construir un chatbot?
No. El SDK de OpenAI y una lista de mensajes son suficientes para un bot funcional. Añade un framework después solo si necesitas sus extras.
¿La API recuerda los mensajes anteriores?
No. Cada petición es independiente, por lo que tu código debe reenviar el historial cada vez.
¿Cómo evito que el historial sea demasiado largo?
Mantén el mensaje del sistema y los turnos recientes, y resume los más antiguos en una nota breve una vez que la lista supere un tamaño que tú establezcas.
¿Puede el bot llamar a mis propias funciones?
Sí. Pasa tools y tool_choice, ejecuta la función cuando la respuesta contenga tool_calls, y devuelve el resultado como un mensaje tool.
Tu clave está a un formulario de distancia
Crea una cuenta, copia la clave, cambia la URL base. Esa es toda la configuración.