Техническая ветка для разработчиков Собрать руками

Structured outputs для бизнес-процессов

Structured outputs — это не просто «JSON вместо текста». Это фундамент для построения отказоустойчивых AI-агентов и интеграций. В этой статье — как делать это правильно, с примерами, ловушками и готовым чеклистом.

Видео по теме

Открыть видео на YouTube

Практический выпуск CodeVibers: собираем локальный pipeline обработки заявки. Показываю JSON Schema, llama.cpp/Qwen, retry при 503, независимую validation, business gate и routing в CRM либо review queue.

Таймкоды

  • 00:00 Что строим
  • 00:30 JSON Schema и два барьера
  • 00:50 Пишем адаптер локальной модели
  • 01:35 Запуск и тесты отказов
  • 02:20 CRM payload или review queue

Shorts

Источники выпуска

  • ggml-org llama.cpp documentation
  • JSON Schema documentation

Практический материал из выпуска

Артефакт: Рабочий Python pipeline: текст заявки -> llama.cpp/Qwen -> JSON Schema gate -> CRM payload или review queue -> HTML result.

Что должно получиться: Проект без внешних Python-зависимостей с schema, extractor, tests, action log и визуальным результатом.

Видимый результат: На экране меняются исходники, запускается локальная модель, проходят тесты и открывается итоговый routing result.

Вход для демо: Фиктивное обращение компании Север Маркет с задачей, бюджетом, сроком и целевыми системами без реальных контактов.

Выход демо: out/lead.json, out/crm_payload.json или out/review_queue.json, out/action_log.json и out/result.html.

Проверка результата: Schema validator запрещает missing/extra/wrong types; business gate требует confidence, budget и deadline; model 503 обрабатывается retry и review fallback.

Как собрать

  1. Создать lead_schema.json с required, enum, ranges и additionalProperties=false.
  2. Написать llama.cpp adapter с response_format и enable_thinking=false.
  3. Добавить независимую post-validation и CRM/review router.
  4. Запустить extraction на фиктивном обращении и сохранить action log.
  5. Прогнать unit tests и открыть итоговый HTML artifact.
  6. Define strict lead schema.
  7. Implement local llama.cpp adapter and retry.
  8. Implement independent validator and router.
  9. Run live extraction and persist action log.
  10. Run regression tests and render result UI.

Чеклист перед пилотом

  • build_result.status equals passed.
  • All unit tests pass.
  • pipeline_result contains explicit status and reason.
  • Every screen recording has passed privacy OCR report.
  • Pipeline always returns crm_ready or review_required with a reason.
  • All five regression tests pass and invalid fields never reach CRM payload.
  • HTML result shows attempts, validation decision and output artifact.

Примеры команд, настроек или правил

python3 extract_lead.py fixtures/lead_request.txt
python3 -m unittest -v test_pipeline.py
response_format: {type: json_schema, schema: lead_schema}
additionalProperties: false
lead_schema.json
fixtures/lead_request.txt
pipeline.py
extract_lead.py
test_pipeline.py
render_result.py
python3 render_result.py

Требования и рекомендации

Требования

  • Схема содержит required, типы, enum, диапазоны и запрет дополнительных полей.
  • Thinking отключен для grammar-constrained ответа локального Qwen.
  • Каждая попытка модели записывается в action log без публикации исходных персональных данных.
  • CRM routing происходит только после schema и business validation.

Рекомендации

  • Ограничивать generation JSON Schema, но все равно валидировать результат после модели.
  • Запрещать дополнительные поля через additionalProperties=false.
  • Разделять schema validity и business readiness.
  • При 503, низкой confidence или неполных данных отправлять заявку в review queue, а не в CRM.

Что такое structured outputs и зачем он бизнесу

Structured outputs — это формат ответа LLM, где результат представлен в строго определённой структуре (обычно JSON), соответствующей заранее заданной схеме (schema). В отличие от свободного текста, такие ответы можно напрямую использовать в коде: сохранять в БД, передавать в API, валидировать, логировать и автоматизировать.

