Structure-aware units with audience/evidence metadata, manual review, hybrid BM25 search, citation-checked answers and an eval set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
11 KiB
RAG по клиническим рекомендациям Минздрава
Статус: черновик подхода, 2026-10-04. Реализация — отдельной задачей (lane B,
app/llm/rag.pyпо SPEC §структура). Пример исходника: КР «Посттравматическое стрессовое расстройство», ID 753, 2023 (Российское общество психиатров).
Принцип
Файлов мало, глубина нужна максимальная, поэтому мы не делаем классический RAG «нарезка по N токенов → эмбеддинги → top-k». Каждая КР один раз превращается в размеченную и вычитанную базу знаний из смысловых единиц. Поиск по ней почти тривиален, а каждый ответ проверяется по цитате.
1. Кому отвечает RAG
КР написаны для врачей: дозы, препараты off-label (#), показания к госпитализации. Пересказывать это пациенту нельзя —
это противоречит нашим guardrails (app/llm/med_qa.py: о препаратах — только по инструкции ГРЛС и без доз).
| Потребитель | Что можно отдавать из КР |
|---|---|
| Пациент (бот) | Только Приложение В. Информация для пациента и психообразование. Без доз и названий препаратов |
| Врач (дашборд) | Всё, с цитатой, уровнем убедительности (УУР) и достоверности доказательств (УДД) |
| Команда (design-time) | Обоснование порогов в config/ (TSQ ≥ 6 — Прил. Г1, градации шкалы Бека — Г10): ссылки на источник, а не runtime-RAG |
У каждой единицы есть поле audience. Фильтр по нему применяется до поиска, а не через промпт LLM.
2. Разбивка на смысловые единицы
Структура КР Минздрава стабильна, используем её как схему.
type |
Пример из КР ПТСР | Как хранить |
|---|---|---|
recommendation |
«Пациентам с ПТСР … рекомендуется начинать терапию с СИОЗС…» | Тезис + УУР/УДД + комментарий + номера источников |
definition / criteria |
Критерии МКБ-10 А–Д, кластеры МКБ-11 | По одному критерию на единицу |
dose_row |
Таблица «Рекомендуемые дозы» (Прил. А3) | Строка: препарат, диапазон, off_label, zhnvlp (**) |
scale |
TSQ, CAPS, IES-R, BHS, TOP-8 (Прил. Г1–Г11) | Пункты + ключ интерпретации как данные |
algorithm |
Прил. Б и Б1 (в PDF это картинки) | Переписать вручную в шаги и ветвления |
patient_info |
Прил. В | Абзацы с audience: patient |
quality_criterion |
«Критерии оценки качества медицинской помощи» | По строке таблицы |
Пример единицы:
{
"id": "kr753.3.2.rec01",
"doc": {"kr_id": 753, "title": "ПТСР", "approved": "2023", "revise_by": "2025"},
"path": ["3. Лечение", "3.2. Психофармакотерапия", "Терапия первой линии"],
"type": "recommendation",
"text": "Пациентам с ПТСР в качестве препаратов первой линии ... рекомендуется начинать терапию с СИОЗС ...",
"comment": "После установления диагноза ... эффективность оценивается через 4–6 недель ...",
"uur": "A",
"udd": 1,
"refs": [51, 53, 302],
"drugs": ["пароксетин", "сертралин", "флуоксетин", "венлафаксин"],
"contains_dose": true,
"off_label": ["флуоксетин", "венлафаксин"],
"audience": ["doctor"],
"pages": [17, 18]
}
Комментарий хранится вместе с тезисом: по отдельности они теряют смысл, а основная глубина КР — именно в комментариях.
3. Пайплайн подготовки: автоматика, затем вычитка
Файлов мало, поэтому ручная вычитка реальна и даёт больше всего качества. Повторяем практику docs/clinical/: хеши
исходников, review-status.json.
- Источник. Первоисточник — cr.minzdrav.gov.ru, а не перевёрстки (пример выше — перевёрстка с disuria.ru). Храним sha256.
- Очистка. Убрать колонтитулы («Страница N из 117», рекламу сайта), склеить переносы и разрывы страниц (слипания вида «клиникопсихопатологических»), собрать таблицы, разорванные между страницами.
- Парсер по шаблону. Абзац «- Пациентам…» до строки «Уровень убедительности рекомендаций X (уровень достоверности
доказательств N)» — одна единица
recommendation. Следующий за ней блок «Комментарии:» — её полеcomment. - Список литературы не индексируем. Это шум для поиска; номера источников остаются в
refs. - Ручная вычитка. В первую очередь — единицы для пациента и всё, где есть числа. В КР ПТСР уже видны ошибки самого
источника, которые автоматика пропустит:
- в таблице критериев качества перепутаны колонки УДД и УУР;
- раздел 6.1 встречается дважды;
- опечатка «ценить суицидальный риск» вместо «оценивать».
- Словарь аббревиатур и синонимов — из списка сокращений в начале каждой КР. Нужен для расширения запросов: СИОЗС ↔ сертралин/пароксетин, ДПДГ ↔ EMDR, ТФ-КПТ и т.д.
Раскладка по ADR-008:
data/kb/sources/ исходные PDF + sha256
data/kb/units/*.jsonl вычитанные единицы (в git)
data/kb/review-status.json статус вычитки по единицам
data/eval/kb_questions.yaml эталонные вопросы
4. Поиск
Корпус маленький, тяжёлая инфраструктура не нужна.
- Фильтр по метаданным до поиска:
audience,doc,type. Вопрос пациента о дозе — отказ без поиска. - Гибридный поиск:
- BM25 с русской лемматизацией (pymorphy3) и расширением запроса по словарю аббревиатур;
- эмбеддинги — только GigaChat Embeddings или локальная модель (guardrails 4 и 9; для офлайн-демо — только локальная).
- Small-to-big. Найден тезис — в контекст LLM уходит тезис с комментарием и заголовками родительского раздела. При нашем объёме допустимо отдавать раздел целиком.
- Порог уверенности. Лучшая единица ниже порога — ответ «В клинических рекомендациях ответа на этот вопрос нет»
(по аналогии с
fallbackвconfig/texts/med_qa.yaml).
5. Генерация строго по источнику
Переиспользуем механизмы app/llm/med_qa.py:
-
LLM получает пронумерованные единицы и обязана ссылаться на
idв каждом утверждении. -
Детерминированная проверка после генерации:
- каждое число в ответе встречается в процитированных единицах;
- доля «новых» слов ограничена (
MAX_NOVEL_STEM_SHARE).
Не прошло — вместо пересказа отдаём саму цитату.
-
Ссылка на источник («КР ПТСР 2023, разд. 3.2, УУР A») и фраза «решение принимает врач» добавляются кодом, не через LLM.
-
До поиска действуют общие guardrails: проверка безопасности (
acute→ фиксированный кризисный скрипт), затемscrub(), затем вызов модели только черезapp/llm/gateway.py.
6. Оценка качества
Эталонный набор в data/eval/ на 50–100 вопросов с ожидаемыми id единиц. Вопросы трёх видов:
- прямые;
- перефразированные;
- ловушки, на которые в КР ответа нет.
Метрики:
- recall@k по
id(есть ли нужные единицы среди первых k найденных); - доля ответов, прошедших проверку по цитате;
- доля правильных отказов на ловушках.
Оценка запускается обычным pytest-тестом, чтобы правки разметки не ломали поиск незаметно.
Риски и ограничения
-
Актуальность. КР ПТСР указывает «пересмотр не позднее 2025». Перед использованием проверить в рубрикаторе Минздрава наличие новой редакции.
approved/revise_byхраним в метаданных и показываем в ответе. -
Объём к дедлайну (05.10.2026, 13:00). Реалистичный MVP:
- 2–3 КР (ПТСР, депрессия), размеченные полуавтоматически и вычитанные;
- BM25 + фильтр по
audience; - строгие цитаты.
Эмбеддинги и реранкер — по остаточному принципу: глубину даёт качество разметки, а не векторная база.