Как исправить ошибки LLM в медицине: 4 реальных кейса | AiManual
AiManual Logo Ai / Manual.
18 Июн 2026 Гайд

Ошибки при создании медицинского сервиса на LLM: 4 кейса из продакшна и как их исправить

Разбор фатальных ошибок при внедрении LLM в диагностику. Ложные диагнозы, дублирующие рекомендации, галлюцинации. Уроки для DevOps и ML-инженеров.

Реклама
cliv2

Введение: Медицина не прощает вольностей

Год назад мы запустили сервис по интерпретации гематологических анализов на базе LLM. Звучит круто? На бумаге — да. В продакшне — ад. Пациенты получали рекомендации с точностью до наоборот, врачи отказывались работать с системой, а один юрист уже готовил иск. В этой статье — четыре реальных прокола, которые мы допустили, и способы их исправления. Никакой теории — только кровь (в прямом смысле), пот и слезы DevOps-инженера.

Если вы думаете, что достаточно скормить модели пару медицинских учебников и она станет доктором, — вы либо не работали с LLM, либо не видели, что бывает, когда модель уверенно несет чушь. Поехали.

Кейс 1: «Доктор, у меня рак?» — Как мы научили LLM не паниковать

Проблема: гиперагрессивная интерпретация

Наша первая версия промпта звучала примерно как «Ты — опытный гематолог. Проанализируй результаты анализов и дай диагноз». LLM (GPT-4o на тот момент) при малейшем отклонении от нормы тут же пугала пациента онкологией. Пример: легкий лимфоцитоз (47% при референсе 19–37%) — и модель пишет «Возможно, хронический лимфолейкоз». Без контекста, без учета возраста пациента, без динамики.

В теории мы хотели получить настороженность. На практике — получили панику и звонки от разгневанных врачей. Корень зла? Модель не знала, где проводить границу между нормой и патологией. Она просто галлюцинировала вероятности, опираясь на свой обучающий корпус, где онкология встречается чаще, чем безобидный лимфоцитоз.

Ошибка: отсутствие пост-процессинга и жесткой фильтрации по клиническим протоколам. LLM нельзя доверять пороговые решения без внешнего валидатора.

Решение: контрольный слой с референсными диапазонами

Мы добавили этап проверки — перед тем как отдать ответ пользователю, система сравнивает каждый показатель с официальными референсными интервалами (из Минздрава РФ) и категоризирует отклонения: «незначительное», «умеренное», «критическое». Если модель выставляет диагноз «рак» при незначительном отклонении — блокируем и отправляем на доработку промпта.

Вот как выглядит минимальный пайплайн проверки:

def validate_interpretation(llm_output: dict, ref_ranges: dict) -> bool:
    for param, value in llm_output['parameters'].items():
        low, high = ref_ranges[param]
        deviation = abs(value - (low+high)/2)
        severity = 'critical' if deviation > 0.5*(high-low) else 'moderate' if deviation > 0.2*(high-low) else 'minor'
        if severity == 'critical':
            continue  # допустимо
        if severity == 'minor' and llm_output.get('diagnosis_severity') in ['severe']:
            return False  # блокируем
    return True

Детальнее про конструкцию control layer мы писали в статье «Как построить production-ready control layer для LLM: 8 компонентов с кодом и бенчмарками».

Пошаговый план исправления

  1. Собрать авторитетные справочники референсных интервалов (Минздрав, ВОЗ, UpToDate).
  2. Внедрить классификатор отклонений перед LLM-пайплайном.
  3. Добавить правило: если модель предсказывает заболевание тяжелее, чем позволяет степень отклонения, — вернуть ответ «normal» и запросить дополнительное подтверждение у врача.
  4. Верифицировать на синтетическом датасете с 1000+ вариантов.

Кейс 2: Железодефицит, который удвоился — дублирующие рекомендации

Проблема: недетерминированный вывод

Пациент сдает анализы дважды с интервалом в неделю. Показатели почти не изменились. Но LLM в первый раз советует «принимать препараты железа с витамином C», а во второй — «сначала проверить ферритин, потом решать». Разные советы по одним и тем же данным. Естественно, пациент в панике: «Почему второй врач думает иначе?».

