Всем привет! Наверняка у вас были ситуации, когда нужно быстро найти что-то в длинном документе-договоре, инструкции или отчёте. Сегодня я покажу, как сделать своего помощника, который будет отвечать на такие вопросы автоматически. Соберем RAG с нуля: загрузим документы, "нарежем" их на куски, проиндексируем в Qdrant и подключим LLaMA через Amvera Inference.
Если вы увидели незнакомые слова — не пугайтесь, далее я расскажу об этом подробно.
Самое главное, что всё это работает самостоятельно, без зависимости от OpenAI.
RAG - что это?
RAG (Retrieval-Augmented Generation) — это подход, где любая LLM (большая языковая модель) при генерации ответа использует внешние данные, полученные из предложенной пользователем базы знаний. Простым языком — из обработанных приложенных документов.
Обычно LLM не знает, что происходит в ваших документах, не знает контекст вопроса, если этого нет в её базе знаний, которую провайдеры (OpenAI и подобные) внедряют при обучении. Она отвечает "из головы". Но с RAG:
Вы загружаете документы в векторную базу (например, в нашем случае, Qdrant).
При каждом запросе делается поиск по смыслу.
Модель подставляет найденные куски текста в промт.
LLM формирует ответ уже с учетом этих данных.
Пример: у вас есть договор на 40 страниц. Вместо того чтобы пересказывать его в промпте, мы грузим его в RAG. А дальше просто спрашиваем: "Какие у нас сроки?" и LLM ответит, потому что увидит кусок загруженного договора, где это написано.
В этом вся магия. И именно ее мы рассмотрим в данной статье, создадим RAG с нуля.
Наши зависимости
Предварительно нам понадобится поднять несколько сервисов и получить токен LLM Inference API — все это сделаем в Amvera.
Amvera LLM Inference
Первое и самое важное — доступ к LLM. В нашем случае мы будем работать через наш инференс LLaMA. Это удобно: вам не нужно запускать модель вручную, возиться с зависимостями, подбирать железо, всё это за вас уже сделал Amvera, просто отправляете запрос и получаете ответ от LLaMA через готовый API. А главное, это не требует иностранной карты и у тарифов есть ограничения, которые не позволят уйти в минус при ошибке.
Для получения доступа вам необходимо:
Зарегистрироваться в Amvera по ссылке.
После регистрации мы уже получаем совершенно бесплатные 111 рублей для тестов - этого будет достаточно для того, чтобы развернуть необходимые нам сервисы и пользоваться ими некоторое время.
На странице проектов уже доступны LLM - переходим туда и покупаем необходимый нам пакет токенов. Я уже взял тариф на 200 тыс. токенов за 490 рублей от LLaMA 3.3 70B.


Во вкладке "Инфо" можем выпустить новый токен для доступа к API.
Мы получили токен для доступа и можем сделать тестовый запрос в Inference API.
Подробнее можно почитать на странице документации Amvera и Swagger.

Теперь, когда мы убедились, что все работает, можем развернуть следующую зависимость.
Qdrant
Следующая важная часть нашей системы — векторная база данных. Мы будем использовать Qdrant, который идеально подходит для RAG.
Проще говоря, Qdrant - это хранилище "смысла". Поиск идет не по ключевым словам, а по значению кусков текста. Именно поэтому мы используем данную СУБД, чтобы передать LLM только нужную информацию из большого массива данных. Помимо прочего, это сэкономит нам расход токенов на промт для моделей.
Мы выпустили Qdrant как преднастроенный сервис — с WEB UI, API и всем необходимым. Всё это подробно описано в нашей отдельной новости на Хабре: «Векторная база данных Qdrant стала доступна как сервис в Amvera Cloud».
Qdrant готов к работе сразу после запуска — нет необходимости настраивать его и окружение самостоятельно. В этом особенность Amvera — запуска кода и любых сервисов "одной кнопкой".
Подробности — в документации Qdrant от Amvera.
Для запуска Qdrant вам необходимо лишь нажать на выделенную кнопку на скриншоте ниже. Эта кнопка доступна на странице проектов.

