feat(llm): RAG knowledge base over clinical guidelines with cited extractive answers
CI / ruff · pytest (pull_request) Successful in 1m30s

- docs/source/rag: PDF sources (KR PTSD 2023, KR depression 2024, meds module spec),
  pdf->txt converter (tables as markdown, page markers, hand-transcribed figures),
  word-level check against pdftotext; fixes HAM-D/MADRS fake headers and split rows
- config/rag: corpus txt + sources.yaml (documents, audiences, retrieval params, synonyms)
- app/llm/rag: Snowball stemmer, section-aware chunker with page citations,
  BM25 + synonym expansion + densest-passage reranking, extractive answer()
  with coverage gate, patient dose/prescribing filter, optional LLM rephrasing
  rejected when it adds content; CLI python -m app.llm.rag
- tests: gold retrieval set (hit@3 >= 15/18), off-topic, safety, faithfulness
- ADR-011

Refs #60

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-04 04:11:06 +03:00
co-authored by Claude Opus 5.5
parent 66986255e2
commit 6a77831603
26 changed files with 7776 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
# База знаний RAG (#60): документы, параметры поиска, синонимы.
# Тексты в corpus/ собраны из PDF конвертером docs/source/rag/pdf_to_txt.py — правьте PDF/figures/manual
# и перегенерируйте, а не редактируйте txt руками.
#
# audiences — кому можно показывать выдержки:
# doctor — врач (дашборд, подсказки по КР);
# patient — пациент (только экстрактивно, без дозировок, с припиской «решение за врачом»);
# team — внутренние документы команды (логика модулей), пациенту и врачу не показываются.
documents:
- id: kr_ptsd
file: corpus/kr_ptsd.txt
title: "Клинические рекомендации «Посттравматическое стрессовое расстройство»"
short: "КР ПТСР 2023"
issuer: "Минздрав РФ, Российское общество психиатров"
year: 2023
icd: [F43.1]
audiences: [doctor, patient]
- id: kr_depression
file: corpus/kr_depression.txt
title: "Клинические рекомендации «Депрессивный эпизод, рекуррентное депрессивное расстройство»"
short: "КР Депрессия 2024"
issuer: "Минздрав РФ, Российское общество психиатров"
year: 2024
icd: [F32, F33]
audiences: [doctor, patient]
- id: meds_module_spec
file: corpus/meds_module_spec.txt
title: "Модуль «Лекарства»: спецификация для разработки"
short: "Спецификация модуля «Лекарства»"
issuer: "команда MedITron"
year: 2026
icd: []
audiences: [team]
chunking:
max_chars: 1200 # целевой размер фрагмента; абзац длиннее режется по предложениям
min_chars: 200 # короткий хвост раздела приклеивается к предыдущему фрагменту того же раздела
# Разделы, которые не индексируются (шум для поиска). Сравнение — по началу заголовка.
skip_sections:
- "Список литературы"
- "Список сокращений" # аббревиатуры раскрываются через synonyms ниже, сам список только засоряет поиск
retrieval:
top_k: 5
bm25_k1: 1.5
bm25_b: 0.75
title_weight: 2 # заголовок раздела повторяется в индексе столько раз — совпадение с ним весомее
min_score: 3.0 # ниже — считаем, что в базе нет ответа
rerank_candidates: 30 # сколько лучших по BM25 фрагментов переранжировать по самому плотному отрывку
window_sentences: 2 # размер отрывка (предложений подряд)
window_weight: 0.5 # вес оценки отрывка относительно BM25
# Множитель оценки для разделов (по началу заголовка) в зависимости от аудитории.
# «Приложение В» в обеих КР — «Информация для пациента»: написано для пациента, ему и показываем в первую очередь.
# «Приложение Г» — бланки шкал и история их валидации, «Критерии оценки качества» — для организаторов
# здравоохранения: пациенту это шум.
section_boost:
patient:
"Приложение В": 1.5
"Приложение Г": 0.5
"Критерии оценки качества": 0.5
answer:
max_chunks: 5 # в скольких лучших фрагментах ищем отрывок
max_passages: 2 # отрывков в ответе (второй — только если почти так же хорош)
second_passage_ratio: 0.8
max_sentences: 3 # предложений в отрывке (подряд, как в источнике)
neighbor_ratio: 0.5 # соседнее предложение входит в отрывок, если его релевантность >= доли лучшего
max_chars: 600
min_coverage: 0.5 # доля «веса» слов вопроса, найденная в отрывках; ниже — «ответа нет»
# Синонимы и аббревиатуры: запрос расширяется всеми формами группы (сравнение — по основам слов).
synonyms:
- ["птср", "посттравматическое стрессовое расстройство"]
- ["кптср", "комплексное посттравматическое стрессовое расстройство"]
- ["рдр", "рекуррентное депрессивное расстройство"]
- ["дэ", "депрессивный эпизод"]
- ["ад", "антидепрессант"]
- ["сиозс", "селективные ингибиторы обратного захвата серотонина"]
- ["сиозсн", "ингибиторы обратного захвата серотонина и норадреналина"]
- ["тца", "трициклические антидепрессанты"]
- ["кпт", "когнитивно-поведенческая психотерапия"]
- ["дпдг", "emdr", "десенсибилизация и переработка травмы движениями глаз"]
- ["сопа", "синдром отмены антидепрессантов"]
- ["эст", "электросудорожная терапия"]
- ["ртмс", "транскраниальная магнитная стимуляция"]
- ["кошмар", "кошмарные сновидения"]
- ["бессонница", "инсомния", "нарушения сна"]
- ["флешбэк", "флэшбек", "навязчивые воспоминания"]
- ["суицид", "самоубийство", "суицидальные мысли"]
# Разговорная лексика пациента -> термины КР.
- ["таблетки", "препарат", "лекарство"]
- ["бросить", "отменять", "отменить", "отмена", "прекратить", "прекращение приема"]
- ["подействовать", "действовать", "помогать", "эффект", "улучшение"]
- ["антидепрессивный", "тимоаналептический"]
- ["привыкание", "зависимость"]
- ["спорт", "физическая активность", "физические упражнения", "физическая нагрузка"]
- ["побочка", "побочные эффекты", "нежелательные явления"]
- ["тошнит", "тошнота"]
- ["выпить", "спиртное", "алкоголь"]
- ["сколько длится", "продолжительность", "длительность"]
- ["психолог", "психотерапия"]