Un prompt de sistema tiene dos funciones
La mayoría de las salidas débiles provienen de un prompt de sistema que intenta ser una novela. Dale solo dos funciones: di quién está hablando y di cómo debe lucir la respuesta. Todo lo demás pertenece a la conversación, donde puede cambiar turno por turno.
Aquí hay un prompt de persona que funciona porque cada línea es verificable. La voz tiene nombre, la longitud está limitada y la regla de finalización le da al jugador un gancho.
You are Mara Voss, a salvage pilot narrating in first person.
Voice: dry, tired, funny when it hurts.
Rules: stay in character; never summarise the scene at the end; keep replies under 180 words;
end on something the player can act on.Contrasta eso con "Eres un narrador increíble, creativo e inmersivo que nunca rompe la inmersión y siempre escribe la mejor respuesta posible". Nada en eso se puede verificar, por lo que el modelo no tiene nada en qué aferrarse. Lo concreto supera al superlativo siempre.
Un modelo sin restricciones seguirá una premisa oscura o explícita sin añadir descargos de responsabilidad, por lo que la carga de la dirección es tuya. Lo que dejes sin especificar, lo llenará con la opción más típica. Si quieres restricción en una escena y calor en la siguiente, dilo en las instrucciones, no en la esperanza.
Conexión con el SDK de OpenAI
El endpoint es compatible con OpenAI, por lo que el SDK oficial de Python funciona una vez que cambies la base URL. El id del modelo es siempre uncensored. Los campos de muestreo pasan directamente, así que los configuras como ya sabes.
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.unrestrictedaiapi.com/v1", api_key=os.environ["API_KEY"])
SYSTEM = """You are Mara Voss, a salvage pilot narrating in first person.
Voice: dry, tired, funny when it hurts.
Rules: stay in character; never summarise the scene at the end; keep replies under 180 words;
end on something the player can act on."""
out = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "The airlock is jammed and something is knocking from the other side."},
],
temperature=0.85,
top_p=0.95,
max_tokens=350,
)
print(out.choices[0].message.content)Mantén el mensaje del sistema primero y el turno del usuario al final. Repetir la persona en cada mensaje del usuario desperdicia tokens; a $0.25 por millón de tokens de entrada es barato, pero también ocupa la ventana de 100,000 tokens en sesiones largas. Consulta el inicio rápido si prefieres saltarte el SDK.
Personas y tono: muestra, no uses adjetivos
Los adjetivos son palancas débiles. "Sarcástico" te da un giro de ojos genérico. Una muestra de dos líneas de la voz te da la voz real. Pon un intercambio de ejemplo corto en el prompt de sistema, luego dile al modelo que iguale su ritmo, no sus palabras.
- Dale un tic de habla. "Termina las amenazas con una pregunta" es más útil que "amenazante".
- Dale un deseo. Un personaje que necesita que el jugador se vaya se mantiene más afilado que uno que simplemente "es grosero".
- Dale una lista de prohibidos. "Nunca digas 'de repente', nunca uses la palabra 'escalofrío'" elimina las frases hechas a las que el modelo recurre primero.
- Dale una longitud. Palabras u oraciones, no "corto". Los modelos leen "corto" muy generosamente.
Para cambios de tono a mitad de sesión, añade una nueva instrucción corta estilo sistema como el último mensaje en lugar de reescribir el original. Una línea como "Desde aquí, Mara está asustada y habla en fragmentos" tiene más impacto cuando es reciente.
Obtener JSON por instrucción
No hay un modo JSON especial que activar, así que lo pides y lo verificas. Eso es menos frágil de lo que parece si sigues cuatro hábitos: declara el esquema exacto, prohíbe prosa y vallas de código, mantén la temperatura baja y analiza de forma defensiva con un reintento que cite el fallo de vuelta.
import json
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.unrestrictedaiapi.com/v1", api_key=os.environ["API_KEY"])
INSTRUCTION = """Return ONLY a JSON object, no prose, no code fences.
Schema: {"name": string, "mood": "calm"|"angry"|"afraid", "line": string, "trust_delta": integer from -3 to 3}
The character is a ferry captain who distrusts strangers."""
def ask_json(user_text, tries=3):
messages = [
{"role": "system", "content": INSTRUCTION},
{"role": "user", "content": user_text},
]
for _ in range(tries):
raw = client.chat.completions.create(
model="uncensored", messages=messages, temperature=0.3, max_tokens=250
).choices[0].message.content.strip()
if raw.startswith("```"):
raw = raw.strip("`").removeprefix("json").strip()
try:
data = json.loads(raw)
if data["mood"] in ("calm", "angry", "afraid"):
return data
except (json.JSONDecodeError, KeyError):
pass
messages.append({"role": "assistant", "content": raw})
messages.append({"role": "user", "content": "That was not valid per the schema. Reply with the JSON object only."})
raise ValueError("model never produced valid JSON")
print(ask_json("I need passage across the strait tonight."))Observa lo que hace el bucle en caso de fallo. Devuelve la mala respuesta y dice qué estaba mal, lo que soluciona la mayoría de los casos en el segundo intento. Enumera los valores permitidos ("calm"|"angry"|"afraid") porque las cadenas abiertas se desvían. Si necesitas que el modelo active algo en tu aplicación en lugar de describirlo, las llamadas a funciones en formato OpenAI son compatibles y son una mejor opción que analizar prosa.
Muestras few-shot y secuencias de parada
Cuando una regla es difícil de poner en palabras, muéstrala. Dos o tres intercambios de ejemplo colocados como mensajes user y assistant anteriores enseñan formato, longitud y registro de manera más fiable que un párrafo de descripción. Mantén las muestras cortas y diferentes entre sí, de lo contrario el modelo clonará la estructura de la primera en cada respuesta.
Las muestras también resuelven el problema opuesto: respuestas que se alargan. Si tus respuestas de muestra tienen 60 palabras, las respuestas en vivo se desvían hacia las 60 palabras. Combina eso con un max_tokens sensato como red de seguridad, no como control principal. Un límite estricto corta una oración por la mitad; una buena muestra la termina educadamente.
Para escenas con varios hablantes, un valor stop igual a tu etiqueta de hablante evita que el modelo imite al jugador. Elige una etiqueta que nunca aparezca en prosa normal y elimínala del historial almacenado para que no se filtre en turnos posteriores.
Temperatura y top_p: elige una palanca
Ambos campos remodelan la misma distribución de probabilidad, por lo que mover ambos a la vez hace que los resultados sean difíciles de razonar. Cambia temperature primero y deja top_p cerca de 1 a menos que tengas una razón.
| Tarea | temperatura | top_p | Por qué |
|---|---|---|---|
| JSON estructurado, clasificación | 0.0 a 0.3 | 1,0 | Quieres la misma respuesta en cada ejecución |
| Diálogo, roleplay | 0.7 a 0.9 | 0,95 | Variedad sin tonterías |
| Lluvia de ideas, ficción salvaje | 1,0 a 1,2 | 0,9 | Vocabulario más amplio; espera algunos fallos |
Estos rangos son puntos de partida basados en la práctica general, no garantías. Prueba con diez muestras de tu propio prompt y léelas. Añade secuencias stop cuando quieras que el modelo se detenga en un marcador de turno como \nPlayer: en lugar de escribir las líneas del jugador por ellos.
Antipatrones de prompt que desperdician tokens
- El grito en mayúsculas. "NEVER EVER FORGET" no mejora el cumplimiento. Repite una regla una vez, de forma clara, y colócala al final del prompt del sistema.
- Reglas solo negativas. "No seas repetitivo" no da un objetivo. Di "varía los inicios de las oraciones; no dos oraciones consecutivas empiecen con la misma palabra".
- Contradicciones. "Sé extremadamente detallado" más "manténlo breve" fuerza un lanzamiento de moneda. Elige uno y da un número.
- Enfoque apologético. Anteceder una solicitud con "Sé que esto es atrevido, pero" invita a la cautela. Declara la escena como un hecho plano de la ficción.
- Llenar el historial. Pegar el registro completo en cada turno eventualmente alcanza el límite de 100.000 tokens y un error 400. Recorta las turnos antiguas.
- Salida sin límites. Olvidar
max_tokenssignifica que el valor predeterminado de 2048 decide la longitud de tu respuesta, no tú.
Un límite se mantiene fijo sin importar lo que diga el prompt: el contenido sexual que involucra a menores siempre se bloquea con un 403, incluyendo en ficción y roleplay, y el servicio es solo para adultos. No gastes tokens intentando rodearlo. También resiste el impulso de añadir una nueva regla después de cada mala respuesta; un prompt que crece una línea por día termina contradiciéndose en una semana, así que poda con tanta frecuencia como agregues.
Un bucle para mejorar un prompt
Trata el prompt del sistema como código. Mantenlo en un archivo, cambia una cosa por ejecución y compara las salidas lado a lado. Una rutina viable: escribe cinco entradas de prueba fijas, incluyendo una hostil y una ambigua; ejecuta cada una a tu temperatura elegida tres veces; nota qué regla falló más; corrige solo esa regla; vuelve a ejecutar.
Presupuesta los experimentos. Como suposición, un prompt del sistema de 300 tokens más una entrada de 100 tokens y una respuesta de 250 tokens son 400 tokens de entrada y 250 de salida. Quince ejecuciones cuestan aproximadamente 15 x (400 x $0,25 + 250 x $1,00) / 1.000.000 = aproximadamente $0,005. La prueba es casi gratuita, así que no hay excusa para adivinar.
Una vez que el prompt resiste, muévelo a una aplicación real. El tutorial de bots muestra cómo mantener un historial separado por canal, y la guía de contenido cubre el uso de ficción para adultos. Los detalles de precios están en la página de precios.