Перейти к содержимому
6 мин чтения

Доступ к продакшен-трассам LLM для разных ролей

Доступ к продакшен-трассам LLM: матрица прав для разработчиков, поддержки и аудиторов, маскирование, раскрытие и аудит без потери диагностики.

Доступ к продакшен-трассам LLM для разных ролей

Продакшен-трасса LLM почти всегда содержит больше, чем нужно человеку, который ее открывает. В ней могут оказаться системные инструкции, текст пользователя, фрагменты RAG-контекста, вызовы инструментов, аргументы, ответы, идентификаторы клиентов и оценки качества. Если вы выдаете доступ к такой записи по принципу "может смотреть трассы", вы уже смешали несколько разных полномочий в одно.

Рабочая схема начинается не с выбора хранилища и не с галочек в IAM. Сначала надо разложить трассу на типы данных и решить, какая роль решает какую задачу. Разработчик должен быстро найти регрессию. Поддержка должна разобрать конкретное обращение клиента. Аудитор должен проверить, что правила действуют. Ни одна из этих задач сама по себе не требует постоянного доступа ко всему исходному диалогу.

Трасса не является одним объектом доступа

Трасса выглядит как одна запись в интерфейсе наблюдаемости, но для контроля доступа это набор объектов с разным риском. Пока команда хранит ее как монолитный JSON, она неизбежно выбирает между двумя плохими вариантами: дать широкое чтение или лишить людей данных для работы.

Разделите содержимое как минимум на четыре слоя.

  • Операционные метаданные: trace_id, время, сервис, среда, тенант, маршрут, версия приложения, модель, провайдер, задержка, коды ошибок, причины завершения, входные и выходные токены, стоимость или ее внутренний эквивалент.
  • Содержимое запроса: системные инструкции, сообщения пользователя, вложения, retrieved documents, аргументы инструментов, параметры, пришедшие из приложения.
  • Содержимое ответа: текст модели, структурированный ответ, аргументы вызова инструмента, результат инструмента, сообщения об отказе.
  • Производные артефакты: оценки качества, классы ошибок, результат проверок безопасности, сигналы PII, хеши, отпечатки шаблонов, краткие выдержки и агрегаты.

OpenTelemetry делает это различие видимым в своих GenAI semantic conventions. В документации отдельно помечены как потенциально чувствительные retrieved documents, системные инструкции, аргументы и результаты инструментов. Там же сказано, что атрибуты, которые могут содержать чувствительные данные, должны быть opt-in, а не собираться по умолчанию. Это хорошая инженерная граница: полезные метаданные пишутся всегда, а исходное содержимое включается намеренно и по политике.

Не путайте две операции. Сбор определяет, что попадает в хранилище. Видимость определяет, что конкретный человек получает при чтении. Если вы собираете полный текст каждой транзакции, а потом надеетесь скрыть его в UI, то секрет уже прошел через коллектор, очередь, индексы, резервные копии и, возможно, экспорт. Маска на экране не отменяет этот маршрут.

Матрица прав должна описывать действия и поля

Роль "viewer" бесполезна, если она не отвечает на два вопроса: какие поля человек видит и что он может с ними сделать. Матрица прав должна проверяться на операции поиска, открытия, экспорта, API-чтения, сохраненного запроса, уведомления и скачивания вложений. Часто команда защищает только страницу деталей, а выгрузка CSV или внутренний endpoint возвращает исходный payload.

Ниже приведена стартовая матрица. Она не заменяет классификацию данных, но хорошо показывает, почему общая роль чтения ломается в первый же месяц эксплуатации.

Слой данныхРазработчикПоддержкаАудитор
Метаданные и ошибкиПолный просмотр по своим сервисамПросмотр по обращению и тенантуПросмотр и выборки по области аудита
Промпты и RAG-контекстМаскированные фрагменты, полный текст только по исключениюМаскированные фрагменты только по тикетуОбычно не показывать
Ответы моделиМаскированные фрагменты, полный текст по исключениюМаскированный ответ по тикетуОбычно не показывать
Аргументы и результаты инструментовМетаданные и безопасная нормализованная формаСтатус выполнения без аргументовФакт вызова, политика, журнал доступа
Оценки и классы ошибокПолный просмотрПросмотр для выбранного обращенияПолный просмотр и агрегаты
ЭкспортТолько производные данныеЗапрет по умолчаниюЭкспорт доказательств без исходного текста

