Права изменились, пока AI-агент ждал: где повторно проверять доступ
AI-агент готовит заметки к релизу. Пользователь просит собрать изменения из задач, дождаться результатов тестов и опубликовать текст в проекте. Ожидание занимает несколько минут, поэтому приложение сохраняет промежуточный результат: черновик и шаг, на котором остановилась работа. Такую сохранённую точку будем называть checkpoint.
В момент запуска пользователь имеет право публиковать материалы. Пока агент ждёт тесты, его выводят из проекта. Черновик от этого не исчезает, но последняя операция уже не должна выполняться. Если агент сохранил в checkpoint старое решение can_publish=True и использует его после возобновления, сохранение состояния незаметно превращается в сохранение разрешения.
Здесь полезно разделить два вопроса. Checkpoint отвечает, с какого места продолжать вычисление. Система авторизации отвечает, можно ли выполнить действие сейчас. У этих ответов разный срок жизни.
Как появляется устаревшее разрешение
Можно проверить доступ при запуске и сохранить результат вместе с черновиком. Тогда после ожидания агент просто прочитает флаг can_publish_at_start. Проблема в том, что этот флаг хранит ответ на старый вопрос: разрешали ли пользователю публикацию в момент запуска? За несколько минут права могли измениться.
Если обработчик продолжения доверяет старому флагу, он опубликует текст даже после отзыва доступа. Проверка была, но произошла слишком рано.
Что сохранять в checkpoint
В checkpoint сохраним пользователя, проект, черновик и текущий шаг. А перед публикацией снова проверим, может ли этот пользователь записывать данные в этот проект. Ниже сравним два варианта: один доверяет сохранённому флагу, другой проверяет доступ повторно.
Проверять доступ нужно непосредственно перед записью. Если после проверки снова ждать несколько минут, возникнет та же проблема. Для записи в базу проверку и изменение можно объединить в транзакцию. При обращении к внешнему сервису полезно, чтобы он сам проверял актуальные права в момент выполнения действия.
Полный пример со сменой роли
permissions = {("user-17", "project-42", "publish"): True}
published = []
def allowed(user_id: str, project_id: str, action: str) -> bool:
return permissions.get((user_id, project_id, action), False)
def start_job():
return {
"user_id": "user-17",
"project_id": "project-42",
"draft": "Release 2.4 is ready",
"can_publish_at_start": allowed("user-17", "project-42", "publish"),
}
def resume_bad(checkpoint):
if checkpoint["can_publish_at_start"]:
published.append(checkpoint["draft"])
return "published"
return "denied"
def resume_fixed(checkpoint):
if not allowed(checkpoint["user_id"], checkpoint["project_id"], "publish"):
return "denied: permission changed"
published.append(checkpoint["draft"])
return "published"
checkpoint = start_job()
permissions[("user-17", "project-42", "publish")] = False
print("Saved authorization flag:", checkpoint["can_publish_at_start"])
print("Naive resume:", resume_bad(checkpoint), "published=", len(published))
published.clear()
print("Fixed resume:", resume_fixed(checkpoint), "published=", len(published))
Результат запуска:
Saved authorization flag: True
Naive resume: published published= 1
Fixed resume: denied: permission changed published= 0
В первом случае запись появляется: обработчик поверил старому разрешению. Во втором он получает отказ и останавливается до публикации. Подготовленный черновик при этом можно сохранить; показывать его следует только тому, у кого осталось право чтения.
Где нужны повторные проверки
Повторная проверка нужна перед записью, отправкой или удалением данных. Она нужна и перед выдачей сохранённого ответа: за время ожидания пользователь мог потерять право читать документ. Если операция изменяет сразу несколько записей, заранее решите, что делать при отзыве доступа посередине: отменять всю операцию или сохранять уже выполненную часть.
Бывает, что агент обращается к внешнему сервису через общий ключ приложения. У ключа есть доступ ко всем проектам, а у конкретного пользователя — только к одному. Поэтому приложение должно проверять права самого пользователя. Проверка общего ключа не обнаружит, что человека уже исключили из проекта.
Не повторяйте отказ в доступе так же, как сетевую ошибку. Новый запрос с теми же правами не вернёт разрешение. Сохраните подготовленную работу и сообщите пользователю, какое действие остановлено.
Как проверить сценарий
В тесте остановите задачу прямо перед публикацией, отзовите у пользователя доступ и продолжите ту же задачу. Проверьте, что запись не появилась, а в журнале осталось объяснение отказа: кто пытался публиковать и в какой проект. Затем повторите проверку для удаления документа и выхода пользователя из команды.
Сохранённая точка помогает продолжить работу с нужного шага. Разрешение на публикацию она с собой не переносит. Это различие важно сохранить и в коде, и в тестах.
Собрать долгоживущий агентный процесс
В AI Agents PRO: LangGraph, AutoGen и LLMOps в продакшне вы соберёте агента, который выполняет задачу в несколько шагов и обращается к внешним сервисам. В программе есть контроль полномочий, повторные запросы и защита от повторного выполнения одного действия. Затем вы запустите сервис через FastAPI и Docker и добавите проверки его работы.
Посмотреть программу AI Agents PRO. Открытый урок про цикл, tools и память AI-агента поможет собрать базовый контур перед более сложным графом.
Следующий шаг: AI-агенты в приложениях: состояние, инструменты и сбои. По смежным вопросам: Как остановить AI-агента, если пользователь отменил задачу, Лимит шагов AI-агента: как отличить полезный поиск от бесконечного цикла.
Источник: официальная документация LangGraph по persistence.
