Агентная система RAG C LangGraph и Vector DB#

Традиционные системы генерации с поддержкой поиска (RAG) работают по простому пути: запрос → поиск → генерация. Конечно, это хорошо работает во многих сценариях. Этот линейный подход часто дает сбой при работе со сложными запросами, требующими нескольких шагов или объединения различных типов информации.

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

Объединив надежную систему управления состоянием LangGraph с передовым векторным поиском Platform V Vector DB (далее - Vector DB), будет построена система, которая не просто отвечает на вопросы — она изящно справляется со сложными многоэтапными задачами информационного поиска.

Цель и задачи#

В данном руководстве представлено создание агента искусственного интеллекта для ответов на вопросы о документации Hugging Face и Transformers с использованием LangGraph. В основе агента лежит LangGraph, который действует подобно дирижеру оркестра. Он направляет поток между различными компонентами — решает, когда извлекать информацию, когда выполнять веб-поиск и когда генерировать ответы.

Компоненты включают два хранилища векторов Vector DB и веб-поисковую машину Brave. Однако агент не следует одному пути вслепую. Вместо этого он оценивает каждый запрос и принимает решение обратиться к первому хранилищу векторов, второму или выполнить веб-поиск.

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

Базовый принцип работы#

image1

Шаг

Описание

1. Пользовательский ввод

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

2. Обработка запроса агентом ИИ

Агент искусственного интеллекта анализирует запрос, выясняя, что именно спрашивается и какие инструменты или источники данных лучше всего ответят на вопрос

3. Выбор инструмента

На основании анализа агент искусственного интеллекта выбирает подходящий инструмент для работы. Данные распределены по двум базам векторов, и в зависимости от запроса он выбирает подходящую базу. Для запросов, требующих актуальных или внешних веб-данных, агент обращается к инструменту веб-поиска, управляемому BraveSearchAPI

4. Выполнение запроса

Далее агент искусственного интеллекта применяет выбранный инструмент:
- Инструмент RAG 1 запрашивает Векторную базу данных 1.
- Инструмент RAG 2 запрашивает Векторную базу данных 2.
- Инструмент веб-поиска погружается в интернет с помощью поискового API

5. Извлечение данных

Результаты поступают:
- Векторные базы данных 1 и 2 возвращают наиболее релевантные документы для запроса.
- Инструмент веб-поиска предоставляет актуальные или внешние сведения

6. Генерация ответа

Используя модель генерации текста (например, GPT), агент искусственного интеллекта создает подробный и точный ответ, адаптированный под запрос

7. Ответ пользователю

Отшлифованный ответ возвращается через интерфейс, готовый к использованию

Стек технологий#

Архитектура использует новейшие инструменты для обеспечения эффективных рабочих процессов Agentic RAG. Вот краткий обзор ее компонентов и необходимых технологий:

  • Агент ИИ: мозговой центр системы, этот агент обрабатывает запросы, выбирает подходящие инструменты и интегрирует ответы. Используйте движок рассуждений OpenAI gpt-4o, управляемый плавно LangGraph.

  • Встраивание: запросы преобразуются в векторные вложения с использованием модели OpenAI text-embedding-3-small.

  • Векторная база данных: вложения хранятся и используются для поиска сходства, а Vector DB выступает в роли базы данных по выбору.

  • Языковая модель: ответы генерируются с использованием OpenAI gpt-4o, обеспечивая точность и контекстное обоснование ответов.

  • Средства поиска: чтобы расширить возможности RAG, необходимо добавить компонент веб-поиска, поддерживаемый BraveSearchAPI, идеально подходящий для получения реальных и внешних данных.

  • Управление рабочим процессом: Вся оркестровка и принятие решений реализованы с помощью LangGraph, предоставляя гибкость и интеллект, необходимые для обработки сложных рабочих процессов.

Реализация#

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

Импорт библиотек#

Список ключевых импортов, которые потребуются:

import os
import json
from typing import Annotated, TypedDict
from dotenv import load_dotenv
from langchain.embeddings import OpenAIEmbeddings
from langgraph import StateGraph, tool, ToolNode, ToolMessage
from langchain.document_loaders import HuggingFaceDatasetLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.llms import ChatOpenAI
from qdrant_client import QdrantClient
from qdrant_client.http.models import VectorParams
from brave_search import BraveSearch

Настройка векторной базы данных Vector DB#

