Векторные представления текста для RAG и поиска — Python, Ollama, совместимые с API OpenAI

Встраивания для RAG — Python, Ollama, API OpenAI.

Содержимое страницы

Если вы работаете с генерацией с расширением поиска (RAG), этот раздел объясняет векторные представления текста (эмбеддинги) простым языком: что это такое, как они работают в поиске и извлечении данных, и как вызывать два распространенных локальных режима из Python с помощью Ollama или OpenAI-совместимого HTTP API (так как многие серверы на базе llama.cpp поддерживают такой интерфейс).

Векторные представления текста и извлечение

Для клиентов на Go и сравнения SDK для Ollama см. SDK для Ollama на Go — сравнение с примерами.

Что такое векторное представление текста (эмбеддинг)?

Векторное представление текста (эмбеддинг) — это вектор (список чисел с плавающей точкой), создаваемый моделью эмбеддингов. Модель преобразует текст переменной длины в пространство с фиксированной размерностью так, что тексты со схожим смыслом оказываются близко друг к другу согласно метрике расстояния или сходства (часто используется косинусное сходство на L2-нормализованных векторах).

Эмбеддинги не являются идентификаторами токенов и не являются результатом чат-запроса. Это слой представления, который используется для поиска, кластеризации, удаления дубликатов и, в архитектуре RAG, для извлечения данных.

Распространенные сценарии использования

Сценарий Роль эмбеддингов
Семантический поиск / Извлечение в RAG Преобразование запросов и фрагментов документов в векторы; ранжирование по сходству для получения релевантных отрывков.
Переранжирование с помощью моделей эмбеддингов Преобразование запроса и каждого кандидата в векторы; оценка пар по сходству (см. Переранжирование с помощью моделей эмбеддингов).
Кластеризация и удаление дубликатов Группировка или удаление дубликатов в пространстве эмбеддингов без ручной разметки каждого примера.
Оценка в стиле классификации Сравнение текста с описаниями прототипов или названиями классов в том же пространстве (паттерны зависят от модели).

Для мультимодальных настроек (текст-изображение и связанные концепции) см. Кросс-модальные эмбеддинги.

Эмбеддинги внутри конвейера RAG

Типичный оффлайн процесс выглядит так:

  1. Фрагментация документов (размер, перекрытие и структура имеют значение — см. Стратегии фрагментации в RAG).
  2. Векторизация каждого фрагмента; опциональное сохранение метаданных (идентификатор источника, раздел, ACL).
  3. Индексация векторов в памяти, в библиотеке индексов или в векторной базе данных (сравнение компромиссов см. в Векторные хранилища для RAG — сравнение).

В момент запроса:

  1. Векторизация пользовательского запроса (одна короткая строка или небольшая пакетная обработка).
  2. Извлечение топ-k наиболее похожих фрагментов с помощью векторного поиска (опционально с добавлением ключевого слова или гибридного поиска).
  3. Создание промпта на основе извлеченных фрагментов обычного текста и вызов вашей чат-модели.

Важный нюанс — большие языковые модели в чат-API потребляют текст (и инструменты), а не произвольные тензоры эмбеддингов. Вы используете эмбеддинги для выбора текста, который нужно вставить. Если вы видите фразу «запросить LLM с заранее рассчитанными эмбеддингами», на практике это означает извлечь данные с помощью эмбеддингов, а затем отправить выбранный текст в LLM.

Получение эмбеддингов с помощью Ollama (Python)

Ollama предоставляет HTTP API. Для получения эмбеддингов вызовите POST /api/embed на вашем хосте Ollama (по умолчанию http://127.0.0.1:11434). JSON-тело запроса включает имя model и input (строка или список строк). В ответе содержится поле embeddings — список векторов, соответствующих вашим входным данным.

Установите httpx (или используйте requests аналогичным образом).

import httpx

OLLAMA = "http://127.0.0.1:11434"
MODEL = "nomic-embed-text"  # замените на модель эмбеддингов, которую вы загрузили

def embed_ollama(texts: list[str]) -> list[list[float]]:
    r = httpx.post(
        f"{OLLAMA}/api/embed",
        json={"model": MODEL, "input": texts},
        timeout=120.0,
    )
    r.raise_for_status()
    data = r.json()
    return data["embeddings"]

if __name__ == "__main__":
    q = "Что такое генерация с расширением поиска?"
    chunks = [
        "RAG объединяет извлечение данных с генерацией.",
        "Эмбеддинги отображают текст в векторное пространство для поиска по сходству.",
    ]
    qv = embed_ollama([q])[0]
    doc_vs = embed_ollama(chunks)
    print(len(qv), len(doc_vs), len(doc_vs[0]))

Операционные заметки

Получение эмбеддингов через OpenAI-совместимый сервер (Python)

Многие локальные серверы (включая распространенные HTTP-конфигурации на базе llama.cpp) предоставляют OpenAI-совместимые маршруты, такие как POST /v1/embeddings. Вы можете использовать официальную библиотеку openai для Python и указать base_url на корень …/v1 вашего сервера.

from openai import OpenAI

# Пример — замените хост, порт и идентификатор модели на значения вашего сервера
client = OpenAI(
    base_url="http://127.0.0.1:8080/v1",
    api_key="not-needed",  # многие локальные серверы игнорируют это
)

def embed_openai_compatible(text: str, model: str) -> list[float]:
    r = client.embeddings.create(model=model, input=text)
    return r.data[0].embedding

if __name__ == "__main__":
    v = embed_openai_compatible("привет от llama.cpp", "your-embedding-model-id")
    print(len(v))

Почему оба паттерна объединены на одной странице? Концепции (фрагментация, векторизация, индексация, запрос, извлечение текста) идентичны; меняется только HTTP-интерфейс. Одна статья в стиле воркшопа позволяет избежать дублирования одного и того же повествования под двумя URL.

Сохранение векторов и их запрос

В минимальном варианте необходимо сохранить три вещи для каждого фрагмента — вектор, текст и метаданные (идентификатор источника, смещения, ACL). Для быстрого прототипирования можно хранить все в списке Python и использовать косинусное сходство с NumPy или scikit-learn. Для растущих объемов данных используйте векторную базу данных или библиотечный индекс (FAISS и др.); см. Векторные хранилища для RAG — сравнение для сравнения компромиссов на уровне продуктов.

Концептуальный цикл запроса:

  1. query_vec = embed(query)
  2. neighbors = index.search(query_vec, k)
  3. context = "\n\n".join(chunk.text for chunk in neighbors)
  4. Отправить context и вопрос пользователя в ваш чат-API.

Переранжирование после извлечения

Переранжировщик (часто кросс-энкодер или вторая модель оценки) может переупорядочить лучших кандидатов после векторного извлечения. На этом сайте есть примеры на Python и Go, включая Переранжирование с помощью моделей эмбеддингов и Переранжирование с Ollama и Qwen3 Embedding на Go.

На этом сайте — связанные статьи

Тема Статья
Полная архитектура RAG Учебник по RAG — архитектура, реализация, продакшн
Фрагментация перед векторизацией Стратегии фрагментации в RAG
Выбор векторной БД Векторные хранилища для RAG — сравнение
Qwen3 в Ollama Модели Qwen3 для эмбеддингов и переранжирования в Ollama
Кросс-модальные Кросс-модальные эмбеддинги
Ollama CLI и советы Шпаргалка по Ollama
Go + Ollama Использование Ollama в Go — сравнение SDK

Полезные ссылки