Logo Craft Homelab Docs Контакты Telegram
RAG-системы: поиск и векторы — полное руководство
Fri Jan 02 2026

RAG-системы: поиск + векторы

В последнее время Retrieval-Augmented Generation (RAG) системы стали настоящим трендом в области LLM. Они позволяют значительно улучшить качество ответов больших языковых моделей (LLM), предоставляя им доступ к внешним источникам знаний. Проблема в том, что просто “скормить” LLM кучу текста недостаточно. Нужно эффективно искать релевантную информацию и правильно ее интегрировать в запрос. Эта статья – глубокое погружение в RAG, от embeddings до векторных баз данных, с акцентом на практические аспекты и потенциальные подводные камни.

Embedding: Превращаем текст в числа

Векторные представления (embeddings) – это основа RAG. Они позволяют нам математически измерить семантическую близость между текстами. LLM не понимают текст напрямую, им нужны числа. Embedding модели (например, OpenAI’s text-embedding-ada-002, Sentence Transformers) преобразуют текст в вектор фиксированной размерности. Чем ближе векторы, тем более похожи тексты по смыслу.

Как это работает “под капотом”?

Большинство современных embedding моделей основаны на трансформерах. В упрощенном виде, процесс выглядит так:

  1. Токенизация: Текст разбивается на токены (слова или части слов).
  2. Встраивание токенов: Каждый токен преобразуется в векторное представление.
  3. Трансформерные слои: Несколько слоев трансформеров обрабатывают эти векторные представления, учитывая контекст и взаимосвязи между токенами. Ключевой механизм – self-attention, который позволяет модели взвешивать важность разных токенов при формировании представления всего текста.
  4. Агрегация: Векторные представления всех токенов агрегируются (например, усредняются или суммируются) для получения финального векторного представления всего текста.

Почему это важно?

Понимание архитектуры позволяет оптимизировать процесс. Например, можно использовать более компактные модели для снижения вычислительных затрат, или fine-tune embedding модель на специфическом домене для повышения точности.

Векторные базы данных: Храним и ищем векторы

После того, как мы получили embeddings для наших документов, нам нужно где-то их хранить и эффективно искать ближайшие векторы к запросу пользователя. Традиционные реляционные базы данных для этого не подходят. Векторные базы данных (Vector Databases, VDB) оптимизированы для работы с векторными данными.

Основные типы VDB:

  • Approximate Nearest Neighbor (ANN) индексы: Это наиболее распространенный подход. ANN алгоритмы (например, HNSW, Faiss) жертвуют абсолютной точностью ради скорости поиска. Они находят приблизительно ближайшие векторы, что достаточно для большинства задач.
  • Квантование: Снижает размерность векторов, что ускоряет поиск, но может ухудшить точность.
  • Графовые базы данных: Подходят для задач, где важны связи между документами.

Примеры VDB:

  • Pinecone: Облачная VDB, простая в использовании, но платная.
  • Weaviate: Open-source VDB с GraphQL API.
  • ChromaDB: Open-source VDB, ориентированная на разработку.
  • Faiss: Библиотека от Facebook AI Research, предоставляет ANN алгоритмы. Можно использовать самостоятельно, без VDB.

Retrieval: Находим релевантные документы

Этап retrieval – ключевой для качества RAG. Мы берем запрос пользователя, преобразуем его в embedding, и ищем в векторной базе данных ближайшие векторы. Результатом является список релевантных документов.

Практическая реализация (Python + ChromaDB):

from chromadb import PersistentClient
from sentence_transformers import SentenceTransformer

# Инициализация модели embedding
embedding_model = SentenceTransformer('all-MiniLM-L6-v2')

# Инициализация ChromaDB
client = PersistentClient(path="chroma_db")
collection = client.get_or_create_collection("my_collection")

# Добавление документов
documents = [
    "Python is a high-level, general-purpose programming language.",
    "Java is a widely used object-oriented programming language.",
    "C++ is a powerful language often used for system programming."
]
ids = ["doc1", "doc2", "doc3"]
embeddings = embedding_model.encode(documents).tolist()

collection.add(
    documents=documents,
    embeddings=embeddings,
    ids=ids
)

# Поиск
query = "What is Python?"
query_embedding = embedding_model.encode(query).tolist()
results = collection.query(
    query_embeddings=[query_embedding],
    n_results=2  # Возвращаем 2 лучших документа
)

print(results)

Важные моменты:

  • n_results: Определяет, сколько документов вернуть. Слишком мало – пропустим важную информацию. Слишком много – перегрузим LLM.
  • query_embeddings: Важно, чтобы embedding модель для запроса и документов была одинаковой.
  • Нормализация векторов: Перед вычислением расстояния между векторами рекомендуется их нормализовать.

Generation: Интегрируем информацию в LLM

Наконец, мы берем релевантные документы, полученные на этапе retrieval, и передаем их в LLM вместе с запросом пользователя. Это можно сделать разными способами:

  • Context Injection: Просто добавляем текст документов в начало запроса.
  • Prompt Engineering: Создаем более сложные промпты, которые явно указывают LLM, как использовать предоставленную информацию.
  • Fine-tuning: Fine-tune LLM на данных, содержащих контекст и ответы.

Пример (Context Injection):

from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY")

query = "What is Python?"
results = collection.query(
    query_embeddings=[embedding_model.encode(query).tolist()],
    n_results=1
)

context = results['documents'][0][0]  # Берем первый документ

prompt = f"Answer the following question based on the provided context:\n\nContext: {context}\n\nQuestion: {query}"

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=[{"role": "user", "content": prompt}]
)

print(response.choices[0].message.content)

Edge Cases & Pitfalls

  • Embedding Model Choice: Не все embedding модели одинаково хороши. Выбор модели зависит от домена и задачи.
  • Vector Database Scaling: VDB могут стать узким местом при больших объемах данных. Необходимо правильно настроить индексацию и шардирование.
  • Context Window Limits: LLM имеют ограничение на длину контекста. Необходимо уметь сокращать документы или выбирать наиболее релевантные фрагменты.
  • Hallucinations: LLM могут генерировать неверную информацию, даже при наличии релевантного контекста. Необходимо тщательно тестировать систему и использовать техники для снижения галлюцинаций.
  • “Lost in the Middle” Problem: LLM хуже всего обрабатывают информацию, находящуюся в середине контекста. Подумайте о стратегиях перестановки информации.

Verdict

RAG – мощный инструмент для улучшения качества LLM. Он позволяет использовать LLM для задач, требующих доступа к внешним знаниям. Однако, RAG – это не серебряная пуля. Необходимо тщательно выбирать компоненты системы, оптимизировать параметры и учитывать потенциальные подводные камни.

Когда использовать RAG:

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

Когда не использовать RAG:

  • Когда задача не требует доступа к внешним знаниям.
  • Когда LLM уже достаточно хорошо справляется с задачей без RAG.
  • Когда данные постоянно меняются и требуют частой переиндексации.