Status

active

Контекст

Вики-страницы LLM-сервисов (technical/<service>.md) описывают, что сервис принимает и что отдаёт. Нужен формат, который:

  • читается человеком в Markdown-рендере, не требует IDE / type-aware-инструментов;
  • передаёт семантику (зачем поле, откуда берётся, что решает), а не только shape;
  • не дублирует код — shape в коде остаётся source of truth, страница ссылается;
  • одинаково применим ко всем LLM-сервисам в нашем стеке.

Первый собранный пример (validity-classifier) использовал TS-fence для input и output. На ревью 12 мая 2026 Ильдар отметил: TS-синтаксис (gemini-doom-loop стиль analyte: string; value: string | number; …) — носитель shape, не смысла; читается как код, а не как объяснение; жёстко привязан к одному языку.

Рассматривали

  • TS-fence — точный, IDE-копируется. Но: noisy (?:, | undefined), language-locked, не передаёт «зачем это поле модели».
  • Zod-фенс — то же + framework-locked, ещё больше noise.
  • JSON Schema — language-agnostic, но verbose; читается хуже TS.
  • JSON-пример с прозой — концретно, легко grok. Минус — не контракт (один пример ≠ полное описание), без аннотаций к опциональности.
  • Таблица полей — семантика впереди, тип — один столбец из нескольких; язык-агностично; symmetric input/output. Минус — менее точна, чем TS, может дрейфовать от кода.
  • Чистая проза — гибкая, но плохо сканируется, тяжело найти конкретное поле.

Выбрали

Таблица полей для input и output, симметрично. Структура столбцов разная по содержанию:

Output (что модель эмитит):

ПолеТипЧто решаетЧто НЕ смотрит

Что решает — какую функцию это поле выполняет в финальном контракте. Что НЕ смотрит — явно выводит границы, чтобы читатель не приписывал полю значение, которого нет.

Input (что сервис принимает):

ПолеТипИсточникЗачем модели

Источник — откуда поле берётся (FHIR Observation / activeConditions / demographics-bundle / patient-context); Зачем модели — что LLM с ним делает (использует для классификации / только проксирует / link-back identifier).

JSON-пример — опциональный companion под таблицей, когда shape вложенная (например, FHIR-Observation внутри bundle, RetrievedMatch-объекты со sub-полями) или когда конкретные значения проясняют семантику быстрее, чем описание. Один реалистичный пример, не исчерпывающий.

TS-shape остаётся в коде; страница ссылается через § «Где в коде» — кликнул и попал в .ts с полным синтаксисом.

Почему

  • Семантика впереди типа — на вики-странице человек хочет понять «зачем поле», а не «как оно по типам». Тип — один столбец из четырёх.
  • Симметрия input/output — одинаковая mental model для обоих контрактов; легче читать, легче редактировать. Asymmetric format (output-таблица + input-fence) — артефакт раннего черновика, не принципиальное различие.
  • Язык-агностично — Markdown-таблица читается одинаково и в Obsidian, и на GitHub, и в любом тексте. TS-fence требует от читателя знания TS.
  • Drift acceptable — wiki курируется человеком, точность shape ловится в коде. Страница объясняет смысл, код держит shape. Дрейф в смысле опаснее дрейфа в shape; таблица фокусирует ревью на смысле.
  • JSON-пример как companion — не заменяет таблицу, а конкретизирует, когда абстрактное описание не клик. Особенно для вложенных структур.

Следствия

  • Обновить structured-llm-service-page-template § 2 «I/O-контракт» — заменить рекомендацию TS-фенса на таблицу + опциональный JSON-пример.
  • Обновить validity-classifier-v3 § «I/O-контракт» (когда будет код-сессия) — перевести существующие TS-фенсы в таблицы; решить, какие из полей реально нужны (отдельный вопрос про избыточность инпута — см. CriticMarkup-комментарии в файле).
  • Новые LLM-service страницы — по этой convention с самого начала.
  • В § «Где в коде» каждой такой страницы — обязательная ссылка на типы в коде (как link, не как голая строка пути), чтобы compensate за меньшую точность таблицы.

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

  • Вложенные input-структуры (FHIR Observation, RetrievedMatch, demographics-bundle): один ряд = leaf-поле каждого уровня, или sub-table per вложенный объект, или ссылка на отдельную таблицу? Решим, когда будем переписывать validity-classifier-v3 и встретим этот случай реально.
  • Что считать «нетривиальной shape», требующей JSON-пример — пока ad hoc, по judgement автора. Если паттерн устоится — формализовать.

Связано

  • structured-llm-service-page-template — где это правило живёт инструкционно
  • validity-classifier-v3 — первый кандидат на миграцию формата
  • structured-output-field-order-cot — output-таблица уже использует «# | Поле | Тип | Что решает | Что НЕ смотрит» для CoT-приёма; этот decision просто фиксирует, что та же форма расширяется на input

Источники

  • Ревизия structured-llm-service-page-template от 12 мая 2026, CriticMarkup-комментарий «вообще мне кажется, может быть, стоит не использовать такой способ, а какой-то другой способ описание входных и выходных данных, то есть не через тайп скриптовские, вот эти синтаксис»
  • Discussion: chain 9c5f146c