Игорь Градов
Игорь Градов
5 мин
ai

ИИ-агенты для здоровья: как связать Apple Health, парсер и Claude в один дневник

Apple Health хранит данные в закрытой экосистеме, но отдаёт их тремя способами.

ИИ-агенты для здоровья: как связать Apple Health, парсер и Claude в один дневник

Ручной экспорт. Настройки → Здоровье → Экспортировать медданные. Выгружается ZIP с XML всех записей. Файл бывает большим, у меня около 300 МБ за несколько лет.

Ярлыки (Shortcuts). Через приложение «Команды» можно запросить конкретный тип данных за период и сохранить результат в файл. Подходит, когда нужны только тренировки за последнюю неделю.

Сторонние приложения. Health Auto Export и подобные утилиты могут выгружать данные автоматически в CSV или JSON. Удобно, но каждое такое приложение получает доступ ко всей медицинской истории.

Для моей системы хватает ручного экспорта раз в одну‑две недели. Если частота вырастет, перейду на Shortcuts.

Как парсер обрабатывает XML

Apple Health отдаёт каждую тренировку как элемент <Workout> с атрибутами: тип, дата начала, длительность, дистанция, активная энергия. Пульс хранится отдельно, в <HeartRateStatistics> или в отдельных <Record> с типом HKQuantityTypeIdentifierHeartRate.

Парсер делает четыре вещи:

  1. Находит тренировки за нужный период.
  2. Извлекает поля: тип, дата, длительность, дистанция, средний и максимальный пульс, активные калории.
  3. Нормализует единицы. Apple хранит дистанцию в километрах или милях в зависимости от настроек. Парсер приводит всё к километрам и минутам.
  4. Генерирует source_record_id — уникальный ключ записи, чтобы при повторном импорте не создать дубль.

Ключ дубликата я строю из sourceName + startDate + workoutActivityType. Если файл с таким ключом уже существует, парсер дополняет пустые поля, но не трогает заполненные вручную.

import xml.etree.ElementTree as ET
from pathlib import Path
import hashlib, json

def parse_workouts(export_path: str, since: str):
    tree = ET.parse(Path(export_path) / "export.xml")
    root = tree.getroot()
    workouts = []
    for w in root.iter("Workout"):
        if w.get("startDate", "") >= since:
            uid = hashlib.md5(
                f'{w.get("sourceName")}{w.get("startDate")}{w.get("workoutActivityType")}'
                .encode()
            ).hexdigest()[:12]
            workouts.append({
                "source_record_id": uid,
                "workout_type": w.get("workoutActivityType"),
                "workout_date": w.get("startDate")[:10],
                "workout_time": w.get("startDate")[11:16],
                "duration_min": round(float(w.get("duration", 0))),
                "distance_km": round(float(w.get("totalDistance", 0)), 2),
                "active_kcal": round(float(w.get("totalEnergyBurned", 0))),
            })
    return workouts

Скрипт минимальный. Пульс из <HeartRateStatistics> можно добавить вторым проходом по <WorkoutStatistics> внутри каждого <Workout>.

Как агент обрабатывает ввод

Агент — это системный промпт (постоянная инструкция, которую модель получает до вашего сообщения) плюс доступ к файлам Obsidian. Я использую Claude с подключённой папкой через MCP.

Задача агента — превратить короткое сообщение в структурированную запись. Вот как выглядит типичный обмен:

Я пишу:

Пробежал 3 км, колено ноет после второго километра, пульс не смотрел

Агент находит сегодняшний файл тренировки (или создаёт новый по шаблону), заполняет:

  • distance_km: 3
  • pain_level: 1
  • В секцию «Факт» добавляет: «Бег 3 км. Боль в колене после 2-го км.»
  • Исходное сообщение сохраняет в секцию «Сырой ввод».

Агент не заполняет поля, которых нет в сообщении. Пульс остаётся пустым до импорта из Apple Health.

Системный промпт агента

Ты — ассистент по ведению дневника тренировок в Obsidian.

Правила:

