Главная / Статьи / Практические заметки: проектирование RAG для 100 миллионов документов

Практические заметки: проектирование RAG для 100 миллионов документов

Пошаговое руководство по практическим заметкам: проектирование RAG для 100 миллионов документов: контракты, проверки и слоты для кода для команд, использующих эту схему.

5618 слов

Используйте это как переработанную версию идей из книги «Проектирование RAG для 100 миллионов документов», ориентированную на операторов: четкие этапы, упорядоченные блоки кода и записи о восстановлении, сохраняющиеся при передаче задач. Этап обзора работает наилучшим образом, если рассматривать его как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отображение стоимости на ранних этапах предотвращает неожиданные счета при переходе от демо-версии к общедоступным средам.

Вот требования:

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

Начните с математики

На этапе «Начнем с математики» необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Необходимо одновременно задокументировать успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не этапом последующей доработки. Указывайте те фрагменты текста, которые легли в основу ответа. Без цитат операторы не смогут отличить галлюцинации от проблем с индексацией.

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

При работе над этим этапом сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист помогает сохранять честность последующих изменений в коде. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, которое операторы могут проверять, не читая весь код. Храните в кэше стабильные инструкции системы и схемы инструментов. Пересылка одинакового преамбула — распространенная причина износа ресурсов.

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

Обратное давление необходимо

При работе над этапом «Обратное давление — неотъемлемый элемент» сначала запишите условия работы: требуемые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Документируйте одновременно успешный сценарий работы и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не элементами последующей доработки. Измеряйте точность восстановления данных на фиксированном наборе вопросов перед настройкой подсказок. Частая смена подсказок редко помогает улучшить качество поиска.

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