Далее мы подключим библиотеку qdrant-client
и начнём добавлять туда данные из наших документов.
Практика с Qdrant
Начнём с самого простого — подключение к нашему экземпляру Qdrant через Python. В Amvera он уже настроен, так что подключиться можно буквально в пару строк:
from qdrant_client import QdrantClient
client = QdrantClient(
url="http://amvera-pushmaster-run-qdrant-test:6333", # укажите внутреннее доменное имя
api_key="your_secret_api_key_here" # если используется авторизация
)
Учтите, что все взаимодействия с Qdrant через клиент qdrant-client будет приведено на примере взаимодействия из проектов развернутых в Amvera.
Вот как можно создать коллекцию и добавить в неё данные вручную:
from qdrant_client.models import VectorParams, Distance, PointStruct
# Создание коллекции
client.recreate_collection(
collection_name="my_documents",
vectors_config=VectorParams(size=384, distance=Distance.COSINE)
)
# Добавление данных
client.upsert(
collection_name="my_documents",
points=[
PointStruct(
id=1,
vector=[0.1] * 384, # пример вектора
payload={"text": "Срок поставки составляет 30 дней."}
)
]
)
На практике, конечно, мы не генерируем векторы вручную. Для этого используют модели эмбеддингов. Один из самых простых вариантов - sentence-transformers
:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("intfloat/e5-small")
texts = [
"Срок составляет 30 дней.",
"Оплата производится по факту доставки материалов."
]
vectors = model.encode(texts).tolist()
Теперь мы можем загрузить эти вектора в Qdrant вместе с текстами:
points = [
PointStruct(id=i, vector=vectors[i], payload={"text": texts[i]})
for i in range(len(texts))
]
client.upsert(
collection_name="my_documents",
points=points
)
На этом этапе Qdrant уже содержит документы в векторном виде и готов к поиску по смыслу. Следующим шагом будет использование этого поиска вместе с LLaMA, чтобы отвечать на вопросы пользователя на основе этих текстов.
Но сначала рассмотрим, что это вообще за штуки такие: "вектор", "эмбеддинг", "поиск по смыслу"?
Что такое векторы и зачем они нужны
Когда мы говорим, что сохраняем текст в Qdrant, на самом деле мы сохраняем его представление в виде чисел — векторов. Это такие списки из 384 (или 768, или 1024) чисел, которые описывают смысл текста. Чем ближе два вектора, тем ближе тексты по смыслу.
Это называется эмбеддингом, и создаётся с помощью специальной модели, например intfloat/e5-small
. Именно она превращает фразу вроде:
"Срок составляет 30 дней"
в вектор из 384 чисел вроде:
[0.12, -0.03, 0.85, ...]
Сами числа нам не важны, главное, что такие представления можно сравнивать между собой.
Вот зачем нам Qdrant: это база данных, в которой можно делать поиск по близости векторов, то есть по смыслу. Поэтому когда мы получим от пользователя вопрос, мы сначала найдём в Qdrant те куски документа, которые по смыслу ближе всего к этому вопросу, и уже их покажем LLaMA.
Теперь, когда векторная база готова, переходим к LLM.
Наконец, всё готово к финальному этапу. Разработке RAG-приложения. Начнём с базовой, немного примитивной версии: пользователь задает вопрос, а мы находим ответ в заранее загруженном документе.
from sentence_transformers import SentenceTransformer
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance, PointStruct, Filter, SearchParams
import requests
import os
# Подключение к Qdrant
client = QdrantClient(url="http://amvera-user-run-project:6333") # не забудьте заменить
# Загрузка документа
with open("/data/data.txt", "r", encoding="utf-8") as f:
raw_text = f.read()
lines = [line.strip() for line in raw_text.split("\n") if line.strip()]
# Эмбеддинги
model = SentenceTransformer("intfloat/e5-small")
vectors = model.encode(lines).tolist()
collection_name = "my_documents"
if client.collection_exists(collection_name):
client.delete_collection(collection_name)
client.create_collection(
collection_name=collection_name,
vectors_config=VectorParams(size=384, distance=Distance.COSINE)
)
points = [
PointStruct(id=i, vector=vectors[i], payload={"text": lines[i]})
for i in range(len(lines))
]
client.upsert(collection_name=collection_name, points=points)
# Запрос
query = "Какие сроки указаны в документе? И где об этом написано?"
query_vector = model.encode(query).tolist()
search_result = client.search(
collection_name=collection_name,
query_vector=query_vector,
limit=3
)
context = "\n".join(hit.payload["text"] for hit in search_result if "text" in hit.payload)
# Запрос в Inference API
api_url = "https://kong-proxy.yc.amvera.ru/api/v1/models/llama"
payload = {
"model": "llama70b",
"messages": [
{
"role": "user",
"text": f"Контекст:\n{context}\n\nВопрос: {query}"
}
]
}
headers = {
"Content-Type": "application/json",
"X-Auth-Token": "Bearer <ваш-токен>" # Токен лучше всего хранить в переменных окружения!
}
response = requests.post(api_url, json=payload, headers=headers)
response.raise_for_status()
print("Ответ:", response.json().get("result"))
Конкретно в этом примере используется предзагруженный документ data.txt, где содержится информация про некоторые сроки. При запуске выводится ответ, где LLM отвечает корректно по заданному вопросу и контексту документа.
Это и есть простейшая реализация RAG: вы находите фрагменты, соответствующие вопросу, и передаёте их LLM. В будущем к этому можно легко прикрутить загрузку документов от пользователя, например через Telegram-бот.
Итог
Вот и всё! Мы собрали свою RAG систему, которая умеет отвечать на вопросы по документам. Просто загружаем файл, разбиваем его на куски, ищем нужные фрагменты через Qdrant — и передаём их модели LLaMA от Amvera, чтобы получить ответ.
Все работает без OpenAI, без сложных настроек, без необходимости иметь иностранную карту. Можно использовать для чатов, ботов, поддержки клиентов или просто чтобы самому не искать вручную нужный абзац в договоре.
Попробуйте сами — и, возможно, это станет вашим новым любимым инструментом!
Комментарии (10)
avshkol
13.07.2025 10:20Может ли qdrant взять pdf и корректно нарезать его на главы и разделы? Один текст- один раздел?
latuk993
13.07.2025 10:20Сам QDrant - скорее нет. Он не парсит PDF и не делит его на главы. Документ нужно будет предварительно распарсить любой удобной либой и уже в таком виде грузить в векторную БД
alex896079
13.07.2025 10:20чтобы развернуть похожую по характеристикам систему локально нужно довольно серьёзное железо особенно для модели llama70b. Но для фанатов можно было бы и выложить на github исходники, тем более что есть некоторые сомнения в качестве inference. Вот например почему для эмбеддинга была взята эта модель, хотя, лучшее качество на русском — у e5-large или sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2?
Politura
13.07.2025 10:20Я уже взял тариф на 200 тыс. токенов за 490 рублей от LLaMA 3.3 70B.
Скажите, а зачем кому-то покупать у вас 200 тыс. токенов 70B модели за 490 рублей, когда можно купить 1 миллион токенов 670B модели DeepSeek-V3-0324 за где-то 80 рублей?
Модель намного лучше, цена за токен в 30 раз дешевле.
Data4
13.07.2025 10:20Возможность оплаты РФ картой. Если у вас есть иностранная карта, есть много вариантов дешевого инференса. Если только карта выпущенная в РФ вариантов сильно меньше.
Если другие проекты развернуты в облаке, то следить за одним балансом намного проще.
paulmann
13.07.2025 10:20DeepSeek без проблем оплачивается через Сбербанк платёжки на вполне легальный в РФ аккаунт AliPay с последующей оплатой с него DeepSeek
kirillkosolapov
13.07.2025 10:20Если вы юридическое лицо и вам нужны закрывающие документы, такой способ не подойдет. Да и для физических лиц это дополнительные затраты времени, и уже каждый сам решает насколько его время дорого и стоит ли заморачиваться ради небольшой экономии.
ovchinnikovproger
Для RAG приложений ещё бывает полезно использовать MCP и такие фреймворки, как Langchain.