Как из FHIR-хранилища (анализы, выписки, PHR за годы) получить “текущее состояние здоровья” для LLM.

Pending refactor: страница пока в digest-стиле ([Н]/[Р] секции, длинные inline rationales). Concept-page в нашей wiki — thin layer-овый narrative со ссылками на entity/decision pages, не all-inclusive. Аналогичная ситуация с custom-domains-saas. Refactor — отдельный pass.

Сессия 18d2aef8 (Jan 30 → Feb 3) установила каркас: что уже есть в индустрии (IPS-стандарт), какими подходами решают retrieval, как фильтровать данные без feedback (cold start). Детали архитектуры под BloodGPT-специфику (Composition + CarePlan + Google Healthcare) — отдельные wiki-страницы (это нормально, wiki состоит из cross-linked страниц).

Факты [Н]

[Н1] IPS = формальный международный стандарт для “essential healthcare information extract”

International Patient Summary — ISO 27269 / HL7 FHIR IPS IG v2.0.0. Не “полная медкарта”, а минимальный набор клинически значимой инфы о пациенте (для emergency, cross-border, specialist handoff).

Три обязательные секции с LOINC-кодами:

  • Allergies — 48765-2
  • Medications — 10160-0
  • Problems (active conditions) — 11450-4

Опциональные (~20): Procedures, Immunizations, Devices, Results (labs), Vital Signs, Past Illness History, Functional Status, Plan of Care и т.д.

Структурно — FHIR Bundle с Composition как корневым ресурсом, который группирует секции через section[].entry[] → FHIR references на Condition, MedicationStatement, AllergyIntolerance и пр.

Происхождение факта — RFC-019 §3.1 (пересказ Claude по HL7 IPS IG v2.0.0 + ISO 27269):

«IPS (International Patient Summary) — ISO 27269 / HL7 FHIR IPS IG v2.0.0 — “essential healthcare information extract”» (session digest 18d2aef8 [Н1])

[Н2] HAPI FHIR имеет нативную генерацию IPS через Patient/$summary

С версии HAPI 7.2 — built-in operation. Сервер сам собирает IPS Bundle по стандарту из ресурсов пациента, без самописной логики формирования Composition.

Для BloodGPT значит: если используем HAPI как FHIR backend, не надо писать свою agregation-логику для базового IPS. Можно строить кастом-фильтрацию поверх или вместо $summary.

Ильдар: «в хапи есть генерация ипс?» (session 18d2aef8, 2026-01-30)

[Н3] emptyReason — FHIR-способ различать “нет данных” и “не спросили”

Для обязательных IPS-секций, когда данных нет, FHIR требует явной причины пустоты:

  • nilknown — известно, что у пациента этого нет (“no known allergies”)
  • unavailable — не спросили / не выяснили

Клинически критично: “no known allergies” ≠ “we didn’t ask”. Для medical-LLM это значит нельзя просто опустить пустую секцию в промпте — надо передавать reason.

Источник — FHIR R4 spec (AllergyIntolerance.code nil flavor). RFC-019 это не canonical источник — это LLM-эксперимент Ильдара (см. memory project_bgloodgpt_specs_decisions_llm_summaries), используется как secondary reference, не source-of-truth. Также — у нас в проекте этот pattern (emptyReason) пока не реализован в коде.

[Н4] Temporal relevance имеет research-обоснованные half-life значения

Stanford research (PMC5459355) — медицинские данные имеют “период полураспада” релевантности ~4 месяца в среднем (с большим разбросом по типам).

Carry-over (отдельная page): эта тема — temporal decay в медицинских данных — заслуживает выделения. Аналогично carry-over в llm-safety-in-medicine про medical-knowledge benchmarks. Возможная page: domain/medical-temporal-decay.md или часть domain/medical-research-references.md — что показывает Stanford research, как это влияет на наш scoring, какие альтернативные источники half-life. TBD.

Формула затухания:

decay = 0.5 ^ (age_months / half_life)

Разбивка по типам (из RFC-019 §3.3):

ТипHalf-lifeLookback
AllergyIntolerance∞ (не затухают)
Chronic Condition48 мес
Acute Condition12 мес365 дней
Lab (Observation)4 мес30 дней
Vitals0.5 мес72 часа

