Головна / Статті / Практичні поради: Я створив систему RAG, яка сама себе перевіряє. Ось як (з

Практичні поради: Я створив систему RAG, яка сама себе перевіряє. Ось як (з

Покрокова інструкція з практичних нотаток: Я створив систему RAG, яка сама себе перевіряє. Ось як (з контрактами, перевірками та слотами для коду для команд, які використовують цю схему).

3096 слів

У цьому посібнику описано процес створення системи, яка починається з сировини та закінчується функціональною системою, для проекту «Я створив систему RAG, яка сама себе перевіряє. Ось як (з кодом)». Основна увага приділяється конкретним крокам виконання, чітким перевіркам та коду, який можна просто додати до репозиторію, не намагаючись здогадатися про його призначення. На етапі огляду необхідно визначити вхідні дані, виконавця кроку та критерії завершення перед зміною коду. Виконавці мають мати можливість перезапустити крок з відомої точки контролю, не намагаючись зрозуміти прихований стан системи. Краще використовувати невеликі, тестовані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має бути пов’язана з конкретною функцією, а не з складною структурою всієї системи.

Чому ніхто не стежить за процесом отримання даних (і чому це скоро їм зашкодить)

Під час роботи над етапом «Чому ніхто не контролює процес отримання даних» спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Дайте назви елементам, визначте критерії успіху та не допускайте беззвучного часткового виконання завдань. Вимірюйте рівень відтворення інформації за фіксованим набором запитань перед налаштуванням підказок. Часта зміна підказок рідко виправляє проблеми з процесом отримання даних.

Три речі, які відбуваються непомітно

Під час роботи над етапом «Три аспекти, які мають бути враховані», спочатку запишіть умови виконання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Запишіть час виконання та витрати на токени або запити поруч із результатами функціональності. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам, коли система переходить від демо-режиму до спільних середовищ. Перевірте ефективність пошуку на фіксованому наборі запитань перед налаштуванням формулювань запитів. Часта зміна формулювань рідко допомагає покращити якість пошуку.

1. Забруднення даних

Під час роботи над етапом 1 «Отруєння чанків» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища секретних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Вимірюйте рівень відтворення інформації на фіксованому наборі запитань перед налаштуванням підказок. Часта зміна підказок рідко виправляє слабку систему пошуку інформації. Під час роботи над етапом 1 «Отруєння чанків» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Віддавайте перевагу малим, тестованим одиницям коду перед величезними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій.

2. Відхилення ембеддингів

Етап 2 Embedding Drift працює найкраще, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний зразок тексту, один випадок невдачі та примітку про скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як угоду між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового виконання завдань. Розділіть політику часткового оброблення даних від політики їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.

3. Марнування ресурсів контекстного вікна

Етап „Витрати контекстного вікна“ найкраще функціонує, якщо його розглядати як вимірювану характеристику. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат на ранньому етапі запобігає несподіваним рахункам під час переходу від демо-середовища до спільних середовищ. Розділяйте політику часткового оброблення даних та політику їх пошуку. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.

Що ми створюємо

Етап «Що ми будуємо» функціонує найкраще, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Розділіть політику поділу на частини від політики отримання даних. Зміна однієї з них не повинна змушувати переписувати іншу, коли змінюються показники якості. Етап «Що ми будуємо» функціонує найкраще, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Віддавайте перевагу малим, тестованим одиницям перед величезними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій.

▣ Перевірка №1: Оцінювання релевантності частин.

На етапі перевірки релевантності частини 1 необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість знову виконати цей крок, починаючи з відомої точки контролю, без необхідності здогадуватися про прихований стан. Розглядайте цей етап як угоду між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового завершення роботи. Наводьте конкретні уривки, які лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем із індексуванням.

▣ Перевірка №2: Виявлення зміщення ембеддингів.

На етапі перевірки відхилень у вбудовуванні Check 2 необхідно спочатку визначити вхідні дані, відповідального за крок та критерії завершення, перш ніж змінювати код. Оператори повинні мати можливість знову запустити крок з відомої точки контролю, не намагаючись визначити прихований стан. Записуйте час виконання та витрати на токени або запити поруч із функціональними результатами. Чітке відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні. Наводьте конкретні уривки тексту, на яких ґрунтується відповідь. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням.

▣ Перевірка №3: Ефективність вікна контексту.

На етапі вікна контексту Check 3 необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функціоналу мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Наводьте уривки тексту, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинацію від проблем із індексуванням. На етапі вікна контексту Check 3 необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Віддавайте перевагу невеликим, тестованим одиницям перед об’ємними скриптами. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру обробки даних.

Створення аудиту: почніть з ідеального набору запитів

Під час виконання етапу «Створення аудиту: початок» спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Дайте назви елементам, визначте критерії успіху та не допускайте беззвучного часткового виконання завдань. Вимірюйте рівень відтворення інформації за фіксованим набором запитань перед налаштуванням підказок. Часта зміна підказок рідко вирішує проблеми слабкого пошукового механізму.

[
  {
    "query": "What is the refund policy for digital products?",
    "expected_chunk_ids": ["faq_doc_chunk_12", "faq_doc_chunk_13"],
    "notes": "Customer FAQ, policy updated 2024-Q1"
  },
  {
    "query": "How do I reset my API key?",
    "expected_chunk_ids": ["api_docs_chunk_07"],
    "notes": "API documentation, stable"
  }
]

Кілька важливих моментів під час створення:

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

Сценарій аудиту

Під час роботи над етапом «Скрипт аудиту» спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, щоб оператори могли їх перевіряти, не читаючи весь код. Вимірюйте рівень точності відповідей на фіксований набір запитань перед налаштуванням промптів. Зміна промптів рідко вирішує проблеми слабкої системи пошуку інформації. Під час роботи над етапом «Скрипт аудиту» спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Віддавайте перевагу невеликим, тестованим одиницям коду перед величезними скриптами. Якщо якийсь крок зазнає невдачі, причина має бути пов’язана з конкретною функцією, а не з заплутаною послідовністю операцій.

Структура репозиторію Github

Етап структурування репозиторію Github працює найкраще, якщо його розглядати як вимірювану основу. Зафіксуйте один ідеальний приклад, один випадок невдачі та примітку щодо скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового виконання завдань. Розділіть політику часткового оброблення даних від політики їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.

rag-retrieval-audit/
├── audit/
│   ├── __init__.py           # Package exports
│   ├── rag_audit.py          # Main audit logic — all three checks
│   └── config.py             # All thresholds and model settings
├── examples/
│   ├── golden_queries.json   # Sample golden set (10 queries)
│   └── run_audit.py          # End-to-end demo — runs without an existing collection
├── tests/
│   └── test_audit.py         # Unit tests for all scoring functions
├── requirements.txt          # sentence-transformers, chromadb, scipy, numpy
└── README.md                 # Setup, usage, how to read the report
# rag_audit.py — structure overview
# Full implementation: https://github.com/satyam671/rag-retrieval-audit

# ── CONFIGURATION (tune to your pipeline)
EMBEDDING_MODEL      = "all-MiniLM-L6-v2"  # must match your index
TOP_K                = 5
RELEVANCE_THRESHOLD  = 0.70
DRIFT_P_THRESHOLD    = 0.05
EFFICIENCY_THRESHOLD = 0.40

# ── CHECK 1: Are the right chunks coming back?
def score_relevance(query_embedding, chunk_embeddings, expected_ids, retrieved_ids):
    """Cosine similarity per chunk + expected chunk hit/miss against golden set."""
    ...
# ── CHECK 2: Has retrieval quality shifted over time?
def detect_drift(current_sims, baseline_path=None):
    """Two-sample KS test comparing current similarity distribution to baseline."""
    ...
# ── CHECK 3: How much of the context window is signal?
def score_efficiency(retrieved_docs, answer):
    """Token overlap between retrieved chunks and the LLM answer."""
    ...
# ── RUNNER
def run_audit(golden_set_path, collection_name, chroma_persist_dir,
              baseline_path=None, answers_path=None, output_path="rag_audit_report.json"):
    """Runs all three checks, writes a structured JSON report, saves the baseline."""
    ...

Детальний огляд того, що насправді робить кожна перевірка

Аналіз кожної стадії є найефективнішим, якщо її розглядати як вимірювану поверхню. Запишіть один ідеальний результат, один випадок невдачі та примітки щодо скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-версії до спільних середовищ. Розділяйте політику часткового оброблення даних та політику їх пошуку. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.

▣ Оцінка релевантності частин даних

Етап оцінки релевантності фрагментів працює найкраще, якщо його розглядати як вимірювану характеристику. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Розділяйте політику формування фрагментів та політику їх пошуку. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості. Етап оцінки релевантності фрагментів працює найкраще, якщо його розглядати як вимірювану характеристику. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Віддавайте перевагу малим, тестованим одиницям перед складними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій.

# WITHOUT the relevance gate — standard approach most teams use
def build_context_naive(query, collection, top_k=5):
    results = collection.query(
        query_embeddings=[embed(query)],
        n_results=top_k,
        include=["documents"]
    )
    # Pass everything back, no quality check
    return "\n\n".join(results["documents"][0])

# WITH the relevance gate - what the audit tells you to build
def build_context_gated(query, collection, model, top_k=5, threshold=0.70):
    q_emb   = model.encode([query], normalize_embeddings=True)[0]
    results = collection.query(
        query_embeddings=[q_emb.tolist()],
        n_results=top_k,
        include=["documents", "embeddings", "ids"]
    )
    passed_chunks = []
    for i, chunk_emb in enumerate(results["embeddings"][0]):
        sim = cosine_sim(q_emb, np.array(chunk_emb))
        if sim >= threshold:
            passed_chunks.append(results["documents"][0][i])
    # Empty context is better than wrong context
    return "\n\n".join(passed_chunks)

▣ Виявлення змін у ембеддингах

Для етапу виявлення зсуву імбеддингів необхідно визначити вхідні дані, відповідальну особу за виконання кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити цей крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як угоду між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового завершення роботи. Наводьте конкретні уривки тексту, які лягли в основу відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем із індексуванням.

▣ Ефективність вікна контексту

На етапі оптимізації вікна контексту необхідно визначити вхідні дані, виконавця кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись визначити прихований стан. Записуйте час виконання та витрати на токени або запити поруч із функціональними результатами. Чітке відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні. Наводьте конкретні уривки тексту, які лягли в основу відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням.

Читання звіту

На етапі читання звіту необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, яке оператори можуть перевірити, не читаючи весь алгоритм. Наводьте уривки тексту, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинацію від проблем із індексуванням. На етапі читання звіту необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Віддавайте перевагу невеликим, тестованим одиницям перед об’ємними скриптами. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій.

Очікуваний результат після запуску run_audit.py:

Під час роботи над етапом «Очікуваний результат після запуску» спочатку складіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Призначте назви елементам, визначте критерії успіху та не допускайте беззвучного часткового виконання завдань. Вимірюйте рівень відтворення інформації на фіксованому наборі запитань перед налаштуванням запрошень до введення даних. Часта зміна запрошень рідко вирішує проблеми слабкого пошуку інформації.

python -m examples.run_audit

Довідник з аудиту пошуку інформації

Під час виконання етапу «Чек-лист для аудиту отримання даних» спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей чек-лист допомагає зберігати чесність пізніших змін у коді. Запишіть час виконання та витрати на токени чи запити поруч із функціональними результатами. Відображення витрат заздалегідь запобігає несподіваним рахункам, коли система переходить від демо-режиму до спільних середовищ. Вимірюйте рівень відтворення даних на фіксованому наборі запитань перед налаштуванням підказок. Часта зміна підказок рідко допомагає покращити якість отримання даних.

Одна річ, яку б ви зробили інакше

Під час роботи над однією ключовою задачею, яку потрібно реалізувати, спочатку запишіть умови її виконання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Тримайте конфігурацію окремо від коду програми. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Вимірюйте рівень точності відповідей на фіксований набір запитань перед налаштуванням формулювань запитів. Часта зміна формулювань рідко допомагає покращити якість пошуку. Під час роботи над однією ключовою задачею, яку потрібно реалізувати, спочатку запишіть умови її виконання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на складну послідовність операцій.

Що тут не охоплюється

Етап «Що це не є» функціонує найкраще, якщо його розглядати як вимірювану поверхню. Запишіть один ідеальний приклад, один випадок невдачі та примітку про скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового виконання завдань. Розділіть політику часткового оброблення даних від політики їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.

Посилання

Етап посилань функціонує найкраще, якщо його розглядати як вимірювану площину. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи.

Чек-лист операцій

Етап чек-листу операцій працює найкраще, якщо його розглядати як вимірювану площину. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи.

Документуйте як успішний, так і відновлювальний сценарії роботи разом. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки.

Розділіть політику чанкування від політики отримання даних. Зміна однієї не повинна змушувати переписувати іншу, коли змінюються показники якості.

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

Віддавайте перевагу невеликим, тестованим одиницям перед складними скриптами. Якщо якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану систему обробки даних.

Розділіть політику чанкування від політики отримання даних. Зміна однієї не повинна змушувати переписувати іншу, коли змінюються показники якості.

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

Примітка до пакету ffe9673a9f17: не включайте ключі постачальників у репозиторій, встановіть ліміт токенів на сеанс та зберігайте транскрипції поруч із фіксами для оцінки, щоб подальша заміна моделей залишалася порівнянною.