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

Structured output validation в n8n: как заставить AI отдавать безопасный JSON для production

Обновлено: 2026-05-29

Открыть мой план

Короткий ответ

Structured output validation в n8n — это слой между LLM и реальным действием: CRM-записью, API-запросом, созданием тикета, оплатой, рассылкой или маршрутизацией. Модель может вернуть красивый JSON, но это не значит, что он корректен по типам, смыслу, правам и бизнес-правилам. Production workflow должен использовать Structured Output Parser или отдельную LLM-chain, затем валидировать результат в Code node, проверять confidence, evidence и forbidden actions, а все сомнительные случаи отправлять в human review.

Зачем нужна отдельная валидация

Самая опасная ошибка — считать, что “модель попросили вернуть JSON, значит можно сразу отправить результат дальше”. В реальном workflow AI может вернуть лишний текст до JSON, перепутать enum, поставить строку вместо числа, пропустить required поле, придумать source, неверно классифицировать risky action или заполнить поле уверенно, но без доказательств. Если такой ответ сразу уйдёт в CRM, базу, оплату или email, ошибка станет бизнес-инцидентом.

Structured output validation решает три задачи. Первая — техническая: ответ должен быть валидным JSON и соответствовать schema. Вторая — смысловая: значения должны быть допустимыми для процесса. Третья — операционная: workflow должен понимать, что делать при ошибке, низкой уверенности или неполном результате.

Где ставить validation layer

Правильная цепочка выглядит так:

  1. Trigger получает вход: email, chat, webhook, Telegram, CRM event.
  2. Normalize node приводит вход к единому формату.
  3. LLM или AI Agent формирует structured output.
  4. Structured Output Parser задаёт expected schema.
  5. Code node валидирует типы, enum, длины, обязательные поля и бизнес-правила.
  6. IF/Switch решает: auto-action, repair, clarification, human review или deny.
  7. Downstream node выполняет действие только после успешной проверки.
  8. Audit log сохраняет вход, schema version, validation status и decision.

Важно: parser — это не замена бизнес-валидации. Parser помогает модели вернуться к форме, но не знает вашу CRM, стоимость ошибки, права пользователя и downstream constraints.

Минимальная схема ответа

Для production не делайте JSON только из полезных данных. Добавьте служебные поля, которые помогают маршрутизировать ответ.

{
  "schema_version": "1.0",
  "status": "ok",
  "confidence": 0.86,
  "intent": "create_ticket",
  "requires_review": false,
  "result": {
    "priority": "medium",
    "summary": "Клиент не получил письмо с доступом",
    "customer_email": "user@example.com"
  },
  "evidence": [
    {"source_id": "email_body", "quote": "письмо с доступом не пришло"}
  ],
  "error_code": null,
  "human_message": "Создать тикет со средним приоритетом"
}

Поля status, confidence, requires_review, error_code и evidence нужны не для красоты. Они позволяют workflow безопасно решать, что делать дальше. Без них следующему node остаётся только доверять модели.

Что проверять в Code node

В Code node проверяйте не только JSON.parse. Список production-проверок:

Проверка Зачем нужна
required fields downstream node не должен падать из-за пустого значения
enum AI не должен придумать новый статус, которого нет в CRM
type check числа, boolean, arrays и dates должны быть ожидаемого типа
length limits защита от слишком длинных summaries и prompt injection
forbidden fields AI не должен передавать поля, которые workflow не разрешает
confidence threshold низкая уверенность не должна идти в auto-action
evidence required важные решения должны ссылаться на входные данные
idempotency key повторный execution не должен создавать дубли

Пример базовой проверки:

const data = $json;
const errors = [];

const allowedStatus = ['ok', 'needs_review', 'no_data', 'error'];
const allowedPriority = ['low', 'medium', 'high', 'urgent'];

if (!allowedStatus.includes(data.status)) errors.push('invalid_status');
if (typeof data.confidence !== 'number') errors.push('confidence_not_number');
if (data.confidence < 0 || data.confidence > 1) errors.push('confidence_out_of_range');
if (!data.result || typeof data.result !== 'object') errors.push('missing_result');

if (data.result?.priority && !allowedPriority.includes(data.result.priority)) {
  errors.push('invalid_priority');
}

if (data.status === 'ok' && data.confidence < 0.75) {
  errors.push('low_confidence_for_auto_action');
}

