Files
PTSRaiAgent/config/lexicon/risk_ru.yaml
ElebobaandClaude Opus 5.5 97f3173c9f feat(core): safety detector with RU risk lexicon and fixed crisis script
- check(text, llm_signal) -> SafetyResult: normalisation (ё, homoglyphs, translit,
  repeats), stem regexes per category, negation window (acute -> possible only),
  weapon+risk combination, final level = max(lexicon, llm)
- crisis_reply(categories, audience) loads config/texts/crisis.yaml (patient/family,
  domestic violence and harm-to-others variants)
- 99-phrase eval set; acute recall 100%, < 5 ms per message

Refs #4

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:01:35 +03:00

255 lines
21 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Лексикон риска для app/core/safety.py (guardrail №2, issue #4).
# СТАТУС: черновик, утверждает психиатр (#8).
#
# Как читать:
# - Шаблоны (`pattern`) — регулярные выражения Python над НОРМАЛИЗОВАННЫМ текстом:
# нижний регистр, ё→е, латиница-двойники в русских словах → кириллица, целиком латинские
# слова транслитерируются (hochu → хочу), пунктуация → пробел, 3+ одинаковых буквы → одна
# («жииить» → «жить»). Поэтому в шаблонах: только строчные, без «ё», слова через `\s+`.
# - Морфологию покрываем основами слов: `\bпоконч\w*`, `\bсу[иейы]ц[иы]д\w*` (заодно частые опечатки).
# - `level`: acute — кризис (фиксированный скрипт + немедленный алерт), possible — алерт врачу ≤ 24 ч + C-SSRS.
# - `negation`: как правило реагирует на отрицание (см. раздел negation внизу):
# pre — (по умолчанию) смотрим отрицание ПЕРЕД совпадением («не думаю о суициде»);
# pre_post — ещё и ПОСЛЕ («мыслей о суициде нет»); только для тем-существительных;
# none — отрицание не учитываем (шаблон сам содержит «не», либо фраза опасна в любом виде).
# Отрицание НИКОГДА не снижает уровень ниже possible: acute → possible. Сомневаемся — выбираем выше.
# - Ложноположительные срабатывания допустимы, пропуск кризиса — нет.
version: 1
status: "черновик, утверждает психиатр (#8)"
categories:
suicide:
description: "Суицидальные мысли, намерение, план, прощание (включая косвенные и сленговые формулировки)"
rules:
- id: suicide.kill_self
pattern: '\bпоконч\w*\s+(\w+\s+)?(с\s+|со\s+)?(собой|жизнью)\b'
level: acute
- id: suicide.keyword
pattern: '\bсу[иейы]ц[иы]д\w*'
level: acute
negation: pre_post
- id: suicide.samoubiystvo
pattern: '\bсамоуби\w*'
level: acute
negation: pre_post
- id: suicide.want_die
pattern: '\b(х[ао]чу|х[ао]чется|х[ао]тел\w*|охота|мечтаю|хотелось\s+бы)\s+(\w+\s+)?(умер(еть|ет)|умирать|умиреть|умерть|помереть|сдохнуть|исчезнуть|уйти\s+из\s+жизни|не\s+просыпаться|не\s+проснуться|на\s+тот\s+свет)\b'
level: acute
- id: suicide.dont_want_live
# «не хочу жить», «не хочется больше так жить»; «не» внутри шаблона → negation: none
pattern: '\bне\s+(х[ао]чу|х[ао]чется|х[ао]телось|х[ао]тел\w*|желаю)\s+(\w+\s+){0,2}ж[иы]т[ьи]?\b'
level: acute
negation: none
- id: suicide.live_dont_want
pattern: '\bж[иы]ть\s+(\w+\s+)?не\s+(х[ао]чу|х[ао]чется|охота|х[ао]телось)'
level: acute
negation: none
- id: suicide.no_reason_to_live
pattern: '\b(незачем|не\s+зачем|нет\s+смысла|смысла\s+нет|не\s+вижу\s+смысла|зачем\s+(мне\s+)?(вообще\s+)?(дальше\s+)?)\s*(\w+\s+)?ж[иы]ть\b'
level: acute
negation: none
- id: suicide.cant_live
pattern: '\bне\s+(могу|в\s+силах|хватает\s+сил)\s+(\w+\s+){0,2}ж[иы]ть\b'
level: acute
negation: none
- id: suicide.tired_of_life
pattern: '\b(устал\w*\s+(\w+\s+)?(жить|от\s+жизни)|надоело\s+жить|жить\s+надоело|жизнь\s+(\w+\s+)?не\s+(нужна|мила))\b'
level: acute
- id: suicide.better_not_exist
# «лучше бы меня не было», «лучше бы я там остался / погиб» (вина выжившего у ветеранов)
pattern: '\bлучше\s+бы\s+(меня|я|мне)?\s*(\w+\s+){0,2}(не\s+было|не\s+стало|не\s+родил\w*|не\s+жить|умер\w*|погиб\w*|сдох\w*|остал\w*\s+там|там\s+остал\w*|не\s+вернул\w*)'
level: acute
negation: none
- id: suicide.better_without_me
pattern: '\bлучше\s+(\w+\s+)?без\s+меня\b'
level: acute
negation: none
- id: suicide.so_that_i_am_gone
pattern: '\b(чтоб(ы)?|если)\s+меня\s+(\w+\s+)?не\s+(было|стало|станет)\b|\bменя\s+(\w+\s+)?не\s+станет\b|\bменя\s+(скоро|больше|совсем|просто|вообще)\s+не\s+будет\b|\b(скоро|больше)\s+меня\s+не\s+будет\b'
level: acute
negation: none
- id: suicide.not_wake_up
pattern: '\b(заснуть|уснуть|лечь|лечь\s+спать)\s+и\s+(больше\s+)?не\s+проснуться\b|\bбольше\s+не\s+(просыпаться|проснуться)\b'
level: acute
negation: none
- id: suicide.dont_want_wake
pattern: '\bне\s+(х[ао]чу|х[ао]чется|х[ао]телось\s+бы)\s+(\w+\s+)?просып\w*|\b(мне|просто|лучше)\s+не\s+быть\b'
level: acute
negation: none
- id: suicide.lay_hands
# «наложить на себя руки»
pattern: '\bналож\w*\s+(\w+\s+)?на\s+себя\s+руки\b|\bруки\s+на\s+себя\s+налож\w*'
level: acute
- id: suicide.plan
pattern: '\bплан\w*\s+(\w+\s+)?(как\s+)?(уйти|умереть|покончить|свести|убить\s+себя|сдохнуть)\b'
level: acute
- id: suicide.leave_forever
pattern: '\b(исчезнуть|исчезну|уйти|уйду)\s+(\w+\s+)?(навсегда|насовсем)\b|\bуйти\s+из\s+жизни\b|\bсч[её]ты\s+с\s+жизнью\b'
level: acute
- id: suicide.end_it_all
pattern: '\b(закончить|закончу|покончить|покончу|кончить|кончу)\s+(со\s+|с\s+)?(всем|все|этим)\s*(этим|разом|сразу)?\b'
level: acute
- id: suicide.hang
pattern: '\bп[ао]ве(шусь|шаюсь|шаться|сит?ь?ся|сился|силась|силсь)\b|\bв\s+петлю\b|\bпетл[яюеи]\b|\bвздерн\w*'
level: acute
- id: suicide.shoot
pattern: '\bзастрел\w*|\b(пулю|пуля)\s+(себе\s+)?(в\s+)?(лоб|висок|голову|рот)\b|\bпустить\s+(себе\s+)?пулю|\bствол\s+(к|в)\s+(виску|висок|рот)\b'
level: acute
- id: suicide.jump
pattern: '\b(прыг\w*|шагн\w*|выпрыг\w*|сброс\w*|выйти|выйду|кинуться|кинусь|брошусь|броситься|лечь)\s+(\w+\s+)?(с\s+(крыши|моста|балкона|многоэтажки|высоты)|из\s+окна|в\s+окно|под\s+(поезд|машину|электричку|колеса|грузовик))\b'
level: acute
- id: suicide.kill_myself
pattern: '\b(уб(ить|ью|ил|ила|ю)|угроб(ить|лю))\s+(\w+\s+)?себя\b|\bубиться\b|\bсдохн(уть|у)\b'
level: acute
- id: suicide.slang
# молодёжный/интернет-сленг: «выпилиться», «роскомнадзорнуться», «самовыпил»
pattern: '\bвыпил(иться|юсь|ился|илась|ится)\b|\bсамовыпил\w*|\bроскомнадзорн\w*|\bркн(уться|усь|улся|улась)\b|\bвыйти\s+в\s+окно\b'
level: acute
- id: suicide.veteran_200
# ветеранский сленг: «стать двухсотым», «уйти в двухсотые», «груз 200 сам себе»
pattern: '\b(стать|стану|быть|буду|был|уйти|уйду|лучше\s+бы\s+я\s+был|сам|сам\s+себе)\s+(\w+\s+)?(двухсот\w*|200\w*|груз\w*\s+200)'
level: acute
- id: suicide.join_fallen
# «уйти к пацанам туда / на небо», «к ребятам, которые не вернулись»
pattern: '\bк\s+(пацанам|ребятам|братишкам|братьям|своим)\s+(\w+\s+)?(туда|на\s+небо|наверх|на\s+тот\s+свет|которые\s+(погибли|не\s+вернулись|там\s+остались))'
level: acute
- id: suicide.join_comrades_vague
pattern: '\b(уйти|уйду|хочу|отправиться|отправлюсь|пора)\s+(\w+\s+)?к\s+(пацанам|ребятам|братишкам)\b'
level: possible
- id: suicide.thoughts_of_death
pattern: '\b(мысл\w*|дума\w*|думаю)\s+(\w+\s+)?(о|об|про)\s+(своей\s+)?смерт\w*'
level: acute
negation: pre_post
- id: suicide.farewell
pattern: '\bпредсмертн\w*|\bпрощальн\w*\s+(записк|письм|сообщени)\w*|\bпрощайте\b|\bэто\s+(мое\s+)?последнее\s+(сообщение|письмо)\b|\bраздал\w*\s+(\w+\s+)?вещи\b'
level: acute
- id: suicide.no_way_out_but
pattern: '\bединственн\w*\s+выход\b'
level: possible
self_harm:
description: "Самоповреждение, передозировка"
rules:
- id: self_harm.cut
pattern: '\b(вскр\w*|перерез\w*|порез\w*|резать|режу|резанул\w*)\s+(\w+\s+)?(себе\s+)?(вены|вену|руки|руку|запясть\w*|себя)\b|\bвскр(ыться|оюсь|ылся|ылась)\b'
level: acute
- id: self_harm.hurt_self
pattern: '\b(причин\w*|наношу|нанести|нанесу)\s+(себе\s+)?(вред|боль|порезы|увечь\w*|травм\w*)\b|\b(сделать|делаю|сделаю)\s+себе\s+больно\b|\b(жгу|прижигаю|обжигаю)\s+себя\b|\bселф\s*харм\w*|\bселфхарм\w*|\bсамоповрежд\w*'
level: acute
- id: self_harm.overdose_all
pattern: '\b(выпить|выпью|выпила|выпил|сожрать|сожру|съесть|съем|принять|приму|глотнуть|закинуться|закинусь)\s+(\w+\s+){0,2}(все|всю|целую|целый|горсть|разом|сразу|пачку|упаковку|блистер)\s+(\w+\s+){0,2}(таблет|колес|пачк|упаковк|снотворн|лекарств|блистер|антидепрессант|пилюл|сертралин|феназепам)\w*'
level: acute
- id: self_harm.overdose_pack
pattern: '\b(выпить|выпью|выпила|выпил|сожрать|сожру|съесть|съем|принять|приму)\s+(\w+\s+)?(всю|целую)\s+(пачку|упаковку|коробку)\b'
level: acute
- id: self_harm.overdose_binge
pattern: '\b(нажр|наем|нажир|обожр|нажира|закинусь|закинуться)\w*\s+(\w+\s+)?(таблет|колес|снотворн|лекарств|антидепрессант|феназепам)\w*'
level: acute
- id: self_harm.overdose_word
pattern: '\bнаглота\w*|\bпередоз\w*|\bотрав(иться|люсь)\b'
level: acute
- id: self_harm.hit_self
pattern: '\b(бью|избиваю)\s+себя\b|\bбьюсь\s+(\w+\s+)?головой\b'
level: possible
harm_others:
description: "Угроза причинить вред другим"
rules:
- id: harm_others.kill_threat
pattern: '\bуб(ь|)(ю|ем)\b|\bприбь(ю|ем)\b|\bзареж(у|ем)\b|\bпорешу\b|\bурою\b|\bпокалечу\b|\bзадуш(у|ить)\b|\bперестреля\w*|\bсверну\s+(\w+\s+)?шею\b'
level: acute
- id: harm_others.kill_target
pattern: '\bуби(ть|л)\s+(\w+\s+)?(его|ее|их|всех|кого\s+нибудь|жену|мужа|соседа|соседей|тещу|начальника|ребенка|детей)\b'
level: acute
- id: harm_others.blow_up
pattern: '\b(взорв|подорв)(у|ать|ем)\b'
level: acute
- id: harm_others.urge_to_hit
pattern: '\b(х[ао]чется|х[ао]чу|тянет)\s+(кого\s+(то|нибудь)\s+)?(ударить|избить|врезать|покалечить)\b'
level: possible
weapon_access:
description: "Доступ к оружию. Само по себе — possible; вместе с суицидальным/агрессивным/безнадёжным сигналом — acute (см. combinations)"
rules:
- id: weapon.gun
pattern: '\bруж[ьъ]?[еяю]\w*|\bпистолет\w*|\bавтомат(а|ом|ы|у)?\b|\bкарабин\w*|\bвинтовк\w*|\bобрез\b|\bсайг[аиу]\b|\bтравмат\w*|\bмакаров\w*|\bкалаш\w*'
level: possible
- id: weapon.generic
# включая «наградное оружие», «оружейный сейф»
pattern: '\bоруж\w*|\bствол(ы|а|ов)?\b|\bпатрон(ы|ов)?\b|\bгранат(а|у|ы)\b|\bбоеприпас\w*'
level: possible
domestic_violence:
description: "Домашнее насилие (сообщает пациент или член семьи)"
rules:
- id: dv.beats
pattern: '\b(бьет|бил|избива\w*|избил\w*|душил\w*|душит|ударил\w*|колотит)\s+(меня|нас|детей|ребенка|маму|сына|дочь)\b|\b(меня|нас|детей|ребенка)\s+(\w+\s+)?(бьет|бил|избива\w*|избил\w*|душил\w*|душит|ударил\w*)\b(?!\s+(дрожь|озноб|током|тик|кашель))'
level: acute
- id: dv.threat
pattern: '\b(угрожа|гроз)\w*\s+(\w+\s+){0,2}(убить|убьет|зарезать|зарежет|пристрелить|застрелить|покалечить|оружием|ружьем|пистолетом|ножом)\b|\b(убьет|прибьет|зарежет|пристрелит|придушит)\s+(меня|нас|детей|ребенка|маму)\b'
level: acute
- id: dv.raised_hand
pattern: '\bподн(ял|има)\w*\s+на\s+(меня|нас|детей|ребенка)\s+руку\b|\bруку\s+на\s+(меня|нас|детей|ребенка)\b|\b(схватил|хватает|сдавил)\w*\s+(\w+\s+)?за\s+(горло|шею)\b|\bброса\w*\s+на\s+(меня|нас|детей)\b'
level: acute
- id: dv.keyword
pattern: '\bдомашн\w*\s+насили\w*|\bабьюз\w*|\bтиран\w*'
level: acute
negation: pre_post
- id: dv.fear
pattern: '\bбоюсь\s+(\w+\s+)?(мужа|жены|отца|отчима|сына|его|ее|возвращаться\s+домой|идти\s+домой)\b|\b(ломает|крушит|разбил|разбивает)\s+(\w+\s+)?(вещи|мебель|посуду|дверь|двери)\b|\b(запира|запер)\w*\s+(меня|нас)\b|\bне\s+выпускает\s+(\w+\s+)?из\s+дома\b|\bв\s+синяках\b'
level: possible
hopelessness:
description: "Безнадёжность, обесценивание себя — сигнал для C-SSRS (possible)"
rules:
- id: hope.meaningless
pattern: '\bбессмысл\w*|\bнет\s+(\w+\s+)?смысла\b|\bсмысла\s+(\w+\s+)?нет\b|\bне\s+вижу\s+(\w+\s+)?смысла\b|\bникакого\s+смысла\b|\bсмысл\w*\s+(\w+\s+)?(потерян|пропал)\w*'
level: possible
- id: hope.tired_of_everything
pattern: '\bустал\w*\s+(\w+\s+)?от\s+(всего|всех|этого\s+всего)\b|\bвс[её]\s+(\w+\s+)?надоело\b|\bничего\s+не\s+х[ао]чу\b'
level: possible
- id: hope.burden
pattern: '\bобуз[аеоуы]\w*'
level: possible
- id: hope.no_way_out
pattern: '\bбезнад[её]ж\w*|\bбезысход\w*|\bвыхода\s+(\w+\s+)?нет\b|\bнет\s+(\w+\s+)?выхода\b|\bне\s+вижу\s+(\w+\s+)?выхода\b|\bтупик\w*'
level: possible
- id: hope.no_future
pattern: '\bничего\s+(\w+\s+)?не\s+(изменится|поменяется|поможет|исправить)\b|\bне\s+вижу\s+(\w+\s+)?будущ\w*|\bбудущего\s+(\w+\s+)?нет\b'
level: possible
- id: hope.worthless
pattern: '\bникому\s+(\w+\s+)?не\s+нуж(ен|на|ны)\b|\bвсем\s+(\w+\s+)?(на\s+меня\s+)?плевать\b|\bзачем\s+я\s+(вообще\s+)?(живу|выжил|вернулся|нужен|родился)\b|\bя\s+(\w+\s+)?ничтожество\b'
level: possible
- id: hope.cant_take_it
pattern: '\bсил\s+(\w+\s+)?нет\s+(терпеть|больше)\b|\bбольше\s+нет\s+сил\b|\bне\s+выдержу\b|\bсдаюсь\b|\bпустот[аеуы]\b'
level: possible
# Комбинации: если в одном сообщении есть совпадения из всех `all_of` и хотя бы одной из `any_of` категорий,
# итоговый уровень поднимается до `level`. Ограничение доступа к средствам — одна из самых доказательных мер
# профилактики, поэтому оружие + любой сигнал риска = acute (ADR-006: «доступ к оружию при риске» → красный).
combinations:
- id: combo.weapon_with_risk
all_of: [weapon_access]
any_of: [suicide, self_harm, harm_others, hopelessness, domestic_violence]
level: acute
# Обработка отрицаний (только для правил уровня acute; снижает acute → possible, не ниже).
# ПЕРЕД совпадением: идём назад по словам (не дальше `window` и не через границу предложения/запятую),
# пропуская «связки» (bridge_words). Встретили отрицание (negators) → правило отрицается.
# Любое другое слово — стоп, отрицания нет. Пример: «не думаю о суициде» → не ← думаю ← о ← [суицид].
# «ничего не хочу хочу умереть» → перед совпадением «хочу» (не связка) → стоп → acute сохраняется.
# ПОСЛЕ совпадения (только negation: pre_post): пропускаем связки, затем ищем post_negators
# («нет», «нету», «отсутствуют») или «не» + слово из post_not_followers («не было», «не возникало»).
# «мысли о суициде не отпускают» → «не отпускают» не в списке → acute сохраняется.
negation:
window: 4
negators: [не, нет, ни, нету, никогда, без, никаких, нисколько]
bridge_words: [о, об, обо, про, думаю, думал, думала, думаем, задумывался, задумывалась, мыслей, мысли, мысль,
планирую, планировал, планировала, собираюсь, собирался, собиралась, планов, намерений,
у, меня, есть, было, были, сейчас, вообще, совсем, даже, уже, точно, давно, разу, раз, и,
суицидальных, суицидальные, таких, этих, никаких, никогда, дома, в, этом]
post_negators: [нет, нету, отсутствуют, отсутствует]
post_not_followers: [было, были, бывает, бывало, возникает, возникали, возникало, возникают, появлялось,
появлялись, появляются, посещают, посещали, испытываю, испытывал, испытывала]