Всем привет! Наверняка у вас были ситуации, когда нужно быстро найти что-то в длинном документе-договоре, инструкции или отчёте. Сегодня я покажу, как сделать своего помощника, который будет отвечать на такие вопросы автоматически. Соберем 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. А главное, это не требует иностранной карты и у тарифов есть ограничения, которые не позволят уйти в минус при ошибке.

Для получения доступа вам необходимо:

  1. Зарегистрироваться в Amvera по ссылке.

  2. После регистрации мы уже получаем совершенно бесплатные 111 рублей для тестов - этого будет достаточно для того, чтобы развернуть необходимые нам сервисы и пользоваться ими некоторое время.

  3. На странице проектов уже доступны LLM - переходим туда и покупаем необходимый нам пакет токенов. Я уже взял тариф на 200 тыс. токенов за 490 рублей от LLaMA 3.3 70B.

Переходим в раздел LLM
Переходим в раздел LLM
Овормляем нужную нам подписку на токены LLM. Все в рублях.
Овормляем нужную нам подписку на токены LLM. Все в рублях.
  1. Во вкладке "Инфо" можем выпустить новый токен для доступа к API.

Мы получили токен для доступа и можем сделать тестовый запрос в Inference API.

Подробнее можно почитать на странице документации Amvera и Swagger.

Проверяем работу API LLM
Проверяем работу API LLM

Теперь, когда мы убедились, что все работает, можем развернуть следующую зависимость.

Qdrant

Следующая важная часть нашей системы — векторная база данных. Мы будем использовать Qdrant, который идеально подходит для RAG.

Проще говоря, Qdrant - это хранилище "смысла". Поиск идет не по ключевым словам, а по значению кусков текста. Именно поэтому мы используем данную СУБД, чтобы передать LLM только нужную информацию из большого массива данных. Помимо прочего, это сэкономит нам расход токенов на промт для моделей.

Мы выпустили Qdrant как преднастроенный сервис — с WEB UI, API и всем необходимым. Всё это подробно описано в нашей отдельной новости на Хабре: «Векторная база данных Qdrant стала доступна как сервис в Amvera Cloud».

Qdrant готов к работе сразу после запуска — нет необходимости настраивать его и окружение самостоятельно. В этом особенность Amvera — запуска кода и любых сервисов "одной кнопкой".

Подробности — в документации Qdrant от Amvera.

Для запуска Qdrant вам необходимо лишь нажать на выделенную кнопку на скриншоте ниже. Эта кнопка доступна на странице проектов.

Запуск Qdrant
Запуск 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)


  1. ovchinnikovproger
    13.07.2025 10:20

    Для RAG приложений ещё бывает полезно использовать MCP и такие фреймворки, как Langchain.


  1. avshkol
    13.07.2025 10:20

    Может ли qdrant взять pdf и корректно нарезать его на главы и разделы? Один текст- один раздел?


    1. avshkol
      13.07.2025 10:20

      Нет, говорит перплексити,...


    1. latuk993
      13.07.2025 10:20

      Сам QDrant - скорее нет. Он не парсит PDF и не делит его на главы. Документ нужно будет предварительно распарсить любой удобной либой и уже в таком виде грузить в векторную БД


  1. alex896079
    13.07.2025 10:20

    чтобы развернуть похожую по характеристикам систему локально нужно довольно серьёзное железо особенно для модели llama70b. Но для фанатов можно было бы и выложить на github исходники, тем более что есть некоторые сомнения в качестве inference. Вот например почему для эмбеддинга была взята эта модель, хотя, лучшее качество на русском — у e5-large или sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2?


    1. Fardeadok
      13.07.2025 10:20

      С чего вы решили что у них лучшее?


  1. Politura
    13.07.2025 10:20

    1. Я уже взял тариф на 200 тыс. токенов за 490 рублей от LLaMA 3.3 70B.

    Скажите, а зачем кому-то покупать у вас 200 тыс. токенов 70B модели за 490 рублей, когда можно купить 1 миллион токенов 670B модели DeepSeek-V3-0324 за где-то 80 рублей?

    Модель намного лучше, цена за токен в 30 раз дешевле.

    https://api-docs.deepseek.com/quick_start/pricing


    1. Data4
      13.07.2025 10:20

      • Возможность оплаты РФ картой. Если у вас есть иностранная карта, есть много вариантов дешевого инференса. Если только карта выпущенная в РФ вариантов сильно меньше.

      • Если другие проекты развернуты в облаке, то следить за одним балансом намного проще.


      1. paulmann
        13.07.2025 10:20

        DeepSeek без проблем оплачивается через Сбербанк платёжки на вполне легальный в РФ аккаунт AliPay с последующей оплатой с него DeepSeek


        1. kirillkosolapov
          13.07.2025 10:20

          Если вы юридическое лицо и вам нужны закрывающие документы, такой способ не подойдет. Да и для физических лиц это дополнительные затраты времени, и уже каждый сам решает насколько его время дорого и стоит ли заморачиваться ради небольшой экономии.