Это не значит, что разработчик никогда не увидит текст. Это значит, что текст не становится платой за обычную отладку. Разработчик сначала видит достаточно, чтобы сказать: ошибка появилась в версии 2026.07.3, затронула маршрут claims-summary, повторяется только на одном провайдере, случается после tool call и связана с конкретным шаблоном. Если этого мало, он открывает запрос на раскрытие одной трассы или короткого набора связанных трасс.

Поддержка работает иначе. Ей редко нужна статистическая выборка всех клиентов. Ей нужен один контекст, связанный с заявкой, и возможность ответить, что произошло. Поэтому ее основное ограничение не только по полям, но и по набору записей: конкретный тенант, период, тикет или внешний идентификатор обращения. Поиск вида "найди все сообщения со словом ..." для поддержки обычно создает лишний риск и почти не помогает работе.

Аудитор проверяет контроль, а не литературное качество ответа модели. Для него важнее неизменяемость событий, история изменений политики, доказательство применения маски, журнал временных раскрытий и связь трассы с версией приложения. Дайте аудитору возможность увидеть, что поле существовало, было классифицировано, скрыто по политике и не экспортировалось. Исходный текст нужен только в исключительных процедурах, если вообще нужен.

Метаданные дают большую часть диагностики

Большинство инцидентов с LLM удается сузить без полного промпта. Команды часто не делают этого только потому, что записывают текст удобно, а не потому, что текст необходим.

Для первого разбора должны быть доступны следующие признаки:

  • идентификаторы трассы, родительского span и корреляции с запросом приложения;
  • идентификатор тенанта в виде, разрешенном для данной роли;
  • модель, провайдер, маршрут, регион исполнения, версия шаблона и версия кода;
  • длительность всего запроса, time to first token, токены, причина остановки и статус tool call;
  • тип ошибки, код ответа, число повторов, факт fallback и причина переключения;
  • классы контента: найдено PII, есть вложение, есть результат поиска, есть вызов инструмента, оценка ниже порога.

OpenTelemetry рекомендует фиксировать только детали, которые действительно нужны для конкретной операции, а не записывать все доступные свойства. В документе прямо сказано, что лишние атрибуты увеличивают объем телеметрии и ее накладные расходы, а при сомнении лучше не добавлять атрибут, пока не появится подтвержденная потребность. Для LLM-трасс это еще и правило безопасности.

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

Например, вместо такого события:

{
  "message": "Retrying gpt request for client acme: prompt failed after tool returned passport 123456789"
}

записывайте событие, пригодное для поиска и безопасное для широкого круга инженеров:

{
  "trace_id": "01JQ4F9B6XZ3R4H8V0M2K7C1P9",
  "tenant_ref": "t_7a91",
  "service": "claims-api",
  "route": "POST /v1/claim-summary",
  "prompt_template_version": "claims-v18",
  "model": "provider/model-name",
  "attempt": 2,
  "fallback_used": true,
  "error_class": "tool_result_schema_error",
  "pii_detected": true,
  "input_tokens": 1834,
  "output_tokens": 0
}

Такой набор отвечает на вопросы, которые возникают в первые десять минут: где сбой, кого он затронул, изменилась ли версия, сработал ли fallback, есть ли риск чувствительных данных. Для содержательного разбора остается запрос по одному trace_id, а не поиск по всем диалогам.

Маска должна сохранять диагностический смысл

Маскирование, которое превращает каждый текст в [REDACTED], выглядит безопасно на демо и бесполезно в реальной смене. Инженер не сможет отличить пустой retrieval от неверной инструкции, а сотрудник поддержки не поймет, что клиент отправил файл вместо текста. Но маска, которая оставляет слишком много, превращается в декоративный контроль.

Сохраняйте форму, а не содержание. Вместо исходной фразы можно показать тип сообщения, длину, класс найденных сущностей, язык, хеш нормализованного фрагмента и короткий безопасный preview. Preview должен строиться после удаления распознанных PII и секретов, а не до нее.

Пример полезной проекции сообщения:

{
  "role": "user",
  "chars": 842,
  "language": "ru",
  "content_hash": "sha256:9ce1...aa84",
  "pii_types": ["person_name", "phone"],
  "secret_types": [],
  "preview": "Пользователь просит уточнить статус обращения [PERSON] по номеру [PHONE]",
  "attachment_count": 1
}