Итоговая scoring-формула в RFC-019: score = base × decay × context × severity.

[Н5] Prompt engineering формат влияет на точность FHIR-операций

Vanderbilt Dec 2025 study (найдено на замену устаревшей GPT-3.5 работе):

  • Claude 85% accuracy на JSON/YAML представлении FHIR-ресурсов
  • TOON format (табличный) экономит 30-60% токенов против JSON
  • Gemini и GPT-4o включены в compare, результаты сопоставимы

Предыстория — Ильдар сам принёс arXiv:2411.10541 (GPT-3.5 вариативность до 40% от формата), пометил как устаревшую (GPT-3.5 эра уже не релевантна для нашего текущего LLM-stack):

Ильдар: «Важное открытие: https://arxiv.org/html/2411.10541v1 показало, что GPT-3.5 производительность варьируется до 40% в зависимости от формата промпта. устаревшее укажи. найти бы что-то за конец 2025» (session 18d2aef8, 2026-01-31)

[Н6] Industry-паттерн: pre-visit summary готовится ДО приёма, не в момент запроса

Abridge, Nabla, Ambience — все используют один и тот же pattern:

  • Summary генерируется заранее (batch / overnight), когда врач ещё не у пациента
  • Агрессивная компрессия (target: one-pager)
  • Linked evidence — каждое утверждение в summary кликабельно, ведёт на конкретный FHIR ресурс / документ-источник. Особенно у Abridge — explicit доверительный механизм для врачей.

Детальные разборы в RFC-019 §2 (Abridge Contextual Reasoning Engine, Nabla pre-visit, Ambience Patient Recap nightly batch, Recursive Summarization research pattern).

[Н7] IPS — это база, а не потолок

(Важная идея — confirmed Ильдаром.)

Концепт, сформулированный Ильдаром в середине сессии: IPS даёт минимальный общий знаменатель для всех врачей. Поверх него каждая специализация дозапрашивает своё (endocrinologist → HbA1c trends; cardiologist → ECG history). Это легитимизирует two-layer модель: static IPS baseline + dynamic per-specialty retrieval.

Ильдар: «а мы же в итоге вроде ушли от ИПС. сделали шаг вперёд какой-то, да что ИПС. это такая база. но мы ещё можем учесть более сложную логику» (session 18d2aef8, 2026-02-01)

Ильдар: «если мы хотим представить что-то больше, чем ипс — то, что не только минимальное, но какие-то ещё дополнительные вещи… для каждого врача как свои. в этом идея, что ипс — это одинаково для всех врачей. потом дополнительно каждый врач может запрос[ить]» (session 18d2aef8, 2026-02-03)

Решения [Р]

Note: этот раздел структурно похож на digest (списки [Р1-Р4] с alternatives). В отрефактoренной concept-page будет thin layer со ссылками на atomic decision-pages в decisions/. Сейчас alternative pattern — оставлено как-есть до refactor.

[Р1] Tool Calling (+ опционально MCP) над RAG для retrieval структурированных FHIR данных

Рассмотренные варианты:

  • RAG (embeddings FHIR-ресурсов) — семантический поиск по тексту ресурса. Проблема: разрушает structural связи (clinicalStatus=active, code.system=LOINC), embeddings не чувствительны к типу ресурса и ref-графу.
  • Tool Calling — LLM вызывает чёткие функции: get_active_conditions(patient_id), get_lab_results(patient_id, loinc_codes, date_range). За кулисами — FHIR search API, то есть нативный способ доступа.
  • MCP (Model Context Protocol) — обёртка над tool-endpoints, Anthropic-стандарт для стандартизации LLM↔systems интерфейсов.

Выбор: Tool Calling основной, MCP опционально как transport-layer.

Причина: FHIR данные структурированы (ресурс-тип + поля + references). Семантический поиск embeddings-ом режет именно то, что FHIR уникально предоставляет — structured queryability. RAG остаётся уместен для нестандартных документов (свободный текст выписок, OCR PDF), но не для structured FHIR.

