46.5kЗаказать демоВойтиНачать бесплатно

Использование SelfQueryRetriever с LangChain для запросов к векторной базе данных

Sep 28, 20238 min read

LangChain хорошо известен тем, что оркестрирует взаимодействия с большими языковыми моделями (LLM). Недавно LangChain представил способ выполнения self-querying, позволяющий им запрашивать саму «цепочку» или модули с помощью пользовательского запроса. В этом посте мы покажем, как выполнять self-querying в Milvus, самой популярной в мире векторной базе данных. Интерпретируя пользовательский запрос, система может уточнять поиск в векторных хранилищах, улучшая результаты извлечения. Код для этого примера можно найти в CoLab здесь.

Давайте настроим self-querying в Milvus с помощью LangChain. Этот процесс состоит из четырех логических шагов.

  1. Настроить основы LangChain и Milvus.

  2. Получить или создать необходимые данные.

  3. Сообщить модели об ожидаемом формате данных.

  4. Продемонстрировать self-querying и объяснить, как он работает.

Введение в Self-Querying

Self-querying — это мощная техника, используемая в обработке естественного языка (NLP) и поиске информации. Она позволяет системе запрашивать саму себя, используя пользовательский запрос, обеспечивая более точные и релевантные результаты. В контексте LangChain self-querying используется для извлечения информации из векторного хранилища, то есть базы данных, которая хранит векторы, представляющие документы или точки данных. Self-query retriever — ключевой компонент фреймворка LangChain, позволяющий создавать сложные запросы и извлечения с использованием естественного языка.

Используя self-querying, LangChain может преобразовать пользовательский запрос в структурированный формат, понятный векторному хранилищу. Этот процесс гарантирует, что извлеченные документы будут высоко релевантны пользовательскому запросу, упрощая поиск нужной информации. Независимо от того, создаете ли вы разговорную AI-модель или поисковую систему, self-querying может значительно повысить точность и релевантность ваших результатов.

Настройка LangChain и Milvus

Первый шаг — настроить необходимые библиотеки. Вы можете установить требуемые библиотеки с помощью pip install openai langchain milvus python-dotenv. Если вы следовали моим предыдущим руководствам, вы уже знакомы с python-dotenv, моей предпочтительной библиотекой для работы с переменными окружения. Мы используем библиотеку OpenAI вместе с LangChain для доступа к GPT и применяем Milvus как наше векторное хранилище.

После подключения к ключу OpenAI API импортируйте необходимые модули LangChain. Нам понадобятся следующие шесть модулей:

  • Document: тип данных LangChain для хранения данных.

  • OpenAI и OpenAIEmbeddings: две функциональности для доступа к OpenAI и ее embeddings.

  • Milvus: модуль для доступа к Milvus из LangChain.

  • SelfQueryRetriever: модуль retriever.

  • AttributeInfo: модуль, определяющий нашу структуру данных для LangChain.

После импорта модулей мы устанавливаем переменную embeddings в функцию по умолчанию OpenAI Embeddings. Последний шаг в процессе настройки — использовать библиотеку milvus, чтобы запустить экземпляр Milvus Lite в нашем notebook.

Теперь давайте посмотрим на данные.

import os
from dotenv import load_dotenv

load_dotenv()
import openai

openai.api_key = os.getenv("OPENAI_API_KEY")
from langchain.schema import Document
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Milvus
from langchain.llms import OpenAI
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo

embeddings = OpenAIEmbeddings()
from milvus import default_server
default_server.start()

Давайте соберем немного данных. Вы можете спарсить свои данные, использовать предоставленные данные как есть или использовать их как шаблон для создания своих данных. Для этого примера я подготовил список документов о фильмах, включая Jurassic Park, Toy Story, Finding Nemo, The Unbearable Weight of Massive Talent, Lord of War и Ghost Rider. Хотя я не включаю названия в наши данные, я хочу, чтобы вы знали, к каким фильмам они относятся.

Я храню каждый из этих фильмов как объект LangChain Document. Он содержит ключ page_content, соответствующий строке, в данном случае описанию фильма. Он также включает metadata, такие как год, рейтинг и жанр фильма.

docs = [
    # jurassic park
    Document(page_content="A bunch of scientists bring back dinosaurs and mayhem breaks loose",
    metadata={"year": 1993, "rating": 7.7, "genre": "action"}),
    # toy story
    Document(page_content="Toys come alive and have a blast doing so",
    metadata={"year": 1995, "genre": "animated", "rating": 9.3 }),
    # finding nemo
    Document(page_content="A dad teams up with a mentally disabled partner to break into a dentist\'s office to save his son.",
    metadata={"year": 2003, "genre": "animated", "rating": 8.2 }),
    # unbearable weight of massive talent
    Document(page_content="Nicholas Cage plays Nicholas Cage in this movie about Nicholas Cage.",
    metadata={"year": 2022, "genre": "comedy", "rating": 7.0 }),
    # lord of war
    Document(page_content="Nicholas Cage sells guns until he has enough money to marry his favorite model. Then he sells more guns.",
    metadata={"year": 2005, "genre": "comedy", "rating": 7.6 }),
    # ghost rider
    Document(page_content="Nicholas Cage loses his skin and sets his skull on fire. Then he rides a motorcycle.",
    metadata={"year": 2007, "genre": "action", "rating": 5.3 }),
]

Определение метаданных self-query и self query retriever для LangChain и Milvus

Мы завершили первые два шага головоломки, и теперь пришло время третьего.

Сначала давайте настроим нашу векторную базу данных для загрузки. Мы можем использовать реализацию LangChain Milvus, чтобы загрузить наши документы и создать векторную базу данных на основе существующих документов. На этом шаге также вступает в действие функция эмбеддингов, использующая переменную embeddings, которую мы создали ранее. Оператор сравнения учитывает конкретные форматы и рекомендации, необходимые для создания условий фильтрации, которые направляют процессы извлечения данных.