Хеш не делает текст безопасным сам по себе. Если пространство возможных значений маленькое, его можно перебрать. Не хешируйте отдельно номера договоров, ИИН, email и другие короткие идентификаторы в надежде, что этого достаточно. Хеш полезен для сравнения повторов и дедупликации длинных сообщений, когда доступ к исходнику уже закрыт. Для чувствительного идентификатора лучше хранить отдельный внутренний reference, который не имеет смысла вне защищенного контура.

Особенно осторожно относитесь к аргументам инструментов. Они часто содержат номер счета, адрес, результат поиска по клиенту или payload внутреннего API. OpenTelemetry отдельно предупреждает о чувствительности gen_ai.tool.call.arguments и gen_ai.tool.call.result. В обычной трассе показывайте имя инструмента, схему результата, статус, длительность и классификацию полей. Исходные аргументы храните отдельно и выдавайте только через исключение.

OWASP в разделе Sensitive Information Disclosure рассматривает PII, финансовые сведения, данные о здоровье, учетные данные и конфиденциальные документы как чувствительную информацию, которую LLM-приложение может раскрыть. Документ также предупреждает, что запрет в системном промпте не дает надежной защиты, потому что его могут обойти prompt injection и другие пути. Политика трасс не должна зависеть от послушания модели.

Полный текст храните отдельно от поискового индекса

Применяйте правила к содержимому
Метки контента и маскирование PII помогают закрепить правила для входящих LLM-данных.

Правило простое: если по тексту можно искать без специального разрешения, текст уже слишком широко доступен. Не индексируйте исходные промпты и ответы в том же поисковом контуре, где инженеры ищут ошибки, latency и расходы.

Нужны два представления одной трассы. Первое, оперативное, содержит метаданные и маскированные проекции. Оно доступно большинству технических ролей и оптимизировано для фильтрации. Второе, защищенное, содержит зашифрованные исходные сегменты, связанные с trace_id и конкретным полем. Оно не участвует в полнотекстовом поиске и не выдается пакетным экспортом.

Схема записи может выглядеть так:

trace_envelope
  trace_id
  tenant_ref
  timestamps
  operational_metadata
  safety_labels
  masked_message_views
  content_refs[]

content_vault
  content_ref
  trace_id
  field_path
  encrypted_payload
  retention_class
  access_policy_version
  content_hash

trace_envelope отвечает на повседневные вопросы. content_vault существует для доказуемо необходимых разборов. Не дублируйте encrypted_payload в очереди ошибок, dead letter queue, аналитическом lakehouse и snapshot базы. Когда команда строит четыре копии "на всякий случай", доступ к исходнику становится невозможно объяснить даже самой команде.

Политика должна применяться на чтении, а не только при записи. Причины две. Во-первых, у одной трассы может измениться классификация после более точного сканирования. Во-вторых, права человека и контекст его запроса меняются. Поддержка могла открыть запись по действующему тикету утром, а вечером тикет уже закрыт. Сервис чтения обязан оценить роль, тенант, цель, объект, время и одобрение непосредственно перед выдачей.

Подход с фильтрами строк и масками столбцов хорошо иллюстрирует нужное свойство: ограничения должны срабатывать до того, как пользователь увидит исходное значение. Документация Databricks описывает row filters как ограничение строк во время запроса, а column masks как подстановку маскированного значения при чтении. Она также отмечает, что при конфликте между оптимизацией и защитой от раскрытия движок выбирает защиту. Для трасс LLM это правильный порядок приоритетов.

Разработчику нужен путь раскрытия, а не постоянная привилегия

Запретить полный текст навсегда легко. Потом приходит дефект, который воспроизводится только на одном редком входе, и кто-то дает группе администраторские права "до конца расследования". Так появляется постоянная дыра, потому что временные права никто не снимает.

