Практичні нотатки: проектування RAG для 100 мільйонів документів
Покрокове пояснення до практичних нотаток: проектування RAG для 100 мільйонів документів: контракти, перевірки та слоти для коду для команд, які використовують цю схему.
Використовуйте цей документ як оновлену версію ідей з книги „Designing RAG for 100 Million Documents“, орієнтовану на операторів: чіткі етапи, впорядковані блоки коду та примітки щодо відновлення, які залишаються при передачі обов’язків. Етап Огляду найкраще функціонує, якщо його розглядати як вимірювану поверхню. Запишіть один ідеальний запис, один випадок збою та примітки щодо скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени або запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-версії до спільних середовищ.
Ось вимоги:
На етапі визначення вимог необхідно перед зміною коду визначити вхідні дані, відповідальну особу за крок та критерії завершення. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись визначити прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функціоналу мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Необхідно наводити конкретні уривки тексту, які лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинацію від проблем з індексуванням.
Почніть з математики
На етапі «Почнемо з математики» необхідно визначити вхідні дані, відповідального за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Необхідно документувати як шлях успішного виконання, так і шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Наводьте уривки тексту, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням.
Documents = 100,000,000
Average chunks/document = 30
Embedding dimensions = 768
Storage/dimension = 4 bytes (float32)
100,000,000 × 30
= 3,000,000,000 vectors
3B × 768 × 4 bytes
≈ 9.2 TB
ANN index structures
chunk text
document metadata
ACL metadata
IDs
lexical indexes
replicas
snapshots
WALs
temporary indexes
operational headroom
100M documents × 50 chunks
= 5 billion vectors
Архітектура, яку ви б побудували
Для архітектури, яку ви плануєте впровадити, необхідно перед зміною коду визначити вхідні дані, власника кроку та критерії завершення. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру процесу. Наводьте ті уривки, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням. Для архітектури, яку ви плануєте впровадити, необхідно перед зміною коду визначити вхідні дані, власника кроку та критерії завершення. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Чітке відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-версії до спільного середовища.
Коли ви працюєте на етапі „Джерело істини“, спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища секретних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь граф. Вимірюйте рівень відтворення інформації за фіксованим набором запитань перед налаштуванням підказок. Зміни підказок рідко виправляють слабку систему пошуку.
Процес отримання даних має бути асинхронним
Під час роботи над етапом «Завантаження має бути асинхронним» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність у подальших змінах коду. Одночасно задокументуйте шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Перед налаштуванням запитів вимірюйте рівень відтворення даних на фіксованому наборі запитань. Зміна запитів рідко вирішує проблеми слабкої системи пошуку.
POST /documents
│
▼
Store document
│
▼
Create ingestion event
│
▼
Return 202 Accepted
Кожен крок завантаження має бути ідемпотентним
Під час роботи над етапом «Every Ingestion Step Should» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру обробки даних. Перед налаштуванням запитів вимірюйте рівень відтворення інформації за фіксованим набором запитань. Часта зміна формулювань запитів рідко допомагає покращити ефективність пошуку. Під час роботи над етапом «Every Ingestion Step Should» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Поруч із функціональними результатами записуйте час виконання та витрати на токени або запити. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовищ до спільних.
document_id
document_version
chunk_index
embedding_model_version
hash(
tenant_id +
document_id +
document_version +
chunk_index
)
upsert(chunk_id, ...)
Чанкінг стає рішенням інфраструктури
Етап «Чанкінг стає рішенням інфраструктури» працює найкраще, коли його розглядають як вимірювану характеристику. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь граф. Розділіть політику чанкінгу від політики отримання даних. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.
embedding compute
vector storage
indexing work
retrieval fan-out
reindexing time
replication traffic
{
"chunk_id": "c_982...",
"document_id": "doc_51...",
"document_version": 8,
"tenant_id": "tenant_17",
"page": 43,
"section": "Risk Factors",
"language": "en",
"created_at": "...",
"acl_groups": ["finance", "executives"],
"embedding_version": "embed_v4"
}
Не шукайте в усьому корпусі даних, якщо це справді не необхідно
Механізм «Не шукати» працює найкраще, коли його розглядають як вимірювану поверхню. Зафіксуйте один ідеальний варіант виконання, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний сценарії роботи разом. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Розділіть політику часткової обробки даних від політики їх пошуку. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.
organization = current tenant
region = Europe
topic = refund policy
time = current quarter
permissions = documents user may access
Шардинг — це спосіб, яким векторний шар стає розподіленим
Шардування — це найкращий спосіб функціонування етапу, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Віддавайте перевагу невеликим, тестованим одиницям перед складними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Розділяйте політику часткового оброблення даних та політику їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості. Шардування — це найкращий спосіб функціонування етапу, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-версії до спільних середовищ.
tenant_id
region
document namespace
language
time partition
Query
↓
128 shards
tenant_id = 429
↓
Shard group 18
↓
4 shards
Реплікація вирішує іншу проблему
На етапі «Реплікація вирішує іншу проблему» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись визначити прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, яке оператори можуть перевірити, не читаючи весь граф. Наводьте уривки тексту, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинацію від проблем з індексуванням.
Shard A → Node 1
Shard B → Node 2
Shard C → Node 3
Shard A → Node 1 + Node 4
Shard B → Node 2 + Node 5
Shard C → Node 3 + Node 6
Лише векторний пошук недостатній
На етапі «Лише пошук векторів» необхідно заздалегідь визначити вхідні дані, виконавця кроку та критерії завершення перед зміною коду. Оператори мають мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Необхідно документувати як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Указуйте конкретні уривки тексту, які лягли в основу відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням.
RRF(d) = Σ 1 / (k + rank_i(d))
Будьте обережні з послідовним попереднім фільтруванням
На етапі «Будь обережний із послідовністю» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру обробки даних. Наводьте уривки тексту, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням. На етапі «Будь обережний із послідовністю» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Чітке відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-версії до спільного середовища.
Розділи.
3B documents
↓
BM25 returns 10,000
↓
vector search only those
tenant
permissions
document status
Авторизація має відбутися перед тим, як докази надійдуть до LLM
Під час роботи над етапом «Авторизація має відбутися перед тим, як докази надійдуть до LLM», спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Зберігайте конфігурацію окремо від коду додатку. Файли середовища, сховища секретів та флаги функцій мають знаходитися в одному місці, яке оператори можуть перевіряти, не читаючи весь код. Зберігайте у кеші стабільні інструкції системи та схеми інструментів. Повторна передача ідентичного вступу є поширеною причиною надмірних витрат.
Engineering documents
HR documents
Board documents
Legal documents
Executive compensation
Customer contracts
Vector Search
↓
Retrieve confidential chunk
↓
Send chunk to LLM
↓
Check permission
User
↓
Identity
↓
Groups / roles / ACL
↓
Authorized search space
↓
Retrieval
Завантаження має забезпечувати кандидатів, а не контекст
Під час роботи над етапом «Отримання даних має забезпечувати кандидатів» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Документуйте як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Вимірюйте рівень відтворення інформації на фіксованому наборі запитань перед налаштуванням підказок. Зміна підказок рідко вирішує проблеми слабкої системи отримання даних.
Vector candidates: 200
Lexical candidates: 200
│
▼
Fusion
│
▼
~250 unique chunks
│
▼
Reranker
│
▼
top 20–40
Потім усуньте зайве
Під час виконання етапу «Потім усунути дублювання» спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну функцію, а не на складну систему обробки даних. Перед налаштуванням запитів вимірюйте рівень точності відповідей на фіксованому наборі запитань. Часта зміна формулювань запитів рідко допомагає покращити якість пошуку. Під час виконання етапу «Потім усунути дублювання» спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Поруч із функціональними результатами записуйте час виконання та витрати на обробку токенів чи запитів. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовищ до спільних середовищ.
Chunk 1 → page 14
Chunk 2 → page 14
Chunk 3 → page 15
Chunk 4 → page 14
Chunk 5 → page 15
deduplication
document diversity
section diversity
near-duplicate detection
adjacent-chunk merging
token budgeting
chunk 46
chunk 47
chunk 48
Створення контексту — це окремий рівень
Процес створення контексту функціонує найкраще, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Тримайте конфігурацію поза кодом додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь граф. Розділіть політику часткового оброблення даних від політики їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.
context = "\n\n".join(retrieved_chunks)
Retrieved Evidence
↓
Deduplicate
↓
Merge related chunks
↓
Enforce token budget
↓
Preserve source IDs
↓
Order evidence
↓
Generate context
SOURCE S1
Document: Employee Handbook
Page: 42
Version: 18
Text: ...
SOURCE S2
Document: European Leave Addendum
Page: 7
Version: 4
Text: ...
QUESTION
...
Розуміння запитів має бути простим
Розуміння запиту працює найкраще, якщо його розглядати як вимірювану характеристику. Збережіть один ідеальний запис, один випадок збою та примітки щодо скасування дій перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Розділіть політику часткової обробки та політику пошуку інформації. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.
metric = revenue
region = Europe
year = 2025
intent = financial comparison
How much did revenue grow in Asia in 2025?
small model
↓
classification
small model
↓
query rewriting
embedding model
↓
retrieval
reranker
↓
relevance
large model
↓
final reasoning
largest model everywhere
Розкладання запиту допомагає при багатоетапних запитах
Метод розкладання запитів ефективно працює на етапі розробки, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Віддавайте перевагу невеликим, тестованим одиницям перед величезними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на складну послідовність дій. Розділіть політику часткового оброблення даних від політики їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу, коли змінюються показники якості. Метод розкладання запитів ефективно працює на етапі розробки, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-версії до спільних середовищ.
Question 1:
Which European product had the largest decline?
Question 2:
What explanation did management provide for that product?
Complex Query
│
▼
Query Decomposer
/ \
/ \
▼ ▼
Subquery A Subquery B
│ │
▼ ▼
Retrieval Retrieval
\ /
\ /
▼ ▼
Evidence Join
│
▼
LLM
Свіжість змінює стратегію індексації
На етапі «Свіжість змінює індексацію» необхідно визначити вхідні дані, власника кроку та критерії завершення ще до змін у коді. Оператори повинні мати можливість перезапустити цей крок з відомої точки контролю, не намагаючись визначити прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, яке оператори можуть перевірити, не читаючи весь код. Необхідно наводити конкретні уривки тексту, на яких ґрунтується відповідь. Без посилань оператори не зможуть відрізнити галюцинації від прогалин у індексації.
Document updated
│
▼
new document version
│
▼
parse changed document
│
▼
generate new chunks
│
▼
embed
│
▼
write new index entries
│
▼
mark previous version inactive
document_id = D17
version 41 → status=inactive
version 42 → status=active
status = active
Версіонування моделей також має значення
На етапі «Версіонування моделей також має значення» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Необхідно документувати як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. У разі, коли наступним кроком є код або виклик інструменту, краще використовувати структуровані результати з перевіркою схеми, ніж вільний текст.
embedding_model
embedding_version
embedding_dimensions
chunking_version
parser_version
Documents
│
┌─────────┴─────────┐
▼ ▼
embedding model V3 embedding model V4
│ │
▼ ▼
Index V3 Index V4
│
▼
shadow traffic
│
▼
evaluate
│
▼
switch alias
Кешування має існувати на кількох рівнях
На етапі «Кешування має існувати» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру процесу. Наводьте уривки тексту, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням. На етапі «Кешування має існувати» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Чітке відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-версії до спільного середовища.
embedding
→ distributed retrieval
→ reranking
→ large LLM
User Query
│
▼
Exact Response Cache
│ miss
▼
Semantic Cache
│ miss
▼
Retrieval Cache
│ miss
▼
Search
hash(normalized_query)
↓
query embedding
Policy version 17
Policy version 18
Обробка несправностей має важливіше значення, ніж затримка у успішному сценарії
Під час роботи над етапом «Обробка несправностей має важливе значення» спочатку запишіть умови взаємодії: необхідні дані вхіду, сигнал про успіх та те, що відбувається при частковій несправності. Цей перелік допомагає зберігати чесність пізніших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Перед налаштуванням запитів вимірюйте рівень відтворення інформації на фіксованому наборі запитань. Зміна формулювань запитів рідко вирішує проблеми слабкої системи пошуку.
embedding provider unavailable
one vector shard unavailable
search cluster degraded
reranker timeout
LLM rate limited
LLM provider outage
queue backlog growing
parser crashing on malformed PDF
OCR worker running out of memory
Vector search fails
↓
Can lexical search answer?
↓
yes
↓
return degraded retrieval mode
Primary LLM unavailable
↓
Fallback model
↓
Lower quality but service continues
Document parser fails 5 times
↓
Dead-letter queue
↓
record failure reason
↓
operator / automated remediation
Зворотний тиск є необхідним
Під час роботи над етапом «Backpressure Is Essential» спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Одночасно задокументуйте шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Перед налаштуванням запитів вимірюйте рівень точності пошуку на фіксованому наборі запитань. Зміна запитів рідко допомагає вирішити проблеми з низькою якістю пошуку.
20M chunks/hour
25M chunks/hour
200M chunks/hour
embedding service overloaded
↓
timeouts
↓
retries
↓
more load
↓
more failures
↓
retry storm
incoming workload
↓
durable queue
↓
workers consume at safe rate
↓
backlog temporarily grows
Оперативність моніторингу має вимірювати якість пошуку
Під час роботи над етапом «Оперезорність має вимірюватися» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій. Перед налаштуванням запитів вимірюйте рівень відтворення інформації на фіксованому наборі запитань. Часта зміна формулювань запитів рідко виправляє проблеми з пошуком інформації. Під час роботи над етапом «Оперезорність має вимірюватися» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Поруч із функціональними результатами записуйте час виконання та витрати на токени або запити. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовищ до спільних середовищ.
HTTP 200 rate
CPU
memory
disk
p95 latency
error rate
requests/second
request_id: rq_912
query rewrite:
"parental policy?" → "parental leave policy"
vector retrieval:
200 candidates
145 ms
lexical retrieval:
200 candidates
91 ms
fusion:
278 unique candidates
reranking:
278 → 20
212 ms
context:
13 chunks
8,420 tokens
LLM:
input 9,104 tokens
output 681 tokens
1.8 sec
citations:
3 documents
total:
2.4 sec
Оцінюйте канал отримання даних окремо від LLM
Етап оцінки каналу отримання даних працює найкраще, коли його розглядають як вимірювану характеристику. Збережіть один ідеальний запис, один випадок збою та примітку про скасування дій перед розширенням обсягу роботи. Тримайте конфігурацію поза кодом додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Встановіть ліміт токенів на одну інтеракцію та на сеанс. Інструменти типу агентів активно розширюють контекст; жорсткі обмеження запобігають тому, що демонстрації перетворюються на несподівані рахунки.
Збої у отриманні даних
Етап виявлення невдач працює найкраще, коли його розглядають як вимірювану характеристику. Збережіть один ідеальний запис, один випадок невдачі та примітку про скасування змін перед розширенням обсягу. Документуйте як успішний, так і відновлювальний шляхи роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Розділіть політику часткової обробки даних від політики їх пошуку. Зміна однієї не повинна змушувати до переписування іншої при зміні показників якості.
Correct document exists
↓
retriever misses it
↓
LLM never sees it
↓
wrong answer
Невдача у генерації
Етап виявлення помилок у генерації працює найкраще, коли його розглядають як вимірювану характеристику. Збережіть один ідеальний запис, один випадок помилки та примітку про скасування змін перед розширенням обсягу роботи. Віддавайте перевагу невеликим, тестованим одиницям перед складними скриптами. Коли якась крок виконується неправильно, помилка має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Розділяйте політику часткової обробки даних та політику їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу, коли змінюються показники якості. Етап виявлення помилок у генерації працює найкраще, коли його розглядають як вимірювану характеристику. Збережіть один ідеальний запис, один випадок помилки та примітку про скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовищ до спільних середовищ.
correct evidence
↓
context
↓
LLM
↓
incorrect interpretation
Латентність має мати бюджет
Щоб зменшити затримку, необхідно спочатку визначити етапи виконання, вхідні дані, відповідального за кожен крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись визначити прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функціоналу мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Необхідно наводити конкретні уривки тексту, які лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням.
API + auth 50 ms
query understanding 100 ms
retrieval 300 ms
fusion 20 ms
reranking 250 ms
context construction 30 ms
LLM time-to-first-token 1,200 ms
network / safety margin 550 ms
-----------------------------------
target ~2,500 ms
Витрати також потребують однакового підходу
Для визначення витрат на ту саму стадію необхідно спочатку визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Необхідно документувати як шлях успішного виконання, так і шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Наводьте цитати з тих частин тексту, які фактично лежать в основі відповіді. Без цитат оператори не зможуть відрізнити галюцинації від проблем з індексуванням.
object storage
document parsing
OCR
embedding generation
vector storage
vector replicas
lexical search
metadata database
network transfer
reranking
LLM input tokens
LLM output tokens
observability
backups
cost / 1,000 indexed documents
cost / million chunks
cost / query
cost / successful answer
cost / tenant
Tenant A
5% of revenue
42% of LLM spend
Не зберігайте все у дорогому сховищі
На етапі «Не ставте все в одну купу» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру процесу. Наводьте ті уривки, які фактично лежать в основі відповіді. Без посилань оператори не зможуть відрізнити галюцинації від проблем з індексуванням. На етапі «Не ставте все в одну купу» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Чітке відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовищ до спільних.
>expensive / fast
▲
│
vector indexes
search indexes
Redis caches
│
metadata DB
│
object storage
│
▼
cheap / large
Гарячі та холодні дані можуть потребувати різного підходу
Під час роботи з етапом гарячих та холодних даних спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успішну обробку та наслідки часткової невдачі. Такий перелік допомагає зберігати чесність у подальших змінах коду. Зберігайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Перед налаштуванням запитів вимірюйте рівень відтворення інформації на фіксованому наборі запитань. Зміни запитів рідко допомагають покращити ефективність пошуку.
Last 30 days → 70% of queries
Last 12 months → 25%
Older archive → 5%
Query
│
├────→ Hot index
│
└────→ Archive index when necessary
Багатокористувацька архітектура все змінює
Під час роботи над етапом «Багатокористувацькість — це все змінює», спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Одночасно задокументуйте шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Перед налаштуванням запитів вимірюйте рівень відтворення інформації за фіксованим набором запитань. Зміна запитів рідко вирішує проблеми слабкої системи пошуку інформації.
10,000 organizations
10,000 completely independent vector clusters
Small tenants
↓
shared shard groups
Medium tenants
↓
partitioned shared infrastructure
Very large tenants
↓
dedicated shard groups
LLM має знаходитися ближче до кінця архітектури
Під час роботи над етапом «The LLL Should Be» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу невеликим, тестованим одиницям перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій. Зберігайте у кеші стабільні інструкції системи та схеми інструментів. Повторна передача ідентичних даних є поширеною причиною зайвих витрат. Під час роботи над етапом «The LLL Should Be» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Записуйте час виконання та витрати на токени або запити поруч із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-версії до спільних середовищ.
User
↓
API Gateway
↓
Authentication
↓
Authorization
↓
Rate Limiter
↓
Query Understanding
↓
Shard Routing
↓
Hybrid Candidate Retrieval
↓
Rank Fusion
↓
Reranker
↓
Deduplication
↓
Context Builder
↓
LLM
↓
Citation Validation
↓
Response
Повна архітектура продакшну
Етап «Повна архітектура продукції» функціонує найкраще, якщо його розглядати як вимірювану структуру. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь граф. Розділіть політику часткової обробки даних від політики їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.
CLIENTS
│
▼
┌──────────────┐
│ API Gateway │
└──────┬───────┘
│
┌──────▼───────┐
│ Auth / ACL │
│ Rate Limits │
└──────┬───────┘
│
▼
┌────────────────────┐
│ Query Orchestrator │
└─────────┬──────────┘
│
┌─────────────┼──────────────┐
│ │ │
▼ ▼ ▼
Cache Query Rewrite Metadata
Filters
│ │ │
└─────────────┼──────────────┘
▼
Shard Router
│
┌────────────┴────────────┐
▼ ▼
Lexical Search Vector Search
│ │
└───────────┬─────────────┘
▼
Rank Fusion
│
▼
Reranker
│
▼
Deduplicate
│
▼
Context Builder
│
▼
LLM
│
▼
Citation Validation
│
▼
RESPONSE
================================================================
INGESTION SYSTEM
Documents
│
▼
Object Store
│
▼
Event Queue
│
┌────────────┼────────────┐
▼ ▼ ▼
Parser Parser Parser
│ │ │
└────────────┼────────────┘
▼
Normalization
│
▼
Chunker
│
┌──────────────┴──────────────┐
▼ ▼
Embedding Queue Text Index Queue
│ │
┌─────┼─────┐ ▼
▼ ▼ ▼ Lexical Index
GPU GPU GPU
│ │ │
└─────┼─────┘
▼
Vector Index
================================================================
SUPPORTING SYSTEMS
Metadata DB → document state, versions, ownership
Object Storage → original source documents
Vector Cluster → semantic retrieval
Search Cluster → lexical retrieval
Redis → caches and rate limiting
Message Queue → asynchronous ingestion
Observability → traces, metrics, evaluation
Secrets / IAM → service authorization
Evaluation System → retrieval + answer-quality tests
Що ви не повинні робити
Підхід «Того, що не варто реалізовувати» найкраще функціонує, якщо його розглядати як вимірювану поверхню. Запишіть один ідеальний приклад роботи, один випадок збою та примітки щодо скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний сценарії роботи разом. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Розділіть політику часткової обробки даних від політики їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу при зміні показників якості.
One giant vector collection with no routing strategy
Synchronous PDF ingestion
Only vector retrieval, no lexical search
ACL filtering after retrieval
No document versioning
No embedding model version
No reranking
Sending top-100 chunks directly to the LLM
Using the LLM for every trivial classification task
No dead-letter queue
No retrieval-level evaluation
No tenant-level cost attribution
Treating the vector DB as permanent document storage
Re-embedding the entire corpus for every small content change
Benchmarking only average latency instead of tail latency
Основний принцип проектування
Етап Основного принципу проектування функціонує найкраще, коли його розглядають як вимірювану поверхню. Зафіксуйте один ідеальний зразок виконання, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Віддавайте перевагу невеликим, тестованим одиницям перед складними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Розділяйте політику часткового оброблення даних та політику їх отримання. Зміна однієї з них не повинна змушувати переписувати іншу, коли змінюються показники якості. Етап Основного принципу проектування функціонує найкраще, коли його розглядають як вимірювану поверхню. Зафіксуйте один ідеальний зразок виконання, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-версії до спільних середовищ.
question
→ vector search
→ LLM
billions of possible evidence units
↓
routing constraints
↓
relevant partitions
↓
cheap candidate search
↓
hundreds of items
↓
expensive reranking
↓
tens of passages
↓
context optimization
↓
LLM
↓
grounded answer
Cheap operation → huge search space
Moderate operation → smaller candidate set
Expensive operation → tiny candidate set
Most expensive model → final context only
Остаточні висновки
На етапі остаточного підсумку необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Наводьте уривки тексту, які фактично лягли в основу відповіді. Без посилань оператори не зможуть відрізнити галюцинацію від проблем із індексуванням.
Чек-лист для експлуатації
Під час роботи за чек-листом для експлуатації спочатку запишіть умови виконання: необхідні вхідні дані, сигнал про успіх та наслідки часткової невдачі. Цей чек-лист допомагає зберігати чесність подальших змін у коді.
Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Дайте назви кожним елементам, визначте критерії успіху та не погоджуйтесь на мовчазне часткове виконання завдань.
Вимірюйте рівень відтворення інформації за фіксованим набором запитань перед налаштуванням промптів. Часта зміна промптів рідко допомагає покращити слабкі механізми пошуку інформації.
Фіксуйте версії залежностей та записуйте дайджест зображень, які використовувалися під час демонстрації. Відтворюваність результатів краща за індивідуальні знання спеціалістів.
Записуйте час виконання та витрати на обробку токенів чи запитів разом із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним витратам під час переходу від демо-версії до спільних середовищ.
Вимірюйте рівень відтворення інформації за фіксованим набором запитань перед налаштуванням промптів. Часта зміна промптів рідко допомагає покращити слабкі механізми пошуку інформації.
Перш ніж запускати стек у продакшн, заморозьте версії, створіть «золотий» запис для критичного шляху та підтвердьте кроки відкату. У спільних середовищах необхідні обмеження швидкості, перевірки прав на використання та чіткий власник для зміни секретів. Віддавайте перевагу надійності перед креативними одноразовими демонстраціями.
Примітка до 1f03733b8d4b: не зберігайте ключі постачальника у репозиторії, встановіть ліміт токенів на сеанс та зберігайте записи поруч із фікстурами для оцінки, щоб подальша заміна моделей залишалася порівнянною.