Причина: LLM недетерминирована. Даже при нулевой температуре многие модели (GPT, Claude) показывают разброс из-за floating point операций и внутреннего состояния. Мы выявили, что до 30% повторных запросов с идентичным контекстом дают разные рекомендации.

Важно: в медицине воспроизводимость — это не роскошь, а юридическое требование. Если врач не может повторить результат — ответственность ложится на разработчика.

Решение: семантическое кэширование и детерминированный слой

Мы перестали отправлять каждый новый запрос напрямую в LLM. Вместо этого на уровне API вычисляется семантический хэш от контекста (показатели, возраст, пол) через эмбеддинги. Если хэш совпал с предыдущим — отдаем закэшированный ответ. Если не совпал, но семантическая близость > 95% — сверяемся: можно использовать предыдущий или перегенерировать с указанием «не противоречить предыдущему ответу».

Параллельно мы увеличили temperature до 0.0 (для некоторых моделей это не панацея, но снижает variance). А главное — внедрили юнит-тесты на детерминизм, как описано в статье «Тестируем недетерминированные LLM: как написать тесты для вызова функций и не сойти с ума».

Пошаговый план исправления

  1. Реализовать семантическое кэширование на основе эмбеддингов (sentence-transformers + FAISS).
  2. Для каждого уникального контекста генерировать канонический ответ один раз и сохранять.
  3. Добавить в промпт инструкцию: «Если ты уже отвечал на этот запрос, повтори предыдущий ответ дословно».
  4. Ввести регрессионные тесты на повторяемость: 10 запусков одинакового входа — все ответы должны быть идентичны по смыслу (сравнение через LLM-as-judge).

Кейс 3: Доктор Хаус, который выдумывает больных — галлюцинации с вымышленными диагнозами

Проблема: ссылки на несуществующие исследования

Однажды модель выдала пациенту заключение: «Выявлен редкий синдром Старгардта-Фишера, описанный в работе Elias Thorne (2019)». Проблема в том, что ни такого синдрома, ни Elias Thorne не существует. Это типичный феномен «Элиаса Торна», когда LLM генерирует правдоподобные, но полностью вымышленные сущности. Мы подробно разбирали этот кейс в отдельной статье «Феномен 'Elias Thorne': как LLM создают вымышленных экспертов и почему это опасно».

В контексте медицины это смертельно опасно. Пациент мог начать лечить несуществующую болезнь, а реальная — прогрессировать.

Ошибка: мы использовали LLM с открытым доступом к общим знаниям, не ограничивая домен только проверенными источниками. Модель «фантазировала», потому что не имела жесткой привязки к авторитетной базе.

Решение: RAG с верификацией источника

Мы перешли на Retrieval-Augmented Generation: LLM отвечает, только опираясь на заранее загруженные документы (протоколы Минздрава, PubMed, UpToDate). Каждый сгенерированный факт сопровождается ссылкой на конкретный документ. Если модель не находит подтверждения в базе — она должна ответить «Недостаточно данных для заключения».

Дополнительно внедрили rejection sampling: после генерации запускается модель-верификатор (отдельная небольшая LLM, специально обученная на медицинских текстах), которая проверяет, все ли утверждения подкреплены источниками. Если нет — ответ отклоняется и отправляется на повторную генерацию с более строгим промптом.

Про построение такого пайплайна читайте в статье «Как построить семантический пайплайн для LLM: от ETL к итеративной обработке данных».

Пошаговый план исправления

  1. Собрать корпус авторитетных медицинских документов (желательно в формате Markdown/PDF с разметкой).
  2. Построить векторное хранилище (Pinecone, Qdrant, Weaviate) и настроить RAG-пайплайн.
  3. В промпт добавить инструкцию: «Отвечай ТОЛЬКО на основе предоставленных документов. Если информации нет — напиши 'Диагноз не может быть поставлен на основе имеющихся данных'. Никогда не выдумывай источники».
  4. Внедрить верификатор фактов (можно использовать ту же модель с промптом «Проверь, все ли утверждения имеют источник в документах»).