Сделайте процедуру раскрытия обычной инженерной операцией. Она должна быть быстрой для реального инцидента и неприятной для любопытства.

  1. Инженер указывает trace_id или ограниченный набор связанных трасс, причину, тикет и ожидаемую длительность доступа.
  2. Система проверяет, может ли он получить ответ без исходного текста. Если да, заявка возвращается с маскированным представлением и нужными метаданными.
  3. Для полного содержимого требуется одобрение владельца сервиса, дежурного по безопасности или другого назначенного лица. Не назначайте одобрение самому запрашивающему.
  4. Доступ действует недолго, не дает массовый поиск и не открывает экспорт. После истечения срока сервис чтения снова возвращает маскированную проекцию.
  5. Каждое чтение создает отдельное событие аудита, даже если одно разрешение покрывает несколько просмотров.

Разделяйте "право запросить раскрытие" и "право прочитать исходник". Первое может быть у любого инженера, отвечающего за сервис. Второе появляется только после оценки контекста. Это сохраняет скорость работы и не превращает всех разработчиков в привилегированных операторов хранилища.

Не выдавайте доступ на основе названия команды без области данных. Разработчик платежного сервиса не должен открывать содержимое трасс медицинского чат-бота только потому, что оба входят в Engineering. В policy input должны входить минимум роль, сервис, тенант, классификация данных, цель доступа и статус одобрения.

Поддержка должна видеть историю обращения, а не весь тенант

Храните данные в стране
Платформа поддерживает хранение данных внутри Казахстана для LLM-нагрузок.

Поддержка сталкивается с другим видом давления. Клиент пишет: "Вчера ассистент раскрыл не тот документ, проверьте". Сотруднику нужно понять последовательность, но широкий поиск по клиентским сообщениям создаст новый канал утечки.

Связывайте доступ поддержки с идентификатором обращения. Система может найти трассу по заявке, внешнему request ID, времени, пользователю в защищенном CRM reference или идентификатору сессии, если политика это допускает. После этого она выдает ограниченную временную линию: маскированные сообщения, статусы вызовов, номера версий, оценки, факт использования документа и итоговый ответ в безопасной проекции.

Полезная карточка для поддержки отвечает на конкретные вопросы:

  • модель вернула ответ или произошел технический сбой;
  • сработала ли политика безопасности и почему;
  • использовался ли RAG, сколько документов вернулось и есть ли признак пустого контекста;
  • вызывался ли инструмент и завершился ли он ошибкой;
  • менялась ли модель, шаблон или маршрут между успешным и неуспешным обращением.

Не добавляйте туда кнопку "показать все сообщения клиента". Если содержимое необходимо для ответа на жалобу, поддержка подает запрос на раскрытие с номером обращения. В некоторых организациях этот запрос должен одобрять владелец данных, а не руководитель поддержки. Это зависит от категории данных, но принцип одинаков: сотрудник не должен сам решать, что его любопытство равно служебной необходимости.

Ограничение по тенанту должно работать раньше поиска. Если сначала сервис ищет по всей базе, а потом скрывает чужие строки в интерфейсе, вы оставляете риски в подсказках поиска, статистике количества результатов, кешах и ошибках API. Идентификатор тенанта должен быть частью predicate на уровне запроса к хранилищу.

Аудит доказывает контроль без чтения разговоров

Сведите провайдеров к одному API
Один OpenAI-совместимый endpoint направляет запросы к моделям разных провайдеров.

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

Аудитору нужен набор доказательств, связанный во времени:

  • версия матрицы прав и дата ее изменения;
  • список ролей, групп и областей ответственности;
  • события выдачи, отказа, продления и отзыва временного доступа;
  • события чтения protected content с субъектом, объектом, причиной и решением политики;
  • хеши или подписанные манифесты для проверки неизменности трассы;
  • результаты регулярных тестов, которые подтверждают маскирование и tenant scoping.

Неизменяемость не означает, что вы никогда ничего не удаляете. Содержимое может иметь короткий срок хранения по политике данных. После удаления оставьте минимальную запись о самом факте: trace_id, время, категория данных, версия retention policy, идентификатор операции удаления и криптографический отпечаток, если его хранение допустимо. Тогда аудитор видит, что запись существовала и была удалена по правилу, но не получает сам текст.

В NIST SP 800-53 семейство AC-6 требует явно авторизовать доступ к security functions и связанной security-relevant information по принципу наименьших привилегий. Для продакшен-трасс это означает, что доступ к обычной панели наблюдаемости не должен автоматически включать чтение исходных сообщений.

