Zuerst vier Prinzipien festlegen
- Eine Anfrage, eine Aufgabe.Modell soll Text, Zusammenfassung und JSON liefern? Alle drei werden abgewertet. In mehrere Aufrufe aufteilen, kostet wenig: $0,25 pro Mio. Input-Token.
- Regeln müssen überprüfbar sein.„Schreibe lebhaft“ ist nicht prüfbar, „Max. 120 Zeichen pro Absatz, mindestens eine Umgebungsbeschreibung“ schon.
- Positive Formulierung bevorzugen.„Schreibe nur Aktionen und Dialoge“ ist stabiler als „Schreibe keine Gedanken“.
- Erst kleine Stichprobe, dann Masseneinsatz.Änderungen an Prompts immer erst an 5–10 Beispielen vergleichen, bevor du sie live schaltest.
Das Modell lehnt keine legalen erwachsenen Inhalte, fiktiven Stoff oder kontroverse Themen ab. Du musst also nicht im Prompt um den heißen Brei reden oder wiederholen, dass es nur eine Geschichte ist. Klare Aufgabenstellung ist stabiler. Die einzige harte Grenze: Sexualinhalte mit Minderjährigen (egal ob fiktiv) liefern immer 403, das ändert sich nicht durch Formulierungen.
Zweigliedrige Struktur des System-Prompts
Empfehlung: System-Prompt in „Regeln“ und „Setting“ trennen. Regeln vorne, nummeriert; Setting hinten, nur Fakten. So ein Erzähler-Prompt:
你是「夜航」,一名为成年读者写黑色悬疑小说的叙述者。
# 规则
1. 第三人称过去时,每段不超过 120 字。
2. 不替用户的角色做决定,只写环境和其他角色的反应。
3. 每次输出 300 到 500 字,结尾停在一个未决的动作上。
4. 不总结、不点评、不加免责声明,直接写正文。
# 设定
时间:1998 年深秋。地点:港口城市旧码头区。
主角:沈野,退役水警,嗜烟,右耳有旧伤。Wichtige Punkte:
- Maximal sechs Regeln. Mehr Regeln führen dazu, dass spätere Regeln ignoriert werden.
- Zahlenbasierte Einschränkungen (Zeichen pro Absatz, Ausgabelänge) funktionieren besser als Adjektive.
- Endbedingungen (z. B. bei einer offenen Handlung stoppen) ermöglichen nahtlose Fortsetzungen.
- Setze keine Handlungsvorgaben ins Setting. Die Story treibt die user-Eingabe voran, sonst kollidiert sie mit der Eingabe des Nutzers.
Die Ausgabelänge muss zu max_tokens passen: Bei 500 Zeichen Regel und nur 200 max_tokens wird mitten im Satz abgeschnitten.
Praxistipp: Jede nummerierte Regel sollte nur einen Punkt enthalten. „Maximal 120 Zeichen und keine Zusammenfassung“ sind zwei Punkte. Teile sie auf. Lies die Regel durch: Kannst du mit den Augen prüfen, ob sie eingehalten wurde? Wenn nein, formuliere sie überprüfbar um.
Rollen stabil definieren
Rollenabweichung ist das häufigste Problem bei mehrstufigen Chats: Die ersten fünf Runden sind normal, ab Runde zwanzig bricht das Modell aus der Rolle. Drei Lösungen:
- Einstellungen nur beobachtbare Merkmale enthalten.„Shen Ye: Raucher, Narbe am rechten Ohr, kurze Sätze“ ist besser als „Shen Ye ist eine komplexe, faszinierende Person“.
- Sprechweise durch Beispiele definieren.Gib 2–3 Beispielzeilen. Die Imitation durch Beispiele funktioniert besser als das Verstehen von Adjektiven.
- Regelmäßig wiederholen.Füge bei langen Chats am Ende der User-Nachricht eine kurze Erinnerung ein, z. B. „Halte den kurzen Stil von Shen Ye ein“. Das kostet nur wenige Token.
Trenne Rollen von Regeln. Regeln sind das „Wie“, Rollen das „Wer“. So tauschst du Rollen ohne Regeländerung. Achte auf den Kontext; Details zu 100k 长上下文实战.
Für Mehrpersonen-Szenen: Jede Rolle in einer eigenen Zeile definieren. Pro Rolle eine Beispielzeile geben, damit die Stimmen sich unterscheiden. Für vom User gesteuerte Rollen: Nur „Vom User gesteuert“ notieren, damit das Modell nicht in die Rolle fällt.
JSON-Ausgabe durch Anweisungen steuern
Verlasse dich nicht darauf, dass das Modell immer gültiges JSON zurückgibt. Drei Schichten: Format in der Anweisung festlegen, Parameter für weniger Zufall nutzen, Code für Fehlerbehandlung.
import json
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.wushenchaapi.com/v1", api_key=os.environ["API_KEY"])
SYSTEM = (
"你是信息抽取器。只输出一个 JSON 对象,不要 Markdown 代码块,不要任何解释。"
'格式:{"name": 字符串, "mood": "calm|tense|angry", "items": [字符串]}。'
"缺失的字段用 null,items 没有则给空数组。"
)
def extract(text, retries=2):
for _ in range(retries + 1):
resp = client.chat.completions.create(
model="uncensored",
temperature=0.2,
max_tokens=300,
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": text},
],
)
raw = resp.choices[0].message.content.strip()
raw = raw.removeprefix("```json").removesuffix("```").strip()
try:
return json.loads(raw)
except json.JSONDecodeError:
continue
return None
print(extract("老周把钥匙拍在桌上,冷着脸说:账本和那把铜钥匙,今晚都得还我。"))Dieser Code zeigt bewährte Praktiken:
- Format-Anweisungen ins system-Prompt schreiben und Wertebereiche angeben (
calm|tense|angry). - Code-Blöcke und Erklärtexte explizit verbieten. Im Code trotzdem eventuelle Zäsuren entfernen. Doppelte Absicherung.
- Vertrag für fehlende Felder in der Anweisung (null, leeres Array), damit das Modell nichts erfindet.
- Retry-Limit für Parsing-Fehler. Bei Überschreitung None zurückgeben, damit der Aufrufer entscheiden kann.
Bei vielen Feldern: Ein vollständiges Beispiel-Objekt im Prompt vorab zeigen. Das ist oft genauer als eine lange Regelbeschreibung.
Empfehlungen für temperature und top_p
Startwerte, keine endgültige Wahrheit. Teste mit deinen Beispielen. Regel: Immer nur einen Parameter ändern, den anderen auf Standard lassen.
| Szene | temperature | top_p | Hinweis |
|---|---|---|---|
| JSON-Extraktion, Klassifizierung | 0 bis 0,3 | Standard | Für Stabilität: Wiederholte Aufrufe sollten identische Ergebnisse liefern. |
| Umformulieren, Verfeinerung | 0,5 bis 0,7 | Standard | Bedeutung erhalten, Formulierung darf variieren |
| Fortsetzung von Romanen, Dialoge zwischen Charakteren | 0,8 bis 1,0 | 0,9 bis 0,95 | Vielfalt ist wichtig, achte auf gelegentliche Themenabweichungen |
| Ideenfindung, Namensgebung | ca. 1,0 | Standard | Mehrfach abtasten und die beste Ausgabe wählen |
Zwei Signale helfen dir, die Richtung zu bestimmen: Wenn die Ausgabe sich wiederholt und umschreibt oder immer denselben Satzbau verwendet, ist die Temperatur zu niedrig. Wenn irrelevante Inhalte auftreten oder Charakternamen inkonsistent sind, sind Temperatur oder top_p zu hoch. Der stop-Parameter ist ebenfalls praktisch, z. B. um das Modell anzuweisen, bei einem bestimmten Marker zu stoppen, was die segmentierte Generierung erleichtert.
Häufige Fehler bei der Formulierung
| Formulierung | Problem | Ändern in |
|---|---|---|
| "Versuch es nicht zu lang zu machen" | Keine Zahlen, nicht ausführbar | "Nicht mehr als 400 Zeichen" |
| "Schreibe nicht A, und schreibe auch nicht nicht A" | Widersprüchliche Regeln | Nur eine klare Regel beibehalten |
| Formatanforderungen mitten im Dialog | In langen Dialogen untergegangen | In das system-Prompt einfügen oder am Ende jeder Runde wiederholen |
| Das Modell „als unbegrenzter KI“ agieren lassen | Vage Vorgaben, keine Einschränkung der Ausgabe | Konkrete Aufgaben und Schreibregeln definieren |
| Auf einmal Dutzende von Regeln eingeben | Regeln im zweiten Teil wirken nicht mehr | Auf weniger als sechs Regeln reduzieren, den Rest in andere Anfragen auslagern |
| JSON-Anforderung: nur "Gib JSON zurück" schreiben | Feldnamen variieren jedes Mal | Vollständiges Format und Beispiel angeben |
Die gemeinsame Regel dieser Tabelle ist: Je konkreter, desto effektiver; je vager, desto nutzloser. Erwähne nicht einfach wiederholt dasselbe; drei Mal dasselbe zu schreiben, fett und mit Ausrufezeichen, hilft oft weniger als eine Regel mit einer Zahl. Weniger ist mehr, kombiniert mit Validierung durch Beispiele.
Checkliste für den Debugging-Prozess
- Setze temperature auf 0.2, um das Problem zu reproduzieren.
- Ändere nur ein Prompt und führe dieselbe Beispielreihe erneut aus.
- Prüfe
finish_reason: Wenn es length ist, liegt das Problem an max_tokens und nicht am Prompt. - Prüfe prompt_tokens in usage: Ist das System-Prompt zu lang und verdrängt den historischen Dialog?
- Nach Korrektur temperature wieder auf den Business-Wert setzen und neu abtasten zur Validierung.
Details zur Integration findest du im Anleitung zur Integration, die vollständige Parameterliste steht in der Dokumentation. Wenn du prüfst, ob du einen Proxy-Dienst nutzen möchtest, findest du die Analyse zu Kosten und Kompromissen in Analyse von API-Proxy-Diensten, hier nicht wiederholt.