Перейти к содержанию
Публикация AiManual

Мультитенантная AI-платформа с жёсткой изоляцией данных: как Octave Reliance построила её на Amazon Bedrock

Octave Reliance построила мультитенантную AI-платформу на Amazon Bedrock, где данные клиентов не пересекаются: отдельные векторные хранилища, сессии агентов в m

Коротко

Что будет в материале

  1. 01

    В чём задача: изоляция данных тенантов как архитектурное требование

  2. 02

    Три слоя архитектуры Octave: общая картина

  3. 03

    Слой данных: эмбеддинги Cohere Embed v4 и отдельное векторное хранилище

  4. 04

    Слой исполнения: изоляция агентов в Amazon Bedrock AgentCore

Octave Reliance построила мультитенантную AI-платформу на Amazon Bedrock. Каждый клиент в ней отдельный тенант, и данные не могут пересекать границу тенанта: векторный поиск, рантайм агентов и фильтры контента спроектированы так, чтобы у сценария одного клиента не было технической возможности дотянуться до корпуса другого. Первый продакшн-сценарий, Complaint Triage Assistant, ищет по 2 млрд регулируемых документов, не смешивая клиентов. Разбор кейса опубликован в блоге AWS; все цифры ниже приводятся по этому описанию, если не указано иное.

Контекст бизнеса объясняет жёсткость требований. Reliance, облачная система управления качеством Octave, поддерживает более 650 корпоративных клиентов и более 40 приложений: управление жалобами, отслеживание CAPA, аудиты, качество поставщиков. Сама платформа обслуживает более 14 000 клиентов в производстве медицинских изделий, фармацевтике и пищевой промышленности, работает в 180 странах и покрывает более 60% компаний из Global Fortune 500. В таких отраслях документы содержат данные о дефектах продукции, нежелательных реакциях и претензиях, а смешение корпусов двух клиентов означает регуляторный инцидент, а не баг в интерфейсе.

Второй вывод из кейса важнее технических деталей: команда не выпускала одну AI-функцию. Первый цикл ушёл на горизонтальный фундамент, на который затем ставятся вертикальные сценарии, и этот фундамент сократил время развёртывания одного сценария на 50%.

В чём задача: изоляция данных тенантов как архитектурное требование

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

Почему прикладной код - плохое место для изоляции

Подход «в каждом обработчике проверим tenant_id» работает, пока точек входа мало и все они идут через один слой доступа. В AI-сценарии эти точки размножаются: чат, фоновый конвейер индексации, вызов инструмента агентом, кэш ответов, логи трассировок. Пропущенная проверка в одном новом эндпоинте даёт доступ к чужому корпусу, а найти такой пропуск в аудите трудно, потому что проверки размазаны по коду и не видны как схема.

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

Ещё один аргумент практический. Инженерная команда меняется, сценариев становится больше, и требование «не забывай про tenant_id» живёт в документации и код-ревью, то есть в головах людей. Требование «у тенанта своё хранилище» живёт в конфигурации и проверяется автоматически.

Три слоя архитектуры Octave: общая картина

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

СлойЧто делаетКомпонентыЧто изолирует
ДанныеРежет документы на чанки, считает векторы, хранит их и ищет по нимCohere Embed v4, Amazon OpenSearch ServiceКорпус и индекс тенанта
ИсполнениеЗапускает агента и его инструменты, ведёт сессиюAmazon Bedrock AgentCore, microVMПамять, процесс и файловую систему сессии
Защита контентаПроверяет запрос на входе и ответ на выходеAmazon Bedrock GuardrailsДопустимость запроса и ответа

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

Слой данных: эмбеддинги Cohere Embed v4 и отдельное векторное хранилище

Ключевое решение слоя: у каждого тенанта своё векторное хранилище на Amazon OpenSearch Service, а не общий индекс с фильтром по полю tenant_id. Разница практическая. Общий индекс экономит память и упрощает эксплуатацию, но каждую выборку нужно сопровождать корректным фильтром, а ошибка в фильтре или в запросе от инструмента открывает чужие документы. Отдельное хранилище убирает эту категорию ошибок: неверный запрос просто не найдёт данных за своими границами.

Цена очевидна. Число индексов растёт вместе с числом тенантов, а вместе с ним растут расходы на хранение векторов, на реплики и на регламентные работы. Octave выбрала этот путь, потому что регулируемый домен не прощает даже теоретической возможности смешения. Для эмбеддингов используется Cohere Embed v4 в Amazon Bedrock, выбор модели подтверждён оценкой на собственном корпусе, а не публичными лидербордами (описание кейса).

Почему модель эмбеддингов оценивали на своём корпусе