Кейс 4: Бот, который не знает, когда молчать — ложные срабатывания делегирования

Проблема: LLM берет на себя функции врача

Наша система задумывалась как вспомогательный инструмент: она должна подсвечивать аномалии, но окончательное решение оставляет врачу. Однако LLM в некоторых случаях начинала давать конкретные предписания: «Примите 500 мг цефтриаксона внутримышечно». Это уже назначение лекарства — без лицензии, без проверки противопоказаний, без учета аллергий. Врачи возмутились, юридический отдел — в шоке.

Проблема оказалась в том, что промпт не содержал четкого ограничения на действия. Модель пыталась быть «полезной» и давала максимально конкретный ответ. Мы не предусмотрели фильтра, который запрещает LLM делать то, что должно делать другое программное обеспечение (система поддержки принятия решений врача, CPOE).

Решение: Delegation Filter

Этот концепт мы разобрали в статье «Delegation Filter: когда НЕ использовать LLM в продакшн-пайплайнах (чек-лист от инженера)». Суть простая: перед тем как отдать управление LLM, мы проверяем, относится ли запрос к категориям, которые модель может обрабатывать (анализ, интерпретация, визуализация) или к тем, которые строго запрещены (назначение лечения, выписка рецептов). Для запрещенных категорий мы просто не передаем управление модели — ответ генерируется шаблонной фразой «Обратитесь к врачу для назначения терапии».

Фильтр реализован как пре-процессор на уровне API: проверяет тип запроса (classification + regex по ключевым словам «назначить», «дозировка», «препарат»). Если срабатывает — LLM не вызывается вообще.

DELEGATION_RULES = {
    'prescribe': {'block': True, 'response': 'Обратитесь к врачу для назначения терапии.'},
    'interpret': {'block': False, 'model': 'gpt-4o'},
    'summarize': {'block': False, 'model': 'claude-4'}
}
def delegation_filter(request_type: str):
    rule = DELEGATION_RULES.get(request_type)
    if rule and rule['block']:
        return {'action': 'block', 'message': rule['response']}
    return {'action': 'proceed'}

Пошаговый план исправления

  1. Составить матрицу компетенций: какие типы запросов разрешены, какие запрещены.
  2. Реализовать классификатор запросов (можно на легковесной модели типа DistilBERT или даже на правилах).
  3. Внедрить фильтр как отдельный микросервис перед вызовом LLM.
  4. Провести аудит всех возможных промптов: нет ли в них случайных разрешений на назначение лечения.

Ошибки, которые мы заметили слишком поздно (и как их избежать заранее)

  • Переобучение на своих данных. Мы дообучали маленькую LLM на истории диагнозов одной больницы. В итоге модель стала выдавать результаты, смещенные в сторону практик именно этой клиники, игнорируя общепринятые протоколы. Решение: не дообучать на малых разнородных выборках, лучше использовать RAG.
  • Утечка персональных данных через промпты. Логирование всех запросов для дебага привело к тому, что в логах оказались ФИО и номера полисов. Пришлось экстренно внедрять скремблирование на уровне entry-прокси. Подробнее о построении безопасного ETL — в статье «Как создать самовосстанавливающийся ETL-пайплайн на Python с помощью LLM».
  • Cost inflation. RAG с верификатором удвоил расходы на токены. Мы оптимизировали: вместо отдельного верификатора используем «self-consistency» — генерируем 3 ответа и выбираем самый частотный. Это снизило cost на 40% без потери точности.
💡
Совет из траншеи: Лучшая LLM в медицине — та, которая молчит, когда не уверена. Мы потратили полгода, чтобы построить вокруг модели защитные решетки. И только тогда врач начал доверять системе. В 2026 году я ставлю на то, что контрольные слои станут важнее самих моделей. Тренируйте промпты и фильтры, а не гоняйтесь за benchmark-рекордами. Иначе однажды вы получите иск за то, что ваш бот «вылечил» здорового человека.

Подписаться на канал