Решение касается per-параметрного rich-output biomarker-analysis-pipeline (~8 полей: clinicalInterpretation, whatAdditionalDataWouldClarify, foundContext[], missingContext[], referenceContext[], additionalWorkup[], triage, citations[]). Compounding на decision: см. также foundcontext-fhir-mapping (sub-вопрос про конкретный slot для foundContext[]).
Контекст
Per-параметрный AI clinical assessment pipeline (см. biomarker-analysis-pipeline) на каждый параметр производит rich-output: prose-резюме (Writer), prose-«что доисследовать» (Personalizer), три массива evidence items с цитатами из guidelines (foundContext / missingContext / referenceContext), массив рекомендованных тестов (additionalWorkup), enum приоритета (triage), URLs guideline-источников (citations).
Конструкция должна:
- Лечь в FHIR R4 (Google Healthcare API не принимает custom resourceTypes — см. zero-extensions-fhir).
- Поддерживать update-on-rerun без накопления дубликатов и без ненужных перезаписей (если содержимое не поменялось — не платить write-resources). Стратегия conditional PUT через identifier — один из подходов, но не единственный; нюанс «когда обновлять» open.
- Сохранять структуру evidence items (rationale, quotes, source, personalizedRationale — нельзя сливать в один блок prose, см. правило в принципы-fhir-моделирования-ai-контента).
- Поддаваться audit trail в смысле regulatory traceability (включая «glass box» подход FDA для AI-medical-devices — отдельная концептуализация TBD, см. open).
Внутри принятой [[zero-extensions-fhir]] стратегии (минимум custom extensions, максимум native FHIR) есть несколько open осей. Вопрос «всё в одном слоте vs spread» в основе своей про денормализацию vs нормализацию данных — общая тема обсуждается в fhir-modeling-ai-content.
Оси выбора
Три ортогональные оси:
- Host resource — какой FHIR ресурс owner’ит rich-output.
- Гранулярность CI — если выбрали ClinicalImpression: один CI на тест, или CI per параметр.
- Distribution — если выбрали CI: всё в одну custom extension / в один native slot / spread по semantic-correct native slots.
Ось 1 — host resource
| Кандидат | Применимость | Почему |
|---|---|---|
| fhir-clinical-impression | основной кандидат | spec-семантика «AI/clinician’s view of patient situation» совпадает с rich-output |
| fhir-composition | secondary | сейчас контейнер для overview; section-based, расширяется под per-param но смешивает overview и per-param assessment |
Pure Observation.note[] | regression | где parameterDetails живёт в V2; теряет structure (foundContext / additionalWorkup arrays) |
| Другой ресурс | open | возможно есть подходящий FHIR-ресурс, не рассмотренный — не settled |
ClinicalImpression — leading кандидат.
Ось 2 — гранулярность CI
При выборе CI:
| Вариант | Описание |
|---|---|
| Per-test | один ClinicalImpression на весь тест, N параметров внутри одного CI как repeating extensions / sub-sections |
| Per-parameter | один ClinicalImpression на каждый Observation (биомаркер), focus → Observation/{biomarker}. Один тест → N CIs. |
Ось 3 — distribution V2.5 fields в CI
При выборе CI, для всех 8 V2.5 полей надо решить куда они ложатся внутри ресурса:
| Вариант | Описание |
|---|---|
| One custom extension | всё (~8 полей) внутри одной repeating bloodgpt-parameter-analysis extension. Native FHIR slots (summary, investigation, supportingInfo, note, finding, problem) пусты. |
| One native slot piled-in | всё ложится в один permissive native slot (например supportingInfo[] который принимает Reference(Any) и не имеет жёсткой семантики). Custom extensions — только для триажа/citations enum’ов. |
| Spread across natives | каждое поле в semantic-correct native slot: clinicalInterpretation → summary, foundContext → investigation.item[], referenceContext → supportingInfo[], whatAdditionalDataWouldClarify / reasoning → note[], additionalWorkup → отдельный ServiceRequest(intent: proposal), custom extensions минимальны. |
Конкретные комбинации, которые реально рассматриваются
Комбинация A — per-test + one custom extension
ClinicalImpression × 1
├── identifier = "{system}|{testId}" (для conditional PUT)
├── meta.versionId
├── meta.security = [{ code: "AIAST" }]
├── status = "completed"
├── (native slots — пустые)
└── extension[] × N parameters
└── url: "bloodgpt-parameter-analysis"
├── parameterName, loincCode, value, unit, refRange, interpretation, testDate, isHealthy
├── clinicalInterpretation (valueString, Writer prose)
├── whatAdditionalDataWouldClarify (valueString, Personalizer prose)
├── foundContext (complex extension — items с {name, type, rationale, quotes, source, personalizedRationale, unmatched})
├── missingContext (complex)
├── referenceContext (complex)
├── additionalWorkup (complex)
└── citations (complex — repeating valueUrl)
Свойства: один conditional PUT per тест; read pattern «1 CI → N extensions через свой parser»; внешний FHIR-клиент не видит structured данных; foundContext items — inline данные, не References на real Observation/Condition; partner-unfriendly; audit per-test через _history.
Комбинация B — per-parameter + spread across natives
ClinicalImpression × N (по одному на параметр)
├── focus → Observation/{biomarker}
├── identifier = "{system}|{testId}|{biomarker}"
├── effectiveDateTime, status
├── summary ← clinicalInterpretation (prose)
├── investigation[].item[] ← foundContext[] type=observation (References to Observation)
├── problem[] ← foundContext[] type=condition (References to Condition)
├── supportingInfo[] ← referenceContext[] + foundContext[] type=medication (Reference(Any))
├── note[]
│ ├── { authorString: "writer", text } ← clinicalInterpretation (если уже не в summary)
│ ├── { authorString: "personalizer", text } ← whatAdditionalDataWouldClarify
│ └── { authorString: "missing-context", text } ← missingContext[]
└── extension
├── bloodgpt-triage ← triage
└── bloodgpt-citation* ← citations[]
<{recommended-tests resource} × M (reasonReference → CI) ← additionalWorkup[]>
Provenance × 1 (target → все CI + SRs)
Куда конкретно идут «рекомендованные нами анализы» — отдельный sub-вопрос:
ServiceRequest(intent: proposal)(типичный кандидат), илиTask(если описывается как pending action, не lab order), или другой ресурс. Не settled — open ниже.
Свойства: granular linkage (focus → Observation, Provenance per CI); native FHIR-search работает (?_include=focus, GET /ServiceRequest?intent=proposal&...); partner-friendly; bundle multi-resource per rerun; conditional updates по identifier per CI; sub-вопрос куда foundContext[].type=condition/medication идёт пересекается closed list investigation.item — см. foundcontext-fhir-mapping.
Комбинация C — per-test + one native slot piled-in
Один CI на весь тест (per-test гранулярность как в A — не per-param), всё V2.5 ложится в native supportingInfo[] slot:
ClinicalImpression × 1
├── identifier = "{system}|{testId}"
├── meta.security = [{ code: "AIAST" }]
├── summary = <общий prose-резюме на тест> (опционально)
├── supportingInfo[] ← всё V2.5 ложится сюда как Reference(Any) или inline-by-extension
│ ├── { extension: bloodgpt-parameter-analysis (per param) }
│ └── ...
└── extension
└── bloodgpt-citation* (если хочется триажа/citations отдельно)
Свойства: один resource как в A, но V2.5 кладётся в native supportingInfo[] slot (permissive Reference(Any)) — внешний FHIR-клиент видит «ресурс полный»; structured данные доступны через extension’ы внутри supportingInfo entries; нет distribution semantics (всё в одном слоте), но slot существует в spec; partner-неполноценный (нет References на реальные Observation/Condition), но «не пустой».
Связи между осями
Не все 6 комбинаций равно осмыслены. Per-test composability с distributed-natives (investigation.item[] как aggregate всех param Observations) теряет per-param структуру. Per-parameter с one-custom-extension тратит N writes без выигрыша интероп. Реальные кандидаты — A, B, C.
Open
- Какой подход выбираем для prod cutover. Текущая implementation пишет вариант A; не commit’нуто как architectural decision.
- Если B — как разрешается closed-list constraint на
investigation.item[](не принимает Condition/Medication). См. foundcontext-fhir-mapping. - В A и C: как партнёр-EHR (InterSystems и др.) парсит наши custom extensions — нужен published Profile, или договорённость в integration spec.
- Как мигрировать между вариантами без потери
versionIdистории (если выбираем разныеidentifierpatterns). - Composition + section-based маршрут: open параллельно —
Composition.section[]уже используется для overview, можно расширить под per-param assessment вместо CI вообще. - Какой FHIR-ресурс owner’ит «рекомендованные доисследования» (additionalWorkup):
ServiceRequest(intent: proposal)vsTaskvs другой. ServiceRequest — типичный кандидат для lab order proposal, но если нюанс в “это AI-задача врачу для рассмотрения”,Taskили другой может подойти лучше. - Когда переписывать CI на rerun: всегда conditional PUT vs только при изменении содержимого (диффом). Связано с cost’ом FHIR-write resources.
- Audit trail / regulatory traceability — концептуализация на отдельной странице (TBD): включая FDA glass-box подход для AI-medical-devices, требования к тому что должно быть прослеживаемо.
- DiagnosticReport rollup:
conclusion+conclusionCode[](max-severity triage) — слой над CI/CIs, общий для всех вариантов выше.
Сопутствующая документация требуется
Несколько концептуальных вопросов всплывают при принятии этого решения; каждый достоин отдельной страницы (TBD):
- Карта связей всех FHIR-ресурсов в нашей системе — как Patient/Observation/DiagnosticReport/CI/Composition/CarePlan/ServiceRequest/Provenance связаны через References. Раньше это была наша relational schema; сейчас это spec-driven FHIR model — но вопрос «как у нас данные связаны между собой» тот же. Не задокументировано.
- Regulatory audit trail / glass-box AI — концепт-страница про требования к tracability AI-выводов и FDA glass-box подход.
Связано
- biomarker-analysis-pipeline — concept-страница про сам pipeline (Reasoner + Writer + Personalizer), output которого здесь маппится в FHIR
- fhir-clinical-impression — справочная страница про FHIR R4 ресурс (field semantics, gotchas)
- fhir-composition, fhir-careplan — текущая deployed архитектура для overview
- fhir-service-request — кандидат для
additionalWorkupв варианте B - fhir-provenance — multi-agent audit chain
- zero-extensions-fhir — общая стратегия: минимум custom extensions
- foundcontext-fhir-mapping — sub-вопрос куда конкретно идёт
foundContext[] - edge-role-encoding — sub-вопрос, кодировать ли role на каждом evidence item edge (explains/corroborates/confounds/contextualizes), пересекается с distribution в оси 3
- authorship-organization-not-device —
Organization/bloodgptкак author - fhir-modeling-ai-content — общие принципы маппинга AI-output в FHIR (включая обсуждение normalized vs denormalized)
- parameter-triage-codes — triage enum
Источники
Источники: 1.
Сноски
-
FHIR R4 ClinicalImpression, accessed 2026-05-17, https://hl7.org/fhir/R4/clinicalimpression.html. ↩