У Confluence 1200 сторінок, пів сотні авторів — ніхто не пам'ятає, де лежить інструкція по VPN. Співробітники витрачають в середньому 20 хвилин на пошук, а частіше перепитують в чатах. Keyword-пошук видає список статей без розуміння контексту. RAG-система змінює це: ви задаєте питання — отримуєте відповідь з цитатами за 10 секунд. Ми розробляємо такі системи більше 5 років і впровадили 15+ проєктів. Середня економія склала $1 500 на місяць, а окупність — 4 місяці. Для одного клієнта економія досягла $15 000 на рік за рахунок скорочення часу інженерів.
Як працює семантичний пошук?
Збірка індексу на LlamaIndex з Qdrant в якості векторного стора та моделлю ембедінґів HuggingFace. Документи розбиваються на чанки, векторизуються і зберігаються в векторній БД. За запитом шукаються семантично близькі чанки, реранжуються cross-encoder моделлю, і LLM генерує фінальну відповідь з цитатами. Для російсько-англійських баз використовуємо multilingual-e5-large (1024d) — він дає на 15% більше recall, ніж BGE-small. Джерело: документація LlamaIndex. Ось ключовий фрагмент коду:
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader from llama_index.core.node_parser import SentenceSplitter from llama_index.core.retrievers import VectorIndexRetriever from llama_index.core.query_engine import RetrieverQueryEngine from llama_index.core.postprocessor import SentenceTransformerRerank from llama_index.vector_stores.qdrant import QdrantVectorStore from llama_index.embeddings.huggingface import HuggingFaceEmbedding import qdrant_client embed_model = HuggingFaceEmbedding( model_name="intfloat/multilingual-e5-large", embed_batch_size=32 ) splitter = SentenceSplitter( chunk_size=512, chunk_overlap=64, paragraph_separator="\n\n" ) reranker = SentenceTransformerRerank( model="cross-encoder/ms-marco-MiniLM-L-6-v2", top_n=5 ) client = qdrant_client.QdrantClient(url="http://localhost:6333") vector_store = QdrantVectorStore(client=client, collection_name="kb_docs") index = VectorStoreIndex.from_vector_store( vector_store=vector_store, embed_model=embed_model ) query_engine = RetrieverQueryEngine( retriever=VectorIndexRetriever(index=index, similarity_top_k=15), node_postprocessors=[reranker], ) Чому parent-child chunking необхідний?
Документація ієрархічна: розділ, підрозділ, параграф. Наївний чанкінг по 512 токенів розрізає логічні блоки. Рішення — parent-child chunking: дрібні чанки для пошуку, великі для контексту. Це дає faithfulness +12% та relevance +18% у порівнянні з flat chunking.
| Параметр | Flat chunking | Parent-child chunking |
|---|---|---|
| Faithfulness (RAGAS) | 0.68 | 0.76 |
| Relevance (RAGAS) | 0.72 | 0.85 |
Як налаштувати інкрементальне оновлення?
Ключові кроки налаштування RAG-пайплайну
- Зберіть список усіх джерел (Confluence, Notion, Google Docs).
- Виберіть модель ембедінґів (multilingual-e5-large для російської+англійської).
- Налаштуйте parent-child chunking з розміром parent=1024 токенів, child=256.
- Розгорніть векторну БД (Qdrant або pgvector).
- Реалізуйте інкрементальний збирач змін за API.
- Підключіть реранкер (cross-encoder) для підвищення точності.
- Інтегруйте LLM (GPT-4o або Claude) для генерації відповідей.
class DocumentationIndexer: def __init__(self, confluence_client, vector_store): self.confluence = confluence_client self.index = vector_store self.last_indexed = {} async def incremental_update(self): all_pages = self.confluence.get_all_pages(space_key="KB") for page in all_pages: page_id = page["id"] modified = page["version"]["when"] if self.last_indexed.get(page_id) == modified: continue self.index.delete(filter={"page_id": page_id}) content = self.confluence.get_page_body(page_id) nodes = self._parse_and_chunk(content, page) self.index.add(nodes) self.last_indexed[page_id] = modified return {"updated": len([p for p in all_pages if self.last_indexed.get(p["id"]) != p["version"]["when"]])} Інкрементальне оновлення виконується раз на годину, що гарантує актуальність без переіндексації всього корпусу.
Процес роботи
| Етап | Тривалість | Що робимо | Результат |
|---|---|---|---|
| Аналітика | 1–2 дні | Аналізуємо структуру документації, типи документів, частоту запитів | Технічне завдання та прототип на 10–20 документах |
| Проєктування | 2–3 дні | Вибираємо модель ембедінґів, векторну базу, схему чанкінгу | Документ архітектури рішення |
| Реалізація | 1–4 тижні | Розробляємо пайплайн індексації, конфігуруємо ретрівер та LLM, інтегруємо з Confluence/Notion та Slack | Працююча система на тестовому наборі |
| Тестування | 3–5 днів | Оцінюємо за RAGAS (faithfulness, relevance, precision), проводимо A/B тест | Звіт з метриками та рекомендації |
| Розгортання | 2–3 дні | Розгортаємо на інфраструктурі клієнта, налаштовуємо CI/CD | Продуктивний контур, документація адміністратора |
Що входить в роботу
- Документ архітектури рішення з обґрунтуванням вибору моделі та векторної бази.
- Пайплайн індексації з parent-child chanking та інкрементальним оновленням.
- Інтеграція з Confluence, Notion або Google Docs через API.
- Slack-бот або веб-інтерфейс для запитів з цитуванням джерел.
- Адміністративна панель для моніторингу запитів та метрик (RAGAS).
- Документація адміністратора та навчання команди (2 години).
- Підтримка протягом 1 місяця після запуску.
Типові помилки
- Ігнорування ієрархії документів. Parent-child chunking обов'язковий — інакше втрачаєте до 18% relevance.
- Рідке оновлення індексу. Налаштуйте інкрементальний пайплайн раз на годину.
- Вибір слабкої моделі ембедінґів. Для російсько-англійської документації multilingual-e5-large (1024d) або BGE-M3 — мінімум. BGE-small втрачає 15% recall.
- Відсутність реранкера. Без cross-encoder точність топ-3 падає на 10–20%.
- Нехтування безпекою. Налаштуйте фільтрацію prompt injection та аудит запитів.
Кейс: IT-компанія, 200 осіб, 1200 статей. Середній час відповіді — 1,4 сек, accuracy 82%. Кількість повторних питань у #general впала на 43% за перший місяць. Проєкт окупився за 4 місяці — середня економія $12 000 на рік.
Зв'яжіться з нами для оцінки вашого проєкту. Отримайте консультацію з впровадження RAG-пошуку на ваших даних. Замовте демо-доступ до готової системи на тестовому наборі документів.







