Приём: когда модель просят выдать структурированный output (JSON по схеме — generateObject / responseSchema), она эмитит поля в порядке объявления в схеме. Значит, если упорядочить поля схемы как цепочку рассуждения — сначала «посылки», потом поля, зависящие от них, потом «вывод» — получаешь chain-of-thought бесплатно, встроенный прямо в output, без отдельного reasoning-преамбула. Порядок полей схемы и есть порядок рассуждения. Перестановка полей превращает CoT в коррелированный шум.

Почему работает

Constrained-decoding заполняет поля слева-направо; каждый следующий токен обусловлен предыдущими. Поэтому поле, объявленное позже, «видит» уже заполненные ранние поля и обязано быть с ними консистентно. Расположив shelfClassification (свойство биологии аналита) → activeStateAssessment (разбор контекста пациента) → finalStatus (вердикт) в этом порядке, заставляешь модель рассуждать «биология → контекст пациента → вердикт» именно так, и вердикт не может противоречить ранним полям. Поле reasoning ставится последним — это audit-резюме уже сделанной цепочки, не вход в неё.

Когда применимо / границы

  • Нужен провайдер, который уважает порядок полей в structured output. Vertex/Gemini — уважает (опыт validity-классификатора построен на этом). Поведение других провайдеров (OpenAI / Anthropic) — TBD verify.
  • Работает, когда рассуждение действительно DAG, который можно топологически уложить в порядок полей (ранние поля — независимые «посылки», поздние — производные).
  • Не заменяет runtime-валидатор. Модель всё ещё может эмитнуть позднее поле, не консистентное с ранним — поэтому кросс-полевую консистентность всё равно проверяют кодом постфактум (в validity-классификаторе validateClassifierOutput ровно это и делает: finalStatus обязан соответствовать shelfClassification / числу materialRelevance:"yes" в activeStateAssessment и т.д.). CoT-через-порядок-полей делает рассуждение более вероятно правильным, не гарантированно.
  • cleanSchema (стрип JSON-schema-артефактов для Vertex — см. gemini-doom-loop) порядок полей не меняет, так что приём с ним совместим.

Где у нас используется

validity-classifier — его выходная схема на одно наблюдение — 9 полей, упорядоченных как CoT: observationIndexanalyteshelfClassificationshelfNoteactiveStateAssessment[]asymptomaticExtensionAppliesextensionNotefinalStatusreasoning. Сначала идентификация (index/имя), потом биология аналита, потом разбор активных состояний пациента, потом два gating-поля, потом вердикт, в конце — резюме. Подробности — на странице классификатора, § «Выходная схема как CoT».

Кандидат на переиспользование там, где у нас есть многошаговое структурированное рассуждение (параметр-анализ? fact-extraction в recognition?) — пока зафиксировано только в validity-классификаторе.

Открытые вопросы

  • Какие провайдеры реально честно держат порядок полей в structured output (Vertex — да; OpenAI / Anthropic — проверить); есть ли у кого-то официальная гарантия.
  • Стоит ли это сделать осознанным паттерном в наших промптах/схемах (а не «случайно работает у Артура в validity») — где ещё это уместно.

Связано

  • validity-classifier — основной носитель приёма (9-шаговый CoT, § «Выходная схема как CoT»); там же validateClassifierOutput — почему приём не заменяет валидатор
  • gemini-doom-loop — тот же Vertex-structured-output-режим, где это живёт; cleanSchema совместим
  • tool-calling / agent-vs-workflow — смежное: structured output как контракт LLM-шага; узкие промпты + детерминистический слой между ними
  • gemini-flash-vs-pro-allocation — модель, на которой это обкатано (Gemini Flash через Vertex)
  • llm-call-granularity — паттерн «1 / N / батчами» + трёхуровневая декомпозиция; field-order-CoT — независимый приём в schema, работает при любой гранулярности
  • llm-call-failure-classes — таксономия сбоев structured-output; field-order-CoT снижает риск семантических несоответствий, но не заменяет валидатор

Источники