Перейти к содержанию

7. Смотрим, как он работает

Граф готов. Осталось увидеть его в работе: какой узел сейчас исполняется, что лежит во фрейме, какой дорогой ушло решение.

В ядре есть пошаговый отладчик, а редактор — фронтенд к нему. Оба останавливаются между узлами, показывают фрейм и дают его править.

Из Python

from stageflow import Pipeline, Session, StepDebugger

debugger = StepDebugger(mode="step", delay=0.0, on_event=print)
session = Session("run-1", Pipeline.from_dict(data), debugger=debugger)
task = asyncio.create_task(session.run())   # остановится перед первым узлом

debugger.step()                  # один узел и снова стоп
debugger.set_vars({"ticket_id": "T-1006"})
debugger.resume()                # доиграть до конца
result = await task

В редакторе

«Run» → «Debug step by step» сначала спрашивает стартовые переменные. Значения из узла entry стоят подсказками в полях; заполненное поле переопределяет значение только для этого запуска.

Диалог со стартовыми переменными

Дальше запуск останавливается перед первым узлом и ждёт.

Отладчик остановился перед узлом

Кнопки — это команды отладчика: продолжить, шаг, стоп и пауза между узлами в миллисекундах.

Управление отладчиком

Фрейм

Слева — фрейм в точке остановки, и каждое значение в нём можно править. Запись применяется перед следующим узлом и проверяется по объявленному типу; о несовпадении сообщает событие var_rejected, запуск при этом не ломается.

Это самый быстрый способ попасть на дорогу, которую иначе трудно вызвать. Остановите запуск перед route, поставьте urgency в high — и тикет, которому уже готовился ответ, уйдёт человеку.

События

Справа — всё, что запуск сообщает о себе: в какой узел вошли и из какого вышли, какая стадия началась и закончилась, какой случай выбрал switch, какой обработчик сработал у try.

Лог запуска, который потерял модель и ушёл на резервную дорогу

Три строки рассказывают всю историю шага 5: стадия упала, try поймал, исполнение продолжилось с rules.

Результат

Запуск заканчивает terminal. В шапке панели видны результат и артефакты, а фрейм остаётся на месте и его можно дочитать:

Завершённый запуск

Средняя колонка — текстовый поток. Туда попадает любое событие, у которого payload выглядит как {"stream": true, "text": "…", "label": "…"}, так что за стадией, которая пишет ответ по частям, можно следить по ходу дела:

Ответ, каким он приходил

self.emit("reply_chunk", {"stream": True, "text": word + " ", "label": "Reply"})

Ключи

Стадии с моделью нужен API-ключ, а ключу нечего делать в JSON пайплайна, который экспортируют и пересылают. Отдайте его серверу:

SF_SECRET_OPENAI_API_KEY=sk-… python main.py

Редактор спрашивает у бэкенда, какие у того есть секреты, и получает только имена. Пайплайн читает имя как обычную переменную (api_key ← OPENAI_API_KEY), бэкенд подставляет значение при запуске, а на обратном пути в браузер везде вместо значения идёт ••••••••.

Хранилище секретов в редакторе

Ключи, введённые в самом редакторе, живут в браузере, в JSON не попадают и отправляются вместе с запуском.

Это и есть бот

Семь шагов, и все типы узлов появились: entry, stage, condition, switch, parallel, try, subpipeline, terminal. Подробности по каждому — в справочнике, а готовые пайплайны, стадии и данные — в репозитории примера.