Головна / Статті / Створення RAG у Azure: чанкування, гібридний пошук, фільтри та цитування

Створення RAG у Azure: чанкування, гібридний пошук, фільтри та цитування

Для пошуку в масштабах підприємства потрібні фрагменти з урахуванням структури, гібридний пошук, фільтри ACL, переранжування, чітко сформульовані запити та механізми оцінки — а не демонстрація у форматі PDF.

1350 слів

Демонстрації RAG виглядають простими: PDF → фрагменти → ембеддинги → векторна БД → запит до моделі. А потім надходять п’ять тисяч документів, і хтось просить правила відшкодування витрат на міжнародні поїздки. Складною є частина надійного введення правильних доказів у модель.

1. Почніть з даних, а не з LLM

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

2. Розділення на фрагменти: не діліть сліпо кожні N символів

Віддавайте перевагу розділенню з урахуванням структури (заголовки, сторінки, таблиці) з перекриттям. Таблиці тарифів та положення правил не переносять наївні підходи з розділенням за кількістю символів.

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

Зберігайте текст, вектори та фільтруванну метадані (id документа, продукт, локалізація, група ACL, updated_at).

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 на одній сторінці, щоб кожен новий завдання імпорту записувало ті самі дані, яких очікує фільтр отримання інформації.

Оцінка має знаходитися в тому самому репозиторії, що й конфігурація чанкінгу: коли хтось „лише трохи змінює“ параметри перекриття, „золотий пакет“ має зазнати невдачі ще до того, як це помітять користувачі.