Ильдар: «раг как будто уместно, а вот интеграция не очень» (session 18d2aef8, 2026-01-30)

Ильдар: «а если погуглить подходы, которые сейчас реализуются вместо рага? я имею в виду, что агенты и агенты для кода стали больше работать с помощью вызовов» (session 18d2aef8, 2026-01-31)

Детали: RFC-019 §4.1.

[Р2] Cold Start фильтрация — standards-based, не feedback-driven

Open question (выделено): “cold start” — сложная тема сама по себе. Сейчас написан standards-based подход (использовать external research half-life / mapping LOINC). Альтернатива — feedback-driven pipeline который обучается на реальных данных у нас (доходит до validation, sees что врачи кликают / approve, постепенно adapts). Не обязательно идти по standards-based — может в будущем свой pipeline сделать. Это не финализированный выбор, направление worth выносить в отдельную concept-page или decision (TBD: decisions/cold-start-strategy.md).

Задача: как построить Patient Summary до того, как у нас есть feedback / ML-training data.

Рассмотренные источники весов:

  • Expert-driven (опрос врачей) — долго, дорого на cold start
  • Data-driven (обучение на больших EHR) — нет датасета
  • Standards-based — IPS required sections + Stanford half-life + AHRQ chief-complaint mapping + FHIR clinicalStatus
  • LLM-based (LLM сам оценивает важность) — дорого, недетерминированно
  • Hybrid — standards сейчас, feedback позже когда накопится

Выбор: Standards-based на холодном старте. Feedback-driven calibration — будущая итерация.

Причина: research-based defaults (Stanford, AHRQ, IPS) дают воспроизводимый baseline, не зависят от продакшн-данных, которых у нас нет. Их формальность упрощает позже regulatory / validation story (см. страницу domain/llm-safety-in-medicine.md — process validation pre-deployment).

Детали: RFC-019 §3.3, §3.4, §3.5.

Static vs Dynamic — один спектр правил, не два режима

Static cold-start rules и dynamic LLM retrieval — это один спектр, не два изолированных режима. Оба слоя — правила выбора релевантного из FHIR Bundle; различие только в trigger-е: precomputed batch (static) vs on-demand interactive (dynamic). Архитектурно — IPS-like baseline поверх которого LLM может задавать дополнительные queries, не отдельный retrieval-pipeline сбоку.

[Р4] RFC-019 структурирован: Industry → Concept → Implementation

RFC после reorganisation: (1) Problem → (2) Industry examples (Abridge, Nabla, Ambience, Recursive Summarization) → (3) Our Approach (scoring model) → (4) Implementation → (5) FHIR examples → (6) Questions → (7) Next Steps → (8) References. Industry наверх — для контекста “как вообще решают”.

Ильдар: «может быть примеры из индустрии поместить вверх?» (session 18d2aef8, 2026-02-01)

Следствия для BloodGPT

(Черновик — не согласовано с Ильдаром.)

  • Composition как root-ресурс для BloodGPT summary — напрямую mapping в IPS Bundle. Не надо изобретать свой контейнер; использование IPS-compatible формата даёт: (a) cross-vendor interoperability, (b) понятную для клиницистов семантику, (c) путь к HAPI $summary если backend поменяем. Это пересекается с более поздним решением “Composition + CarePlan” (Feb 13+), но ingest той сессии — отдельная страница.

  • Tool Calling как primary retrieval — архитектурный якорь. Интерфейс между pipeline-и (recognize, interpretation, enrichments) и FHIR store должен быть в терминах “типизированных функций”, не “общего SQL-подобного запроса к бандлу”. Это упрощает auditability (какая функция что вернула → цитируется в LLM-ответе).

  • Cold start scoring должен быть zero-PII reproducible. Если параметры декайа и базовых скоров вынесены в config / registry (a не закодированы), это позволяет: independent review клиницистами, versioning scoring policy, trace-back почему ресурс попал / не попал в summary. Для regulatory (Purolea-precedent) это формальная опора accountability.

  • Linked evidence как возможный roadmap-этап. Abridge делает click → source. Для BloodGPT — если каждый утверждение в summary несёт FHIR-reference (DiagnosticReport/…, Observation/…), это одновременно: (a) trust mechanism для врачей, (b) compliance evidence (как AI пришёл к выводу), (c) debugging — видно когда AI fabricates. Не приоритет на сейчас, но архитектурно стоит закладывать.

  • “IPS как база” = ready-made контракт с partners. Medical-grade partnerships (labs, клиники) часто уже говорят на IPS. Если наш summary IPS-compatible, мы упрощаем onboarding. Если кастом — каждый integration заново.

  • Prompt engineering format — testable, not implicit. Vanderbilt research даёт reproducible выбор (Claude + JSON/YAML). Но это research; под нашу задачу (интерпретация лабораторных) нужен собственный replication: prod cases, наши prompts, наши metrics. Иначе полагаемся на paper, которого не проверяли под себя.

