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