Компиляция потока в Сценарий
Превратите многошаговый процесс в состоятельный направленный граф — создавайте, проверяйте, публикуйте.
create_storylinevalidate_storylinepublish_storylinelist_storylinesupdate_storylineStoryline — это направленный граф, привязанный к агенту: он превращает «ответить на один вопрос» в «выполнить задачу от начала до конца» (сбор данных, обучение, коучинг…). Узлы — это шаги (каждый со своей задачей / навыками / kb / инструментами и изменяемыми измерениями профиля); выходы несут условия (ai / user_choice / rule / callback / goto_storyline). Runtime никогда не редактирует «душу» агента или его границы безопасности — она постоянна от первого узла до последнего, что именно то, что нужно для регулируемых продуктов или продуктов для детей.
Создать черновик
create_storyline(
agent_name="Support", key="loan-intake", name="Loan intake",
profile_schema={"docs_ready": {"type": "bool"}}, # dims that accumulate across nodes
graph={"nodes": [
{"node_key": "n1", "title": "Understand need", "flags": {"is_entry": True},
"on_enter_opening": "Hi — which kind of loan are you applying for?",
"exits": [{"kind": "ai", "label": "need clear", "to_node_key": "n2",
"ai_criteria": "the user stated the loan type and rough amount"}]},
{"node_key": "n2", "title": "Collect documents",
"task": "Collect the checklist items; chase missing ones across turns.",
"exits": [{"kind": "user_choice", "label": "documents ready", "to_node_key": "n3",
"user_choice": {"button_text": "I've uploaded everything"},
"writes": [{"ref": "dim", "key": "docs_ready", "op": "set", "value": True}]}]},
{"node_key": "n3", "title": "Hand off", "task": "Summarise the case and hand off to a human.",
"flags": {"is_terminal": True}, "exits": []}
]},
allow_agent_enroll=True,
enroll_trigger="the visitor says they want to apply for a loan",
)★ Проверить, затем опубликовать ★
validate_storyline(storyline_id="…") # → {"ok": true} is required to publish
publish_storyline(storyline_id="…") # freezes an immutable version and goes liveEnroll — кто входит и когда (требуется публикация)
is_default=True— один на агента; авто-enroll при первом разговоре.allow_agent_enroll=True+enroll_trigger— агент делает enroll пользователя, когда считает триггер выполненным.entry="user"(или"both") — поток отображается в меню guided-flgets виджета чата и в выпадающем списке New-chat, поэтому пользователь запускает его намеренно (кнопка, а не решение модели). Задайтеdisplay_nameи однострочноеdescription— это то, что показывает меню. В сочетании сconcurrency="session"для потоков «один кейс на разговор»: каждый выбор открывает новый кейс.- Ручное назначение в консоли.
Что видит пользователь — видимость, баннер и карта только для чтения
user_visibility управляет представлением для конечного пользователя запущенного потока (по умолчанию invisible):
invisible— никакого UI; поток работает тихо (прежнее поведение).named— тонкий баннер над чатом показывает имя потока. Ничего больше.trail— баннер + кнопка View, открывающая карту только для чтения: пройденные шаги сохраняют свои заголовки; непройденные ветки и будущие шаги — анонимные серые блоки (редактируется на сервере — пользователь видит длину потока, но не его содержимое).full— баннер с шагомx / y+ полная карта: каждый шаг именован, раскрашен в зависимости от статуса done / current / upcoming.
Дополнительно: allow_exit=True добавляет кнопку Exit в баннер (выходящий из потока поток не делает авто-enroll в этом разговоре; поток, выбранный пользователем, может быть перезапущен из меню, прогресс сохраняется). show_profile=True отображает текущие значения измерений профиля под картой (числа в виде прогресс-баров, если схема объявляет min/max). Для каждого узла rewind: "reset" | "keep" позволяет пользователю нажать на пройденный шаг в полной карте и вернуться к нему — reset восстанавливает снимок профиля, сделанный при входе, keep сохраняет собранные данные (потоки обучения/проверки). Реальные побочные эффекты (поданные записи, отправленные документы) никогда не откатываются, поэтому отмечайте только шаги без побочных эффектов. В IM-каналах (Telegram/WhatsApp) команда /storyline сообщает о текущем потоке и, для trail/full, возвращает короткоживущую подписанную ссылку на ту же карту только для чтения.
Устаревшее имя параметра learner_visibility и его значения hidden / completed_only всё ещё принимаются (они отображаются в invisible / trail), но устарели — используйте user_visibility.
Конкурентность — следует ли прогресс за человеком или за кейсом?
concurrency решает, сколько запусков один пользователь может иметь на этой линии:
"user"(по умолчанию) — один запуск на человека; каждый разговор продолжает тот же прогресс. Подходит для учебных программ, онбординга, KYC: «насколько далеко зашёл этот человек»."session"— один запуск на разговор; новый чат начинает новый независимый кейс. Подходит для заявок на лицензию, тикетов поддержки, потоков по продукту: «насколько далеко зашёл этот кейс». Один и тот же пользователь может запустить три заявки на продукт в трёх чатах, каждый со своим прогрессом и blackboard.
Размещайте состояние там, где оно должно быть: состояние кейса на blackboard (он живёт и умирает вместе с запуском — название продукта, список документов этого приложения), факты о человеке в измерениях профиля (они следуют за пользователем между запусками и storylines — детали компании, подтверждённая личность). Один кейс на разговор — это намеренно: чтобы открыть другой кейс, откройте другой чат. Изменение concurrency влияет только на будущие enrollments; запуски, уже находящиеся в работе, сохраняют свой ключ.
Чеклисты, заблокированные выборы, файлы и детерминированные действия
Четыре возможности на уровне узла превращают «ИИ решает, когда мы закончили» в накопленное, детерминированное состояние:
checklist—[{key, label}, …]на узле. Каждый ход платформа отмечает пункты из того, что посетитель фактически предоставляет (загрузки или описания с конкретными деталями — обещания не учитываются), и правило выхода{"op": ">=", "left": {"ref": "checklist"}, "right": {"value": 1}}продвигает момент, когда всё отмечено. Карта только для чтения показывает пользователю живой список ✓/○. Это правильная форма для потоков заявок/одобрения: шаг 1 объявляет, что нужно, шаг 2 с помощью чеклиста собирает это по пунктам.choices_offer: "on_ready"— темп в стиле игр для кнопок выбора: они остаются скрытыми (и текстовое совпадение с ними отключено — нельзя пропустить вперёд, напечатав слово кнопки), пока шаг не будет завершён — чеклист завершён илиchoices_ready_criteria, которую вы предоставляете, признана истинной. Используйтеuser_choiceдля настоящих решений между альтернативами; одинокая кнопка «продолжить» — это признак проблемы.{"ref": "files"}в правилах выхода — количество загруженных файлов/изображений пока этот узел активен (сбрасывается при переходе).files >= 2— полностью детерминированный шлюз «документы получены».questions— ледокольные чипсы на уровне узла (макс. 6): вопросы, которые пользователь, вероятно, задаст на этом шаге, отображаются как нажимаемые предложения, пока он находится на нём. В сочетании сon_enter_opening, чтобы каждый шаг представлял себя и предлагал способ входа — пользователь никогда не должен задуматься «что мне здесь supposed делать».on_enter_actions/on_complete_actions—[{tool, args}]платформа выполняет детерминированно, когда шаг входит / завершает поток (например, подаёт лид с помощьюmcp__agent4__submit_leadна терминальном шаге). Строковые аргументы интерполируют ключи измерений и blackboard с помощью шаблонов в фигурных скобках. Ошибки логируются и никогда не ломают чат.
Контекст остаётся плоским независимо от длины storyline: каждый ход инжектирует только текущий узел (задача, ресурсы, выборы), измерения профиля и blackboard с ограничением размера — никогда не весь граф или прошлые шаги. Долгие путешествия (учебный год, сезонная игровая арка) должны быть связаны storylines (on_complete: goto_next): blackboard каждой линии начинается заново, пока измерения профиля переносятся, что и есть «подвести итог прошлому, сохранить настоящее дословно».
Судья выхода теперь видит окно недавних разговоров и собранное состояние, а не только последнее сообщение — но держите ai_criteria о том, что посетитель сказал или сделал; механизм чеклиста выше, чем любые текстовые критерии.
Ловушки дизайна — каждая из них привела к зависшему потоку в продакшене
Вы (агент, строящий это) — наиболее вероятный автор этих багов. Проверьте каждый перед публикацией:
- Выход
ruleтребует писателя.readiness >= 100— тупик, если никто фактически не пишетreadiness:writesвыхода (детерминированный — предпочтительно),profile_writesузла сsource: "ai"(оценено из разговора), другой storyline или ручные изменения в консоли.validate_storylineтеперь помечает это какwarn.rule_unwritten_dim— относитесь к этому предупреждению как к багу, если вы не знаете о внешнем писателе. Эта ошибка однажды попала в продакшен: трёхшаговый сбор данных, второй шаг которого блокировался на измерении, которое никто не писал; пользователи никогда не могли пройти его. - Оценённые ИИ измерения почти никогда не достигают точных границ. Если измерение оценивается моделью,
>= 100(или== max) практически никогда не срабатывает — модели оценивают консервативно. Блокируйте на реалистичном пороге (>= 70), или сделайте завершение шагаuser_choiceи используйтеwritesвыхода для детерминированной установки значения. user_choiceточно совпадает с текстом кнопки — и метка должна говорить, что она делает. Сообщение посетителя должно равнятьсяbutton_text. На видимых линиях виджет отображает их как настоящие кнопки, поэтому пишите полные, точные глагольные фразы — «Начать сбор документов», а не «Начать» (начать что? — реальная обратная связь от тестирования). Держите их разными и на языке аудитории. Наinvisibleлиниях нет кнопок — повторите варианты вtaskузла. Предпочитайтеuser_choiceдля настоящих решений (какая ветка, отправить или продолжать редактирование); «закончил ли я этот шаг» — задача ИИ/выходов rule, а не кнопки.- Публикация не затрагивает запуски, уже находящиеся в работе. Enrollments остаются привязанными к ревизии, на которой они начались — выпуск с исправлением багов достигает только новых запусков. Чтобы переместить существующих пользователей, вызовите
POST /storylines/{id}/enrollments/migrate(resetобратно к входу илиmoveк узлу — оба повторно привязывают запуск к текущей опубликованной ревизии). - Пройдите линию как пользователь перед тем, как передать её. Откройте страницу
/s/из ссылки, войдите в поток, пройдите через каждую кнопку и ветку до конца. Тестовый запуск редактора симулирует граф; только реальная страница проверяет открытия, кнопки, видимость и завершение вместе.
Выходы упорядочены по приоритету (порядок в списке): детерминированные rule / user_choice / callback оцениваются первыми, ai последним. Стройте if/else, циклы повторных попыток и AND-соединения из детерминированных выходов — не играйте в лотерею с LLM. Редактируйте черновик с помощью update_storyline (семантика PUT; держите каждый node_key стабильным, так как выходы и воронка ссылаются на него).
Верните отчёт. Верните ссылку на консоль опубликованного Storyline —
https://console.agent4.io/#/storylines/<id>(id изcreate_storyline) — с однострочным резюме потока и тем, как пользователь входит в него.