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

Structured Output JSON в n8n: как спроектировать схему ответа, которую можно передавать в CRM, БД и API

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

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

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

Structured Output JSON в n8n — это контракт между AI node и остальным workflow. Он должен быть спроектирован не как “удобный ответ модели”, а как стабильный формат для IF, Switch, CRM, Postgres, HTTP Request, approval и логирования. Хороший JSON содержит schema_version, status, confidence, result, evidence, error_code и поля, которые downstream действительно умеет обработать. Плохой JSON выглядит красиво, но ломает workflow: смешивает null и пустые строки, придумывает enum, меняет типы, отдаёт вложенность без версии и не объясняет, почему результат можно использовать.

Почему схема важнее prompt

Prompt говорит модели, что сделать. JSON-схема говорит workflow, что он получит. Если schema размыта, каждый следующий node вынужден угадывать смысл. Например, поле priority может прийти как high, urgent, important, критично, 1 или true. Человек поймёт, а автоматизация — нет. В production это ведёт к неправильной маршрутизации, падениям API, дублям и ручным исправлениям.

Схема должна проектироваться от downstream. Сначала ответьте: куда пойдёт результат? В CRM? В Postgres? В email draft? В ticketing system? В RAG source filter? В approval card? Потом определите поля, типы, enum, required и error behavior.

Базовый шаблон structured output

Для большинства AI workflow удобно начинать с такой структуры:

{
  "schema_version": "1.0",
  "status": "ok",
  "confidence": 0.82,
  "result": {},
  "evidence": [],
  "warnings": [],
  "requires_review": false,
  "error_code": null,
  "human_message": ""
}

status отвечает на вопрос “можно ли использовать результат”. confidence помогает routing. result содержит бизнес-данные. evidence показывает, на чём основан вывод. warnings не блокируют workflow, но помогают оператору. requires_review переводит кейс в approval. error_code нужен для машинной обработки. human_message — короткое объяснение для пользователя или ревьюера.

Как проектировать result

Не кладите всё в один текст. Если AI извлекает лид, result должен быть структурой:

{
  "lead_type": "b2b",
  "company_name": "Ромашка ООО",
  "contact_name": "Анна",
  "email": "anna@example.com",
  "phone": null,
  "budget_range": "unknown",
  "need": "автоматизация заявок из Telegram в CRM",
  "urgency": "this_month"
}

Для классификации:

{
  "category": "billing",
  "subcategory": "invoice_missing",
  "priority": "medium",
  "language": "ru",
  "route_to": "finance_support"
}

Для action request:

{
  "action": "create_task",
  "target_system": "crm",
  "idempotency_key": "ticket_1021_create_task",
  "action_preview": "Создать задачу для менеджера по счёту INV-44",
  "parameters": {
    "task_title": "Проверить счёт INV-44",
    "due_date": "2026-05-30"
  }
}

В action-схемах idempotency_key обязателен. Иначе повторный execution или retry может создать дубли.

Required fields и nullable values

Главное правило: required означает “workflow не может продолжить работу без этого поля”. Не делайте required всё подряд. Например, email может быть необязательным, если пользователь написал только телефон. Но status, schema_version, confidence и ключевая классификация часто должны быть required.

Определите политику отсутствующих значений:

Ситуация Как писать в JSON
значение неизвестно null
список пуст []
действие невозможно status: no_data или status: blocked
поле не применимо null + warning
ошибка обработки status: error + error_code

Не используйте одновременно null, "", "unknown", "n/a" и false для одного смысла. Downstream станет хрупким.

Enum: меньше свободы, больше стабильности

Enum защищает workflow от фантазии модели. Вместо свободного priority задайте:

{
  "priority": "low | medium | high | urgent"
}

Но в production мало написать enum в prompt. Проверьте его в Code node. Если модель вернула critical, решите заранее: маппить в urgent, отправлять на repair или review. Не позволяйте новым значениям тихо проходить в CRM.

Массивы и вложенность

Массивы нужны для items, evidence, warnings, tasks, extracted_entities. Но они часто ломаются: модель возвращает объект вместо массива, пустую строку вместо [] или добавляет разные структуры внутри одного списка.

Хорошая структура evidence:

{
  "evidence": [
    {
      "source_id": "email_body",
      "quote": "не можем оплатить счёт",
      "supports_field": "category"
    }
  ]
}

Плохая структура:

{
  "evidence": "клиент сказал, что не может оплатить"
}

Почему плохо: downstream не сможет фильтровать evidence, привязать цитату к полю и показать ревьюеру источник.

Error codes для workflow

Не возвращайте только “не получилось”. Ошибка должна быть машинно читаемой:

Код Что означает Что делает workflow
missing_required_input не хватает входных данных уточняющий вопрос
low_confidence модель не уверена human review
no_relevant_source RAG не нашёл источник no-answer policy
invalid_user_permission пользователь не имеет права deny
schema_validation_failed JSON не прошёл проверку repair или fallback
unsafe_action действие рискованное approval

Такой подход позволяет строить Switch node без хаоса.

Версионирование схемы

Добавьте schema_version с первого дня. Менять версию нужно, если вы:

  • добавили required field;
  • удалили поле;
  • изменили enum;
  • поменяли смысл поля;
  • перенесли данные во вложенный объект;
  • изменили error policy.

Старые executions должны оставаться понятными. Если раньше priority был 1/2/3, а теперь low/medium/high, не смешивайте версии в одном отчёте.

Пример валидации схемы в n8n

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

if (x.schema_version !== '1.0') errors.push('unsupported_schema_version');
if (!['ok','no_data','needs_review','blocked','error'].includes(x.status)) errors.push('bad_status');
if (typeof x.confidence !== 'number') errors.push('bad_confidence');
if (x.evidence && !Array.isArray(x.evidence)) errors.push('evidence_not_array');
if (x.warnings && !Array.isArray(x.warnings)) errors.push('warnings_not_array');

if (x.status === 'ok' && !x.result) errors.push('ok_without_result');
if (x.status === 'no_data' && !x.human_message) errors.push('no_data_without_message');

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

Как не перегрузить схему

Одна из частых ошибок — сделать универсальный JSON для всех AI-задач: классификация, суммаризация, извлечение, scoring, action request и RAG answer одновременно. Такая схема становится длинной, модель путается, а редактору сложно поддерживать её руками. Лучше сделать отдельные схемы под разные типы outputs.

Принцип простой: один output — одна бизнес-задача. Если workflow сначала классифицирует обращение, потом извлекает данные, потом пишет черновик ответа, используйте три маленьких контракта. Это проще тестировать, логировать и чинить.

FAQ

Чем structured output JSON отличается от обычного ответа AI?
Обычный ответ предназначен для человека. Structured output JSON — контракт для следующего node: CRM, БД, API, Router, IF или approval workflow.

Можно ли делать очень большую JSON Schema?
Можно, но это ухудшает стабильность. Лучше делать схему по задаче: extraction, classification, routing, draft generation или action request. Для сложных процессов используйте несколько маленьких схем.

Нужно ли добавлять поле confidence?
Да, но не как единственный критерий. Confidence полезен для routing и review, но его нужно сочетать с validation, source evidence, business rules и тестами.

Как описывать отсутствующие значения?
Не смешивайте null, пустую строку и “unknown”. Выберите политику: null для неизвестного, empty array для отсутствующего списка, status=no_data для невозможного результата.

Как версионировать JSON-схему?
Добавьте schema_version и меняйте её при изменении required fields, enum, вложенности или смысла полей. Старые executions должны оставаться интерпретируемыми.