Базова реалізація RAG: покроковий посібник
Цей посібник для початківців пояснює, як працює базова реалізація RAG, розглядає найкращі практики й крок за кроком показує, як створити робочу систему RAG для командного рядка за допомогою Python, ChromaDB, а також моделей ембедингів і мовних моделей Perplexity.

RAG — важливий компонент сучасної інфраструктури на основі LLM. Надаючи моделям ШІ доступ до зовнішніх даних, він допомагає розв’язувати такі проблеми, як галюцинації та неповнота навчальних даних. Крім того, завдяки йому компанії можуть використовувати внутрішні бази знань, що містять конфіденційну або службову інформацію.
Реалізація RAG може бути дуже складною. Проте базову систему RAG напрочуд легко створити. Для початківців побудова простої архітектури допоможе зрозуміти, як RAG працює в реальних умовах, і стане відправною точкою для подальших експериментів.
У цій статті ми окреслимо базову реалізацію RAG, розглянемо найкращі практики, а потім створимо робочу систему за допомогою Python, ChromaDB і двох моделей Perplexity — для створення ембедингів і генерування відповідей.
Процес базової реалізації RAG: загальний огляд
Базова система RAG має три основні компоненти: оркестратор, джерело інформації та LLM. У типовому робочому процесі користувач вводить промпт, а оркестратор змінює його, щоб виконати пошук у під’єднаних джерелах інформації. Потім знайдену інформацію додають до початкового вхідного контексту й надсилають LLM, щоб згенерувати відповідь.
Під час створення реалізації RAG потрібно врахувати такі етапи:
- Індексування та створення ембедингів: На цьому етапі ваші документи перетворюються на джерело інформації, у якому оркестратор може виконувати пошук. Один із найпоширеніших способів зробити це — побудувати векторний індекс із можливістю пошуку. Ми використаємо спеціальну модель від Perplexity, щоб перетворити фрагменти ваших документів на ембединги. Потім збережемо ембединги в ChromaDB — популярній векторній базі даних з відкритим кодом.
- Оркестрація: Це застосунок, який розташований між зовнішнім джерелом інформації (у нашому випадку — векторною базою даних) і LLM. Ми створимо простий скрипт на Python, який виконуватиме роль оркестратора.
- Отримання та генерування: Коли користувач ставить запитання через інтерфейс чату, оркестратор приймає його, виконує векторний пошук і передає розширені вхідні дані LLM. Замість створення окремого фронтенду ми використовуватимемо командний рядок, щоб надсилати промпти нашому оркестратору на Python.
Найкращі практики: що робить реалізацію RAG ефективною?
Існує кілька типів архітектури RAG, і різні сценарії використання потребують різних підходів. Водночас низка найкращих практик застосовна в усіх випадках і забезпечує точність, економічну ефективність, масштабованість і зручність підтримки систем.
Наведені нижче найкращі практики стосуються всіх типів реалізації RAG:
- Забезпечте чистий конвеєр завантаження даних: Перед індексуванням вихідні дані мають бути максимально чистими. Також слід використовувати модель ембедингів, яка підходить для вашого контенту.
- Використовуйте гібридний пошук: Найкращі методи отримання даних — чи то пошук у векторній базі даних, вебпошук через API, обхід графа знань, пошук за ключовими словами чи інші методи — залежать від сценарію використання. Правильне поєднання методів важливе для мінімізації витрат.
- Оцінюйте свою систему: Після впровадження слід оцінити систему за трьома ключовими показниками: точність, релевантність і затримка. Точність означає фактичну правильність, релевантність — доречність отриманої інформації щодо запитів користувачів, а затримка — швидкість, з якою інформація отримується.
- Безпечно поводьтеся з інформацією: Якщо ваша система RAG використовує приватну внутрішню інформацію, переконайтеся, що вона зберігається безпечно, а доступ до інтерфейсу системи контролюється. Ніколи нікому не передавайте ключі API.
Базова реалізація RAG: посібник із 7 кроків
У цьому посібнику ми створимо застосунок для командного рядка, який відповідає на запитання щодо одного документа. Ми використаємо Python, ChromaDB і Perplexity API.
Мета — не створити готову до продакшену систему RAG. Це радше посібник для початківців, який показує, як елементарна архітектура RAG працює на практиці.
Крок 1: встановіть програмне забезпечення
Переконайтеся, що на вашому комп’ютері встановлено наведене нижче програмне забезпечення і у вас є обліковий запис Perplexity API:
- Python: Це мова програмування, за допомогою якої ми створимо оркестратор, що координуватиме потік даних між моделлю ембедингів, ChromaDB і Perplexity.
- Visual Studio: Ми використовуватимемо Visual Studio як редактор коду. Після встановлення відкрийте панель Extensions і завантажте розширення Python.
- Обліковий запис Perplexity API: Perplexity надасть як модель ембедингів (яка перетворює ваші дані на векторні ембединги), так і LLM, що оброблятиме розширений промпт. Платний обліковий запис для цього не потрібен, хоча буде витрачено невелику кількість кредитів.
Крок 2: створіть папку проєкту
Спершу створіть папку з назвою rag-project і відкрийте її у VS Code, вибравши File > Open Folder. Потім відкрийте вбудований термінал через Terminal > New Terminal.
Введіть наведену нижче команду, щоб створити віртуальне середовище Python:
py -3.12 -m venv .venvТепер потрібно встановити чотири бібліотеки Python: perplexityai, chromadb, python-dotenv і numpy. Perplexity SDK дає змогу під’єднуватися до моделей Perplexity через API. ChromaDB створює векторну базу даних і працюватиме локально. Python-dotenv безпечно завантажує ваші ключі API з локального файлу, а NumPy потрібна під час завантаження даних.
Встановіть їх за допомогою такої команди:
.\.venv\Scripts\python.exe -m pip install perplexityai chromadb python-dotenv numpyКрок 3: налаштуйте файли
Додайте наведені нижче файли до rag-project (кореневої папки проєкту), вибравши New File… на бічній панелі Explorer:
- index.py: Це застосунок, який індексуватиме ваш документ. Ви можете запустити його повторно, щоб додати більше тексту.
- rag.py: Це застосунок на Python, який виконуватиме роль оркестратора.
- document.txt: Цей файл міститиме документацію, яку ви перетворите на векторну базу даних.
- .env: Тут зберігатиметься ваш ключ Perplexity API.
У файлі .env введіть таке:
PERPLEXITY_API_KEY=your_api_key_hereЗамініть your_api_key_here на свій справжній ключ. Для цього перейдіть на головну панель керування Perplexity API Console і виберіть Create an API key. Зберігайте цей ключ API в таємниці.
Ми використовуватимемо дві моделі: pplx-embed-v1-0.6b від Perplexity — для створення ембедингів документації перед завантаженням у ChromaDB, і GPT-5.6-Luna (з доступом через API Perplexity) — для обробки отриманої інформації.
Додайте у файл document.txt текст, який отримуватиме ваш конвеєр RAG. Якщо у вас немає під рукою документа, використайте для цього посібника збірку Вільяма Блейка Songs of Innocence and of Experience («Пісні невинності та досвіду») з Project Gutenberg. Це короткий і зрозумілий текст, що перебуває в суспільному надбанні.
Крок 4: напишіть програму для індексування
Скопіюйте наведений нижче код і вставте його в index.py. Кожен підзаголовок коротко пояснює, що робить наступний фрагмент коду. Ця програма перетворить ваші вихідні матеріали на векторні ембединги та збереже їх у базі даних ChromaDB за допомогою моделі ембедингів Perplexity pplx-embed-v1-0.6b і бібліотеки NumPy.
Ось що робить програма:
- Відкриває document.txt.
- Розбиває текст на фрагменти, що перекриваються.
- Надсилає ці фрагменти до моделі ембедингів Perplexity pplx-embed-v1-0.6b.
- Декодує й нормалізує отримані вектори за допомогою NumPy — бібліотеки обчислювальних функцій для Python.
- Зберігає вектори та вихідні фрагменти в базі даних ChromaDB (вона з’явиться в каталозі вашого проєкту).
Програму налаштовано так, щоб вона не індексувала документ повторно під час кожного запуску. Якщо ви додасте інформацію в document.txt, вона створить ембединги лише для нового тексту.
from pathlib import Path
from collections import defaultdict, deque
from hashlib import sha256
import base64
import numpy as np
import chromadb
from dotenv import load_dotenv
from perplexity import Perplexity
# 1. Connect to Perplexity and ChromaDB
load_dotenv()
ai = Perplexity()
db = chromadb.PersistentClient(path="./rag_database_perplexity")
collection = db.get_or_create_collection(
name="documents",
metadata={"hnsw:space": "cosine"}
)
# Convert Perplexity's encoded embeddings into numerical vectors
def decode_embedding(encoded):
vector = np.frombuffer(base64.b64decode(encoded), dtype=np.int8).astype(np.float32)
norm = np.linalg.norm(vector)
if norm == 0:
raise ValueError("Received a zero-length embedding vector.")
return (vector / norm).tolist()
# 2. Read the document and split it into chunks
text = Path("document.txt").read_text(encoding="utf-8")
words = text.split()
chunk_size = 180
overlap = 30
step = chunk_size - overlap
chunks = [" ".join(words[i:i + chunk_size]) for i in range(0, len(words), step)]
if not chunks:
raise ValueError("document.txt is empty.")
# 3. Retrieve the chunks already stored in ChromaDB
existing = collection.get(include=["documents"])
stored_chunks = defaultdict(deque)
existing_ids = set(existing["ids"])
for chunk_id, document in zip(existing["ids"], existing["documents"]):
stored_chunks[document].append(chunk_id)
# 4. Identify unchanged and new chunks
new_chunks = []
new_ids = []
kept_ids = set()
unchanged = 0
for chunk in chunks:
if stored_chunks[chunk]:
chunk_id = stored_chunks[chunk].popleft()
kept_ids.add(chunk_id)
unchanged += 1
else:
chunk_hash = sha256(chunk.encode("utf-8")).hexdigest()
chunk_id = f"chunk-{chunk_hash}"
suffix = 1
while chunk_id in existing_ids or chunk_id in kept_ids or chunk_id in new_ids:
chunk_id = f"chunk-{chunk_hash}-{suffix}"
suffix += 1
new_chunks.append(chunk)
new_ids.append(chunk_id)
kept_ids.add(chunk_id)
# 5. Generate embeddings in batches of up to 100 chunks
batch_size = 100
for i in range(0, len(new_chunks), batch_size):
batch_chunks = new_chunks[i:i + batch_size]
batch_ids = new_ids[i:i + batch_size]
embeddings = ai.embeddings.create(
model="pplx-embed-v1-0.6b",
input=batch_chunks,
encoding_format="base64_int8"
)
vectors = [decode_embedding(item.embedding) for item in embeddings.data]
# 6. Store each batch in ChromaDB
collection.upsert(
ids=batch_ids,
documents=batch_chunks,
embeddings=vectors
)
print(f"Indexed batch {(i // batch_size) + 1}")
# 7. Remove outdated chunks
old_ids = [chunk_id for chunk_id in existing["ids"] if chunk_id not in kept_ids]
if old_ids:
collection.delete(ids=old_ids)
# 8. Display indexing results
print("Indexing complete!")
print("Unchanged chunks:", unchanged)
print("New or modified chunks:", len(new_chunks))
print("Removed chunks:", len(old_ids))
print("Total stored chunks:", collection.count())Крок 5. Напишіть оркестратор для системи RAG
Скопіюйте наведений нижче код і вставте його в rag.py. Це повна, але мінімальна реалізація RAG, яка використовує Perplexity SDK і функціональність локальної векторної бази даних ChromaDB.
Ось що відбуватиметься, коли ви запустите програму:
- Під’єднується до Perplexity і вашої нової бази даних ChromaDB.
- Перевіряє, чи містить база даних проіндексовані документи.
- Приймає запитання від користувача.
- Надсилає запитання до моделі ембедингів Perplexity.
- Декодує й нормалізує отриманий ембединг за допомогою NumPy.
- Шукає в ChromaDB три найсхожіші фрагменти документа.
- Формує промпт, що містить отримані фрагменти та запитання користувача.
- Надсилає промпт моделі GPT-5.6 Luna через Agent API від Perplexity.
- Показує відповідь і чекає на наступне запитання.
import base64
import numpy as np
import chromadb
from dotenv import load_dotenv
from perplexity import Perplexity
# 1. Connect to Perplexity and the existing ChromaDB database
load_dotenv()
ai = Perplexity()
db = chromadb.PersistentClient(path="./rag_database_perplexity")
collection = db.get_collection("documents")
# Convert Perplexity's encoded embeddings into numerical vectors
def decode_embedding(encoded):
vector = np.frombuffer(base64.b64decode(encoded), dtype=np.int8).astype(np.float32)
norm = np.linalg.norm(vector)
if norm == 0:
raise ValueError("Received a zero-length embedding vector.")
return (vector / norm).tolist()
# 2. Check that the database contains indexed documents
count = collection.count()
if count == 0:
raise ValueError("The database is empty. Run index.py first.")
print("Connected to existing ChromaDB database.")
print("Stored chunks:", count)
# 3. Accept questions from the user
while True:
question = input("\nAsk a question (or type exit): ")
if question.lower().strip() == "exit":
break
if not question.strip():
continue
# 4. Convert the question into a Perplexity embedding
question_response = ai.embeddings.create(
model="pplx-embed-v1-0.6b",
input=[question],
encoding_format="base64_int8"
)
question_vector = decode_embedding(question_response.data[0].embedding)
# 5. Retrieve the most similar document chunks from ChromaDB
results = collection.query(
query_embeddings=[question_vector],
n_results=min(3, count)
)
context = "\n\n".join(results["documents"][0])
# 6. Construct a prompt and send it to the fixed LLM
response = ai.responses.create(
model="openai/gpt-5.6-luna",
instructions=(
"Answer using only the supplied document excerpts. "
"Do not use external information. "
"If the answer is not present, say you don't know."
),
input=f"Document excerpts:\n{context}\n\nQuestion: {question}"
)
# 7. Display the answer
print("\nAnswer:\n", response.output_text)Крок 6: запустіть застосунки
У терміналі PowerShell у VS Code введіть наведену нижче команду, щоб створити ембединги для вмісту document.txt:
.\.venv\Scripts\python.exe index.pyЯкщо документ успішно проіндексовано, ви побачите приблизно такий результат:
Indexing complete!
Unchanged chunks: 0
New or modified chunks: 58
Removed chunks: 0
Total stored chunks: 58Тепер настав час запустити основний застосунок-оркестратор. Введіть цю команду:
.\.venv\Scripts\python.exe rag.pyЯкщо запуск буде успішним, ви побачите таке:
Connected to existing ChromaDB database.
Stored chunks: 58
Ask a question (or type exit): Тепер ви можете ставити запитання, відповіді на які братимуться зі створеної вами векторної бази даних, наприклад:
Ask a question (or type exit): What animals does William Blake talk about?
Answer: The excerpts mention sheep, lambs, birds, beasts, wolves, tigers, and a lion.Крок 7: зрозумійте, що ви створили
Створена вами система містить два основні конвеєри, наявні в кожній архітектурі RAG: конвеєр індексування, або «завантаження даних», і конвеєр отримання та генерування.
Тепер ваша базова реалізація RAG виконує все перелічене нижче:
- Векторне зберігання: Ембединги, створені на основі вашого файлу знань, зберігаються в базі даних ChromaDB у вашому локальному середовищі.
- Інкрементне індексування: Для незмінених фрагментів документа ембединги повторно не створюються, а сам документ можна оновлювати будь-коли.
- Семантичний пошук: ChromaDB знаходить фрагменти на основі векторної подібності (за ініціативою оркестратора).
- Генерування обґрунтованих відповідей: LLM отримує знайдені уривки як контекст і використовує їх у відповіді.
- Незалежне індексування та виконання запитів: Ви можете ставити запитання, не обробляючи повторно весь текст, що міститься у вашому файлі знань.
- Під’єднання до моделі через API: Усі відповіді генеруються за допомогою GPT-5.6 Luna через Perplexity, а не моделлю, що працює на вашому комп’ютері.
Наступні кроки: як розвинути цю реалізацію
Мета цього посібника — створити просту базову реалізацію. Вона охоплює деякі ключові компоненти архітектури RAG, наявні в сучасних системах. Якщо ви хочете піти далі, є різні способи її розвинути.
Ось кілька ідей, як розширити можливості вашої реалізації:
- Поекспериментуйте з LangChain: LangChain — один із найпопулярніших фреймворків оркестрації з відкритим кодом. Він містить готові компоненти для створення застосунків, здатних запускати складні конвеєри RAG.
- Розширте можливості пошуку: Поєднайте щільний векторний пошук із лексичним пошуком (за ключовими словами), наприклад BM25. Додавання вебпошуку через Perplexity Search API також дасть змогу обґрунтовувати відповіді актуальними даними.
- Додайте модель переранжування: Інтегруйте модель переранжування, яка ранжує отримані уривки відносно початкового промпту й вибирає найрелевантніші з них для включення у вхідний контекст, що передається LLM.
- Створіть адаптивну систему RAG: Адаптивний RAG використовує LLM або класифікатор (компонент оркестратора), щоб визначити, який метод отримання даних застосувати в модульній системі RAG. Створення такої системи — хороший спосіб ознайомитися зі складнішими реалізаціями RAG.
Хоча все це може здаватися складним, пам’ятайте, що популярні платформи ШІ, як-от Perplexity, можуть надавати розширену допомогу з програмуванням. Вони чудово підходять для особистих проєктів і експериментів, а витрати можуть залишатися порівняно невисокими.
Примітка. У цьому посібнику використовується GPT-5.6 Luna. Доступність моделей може змінюватися, тому вам, можливо, знадобиться оновити виклик API.