Files
HadTavern/docs/VARIABLES.md

328 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Переменные и макросы НадTavern
Краткая, человеко‑понятная шпаргалка по тому, какие переменные и макросы доступны в шаблонах (в том числе в Prompt Blocks), как они устроены и как их правильно использовать. Док ниже соответствует текущему коду.
Реализация формирует единый «контекст» переменных для всех нод пайплайна, дополняет его выходами уже выполненных нод, а узел ProviderCall добавляет свои служебные структуры для удобной сборки промпта.
Ссылки на код:
- Формирование контекста запроса: [build_macro_context()](agentui/api/server.py:142)
- Исполнитель пайплайна и снапшот OUT: [PipelineExecutor.run()](agentui/pipeline/executor.py:136)
- Узел провайдера (Prompt Blocks → provider payload): [ProviderCallNode.run()](agentui/pipeline/executor.py:650)
- Шаблоны/макросы ([[...]] и {{ ... }}): [render_template_simple()](agentui/pipeline/templating.py:187)
- Короткая форма [[OUTx]] (извлечение текста): [_best_text_from_outputs()](agentui/pipeline/templating.py:124)
- Прямой форвард запросов: [RawForwardNode.run()](agentui/pipeline/executor.py:833)
---
## 1) Общие переменные контекста (для всех нод)
Эти переменные доступны в шаблонах любой ноды. Они добавляются на стороне сервера при обработке входящего HTTPзапроса.
- model — строка с именем модели.
Пример: "gpt-4o-mini"
- vendor_format — вендор/протокол запроса: "openai" | "gemini" | "claude" | "unknown"
- system — «системный» текст, если он был во входящем запросе; иначе пустая строка.
- params — стандартные параметры генерации (можно использовать как дефолты)
- params.temperature — число с плавающей точкой (по умолчанию 0.7)
- params.max_tokens — целое или null
- params.top_p — число (по умолчанию 1.0)
- params.stop — массив строк или null
- chat — сведения о чате во входящем запросе
- chat.last_user — последнее сообщение пользователя (строка)
- chat.messages — массив сообщений в унифицированной форме:
- role — "system" | "user" | "assistant" | "tool"
- content — содержимое (обычно строка)
- name — опционально, строка
- tool_call_id — опционально
- incoming — детали ВХОДЯЩЕГО HTTPзапроса
- incoming.method — метод ("POST" и т.п.)
- incoming.url — полный URL (в query ключи маскируются для логов)
- incoming.path — путь (например, /v1/chat/completions)
- incoming.query — строка query без вопросительного знака
- incoming.query_params — объект со всеми queryпараметрами
- incoming.headers — объект всех заголовков запроса
- incoming.json — сырой JSON тела запроса, как прислал клиент
- incoming.api_keys — удобные «срезы» ключей
- incoming.api_keys.authorization — значение из заголовка Authorization (если есть)
- incoming.api_keys.key — значение из query (?key=...) — удобно для Gemini
Пример использования в шаблоне:
- [[VAR:incoming.api_keys.key]] — возьмёт ключ из строки запроса (?key=...).
- [[VAR:incoming.headers.x-api-key]] — возьмёт ключ из заголовка x-api-key (типично для Anthropic).
- {{ params.temperature|default(0.7) }} — безопасно подставит число, если не задано во входящих данных.
---
## 2) Выходы нод (OUT) и ссылки на них
Во время исполнения пайплайна результаты предыдущих нод собираются в снапшот OUT и доступны при рендере шаблонов следующих нод:
- OUT — словарь выходов нод, ключи — id нод в пайплайне (например, "n1", "n2").
- OUT.n1, OUT.n2, ... — объект результата соответствующей ноды.
Формы доступа:
- Полная форма: [[OUT:n1.result.choices.0.message.content]]
(или фигурными скобками: {{ OUT.n1.result.choices.0.message.content }})
- Короткая форма «просто текст»: [[OUT1]], [[OUT2]], ...
Это эвристика: берётся самое вероятное «текстовое» поле из результата (см. [_best_text_from_outputs()](agentui/pipeline/templating.py:121)).
Что возвращают встроенные ноды:
- ProviderCall:
- OUT.nX.result — сырой JSON ответа провайдера
- OUT.nX.response_text — уже извлечённый «лучший текст» (строка)
- RawForward:
- OUT.nX.result — JSON, как пришёл от апстрима (или {"error": "...", "text": "..."} при неJSON ответе)
Подсказка по короткой форме [[OUTx]]:
- OpenAI: вернёт choices[0].message.content
- Gemini: вернёт candidates[0].content.parts[0].text
- Claude: склеит content[].text
- Если явных полей нет — выполнит «глубокий поиск» по ключам "text"/"content"
---
## 3) Макросы подстановки и синтаксис
В шаблонах доступны обе формы подстановки:
1) Квадратные скобки [[ ... ]] — простая подстановка
- [[VAR:путь]] — взять значение из контекста по точечному пути
Пример: [[VAR:incoming.json.max_tokens]]
- [[OUT:путь]] — взять значение из OUT (см. раздел выше)
Пример: [[OUT:n1.result.choices.0.message.content]]
- [[OUT1]] / [[OUT2]] — короткая форма «просто текст»
- [[PROMPT]] — специальный JSONфрагмент из Prompt Blocks (см. ниже)
2) Фигурные скобки {{ ... }} — «джинджа‑лайт»
- {{ путь }} — взять значение по пути из контекста (или из OUT.* если начать с OUT.)
Пример: {{ OUT.n1.result }}
- Фильтр по умолчанию: {{ что-то|default(значение) }}
Примеры:
- {{ params.temperature|default(0.7) }}
- {{ incoming.json.stop|default([]) }}
- {{ anthropic_version|default('2023-06-01') }} — см. «Опциональные поля» ниже
- Фигурные скобки удобны там, где нужно вставить внутрь JSON не строку, а ЧИСЛО/ОБЪЕКТ/МАССИВ без кавычек и/или задать дефолт.
---
## 4) ProviderCall: Prompt Blocks, pm.* и [[PROMPT]]
Узел ProviderCall собирает ваши Prompt Blocks (блоки вида: роль/текст/вкл‑выкл/порядок) в стандартные «сообщения» и превращает их в структуру для конкретного провайдера.
Внутри шаблонов этого узла доступны:
- pm — «сырьевые» структуры из Prompt Blocks
- Для OpenAI:
- pm.messages — массив { role, content, name? }
- pm.system_text — один большой текст из всех systemблоков
- Для Gemini:
- pm.contents — массив { role: "user"|"model", parts: [{text}] }
- pm.systemInstruction — объект вида { parts: [{text}] } или пустой {}
- pm.system_text — строка
- Для Claude:
- pm.system_text — строка
- pm.system — то же самое (удобно подставлять в поле "system")
- pm.messages — массив { role: "user"|"assistant", content: [{type:"text", text:"..."}] }
- [[PROMPT]] — готовый JSONфрагмент на основе pm, безопасный для вставки внутрь шаблона:
- OpenAI → подставит: "messages": [...]
- Gemini → подставит: "contents": [...], "systemInstruction": {...}
- Claude → подставит: "system": "...", "messages": [...]
Зачем это нужно?
- Чтобы 1) удобно собирать промпт из визуальных блоков, 2) не «сломать» JSON руками.
Вы можете вручную использовать {{ pm.* }}, но [[PROMPT]] — рекомендуемый и самый безопасный вариант.
---
## 5) Частые сценарии и примеры
Примеры ниже можно вклеивать в поле «template» ноды ProviderCall. Они уже используют [[PROMPT]] и аккуратные дефолты.
OpenAI (POST /v1/chat/completions):
```
{
"model": "{{ model }}",
[[PROMPT]],
"temperature": {{ incoming.json.temperature|default(params.temperature|default(0.7)) }},
"top_p": {{ incoming.json.top_p|default(params.top_p|default(1)) }},
"max_tokens": {{ incoming.json.max_tokens|default(params.max_tokens|default(256)) }},
"stop": {{ incoming.json.stop|default(params.stop|default([])) }}
}
```
Gemini (POST /v1beta/models/{model}:generateContent):
```
{
"model": "{{ model }}",
[[PROMPT]],
"safetySettings": {{ incoming.json.safetySettings|default([]) }},
"generationConfig": {
"temperature": {{ incoming.json.generationConfig.temperature|default(params.temperature|default(0.7)) }},
"topP": {{ incoming.json.generationConfig.topP|default(params.top_p|default(1)) }},
"maxOutputTokens": {{ incoming.json.generationConfig.maxOutputTokens|default(params.max_tokens|default(256)) }},
"stopSequences": {{ incoming.json.generationConfig.stopSequences|default(params.stop|default([])) }}
}
}
```
Подсказка: ключ Gemini удобно брать из строки запроса:
в endpoint используйте …?key=[[VAR:incoming.api_keys.key]]
Claude (POST /v1/messages):
```
{
"model": "{{ model }}",
[[PROMPT]],
"temperature": {{ incoming.json.temperature|default(params.temperature|default(0.7)) }},
"top_p": {{ incoming.json.top_p|default(params.top_p|default(1)) }},
"max_tokens": {{ incoming.json.max_tokens|default(params.max_tokens|default(256)) }},
"system": {{ pm.system|default("") }}
}
```
Подсказка: ключ Anthropic обычно передают в заголовке x-api-key.
В UIпресете это поле уже есть в headers.
RawForward (прямой форвард входящего запроса):
- Поля конфигурации base_url, override_path, extra_headers проходят через те же макросы, поэтому можно подставлять динамику:
- base_url: https://generativelanguage.googleapis.com
- override_path: [[VAR:incoming.path]] (или задать свой)
- extra_headers (JSON): `{"X-Trace":"req-{{ incoming.query_params.session|default('no-session') }}"}`
---
## 6) Опциональные/редкие поля, о которых стоит знать
- anthropic_version — используется как HTTPзаголовок для Claude ("anthropic-version"). В тело запроса не вставляется.
Если нужен дефолт, задавайте его в headers (например, в конфиге ноды/шаблоне заголовков). В шаблонах тела используйте [[PROMPT]]/pm.* без anthropic_version.
- stream — в MVP стриминг отключён, сервер принудительно не стримит ответ.
В шаблонах можно встретить поля stream, но по умолчанию они не включены.
---
## 7) Когда использовать [[...]] и когда {{ ... }}
- Внутрь JSON как ОБЪЕКТ/МАССИВ/ЧИСЛО: используйте {{ ... }}
(фигурные скобки вставляют «как есть», без кавычек, и умеют |default(...))
- Для строк/URL/заголовков/простых значений: можно использовать [[...]]
(квадратные скобки удобны и короче писать)
Примеры:
- {{ pm.contents }} — вставит массив как настоящий массив (без кавычек)
- {{ params.temperature|default(0.7) }} — безопасный дефолт для числа
- [[VAR:incoming.api_keys.authorization]] — быстро подставить строку Authorization
---
## 8) Отладка и рекомендации
- ProviderCall печатает в консоль DEBUG сведения: выбранный провайдер, конечный URL, первые символы тела запроса — удобно для проверки корректности шаблона.
- Если «ничего не подставилось»:
1) Проверьте, что вы НЕ передаёте сырое входное тело напрямую в ProviderCall (узел строит тело из шаблона и Prompt Blocks).
2) Убедитесь, что итоговый JSON валиден (закрывающие скобки, запятые).
3) Проверьте точность путей в макросах (OUT vs OUTx, правильные id нод n1/n2/...).
- Для ссылок на выходы предыдущих нод используйте [[OUT1]] как «просто текст», либо полные пути [[OUT:n1...]] для точного фрагмента.
---
## 9) Быстрая памятка по ключам доступа
- Gemini: [[VAR:incoming.api_keys.key]] — рекомендовано; ключ приходит в query (?key=...).
- OpenAI: [[VAR:incoming.headers.authorization]] (или [[VAR:incoming.api_keys.authorization]]) — стандартный Bearerтокен.
- Anthropic: [[VAR:incoming.headers.x-api-key]] — ключ в заголовке.
---
## 10) Ссылки на реализацию (для интересующихся деталями)
- Контекст (переменные): [build_macro_context()](agentui/api/server.py:142)
- Исполнение пайплайна, зависимости, снапшоты OUT: [PipelineExecutor.run()](agentui/pipeline/executor.py:136)
- Узел провайдера (Prompt Blocks → провайдер): [ProviderCallNode.run()](agentui/pipeline/executor.py:650)
- PMструктуры для шаблонов: [ProviderCallNode._blocks_struct_for_template()](agentui/pipeline/executor.py:592)
- Подстановка [[PROMPT]], макросы, дефолты: [render_template_simple()](agentui/pipeline/templating.py:187)
- Короткая форма [[OUTx]] и поиск «лучшего текста»: [_best_text_from_outputs()](agentui/pipeline/templating.py:124)
- Прямой форвард входящего запроса: [RawForwardNode.run()](agentui/pipeline/executor.py:833)
- Детекция вендора по входному payload: [detect_vendor()](agentui/common/vendors.py:8)
Удачного редактирования!
---
## Пользовательские переменные (SetVars) — «для людей»
Задача: в начале пайплайна положить свои значения и потом использовать их в шаблонах одной строкой — например [[MY_KEY]] или {{ MAX_TOKENS }}.
Где это в UI
- В левой панели добавьте ноду SetVars и откройте её в инспекторе.
- Жмите «Добавить переменную», у каждой переменной есть три поля:
- name — имя переменной (латинские буквы/цифры/подчёркивание, не с цифры): MY_KEY, REGION, MAX_TOKENS
- mode — режим обработки значения:
- string — строка, в которой работают макросы ([[...]] и {{ ... }})
- expr — «мини‑формула» без макросов (подробнее ниже)
- value — собственно значение
Как потом вставлять переменные
- Для строк (URL/заголовки/текст) — квадратные скобки: [[MY_KEY]]
- Для чисел/массивов/объектов — фигурные скобки: {{ MAX_TOKENS }}, {{ GEN_CFG }}
Примеры «как надо»
- Переменная-строка (mode=string):
- name: AUTH
- value: "Bearer [[VAR:incoming.headers.authorization]]"
- Использование в заголовке: "Authorization": "[[AUTH]]"
- Переменная-число (mode=expr):
- name: MAX_TOKENS
- value: 128 + 64
- Использование в JSON: "max_tokens": {{ MAX_TOKENS }}
- Переменная-объект (mode=expr):
- name: GEN_CFG
- value: {"temperature": 0.3, "topP": 0.9, "safe": true}
- Использование: "generationConfig": {{ GEN_CFG }}
Важно про два режима
- string — это «шаблон». Внутри работают все макросы ([[VAR:...]], [[OUT:...]], [[PROMPT]], {{ ... }}). Значение прогоняется через рендер [render_template_simple()](agentui/pipeline/templating.py:184).
- expr — это «мини‑формула». Внутри НЕТ макросов и НЕТ доступа к контексту; только литералы и операции (см. ниже). Вычисляет значение безопасно — без eval, на белом списке AST (реализация: [SetVarsNode._safe_eval_expr()](agentui/pipeline/executor.py:291)).
Что умеет expr (мини‑формулы)
- Числа и арифметика: 128 + 64, (5 * 60) + 30, 42 % 2, -5, 23 // 10
- Строки: "eu" + "-central" → "eu-central" (строки склеиваем знаком +)
- Булева логика: (2 < 3) and (10 % 2 == 0), 1 < 2 < 5
- Коллекции: ["fast", "safe"], {"temperature": 0.3, "topP": 0.9, "safe": true}
- JSONлитералы: true/false/null, объекты и массивы если выражение является чистым JSON, оно разбирается напрямую (без макросов), т.е. trueTrue, nullNone и т.п.
- Запрещено: функции (кроме специально разрешённых ниже), доступ к переменным/контексту, атрибуты/индексация/условные выражения.
Рандом в expr
- В expr доступны три простые функции случайности:
- rand() число с плавающей точкой в диапазоне [0, 1)
- randint(a, b) целое число от a до b включительно
- choice(list) случайный элемент из списка/кортежа
- Примеры:
- name: RAND_F, mode: expr, value: rand()
- "temperature": {{ RAND_F }}
- name: DICE, mode: expr, value: randint(1, 6)
- "dice_roll": {{ DICE }}
- name: PICK_MODEL, mode: expr, value: choice(["gpt-4o-mini", "gpt-4o", "o3-mini"])
- "model": "[[PICK_MODEL]]"
- Зерна/seed нет каждый запуск выдаёт новое значение.
«Почему в expr нельзя подставлять переменные/макросы
- Для безопасности и предсказуемости: expr это закрытый миниязык без окружения.
- Если нужно использовать другие переменные/макросы делайте это в режиме string (там всё рендерится шаблонизатором).
- Технические детали: защита реализована в [SetVarsNode._safe_eval_expr()](agentui/pipeline/executor.py:291), а вставка stringзначений через [render_template_simple()](agentui/pipeline/templating.py:184).
Как это работает внутри (если интересно)
- SetVars исполняется как обычная нода пайплайна и отдаёт {"vars": {...}}.
- Исполнитель добавляет эти значения в контекст для последующих нод как context.vars (см. [PipelineExecutor.run()](agentui/pipeline/executor.py:131)).
- При рендере шаблонов:
- [[NAME]] и {{ NAME }} подставляются с приоритетом из пользовательских переменных (см. обработку в [render_template_simple()](agentui/pipeline/templating.py:184)).
- Сам SetVars считает переменные в порядке списка и возвращает их одним пакетом (внутри одной ноды значения не зависят друг от друга).
Частые вопросы
- «Хочу собрать строку с частями из внешнего запроса»: делайте mode=string и пишите: "Bearer [[VAR:incoming.headers.authorization]]".
- «Хочу массив случайных чисел»: mode=expr [rand(), rand(), rand()], а в JSON: "numbers": {{ MY_LIST }}
- «Почему мои значения не сохраняются нажмите «Сохранить параметры» в инспекторе ноды, затем «Сохранить пайплайн» в шапке. UI синхронизирует данные в node.data и сохраняет в pipeline.json (см. [static/editor.html](static/editor.html)).
Ссылки на реализацию (для любопытных)
- Нода переменных: [SetVarsNode](agentui/pipeline/executor.py:264), [SetVarsNode._safe_eval_expr()](agentui/pipeline/executor.py:291), [SetVarsNode.run()](agentui/pipeline/executor.py:354)
- Исполнитель/контекст vars: [PipelineExecutor.run()](agentui/pipeline/executor.py:131)
- Шаблоны и макросы (включая «голые» [[NAME]]/{{ NAME }}): [render_template_simple()](agentui/pipeline/templating.py:184)