Bedingte Prompts ({{#if}})

Ein {{#if}}-Block nimmt einen Teil des Prompt-Textes nur dann auf, wenn eine Bedingung zutrifft. Damit gibst du einem gemeinsamen Preset unterschiedliche Anweisungen für verschiedene Charaktere, Personas oder Chats, oder du lässt ein leeres Feld weg. Bedingungen gehören zum Makro-System und funktionieren deshalb überall dort, wo auch Makros funktionieren: in Charakterkarten, Personas, Lorebook-Einträgen und Presets.

Marinara prüft die Bedingung bei jedem Prompt-Aufbau, behält den passenden Text und verwirft den Rest. Das ist eine Funktion für Fortgeschrittene, und die meisten Chats brauchen sie nie.

Die Grundsyntax

Ein Block beginnt mit {{#if condition}} und endet mit {{/if}}. Mit {{else}} ergänzt du den Fall, dass die Bedingung nicht zutrifft, und mit {{else if}} hängst du weitere Bedingungen an. Marinara prüft die Zweige von oben nach unten und behält den ersten, der zutrifft. Trifft keiner zu und fehlt ein {{else}}, ergibt der Block nichts.

{{#if length == "short"}}
Keep your reply to one or two sentences.
{{else if length == "long"}}
Write a detailed, multi-paragraph reply.
{{else}}
Write a reply of normal length.
{{/if}}

Ein Block kann in einer einzigen Zeile stehen oder sich über mehrere Zeilen ziehen, und du kannst Blöcke verschachteln.

Operatoren

Eine Bedingung besteht meist aus einem linken Wert, einem Operator und einem rechten Wert, etwa char == "Alice".

OperatorBedeutung
==, =, isGleich.
!=, is notUngleich.
>, <, >=, <=Größer, kleiner, größer oder gleich, kleiner oder gleich (nur Zahlen).
contains, includesDer linke Wert enthält den rechten Wert als Text.
not contains, not includesDer linke Wert enthält den rechten Wert nicht.

Für den Vergleich gelten diese Regeln:

  1. Bei den Gleichheitsoperatoren vergleicht Marinara beide Seiten als Zahlen, sofern beide wie Zahlen aussehen. 5 ist also gleich 5.0. Andernfalls vergleicht es Text, ohne Rücksicht auf Groß- und Kleinschreibung. Mari ist also gleich mari.
  2. Bei >, <, >= und <= müssen beide Seiten Zahlen sein. Andernfalls trifft die Bedingung nicht zu.
  3. Bei contains und includes spielt Groß- und Kleinschreibung keine Rolle. contains "dr" passt also auf Dr Smith.

Bedingungen kombinieren

Nimm || für ODER und && für UND. && wird vor || ausgewertet. Mit Klammern legst du die Reihenfolge fest.

{{#if character == "Maukie" || character == "Pantalone"}}
Use the shared instructions.
{{/if}}

{{#if (character == "Maukie" || character == "Pantalone") && scenario contains "lake"}}
Use the lakeside instructions for either character.
{{/if}}

Prüfst du einen Wert auf mehrere Gleichheitsalternativen, kannst du die wiederholte linke Seite weglassen: character == "Maukie" || "Pantalone". Das funktioniert bei ==, = und is. Auf beiden Seiten von && schreibst du vollständige Bedingungen.

Truthy-Prüfungen

Eine Bedingung ohne Operator trifft zu, wenn der Wert echten Inhalt hat. Sie trifft nicht zu, wenn der Wert leer ist oder eines dieser Wörter ist, in beliebiger Groß- und Kleinschreibung: false, 0, no, off, null oder undefined.

{{#if scenario}}
Current scene: {{scenario}}
{{else}}
No specific scene is set.
{{/if}}

Was sich vergleichen lässt

Auf jeder Seite einer Bedingung kann Folgendes stehen:

  1. Ein Feld- oder Identitäts-Schlüsselwort wie char, user, group, persona, description, personality, scenario, input, model oder reasoning. Diese lesen dieselben Werte wie die passenden Makros. group listet die übrigen aktiven Charaktere auf, ohne den gerade antwortenden Charakter.
  2. Ein Literal in Anführungszeichen, etwa "Alice".
  3. Der Name einer Preset-Variablen, etwa length. Siehe Preset-Variablen.
  4. Ein ausdrücklicher Variablenzugriff in der Form var:name oder var.name.
  5. Ein weiteres Makro, das zuerst aufgelöst wird.
  6. Eine Frage an dein Decision-Modell: decision:"..." oder decision_choice:"...". Siehe Das Decision-Modell fragen.

Ein bloßes Wort, das kein Schlüsselwort ist, behandelt Marinara als Variablennamen. Gibt es keine Variable dieses Namens, gilt das Wort als schlichter Text. Setz feste Werte in Anführungszeichen, damit es keine Verwechslung gibt.

Anführungszeichen

Setz festen Text in gerade doppelte oder gerade einfache Anführungszeichen. Innerhalb eines Werts in Anführungszeichen maskierst du ein Anführungszeichen mit einem Backslash, und \n steht für einen Zeilenumbruch. Ein Literal mit Leerzeichen gehört immer in Anführungszeichen, etwa "Dr Smith". Ein mehrteiliger Wert ohne Anführungszeichen gilt als ein einziger Variablenname.

Gruppenblöcke für mehrere Charaktere

In einem Gruppenchat mit zwei oder mehr Charakteren wiederholt ein Gruppenblock seinen Text einmal pro Charakter. Setz ein einzelnes [ in eine eigene Zeile, darunter deinen Text und darunter ein einzelnes ] in eine eigene Zeile. Der Block muss ein Charakter-Makro wie {{char}} oder {{description}} enthalten oder eine charakterbezogene Bedingung.

[
{{char}}'s current attitude:
{{#if char == "Alice"}}cheerful and open{{else}}guarded and quiet{{/if}}
]

Mit Alice und Bob läuft der Block zweimal durch, einmal pro Charakter. Außerhalb eines Gruppenblocks bezieht sich ein Charakter-Makro nur auf den aktuellen oder den primären Charakter. In einem Chat mit nur einem Charakter bleiben die Zeilen mit [ und ] schlichter Text.

Beispiele

Unterschiedlicher Ton pro Charakter:

{{#if char == "Dottore"}}
Speak in a cold, clinical tone.
{{else}}
Speak warmly and casually.
{{/if}}

Ein Feld nur mitschicken, wenn es ausgefüllt ist. Ist Backstory (Vorgeschichte) leer, ergibt der Block nichts, und es geht keine leere Beschriftung mit.

{{#if backstory}}
Backstory to remember: {{backstory}}
{{/if}}

Anweisungen für eine Modellfamilie. model ist die Modell-ID, etwa claude-opus-5-5. contains trifft also auf jede Opus-Version zu, == nur auf ein bestimmtes Modell.

{{#if model contains "opus"}}
Keep replies under 400 words.
{{/if}}

Planungsanweisungen, die vom Nachdenken abhängen. Ist Reasoning auf irgendeiner Stufe aktiv, bekommt das Modell die erste Zeile. Ist Reasoning aus, lautet {{reasoning}} gleich off, was als falsch gilt. Um auf eine bestimmte Stufe zu reagieren, vergleichst du sie, etwa mit {{#if reasoning == "max"}}.

{{#if reasoning}}
Plan the reply in your thinking before you write it.
{{else}}
Before replying, write your plan inside <plan></plan> tags.
{{/if}}

Das Decision-Modell fragen

Eine Bedingung kann dein Decision-Modell fragen, was im Chat passiert. Das Decision-Modell ist ein kleines Modell, das die letzten Nachrichten und eine von dir geschriebene Aussage liest und sagt, ob die Aussage wahr ist. Es schreibt nie etwas in den Chat. So kann ein Preset, eine Karte, ein Lorebook-Eintrag oder ein Agenten-Prompt eine Anweisung nur in den Zügen senden, in denen sie passt.

Bevor du anfängst: Wähle unter Decision model (Entscheidungsmodell) im Panel Connections (Verbindungen) ein Decision-Modell aus. Decision-Modelle erklärt, was es ist und wie du eines auswählst. Soll entschieden werden, ob ein ganzer Lorebook-Eintrag aktiviert wird, nutze stattdessen das Feld Decision des Eintrags.

Ideen: einen neuen Ort nur beschreiben, wenn die Szene gewechselt hat; Regeln für das Kampftempo nur während eines Kampfes laden; in einem Slow-Burn-Preset die Eskalation zurückhalten; oder in einem Gruppenblock nur den angesprochenen Charakter direkt antworten lassen.

Ja oder nein: decision:

{{#if decision:"The latest message moves the scene to a new place"}}
Open your reply by describing the new location in one or two sentences.
{{/if}}

Die Bedingung ist wahr, wenn das Decision-Modell die Aussage für wahr hält. Sie funktioniert mit {{else}}, &&, ||, Klammern, Verschachtelung und Gruppenblöcken. Makros in der Aussage werden zuerst aufgelöst; {{user}} und {{char}} funktionieren also. In einem Gruppenblock wird eine Aussage, die {{char}} nennt, für jeden Charakter einzeln gestellt.

Eine von mehreren Antworten: decision_choice:

decision_choice: bittet das Modell, eine Option auszuwählen. Die Optionen sind die Werte, mit denen du es vergleichst.

{{#if decision_choice:"Kaelen's mood in the latest message" == "angry"}}
Kaelen's lines are short and clipped.
{{else if decision_choice:"Kaelen's mood in the latest message" == "sad"}}
Kaelen speaks quietly and looks away.
{{else}}
Kaelen is his usual self.
{{/if}}

Das Modell wählt zwischen „angry“, „sad“ und „keine davon“. Formuliere die Aussage als Thema und die Optionen als kurze Antworten. Die Kurzform == "rain" || "snow" bietet beide Optionen an.

Um festzulegen, was eine Option in deiner Geschichte bedeutet, hängst du nach ihr Kriterien an, getrennt durch einen Doppelpunkt und mit derselben Art von Anführungszeichen um beide Teile: == "angry":"Kaelen raises his voice, makes threats or breaks something". Das Modell antwortet trotzdem mit „angry“. Hat eine Option an mehreren Stellen unterschiedliche Kriterien, gelten die ersten.

Sticky und Cooldown

Schreib sticky: und cooldown: hinter eine Aussage, damit ihre Antwort einige Züge lang erhalten bleibt, statt jeden Zug neu gefragt zu werden.

{{#if decision:"The latest message starts a fight" sticky:3 cooldown:5}}
Keep combat pacing rules in effect.
{{/if}}

Bei einem Lorebook-Eintrag, der über sein Feld Decision aktiviert wird, nutzt du stattdessen die eigenen Einstellungen Sticky und Cooldown des Eintrags.

Until und While

Soll ein Block so lange aktiv bleiben, wie etwas andauert, schreib until: oder while: mit einer zweiten Aussage dahinter.

{{#if decision:"A fight starts in the latest message" until:"The fight ends in the latest message"}}
Keep combat pacing rules in effect.
{{/if}}

Mit sticky setzt du :and (auch :restrict) oder :or (auch :extend) hinter die zweite Aussage, um festzulegen, wie beide zusammenwirken.

SchreibweiseNach dem Ja bleibt der Block aktiv
until:"..." sticky:5 oder until:"...":and sticky:5Für bis zu 5 weitere Züge; er schaltet sich früher ab, wenn die Until-Aussage wahr ist.
until:"...":or sticky:5Für mindestens 5 weitere Züge, danach so lange, bis die Until-Aussage wahr ist.
while:"..." sticky:5 oder while:"...":or sticky:5Für mindestens 5 weitere Züge, danach so lange, wie die While-Aussage wahr ist.
while:"...":and sticky:5Für bis zu 5 weitere Züge; er schaltet sich früher ab, wenn die While-Aussage falsch ist.

Alle paar Züge prüfen

Schreib every:N hinter eine Aussage, um sie nur alle N Züge zu fragen.

{{#if decision:"The weather changes in the latest message" every:3}}
Describe the new weather in a sentence.
{{/if}}

Priorität

Enthält ein Prompt-Plan mehr Aussagen, als das Kontingent Decision statements per turn erlaubt, entscheidet priority:high oder priority:low, welche gefragt werden. Ohne Angabe gilt mittlere Priorität.

{{#if decision:"In the latest message, a character is badly hurt" priority:high}}...{{/if}}
{{#if decision:"The latest message mentions food" priority:low}}...{{/if}}

Alle Zusätze lassen sich in beliebiger Reihenfolge kombinieren: decision:"..." priority:high sticky:3 cooldown:5 every:2.

Keine Antwort bedeutet nein

Eine Decision-Bedingung ist falsch, sobald keine Antwort vorliegt: Es ist kein Decision-Modell ausgewählt, es hat nicht rechtzeitig geantwortet, oder es ist fehlgeschlagen. Bei decision_choice: ist dann jeder Vergleich falsch. Plane dafür.

Jedes Modell kann falsch antworten. Schreib für „ein Decision-Modell“, nicht für ein bestimmtes Produkt.

Aussagen formulieren

So testest du deine Formulierung:

  1. Wähle unter Decision model ein Modell aus und klick auf Test. Das prüft die Verbindung mit einem festen Beispiel. Deine Aussage wird dabei nicht getestet.
  2. Ergänze die Aussage in deinem Prompt und sende Nachrichten, bei denen sie wahr sein soll, und Nachrichten, bei denen sie falsch sein soll.
  3. Nutze Peek Prompt, um zu sehen, welcher Zweig gesendet wurde. Öffne Decision diagnostics (Entscheidungsdiagnose) und wähle dann Test decisions (Entscheidungen testen), um neue Decision-Antworten zu bekommen, ohne eine Chat-Antwort zu generieren. Gehostete Tests können Geld kosten. Siehe Entscheidungsaussagen testen.
  4. Passe die Formulierung an und teste erneut. Um die Antworten laufender Generierungen zu sehen, schalte Debug Mode oder das Debug-Logging ein.

Grenzen und Kosten

Aussagenkontingent

Decision statements per turn unter Decision model steht standardmäßig auf 32. Das ist keine einzelne Grenze für alle Decision-Anfragen oder für die Ausgaben. Marinara wendet das Kontingent in Phasen an.

  1. Die Aussagen des Haupt-Chat-Prompts werden innerhalb des Kontingents geplant. Lorebook-Decisions nutzen, was übrig bleibt.
  2. Agenten, die vor oder parallel zur Antwort laufen, bekommen einen gemeinsamen Plan mit dem Haupt-Prompt, für den das Kontingent erneut gilt. In dieser Phase wird der Lorebook-Verbrauch nicht abgezogen; die Summe kann die Einstellung deshalb überschreiten.
  3. Nachverarbeitende Agenten bekommen nach der Antwort ein eigenes Kontingent.

Aktivierungsfragen von Agenten und die Smart-Antwortreihenfolge sind von dieser Einstellung unabhängig.

In den Plan einer Phase kommen nur Aussagen, die sie nutzen kann: aktivierte Preset-Abschnitte und -Gruppen, ausgewählte Variablenoptionen und Inhalte aktivierter Lorebook-Einträge. Eine feste Bedingung kann eine Aussage ausschließen, etwa {{#if char == "Dottore" && decision:"..."}}, solange der Charakter Mira ist. Eine Variablenbedingung tut das nicht, weil sich Variablen beim Prompt-Aufbau ändern können. Aussagen, die von Sticky, Cooldown oder every: gehalten werden, belegen keinen Platz. Ausgelassene Aussagen gelten als nein.

Anfragen und Zeit

Bei einem gehosteten Decision-Konto kann ein Zug mehrere berechnete Anfragen verursachen. Aussagen lassen sich bündeln, doch Lorebook-Aktivierung, neu aktivierte Eintragsinhalte, rekursive Treffer und Agentenphasen können weitere Bündel brauchen. Ein lokales Chat-Modell verursacht statt Gebühren zusätzliche Rechenzeit und beantwortet decision_choice: mit einer Ja/Nein-Frage pro Option.

Jede Anfrage hat ein Zeitlimit: standardmäßig 1,5 Sekunden bei einem gehosteten Decision-Konto oder 4 Sekunden bei einem Konto für ein OpenAI-kompatibles Chat-Modell oder einem lokalen Modell. Siehe Zeitlimits. Ein lokales Modell, das zuerst nachdenkt, hält sich vor der Antwort zurück, sofern du Also gate agents that run before the reply (auch Agenten vor der Antwort prüfen) nicht einschaltest.

Antworten wiederverwenden

Marinara verwendet erfolgreiche Antworten normalerweise für denselben Zug und dasselbe Decision-Modell wieder. Eine Neugenerierung sendet daher oft dieselben Zweige ohne neue Anfrage. Der Cache liegt im laufenden Server und hält bis zu 200 Züge. Ein Neustart, eine Entfernung aus dem Cache, eine neue oder bearbeitete letzte Nachricht, ein anderes Modell oder eine geänderte Aussage oder Optionsmenge können eine neue Antwort nötig machen.

Fehlende oder fehlgeschlagene Antworten werden nicht zwischengespeichert. Eine Wiederholung kann deshalb erneut fragen und einen anderen Zweig nehmen. Für Aussagen in Agenten-Prompts gelten dieselben Regeln. Ein manuell wiederholter Agentenlauf verwendet Antworten wieder, die zu seinen Eingaben noch im Cache liegen. Siehe Decision-Bedingungen im Agenten-Prompt.

Prompt-Caching

Der Prompt-Cache des Anbieters ist unabhängig von Marinaras Antwort-Cache. Er kann einen unveränderten Anfang des Prompts wiederverwenden, der an dein Chat-Modell geht. Ein wechselnder Decision-Zweig kann die Wiederverwendung ab dieser Stelle verhindern, auch wenn ein früherer unveränderter Teil weiterhin infrage kommen kann. Die Abrechnung hängt vom Anbieter ab.

Setze Decision-Blöcke, die oft wechseln, spät in den Prompt, etwa in Post-History-Anweisungen oder eine Autorennotiz mit geringer Tiefe. Lass eine Decision nur dann weit oben, wenn ihre Antwort selten wechselt. Für Variablenoptionen eines Presets gilt dasselbe, weil ihr Text dort landet, wo {{name}} steht.

Bei einem direkten Anthropic-Konto mit eingeschaltetem Enable prompt caching (Prompt-Caching aktivieren) markiert Marinara das Ende des System-Prompts und eine Chat-Nachricht, die Cache depth (Cache-Tiefe) Nachrichten vor der neuesten liegt (standardmäßig 5). Eine Änderung vor dem Verlauf kann die System-Grenze und den späteren Verlauf ungültig machen. Eine Änderung nach der markierten Verlaufsgrenze kann den zwischengespeicherten Teil erhalten. Die Mindestlänge für den Cache hängt vom Modell ab. Siehe die aktuelle Anleitung des Anbieters zum Anthropic-Prompt-Caching oder zum OpenAI-Prompt-Caching.

Wenn ein Decision-Zweig nie erscheint

Die wahrscheinlichsten Ursachen, in dieser Reihenfolge:

  1. Es ist kein Decision-Modell ausgewählt. Jede Decision-Bedingung ist falsch. Der Editor zeigt unter jedem Feld, das eine verwendet, eine Warnung.
  2. Das Decision-Modell antwortet nicht: ein falscher Key, kein Guthaben oder ein Anfragelimit bei einem gehosteten Konto, ein gestopptes oder zu langsames lokales Modell oder ein installiertes Entscheidungsmodell, das nicht gestartet ist.
  3. Es ist ein Modell, das zuerst nachdenkt und sich vor der Antwort zurückhält.
  4. Zu viele Aussagen in der Planungsphase, mehr als das Kontingent erlaubt.
  5. Es antwortet, aber unterhalb seiner Schwelle. Meist liegt das an der Formulierung.

Prüfe, was Test meldet, und sieh mit Peek Prompt nach, welche Zweige gesendet wurden. Peek Prompt listet Aussagen auf, die noch keine Antwort haben; sie gelten als nein. Mit Log-Level debug werden jede Aussage, ihre Antwort und ob sie als ja galt protokolliert. Siehe Log-Stufen. Selten liegt die Lösung im Preset. Meist geht es um die Formulierung oder um einen Zweig mit Inhalt, auf den der Prompt nicht verzichten kann.

Verwandte Anleitungen