Приём: когда модель просят выдать структурированный 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: observationIndex → analyte → shelfClassification → shelfNote → activeStateAssessment[] → asymptomaticExtensionApplies → extensionNote → finalStatus → reasoning. Сначала идентификация (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 снижает риск семантических несоответствий, но не заменяет валидатор