--- title: Nodes UI Flow emoji: 🤖 colorFrom: blue colorTo: indigo sdk: docker app_port: 7860 pinned: false --- # Nodes UI Flow Визуальный редактор интерактивных AI-сценариев: сценарий собирается из нод, запускается пошагово, задает вопросы пользователю, сохраняет ответы в память, ветвится по смыслу и может отвечать по knowledge-файлам. Проект сейчас содержит пример для RosUpack 2026, но ноды сделаны универсальными: такой же граф можно собрать для другого стенда, продукта или процесса. ## Что внутри - React + React Flow интерфейс для сборки графов. - FastAPI backend для LLM-запросов, классификации, извлечения памяти и ответов по файлам. - Выбор LLM provider в настройках: Ollama или DeepInfra. - Перефразирование реплик ассистента при запуске нод, чтобы сценарий не звучал одинаково каждый раз. - `LLM Test` режим: LLM сама проходит сценарий, а evaluator проверяет вопросы и ответы ассистента. - Сохранение workflow в JSON. - Knowledge-файлы, привязанные к конкретной `Knowledge Answer` ноде. ## Быстрый запуск на Windows Ollama запускается отдельно вручную. ```bat start_interface.bat ``` Скрипт откроет два окна: - backend: `http://localhost:8000` - frontend: `http://localhost:5173` Остановить интерфейс можно закрытием этих двух окон. ## Ручной запуск Backend: ```powershell cd backend python -m venv .venv .\.venv\Scripts\activate pip install -r requirements.txt python main.py ``` Frontend: ```powershell npm install npm run dev ``` Production build: ```powershell npm run build ``` ## Структура проекта ```text backend/ FastAPI backend public/ frontend config and presets scenarios/ dialog/ markdown versions of scenario scripts knowledge/ curated knowledge bases for Knowledge Answer nodes source/ original source documents src/ React app, nodes and workflow runtime workflows/ saved workflow JSON graphs archive/ old or experimental workflow snapshots start_interface.bat one-click Windows launcher ``` Runtime/generated folders are intentionally ignored by git: ```text dist/ node_modules/ backend/.venv/ knowledge_contexts/ test_logs/ transcript_logs/ ``` ## Основной workflow Главный пример: ```text workflows/full_workflow.json ``` Knowledge base для него: ```text scenarios/knowledge/rosupack_2026_knowledge_base.md ``` В `Knowledge Answer` ноде путь к файлу сохраняется прямо в JSON workflow, поэтому граф можно открыть после clone и продолжить использовать без повторного upload, если файл лежит в репозитории. ## Как устроен интерактивный сценарий Типичный поток: ```text Question -> Save Memory -> Assistant Message -> Semantic Branch -> Question/Message/... -> Knowledge Answer -> Restart ``` Runtime идет до первой `Question`, показывает вопрос в нижней панели и ждет ответ пользователя. Ответ можно: - ввести руками; - сгенерировать кнопкой `LLM answer`; - включить `Auto LLM answer`, чтобы LLM отвечала сама на каждый новый вопрос. Если у ноды включена галочка `Перефразировать при запуске`, backend перед показом реплики отправит текст в выбранный LLM provider и вернет новую формулировку с тем же смыслом. В transcript и дальше по графу попадет именно показанная пользователю версия. ## LLM provider Provider выбирается в `Настройки`: - `Ollama` — локальный режим, backend обращается к `http://localhost:11434`. - `DeepInfra` — облачный OpenAI-compatible endpoint. Для DeepInfra в настройках появляется поле API key. Ключ сохраняется локально в `backend/.deepinfra_api_key`, этот файл игнорируется git. Если ключ уже сохранен, поле можно оставить пустым, чтобы не менять его. Thinking/reasoning в LLM-вызовах отключен: для Ollama backend отправляет `think: false`, для DeepInfra используется `reasoning_effort: none`. ## Основные типы портов Порты окрашиваются по типу/смыслу, а не по цвету ноды. - `turn` — объект одного шага диалога: вопрос, ответ и накопленный dialog. - `dialog` / `dialog-in` — история сообщений. - `question` — текст вопроса. - `answer` — текст ответа пользователя. - `string` — обычный текст. - `object` — структурированные данные. Один input может принимать несколько входящих связей. Это используется, когда несколько веток сходятся в общий блок, например в общий `Еще вопросы?`. ## Ключевые ноды ### Question Задает вопрос ассистента и ставит workflow на паузу до ответа пользователя. Используйте `turn` output, если дальше нужна вся пара вопрос/ответ. Используйте `dialog` или `dialog-in`, если важно сохранить историю реплик. Опция `Перефразировать при запуске` заставляет LLM переписать вопрос перед показом пользователю. ### Assistant Message Показывает реплику ассистента без ожидания пользовательского ответа. Подходит для коротких объяснений, переходов между ветками и финальных историй. Опция `Перефразировать при запуске` работает так же, как в `Question`: смысл сохраняется, формулировка может меняться. ### Save Memory Извлекает значение из ответа пользователя и сохраняет его в память прогона. Пример ключей: ```text name role industry scale ``` Значения доступны в шаблонах через фигурные скобки: ```text {name}, хотели бы узнать что-то еще? ``` Если перед `Save Memory` был retry-переспрос, нода берет последний ответ пользователя из `dialog-in`, а не старый первый ответ из `turn`. Это важно для сценариев вроде проверки имени: пользователь может сначала ответить бессмыслицу, затем назвать имя, и в `{name}` сохранится именно последний корректный ответ. ### Semantic Branch LLM выбирает один выход по смыслу ответа пользователя. Один choice = один output. Альтернативы внутри одного choice пишутся через точку с запятой: ```text да; хочу еще; давай; есть вопрос нет; хватит; вернуться в начало ``` Точка с запятой означает альтернативные формулировки, а не условие, что все фразы должны встретиться одновременно. Если ответ непонятен, `retry on unclear` может сразу переспросить пользователя на этой же точке сценария. У retry-вопроса есть отдельная галочка `Перефразировать unclear-вопрос`, чтобы повторный вопрос звучал живее при нескольких неудачных ответах подряд. ### Knowledge Answer Отвечает на вопрос пользователя по файлу, привязанному к конкретной ноде. Поддерживаются: - `.md` - `.txt` - `.docx` - `.doc` как best-effort text extraction При upload backend сохраняет оригинал и extracted text. Для репозиторных сценариев лучше хранить curated `.md` knowledge base в `scenarios/knowledge/` и указывать этот относительный путь в `contextPath`. ### Restart Перезапускает интерактивный сценарий с начала. Удобно для выставочного сценария: если пользователь больше не хочет задавать вопросы, можно вернуть ассистента в стартовое состояние. ### Request to LLM Отправляет `system` и `user` prompt на backend. Используйте для универсальных LLM-операций, которые не покрыты готовыми специализированными нодами. ### Component Сворачивает часть графа во вложенный компонент. Подходит для повторяющихся блоков, когда сценарий начинает разрастаться. ## Как соединять ноды ### Сохранить имя ```text Question(turn) -> Semantic Branch(turn) Question(turn) -> Save Memory(turn) Semantic Branch(has-name) -> Save Memory(dialog-in) Save Memory(dialog) -> Assistant Message(dialog-in) ``` `Semantic Branch` проверяет, есть ли в ответе имя. Если ответа недостаточно, `retry on unclear` сразу переспросит. `Save Memory` получает старый `turn` и свежий `dialog-in`; приоритет отдается последнему ответу пользователя из `dialog-in`, поэтому после переспроса сохраняется корректное имя. ### Ветвление по смыслу ```text Question(turn) -> Semantic Branch(turn) Semantic Branch(choice A) -> Node A(dialog-in) Semantic Branch(choice B) -> Node B(dialog-in) Semantic Branch(unclear) -> retry или fallback ``` ### Общий финальный блок ```text Branch A final message(dialog) -> Shared Question(dialog-in) Branch B final message(dialog) -> Shared Question(dialog-in) Branch C final message(dialog) -> Shared Question(dialog-in) ``` Так несколько веток сходятся в один общий вопрос без дублирования нод. ### Зацикливание knowledge-вопросов ```text Question "Что узнать?"(turn) -> Knowledge Answer(turn) Knowledge Answer(dialog) -> Question "Еще вопросы?"(dialog-in) ``` Так пользователь может задавать вопросы по файлу, пока не ответит, что больше вопросов нет. ## LLM answer и LLM Test ### LLM answer Разово генерирует ответ пользователя на текущий вопрос. ### Auto LLM answer Автоматически отвечает на каждый новый вопрос тем же prompt-ом тестового пользователя. Prompt хранится в workflow JSON: ```json { "settings": { "llmRolePrompt": "..." } } ``` ### LLM Test Отдельный режим тестирования сценария: 1. LLM проходит сценарий как пользователь. 2. После вопросов/ответов ассистента evaluator проверяет адекватность. 3. Если evaluator видит проблему, в JSONL-лог первым событием пишется причина. 4. Полный trace LLM-запросов сохраняется в `test_logs/`. `LLM Test` можно остановить кнопкой `Stop LLM Test`. ## Логи ### UI logs Правая панель показывает служебные события, ошибки, проверки evaluator и пути к файлам логов. При `Auto LLM answer` и `LLM Test` обычные реплики не дублируются в правый служебный log, потому что они уже видны в transcript. ### Write logs Галочка `Write logs` пишет простой текстовый transcript: ```text ASSISTANT: ... USER: ... ``` Файлы создаются в: ```text transcript_logs// ``` Эта папка не коммитится. ### Test logs `LLM Test` пишет подробные JSONL trace-файлы: ```text test_logs// ``` Если evaluator считает вопрос или ответ плохим, первая строка файла будет `evaluation_failure_summary` с причиной. ## Скриншоты Скриншоты UI лучше хранить отдельно от runtime-логов, например: ```text scenarios/screenshots/ ``` Рекомендуемые скрины для README: - общий вид canvas с RosUpack workflow; - нижняя interactive panel во время прогона; - пример `Knowledge Answer` ноды с привязанным файлом; - пример `Semantic Branch` с альтернативами через `;`. ## Git hygiene В репозиторий должны попадать: - `src/` - `backend/main.py` - `backend/requirements.txt` - `public/` - `workflows/` - `scenarios/` - конфиги приложения В репозиторий не должны попадать: - `node_modules/` - `dist/` - `backend/.venv/` - `knowledge_contexts/` - `test_logs/` - `transcript_logs/` ## GitHub Repository: ```text https://github.com/markitzeroo/nodes-ui-flow ``` Repository is private.