Actuality биомаркеров

Биомаркеры в summary разделяются на два списка по актуальности — актуальные (последнее значение на дату недавнего среза) и out-of-date (не сдавались давно). Счётчики типа «130 нормальных» в summary не показываются: они не отражают текущее состояние здоровья и создают ложное ощущение благополучия.

Трендовые показатели по определению не подпадают под actuality split — их scope исторический ряд, не точка.

Actuality — это UX-слой поверх temporal-decay scoring (см. half-life выше): continuous decay раскладывается в два бинарных bucket’а для отображения.

TTL-механизм:

  • TTL per panel — клетки крови, иммунология, гормоны имеют разный refresh-rate, общее правило не подходит.
  • Anchor — дата самого нового биомаркера пациента, не current date. Корректно работает с историческими загрузками: если пациент backfill’ит старые результаты, «сейчас» для actuality = его последняя сдача.
  • Out-of-date биомаркер не передаётся в retrieval-контекст, но подсвечивается в UI с пометкой. Параметр не исчезает с экрана.

Подробности и open вопросы — в biomarker-actuality-thresholds.

Остальное:

  • Что показывать врачу vs пациенту в summary различается (врачу нужна новизна / длительность / клинические акценты). Конкретный набор полей врачебной версии не определён.

Реализация: PatientSummaryAgent на Mastra (BG-1049)

В session 3d5c475c (Mar 23-25 2026) RFC-019 retrieval logic портирована в Mastra-агента (patientSummaryAgent). Это первая working реализация концепта на этой странице.

4-фазный agent-loop:

Phase 1 — basic collection (always):
  ├─ patient demographics
  ├─ active conditions
  ├─ allergies
  ├─ medications
  └─ immunizations

Phase 2 — condition-driven retrieval:
  ├─ diabetes detected → HbA1c history, glucose, eGFR
  ├─ hypertension → blood pressure series
  ├─ CKD → eGFR, creatinine
  ├─ anemia → hemoglobin
  ├─ hyperlipidemia → cholesterol panel
  ├─ female 15-49 → getPregnancyStatus
  ├─ age >=65 → getFunctionalStatus
  └─ age <18 → growth observations

Phase 3 — full sweep:
  ├─ resolved conditions, procedures
  ├─ family history, vitals
  ├─ diagnostic reports, devices
  ├─ care plans, encounters

Phase 4 — finishSummary tool exit

6/6 test scenarios passed на SmartHealthIT public sandbox с разными patient profiles (chronic, allergies, female-fertile, elderly, pediatric, minimal). Test runner — direct mode через agent.generate() + tsx --env-file=.env. Подробности pattern и debugging — mastra.

finishSummary tool сохранён как structured contract (не для exit-control — Mastra сама останавливается). Гарантирует что summary в toolCall.args.summary (не parse-via-result.text). Поверх — finishSummaryStructured со Zod-схемой повторяющий Python JSON output (для DB persist / UI sections / evals comparison).

См. agent-vs-workflow про agent-for-retrieval pattern (третий тип после decomposed-for-structured-task и agent-for-conversation).

Production deployment не зафиксирован — вызывается через Studio / direct mode test runner. Подключение как Inngest function или API-endpoint — open.

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

[О1] Валидация внешних клинических спецификаций против RFC-019