1. Не давай медицинских рекомендаций. Не интерпретируй боль.
2. Если поле не упомянуто в сообщении, оставь его пустым.
3. Не путай «не записано» с «нет». Пустое поле ≠ 0.
4. Сохраняй исходный текст пользователя без изменений.
5. При конфликте между ручной записью и импортом спроси.
6. Недельную сводку готовь только по запросу.

Агент не принимает решений о нагрузке. Он может показать, что за неделю пульс рос при той же дистанции, но вывод делает человек.

Недельная сводка

Раз в неделю я прошу агента собрать итог. Запрос простой:

Собери сводку за эту неделю

Агент проходит по файлам тренировок, берёт заполненные поля и возвращает таблицу:

Дата Тип Дистанция Ср. пульс Боль Заметка
07-14 Бег 2.1 км 131 0 Лёгкий темп
07-15 Бег 3.0 км — 1 Колено после 2 км
07-17 Подтяг. — — 0 5×8, последний подход тяжёлый

Под таблицей агент добавляет наблюдения без оценок: «Дистанция выросла на 0.9 км, данных о пульсе за 15-е нет, боль появилась впервые за неделю».

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

Почему агент не должен давать советы

В системном промпте я явно запретил медицинские рекомендации. Причин три.

Языковая модель не имеет доступа к полной клинической картине. Она видит только то, что я записал. А я записываю не всё.

Галлюцинация (когда модель уверенно выдаёт несуществующий факт) в контексте здоровья опаснее, чем в любом другом. «Снизь нагрузку на 20%» звучит разумно, но без знания анамнеза может быть и слишком много, и слишком мало.

Ответственность. Если агент посоветовал, а я послушал и стало хуже — виноват я, но ощущение будет другим. Чёткая граница «агент показывает, человек решает» убирает эту ловушку.

Что дальше

Сейчас система работает для бега и силовых. Следующий шаг — добавить сон. Apple Watch записывает фазы сна, и было бы полезно видеть качество сна рядом с нагрузкой предыдущего дня.

Второе — автоматизировать импорт через Shortcuts, чтобы не делать ручной экспорт. Пока это не критично при частоте раз в две недели.

Третье — попробовать ту же схему для анализов. Структура та же: шаблон с YAML-полями, агент для ввода, запрет на интерпретацию результатов.

Система намеренно простая. В ней нет машинного обучения, нейросетевых моделей или предиктивной аналитики. Это текстовые файлы, парсер и языковая модель, которая помогает их заполнять и читать. Вся ценность — в том, что план, факт и контекст лежат рядом.

Исходники парсера, шаблоны Obsidian и системный промпт агента я выложу в репозиторий, когда допишу документацию. Подписывайтесь, чтобы не пропустить.

Источник: https://thisnot.blog/posts/health-tracking-agent

Поделиться:TelegramVK
Игорь Градов
Игорь Градов

Основатель dzen.guru. Эксперт по монетизации и продвижению на Дзен. Автор курса «Старт на Дзен 2026».

Комментарии

Читайте также

Google разворачивает ИИ в медицине Сингапура: $7 млн на науку и ИИ-коуч для жителей
ai

Google разворачивает ИИ в медицине Сингапура: $7 млн на науку и ИИ-коуч для жителей

Google на саммите Google for Health Summit объявила о развёртывании передового ИИ во всей системе здравоохранения Сингапура, где старение населения…

5 мин
Google расширяет рекламу в ИИ-поиске на весь мир: рост поиска замедлился до 12%
ai

Google расширяет рекламу в ИИ-поиске на весь мир: рост поиска замедлился до 12%

Google на квартальной отчётной конференции Alphabet объявила, что выводит рекламу в ИИ-поиске за пределы США, и сделала это на фоне замедления роста поисковой…

5 мин
Gemini открыл интерактивные сцены для всех: 6 языков, русского среди них нет
ai

Gemini открыл интерактивные сцены для всех: 6 языков, русского среди них нет

Чат-бот Gemini открыл библиотеку погружений в темы, интерактивных сцен от атомов до дальнего космоса, и запустил её сразу для всех пользователей, хотя русского…

4 мин