Гайд · TNWS AI
Как разложить документы на chunks для RAG через index projections Azure AI Search
Один поисковый документ на chunk: parent_id, sourceContext, skipIndexingParentDocuments и проверка наследования доступа.
Задача и применимость
Актуальный русскоязычный запрос: «как настроить index projections Azure AI Search chunks RAG». Официальная документация Microsoft проверена 19 сентября 2026 года. Azure AI Search REST API 2026-04-01; индексатор, skillset и поддерживаемый источник уже спроектированы; Text Split skill создаёт /document/pages/*.
Задача здесь — выполнить и проверить конкретную операцию в Azure AI Search. Образцовые значения вроде ru-kb, p1 и policy-2026-01 принадлежат тестовому корпусу, а не обязательным именам в вашем сервисе. У вас должны быть полномочия на указанную операцию; для теста можно использовать административный ключ на доверенном сервере, но в пользовательском браузере нужен защищённый серверный посредник. Сначала снимите baseline по контрольному запросу и набору документов, затем меняйте только одну настройку за раз.
Что подтверждает документация
Index projections определяются внутри skillset и нужны для схемы «один родитель — несколько chunks». Microsoft рекомендует один индекс с повторением полей родителя и projectionMode=skipIndexingParentDocuments. Для него требуется отдельный строковый ключ chunk, строковый filterable parent_id, сопоставление pages и перенесённые поля родителя. Если есть метаданные разрешений, каждое дочернее поле должно получить их через mappings.
Это не обещание одинакового ранжирования для любого русского корпуса. Результат embedding зависит от deployment, подготовки текста, chunking, обновлений модели и состава индекса. Доступность предварительных функций и ограничения сверяйте с документацией и настройками собственного сервиса; цена и длительность операций здесь намеренно не указаны, потому что они не следуют из поискового ответа. Отделяйте успешный HTTP-запрос от оценки полезности найденного фрагмента.
Пошаговое выполнение
- Создайте индекс chunks с ключом chunk_id, filterable parent_id, retrievable chunk и title; если используются vectors, добавьте chunk_vector с правильным profile.
- Настройте Text Split skill на создание pages; проверьте путь фактических outputs в вашем skillset.
- В indexProjections.selectors укажите targetIndexName, parentKeyFieldName, sourceContext=/document/pages/* и mappings для chunk/title.
- Для единого индекса поставьте projectionMode=skipIndexingParentDocuments и согласуйте targetIndexName индексатора.
- Запустите индексатор на одном многостраничном документе, проверьте количество дочерних ID, parent_id и фильтрацию доступа.
После каждого шага сохраняйте версию схемы, идентификатор тестового документа и ответ сервиса. При ошибке сначала установите, на каком слое она возникла: полномочия, схема, несовместимый vector, индексирование или собственно ранжирование. Не обновляйте рабочую схему, если не умеете вернуться к старому индексу. Для тестов доступа всегда предусмотрите документ другого tenant и отрицательный запрос.
Готовый REST-шаблон
"indexProjections":{"selectors":[{"targetIndexName":"ru-chunks",
"parentKeyFieldName":"parent_id","sourceContext":"/document/pages/*",
"mappings":[{"name":"chunk","source":"/document/pages/*"},
{"name":"title","source":"/document/title"}]}],
"parameters":{"projectionMode":"skipIndexingParentDocuments"}}
# Это фрагмент skillset, а не самостоятельный POST payload.
# Для embedding добавьте mapping chunk_vector из фактического output skill.
Подставьте своё имя сервиса в https://<service>.search.windows.net, передайте Content-Type: application/json и авторизацию выбранным поддерживаемым способом. Демонстрационный массив из трёх чисел или строка <embedding массива> — только описание формы; они не являются реальным embedding для поля с 1536 измерениями. Перед отправкой проверьте JSON, размерность и отсутствие ключа в клиентском коде.
Входные данные и ожидаемый результат
Вход: источник contract-1 разделён Text Split skill на страницы с идентификаторами фрагментов и общим названием «Договор». Ожидается несколько поисковых документов в ru-chunks с одинаковым parent_id=contract-1 и разными chunk_id, без дополнительной пустой строки родителя. Поиск возвращает конкретный chunk и название родителя; количество зависит от размера и параметров деления.
Ожидаемый ID — проверяемая гипотеза на подготовленном тестовом наборе. При другом корпусе и другом embedding нельзя честно обещать конкретный score и порядок результатов. Сохраняйте как входное содержимое, так и текст возвращённого фрагмента: найденный ID без исходного подтверждения не годится для публикации ответа от имени компании.
Разбор и границы применения
Для RAG недостаточно просто разбить текст на части. Гранулярность chunk влияет на полноту ответа: слишком короткий фрагмент теряет условия и исключения; слишком длинный затрудняет точную цитату и может перегружать дальнейший генератор. Проверяйте совпадение boundaries с абзацами и разделами вашего корпуса на нескольких длинных документах. Если title и permissions принадлежат родителю, они должны повторяться на каждом дочернем документе: иначе поисковая выдача может показать чужой текст или потерять источник. Поле parent_id не должно становиться ключом chunk, поскольку один родитель имеет несколько дочерних записей. Два индекса «родители/дети» можно построить, но классический поиск не делает соединение индексов во время запроса; это усложняет сбор цитат. В примере намеренно показан фрагмент indexProjections: он запускается только вместе с реальным data source, indexer, Text Split skill и согласованным индексом. При обновлении исходника проверяйте удаление устаревших chunks и сценарий change tracking у выбранного источника. Векторное поле chunk_vector требует отдельного embedding skill и mapping, если вы рассчитываете embeddings во время индексирования; сама projection его не создаёт.
Практический контроль именно этой задачи
Сделайте проверку наследования метаданных до подключения LLM. Один документ contract-1 должен получить несколько chunks, каждый со своим chunk_id, одинаковым parent_id и заголовком. Второй документ другого отдела нужен для проверки прав доступа. Если ACL хранится на уровне родителя, перенесите разрешающие поля в mappings для каждого child; иначе фильтр на поисковом индексе не сможет отделить защищённые фрагменты. Удалите или обновите исходный контракт в тестовом источнике и проверьте, что старые chunks не остаются рядом с новыми; поведение зависит от поддерживаемого механизма change tracking и удаления. Отдельно оцените границу разреза текста: если пункт о сроке на одной странице, а исключение на следующей, генератору могут передаваться неполные основания. Подберите стратегию перекрытия/разбиения из документации Text Split skill и повторите тест нескольких размеров. Не называйте parent_id источником истины: это связка, а не замена ссылке и контролю версий оригинального документа.
Критерии проверки
- Каждый chunk получает уникальный ключ и parent_id.
- Нет пустого parent-документа в едином индексе.
- Каждый chunk несёт нужные title и permissions.
- Найдённый текст можно процитировать по исходному родителю.
Если хотя бы один критерий провален, не маскируйте проблему красивым ответом генеративной модели: возвращайте человеку найденные документы или явное сообщение о недостаточности данных. Сравнение версий проводите на одних и тех же контрольных вопросах, фиксируя документные ID и дату наблюдения.
Типичные ошибки и что не делать
- Использовать parent_id в качестве единственного ключа.
- Не переносить permissions в mappings.
- Считать фрагмент конфигурации полным skillset.
- Путать index projection с генерацией embeddings.
Не обучайте и не оценивайте систему только на запросах, скопированных из заголовков: нужна и перефразировка, и отрицательные тесты. Не называйте близость векторов гарантом правдивости: источник может устареть, противоречить другому документу или оказаться недоступным данному пользователю. При внедрении RAG передавайте генератору текст, ID и разрешённую ссылку на первоисточник, а неподтверждённые утверждения не включайте в итоговый ответ.
FAQ
Где задаются projections?
В определении skillset.
Зачем skipIndexingParentDocuments?
Чтобы один индекс содержал только chunks, без пустых родительских документов.
Нужен ли отдельный embedding skill?
Да, если хотите генерировать vector на этапе индексирования.
Официальные источники
Частые вопросы
Где задаются projections?
В определении skillset.
Зачем skipIndexingParentDocuments?
Чтобы один индекс содержал только chunks, без пустых родительских документов.
Нужен ли отдельный embedding skill?
Да, если хотите генерировать vector на этапе индексирования.
Читайте также
Как фильтровать векторный поиск Azure AI Search по tenant без утечки данных
OData filter и vectorFilterMode preFilter для tenant, негативный тест изоляции и сравнение с postFilter.
Как искать текстом через vectorizer Azure AI Search без передачи массива чисел
Настройка vectorizer и REST kind:text для русских вопросов: связка profile, модели и проверка результатов.
Как измерить recall HNSW в Azure AI Search через exhaustive KNN
Точный baseline exhaustive:true, Recall@k, стабильный набор запросов и диагностика trade-off качества и задержки.
Комментарии
Пока тихо. Скажите первое слово