Будет использовано облако Vector DB Cloud в качестве хранилища векторов для встраивания документов. Вот как его настроить:

Шаг

Описание

1. Создайте учетную запись

Если еще нет аккаунта, перейдите на сайт Vector DB Cloud и зарегистрируйтесь

2. Настройте кластер

Войдите в аккаунт и найдите кнопку Создать новый кластер на панели инструментов. Следуйте подсказкам для настройки:
- Выберите предпочтительный регион.
- Выберите тариф бесплатного уровня для тестирования

3. Защитите детали

Когда кластер будет готов, запишите следующие детали:
- URL-адрес кластера (например, https://xxx-xxx-xxx.aws.cloud.qdrant.io)
- Ключ API

Сохраните их безопасно для дальнейшего использования!

Конфигурация API OpenAI#

Ключ API OpenAI обеспечит как генерацию вложений, так и взаимодействие с языковой моделью. Перейдите на платформу OpenAI и зарегистрируйте аккаунт. На вкладке API в профиле создайте новый ключ API. Будет использоваться модель text-embedding-3-small для вложений и GPT-4 в качестве языковой модели.

Поисковая система Brave#

Чтобы повысить возможности поиска интегрируйте поисковую систему Brave. Посетите API Brave и завершите процесс подачи заявки на доступ к API, чтобы получить ключ API. Этот ключ позволит агенту осуществлять функции веб-поиска.

Для дополнительной безопасности храните все ключи API в файле .env.

OPENAI_API_KEY = <your-openai-api-key>
QDRANT_KEY = <your-qdrant-api-key>
QDRANT_URL = <your-qdrant-url>
BRAVE_API_KEY = <your-brave-api-key>

Затем загрузите переменные среды:

load_dotenv()
qdrant_key = os.getenv("QDRANT_KEY")
qdrant_url = os.getenv("QDRANT_URL")
brave_key = os.getenv("BRAVE_API_KEY")

Обработка документов#

Перед тем, как создать агента необходимо обработать и сохранить документацию. Будет осуществляться работа с двумя наборами данных из Hugging Face: общей документацией и документацией, специфичной для Transformers.

Функция предварительной обработки документов:

def preprocess_dataset(docs_list):
    text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
        chunk_size=700,
        chunk_overlap=50,
        disallowed_special=()
    )
    doc_splits = text_splitter.split_documents(docs_list)
    return doc_splits

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

hugging_face_doc = HuggingFaceDatasetLoader("m-ric/huggingface_doc","text")
transformers_doc = HuggingFaceDatasetLoader("m-ric/transformers_documentation_en","text")

В данном демо выберите первые 50 документов из набора данных и передаем их в функцию обработки.

hf_splits = preprocess_dataset(hugging_face_doc.load()[:number_of_docs])
transformer_splits = preprocess_dataset(transformers_doc.load()[:number_of_docs])

Разделы готовы. Создайте коллекцию в Vector DB для их хранения.

Определение состояния#

В LangGraph состояние (state) относится к данным или информации, сохраняемым и поддерживаемым в определенный момент времени в ходе выполнения процесса или серии операций. Состояния фиксируют промежуточные или окончательные результаты, которые система должна отслеживать для управления и контроля потока задач.

LangGraph работает с системой, основанной на состояниях. Определите состояние следующим образом:

class State(TypedDict):
    messages: Annotated[list, add_messages]

Создание инструментов#

Агент оснащен тремя мощными инструментами:

  1. Извлекатель документации Hugging Face

  2. Извлекатель документации Transformers

  3. Инструмент веб-поиска

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

def create_retriever(collection_name, doc_splits):
    vectorstore = QdrantVectorStore.from_documents(
        doc_splits,
        OpenAIEmbeddings(model="text-embedding-3-small"),
        url=qdrant_url,
        api_key=qdrant_key,
        collection_name=collection_name,
    )
    return vectorstore.as_retriever()

Оба извлекателя документации Hugging Face и Transformers используют эту одну и ту же функцию. При такой настройке очень легко создавать отдельные инструменты для каждого.

hf_retriever_tool = create_retriever_tool(
    hf_retriever,
    "retriever_hugging_face_documentation",
    "Search and return information about hugging face documentation, it includes the guide and Python code.",
)

transformer_retriever_tool = create_retriever_tool(
    transformer_retriever,
    "retriever_transformer",
    "Search and return information specifically about transformers library",
)

Для веб-поиска создается простой, но эффективный инструмент с использованием Brave Search:

