Перейти к содержимому

Система валидации

Moira выполняет всестороннюю валидацию на нескольких уровнях для обеспечения целостности workflow и корректности ответов агентов.

Workflow валидируются против определения JSON Schema:

  • Валидация структуры против схемы workflow
  • Проверка обязательных полей (id, metadata, nodes)
  • Валидация типов для всех свойств
  • Валидация enum для типов нод

Структура графа анализируется на корректность:

  • Связность нод - Все connections указывают на валидные ноды
  • Обязательные ноды - Нода start должна существовать
  • Циклические зависимости - Циклы обнаруживаются и помечаются
  • Недостижимые ноды - Ноды не связанные от start
  • Записи реестра - Каждая запись variableRegistry должна быть валидной JSON Schema (некорректный items/pattern/и т.п. — blocking-ошибка) с непустым описанием

Ответы агентов валидируются против inputSchema:

  • Валидация JSON Schema на основе AJV
  • Проверка типов для полей ответа
  • Валидация обязательных полей
  • Валидация pattern и format

Валидация возвращает структурированные результаты:

{
valid: boolean;
errors: ValidationError[];
warnings: ValidationWarning[];
}
ТипОписаниеПример
schemaНевалидная JSON структураОтсутствует обязательное поле
structureНевалидная структура графаOrphan нода
connectionНевалидное соединениеУказывает на несуществующую ноду
referenceНевалидная ссылкаНевалидный subgraph ID
ТипОписаниеПорог
performanceБольшой workflow>20 agent-directive нод
complexityСложные условияГлубоко вложенные условия
contextБольшой контекст>100KB размер контекста
{
"id": "valid-workflow",
"metadata": {
"name": "Valid Workflow",
"version": "1.0.0",
"description": "A valid workflow"
},
"nodes": [
{ "id": "start", "type": "start", "connections": { "default": "task" } },
{
"id": "task",
"type": "agent-directive",
"directive": "...",
"completionCondition": "...",
"connections": { "success": "end" }
},
{ "id": "end", "type": "end" }
]
}

Результат:

{ "valid": true, "errors": [], "warnings": [] }
{
"nodes": [
{ "id": "start", "type": "start", "connections": { "default": "missing" } },
{ "id": "end", "type": "end" }
]
}

Результат:

{
"valid": false,
"errors": [
{
"type": "connection",
"message": "Node 'start' references non-existent node 'missing'",
"nodeId": "start"
}
]
}

Большой workflow вызывает предупреждение о производительности:

{
"valid": true,
"errors": [],
"warnings": [
{
"type": "performance",
"message": "Workflow has 25 agent-directive nodes. Consider breaking into subgraphs.",
"count": 25
}
]
}

Ответы агентов валидируются против inputSchema определенной на agent-directive нодах.

Ноды без inputSchema требуют пустой ввод от агента. Непустые ответы отклоняются:

// Нода без inputSchema
{ "id": "task", "type": "agent-directive", "directive": "..." }
// Валидно: пустой ответ
{}
// Невалидно: непустой ответ
{ "result": "done" } // Отклоняется с ошибкой валидации
{
"type": "agent-directive",
"inputSchema": {
"type": "object",
"properties": {
"result": { "type": "string" },
"confidence": { "type": "number", "minimum": 0, "maximum": 10 }
},
"required": ["result"]
}
}
{ "result": "completed", "confidence": 8 }
{ "confidence": "high" }

Ошибка:

{
"valid": false,
"errors": [
{ "field": "result", "message": "Required field missing" },
{ "field": "confidence", "message": "Expected number, got string" }
]
}

Предупреждение о переменной, объявленной без default

Заголовок раздела «Предупреждение о переменной, объявленной без default»

Валидатор выдаёт warning (severity warning, не ошибка — workflow остаётся валидным), когда переменная из variableRegistry используется в directive, completionCondition, message или condition, но у переменной нет default и её не записывает ни один вышестоящий узел через globalInputs (и она отсутствует в initialData стартового узла).

В рантайме такая ссылка отображается как литеральный плейсхолдер [[UNDEFINED_VARIABLE]] вместо значения.

{
"valid": true,
"errors": [],
"warnings": [
{
"type": "structure",
"severity": "warning",
"nodeId": "do-work",
"message": "Variable 'iteration' is referenced in node 'do-work' but has no default and is never written by an upstream node. It will render [[UNDEFINED_VARIABLE]] at runtime."
}
]
}

Исправить можно одним из двух способов:

  • Добавить default для переменной в variableRegistry.
  • Сделать так, чтобы вышестоящий узел записывал переменную через globalInputs до узла, который на неё ссылается.

Подставленные ЗНАЧЕНИЯ переменных и данных никогда не выполняются повторно как шаблоны. Когда движок подставляет значение в directive или message, это значение трактуется как литеральная строка — синтаксис фигурных скобок, пришедший из подставленных данных, нейтрализуется и не парсится повторно.

Это означает, что шаблоны выполняются только в статических полях узла, контролируемых автором, а не в значениях, которые приходят из ввода агента или внешних данных.

  1. Всегда включайте inputSchema - Валидируйте ответы агентов для консистентных данных
  2. Держите workflow сфокусированными - Разбивайте большие workflow на subgraphs
  3. Тестируйте валидацию - Используйте manage с includeValidation: true
  4. Обрабатывайте ошибки gracefully - Определяйте error connections для ошибок валидации