Основна имплементация на 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: Тук ще съхранявате своя API ключ за Perplexity.
Във файла .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.
- Разделя текста на припокриващи се фрагменти.
- Изпраща тези фрагменти към модела за ембединги pplx-embed-v1-0.6b на Perplexity.
- Декодира и нормализира върнатите вектори с помощта на 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 извикването.