Параметр connection_args — единственный обязательный параметр для подключения к Milvus. В этом руководстве я также использую параметр collection_name, чтобы назначить имя коллекции, в которой мы храним наши данные. Каждая коллекция в Milvus должна иметь имя. По умолчанию LangChain использует LangChainCollection.

vector_store = Milvus.from_documents(
    docs,
    embedding=embeddings,
    connection_args={"host": "localhost", "port": default_server.listen_port},
    collection_name="movies"
)

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

metadata_field_info = [
    AttributeInfo(
        name="genre",
        description="The genre of the movie",
        type="string",
    ),
    AttributeInfo(
        name="year",
        description="The year the movie was released",
        type="integer",
    ),
    AttributeInfo(
        name="rating", 
        description="A 1-10 rating for the movie", 
        type="float"
    ),
]

Последние несколько фрагментов описывают документ, инициализируют LLM и определяют Self-Query Retriever. Мы определяем self-query retriever, вызывая его метод ‘from_llm’. Мы должны использовать этот метод, чтобы связать LLM, векторное хранилище, описание содержимого документа и информацию о полях метаданных. В этом примере мы также задаем ‘verbose = True’, чтобы включить подробный вывод для этого self-query retriever. Строка запроса должна включать только релевантный текст, соответствующий содержимому документов, гарантируя, что любые условия в фильтрах четко отделены и не включены в саму строку запроса.

document_content_description = "Brief summary of a movie"
llm = OpenAI(temperature=0)
retriever = SelfQueryRetriever.from_llm(
    llm, vector_store, document_content_description, metadata_field_info, verbose=True
)

Результаты self-querying

Мы завершили настройку self-query retriever. Теперь давайте посмотрим, как он работает на практике. В этом примере я использовал три описания фильмов, связанных с Nicholas Cage. Итак, вопрос, который мы задаем: какие есть фильмы о Nicholas Cage?

# This example only specifies a relevant query
retriever.get_relevant_documents("What are some movies about Nicholas Cage?")

Мы должны получить вывод, похожий на приведенный ниже.

langchain-query-vector-database.png langchain-query-vector-database.png

Установив verbose=True, мы можем увидеть запрос, фильтр и лимит. LLM преобразует наш запрос из “What are some movies about Nicholas Cage?” в “Nicholas Cage.” Рассматривая результаты, мы можем заметить, что первые три результата — это все фильмы с участием Nicholas Cage. Однако четвертый результат, Finding Nemo, нерелевантен из-за параметра, установленного на получение четырех результатов.

Надеюсь, пошаговый разбор кода прояснил концепцию self-querying в векторной базе данных. На сайте LangChain LangChain описывает self-querying как метод, позволяющий LLM запрашивать самого себя с использованием базового векторного хранилища. Другими словами, LangChain разрабатывает простое приложение retrieval augmented generation (RAG) в CVP framework, которое включает функцию self-querying.

В этом руководстве мы рассмотрели функцию self-query в LangChain, используя Milvus в качестве базового векторного хранилища. Self-querying позволяет создать простое RAG-приложение, объединяя LLM и векторную базу данных. LLM разбивает запрос на естественном языке на строку, которая затем векторизуется для выполнения запроса.

В нашем примере мы сгенерировали некоторые примерные данные, связанные с фильмами. Один из способов расширить этот пример — собрать ваши данные. При определении self-query retriever не забудьте предоставить описания как для векторного хранилища, так и для метаданных.

Чтобы начать работу и поэкспериментировать с функцией self-query в LangChain, обратитесь к colab notebook.

Запрос к векторному хранилищу с помощью операторов логических операций

При выполнении запроса к векторному хранилищу операторы логических операций используются для указания условий фильтрации документов. Оператор логической операции имеет форму op(statement1, statement2, …), где op — логический оператор, такой как AND, OR или NOT. Каждый statement может быть оператором сравнения, который имеет форму comp(attr, val), где comp — компаратор, такой как EQ, LT или GT, а attr и val — соответственно сравниваемые атрибут и значение.

Например, оператор логической операции может выглядеть так: AND(EQ(language, “English”), GT(rating, 4)). Этот оператор будет фильтровать документы, у которых атрибут language равен “English”, а атрибут rating больше 4. Используя операторы логических операций, вы можете создавать сложные запросы, которые объединяют несколько условий, обеспечивая более точную фильтрацию документов в векторном хранилище.

Обработка запроса пользователя

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

Например, если пользователь вводит запрос «Найти фильмы с рейтингом выше 4 и продолжительностью менее 2 часов», конструктор запросов может сгенерировать такой структурированный запрос: AND(GT(rating, 4), LT(runtime, 120)). Затем этот структурированный запрос будет преобразован в запросы к векторному хранилищу и выполнен в векторном хранилище для извлечения релевантных документов. Обрабатывая запрос пользователя таким образом, ретривер с самозапросом гарантирует, что результаты будут адаптированы к конкретным требованиям пользователя.

Лучшие практики и заключение

При использовании ретривера с самозапросом важно следовать лучшим практикам, чтобы обеспечить точные и релевантные результаты. Вот несколько советов:

  • Используйте конкретный и лаконичный язык при вводе запросов.

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

  • Используйте операторы сравнения, чтобы сравнивать атрибуты и значения.

  • Используйте компаратор EQ, чтобы указывать точные совпадения.

  • Используйте компараторы LT и GT, чтобы задавать диапазонные запросы.

  • Используйте логические операторы AND и OR, чтобы объединять условия.

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

Обновлено Jul 09, 2026