Ein System-Prompt hat zwei Aufgaben
Die meisten schwachen Ergebnisse stammen von einem System-Prompt, der wie ein Roman wirken will. Weise ihm nur zwei Aufgaben zu: sage wer spricht und beschreibe wie die Antwort aussehen muss. Alles andere gehört in den Conversation-Verlauf, wo es von Turn zu Turn variieren kann.
Hier ist ein Persona-Prompt, der funktioniert, weil jede Zeile überprüfbar ist. Die Stimme ist benannt, die Länge ist begrenzt und die Endregel gibt dem Spieler einen Anknüpfungspunkt.
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.Stell dir das vor: "Du bist ein erstaunlicher, kreativer, immersiver Geschichtenerzähler, der die Immersion nie bricht und immer die bestmögliche Antwort schreibt." Nichts daran ist überprüfbar, also hat das Modell nichts, woran es sich halten kann. Konkret schlägt Superlativ immer.
Ein unzensiertes Modell folgt einer düsteren oder expliziten Prämisse ohne Disclaimer, die Verantwortung für die Richtung liegt also bei dir. Was du unbestimmt lässt, füllt es mit der typischsten Wahl. Wenn du in einer Szene Zurückhaltung und in der nächsten Wärme willst, sag es in den Anweisungen, nicht in der Hoffnung.
Anbindung mit dem OpenAI SDK
Der Endpunkt ist OpenAI-kompatibel, daher funktioniert das offizielle Python SDK, sobald du die Base URL änderst. Die Modell-ID ist immer uncensored. Sampling-Felder gehen direkt durch, also stellst du sie so ein, wie du es bereits kennst.
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)Halte die Systemnachricht an erster Stelle und die Benutzerantwort an letzter Stelle. Die Persona in jeder Benutzernachricht zu wiederholen, verschwendet Token; bei $0,25 pro Million Input-Token ist das zwar günstig, aber es verdrängt im Kontextfenster mit 100.000 Token in langen Sessions. Sieh dir die Schnellstartanleitung an, wenn du das SDK überspringen möchtest.
Personas und Tonfall: Zeigen, nicht beschreiben
Adjektive sind schwache Hebel. "Sarkastisch" liefert dir eine generische Augenroll. Ein zweizeiliges Beispiel der Stimme liefert dir die tatsächliche Stimme. Setze einen kurzen Beispiel-Austausch in den System-Prompt und sage dem Modell, es soll den Rhythmus matchen, nicht die Wörter kopieren.
- Gib ein Sprachstottern. „Beendet Drohungen mit einer Frage“ ist nützlicher als „bedrohlich“.
- Gib ein Ziel. Ein Charakter, der will, dass der Spieler geht, bleibt schärfer als einer, der einfach nur „unhöflich ist“.
- Gib eine Verbotsliste. „Sag nie ‚plötzlich‘, verwende nie das Wort ‚Zittern‘“ entfernt die Standardphrasen, auf die das Modell zuerst zurückgreift.
- Gib eine Länge vor. Wörter oder Sätze, nicht „kurz“. Modelle lesen „kurz“ sehr großzügig.
Für Tonfallwechsel während der Session hänge eine neue kurze System-Anweisung als neueste Nachricht an, statt die ursprüngliche zu überschreiben. Ein Satz wie "Ab hier ist Mara ängstlich und spricht in Fragmenten" wirkt stärker, wenn er frisch ist.
JSON per Anweisung erhalten
Es gibt keinen speziellen JSON-Modus zum Einschalten, also fordere ihn an und überprüfe ihn. Das ist weniger fehleranfällig, als es klingt, wenn du vier Gewohnheiten befolgst: Gib das exakte Schema an, verbiete Fließtext und Code-Fences, halte die Temperatur niedrig und parse defensiv mit einem Retry, der den Fehler zurückmeldet.
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."))Beobachte, was die Schleife im Fehlerfall macht. Sie speist die falsche Antwort zurück und sagt, was falsch war, was die meisten Fälle beim zweiten Versuch behebt. Enumeriere erlaubte Werte ("calm"|"angry"|"afraid"), weil offene Strings abdriften. Wenn du möchtest, dass das Modell etwas in deiner App auslöst statt es zu beschreiben, werden Tool Calls im OpenAI-Format unterstützt und sind besser geeignet als das Parsen von Fließtext.
Few-Shot-Beispiele und Stop-Sequenzen
Wenn eine Regel schwer in Worte zu fassen ist, zeige sie. Zwei oder drei Beispiel-Austausche, die als frühere user- und assistant-Nachrichten eingefügt werden, vermitteln Format, Länge und Register zuverlässiger als ein Beschreibungstext. Halte die Samples kurz und unterschiedlich voneinander, sonst klont das Modell die Struktur der ersten Antwort in jede Antwort.
Samples lösen auch das umgekehrte Problem: zu lange Antworten. Wenn deine Sample-Antworten 60 Wörter lang sind, tendieren Live-Antworten dazu, sich auf 60 Wörter zu orientieren. Kombiniere das mit einem sinnvollen max_tokens als Sicherheitsnetz, nicht als primäre Steuerung. Eine harte Grenze schneidet einen Satz in zwei Hälften; eine gute Sample beendet ihn höflich.
Bei Szenen mit mehreren Sprechern verhindert ein stop-Wert, der deinem Sprechernamen entspricht, dass das Modell die Stimme des Spielers imitiert. Wähle einen Namen, der im normalen Text nicht vorkommt, und entferne ihn aus dem gespeicherten Verlauf, damit er nicht in nachfolgende Nachrichten durchsickert.
Temperatur und top_p: Einen Hebel wählen
Beide Felder formen dieselbe Wahrscheinlichkeitsverteilung, daher sind Ergebnisse schwer zu durchschauen, wenn du beide gleichzeitig änderst. Ändere zuerst temperature und lasse top_p nahe 1, es sei denn, du hast einen Grund.
| Aufgabe | Temperatur | top_p | Warum |
|---|---|---|---|
| Strukturiertes JSON, Klassifizierung | 0,0 bis 0,3 | 1,0 | Du willst jedes Mal dieselbe Antwort |
| Dialog, Rollenspiel | 0,7 bis 0,9 | 0,95 | Vielfalt ohne Unsinn |
| Brainstorming, wilde Fiktion | 1,0 bis 1,2 | 0,9 | Größerer Wortschatz; rechne mit einigen Fehltritten |
Diese Bereiche sind Ausgangspunkte aus der allgemeinen Praxis, keine Garantien. Teste mit zehn eigenen Prompts und lies die Ergebnisse. Füge stop-Sequenzen hinzu, wenn du das Modell an einem Markierungspunkt wie \nPlayer: stoppen willst, statt die Zeilen des Spielers für ihn zu schreiben.
Prompt-Anti-Patterns, die Token verschwenden
- Das Schreien in Großbuchstaben. „VERGESSE ES NIEMMERS“ erhöht die Compliance nicht. Wiederhole eine Regel einmal, klar und deutlich, und verschiebe sie ans Ende des System-Prompts.
- Nur negative Regeln. "Sei nicht repetitiv" gibt kein Ziel vor. Schreibe stattdessen: "Varier die Satzanfänge; kein zweiter Satz beginnt mit demselben Wort".
- Widersprüche. "Sei extrem detailliert" plus "halte es kurz" zwingt zu einem Zufallsgenerator. Wähle eine Option und gib eine Zahl vor.
- Entschuldigungs-Framing. Eine Anfrage mit "Ich weiß, das ist gewagt, aber" einzuleiten, lädt zu Abschwächungen ein. Beschreibe die Szene als reine Tatsache der Fiktion.
- Das Überladen des Verlaufs. Das Einfügen des gesamten Protokolls bei jeder Nachricht führt schließlich zum 100.000-Token-Limit und zu einem 400-Fehler. Kürze alte Nachrichten.
- Unbegrenzte Ausgabe. Das Vergessen von
max_tokensbedeutet, dass der 2048-Standardwert die Länge deiner Antwort bestimmt, nicht du.
Eine Grenze bleibt unabhängig vom Prompt immer gleich: Sexueller Inhalt mit Minderjährigen wird immer mit einem 403er blockiert, auch in Fiktion und Roleplay, und der Service ist nur für Erwachsene. Verschwendet keine Token damit, es umzuformulieren. Widerstehe auch dem Drang, nach jeder schlechten Antwort eine neue Regel hinzuzufügen; ein Prompt, der täglich um eine Zeile wächst, widerspricht sich innerhalb einer Woche selbst, also kürze ihn so oft, wie du hinzufügst.
Eine Schleife zur Verbesserung eines Prompts
Behandle den System-Prompt wie Code. Halte ihn in einer Datei, ändere pro Lauf nur ein Element und vergleiche die Ausgaben nebeneinander. Eine praktikable Routine: Schreibe fünf feste Testeingaben, darunter eine feindselige und eine mehrdeutige; führe jede bei deiner gewählten Temperatur dreimal aus; notiere, welche Regel am häufigsten versagt hat; behebe nur diese Regel; führe erneut aus.
Plane das Budget für die Experimente. Als Annahme: Ein 300-Token-System-Prompt plus eine 100-Token-Eingabe und eine 250-Token-Ausgabe ergeben 400 Input-Token und 250 Output-Token. Fünfzehn Läufe kosten etwa 15 x (400 x 0,25 $ + 250 x 1,00 $) / 1.000.000 = etwa 0,005 $. Testen ist fast kostenlos, also gibt es keine Ausrede für Ratespielerei.
Sobald der Prompt steht, kannst du ihn in eine echte App einbauen. Das Bot-Tutorial zeigt, wie du pro Kanal eine separate Historie führst, und der Inhaltsleitfaden behandelt Adult-Fiction-Nutzung. Die Details zur Preisgestaltung findest du auf der Preisseite.