From 4d331e4c0515ce674f80d68505e41d74a40d291d Mon Sep 17 00:00:00 2001 From: Arxip222 Date: Sun, 4 Oct 2026 01:13:56 +0300 Subject: [PATCH] docs(rag): describe RAG approach for Minzdrav clinical guidelines 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 --- docs/info/RAG_GUIDELINES.md | 142 ++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 docs/info/RAG_GUIDELINES.md diff --git a/docs/info/RAG_GUIDELINES.md b/docs/info/RAG_GUIDELINES.md new file mode 100644 index 0000000..a53e72b --- /dev/null +++ b/docs/info/RAG_GUIDELINES.md @@ -0,0 +1,142 @@ +# 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` | «Критерии оценки качества медицинской помощи» | По строке таблицы | + +Пример единицы: + +```json +{ + "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`. + +1. **Источник.** Первоисточник — cr.minzdrav.gov.ru, а не перевёрстки (пример выше — перевёрстка с disuria.ru). Храним sha256. +2. **Очистка.** Убрать колонтитулы («Страница N из 117», рекламу сайта), склеить переносы и разрывы страниц + (слипания вида «клиникопсихопатологических»), собрать таблицы, разорванные между страницами. +3. **Парсер по шаблону.** Абзац «- Пациентам…» до строки «Уровень убедительности рекомендаций X (уровень достоверности + доказательств N)» — одна единица `recommendation`. Следующий за ней блок «Комментарии:» — её поле `comment`. +4. **Список литературы не индексируем.** Это шум для поиска; номера источников остаются в `refs`. +5. **Ручная вычитка.** В первую очередь — единицы для пациента и всё, где есть числа. В КР ПТСР уже видны ошибки самого + источника, которые автоматика пропустит: + - в таблице критериев качества перепутаны колонки УДД и УУР; + - раздел 6.1 встречается дважды; + - опечатка «ценить суицидальный риск» вместо «оценивать». +6. **Словарь аббревиатур и синонимов** — из списка сокращений в начале каждой КР. Нужен для расширения запросов: + СИОЗС ↔ сертралин/пароксетин, ДПДГ ↔ 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`; + - строгие цитаты. + + Эмбеддинги и реранкер — по остаточному принципу: глубину даёт качество разметки, а не векторная база.