В конце сессии Ильдар загрузил 3 документа из Downloads (part1_intro_sections1-7_FORMATTED.md, part2_sections8-12_FORMATTED.md, part3_special_cases_rules_FORMATTED.md, ~1.5K строк). Claude начал анализ: это клиническая спецификация содержания (rules по organ system), RFC-019 — техническая модель фильтрации. Полный cross-check не завершён. Происхождение документов (чьи, какая версия, какой оригинал) — неясно; файлы в Downloads и могут быть потеряны.

Ильдар: «можешь провалидировать то что написано в эти документах в сравнении с тем, что мы записали в наш РФЦ» (session 18d2aef8, 2026-02-02)

Ильдар: «то есть у нас есть типы правил для фильтрации/отбора. а в документах конкретные правила?» (session 18d2aef8, 2026-02-02)

[О2] Linked Evidence — нужна ли функция “кликни на утверждение → покажи источник”

Помечено в RFC-019 как discussion question (добавлено по просьбе Ильдара). Abridge это делает, но удорожает pipeline. Трейд-офф не разрешён.

[О3] Evaluation metrics для medical summarization

Упомянуто как possible next step, не раскрыто в сессии. Конкретный вопрос: какой метрикой меряем качество summary (coverage, factuality, clinical-utility)? Пересекается со страницей domain/llm-safety-in-medicine.md — NOHARM-стиль evaluation (Safety, Completeness, Restraint) применим, но требует адаптации под summary, а не под clinical-decision.

Упомянуто, не раскрыто. Отдельная тема, вероятно требует самостоятельной concept-страницы.

[О5] Production deployment PatientSummaryAgent

В session 3d5c475c агент реализован и протестирован, но не deployed как production endpoint. Варианты: Inngest function (вписывается в существующий orchestrator pipeline), API endpoint (через b2b-api), или часть snapshot-generation pipeline (см. health-report-vision — PatientSummaryAgent как retrieval-stage перед AI-generation).

[О6] Langfuse tracing project не создан

Mastra поддерживает Langfuse out-of-box. Сейчас logging через manual parse result.steps[].toolCalls/toolResults. См. mastra.

[С1] Откуда конкретные значения severity/weights в scoring formula

Standards-based — ответ на “где их искать” (Stanford half-life, AHRQ mapping, IPS config). Но конкретное “почему severity=2.0 для аллергии, а не 1.5” — не обоснованно в сессии. Это калибровочный параметр, который остаётся “expert judgement, to be validated”.

Ильдар: «ты ответила на вопрос: как получить коды? я хотел понять, как получить под то, на сколько каждый из параметров влияет?» (session 18d2aef8, 2026-02-01)

Источники

Источники: 1 2 3 4 5 6.

Пересечения

  • domain/llm-safety-in-medicine.md — NOHARM 76.6% omissions + Purolea accountability. Summary-pipeline должен иметь coverage check и documented human review.
  • recognition-enrichment-hourglass — patient summary это финальный этап нижнего конуса (FHIR → enrichment → human-readable output)
  • TBD: страница про Composition + CarePlan архитектуру под Google Healthcare API (source — session 871a7608 / aae4c1fd / c9560637, Feb 13-20). Конкретные design-решения (Device → Organization pivot, multi-tenant dataset-per-tenant) — туда, не сюда.

Источники (incremental)

Сноски

  1. Сессия ildar/18d2aef8, 2026-01-30 — ad63-4563-b3a1-9994c30a08ae.

  2. HL7 FHIR IPS IG v2.0.0:, accessed 2026-05-17, http://hl7.org/fhir/uv/ips/ — Composition structure, required sections, LOINC codes).

  3. ISO 27269 (IPS):, accessed 2026-05-17, https://www.iso.org/standard/79491.html.

  4. HAPI FHIR $summary operation:, accessed 2026-05-17, https://hapifhir.io/hapi-fhir/docs/server_plain/ips.html — since v7.2).

  5. arXiv:2411.10541, accessed 2026-05-17, https://arxiv.org/html/2411.10541v1 — помечен Ильдаром как устаревший GPT-3.5 исследование).

  6. Abridge Contextual Reasoning Engine:, accessed 2026-05-17, https://www.abridge.com/blog/contextual-reasoning-engine-video.