Публичные бенчмарки строятся на общих текстах: вики, новости, веб-вопросы. Корпус Reliance состоит из жалоб, записей CAPA, отчётов об аудитах и описаний несоответствий, то есть из плотного регуляторного языка с устойчивыми формулировками и внутренними сокращениями. Модель, лидирующая в общем рейтинге, на таком корпусе может проиграть более скромному кандидату.

Рабочая процедура выглядит так. Собрать 200-500 реальных или обезличенных запросов с известными правильными документами. Прогнать через каждого кандидата, сравнить recall@k и MRR на уровне чанка. Отдельно проверить устойчивость к сокращениям и к смешанным языковым формулировкам, если корпус двуязычный. Конкретные значения метрик в опубликованном описании кейса не раскрыты, поэтому повторять чужие числа бессмысленно: ценна сама процедура и то, что решение принимается на своём наборе.

Снижение размерности с 1536 до 512: экономия около 66% хранилища

Векторы урезаны с 1536 до 512 измерений при сохранении точности поиска. Арифметика простая: 512 из 1536 это одна треть, значит на хранении векторов экономится порядка 66%. На корпусе в 2 млрд документов выигрыш огромный, и он умножается на число хранилищ, потому что у каждого тенанта свой индекс.

Ограничение тоже простое. Сжатие размерности теряет часть семантики, и на узком домене деградация вылезет именно там, где нужна точность: различить две близкие категории жалоб или отделить претензию к процессу от претензии к продукту. Перед сжатием повторите оценку на своём наборе с полной и урезанной размерностью и сравните метрики. Если разница в пределах шума, экономия оправдана. Если recall просел, экономия мнимая.

Чанкинг документов для RAG: около 4K токенов в 128K контекст

Документы режутся на чанки примерно по 4K токенов, а при генерации ответа несколько чанков упаковываются в контекст до 128K токенов. Логика двойная. Крупный чанк сохраняет структуру регуляторного документа: заголовок, раздел, вывод, ссылку на процедуру. Куски по 300-500 токенов эту структуру рвут, и модель отвечает фрагментами без причинно-следственной связи.

Вторая часть, упаковка нескольких чанков в один вызов, работает на пропускную способность: одно обращение к модели вместо пяти снижает и задержку, и накладные расходы на API. Компромисс в том, что крупные чанки размывают точность поиска: вектор усредняет содержание четырёх тысяч токенов, и узкий вопрос может попасть в чанк, где нужный абзац занимает 5% текста. Размер подбирается под тип документа и проверяется измерением recall на своём наборе. Копировать 4K вслепую не стоит: для короткой претензии и для многотомного аудиторского отчёта оптимум разный.

Слой исполнения: изоляция агентов в Amazon Bedrock AgentCore

Агенты исполняются в Amazon Bedrock AgentCore, каждая сессия идёт в отдельной microVM. Изоляция на уровне виртуальной машины означает, что сессии двух тенантов не делят ни память, ни процесс, ни файловую систему, ни переменные окружения. Агент, который читает локальные пути или пытается дотянуться до чужого состояния, физически остаётся внутри своей машины.

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

Возможности AgentCore меняются быстро, поэтому параметры сессий и региональные ограничения стоит сверять с документацией перед проектированием. Обзор обновлений платформы за август 2026, включая сессии, кросс-региональный инференс и контроль расходов: что изменилось в Amazon Bedrock и AgentCore.

Сквозная идентичность пользователя: зачем она агенту

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

Пример из домена Reliance: сотрудник клиента ищет по жалобам и записям CAPA, чтобы подготовить ответ регулятору. Область поиска ограничена его тенантом, и агент не может расширить её сам, потому что инструмент поиска привязан к его хранилищу, а сессия к его идентичности. Похожий принцип ограничения поиска рамками тенанта разбирали в кейсе Ninth Wave Compass на AgentCore: tenant-scoped grounding в мультиагентной системе. Полезно как второй пример того, как контроль доступа переносится в слой инструментов, а не остаётся в приложении.

Защита контента: Amazon Bedrock Guardrails на входе и выходе

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

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

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

Конвейер загрузки: SNS, SQS, Step Functions и Lambda на 2 млрд документов

Индексация собрана на четырёх сервисах AWS. SNS публикует событие о появлении или изменении документа. SQS буферизует поток и сглаживает пики: конвейер не падает, когда клиент загружает архив жалоб за несколько лет. Step Functions ведёт оркестрацию шагов: извлечение текста, чанкинг, расчёт эмбеддингов, запись в OpenSearch. Lambda выполняет сами шаги. Схема даёт повторные попытки на уровне отдельного шага и видимый статус обработки для каждого документа.

