Многотенантная RAG за шлюзом API, совместимым с OpenAI
Практическая эталонная архитектура для создания генерации с расширенным поиском на основе многомодельного шлюза API: индексы на уровне клиента, адаптеры извлечения, независимые от поставщика, нормализованные цитаты, элементы управления жизненным циклом и атрибуция затрат.
Помощникам искусственного интеллекта, работающим с клиентами, необходима генерация с расширенным поиском, но RAG становится сложнее, когда запросы проходят через шлюз API, совместимый с OpenAI, а не через собственный стек одного поставщика моделей. Шлюз должен изолировать данные арендаторов, сохранять ссылки между поставщиками моделей, удалять индексированный контент по расписанию, а также переносить затраты на внедрение, извлечение и генерацию на нужного клиента.
Практический ответ — рассматривать извлечение данных как первоклассную подсистему шлюза. Не прячьте это внутри интеграции с одним провайдером. Разделите извлечение информации и генерацию, дайте каждому запросу контекст извлечения на уровне клиента, нормализуйте цитаты перед их возвратом и записывайте каждый оплачиваемый шаг в бухгалтерскую книгу.
Проблема читателя
Команда, создающая ИИ-помощника для многих клиентов, обычно начинается с простого процесса: загрузка документов, встраивание фрагментов, получение наиболее частых совпадений, вставка этих фрагментов в подсказку и попросите модель ответить. Это работает до тех пор, пока продукту не потребуется несколько поставщиков моделей, выставление счетов на уровне клиента, автономность и возможность аудита.
Риск заключается не только в неточных ответах. К более серьезным операционным рискам относятся ошибки в пространстве имен арендаторов, непроверяемые ссылки, устаревшие индексы после удаления документов и прибыль, которую невозможно объяснить, поскольку затраты на поиск исчезают в общих расходах на инфраструктуру.
В этой статье разделены факты, рекомендации и прогнозы. Факты — это возможности реализации, документированные текущими API-интерфейсами поставщиков и векторных баз данных. Рекомендации представляют собой выбор архитектуры для шлюзового продукта. По прогнозам, эта архитектура, вероятно, потребует гибкости, поскольку функции поиска поставщика постоянно меняются.
Эталонная архитектура
Проект RAG на уровне шлюза должен состоять из пяти компонентов:
- Сопоставитель арендатора: сопоставляет входящий ключ API, рабочую область, учетную запись клиента или клиента Partner API с каноническим tenant_id.
- Профиль извлечения: определяет, какой корпус для поиска, какую модель внедрения использовать, количество результатов, фильтры, параметры изменения рейтинга, требования к цитированию и резервное поведение.
- Уровень адаптера извлечения: вызывает функцию поиска собственного поставщика, внешнюю базу данных векторов или настраиваемую службу поиска через один внутренний интерфейс.
- Адаптер быстрой сборки и генерации: передает полученный контекст выбранному поставщику модели, не раскрывая детали серверной части вектора вызывающие абоненты.
- Журнал использования и аудита: записывает внедрение, индексирование, извлечение, токены подсказки, токены завершения, идентификаторы арендатора, модели, поставщика и трассировки.
Контракт минимального запроса может оставаться нейтральным для поставщика:
{
"tenant_id": "tenant_123",
"model": "gpt-совместимая-или-совместимая-claude-модель",
"retrival_profile": "support_docs_v2",
«citation_required»: правда,
"сообщения": [
{"role": "user", "content": "Какова наша политика возврата средств за годовые планы?"}
]
Ответ также должен быть независимым от поставщика:
{
"ответ": "Годовые планы могут быть возвращены в пределах настроенного окна политики...",
"цитаты": [
{
"source_id": "doc_789",
"title": "Политика выставления счетов",
"url_or_internal_ref": "kb://billing-policy",
"chunk_id": "chunk_044",
"смещения": {"страница": 3},
«оценка»: 0,82,
"retrival_provider": "vector_db",
"model_provider": "openai_совместимый",
"provider_payload": {}
}
],
"retrival_trace_id": "rt_456",
"billable_tenant": "tenant_123",
«embedding_usage»: ноль,
"retrival_usage": {"запросы": 1, "результаты": 6},
"model_usage": {"input_tokens": 1920, "output_tokens": 180}Факт: функции поиска у поставщиков не идентичны
API векторных хранилищ OpenAI поддерживает векторные хранилища, которые можно создавать, искать, настраивать с помощью стратегий фрагментирования, связывать с метаданными файлов и удалять. Поиск по хранилищу векторов поддерживает запросы, фильтры, максимальное количество результатов, параметры ранжирования, пороговые значения оценок и элементы управления переписыванием запросов. Эти элементы управления дают авторам шлюзов полезные регуляторы задержки, релевантности и стоимости.
Элементы управления данными платформы OpenAI также делают важным проектирование жизненного цикла: контент клиентов в векторных магазинах сохраняется до тех пор, пока не будет удален. Если арендатор отключается или срок действия временного проекта истекает, шлюз не может рассчитывать на то, что поставщик автоматически удалит проиндексированный контент в соответствии с бизнес-графиком продукта.
Anthropic предлагает другую схему цитирования. Приложения могут предоставлять блоки контента результатов поиска с метаданными источника и заголовка, а когда цитирование включено, модель может присоединять ссылки на цитирование к сгенерированному тексту. Существуют практические ограничения: настройки цитирования результатов поиска в запросе выполняются по принципу «все или ничего», блоки результатов поиска поддерживают текстовый контент, а степень детализации цитирования зависит от того, как контент разделен на блоки.
Следствие прямое: шлюз не должен раскрывать форму извлечения одного поставщика в качестве своего публичного контракта, если только он не намерен сделать этого поставщика постоянным центром получения.
Рекомендация: использовать адаптеры поиска, а не Блокировка извлечения
Создайте внутренний интерфейс адаптера извлечения. Шлюз может поддерживать несколько серверных частей:
- Извлечение данных от собственного поставщика полезно, когда клиенту нужен самый быстрый путь к функциям поиска файлов или векторного хранилища одного поставщика.
- Внешняя база данных векторов: полезно, когда продукт должен поддерживать множество поставщиков моделей с последовательной изоляцией клиентов и контролем жизненного цикла.
- Предварительно выбранные блоки результатов поиска: полезно, когда шлюз собирает полученный текст и передает его. поставщику, который поддерживает явный контекст с учетом цитирования.
Адаптер должен возвращать одну и ту же внутреннюю структуру независимо от серверной части:
interface RetrievalResult {
получениеTraceId: строка;
идентификатор арендатора: строка;
идентификатор корпуса: строка;
куски: Массив<{
sourceId: строка;
заголовок: строка;
текст: строка;
urlOrInternalRef?: строка;
chunkId: строка;
смещения?: { страница?: номер; byteStart?: число; byteEnd?: число; tokenStart?: число; tokenEnd?: число };
оценка?: число;
метаданные: Запись<строка, строка | номер | логическое значение>;
поставщикПолезная нагрузка?: неизвестно;
}>;
получениеUsage: {
поставщик: строка;
запросКаунт: число;
РезультатКаунт: число;
billableUnits?: число;
};Это позволяет уровню генерации получать контекст, не зная, поступил ли он из векторных хранилищ OpenAI, Pinecone, Weaviate, индекса полнотекстового поиска базы данных или внутреннего гибридного средства извлечения.
Изоляция арендатора начинается до векторного запроса
Изоляция арендатора не должна зависеть от подсказок. Его необходимо применять перед извлечением, на границе хранилища и границе запроса.
Для систем типа Pinecone документированный шаблон мультиарендности представляет собой одно пространство имен на каждого арендатора в бессерверных индексах. Операции на уровне данных нацелены на пространство имен, что упрощает изоляцию и отключение арендатора, поскольку при удалении пространства имен удаляются записи этого арендатора. Pinecone также документирует компромиссы между пространствами имен и фильтрацией метаданных: фильтрация внутри большого общего пространства имен может сканировать больше данных, стоить дороже и выполнять медленнее, чем запросы в области пространства имен.
В системах типа Weaviate мультитенантность хранит каждого арендатора в отдельном сегменте, поэтому данные одного арендатора не видны другому арендатору. Удаление клиента приводит к удалению связанного сегмента. Weaviate также поддерживает такие состояния арендатора, как активный, неактивный и выгруженный, что создает вариант жизненного цикла для редко используемых арендаторов.
Контрольный список реализации
- Определите tenant_id из удостоверения аутентифицированного шлюза, а не только из поля тела, предоставленного пользователем.
- Сопоставьте tenant_id с векторным пространством имен, сегментом или идентификатором векторного хранилища поставщика через серверную часть реестра.
- Отклонять запросы, если арендатор ключа API и запрошенный арендатор корпуса не совпадают.
- Держите общие общедоступные корпорации отдельно от частных арендаторов.
- Используйте фильтрацию метаданных по типу документа, языку, области продукта или диапазону дат после того, как граница арендатора уже выбрана.
- Зарегистрируйте пространство имен, сегмент, corpus_id, retrival_profile и retrival_trace_id для возможность аудита.
Зарезервируйте поиск между арендаторами для явных административных рабочих процессов с отдельной авторизацией, отдельными индексами или контролируемыми путями агрегирования. Не делайте межклиентский поиск случайным побочным эффектом фильтров метаданных.
Нормализация ссылок как объектов шлюза
Цитаты — это контракт продукта, а не просто украшение. Помощнику службы поддержки клиентов, инструменту для составления юридических документов или внутреннему помощнику по вопросам знаний необходимо показать, почему был получен ответ и откуда взялся подтверждающий текст.
Шлюз должен нормализовать данные цитирования в свою собственную схему:
{
"source_id": "doc_123",
"title": "Условия возврата",
"url_or_internal_ref": "kb://refund-terms",
"chunk_id": "chunk_006",
"offsets": {"page": 2, "byte_start": 4410, "byte_end": 5020},
«оценка»: 0,79,
"retrival_provider": "переплетать",
"model_provider": "антропный",
"model_provider_citation_payload": {}
Сохраняйте стабильность нормализованных полей и разрешайте расширения, зависящие от поставщика. Некоторые поставщики предоставляют более подробную информацию о цитировании, чем другие. Некоторые будут ссылаться на блоки результатов поиска. Некоторые будут цитировать загруженные файлы. Некоторые из них не предоставляют точный формат смещения, который нужен вашему приложению. Шлюз должен сохранять то, что существует, не делая вид, что все поставщики имеют идентичную семантику цитирования.
Режим строгого цитирования
Когда citation_required имеет значение true, заранее определите поведение при сбое. Строгий режим может требовать, чтобы каждый фактический абзац включал хотя бы одну цитату или чтобы окончательный ответ содержал цитаты из извлеченных фрагментов, превышающих минимальный порог оценки. Если выбранный поставщик модели не может выполнить условия контракта на цитирование, шлюз должен быстро выйти из строя, использовать совместимого поставщика или вернуть структурированный отказ.
Это рекомендация, а не универсальное правило. Режим строгого цитирования повышает доверие, но может увеличить число отказов, повторных попыток и сложность отката. Для творческих рабочих процессов с низким уровнем риска цитирование может быть необязательным. Для поддержки клиентов или регулируемых внутренних рабочих процессов citation_required часто должен быть частью профиля поиска.
Жизненный цикл индекса — это функция продукта
Системы RAG накапливают данные. Временные загрузки случайно становятся постоянными. Бывшие клиенты оставляют после себя вложения. Продуктовые команды меняют стратегии разбиения на блоки и забывают перестроить старые индексы.Шлюз должен явно указывать элементы управления жизненным циклом.
Рекомендуемые элементы управления жизненным циклом включают:
- Временное истечение срока действия корпуса: документы, загруженные для кратковременного сеанса, должны иметь отметку времени истечения срока действия и задание на удаление.
- Отключение клиента: удаление клиента должно ставить в очередь удаление пространств имен, сегментов, хранилищ векторов поставщиков и связанные файловые объекты.
- Обработка холодного клиента: там, где это поддерживается, неактивные клиенты могут быть помечены как неактивные или выгружены для уменьшения использования ресурсов.
- Контроль версий переиндексации: сохраняет модель внедрения, политику фрагментирования, версию анализатора и indexed_at для каждого фрагмента.
- Отображение статуса удаления: Рабочие процессы Partner API должны показывать, удаляются ли документы, векторные файлы и удаление на стороне провайдера завершено.
Важным фактом является то, что некоторый контент векторного хранилища сохраняется до тех пор, пока не будет удален. Архитектура рекомендует сделать удаление видимым и тестируемым, а не хоронить его в асинхронном задании без взаимодействия с клиентом.
Отслеживать три реестра затрат
Одного реестра токенов недостаточно для RAG. Шлюзу требуется как минимум три реестра:
- Стоимость внедрения и индексации: синтаксический анализ документов, разбивка на фрагменты, вызовы внедрения, хранение файлов, запись в индекс и переиндексация.
- Стоимость извлечения: чтение базы данных векторов, поиск в собственном векторном хранилище, переранжирование, перезапись запросов и расширение результатов.
- Стоимость генерации: ввод токенов из сообщений пользователя и полученный контекст, выходные токены, вызовы инструментов, повторные попытки и резервные варианты.
Это особенно важно для агентств, поставщиков SaaS и внутренних команд платформы, которые перепродают или распределяют затраты на ИИ. Без отдельных реестров маржу RAG становится трудно объяснить. Арендатор с небольшим использованием генерации по-прежнему может быть дорогим, если он постоянно загружает документы, переиндексирует большие корпорации или выполняет широкие поисковые запросы.
Каждое событие реестра должно включать tenant_id, customer_id, если он отличается, идентификатор ключа API, retrival_profile, corpus_id, модель, поставщика, трассировку_id и оплачиваемые единицы. Это позволяет аналитике использования отвечать на практические вопросы: у каких арендаторов дорогие профили извлечения, какие корпуса устарели, какие модели приводят к сбоям цитирования и какие клиенты создают слишком большие запросы, поскольку извлечение возвращает слишком много контекста.
Режимы сбоя для тестирования
Подсистема RAG шлюза должна иметь тесты для режимов сбоя, которые создают видимый для клиента ущерб:
- Отсутствует citations: citation_required имеет значение true, но ответ поставщика не содержит полезных ссылок на цитаты.
- Устаревшие индексы: документ был обновлен или удален, но старые фрагменты все еще появляются в результатах поиска.
- Несоответствие арендатора: запрос разрешается арендатору A, тогда как корпус или пространство имен принадлежит арендатору B.
- Слишком широкий извлечение: профиль возвращает слишком много фрагментов, что увеличивает стоимость и ухудшает качество ответа.
- Несоответствие размера фрагмента: фрагменты настолько велики, что цитаты являются неточными, или настолько малы, что контекст теряет смысл.
- Несоответствие функций поставщика: одна модель может выдавать цитаты в требуемой форме, а другая — нет.
- Сбой жизненного цикла: запрашивается удаление, но Хранилище на стороне поставщика остается активным или непроверенным.
Эти тесты должны выполняться на уровне контракта шлюза, а не только внутри одного адаптера поставщика. Цель состоит в том, чтобы доказать, что общедоступное поведение остается стабильным при изменении серверной части извлечения или поставщика генерации.
Компромиссы
Извлечение собственного поставщика может сократить объем кода приложения и ускорить выпуск первой версии. Компромисс заключается в том, что жизненный цикл хранилища, формат цитирования, управление запросами и доступность функций могут быть привязаны к одному поставщику.
Внешние векторные базы данных увеличивают рабочую зону. Преимущество заключается в более высокой переносимости между моделями, совместимыми с OpenAI, моделями Anthropic и будущими поставщиками. Они также упрощают понимание пространств имен или сегментов на уровне клиента, когда шлюз отвечает за выставление счетов и отключение.
Детальные фрагменты повышают точность цитирования и возможность аудита. Они также увеличивают размер индекса, объем поиска и сложность быстрой сборки. Грубые фрагменты проще, но они могут содержать цитаты, указывающие на широкую страницу или раздел, а не на точный подтверждающий отрывок.
Режим строгого цитирования повышает доверие пользователей.Это также заставляет шлюз обрабатывать модели, которые не могут создать требуемый формат цитирования, что может означать отказ в запросе, изменение модели или возврат ответа с более низким состоянием достоверности.
Прогноз: извлечение станет более нативным, но шлюзам по-прежнему нужен собственный контракт
Нативные функции поиска, предоставляемые поставщиком, вероятно, станут более функциональными. Больше моделей будут принимать полученный контекст со структурированными исходными метаданными. Дополнительные API будут предоставлять элементы управления ранжированием, переписывание запросов и настройки цитирования. Это не устраняет необходимость в контракте шлюза.
Шлюз по-прежнему владеет удостоверениями арендаторов, управлением ключами, лимитами расходов, аналитикой использования, рабочими процессами партнерского API и обещаниями удаления, ориентированными на клиента. Функции поставщика можно использовать за уровнем адаптера, но продукт не должен принудительно помещать каждый арендатор, модель и рабочий процесс выставления счетов в абстракцию извлечения одного поставщика.
Полезный вывод
Создавайте многотенантную RAG как подсистему шлюза с явными границами. Уточните личность арендатора перед извлечением. Используйте пространства имен, сегменты или векторные хранилища на уровне клиента. Держите извлечение за адаптерами. Нормализуйте цитаты в схему, принадлежащую шлюзу. Добавьте состояния жизненного цикла и проверку удаления. Отслеживайте затраты на внедрение, извлечение и генерацию отдельно.
Эта архитектура обеспечивает устойчивость RAG без привязки продукта к одному поставщику извлечения. Это также дает командам необходимые оперативные средства контроля, когда ИИ-помощник переходит от прототипа к системе, ориентированной на клиента: изоляция, цитирование, переносимость, управление жизненным циклом и распределение затрат.