Производство RAG в Azure: разбиение на части, гибридный поиск, фильтры и цитаты
Для предприятий поиск требует фрагментов с учетом структуры, гибридного поиска, фильтров ACL, переранжирования, основанных на реальных данных промптов и методов оценки — а не демонстрации в формате PDF.
Демонстрации технологии RAG кажутся простыми: PDF → фрагменты → векторные представления → база данных векторов → запрос к модели. Но затем поступает пять тысяч документов, и кто-то запрашивает правила возмещения расходов на международные поездки. Самая сложная часть — надежное введение правильных данных в модель.
1. Начните с данных, а не с большой языковой модели
Перед выбором чат-модели оцените источники данных, механизмы контроля доступа, актуальность информации и форматы. Некачественные корпуса данных приводят к неверным ответам.
2. Разбиение на фрагменты: не делайте разделение слепо по количеству символов
Предпочитайте разделение с учетом структуры (заголовки, страницы, таблицы) с перекрытием фрагментов. Таблицы тарифов и положения правил плохо справляются с примитивным подходом, основанным на количестве символов.
3. Генерация векторных представлений
Используйте один и тот же способ генерации векторов; записывайте размерность и идентификатор модели для каждого индекса. Смешивание разных моделей незаметно снижает точность результатов.
document = {
"document_id": "HR-2026-001",
"title": "Employee Benefits Policy",
"department": "HR",
"country": "India",
"version": "2026.1",
"effective_date": "2026-01-01",
"source": "HR Portal"
}
def chunk_text(text, size=1000):
return [
text[i:i + size]
for i in range(0, len(text), size)
]
def chunk_by_sections(document):
chunks = []
for section in document.sections:
chunks.append({
"title": section.title,
"content": section.text,
"document_id": document.id
})
return chunks
pip install openai azure-identity
from openai import OpenAI
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
token_provider = get_bearer_token_provider(
DefaultAzureCredential(),
"https://ai.azure.com/.default"
)
client = OpenAI(
base_url="https://YOUR-RESOURCE.openai.azure.com/openai/v1/",
api_key=token_provider
)
response = client.embeddings.create(
model="text-embedding-3-small",
input="Employees are eligible after completing 12 months of service."
)
vector = response.data[0].embedding
{
"id": "HR-2026-001-004",
"document_id": "HR-2026-001",
"title": "Employee Benefits Policy",
"content": "...",
"country": "India",
"version": "2026.1",
"content_vector": embedding
}
from azure.search.documents import SearchClient
from azure.search.documents.models import VectorizedQuery
query = "Can I work remotely from another country?"
query_vector = client.embeddings.create(
model="text-embedding-3-small",
input=query
).data[0].embedding
vector_query = VectorizedQuery(
vector=query_vector,
k_nearest_neighbors=10,
fields="content_vector"
)
results = search_client.search(
search_text=query,
vector_queries=[vector_query],
top=5,
select=["title", "content", "document_id", "country"]
)
results = search_client.search(
search_text=query,
vector_queries=[vector_query],
filter="country eq 'India'",
top=5
)
context = "\n\n".join(
f"Source: {r['title']}\n{r['content']}"
for r in results
)
prompt = f"""
You are an enterprise policy assistant.
Answer the user's question using only the provided evidence.
If the evidence does not contain the answer, say that you don't have enough information.
Do not invent policies.
Evidence: {context}
Question: {query}
"""
{
"document_id": "HR-2026-001",
"page": 14,
"section": "Eligibility",
"content": "..."
}
def answer_question(question):
# 1. Embed the question
vector = embed(question)
# 2. Hybrid retrieval
candidates = search(
query=question,
vector=vector,
top=20
)
# 3. Apply metadata/business filters
candidates = apply_filters(candidates)
# 4. Rerank
ranked = rerank(question, candidates)
# 5. Keep only useful evidence
evidence = ranked[:5]
# 6. Build grounded prompt
prompt = build_prompt(
question,
evidence
)
# 7. Generate answer
response = generate(prompt)
# 8. Return answer + citations
return {
"answer": response,
"sources": extract_sources(evidence)
}
test_cases = [
{
"question": "What is the India travel allowance?",
"expected_source": "travel-policy-india.pdf"
},
{
"question": "How long is parental leave?",
"expected_source": "leave-policy-2026.pdf"
}
]
4. Хранение эмбеддингов в Azure AI Search
Храните текст, векторы и метаданные, подлежащие фильтрации (идентификатор документа, продукт, регион, группа доступа, время обновления).
5. Гибридный поиск эффективнее чисто векторного для большинства предприятий
Сочетайте метод плотного сравнения с алгоритмом BM25/ключевыми словами для идентификаторов, кодов и редких собственных имён.
6. Фильтрация до траты ресурсов на обработку контекста
Применяйте фильтры безопасности и аренды в запросе, а не после того, как модель уже обработала запрещённые фрагменты.
7>Результат поиска — это не окончательный контекст
Переустанавливайте ранги, удаляйте дубликаты и ограничивайтесь заданным лимитом токенов. Больше фрагментов не означает лучших ответов.
8. Создание запроса на основе имеющихся данных
Инструкции должны требовать ответов только из предоставленных отрывков и указывать на отсутствие доказательств.
9. Обоснование с цитатами
Укажите идентификаторы отрывков/страниц, чтобы пользователи могли их проверить. Отсутствие цитат является недостатком.
10. Поток, готовый к использованию
Прием данных → разбиение на части → встраивание → индексация → гибкий поиск → фильтрация → переранжирование → формулировка запроса → генерация ответа → цитирование → оценка.
11. Что обычно ломается
Некорректное разбиение на части; плохие метаданные; поиск только с использованием векторов; чрезмерно большой контекст; отсутствие набора для оценки; отсутствие цитат; отсутствие механизма ACL; тайные замены моделей встраивания; отсутствие информации о свежести данных.
Заключение
Промышленная система RAG — это поиск информации с привязкой к конечной точке LLM, а не наоборот. Инвестируйте в разбиение данных на части, гибкий поиск, фильтры, цитирование и оценку; чат-модель выполняет роль завершающего этапа.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Для каждой области доменов храните идеальный набор вопросов: поиск по точному идентификатору, вопросы-парапроизведения и случаи с отрицательным результатом ACL. Автоматизируйте их в CI каждый раз, когда меняются настройки сегментации или встраивания.
Процесс оценки должен находиться в том же репозитории, что и конфигурация разбиения на части: когда кто-то «немного меняет» параметры перекрытия, система должна сработать некорректно ещё до того, как это заметят пользователи.
Для гибридного поиска всё ещё необходимы качественные анализаторы и списки синонимов для специфической терминологии данной области; одних только эмбеддингов недостаточно для исправления ошибок в коде политик.
Опишите спецификации поля ACL на одной странице, чтобы каждая новая задача обработки данных сохраняла те же данные, которые ожидает фильтр получения информации.
Процесс оценки должен находиться в том же репозитории, что и конфигурация разбиения на части: когда кто-то «немного меняет» параметры перекрытия, система должна сработать некорректно ещё до того, как это заметят пользователи.