Масштаб в кейсе: конвейер обработал 2 млрд документов, а по данным Octave выходит до 1,4 млн документов в сутки на тенант. Это ориентир, а не гарантия. Пропускная способность зависит от среднего размера документа, от лимитов на параллельные вызовы модели и от того, сколько чанков даёт один документ. Аудиторский отчёт на 200 страниц превращается в десятки чанков и десятки вызовов эмбеддингов, короткая претензия в один абзац почти ничего не стоит.

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

Наблюдаемость и оценка качества: OpenTelemetry и AgentCore Evals

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

AgentCore Evals закрывает вторую половину задачи: офлайн-оценку на наборах задач до выката изменений. Логика та же, что при выборе эмбеддингов: фиксированный набор запросов с эталонными ответами, прогон новой версии промпта, модели или правил guardrails, сравнение метрик с предыдущей версией. Разница в том, что оценивается весь агентный сценарий, а не только качество поиска.

Отдельная проблема мультитенантной системы: агент отвечает 200 OK, а содержимое пустое или бессмысленное, и метрики доступности при этом зелёные. Как такие сбои ловят на уровне качества ответа и как ищут первопричину в логах и топологии, разбирали в материале про AgentCore Evaluations и AWS DevOps Agent: двухуровневый мониторинг продакшн-агентов.

Инженерные компромиссы и ограничения подхода

Решение Octave оправдано ценой, которую платит не каждый проект. Собрать компромиссы в одном месте полезнее, чем ещё раз пересказывать слои.

РешениеЧто даётЧем платите
Отдельное векторное хранилище на тенантаОшибка в запросе не достаёт чужие данныеБольше индексов, выше расходы на хранение и регламентные работы
Размерность 512 вместо 1536Около 66% экономии на хранении векторовНужна повторная проверка recall, риск просадки на узком домене
Чанки около 4K токенов и упаковка в 128K контекстМеньше вызовов модели, сохранённая структура документаВектор размывается, узкие вопросы хуже находит поиск
Сессия в отдельной microVMИзоляция памяти, процесса и файловой системыНакладные расходы на запуск, нужен контроль времени жизни сессий
Guardrails на входе и выходеОтсечение инъекций и недопустимого контентаДополнительная задержка и настройка правил под домен

Границы применимости. Для регулируемых отраслей с чувствительными данными и требованием доказуемой изоляции такой фундамент экономит месяцы на каждом следующем сценарии. Для небольшого SaaS с десятком тенантов и публичными данными отдельные хранилища и microVM на сессию будут избыточны: расходы и эксплуатационная сложность вырастут быстрее выгоды. Цены и SLA в кейсе не раскрыты, считать окупаемость придётся на своих объёмах.

Что осталось за рамками публичного описания: точные значения метрик при выборе модели эмбеддингов, перечень включённых политик Guardrails, распределение 1,4 млн документов в сутки по типам документов и тенантам. Эти цифры стоит запрашивать у вендора или измерять самостоятельно, подставлять вместо них оценки по аналогии не нужно.

Что забрать в свой проект: порядок шагов

Отправная точка в кейсе Octave: воркшопы с AWS дали четыре сценария, суммаризацию и триаж жалоб, мониторинг готовности к аудиту, генерацию нарративов инцидентов и прогнозную оценку рисков качества. Команда пошла в горизонтальную платформу, а первым вертикальным срезом сделала суммаризацию и триаж жалоб, чтобы проверить архитектуру на живом процессе. Время развёртывания нового сценария сократилось на 50% (кейс Octave).

Порядок шагов, который повторяет эту логику:

  1. Определите границу тенанта в терминах данных, а не интерфейса: что именно принадлежит клиенту и не может смешиваться.
  2. Выберите уровень изоляции по каждому слою: отдельное хранилище, отдельная сессия исполнения, отдельная цепочка идентичности.
  3. Оцените модель эмбеддингов на своём корпусе с фиксированным набором запросов и метрикой recall@k.
  4. Подберите размер чанка измерением, а не копированием чужого значения; проверьте упаковку нескольких чанков в один вызов.
  5. Настройте Guardrails на входе и выходе, заведите лог срабатываний с разбивкой по тенантам.
  6. Поднимите трассировки OpenTelemetry и офлайн-оценку сценариев до первого релиза, а не после инцидента.
  7. Постройте горизонтальную платформу раньше вертикальных фич: первый сценарий должен проверять архитектуру, а не закрывать отдельную хотелку отдела продаж.

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

Если платформа пока кажется избыточной и хочется собрать агента с нуля на своём стеке, начните с архитектуры, памяти и обработки ошибок, а не с выбора модели: разбор самописного AI-агента с метриками latency, cost и reliability даёт практический код и чек-лист, когда своя разработка выгоднее готового решения.

Подписаться на канал