Практичні нотатки: Dartboard RAG: коли Top-K повертає три версії одного й того ж
Покрокове пояснення до практичних нотаток: Dartboard RAG: коли Top-K повертає три версії одного й того ж – контракти, перевірки та готові шаблони коду для команд, які використовують цю схему.
Наступні примітки описують практичний підхід до вирішення проблеми „Dartboard RAG: коли Top-K повертає три версії одного й того ж фрагмента“. Увага зосереджується на контрактах, перевірках та місцях для вставки коду, а не на мотиваційному описі.
Проблема дубльованих контекстів
Під час роботи над етапом проблеми дубльованих контекстів спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та наслідки часткової невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Записуйте час виконання та витрати на токени або запити поруч із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовищ до спільних середовищ. Перевіряйте рівень відтворення інформації на фіксованому наборі запитань перед налаштуванням підказок. Часта зміна підказок рідко вирішує проблеми слабкої системи пошуку інформації.
Top 3:
1. "Greenhouse gases trap heat in the atmosphere, causing warming..." (sim 0.91)
2. "Atmospheric greenhouse gases are the primary driver of climate change..." (sim 0.89)
3. "The trapping of heat by greenhouse gases leads to rising temperatures..." (sim 0.88)
Аналогія з тиром
Під час роботи над етапом аналогії з мішенню спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища секретних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Вимірюйте рівень відтворення інформації за фіксованим набором запитань перед налаштуванням підказок. Часта зміна підказок рідко виправляє проблеми з недостатньою ефективністю пошуку.
Chunks plotted by relevance to query
(closer to center = higher cosine sim)
●●● ← cluster of near-duplicate chunks
●●● (all about "greenhouse gases")
● bull's-eye = QUERY
● ← chunk about deforestation
(relevant but different topic)
● ● ← chunks about agriculture, ocean carbon
● ● ← chunks about historical climate
STANDARD TOP-3 picks: DARTBOARD TOP-3 picks:
3 closest darts 1 closest, then darts that are also
= 3 darts in the same good but spread across the board
spot near bull's-eye = better coverage of relevant content
Потік обробки
Під час роботи над етапом конвеєра спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Одночасно задокументуйте шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Перед налаштуванням запитів вимірюйте рівень відтворення інформації на фіксованому наборі запитань. Зміна запитів рідко вирішує проблеми слабкої системи пошуку.
Крок 1 — Надмірне отримання даних за допомогою FAISS
Під час виконання кроку 1 «Надмірне отримання даних з використанням етапів» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу невеликим, тестованим одиницям перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру обробки даних. Перед налаштуванням запитів вимірюйте рівень відтворення інформації на фіксованому наборі запитань. Часта зміна формулювань запитів рідко допомагає покращити якість пошуку.
fetch_k = self.k * self.oversampling # default: 5 × 3 = 15
candidates = vector_store.search(query_embedding, k=fetch_k)
Крок 2 — Обчислення матриц відстаней
Під час виконання етапу „Обчислення відстані“ у кроці 2 спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте беззвучного часткового виконання завдань. Перед налаштуванням запитів вимірюйте рівень відтворення інформації на фіксованому наборі запитань. Часта зміна формулювань запитів рідко допомагає покращити якість пошуку. Під час виконання етапу „Обчислення відстані“ у кроці 2 спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Зберігайте конфігурацію окремо від коду програми. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, яке оператори можуть перевіряти, не читаючи весь код.
# Normalize all vectors so dot product = cosine similarity
query_norm = query_vec / np.linalg.norm(query_vec)
cand_norm = candidate_matrix / np.linalg.norm(candidate_matrix, axis=1, keepdims=True)
# Distance = 1 - cosine_similarity
query_distances = 1.0 - np.dot(query_norm, cand_norm.T) # (1, N)
document_distances = 1.0 - np.dot(cand_norm, cand_norm.T) # (N, N)
Крок 3 — Перетворення на лог-нормальні ймовірності
Етап перетворення у Кроці 3 працює найкраще, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування дій перед розширенням обсягу. Документуйте як успішний, так і відновлювальний сценарії разом. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Розділіть політику часткової обробки даних від політики їх пошуку. Зміна однієї не повинна змушувати до переписування іншої при зміні показників якості.
def lognorm(dist, sigma):
return -np.log(sigma) - 0.5 * np.log(2 * np.pi) - dist**2 / (2 * sigma**2)
Крок 4 — Цикл жадібного вибору
Четвертий крок – етап жадібності – найкраще функціонує, якщо його розглядати як вимірювану поверхню. Зафіксуйте один ідеальний результат, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Віддавайте перевагу невеликим, тестованим одиницям перед складними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Розділяйте політику часткового оброблення даних та політику їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.
# Step 1: pick most relevant first
most_relevant_idx = np.argmax(query_probs)
selected_indices = [most_relevant_idx]
max_distances = doc_probs[most_relevant_idx].copy() # diversity tracker
# Step 2-6: iteratively add diverse + relevant chunks
while len(selected_indices) < num_results:
# For each candidate, compute "diversity from any selected"
updated_distances = np.maximum(max_distances, doc_probs)
# Combine relevance + diversity
combined = (diversity_weight * updated_distances
+ relevance_weight * query_probs[np.newaxis, :])
# Aggregate per candidate (logsumexp for numerical stability)
normalized = logsumexp(combined, axis=1)
# Mask already-selected
for idx in selected_indices:
normalized[idx] = -np.inf
# Pick the best
best_idx = np.argmax(normalized)
max_distances = updated_distances[best_idx]
selected_indices.append(best_idx)
Що насправді робить математика (інтуїтивно)
Етап «Що таке математика» функціонує найкраще, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний зразок результату, один випадок невдачі та примітку про скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового виконання завдань. Розділіть політику часткового оброблення даних від політики їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу, коли змінюються показники якості. Етап «Що таке математика» функціонує найкраще, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний зразок результату, один випадок невдачі та примітку про скасування змін перед розширенням обсягу роботи. Зберігайте конфігурацію окремо від коду програми. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код.
Relevance →
Low ●◯
● ● ← Standard top-k picks these 3
(highest relevance, regardless of diversity)
● ●
●●●●●● ● ● ● ← Many similar high-relevance chunks
High (cluster)
Diversity ↓
from
selected
↓
↓ ↓ ← Dartboard picks 1 from cluster,
then far-away ones with high relevance still
Ваги — що робить кожна з них
Щодо ваг кожної стадії, необхідно визначити вхідні дані, виконавця кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Необхідно документувати як шлях успішного виконання, так і шлях відновлення одночасно. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Наводьте уривки тексту, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням.
relevance_weight = 1.0 # how much we care about chunks being close to query
diversity_weight = 1.0 # how much we care about chunks being different from each other
Приклад з реального застосування: тест на дублікати корпусу
Для прикладу, де все працює належним чином, на етапі підготовки необхідно визначити вхідні дані, виконавця кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру обробки даних. Наводьте ті уривки, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинацію від проблем із індексуванням.
1. "Greenhouse gases cause warming..." (sim 0.91)
2. "Greenhouse gases cause warming..." (sim 0.91) ← DUPLICATE
3. "Greenhouse gases cause warming..." (sim 0.91) ← DUPLICATE
4. "Greenhouse gases cause warming..." (sim 0.91) ← DUPLICATE
5. "Greenhouse gases cause warming..." (sim 0.91) ← DUPLICATE
Unique results: 1/5
1. "Greenhouse gases cause warming..." (highest relevance — wins first pick)
2. "Deforestation reduces the carbon sink..." (different chunk, still relevant)
3. "Industrial agriculture emits methane..." (third unique cause)
4. "Land-use changes alter surface albedo..." (fourth unique cause)
5. "Fossil fuel combustion is the largest CO₂ source..." (related to #1 but different angle)
Unique results: 5/5
Суть у кількох реченнях
Для суті на цьому етапі необхідно визначити вхідні дані, виконавця кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового завершення. Наводьте конкретні уривки, які лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням.
def dartboard_select(query_emb, candidate_embs, k=5, sigma=0.1):
# 1. Compute distance matrices
query_dist = 1 - cosine(query_emb, candidate_embs) # query→each
doc_dist = 1 - cosine(candidate_embs, candidate_embs) # each→each
# 2. Convert distances to log-probabilities
query_probs = lognorm(query_dist, sigma)
doc_probs = lognorm(doc_dist, sigma)
# 3. Pick most relevant first
selected = [np.argmax(query_probs)]
max_distances = doc_probs[selected[0]].copy()
# 4. Iteratively add diverse + relevant
while len(selected) < k:
updated = np.maximum(max_distances, doc_probs)
combined = updated + query_probs[np.newaxis, :] # equal weights = sum
scores = logsumexp(combined, axis=1)
for idx in selected:
scores[idx] = -np.inf # don't re-select
best = np.argmax(scores)
max_distances = updated[best]
selected.append(best)
return selected
Щоб зрозуміти сутність кожного етапу, необхідно визначити вхідні дані, власника цього етапу та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити етап з відомої точки контролю, не намагаючись визначити прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код.
Елементи, які можна налаштовувати
Під час роботи з елементами керування можна спочатку скласти контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність під час подальших змін у коді. Документуйте як шлях успішної роботи, так і шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Вимірюйте ефективність пошуку за фіксованим набором запитань перед налаштуванням підказок. Часта зміна підказок рідко вирішує проблеми слабкої системи пошуку.
Де це є корисним, а де — ні
Під час роботи над розділом «Де це досягає своєї стадії» спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Коли якась крок виконується невдало, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій. Перед налаштуванням запитів вимірюйте рівень відтворення інформації на фіксованому наборі запитань. Часта зміна формулювань запитів рідко вирішує проблеми слабкого пошуку даних.
Головна ідея, яку варто запам’ятати
Під час роботи над етапом «The bigger idea worth» спочатку запишіть угоду: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Розглядайте цей етап як угоду між вхідними даними та перевіреними результатами. Дайте назви елементам, визначте критерії успіху та не допускайте беззвучного часткового виконання завдань. Вимірюйте рівень запам’ятовування на фіксованому наборі запитань перед налаштуванням підказок. Часта зміна підказок рідко виправляє проблеми з недостатньою ефективністю пошуку. Під час роботи над етапом «The bigger idea worth» спочатку запишіть угоду: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Зберігайте конфігурацію окремо від коду додатку. Файли середовища, сховища секретних даних та флаги функцій мають знаходитися в одному місці, яке оператори можуть перевіряти, не читаючи весь код.
Останні думки
Етап «Остаточні міркування» найкраще функціонує, якщо його розглядати як вимірювану поверхню. Зафіксуйте один ідеальний варіант роботи, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний сценарії роботи разом. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Розділіть політику часткової обробки даних від політики їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.
Чек-лист операцій
Для етапу чек-листу операцій визначте вхідні дані, відповідальну особу за кожен крок та критерії завершення роботи перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не здогадуючись про прихований стан системи. Записуйте час виконання та витрати на обробку даних поруч із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні середовища.
Наведіть уривки тексту, які насправді лягли в основу відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням.
Напишіть короткий посібник: як обертати ключі, як спорожнювати чергу, як скасовувати останнє завантаження даних.
Зберігайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код.
Наведіть уривки тексту, які насправді лягли в основу відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням.
Перед підвищенням версії стека заморозьте поточні версії, збережіть ідеальний запис для критичного шляху виконання та підтвердьте кроки скасування змін. У спільних середовищах необхідні обмеження на швидкість виконання, перевірки прав доступу та чіткий власник для зміни конфіденційних даних. Віддавайте перевагу надійності перед креативними одноразовими демонстраціями.
Примітка до пакету fd4991fea9d9: не включайте ключі постачальників у репозиторій, встановіть ліміт токенів на сеанс та зберігайте транскрипції поруч із фіксами для оцінки, щоб подальша заміна моделей залишалася порівнянною.