Условные промпты ({{#if}})
Блок {{#if}} добавляет часть текста промпта только тогда, когда условие выполняется. Используйте его, чтобы один общий пресет давал разные инструкции разным персонажам, персонам или чатам, или чтобы пропустить пустое поле. Условия – часть системы макросов, поэтому они работают везде, где работают макросы: в карточках персонажей, персонах, записях лорбуков и пресетах.
Marinara проверяет условие при каждой сборке промпта, оставляет подходящий текст, а остальное отбрасывает. Это продвинутая функция, и большинству чатов она не нужна.
Базовый синтаксис
Блок открывается {{#if condition}} и закрывается {{/if}}. Добавьте {{else}} для случая, когда условие не выполняется, и {{else if}}, чтобы выстроить цепочку из нескольких условий. Marinara проверяет ветки сверху вниз и оставляет первую, условие которой выполняется. Если ни одно условие не выполнилось, а ветки {{else}} нет, блок дает пустую строку.
{{#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}}Блок можно записать в одну строку или в несколько, а блоки можно вкладывать друг в друга.
Операторы
Условие обычно состоит из левого значения, оператора и правого значения, например char == "Alice".
| Оператор | Значение |
==, =, is | Равно. |
!=, is not | Не равно. |
>, <, >=, <= | Больше, меньше, больше или равно, меньше или равно (только числа). |
contains, includes | Левое значение содержит правое как текст. |
not contains, not includes | Левое значение не содержит правого. |
Правила сравнения:
- Для операторов равенства: если обе стороны похожи на числа, Marinara сравнивает их как числа, поэтому
5равно5.0. Иначе она сравнивает текст без учета регистра, поэтомуMariравноmari. - Для
>,<,>=и<=обе стороны должны быть числами. Иначе условие не выполняется. containsиincludesне учитывают регистр, поэтомуcontains "dr"находит совпадение вDr Smith.
Объединение условий
|| означает OR (или), а && – AND (и). && вычисляется раньше ||. Чтобы задать порядок, поставьте скобки.
{{#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}}Если одно значение сравнивается на равенство с несколькими вариантами, повторяющуюся левую часть можно опустить: character == "Maukie" || "Pantalone". Это работает для ==, = и is. По обе стороны && пишите условия целиком.
Проверка на заполненность
Условие без оператора выполняется, когда в значении есть настоящее содержимое. Оно не выполняется, когда значение пустое или равно одному из слов false, 0, no, off, null или undefined в любом регистре.
{{#if scenario}}
Current scene: {{scenario}}
{{else}}
No specific scene is set.
{{/if}}Что можно сравнивать
Любой стороной условия может быть:
- Ключевое слово поля или личности, например
char,user,group,persona,description,personality,scenario,input,modelилиreasoning. Они берут те же значения, что и одноименные макросы.groupперечисляет остальных активных персонажей, кроме того, кто отвечает сейчас. - Литерал в кавычках, например
"Alice". - Имя переменной пресета, например
length. Смотрите Переменные пресета. - Явное обращение к переменной в виде
var:nameилиvar.name. - Другой макрос: сначала раскрывается его значение.
- Вопрос вашей модели решений:
decision:"..."илиdecision_choice:"...". Смотрите Вопрос к модели решений.
Слово без кавычек, если это не ключевое слово, считается именем переменной. Если переменной с таким именем нет, слово используется как обычный текст. Чтобы избежать путаницы, берите литералы в кавычки.
Кавычки
Берите фиксированный текст в простые двойные или одинарные кавычки. Внутри значения в кавычках экранируйте кавычку обратным слешем, а перевод строки записывайте как \n. Литерал с пробелом всегда берите в кавычки, например "Dr Smith". Значение из нескольких слов без кавычек читается как одно имя переменной.
Групповые блоки для нескольких персонажей
В групповом чате с двумя или более персонажами групповой блок повторяет свой текст по одному разу для каждого персонажа. Поставьте одиночную [ на отдельной строке, затем свой текст, затем одиночную ] на отдельной строке. Внутри блока обязателен макрос персонажа, например {{char}} или {{description}}, либо условие по персонажу.
[
{{char}}'s current attitude:
{{#if char == "Alice"}}cheerful and open{{else}}guarded and quiet{{/if}}
]С Alice и Bob блок сработает дважды, по разу для каждого персонажа. За пределами группового блока макрос персонажа раскрывается только для текущего или основного персонажа. В чате с одним персонажем строки [ и ] остаются обычным текстом.
Примеры
Свой тон для каждого персонажа:
{{#if char == "Dottore"}}
Speak in a cold, clinical tone.
{{else}}
Speak warmly and casually.
{{/if}}Поле попадает в промпт, только когда оно заполнено. Если поле Backstory (предыстория) пустое, блок дает пустую строку, и пустой заголовок не отправляется.
{{#if backstory}}
Backstory to remember: {{backstory}}
{{/if}}Инструкции для одного семейства моделей. model – это ID модели, например claude-opus-5-5, поэтому contains подходит ко всем версиям Opus, а == – к одной точной модели.
{{#if model contains "opus"}}
Keep replies under 400 words.
{{/if}}Инструкции по планированию, которые зависят от рассуждений. Если рассуждения включены на любом уровне, модель получает первую строку. Если они выключены, {{reasoning}} равно off, что читается как ложь. Чтобы сработать на одном уровне, сравните его, как в {{#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}}Вопрос к модели решений
Условие может спросить вашу модель решений о том, что происходит в чате. Модель решений – это небольшая модель, которая читает несколько последних сообщений и написанное вами утверждение и сообщает, верно ли оно. В чат она ничего не пишет. Так пресет, карточка, запись лорбука или промпт агента отправляют инструкцию только тогда, когда она применима.
Перед началом: выберите модель в Decision model (модель решений) на панели Connections (подключения). Что это такое и как ее выбрать, объясняет руководство Модели решений. Чтобы решать, активируется ли запись лорбука целиком, используйте вместо этого поле Decision записи.
Идеи: описывать новое место, только если сцена переместилась; загружать правила темпа боя только во время боя; сдерживать эскалацию в пресете медленного сближения; в групповом блоке просить отвечать напрямую только того персонажа, к которому обратились.
Да или нет: 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}}Условие выполняется, когда модель решений считает утверждение верным. Оно работает с {{else}}, &&, ||, скобками, вложенностью и групповыми блоками. Макросы в утверждении подставляются заранее, поэтому {{user}} и {{char}} работают. В групповом блоке утверждение с {{char}} запрашивается отдельно для каждого персонажа.
Один из нескольких ответов: decision_choice:
decision_choice: просит модель выбрать один вариант. Вариантами служат значения, с которыми вы его сравниваете.
{{#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}}Модель выбирает между "angry", "sad" и "none of these". Пишите утверждение как тему, а варианты – как короткие ответы. Короткая запись == "rain" || "snow" предлагает оба варианта.
Чтобы объяснить, что вариант значит в вашей истории, добавьте после него критерии через двоеточие, взяв обе части в кавычки одного вида: == "angry":"Kaelen raises his voice, makes threats or breaks something". Модель по-прежнему отвечает "angry". Если одному варианту в нескольких местах даны разные критерии, используются первые.
Sticky и cooldown
Добавьте sticky: и cooldown: после утверждения, чтобы его ответ сохранялся на несколько сообщений и не запрашивался каждый раз.
{{#if decision:"The latest message starts a fight" sticky:3 cooldown:5}}
Keep combat pacing rules in effect.
{{/if}}sticky:N: после да утверждение остается да следующие N сообщений и не запрашивается.cooldown:N: начинается, когда заканчивается sticky, или сразу после да. Следующие N сообщений утверждение означает нет и не запрашивается.- Один отсчет – каждое новое сообщение, которое читает модель решений. Регенерация или свайп того же сообщения остаются тем же отсчетом, поэтому повторная генерация никогда не сокращает таймер.
- Удерживаемое утверждение не запрашивается и не учитывается в Decision statements per turn (утверждения решений за один ответ).
- Для
decision_choice:sticky сохраняет выбранный вариант, а при cooldown каждое сравнение означает нет. - Утверждение, записанное в нескольких местах, использует самые длинные sticky и cooldown.
- Peek Prompt показывает удерживаемый ответ и никогда не продвигает таймер.
Для записи лорбука, которая активируется полем Decision (решение), используйте вместо этого собственные Sticky (удержание) и Cooldown (пауза) записи.
Until и while
Чтобы блок оставался включенным, пока что-то длится, добавьте until: или while: со вторым утверждением.
{{#if decision:"A fight starts in the latest message" until:"The fight ends in the latest message"}}
Keep combat pacing rules in effect.
{{/if}}- После да блок остается включенным. Первое утверждение не запрашивается. Вместо него каждый раз запрашивается утверждение
until, и блок выключается на том сообщении, где оно окажется истинным. while:работает наоборот: блок остается включенным, пока его утверждение истинно, и выключается, когда оно оказывается ложным.- Используйте что-то одно. Если записаны оба, учитывается только первый.
- Когда блок выключается, как обычно, начинается cooldown. Если на каком-то сообщении ответа нет, блок остается включенным.
- Утверждение
untilилиwhileучитывается в Decision statements per turn. Первое утверждение, пока блок включен, не учитывается. - Это работает с
decision:, но не сdecision_choice:.
Если используется sticky, добавьте после второго утверждения :and (или :restrict) либо :or (или :extend), чтобы выбрать, как они сочетаются.
| Как записано | После да блок остается включенным |
until:"..." sticky:5 или until:"...":and sticky:5 | Не больше 5 следующих сообщений и выключается раньше, если утверждение until окажется истинным. |
until:"...":or sticky:5 | Не меньше 5 следующих сообщений, а затем – пока утверждение until не станет истинным. |
while:"..." sticky:5 или while:"...":or sticky:5 | Не меньше 5 следующих сообщений, а затем – пока утверждение while истинно. |
while:"...":and sticky:5 | Не больше 5 следующих сообщений и выключается раньше, если утверждение while окажется ложным. |
Проверка через несколько сообщений
Добавьте every:N, чтобы запрашивать утверждение только раз в N сообщений.
{{#if decision:"The weather changes in the latest message" every:3}}
Describe the new weather in a sentence.
{{/if}}- Первый раз оно запрашивается, когда до него впервые доходит очередь, следующий – через 3 сообщения, и так далее. Между проверками оно означает нет, не запрашивается и не учитывается в Decision statements per turn.
- Регенерация или свайп не продвигают расписание.
- Sticky и cooldown по-прежнему удерживают ответ.
every:лишь решает, когда запрашивать утверждение, которое они не удерживают. - Утверждение, записанное в нескольких местах, использует наименьшее
every:.
Приоритет
Если в плане промпта больше утверждений, чем допускает лимит Decision statements per turn, priority:high или priority:low определяет, какие из них спросить. Без приоритета используется средний.
{{#if decision:"In the latest message, a character is badly hurt" priority:high}}...{{/if}}
{{#if decision:"The latest message mentions food" priority:low}}...{{/if}}- Утверждения с высоким приоритетом запрашиваются первыми, с низким – последними. При равном приоритете решает порядок в промпте.
- За лимитом первыми исключаются утверждения с наименьшим приоритетом: они означают нет, и Peek Prompt их перечисляет.
- Утверждение, записанное в нескольких местах, использует наивысший приоритет.
- Сначала планируются собственные утверждения промпта (пресет, карточки, персона, заметки автора). Утверждения лорбуков занимают оставшиеся места, каким бы ни был их приоритет.
Все модификаторы можно сочетать в любом порядке: decision:"..." priority:high sticky:3 cooldown:5 every:2.
Нет ответа означает нет
Условие решения ложно всякий раз, когда ответа нет: модель решений не выбрана, не ответила вовремя или завершилась с ошибкой. Для decision_choice: ложно каждое сравнение. Учитывайте это при написании.
- Используйте решение, чтобы добавлять или сокращать указания, и никогда – чтобы передавать содержимое, от которого зависит история.
- Дайте каждому блоку решения вариант по умолчанию: ничего либо
{{else}}, который уместен всегда. - Не связывайте решения так, чтобы один неверный ответ менял несколько других.
- Не ставьте согласие, предупреждения о содержимом или инструкции безопасности в зависимость от решения.
Любая модель может ответить неверно. Пишите для "модели решений", а не для одного конкретного продукта.
Как писать утверждения
- Сообщайте факт, который истинен или ложен, как строку отчета. Не вопрос ("Did the scene change?") и не инструкцию ("If the scene changed, describe it"). Небольшие модели часто отвечают нет на инструкцию, и блок никогда не выполняется.
- Пишите "in the latest message", если имеете в виду текущее сообщение. Модель читает несколько сообщений, и более раннее может заставить ее ответить да.
- Называйте, о ком идет речь. "He is angry" может быть отнесено не к тому персонажу.
- Описывайте то, что видно в тексте, например действие или сказанную фразу. Избегайте слов о настроении ("The scene is intense") и скрытых намерений ("Mira is lying").
- Пишите кратко. Разделите длинное утверждение на части, если хотите переиспользовать или отлаживать их.
Как проверить формулировку:
- Выберите модель в Decision model и нажмите Test (проверить). Это проверяет подключение на фиксированном примере. Ваше утверждение при этом не проверяется.
- Добавьте утверждение в промпт и отправьте сообщения, на которых оно должно быть истинным, и сообщения, на которых оно должно быть ложным.
- Используйте Peek Prompt, чтобы увидеть, какая ветка отправлена. Откройте Decision diagnostics (диагностика решений), затем выберите Test decisions (проверить решения), чтобы заново получить ответы модели решений, не генерируя ответ. Тесты на облачной модели могут стоить денег. Смотрите Проверка условий решений.
- Скорректируйте формулировку и проверьте снова. Чтобы видеть ответы во время обычной генерации, включите Debug Mode или отладочное журналирование.
Ограничения и стоимость
Лимит утверждений
Decision statements per turn в Decision model по умолчанию равен 32. Это не единый предел для всех запросов Decision или расходов. Marinara применяет его поэтапно.
- Утверждения основного промпта чата планируются в пределах лимита. Решения лорбуков используют то, что осталось.
- Агенты, которые работают до ответа или параллельно с ним, получают общий план с основным промптом, и лимит применяется снова. Этот этап не вычитает то, что израсходовал лорбук, поэтому сумма может превысить настройку.
- Агенты постобработки получают отдельный лимит после ответа.
Вопросы активации агентов и Smart response order в эту настройку не входят.
В план этапа входят только утверждения, которые он может использовать: включенные секции и группы пресета, выбранные варианты переменных и содержимое активированных записей лорбука. Фиксированное условие может исключить утверждение, например {{#if char == "Dottore" && decision:"..."}}, когда персонаж – Mira. Условие по переменной этого не делает, потому что переменные могут меняться во время сборки промпта. Утверждения, удерживаемые sticky, cooldown или every:, не занимают места. Не вошедшие утверждения означают нет.
Запросы и время
На облачном аккаунте Decision за один ответ может выполняться несколько платных запросов. Утверждения можно группировать, но активация лорбука, содержимое только что активированных записей, рекурсивные совпадения и фазы агентов могут потребовать новых групп. Локальная модель чата добавляет время обработки вместо платы и отвечает на decision_choice: отдельным вопросом да/нет для каждого варианта.
У каждого запроса есть лимит времени: по умолчанию 1,5 секунды для облачного аккаунта Decision или 4 секунды для аккаунта OpenAI-совместимой модели чата или локальной модели. Смотрите Лимиты времени. Локальная рассуждающая модель воздерживается от решений до ответа, если не включить Also gate agents that run before the reply (проверять также агентов до ответа).
Повторное использование ответов
Обычно Marinara повторно использует успешные ответы для того же сообщения и той же модели решений, поэтому регенерация часто отправляет те же ветки без нового запроса. Кеш находится в работающем сервере и хранит до 200 сообщений. Перезапуск, вытеснение из кеша, новое или измененное последнее сообщение, другая модель, измененное утверждение или набор вариантов могут потребовать нового ответа.
Отсутствующие или неудачные ответы не кешируются, поэтому повторная попытка может спросить снова и выбрать другую ветку. Утверждения в промптах агентов подчиняются тем же правилам. Ручной перезапуск агента использует ответы, которые еще хранятся в кеше для его входных данных. Смотрите Утверждения решений в промпте агента.
Кеширование промпта
Кеш промпта у провайдера не связан с кешем ответов Marinara. Он может повторно использовать неизменное начало промпта, отправленного вашей модели чата. Смена ветки решения может прекратить повторное использование с этого места, хотя более ранняя неизменная часть еще может подойти. Оплата зависит от провайдера.
Размещайте часто меняющиеся блоки решений ближе к концу промпта, например в инструкциях после истории или в неглубокой заметке автора. Оставляйте решение в начале, только если его ответ меняется редко. С вариантами переменных пресета то же самое, потому что их текст попадает туда, где стоит {{name}}.
На прямом аккаунте Anthropic с включенным Enable prompt caching (включить кеширование промптов) Marinara отмечает конец системного промпта и сообщение чата, отстоящее на Cache depth (глубина кеша) сообщений от последнего (по умолчанию 5). Изменение до истории может сделать недействительными системную границу и последующую историю. Изменение после отмеченной границы истории может сохранить кешированную часть. Минимальная длина кеша зависит от модели. Смотрите актуальное руководство Anthropic по кешированию промптов или руководство OpenAI по кешированию промптов.
Если ветка решения никогда не появляется
Вероятные причины по порядку:
- Модель решений не выбрана. Все условия решений ложны. Редактор показывает предупреждение под каждым полем, где они используются.
- Модель решений не отвечает: неверный ключ, нет средств или действует ограничение частоты запросов на облачном аккаунте, локальная модель остановлена или слишком медленная, или установленная модель решений не запустилась.
- Это рассуждающая модель, которая воздерживается от решений до ответа.
- На этапе планирования слишком много утверждений, больше лимита.
- Ответ есть, но ниже порога. Обычно дело в формулировке.
Проверьте, что сообщает Test, и откройте Peek Prompt, чтобы увидеть отправленные ветки. Там перечислены утверждения, у которых еще нет ответа: они означают нет. При уровне журнала debug в журнал записываются каждое утверждение, его ответ и то, было ли оно прочитано как да. Смотрите Уровни логирования. Исправлять редко приходится пресет. Обычно дело в формулировке или в ветке, которая несет то, без чего промпт не может обойтись.
Смежные руководства
- Модели решений
- Макросы промптов
- Переменные пресета
- Групповые чаты в режимах Conversation и Roleplay