Агент изменил заказ по старым данным из кэша инструмента
Помощник получает просьбу перенести доставку заказа на пятницу. Его инструмент чтения показывает статус «готов к отправке», адрес и версию записи. Пока модель формулирует следующий вызов, оператор в CRM меняет адрес и ставит срочную доставку на четверг. Инструмент записи агента отправляет старый объект целиком с новой датой. Если API принимает его без проверки версии, свежий адрес оператора исчезает. Проблема живёт между чтением и записью, даже если каждый отдельный вызов инструмента отработал без ошибки.
Зафиксируйте прочитанную версию
Ответ get_order должен приносить не только поля заказа, но и версию, например сильный HTTP ETag или числовой revision. Передайте эту версию инструменту change_delivery_date как обязательный аргумент. Если внешний API поддерживает HTTP If-Match, отправьте прочитанный ETag в этом заголовке при изменении. При несовпадении сервер вернёт 412 Precondition Failed и не выполнит запись. У базы с числовой ревизией аналогом будет условный UPDATE ... WHERE id = ? AND revision = ? с проверкой, обновилась ли ровно одна строка.
Сильный ETag сравнивает конкретное состояние ресурса; слабый тег с префиксом W/ не подходит для If-Match. Версия должна относиться именно к тому заказу, который меняется. Нельзя брать ETag из другого чтения или использовать одну глобальную «версию CRM» для всех сущностей. Для агента это отдельный контракт: аргументы записи включают order_id, новое значение и версию прочитанной записи.
Что делать после конфликта
Ответ 412 — повод остановить действие и заново прочитать заказ. Покажите модели оба состояния: «я видел адрес A и дату X; сейчас адрес B и дата Y». Дальше решайте по содержанию. Если изменился только не относящийся к доставке комментарий, действие можно повторить с новой версией после проверки правил. Если оператор уже перенёс дату на четверг, просьба пользователя о пятнице теперь конфликтует с новым решением. Автоматический повтор той же записи скроет конфликт. Лучше запросить подтверждение или передать ситуацию оператору.
В журнале сохраните order_id, прочитанную ревизию, ревизию при конфликте, запрошенное изменение и итог. Так видно, с чем именно спорил агент, не помещая весь заказ в промпт и лог. Проверка на тестовом API проста: прочитать заказ версии 7, изменить его вручную до версии 8, затем попробовать запись с версией 7. Успехом теста является отказ и отсутствие перезаписи. После нового чтения можно выполнить осознанную операцию с версией 8.
Условная запись должна быть атомарной именно в том хранилище или API, где живёт заказ. Замок в адаптере агента не защитит от оператора CRM или другого сервиса, которые пишут в обход адаптера. Если авторитетное API не даёт ETag, ревизии или другой формы сравнения при записи, честно сообщайте о неустранимом конфликтном окне и передавайте изменение на ручную сверку либо меняйте контракт API. Обычный порядок «ещё раз прочитать, затем записать» не закрывает гонку: изменение может случиться между этими шагами. Также проверьте гонку с поздним результатом другого запуска агента, если несколько задач могут менять один заказ.
В платном курсе AI Agents PRO: LangGraph, AutoGen и LLMOps в продакшне вы подключаете внешние API и инструменты к агенту, добавляете идемпотентность, ограничения полномочий и трассировку. Эти части нужны вместе: инструмент передаёт версию, граф обрабатывает конфликт как отдельный исход, трасса показывает, почему агент не выполнил просьбу сразу. Откройте программу курса, чтобы собрать такой агентный сервис целиком.
Продолжить на практике
- AI Agents PRO: LangGraph, AutoGen и LLMOps в продакшне ↗
Практический курс по AI-агентам. Соберёте продакшн RAG-сервис: от индекса и графа состояний до API, Docker, метрик качества и контроля стоимости. Плюс профессиональные блоки: LangGraph/AutoGen, Qdrant/FAISS+rerank, eval (RAGAS/custom), quality-гейты, OpenTelemetry+Prometheus/Grafana, CI/CD, ретраи/DLQ/идемпотентность, PII/RBAC.