Для бизнеса это означает:

  • Устранение «человеческого» парсинга («надо вытащить сумму из текста»)
  • Гарантированная структура данных — даже если модель ошиблась, она вернёт JSON, а не «сломанный» текст
  • Прямая интеграция с системами: CRM, ERP, бэкенд, workflow-движки
  • Возможность автоматической валидации и ретраев

Как это работает: пайплайн от промпта до JSON

flowchart TD
    A[Пользовательский запрос] --> B[Промпт с schema]
    B --> C[LLM API call]
    C --> D{Ответ валиден?}
    D -->|Да| E[JSON-объект]
    D -->|Нет| F[Retry / Fallback]
    E --> G[Валидация по схеме]
    G --> H[Использование в бизнес-логике]

Ключевой момент: схема (schema) задаётся до вызова API. Это может быть JSON Schema, Pydantic-модель или встроенный тип (например, в OpenAI — response_format).

Пример: из промпта к JSON в Python

Базовый пример с OpenAI API (через Pydantic):

from pydantic import BaseModel
from openai import OpenAI

class InvoiceData(BaseModel):
    amount: float
    currency: str = "RUB"
    invoice_id: str
    status: "paid" | "unpaid" | "overdue"

client = OpenAI()
completion = client.beta.chat.completions.parse(
    model="gpt-4o-mini",
    messages=[
        {"role": "system", "content": "Извлеки данные из счета. Используй только данные из текста."},
        {"role": "user", "content": "Счет №INV-2024-089 от 12.05.2024: сумма 45 000 руб., статус — оплачен."}
    ],
    response_format=InvoiceData
)

invoice = completion.choices[0].message.parsed
print(invoice.amount, invoice.status)  # 45000.0, 'paid'

Важно: parse() вместо create(), и модель сама гарантирует, что ответ будет соответствовать схеме (или вернёт ошибку).

Бизнес-кейс: автоматизация обработки входящих писем

Сценарий: приходит письмо от клиента с просьбой изменить срок оплаты. Нужно:

  1. Извлечь ID заказа, новую дату, причину
  2. Проверить, что заказ существует и не просрочен
  3. Создать задачу в Jira / CRM

Без structured outputs — 3 этапа: LLM → текст → regex → данные. С ним — 1 этап: LLM → JSON → данные.

Пример схемы для запроса:

class RequestChange(BaseModel):
    order_id: str
    new_due_date: str  # ISO 8601
    reason: str
    priority: "low" | "medium" | "high"

После этого — просто вызов API, валидация, и можно отправлять данные в CRM.

Типичные ошибки и как их избежать

  • Слишком сложная схема → модель «обманывает» (возвращает JSON, но с ложными данными). Решение: разбивайте на подзадачи, используйте step-by-step reasoning.
  • Нет fallback-логики → при ошибке пайплайн падает. Решение: всегда обрабатывайте ValidationError и возвращайте fallback-значения (null, default, human review).
  • Игнорирование типов"45 000" вместо 45000.0. Решение: используйте строгую валидацию (Pydantic v2, strict=True).
  • Нет логирования → невозможно отладить, почему модель «неправильно» спарсила. Решение: логируйте вход, выход и ошибки (включая raw response).

Чеклист внедрения structured outputs

  • [ ] Схема описана в виде JSON Schema / Pydantic и версионирована
  • [ ] В API вызове указан response_format (или эквивалент)
  • [ ] Есть обработка ValidationError и fallback-логика
  • [ ] Логируется raw response + parsed объект + ошибка (если есть)
  • [ ] Проведена тестовая валидация на 10–20 реальных примерах
  • [ ] Определён SLA: сколько времени отводится на парсинг и ретраи

Следующий шаг: от outputs к агенту

Structured outputs — это не конечная точка. Это основа для агентов, которые:

  • Парсят вход → принимают решение → вызывают tool → возвращают структурированный результат
  • Могут обрабатывать ошибки и ретраить вызовы
  • Интегрируются в очереди (например, RabbitMQ) для масштабирования

Дальше — в Telegram-канале и в следующих статьях: как собрать агента с tool-calling, как тестировать его поведение и как сделать production-ready workflow.