В руководстве для разработчиков содержится предупреждение о том, что удержание транзакции базы данных открытой на протяжении всего времени ИИ-чата может привести к искажению ответов и перегрузке лежащей в основе СУБД. В заметке, предназначенной для команд, создающих инструменты на базе LLM, говорится, что такую практику «не следует использовать», и предлагаются четыре альтернативных краткосрочных паттерна обеспечения согласованности.
Почему это предупреждение важно
Ассистенты на базе LLM часто задают серию уточняющих вопросов: они считывают запись, запрашивают деталь, а затем просят итоговое значение. Если исходные данные изменятся между этими шагами, ассистент может вернуть противоречивые цифры — один из ответов будет неверным. Соблазнительное решение — открыть одну транзакцию в начале разговора и держать её открытой до завершения чата. На практике такой подход удерживает версии строк, заполняет tempdb, удерживает блокировки и мешает пулингу соединений.
Что приводит к длительным транзакциям
- Многошаговый промптинг — LLM обычно генерируют несколько промптов, прежде чем пользователь увидит ответ.
- Вызовы инструментов, обращающиеся к базе данных — каждый ход может вызывать хранимую процедуру,
SELECTилиUPDATE. - Неконтролируемая область видимости транзакции — разработчики иногда оборачивают весь чат в блок
BEGIN…COMMIT, полагая, что это гарантирует согласованность.
Когда чат затягивается, движок БД должен сохранять исходные версии строк, чтобы транзакция видела стабильное представление. Эти версии занимают место в tempdb, потребляя пространство и ресурсы ввода-вывода. Блокировки, удерживаемые в течение того же периода, препятствуют параллельной записи, а простаивающее соединение может исчерпать пул, заставляя новых вызывающих ждать свободного слота.
Четыре краткосрочных паттерна
Руководство рекомендует рассматривать согласованность как задачу отдельного вызова инструмента, а не всего разговора. Предлагаются четыре паттерна:
- Операторы в реальном времени (Live statements) — каждый вызов выполняется с уровнем изоляции по умолчанию, видя только те данные, которые были зафиксированы (committed) на момент выполнения. Это самая простая модель; вызывающая сторона принимает тот факт, что данные могли измениться со времени предыдущего шага.
- Ограниченные транзакции (Bounded transactions) — разработчик группирует несколько операторов внутри одной короткой транзакции, которая завершается до следующего шага LLM. Это гарантирует атомарность для данной группы без затягивания процесса за пределы вызова инструмента.
- Чтение снимков (Snapshot reads) — операция начинается с определенной метки времени снимка (snapshot timestamp), что обеспечивает стабильное представление базы данных на время вызова. Все операции чтения внутри вызова видят одни и те же данные, даже если происходят параллельные записи.
- Материализованные отчеты (Materialized reports) — инструмент считывает данные из предварительно сгенерированного, версионного набора результатов, который отражает состояние базы данных в определенный момент времени. Пагинация или дальнейшие вычисления затем выполняются на этом «замороженном» наборе данных.
В SQL Server проверьте, активен ли параметр READ_COMMITTED_SNAPSHOT. Не полагайтесь на то, что название говорит само за себя.
Практические правила для приложений на базе LLM
- Группируйте необходимое — если вопрос требует получения множества значений, вычислите их за один вызов инструмента, а не отправляйте отдельные запросы, каждый из которых открывает новую транзакцию.
- Детерминированная пагинация — при представлении результатов на разных страницах используйте стабильный ключ сортировки, курсор или материализованный набор результатов. Никогда не держите транзакцию открытой, пока пользователь прокручивает страницу.
- Возвращайте подтверждающие данные — вместе с данными включайте метаданные, которые явно описывают модель согласованности: класс согласованности, время начала снимка, точку отсечения отчета, актуальность данных, количество строк, идентификатор базы данных и
trace ID. - Стресс-тестируйте на конкурентность — имитируйте параллельную запись во время генерации промптов LLM и проверяйте, что приложение корректно выполняет повторные попытки или переходит к резервным сценариям.
Вывод очевиден: ИИ-чат не должен диктовать время жизни транзакции базы данных. Ограничивая область согласованности каждым вызовом инструмента, разработчики поддерживают работоспособность базы данных, сохраняют производительность для всех пользователей и при этом предоставляют LLM достаточно надежных данных для точных ответов.