if (data.requires_review === false && data.intent === 'refund_payment') {
  errors.push('dangerous_action_without_review');
}

return [{
  json: {
    ...data,
    validation: {
      passed: errors.length === 0,
      errors
    }
  }
}];

Когда делать repair, а когда review

Repair-chain полезна, если ошибка техническая: лишний текст, неправильная кавычка, поле confidence пришло строкой, отсутствует необязательное поле. Но repair не должен превращаться в “AI сам себя убедил”. Если ошибка смысловая, например модель предлагает вернуть деньги, удалить запись, отправить письмо клиенту или меняет статус сделки без evidence, нужен review.

Ошибка Действие
JSON не парсится repair-chain один раз, затем fallback
отсутствует required поле clarification или review
неверный enum repair, если значение очевидно; иначе review
confidence низкий review или уточняющий вопрос
нет evidence no-answer или review
dangerous action approval обязателен
PII в запрещённом поле redact + review

Ограничьте repair одним повтором. Если после repair ответ снова невалидный, не запускайте бесконечный loop. Запишите error, верните безопасный ответ и отправьте кейс на разбор.

Validation для AI Agent

С агентами сложнее, потому что они могут вызывать tools и строить промежуточные рассуждения. Для production часто надёжнее разделить роли: AI Agent решает, какой tool нужен, а отдельная LLM-chain или Structured Output Parser формирует финальный JSON. После этого Code node валидирует output. Так вы не смешиваете tool orchestration и финальный контракт.

Если agent вызывает tools, валидируйте не только ответ, но и параметры tool call. Например, tool create_crm_task не должен принимать произвольный owner_id, если пользователь не имеет права назначать задачи. Tool send_email не должен принимать внешний recipient без allowlist или review. Tool refund_payment всегда должен требовать human approval.

Логирование validation

Пишите в журнал не только ошибку, но и контекст:

{
  "trace_id": "ai_2026_05_29_001",
  "workflow_id": "wf_support_triage",
  "schema_version": "1.0",
  "prompt_version": "triage_v7",
  "model": "configured_model_name",
  "validation_passed": false,
  "validation_errors": ["low_confidence_for_auto_action"],
  "decision": "human_review",
  "input_hash": "sha256:...",
  "execution_id": "12345"
}

Не логируйте персональные данные без необходимости. Для debugging лучше хранить hash, trace_id, тип ошибки и ссылку на защищённый execution, чем копировать весь email клиента в общий лог.

Production checklist

Перед запуском проверьте:

  • есть schema_version;
  • downstream node не получает сырой текст модели;
  • все enum перечислены явно;
  • низкий confidence не идёт в auto-action;
  • dangerous actions требуют approval;
  • repair-chain не запускается бесконечно;
  • errors имеют коды, а не только текст;
  • audit log не содержит лишнюю PII;
  • есть тесты на invalid JSON, missing field, wrong enum, hallucinated source и dangerous action.

Частые ошибки

Первая ошибка — писать в prompt “верни валидный JSON” и не проверять результат. Вторая — делать одну огромную schema на все случаи жизни. Третья — доверять confidence, который сама модель придумала. Четвёртая — ремонтировать смысловые ошибки через LLM вместо review. Пятая — менять schema без версии, из-за чего старые executions становятся непонятными.

FAQ

Можно ли доверять JSON, который вернула модель?
Нет. Даже при хорошей инструкции модель может вернуть лишний текст, неполные поля, неверный enum, строку вместо числа или валидный JSON с неверным смыслом. Поэтому нужен отдельный слой валидации после LLM.

Что лучше: Structured Output Parser или Code node?
Structured Output Parser задаёт контракт на уровне LLM-цепочки, а Code node проверяет результат перед записью в CRM, базу или API. В production обычно нужны оба слоя.

Когда нужен repair-chain?
Repair-chain нужен, когда ответ близок к правильному, но не проходит схему: лишняя запятая, неверный тип поля, отсутствует необязательный текст. Не используйте repair для критичных действий без повторной проверки.

Какие поля обязательно добавлять в structured output?
Минимум: status, confidence, result, error_code, human_message, source_ids или evidence, requires_review. Для действий добавьте idempotency_key и action_preview.

Что делать при низком confidence?
Не выполнять автоматическое действие. Отправьте ответ на human review, уточните вопрос у пользователя или верните безопасный fallback.