Що таке RAG?
RAG (Retrieval-Augmented Generation) — техніка, за якої LLM перед генерацією відповіді спочатку шукає релевантні фрагменти в базі знань. Це дозволяє моделі точно відповідати на запитання про ваші документи, не вимагаючи додаткового навчання.
Компоненти RAG-системи
- Завантажувачі документів — PDF, DOCX, TXT, веб-сторінки
- Text Splitter — розбивка на чанки (500-1000 токенів)
- Embedding модель — перетворення тексту у вектори
- Векторна БД — Chroma, Qdrant, FAISS
- LLM — генерація відповіді на основі знайденого контексту
Встановлення залежностей
pip install langchain langchain-ollama langchain-community
pip install chromadb pypdf sentence-transformers Повний приклад RAG на Python
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OllamaEmbeddings
from langchain_ollama import OllamaLLM
from langchain.chains import RetrievalQA
# Завантаження і розбиття документа
loader = PyPDFLoader("document.pdf")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)
# Створення векторної бази
embeddings = OllamaEmbeddings(model="nomic-embed-text")
db = Chroma.from_documents(chunks, embeddings, persist_directory="./chroma_db")
# RAG-ланцюжок
llm = OllamaLLM(model="llama3.2")
qa = RetrievalQA.from_chain_type(llm=llm, retriever=db.as_retriever())
result = qa.invoke("Яка головна тема документа?")
print(result["result"]) Embedding моделі для Ollama
# Завантажити спеціалізовану модель для ембеддингів
ollama pull nomic-embed-text
# Або англійський варіант
ollama pull mxbai-embed-large Часті помилки RAG-систем
Більшість проблем з RAG не в коді, а в якості добування — модель відповідає не з контексту, тому що контекст спочатку знайдено неправильно.
Модель відповідає повз контекст, хоча потрібний фрагмент є в базі
Часта причина — промпт не змушує модель спиратися саме на знайдені чанки: вона відповідає із загальних знань, якщо явно не вказати "відповідай лише на основі наведеного контексту, і якщо відповіді там немає — скажи, що не знаєш". Друга причина — retriever повертає замало чанків (k=1-2), і потрібний фрагмент просто не потрапив у вибірку.
Dimension mismatch під час додавання документів у Chroma
chromadb.errors.InvalidDimensionException: Embedding dimension 768 does not match collection dimensionality 1024 Ця помилка виникає, якщо в ту саму колекцію Chroma додавали ембеддинги, згенеровані різними моделями — у них різна розмірність вектора. Рішення — використовувати одну embedding-модель протягом усього життя колекції або створювати окрему колекцію при зміні моделі.
Chroma, Qdrant і FAISS: порівняння
| Критерій | Chroma | Qdrant | FAISS |
|---|---|---|---|
| Запуск | Вбудований, без сервера | Окремий сервер або Docker | Бібліотека, без сервера |
| Персистентність із коробки | Так | Так | Потрібно зберігати індекс вручну |
| Фільтрація за метаданими | Базова | Просунута | Відсутня |
| Підходить для | Прототипів і невеликих баз | Продакшену з великим обсягом | Максимальної швидкості пошуку в пам'яті |
Коли RAG не підходить
- Документів мало, і вони цілком вміщуються в контекстне вікно моделі — простіше передати весь текст у промпт, без векторної БД.
- Дані оновлюються майже в реальному часі — доведеться постійно переіндексувати чанки, і свіжість відповіді все одно відставатиме.
- Потрібні точні обчислення або агрегація по всіх документах одразу — RAG знаходить схожі фрагменти, а не рахує суми і не порівнює всі записи.
- Питання користувачів вимагають міркувань по всій базі, а не по окремих фрагментах — тут ближче повнотекстовий аналіз або SQL-запит, а не пошук за векторами.
Перевірка якості пошуку
results = db.similarity_search_with_score("тестове питання з вашої бази", k=3)
for doc, score in results:
print(score, doc.page_content[:100]) Запустіть пошук із заздалегідь відомим питанням, відповідь на яке точно є в документах, і перевірте, що потрібний чанк опинився серед перших за релевантністю. Якщо він є в базі, але не потрапляє в top-k, варто зменшити розмір чанка або збільшити k, перш ніж змінювати модель ембеддингів.
Ще один нюанс — оновлення документів у базі. Якщо вихідний файл змінився, просте повторне додавання чанків у ту саму колекцію Chroma створить дублікати, а не замінить старі версії. Перед повторною індексацією варто або видаляти чанки з попереднім ідентифікатором джерела, або створювати окрему колекцію на кожну версію документа і явно перемикати retriever на актуальну.