Он уже отправлял это письмо. Три раза
Представьте: ваш агент мониторит тикеты в Jira. Новый баг-репорт - он создает задачу, назначает на разработчика, отправляет уведомление в Slack. Через час тот же тикет появляется снова (система глючит). Агент создает еще одну задачу. И еще. И еще. Разработчик получает 5 одинаковых писем. Команда в панике.
Это не гипотетический сценарий. Это понедельник для каждого, кто запускал долгоживущих агентов на локальных LLM в 2025 году.
Главный парадокс 2026: чем умнее агент, тем глупее он себя ведет в долгоживущих сессиях. GPT-4o, Claude 3.5 Sonnet, локальные Mixtral 8x22B - все они страдают амнезией операций.
Почему state management - это не просто "сохрани контекст"
Когда говорят "управление состоянием агента", 90% разработчиков думают о сохранении истории диалога. Вот и первая ошибка.
История диалога - это то, что агент ВИДИТ. Состояние операций - это то, что агент СДЕЛАЛ. Разница колоссальная.
- Агент может помнить, что обсуждал отправку письма (контекст)
- И забыть, что уже отправил его (состояние операции)
- Или помнить отправку, но не помнить ID созданной задачи в Jira
- Или помнить ID, но не знать, что задача уже выполнена другим агентом
Это не баг LLM. Это фундаментальное несоответствие между дискретными вызовами модели и непрерывным workflow.
Три призрака долгоживущих агентов
1 Призрак дублирования: когда одна операция выполняется N раз
Классика. Агент анализирует почту каждые 5 минут. Видит письмо от клиента. Создает тикет. Через 5 минут видит то же письмо (оно еще в inbox). Создает еще тикет.
Почему это происходит? Потому что проверка "уже обработано" требует:
# Наивный подход (не работает)
if "обработать письмо" in история_диалога:
пропустить()
Но агент может сформулировать задачу по-разному: "создать тикет для клиента X", "обработать запрос от email@example.com", "добавить задачу по письму про баг".
2 Призрак рассинхронизации: когда состояние мира изменилось без ведома агента
Агент создал задачу в Jira с ID=123. Запланировал проверку через час. За это время задачу вручную закрыли. Агент проверяет - видит статус "закрыта". Но в его ментальной модели задача все еще "в работе".
Хуже: агент пытается обновить закрытую задачу. Или отправить уведомление о прогрессе, когда все уже решено.
Эта проблема напрямую связана с эпистемической асимметрией - агенту не хватает контекста изменений.
3 Призрак каскадных отказов: когда одна ошибка ломает всю цепочку
Агент должен: 1) получить данные из API, 2) обработать, 3) сохранить в БД, 4) отправить уведомление.
Шаг 3 падает (коннект к БД потерян). Агент фиксирует ошибку. Но что происходит с шагами 1 и 2? Они уже выполнены. Данные в памяти. При перезапуске агент начнет с шага 1... и получит те же данные (дублирование).
Или хуже: агент попытается откатить изменения, но не знает как - потому что откат не прописан в его skills.
Архитектурные антидоты: как проектировать агентов, которые помнят
Operation Registry - реестр операций вместо истории чата
Забудьте о сохранении простого контекста. Нужен структурированный журнал операций:
| Поле | Зачем нужно | Пример |
|---|---|---|
| operation_id | Уникальный ID операции (UUID) | op_abc123 |
| input_signature | Хеш входящих данных для дедупликации | sha256(email+timestamp) |
| external_ids | ID во внешних системах (Jira, Slack) | {"jira": "PROJ-123", "slack": "C123ABC"} |
| state_machine | Текущее состояние в workflow | {"step": 3, "status": "failed", "retries": 2} |
| compensation_actions | Как откатить операцию при ошибке | ["delete_jira_issue", "revoke_slack_message"] |
Это не просто логи. Это единственный источник правды о том, что агент СДЕЛАЛ в мире.
Сквозные транзакции с сагой-паттерном
Для мультишаговых операций нужна сага - последовательность компенсируемых транзакций. В 2026 для этого есть готовые решения:
# Псевдокод саги для обработки тикета
saga = SagaBuilder()\.add_step(
name="create_jira_issue",
execute=create_issue,
compensate=delete_issue # Функция отката
)\.add_step(
name="notify_slack",
execute=send_slack_message,
compensate=delete_message
)\.add_step(
name="schedule_followup",
execute=add_calendar_event,
compensate=remove_event
)\.build()
# При ошибке на шаге 2, автоматически выполняются
# compensate шага 2, затем шага 1
Сагу нужно сохранять в Operation Registry после КАЖДОГО шага. При перезапуске агент может восстановить состояние и решить: продолжить, откатить или перезапустить с определенного шага.
Event Sourcing для агентов: переосмысление подхода
Вместо того чтобы спрашивать агента "что ты помнишь?", мы даем ему поток событий:
# Восстановление контекста агента при перезапуске
events = event_store.get_events(
agent_id="support_bot",
since=last_checkpoint
)
# Агент получает не историю диалога, а факты:
# 1. 2026-02-03 10:00: Создана задача PROJ-456
# 2. 2026-02-03 10:05: Задаче назначен статус "In Progress"
# 3. 2026-02-03 10:30: Пользователь добавил комментарий
# 4. 2026-02-03 11:00: Задача закрыта (вручную)
# Теперь агент понимает реальное состояние мира
Это решает проблему рассинхронизации. Агент всегда работает с актуальным состоянием, а не с устаревшей ментальной моделью.
Практическая реализация: от теории к продакшену
1 Выбираем правильные инструменты (2026 edition)
Для локальных агентов в 2026 нужно:
- База состояний: Redis с модулем RedisJSON или PostgreSQL с jsonb. Ключевое - быстрый lookup по input_signature.
- Очередь операций: RabbitMQ с persistent messages или Apache Kafka. Обязательно с подтверждением доставки.
- Модель: Любая из LLM с поддержкой Tool Calling, но с важным дополнением - она должна уметь работать с operation registry как с контекстом.
Важно: Не храните состояние в памяти процесса. Любой restart = потеря всего. Используйте внешние хранилища с атомарными операциями.
2 Пишем детерминированные skills с идемпотентностью
Каждый skill (инструмент агента) должен быть идемпотентным. Вызов с теми же параметрами = тот же результат, без побочных эффектов.
# ПЛОХО: создает дубликаты
def create_jira_issue(title, description):
return jira_client.create_issue(title, description)
# ХОРОШО: проверяет существование сначала
def create_jira_issue(title, description, dedupe_hash):
# Проверяем по хешу в operation registry
existing = registry.find_by_signature(dedupe_hash)
if existing:
return existing.external_ids["jira"]
# Создаем с reference на dedupe_hash
issue = jira_client.create_issue(
title,
description,
custom_fields={"dedupe_hash": dedupe_hash}
)
# Сразу сохраняем в registry
registry.record_operation(
op_type="create_jira_issue",
signature=dedupe_hash,
external_ids={"jira": issue.key}
)
return issue.key
3 Реализуем health checks и самовосстановление
Долгоживущий агент должен регулярно проверять:
- Консистентность: все ли операции в registry имеют корректный статус в внешних системах?
- Зависшие операции: есть ли операции в статусе "in_progress" старше таймаута?
- Дубликаты: не появились ли операции с одинаковым signature?
При обнаружении проблем - агент либо сам исправляет (компенсирует дубликаты), либо эскалирует человеку.
Чего НЕ делать: самые частые ошибки 2025 года
Ошибка 1: Доверять LLM отслеживанию состояния. Модель может галлюцинировать о выполненных операциях. Все external calls должны проверяться через registry.
Ошибка 2: Использовать реляционные БД для operation registry. JOIN-ы убивают производительность. Нужны документ-ориентированные БД или специализированные solutions вроде Temporal.io.
Ошибка 3: Забывать про cleanup. Operation registry растет бесконечно. Нужны политики архивации: удалять успешные операции старше 30 дней, оставляя только metadata.
Связь с другими проблемами агентов
Управление состоянием - не изолированная проблема. Она напрямую влияет на:
- Отладку - без четкого operation registry невозможно понять, что пошло не так
- Тестирование - тесты должны проверять не только вызов функции, но и запись в registry
- Мультиагентные системы - когда несколько агентов работают над одним workflow, им нужен shared operation registry
- Надежность skills - skill без компенсации и дедупликации опасен для продакшена
Что будет в 2027? Прогноз от практика
Сейчас мы вручную пишем operation registry и саги. Это сложно. Ошибкоопасно.
К 2027 появятся:
- State-aware LLM frameworks: Библиотеки, где состояние - first-class citizen. Не нужно придумывать велосипеды.
- Автоматическая генерация compensation logic: LLM будет анализировать код skill и генерировать функции отката.
- Кросс-агентные consistency protocols: Как distributed consensus (Raft, Paxos), но для агентов.
- Визуальные debuggers для state flow: Инструменты типа Jaeger, но для трейсинга состояния агентов.
Но пока этого нет - приходится строить надежность самим. Мой совет: начните с простого operation registry на Redis. Добавьте deduplication по хешу. Реализуйте хотя бы один skill с компенсацией.
Потому что агент, который трижды отправляет одно письмо - это смешно. Агент, который трижды списывает деньги с карты - это уже уголовное дело.