@tool("web_search_tool")
def search_tool(query):
    search = BraveSearch.from_api_key(api_key=brave_key, search_kwargs={"count": 3})
    return search.run(query)

Функция search_tool использует API BraveSearch для выполнения поиска. Она принимает запрос, получает три лучших результата поиска с помощью ключа API и возвращает результаты.

Далее настройте и объедините инструменты с языковой моделью:

tools = [hf_retriever_tool, transformer_retriever_tool, search_tool]

tool_node = ToolNode(tools=tools)

llm = ChatOpenAI(model="gpt-4o", temperature=0)

llm_with_tools = llm.bind_tools(tools)

Здесь класс ToolNode управляет и координирует инструменты:

class ToolNode:
    def __init__(self, tools: list) -> None:
        self.tools_by_name = {tool.name: tool for tool in tools}

    def __call__(self, inputs: dict):
        if messages := inputs.get("messages", []):
            message = messages[-1]
        else:
            raise ValueError("No message found in input")

        outputs = []
        for tool_call in message.tool_calls:
            tool_result = self.tools_by_name[tool_call["name"]].invoke(
                tool_call["args"]
            )
            outputs.append(
                ToolMessage(
                    content=json.dumps(tool_result),
                    name=tool_call["name"],
                    tool_call_id=tool_call["id"],
                )
            )

        return {"messages": outputs}

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

Маршрутизация и принятие решений#

Агенту нужно определить, когда использовать инструменты, и когда завершить цикл. Это решение управляется функцией маршрутизации:

def route(state: State):
    if isinstance(state, list):
        ai_message = state[-1]
    elif messages := state.get("messages", []):
        ai_message = messages[-1]
    else:
        raise ValueError(f"No messages found in input state to tool_edge: {state}")

    if hasattr(ai_message, "tool_calls") and len(ai_message.tool_calls) > 0:
        return "tools"

    return END

Собираем все вместе: граф#

Постройте граф, объединяющий все:

graph_builder = StateGraph(State)

graph_builder.add_node("agent", agent)
graph_builder.add_node("tools", tool_node)

graph_builder.add_conditional_edges(
    "agent",
    route,
    {"tools": "tools", END: END},
)

graph_builder.add_edge("tools", "agent")
graph_builder.add_edge(START, "agent")

Agentic RAG c LangGraph будет выглядеть так:

image2

Запуск агента#

Теперь, когда все настроено, можно запустить агента с помощью простой функции:

def run_agent(user_input: str):
    for event in graph.stream({"messages": [("user", user_input)]}):
        for value in event.values():
            print("Assistant:", value["messages"][-1].content)

Теперь можно задать вопросы о Hugging Face и Transformers! Агент интеллектуально объединяет информацию из документации с результатами веб-поиска при необходимости.

Например, можно спросить:

In the Transformers library, are there any multilingual models?

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

Примерно вот какой может получиться реакция:

Yes, the Transformers library includes several multilingual models. Here are some examples:

BERT Multilingual: 
Models like `bert-base-multilingual-uncased` can be used just like monolingual models.

XLM (Cross-lingual Language Model): 
Models like `xlm-mlm-ende-1024` (English-German), `xlm-mlm-enfr-1024` (English-French), and others use language embeddings to specify the language used at inference.

M2M100: 
Models like `facebook/m2m100_418M` and `facebook/m2m100_1.2B` are used for multilingual translation.

MBart: 
Models like `facebook/mbart-large-50-one-to-many-mmt` and `facebook/mbart-large-50-many-to-many-mmt` are used for multilingual machine translation across 50 languages.

These models are designed to handle multiple languages and can be used for tasks like translation, classification, and more.

Заключение#

Успешно внедрена Agentic RAG.

Agentic RAG меняет способ подключения источников данных к искусственному интеллекту, позволяя вести более разумные и динамичные взаимодействия. В этом руководстве подробно описано, как построить систему Agentic RAG, сочетающую силу LangGraph, Vector DB и веб-поиска в одном плавном рабочем процессе.

Эта система не ограничивается простым извлечением актуальной информации из документации Hugging Face и Transformers. Она также умело прибегает к веб-поиску при необходимости, гарантируя, что ни один запрос не останется без ответа. Используя Vector DB в качестве основы векторной базы данных, получаете быстрый, масштабируемый семантический поиск, превосходно справляющийся с извлечением точной информации даже из огромных наборов данных.