Проверяйте не только политику, но и обходные пути. Создайте синтетическую трассу, где есть имя, телефоноподобная строка, секретоподобный токен, аргумент инструмента и ответ с ошибкой. Затем выполните одинаковые запросы от разработчика, поддержки и аудитора через UI, API, экспорт, сохраненный поиск и механизм уведомлений. Сверяйте фактический payload с ожидаемой матрицей. Если один endpoint возвращает исходник, у вас нет контроля доступа, даже если главная страница выглядит аккуратно.

Ретенция и оценка качества требуют отдельной политики

Команда часто сохраняет промпты "для evals", хотя ей нужны не сами промпты, а воспроизводимый способ понять, почему оценка упала. Это разные задачи.

Для регулярной оценки качества полезно хранить производные данные: идентификатор набора, версию промпта, версию модели, сценарий, rubric, оценки, причины провала, хеш входа, маскированную проекцию и ссылку на защищенный контент. Этого достаточно, чтобы построить тренд, сравнить маршруты и найти регрессию. Исходник открывают только эксперты, которые размечают спорный случай или расследуют конкретное расхождение.

Не используйте один retention period для всего. Метаданные о задержке и ошибках могут понадобиться дольше, чем сырой текст диалога. Оценки могут пережить исходное содержимое, если они не позволяют восстановить его. Вложения и результаты инструментов часто требуют еще более короткого срока, потому что несут данные из внешних систем.

Для команд, которым нужны локальное хранение, аудит-логи, маскирование PII и ограничения на уровне ключа, AI Router может быть одним из контуров, где эту модель прав стоит закрепить вместе с маршрутизацией LLM-запросов. Но сама матрица должна жить в архитектуре приложения и проверяться независимо от выбранного шлюза.

Начните с одной реальной трассы, которая сегодня видна слишком многим. Разберите ее на метаданные, исходное содержимое и производные артефакты. Затем попросите разработчика, сотрудника поддержки и аудитора сформулировать по три вопроса, на которые им нужно ответить. Все, что не помогает ответить на эти вопросы, не должно быть в их постоянном доступе.

Часто задаваемые вопросы

Нужен ли разработчику полный доступ к промптам для отладки LLM?

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

Как дать поддержке доступ к трассам клиентов без утечки данных?

Поддержке обычно нужен контекст конкретного обращения и состояние запроса, но не вся история клиента и не все диалоги арендатора. Дайте ей поиск по тикету или идентификатору запроса, ограничение по тенанту, маскированный текст и временный режим раскрытия по одобрению.

Должны ли аудиторы видеть исходные промпты и ответы?

Аудитору нужны доказательства соблюдения контроля: кто получил доступ, к какой записи, по какой причине, что увидел и кто одобрил исключение. Для этого чаще хватает неизменяемого журнала, хешей содержимого, версий политик и агрегированных выборок без исходных промптов.

Чем маскирование отличается от минимизации данных в трассах?

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

Когда можно временно раскрыть полный текст LLM-трассы?

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

Нужно ли ограничивать доступ к трассам по тенанту?

Да, если события содержат идентификатор тенанта, пользователя, сессии или связанный с ними контент. Фильтр тенанта нужно применять до поиска, агрегаций, экспорта и просмотра, а не только скрывать поле в интерфейсе.

Какие метаданные LLM-трассы можно показывать всем инженерам?

Статус HTTP, тип ошибки, модель, маршрут, время, задержка, число входных и выходных токенов, причина остановки, версия шаблона и идентификатор трассы почти всегда нужны. Не включайте в этот слой произвольные заголовки, URL с параметрами, имена файлов и текст аргументов инструментов.

Что должно быть в журнале доступа к продакшен-трассам?

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

Можно ли защитить трассы только системным промптом?

Это не безопасная политика. OWASP прямо указывает, что ограничения в системном промпте могут обходиться через prompt injection, а чувствительные данные могут попасть и во вход, и в выход. Контроль доступа должен работать в хранилище и на выдаче трассы, независимо от инструкции модели.

Как проверить, что новая роль не обходит ограничения на трассы?

Проверьте, что новая роль не получает исходный текст через поиск, экспорт, API, кеш, уведомления, сохраненные запросы и дочерние сервисы. Затем создайте синтетическую трассу с PII и секретоподобной строкой, выполните запросы от каждой роли и сравните фактический ответ с матрицей прав.