Почему медицинские агенты все еще не работают у вас в больнице
Вы видели демо. Агент читает историю болезни, ставит предположительный диагноз, советует терапию. Звучит как будущее. А потом вы пытаетесь запустить это в реальной клинике, и все ломается. Модель галлюцинирует, доступ к медицинским данным заблокирован файрволом, а юристы хватаются за голову.
Проблема не в моделях. Claude 3.5 Sonnet или Llama 3.2 90B достаточно умны. Проблема в архитектуре. В том, как заставить модель безопасно взаимодействовать с инструментами, EHR-системами (Electronic Health Records) и при этом не сойти с ума от контекста в 200 тысяч токенов.
Самый частый провал - это попытка запихнуть все в один промпт к ChatGPT API. Не делайте так. Медицина требует модульности, аудита и четкого разделения ответственности между компонентами.
Спасательный круг: smolagents от Hugging Face и сервисы AWS
В 2026 году экосистема для сборки агентов созрела. Hugging Face smolagents (актуальная версия 2.1+) - это не просто еще один фреймворк. Это минималистичный, но мощный каркас, который заставляет вас думать об архитектуре, а не о синтаксисе. Он родился из осознания, что большие фреймворки часто мешают в production.
А AWS? Это ваша инфраструктурная платформа. Не просто для запуска моделей, а для создания цепочки: безопасный доступ к данным → выполнение агента → логирование и мониторинг. Связка smolagents и AWS решает ключевые вопросы:
- Безопасность и комплаенс: Данные пациентов не улетают в сторонние API.
- Масштаб: От десятка запросов в день до тысяч параллельных консультаций.
- Интеграция: Агент становится частью IT-ландшафта больницы, а не игрушкой в Jupyter Notebook.
Если вы хотите глубже понять философию проектирования современных агентов, загляните в наш гайд о проектировании AI-агентов.
Архитектура: что происходит под капотом
Забудьте про монолитного агента. Наш медицинский помощник - это система.
| Слой | Технологии (актуально на 01.03.2026) | Зачем |
|---|---|---|
| Оркестратор / Мозг | Hugging Face smolagents, модель (Llama 3.2 90B или Claude 3.5 через Bedrock) | Принимает решение, какой инструмент использовать и в каком порядке. Не лечит, а планирует. |
| Инструменты (Skills) | Python-функции, обернутые в smolagents.Tool, доступ к AWS HealthLake, медицинским калькуляторам | Конкретные действия: рассчитать дозу, поиск в медицинской литературе, запрос к EHR. |
| Безопасный контекст | AWS PrivateLink, VPC, зашифрованные S3-бакеты для данных | Изоляция данных пациента. Ключевой момент для HIPAA/GDPR. |
| Сервисный слой | FastAPI (контейнеризованный), запущенный на AWS Fargate или SageMaker Endpoints | Предоставляет REST API для интеграции с фронтендом или EHR-системой. |
Архитектура напоминает принципы, описанные в статье про production-ready агентов, но заточена именно под медицинские нужды.
1 Готовим инструменты: что умеет наш врач-агент
Агент без инструментов - просто чат-бот. Вот набор, который имеет смысл:
from smolagents import Tool
from typing import Dict
import json
# 1. Инструмент для поиска в медицинской базе знаний (условно)
class MedicalLiteratureSearchTool(Tool):
name = "medical_literature_search"
description = "Searches the latest medical guidelines and research for a given query."
inputs = {"query": "The medical question or topic to search for"}
def forward(self, query: str) -> str:
# Здесь интеграция с PubMed API или собственной векторной БЗ
# Например, через Amazon Bedrock Knowledge Bases
return f"Found relevant info on {query}: ..."
# 2. Калькулятор дозировки (крайне упрощенно!)
class DoseCalculatorTool(Tool):
name = "calculate_dose"
description = "Calculates medication dose based on weight, condition, and guidelines."
inputs = {
"drug_name": "Name of the medication",
"patient_weight_kg": "Patient's weight in kilograms",
"condition": "Medical condition being treated"
}
def forward(self, drug_name: str, patient_weight_kg: float, condition: str) -> Dict:
# В реальности - сложная логика с проверкой по базе данных
# Это пример, не используйте в реальной медицине!
standard_dose_per_kg = 5.0 # мг/кг
calculated_dose = patient_weight_kg * standard_dose_per_kg
return {
"drug": drug_name,
"calculated_dose_mg": round(calculated_dose, 2),
"warning": "ALWAYS verify with a licensed pharmacist."
}
# 3. Инструмент для запроса безопасных данных из EHR (имитация)
class QueryPatientEHRTool(Tool):
name = "query_patient_ehr"
description = "Retrieves de-identified patient data from the EHR system for the current session."
inputs = {"patient_id": "De-identified patient identifier"}
def forward(self, patient_id: str) -> str:
# В production здесь будет вызов AWS HealthLake или API вашей EHR
# через PrivateLink в безопасной VPC
mock_data = {
"age": 45,
"latest_observations": {"blood_pressure": "120/80"},
"active_medications": ["Lisinopril"]
}
return json.dumps(mock_data, indent=2)
Внимание! Калькулятор дозировки выше - это демо-заглушка. Настоящий медицинский инструмент должен быть валидирован, сертифицирован и включать десятки проверок. Не используйте такой код в реальных системах без участия врачей и фармакологов.
Идея в том, что каждый инструмент делает одну конкретную, проверяемую вещь. Это делает агента интерпретируемым. Вы всегда можете посмотреть в логи, какой инструмент был вызван и с какими аргументами. В медицине это не просто удобно, это обязательно.
2 Собираем агента воедино с smolagents
Теперь склеиваем инструменты с моделью. Ключевая фишка smolagents - минимализм. Вы явно указываете, что чем управляет.
from smolagents import CodeAgent, ToolCallingAgent
from dotenv import load_dotenv
import os
load_dotenv()
# Создаем экземпляры инструментов
med_search_tool = MedicalLiteratureSearchTool()
dose_calc_tool = DoseCalculatorTool()
ehr_query_tool = QueryPatientEHRTool()
tools = [med_search_tool, dose_calc_tool, ehr_query_tool]
# Выбор модели: локальная или через Bedrock
# Вариант 1: Локальная модель (например, для прототипирования в VPC)
# from transformers import AutoModelForCausalLM, AutoTokenizer
# model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-90B")
# Вариант 2: Модель через Amazon Bedrock (актуально на 2026)
# Это предпочтительный путь для production: управляемый сервис, compliance, масштабирование.
import boto3
from smolagents.models import BedrockModel
# Инициализация клиента Bedrock (предполагается, что права есть)
bedrock_client = boto3.client(
service_name='bedrock-runtime',
region_name='us-east-1'
)
# Используем Claude 3.5 Sonnet - одна из самых способных моделей на 2026 для рассуждений
model = BedrockModel(
model_id="anthropic.claude-3-5-sonnet-20241022",
client=bedrock_client,
max_tokens=4000
)
# Создаем агента
agent = ToolCallingAgent(
model=model,
tools=tools,
max_steps=6, # Ограничиваем, чтобы агент не зациклился
verbosity_level=2 # Подробные логи для отладки
)
# Тестовый запуск
question = "Пациент ID-12345, вес 70 кг. Какая рекомендуемая стартовая доза препарата X для лечения гипертонии согласно последним гайдлайнам?"
try:
answer = agent.run(question)
print("Ответ агента:", answer)
except Exception as e:
print(f"Агент споткнулся: {e}")
Что здесь происходит? Агент получает вопрос, планирует цепочку: 1) Запросить данные пациента из EHR. 2) Поискать актуальные гайдлайны по гипертонии и препарату X. 3) Рассчитать дозу, используя вес из EHR и информацию из гайдлайнов. Smolagents управляет этим циклом (think → act → observe).
3 Упаковка и деплой на AWS: где живет production-агент
Запуск скрипта на ноутбуке - это не продакшен. Медицинская система требует отказоустойчивости, мониторинга и безопасности. Вот план развертывания.
Шаг 3.1: Контейнеризация
Упаковываем агента, инструменты и легковесный HTTP-сервер (например, FastAPI) в Docker-контейнер.
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
# Устанавливаем системные зависимости, если нужны
RUN apt-get update && apt-get install -y --no-install-recommends gcc g++ && rm -rf /var/lib/apt/lists/*
# Копируем requirements
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Копируем исходный код
COPY app ./app
# Открываем порт
EXPOSE 8000
# Запускаем сервер
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
# app/main.py - основа FastAPI приложения
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from app.agent import get_medical_agent # Ваша функция для создания агента
import logging
app = FastAPI(title="Medical AI Agent API")
logger = logging.getLogger(__name__)
# Глобально инициализируем агента (или лениво в запросе)
agent = None
class AgentQuery(BaseModel):
question: str
session_id: str # Для трекинга диалога
patient_id: str | None = None # Деидентифицированный ID
@app.on_event("startup")
async def startup_event():
global agent
logger.info("Initializing Medical Agent...")
agent = get_medical_agent()
logger.info("Agent ready.")
@app.post("/query")
async def query_agent(query: AgentQuery):
if not agent:
raise HTTPException(status_code=503, detail="Agent not initialized")
# Здесь можно добавить валидацию, проверку прав доступа к patient_id и т.д.
logger.info(f"Processing query for session {query.session_id}")
try:
result = agent.run(query.question)
# Обязательно логируем вопрос и ответ (в безопасном, деидентифицированном виде)
logger.info(f"Session {query.session_id}: Q: {query.question[:100]}... | A generated.")
return {"session_id": query.session_id, "answer": result, "status": "success"}
except Exception as e:
logger.error(f"Agent error in session {query.session_id}: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Agent processing failed: {str(e)}")
Шаг 3.2: Развертывание на AWS
У вас есть несколько путей, но для медицинского load'а сценарий обычно такой:
- Реестр образов: Заливаем Docker-образ в Amazon ECR (Elastic Container Registry).
- Оркестрация: Запускаем сервис на AWS Fargate. Почему Fargate, а не SageMaker Endpoints? Потому что наш агент - это кастомное Python-приложение со сложными зависимостями, а не просто модель для инференса. Fargate дает полный контроль над окружением.
- Сеть: Размещаем сервис в приватных подсетях VPC. Настраиваем AWS PrivateLink для безопасного доступа к внутренним API (например, к вашей EHR-системе или AWS HealthLake). Входящий трафик из интернета идет через Application Load Balancer (ALB) с TLS-терминацией.
- Секреты и конфигурация: Ключи API для Bedrock, параметры подключения к базам данных храним в AWS Secrets Manager и передаем в контейнер через переменные окружения.
- Мониторинг: Логи агента (через CloudWatch Logs) и метрики (задержка, количество шагов, ошибки инструментов) настраиваем для тревог. Это критично для отладки и compliance.
Развернуть все это руками - боль. Используйте Infrastructure as Code. Вот кусочек Terraform для Fargate (концептуально):
# main.tf (фрагмент)
resource "aws_ecs_task_definition" "medical_agent" {
family = "medical-agent"
cpu = "4096" # 4 vCPU
memory = "16384" # 16 GB - для больших моделей в памяти
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
execution_role_arn = aws_iam_role.ecs_execution_role.arn
task_role_arn = aws_iam_role.agent_task_role.arn # Роль с доступом к Bedrock, Secrets Manager и т.д.
container_definitions = jsonencode([{
name = "agent-container"
image = "${aws_ecr_repository.medical_agent.repository_url}:latest"
portMappings = [{ containerPort = 8000, hostPort = 8000 }]
environment = [
{ name = "BEDROCK_REGION", value = "us-east-1" },
# Остальное из Secrets Manager
]
secrets = [
{
name = "BEDROCK_ACCESS_KEY"
valueFrom = data.aws_secretsmanager_secret_version.bedrock_creds.arn
}
]
logConfiguration = {
logDriver = "awslogs",
options = {
"awslogs-group" = "/ecs/medical-agent",
"awslogs-region" = var.region,
"awslogs-stream-prefix" = "ecs"
}
}
}])
}
Почему не SageMaker? SageMaker Endpoints отлично подходят для обслуживания одной модели. Но наш агент - это приложение с состоянием, множеством вызовов инструментов и сложной логикой. Его проще упаковать в контейнер и запустить как сервис. Хотя, для прототипа вы можете использовать SageMaker JumpStart с готовыми контейнерами для моделей, а логику агента реализовать в лямбде. Но это быстро становится громоздко.
Где все еще больно: ошибки, которые сломают ваш агент
Теория гладкая. Практика - это сплошные грабли.
- Модель отказывается пользоваться инструментами. Особенно в медицинских сценариях, где ответ «я не могу» предпочтительнее галлюцинации. Решение: Тщательно промпт-инжиниринг в smolagents, описание инструментов с явным указанием их важности. И выбор модели, которая хорошо слушает инструкции (Claude 3.5 в этом чемпион).
- Зацикливание. Агент вызывает один и тот же инструмент с одинаковыми аргументами по кругу. Решение: Строгое ограничение
max_steps, добавление инструмента-«предохранителя», который завершает сессию при повторении. - Утечка PII (Personal Identifiable Information). Самое страшное. Модель может случайно вывести имя пациента в ответе. Решение: Все инструменты, работающие с EHR, должны возвращать только деидентифицированные данные. На выходе агента ставьте дополнительный фильтр-сканер на PII (например, с помощью Amazon Comprehend Medical).
- Непредсказуемая стоимость. Bedrock Claude 3.5 за 1000 токенов входных/выходных данных стоит денег, а агент может делать много шагов. Решение: Жесткие лимиты на длину запроса и количество шагов, мониторинг стоимости на дашборде AWS Cost Explorer.
Оценивать готовность такой системы к продакшену вам поможет фреймворк, о котором мы писали в статье про оценку AI-агентов Amazon.
Что дальше? Агент как часть команды
Успешно развернутый агент - это не конец, а начало. Следующий уровень - интеграция в рабочие процессы врачей. Не как замена, а как ассистент.
Представьте интерфейс, где врач видит ход рассуждений агента: «Я запросил историю прививок → проверил гайдлайны CDC → рассчитал, что вакцина X рекомендуется». Это builds trust. Логи каждого сеанса можно использовать для улучшения инструментов и обучения новых моделей (с соблюдением всех этических норм и анонимизации).
Совет напоследок: начните с узкой, конкретной медицинской задачи. Не «диагностика», а «помощь в подборе начальной дозы антикоагулянта на основе веса, возраста и функции почек». Соберите для нее набор проверенных инструментов. Отработайте цикл на прототипе с юристами и врачами. И только потом масштабируйте архитектуру на AWS. Так у вас будет меньше шансов построить еще одну крутую, но бесполезную игрушку.