Когда врачам нужен AI, который не сливает данные в облако
Представьте: онкологический центр с сотнями историй болезни, снимков, результатов биопсий. Им нужен AI-ассистент, который не отправит данные в Google Cloud, не подчиняется HIPAA через юридические танцы с бубном. Закрытые системы вроде Google Med-PaLM 2 работают хорошо, но вы не контролируете модель, не знаете, на каких данных она дообучена, а главное — ваши пациенты летят на сервера корпорации. IBM Watson for Oncology? Устарел морально и архитектурно. OncoAgent — это open-source ответ: мультиагентный оркестратор на LangGraph, с RAG-пайплайном и дообучением через QLoRA, который вы разворачиваете у себя на AMD MI300X. Если вам нужен приватный медицинский AI без компромиссов — вы на правильном пути.
Двухуровневая архитектура: супервизор и армия специалистов
OncoAgent построен по принципу dual-tier: сверху — supervisor-агент, снизу — пул специализированных агентов (радиолог, патолог, онколог, генетик). Supervisor пишется на LangGraph — фреймворке для построения графов из LLM-шагов. Он получает запрос, парсит его, раскладывает на подзадачи и отправляет нужному агенту.
Звучит логично? На практике графы LangGraph — та ещё боль. В статье AI-агент для код-ревью: как мы строили на LangGraph и что пошло не так авторы честно признаются, где споткнулись. OncoAgent использует похожий граф, но с жёсткой типизацией состояний: supervisor ждёт ответы от всех агентов, потом собирает единый отчёт.
Ключевая фишка: каждый специализированный агент — это отдельная LLM, дообученная на узком домене (например, радиолог — на радиологических заключениях). Supervisor не лезет в предметную область, он только координатор.
Как это выглядит в коде? Ниже — упрощённый пример графа на LangGraph (не пытайтесь скопировать один в один, тут опущены хитрости с очередями).
from langgraph.graph import StateGraph, END
class OncologyState(dict):
query: str
images: list[bytes]
lab_results: dict
radiologist_output: str = None
pathologist_output: str = None
oncologist_output: str = None
final_report: str = None
def radiologist_agent(state: OncologyState):
# Анализ снимков, возвращает текст
return {"radiologist_output": analyze_scan(state["images"])}
def pathologist_agent(state: OncologyState):
return {"pathologist_output": analyze_biopsy(state["lab_results"])}
def oncologist_agent(state: OncologyState):
return {"oncologist_output": recommend_treatment(state)}
def supervisor_decide(state):
if state.get("radiologist_output") and state.get("pathologist_output"):
return "oncologist"
return "wait"
builder = StateGraph(OncologyState)
builder.add_node("radiologist", radiologist_agent)
builder.add_node("pathologist", pathologist_agent)
builder.add_node("oncologist", oncologist_agent)
builder.set_conditional_edge_source("router", supervisor_decide, {"oncologist": "oncologist", "wait": END})
builder.set_entry_point("radiologist")
builder.add_edge("radiologist", "router")
# ... и так далее
Не советую использовать приведённый код для продакшна без обработки таймаутов и отказов. Supervisor должен уметь запрашивать уточнения, если агент вернул мусор.
RAG, который не галлюцинирует
Каждый агент имеет доступ к векторному хранилищу (FAISS или Chroma) с медицинскими документами: PubMed, клинические рекомендации NCCN, ESMO, FDA approvals. RAG-pipeline собирает релевантные фрагменты, чтобы модель не выдумывала стадии и протоколы.
Но базовая LLM (в текущей версии — Llama 3.3 70B) должна быть дообучена на медицинских текстах. Полный fine-tune на 70B — дорого (16 H100, 2 недели). OncoAgent использует QLoRA: 4-битное квантование + LoRA-адаптеры. Всё влезает на одну AMD MI300X с 192 ГБ HBM3. Скорость инференса — ~40 токенов/с для 70B модели в 4-bit.
| Метод | Потребление памяти | Время обучения (на MI300X) | Качество (F1 на MedQA) |
|---|---|---|---|
| Полный fine-tune (16-bit) | ~280 GB | ~14 дней | 82.1 |
| QLoRA (4-bit + LoRA rank=64) | ~48 GB | ~3 дня | 80.7 |
Потеря 1.4% F1 — допустимая плата за возможность развернуть всё на одном ускорителе, который к тому же стоит дешевле H100. Кстати, о настройке стека локальных LLM-агентов и выборе квантований читайте в материале Как настроить стек локальных LLM-агентов для программирования — подходы те же, только модель медицинская.
Сравнение с альтернативами: Google Med-PaLM vs OncoAgent
Рынок медицинских AI-систем — минное поле. Закрытые решения доминируют, но OncoAgent пробивает окно.
| Критерий | OncoAgent | Google Med-PaLM 2 | IBM Watson Health |
|---|---|---|---|
| Лицензия | Apache 2.0 | Закрытая (API) | Закрытая (EOL) |
| Приватность данных | Полная (локально) | Данные покидают клинику | – |
| Мультиагентная архитектура | Да (LangGraph) | Нет (одна модель) | Модульный, но не мультиагентный |
| Дообучение | QLoRA на своих данных | Недоступно | Только через IBM |
| Аппаратное обеспечение | AMD MI300X или NVIDIA A100/H100 | TPU Google | Любое (legacy) |
Med-PaLM 2 показывает высокую точность (на MedQA ~78%), но вы не сможете его адаптировать под специфику вашей клиники. OncoAgent проигрывает в эталонной точности (80.7% на том же бенчмарке после QLoRA), но выигрывает в гибкости.
Пример из жизни: анализ рентгенограммы с историей болезни
Допустим, пациент с подозрением на рак лёгкого. В систему загружают: КТ-снимки, предыдущие биопсии (текст), уровень онкомаркеров.
- Radiologist-агент использует дообученную модель для сегментации опухоли (на базе SAM-CLIP) и генерирует описание: размер, инвазия в лимфоузлы.
- Pathologist-агент анализирует текст биопсии, извлекает гистологический тип (аденокарцинома, EGFR-мутация?).
- Oncologist-агент консультируется с RAG (PubMed, NCCN) и выдает рекомендацию: "Таргетная терапия озимертинибом, рассмотреть иммунотерапию пембролизумабом".
- Supervisor собирает всё в PDF-отчёт на русском/английском.
Весь цикл занимает ~15 секунд на одном MI300X. При этом ни один байт не покидает сервер больницы.
Кому это реально нужно
OncoAgent — инструмент для тех, кто устал от чёрных ящиков:
- Исследовательские группы, которые хотят ставить эксперименты с мультиагентными архитектурами. Сравните с подходом, описанным в Как выбрать архитектуру мульти-агента — OncoAgent использует гибрид: supervisor с кондициональными рёбрами, а не полный mesh.
- Онкологические центры с собственным IT-отделом, которым нужна полная приватность.
- Разработчики медицинского AI, которые хотят форкнуть код и адаптировать под конкретный вид рака. Кстати, профессор биологии недавно собрал похожий multi-agent оркестратор для локальных LLM — его опыт подсказывает, что не стоит завязывать всю логику на одном supervisor, лучше сделать супервизора второго уровня для сложных запросов.
Закончу советом, который звучит банально, но игнорировать его — ошибка: не пытайтесь покрыть все 200+ видов рака сразу. Выберите один — рак лёгкого или молочной железы — соберите качественный датасет, отладьте граф и RAG, а потом масштабируйте. Иначе через месяц вы проклинаете день, когда решили, что мультиагент = универсальный солдат.