Практычныя прытамулкі: Масштабаванне RAG да 10 мільйонаў дакументаў, частка 2: Оптымізаванне
Практычныя прыказкі: Масштабаванне RAG да 10 мільйонаў дакументаў, частка 2: Оптымізацыя – кантракты, перакрычанні та слоты для коду для команд, якія викорыстоўваюць гэты патэрн.
Існавайце гэта як перапрацоўаны варыянт ідэй з матеріалу “Scaling RAG to 10 Million Documents Part 2: Optimizing retrieval and generation”, адпрацаваны для працовнікаў: чыткія этапы, аранжаваныя блакіт коду і прыметкі з восстанавлення, якія застаюцца пасля перадачы задання. Этап Аналізу работае наяўней калі яго розглядаць як мерыябельную плошчу. Запісаце адну ідеальную транскрыпцыю, адзін прыклад неудачы і прыметкі з вярнення да пачатковага стану прычаму расшырэння масштаба. Разглядайце гэты этап як кантракт межа вхіднымі дадзеннямі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, задаце критэрыя успеху і не падтрымайце беззвучнае частковае завершэння задання.
1. Багатоэтапны фанель адзысквання
Для першага багатаступенчатага процеса адгукавання неабяжна прадзеявіць вхідныя даны, адпаведнага адпаведальніка за шаг і крэтыяры завершэння пры перадзеяванні коду. Аператары должны магчымаць перапрацаваць шаг з вядомай точкі контролю, не падозрываючы прыхованы стан. Зявіць вачэнне часу выконання і косту токена або запыту праза функцыйнальных рэзультатаў. Вачэнне коста з самага пачатку запобегае неспадзяваным рахункам, калі парадокс пераходзіць з дэмовай среды ў спяльнаваныя сераўы. Указаць часткі тексту, якія фактычна сталі падставай для адпаведзь. Без цых цытатаў аператары не можуць разлічыць галюцинацію ад прасоўкі ў індэксаванні.
[ 10,000,000 Total Document Chunks ]
│
▼
[ Step 1: SQL Pre-Filter ] ────────► Filter by Tenant / Dept / Role / Region
│
▼
[ ~50,000 Candidates ]
│
▼
[ Step 2: Hybrid Search ] ─────────► Dense Vectors (Qdrant) + Sparse BM25
│
▼
[ Top 100 Candidates ]
│
▼
[ Step 3: Cross-Encoder ] ───────► Cohere Rerank / BGE-Reranker
│
▼
[ Final Top 5 Chunks ] ──────────► Passed to LLM Context Window
Стэп 1: Реляцыйскі прадзеявальны фільтраў (жорсткія абмежэння)
Для стадії прадзержання на асоцыяцыйных звязках 1-й стадіі неабходна прадзефармаванне: перш чым зменяць код, неабходна адзначыць вхідныя даны, адпаведальнага за шаг і крэтыры завершэння. Аперацыйныя працавнікі должны магчымасць перзапуск шагу з вядомай точкі контролю, не падозрываючы прыхованы стан. Конфігурацыю трэба захаваць пазначыцельна ад коду прыемліка. Файлы сераўнавання, храненні секрэтных данных і флагі функций должны знаходзіцца ў аднам месцы, якое працавнікі можуць пераглядаць, не чытаючы весь граф. Неабходна цітаваць тыя часткі, якія фактычна ляглі в основу адпаведнай адказы. Без цітатаў працавнікі не можуць адразліць галюцинацыю ад прасоўкі ў індэксаванні.
from qdrant_client.models import Filter, FieldCondition, MatchValue
# Restrict search space by user session permissions before distance scoring
user_access_filter = Filter(
must=[
FieldCondition(key="department", match=MatchValue(value="Engineering")),
FieldCondition(key="is_active", match=MatchValue(value=True))
]
)
Стадія 2: Гібрыдны пошук (Жыцкаснае + Рэдкое з’еднанне)
Для стадії гібрантнага пошуку 2-го ўрадзу неабходна яшчэ перад змянай коду адзначыць вхідныя даны, адпаведальнага за этап і крэтыры завершэння. Аперацыяныя працавнікі павінны магчымаецца перазапускаць этап з вядомага пункта контролю, не спрабоўваючы здагадвацца пра захаваны стан. Неабходна аддзекластыць як шлях успеху, так і шлях вярнення да нормальнага стану. Перапрыбуткі, пераказы людзей і обробка некоректных паведамленняў ёсць часткай продукту, а не чымось, што дадаецца пазней. Паказваць трэба тыя часткі тексту, якія фактычна служылі падставай для адпаведнага адказу. Без ціх цытатаў аперацыяныя працавнікі не зможуць адразліць галюцинацыю ад прасоў у індэксаванні. Для стадії гібрантнага пошуку 2-го ўрадзу неабходна яшчэ перад змянай коду адзначыць вхідныя даны, адпаведальнага за этап і крэтыры завершэння. Аперацыяныя працавнікі павінны магчымаецца перазапускаць этап з вядомага пункта контролю, не спрабоўваючы здагадвацца пра захаваны стан. Цю стадію трэба спрыяглядаць як кантракт межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Называць неабходныя дакументы, адзначыць крэтыры успеху і не прабаваць прыймать часткова завершаныя рэзультаты без паведамлення.
Этап 3: Переранкігаванне за допамогай Cross-Encoder
Калі працюеце над этапам переранкігавання за допамогай Cross-Encoder, спачатку запісаце крэтыну: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі список дапамагае заліцьваты змяны ў кодзе. Запісваце час выконання і кост токеноў або запытаў праза функцыйнае рэзультат. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмавай версіі ў спяльныя среды. Перад налаштаваннем запрошэнняў змераце рівень вярнага аднаходжэння на фіксаванай сэтке запытаў. Частае змяненне запрошэнняў рэдка калі-небудзь выправляе слабыя рэзультаты аднаходжэння інфармацыі.
2. Умовны рутэр запытаў
Калі працуеце над 2-м ўрадзом маршрутацыі запитаў з умовай, спачатку запісайце контракт: неабходныя даны, сігнал успеху і тое, што выходзіць на частым неудачам. Такі список пераканае ў тым, што пазнейшыя змены коду будуць чыстымі. Зберагаеце настройкі праза код аплікацыі. Файлы сераўнавання, хранілішча секрэтных дадзеных і флагі функцый крануцца ў аднам месцы, дзе аператары можаць аудытаваць іх, не чытаючы весь граф. Замерайце рэкалі на фіксаваным наборе запытанняў прычым регулюванні прамптав. Частае змена прамптав рэдка калі лячы слабую систему аднаходжання дадзеных.
User Query
│
▼
[ Intent Classifier / Router ]
│
├── Simple Math / Logic ──────────► Direct Calculator / Python REPL
├── Conversational / Follow-up ───► Direct LLM Memory Context
└── Domain Knowledge Request ─────► Full Hybrid RAG Pipeline
# Conceptual Router Pattern
def route_query(user_query: str) -> str:
prompt = f"""Classify the user query into one of these routes:
- RETRIEVE: Needs internal company documentation/database lookup.
- COMPUTE: Pure math, calculation, or logic.
- DIRECT: Conversational, greetings, or basic language rewrites.
Query: {user_query}
Classification:"""
# Run a fast, lightweight classifier (or small local SLM)
decision = fast_classifier(prompt).strip()
return decision
3. За межамі простага RAG: оркестрацыя калькоў агентаў і ціклы зворотнай свярзкі
Калі працуеце над 3-й стадзіяю «Beyond simple RAG», спачатку запісайце угоду: неабяжлівыя данні, сигнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі список контроля дапамагае заліцьварыць пазнейшыя змены ў кодзе. Документавайце як шлях успеху, так і шлях вярнення да нормы. Перапрыбуткі, людзкія перакрыцця і обробка некоректных паведамленняў ёсць часткаю продукту, а не пазнейшым дапрацоўкам. Змяржывайце рэкалі на фіксаваным наборы пытанняў прычым регулюванні запрошэнняў. Частае змены запрошэнняў рэдка калі вялікі эфект на слабую систему пошуку. Калі працуеце над 3-й стадзіяю «Beyond simple RAG», спачатку запісайце угоду: неабяжлівыя данні, сигнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі список контроля дапамагае заліцьварыць пазнейшыя змены ў кодзе. Спрэцаваўце гэтую стадзію як угоду межа даннімі і перакананымі выходамі. Дайце назвы элементам, задаце критэрыя успеху і адмовіцеся ад мовчанкавага частковага завершэння.
[ Orchestrator / Planner ]
│
┌─────────────────┴─────────────────┐
▼ ▼
[ Researcher Agent ] [ Compliance Agent ]
• Retrieves 2025 Sales Data • Retrieves 2024 Regulations
• Extracts regional tables • Parses policy constraints
│ │
└─────────────────┬─────────────────┘
▼
[ Synthesis Agent ]
• Reconciles numbers
• Validates output consistency
│
Confidence Score Check
│ │
[ Low Confidence ] [ High Confidence ]
│ │
▼ ▼
Loop back & refine Final Guardrail Validation
Самакорэкцыя і ціклы зворотнага зв’язку
Этап цыклаў зворотнага звязку для самакорэкцыі працуе наўжоўшы, калі яго спрыяваць як вимерную паверхню. Зафіксавайце адна ідеальная транскрыпцыю, адзін прыклад неудачы і прыметку па адкату перш чым расширваць масштаб. Запісвайце часы выканання і кост токеноў або запытаў па боку функцыйнаых рэзультатаў. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі процес пераходзіць з дэмаверсіі ў спяльныя среды. Раздзеліце правілы часткавання дадзеных ад правілаў ўзяць іх. Змена аднаго з іх не должна прымусіваць перапісванне другога, калі змянююцца паказнікі якосці.
4. Настаўнай ацэнка
Этап 4 – адыяктная ацэнка – працюе наўзяй калі яго спрыяваць як мерыемую паверхню. Зберагуце адны ідеальны прыклад, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваце сферу дзейнасці. Храніце настройкі парадульна ад коду прыемліка. Файлы сяродавішча, хранільнікі секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавляць контроль без неабяжнага чытання всіх дадзеных. Раздзеляйце політыку часткавання дадзеных ад політыки ўзяць іх. Змена адной з яных не должна вымагаць перапісву другой, калі зменяюцыся паказнікі якосці.
┌──► Faithfulness (Is the answer grounded in the retrieved chunks?)
RAG Evaluation ─┼──► Answer Relevance (Did it actually answer the user's prompt?)
├──► Context Recall (Did retrieval find all necessary reference chunks?)
└──► System Latency & Token Cost (Is it cost-effective at scale?)
6. Практычны падход «з начала да канца»: Полны працэс адзыскві і стварэння
Этап «6 End-to-End Hands-On» працюе найкраща, калі яго спрыяваць як меравальную паверхню. Зафіксавце адны ідеальны прыклад роботы, адны прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваце сферу дзейнасці. Дакументавце як шлях успеху, так і шлях вярнэння да нормальнага стану. Перапрыбуткі, людзкія контраліны і обработка некоректных паведамленняў ёсць часткай продукту, а не чымось, што дадаецца пазней. Раздзеліце політыку часткавай обработкы дадзеных ад політыки ўтрымання іх. Змена адной з яных не должна вымагаць перапісвання другой, калі зменяюцца паказнікі якосці. Этап «6 End-to-End Hands-On» працюе найкраща, калі яго спрыяваць як меравальную паверхню. Зафіксавце адны ідеальны прыклад роботы, адны прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваце сферу дзейнасці. Спрыявайце гэты этап як кантракт межа вхіднымі дадзенымі і перакананымі выхіднымі рэзультатамі. Даўце назвы артыфактам, задаце критэрыя успеху і не прабывайце прыймаць часткова завершаныя рэзультаты без паведамлення.
from openai import OpenAI
from qdrant_client import QdrantClient
from qdrant_client.models import Filter, FieldCondition, MatchValue
# 1. Initialize Clients
# Pointing to local LM Studio running on port 8080
ai_client = OpenAI(base_url="http://127.0.0.1:8080/v1", api_key="lm-studio")
qdrant_client = QdrantClient(url="http://localhost:6333")
COLLECTION_NAME = "enterprise_knowledge_base"
EMBEDDING_MODEL = "nomic-ai/nomic-embed-text-v1.5"
def retrieve_and_generate(user_query: str, user_department: str) -> str:
print(f"\n🔍 Processing query: \"{user_query}\" for department: [{user_department}]")
# 2. Vectorize the User Query
query_resp = ai_client.embeddings.create(
input=[user_query],
model=EMBEDDING_MODEL
)
query_vector = query_resp.data[0].embedding
# 3. Stage 1 & 2: SQL Pre-Filter + Vector Search
# Filter by user department and active document status
access_filter = Filter(
must=[
FieldCondition(key="department", match=MatchValue(value=user_department))
]
)
search_results = qdrant_client.search(
collection_name=COLLECTION_NAME,
query_vector=query_vector,
query_filter=access_filter,
limit=3
)
if not search_results:
return "No relevant or authorized documents found."
# 4. Context Assembly with Breadcrumbs
context_blocks = []
for hit in search_results:
breadcrumb = hit.payload.get("breadcrumb", "General")
text = hit.payload.get("text", "")
context_blocks.append(f"[{breadcrumb}]\n{text}")
full_context = "\n\n---\n\n".join(context_blocks)
# 5. Generation via Local LLM
system_prompt = (
"You are an enterprise technical assistant. "
"Answer the user query strictly using the provided context. "
"If the context does not contain the answer, explicitly state that you do not know.\n\n"
f"Context:\n{full_context}"
)
completion = ai_client.chat.completions.create(
model="local-model",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_query}
],
temperature=0.1
)
return completion.choices[0].message.content
# Example Execution
if __name__ == "__main__":
response = retrieve_and_generate(
user_query="How do I enable TLS 1.3 in config.yaml?",
user_department="Engineering"
)
print("\n🤖 Final Answer:\n", response)
Вывад: Архітектура RAG у працэйнай среды
Для заключнага падзеўкі стадіі RAG-вырабоцтва неабходна пазначыць вхідныя даны, адпаведальнага за крок і критэрыя завершэння пры перадзмене коду. Аперацыйныя працавнікі должны магчымае перайсці на гэты крок з вядомага пункта контролю, не спрабоўваючы з’ясаваць захаваны стан. Запісваюць час выконання і кост токеноў або запытаў разам з функцыйнымі рэзультатамі. Відразлівае паказанне костаў запобегае неспадзяваным рахункам, калі процес пераходзіць з дэмовай среды ў спадзеленую. Наводзіць урывкі, якія фактычна сталі падставай для адпаведнага адказу. Без ціх цитатаў аперацыйныя працавнікі не можуць разлічыць галюцинацію ад прасоў у індэксаванні.
Чек-ліст для аперацый
Працюючы над чек-лістам для аперацый, спачатку запісваюць умовы: неабходныя вхідныя даны, сігнал успеху і тое, што выходзіць пад час частковага абэранця. Гэты чек-ліст дапамагае заставаць празкідванні коду чыстымі.
Лепшыя маленькія, тэставаныя елементы, чым велікія скрыпты. Калі якісь крок не выйшаў, адказ за гэта павінен быць прысвечаны адзіной адпаведальнасці, а не заплутанай лянцюговой структуре.
Перад налаштаваннем запитоў трэба пераканацца ў робочым стане на фіксаванай сэтке запитаў. Частыя змены запітоў рэдка калі вядуць да павышэння якосці выкарыстоўвання інформацыі.
Перш чым зменяць запіты або моделі, трэба зафіксаваць нынешню версію як „золатую“. Змена як системы, так і критэрыяў оценкі можа маскаваць падышэння якосці.
Калі бюджет дазволяе, трэба дадаць тэст на перакананне ў робочым стане критычнай лянцюговой структуры ў процесе CI, выкарыстоўваючы фіксаты, а не рэальныя платныя API.
Канфігурацыю трэба знаходзіць паза кодам прыкладнага програму. Файлы сяродавішча, хранільнікі секрэтных дадзеных і флагі функций павінны быць у аднам месца, якое аператары можаць пераглядаць без неабяжнага чытання всіх элементаў системы.
Перш чым запускать стак, заморозьце версіі, зафіксавце «золаты» транскрыпты для критычнага шляху і паказайце способы абяроны. У спільных средах неабходны ліміты частоты запытанняў, пераконтрольванне прав на выкарыстоўвання ресурсаў і чысткі власнік для змены секрэтных даных. Лепш выбіраць простую надзею на надзейнасць, чым хітрыя експерыментальныя дэманстрацыі.
Прыметкі для c42ae29c43bc: не кладзіце ключы прадаўцаў у репазітарый, задаце ліміт токенаў на кожную сесію і зберагачыце транскрыпты празаўседы ў фіксатыях для ацэнкі, каб пазнейшыя замены моделяў заставаліся порównаннэй.