Osmi
Использование OSMI-AI

База документов

Храните и обновляйте корпоративные документы для использования в RAG-сценариях

База документов в OSMI-AI — это гибкий подход к управлению данными: вы можете загрузить, разделять и подготовлять ваш набор данных, а также производить его вставку (upsert) в одном месте.

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

Настройка

В этом руководстве мы настроим систему Retrieval Augmented Generation (RAG) для получения информации о LibertyGuard Deluxe Homeowners Policy, теме, по которой модели языковая модель (LLM) не обучались должным образом. Используя OSMI-AI базу документов, мы подготовим и обновим данные о LibertyGuard и его продуктах. Это позволит нашей RAG-системе точно отвечать на вопросы пользователей о страховых продуктах LibertyGuard.

1. Добавьте базу документов

Начните с добавления базы документов и задайте ему имя. В нашем случае — «LibertyGuard Deluxe Homeowners Policy».

2. Выберите загрузчик документов

Перейдите в только что созданную базу документов и выберите загрузчик документов, который вы хотите использовать. В нашем случае, так как наш набор данных представлен в формате PDF, мы будем использовать PDF Loader. Document Loaders — это специализированные узлы, которые обрабатывают загрузку различных форматов документов.

3. Подготовьте данные

Шаг 1: Загрузчик документов

  • Загрузите PDF-файл..
  • Добавьте уникальный ключ метаданных. Это необязательно, но хорошая практика, так как позволяет в будущем фильтровать и управлять этим набором данных при необходимости.
  • Каждый загрузчик имеет преднастроенные метаданные; при необходимости можно использовать Omit Metadata Keys, чтобы удалить лишние ключи.

Шаг 2: Разделитель текста

  • Выберите разделитель текста, который вы хотите использовать для разбиения данных на фрагменты. В нашем конкретном случае мы будем использовать рекурсивный разделитель текста по символам.
  • Разделитель текста используется для разбиения загруженных документов на более мелкие части, документы или фрагменты. Это важный этап предварительной обработки по 2 основным причинам:
    • Скорость и релевантность извлечения: Хранение и запрос больших документов как единого объекта в векторной БД ведёт к медленным запросам и менее релевантным результатам. Разбиение на меньшие чанки даёт прицельное извлечение и ускоряет ответы, повышая точность.
    • Снижение стоимости: Мы извлекаем только релевантные чанки, а не весь документ, поэтому БЯМ обрабатывает существенно меньше токенов. Это напрямую уменьшает стоимость (биллинг обычно по токенам) и снижает объём нерелевантной информации, отправляемой в БЯМ.

Стратегии разбиения текста:

  • Разбиение по символам: разделение текста на фрагменты фиксированного количества символов.Простая методика, но возможен разрыв слов или фраз, что может усложнить понимание.
  • Разбиение по токенам: сегментация текста с учетом границ слов или токенов, что позволяет сохранять смысл и структуру.
  • Рекурсивное разбиение по символам: стратегия направлена на разделение текста на фрагменты, которые сохраняют семантическую связность, оставаясь при этом в пределах заданного размера. Она особенно хорошо подходит для иерархических документов с вложенными разделами или заголовками. Вместо того чтобы слепо разделять по пределу символов, она рекурсивно анализирует текст, чтобы найти логические точки разрыва, такие как окончания предложений или разрывы разделов. Этот подход гарантирует, что каждый фрагмент представляет собой значимую единицу информации, даже если он немного превышает целевой размер.
  • Разделитель текста Markdown разработан специально для документов в формате Markdown, этот разделитель логически сегментирует текст на основе заголовков Markdown и структурных элементов, создавая фрагменты, которые соответствуют логическим разделам в документе.
  • Разделитель кода: стратегия, разработанная для разделения файлов кода, учитывает структуру кода, определения функций и другие элементы, специфичные для языка программирования, для создания значимых фрагментов, подходящих для таких задач, как поиск кода и документация.
  • Разделитель HTML-в-Markdown: сначала преобразует содержимое HTML в Markdown, а затем применяет разделитель текста Markdown, что позволяет структурированно сегментировать веб-страницы и другие документы HTML.

Параметры настройки:

  • Размер фрагмента — максимальный размер чанка (в символах или токенах).
  • Перекрытие фрагментов — перекрытие между соседними чанками (символы/токены) для сохранения контекста.

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

4. Предпросмотр данных

Теперь можем предварительно просмотреть, как наши данные будут разбиты на фрагменты с использованием текущей конфигурации разделителя текста; chunk_size=1500 и chunk_overlap=750.

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

Обратите внимание, что в каждый фрагмент добавлены пользовательские метаданные – company: "liberty". Эти метаданные позволяют легко фильтровать и получать информацию из этого набора данных в дальнейшем, даже если вы используете тот же индекс БД вектора для других наборов данных.

Понимание перекрытия фрагментов

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

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

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

Таким образом, вводя перекрытие фрагментов на этапе разделения текста, мы повышаем способность LLM:

  1. Сохранять контекстную непрерывность: Перекрывающиеся фрагменты обеспечивают более плавный переход информации между последовательными сегментами, позволяя модели поддерживать более связное понимание текста.
  2. Повышать точность извлечения: Увеличивая вероятность захвата всей релевантной информации в целевых top K извлеченных фрагментах, перекрытие способствует более точным и контекстуально подходящим ответам.

Точность и стоимость

Чтобы оптимизировать баланс между точностью поиска и затратами, можно использовать два основных подхода:

  1. Регулировать перекрытие фрагментов: настройка процента перекрытия во время разбиения текста позволяет контролировать объем общего контекста. Чем выше перекрытие, тем лучше сохранение контекста, но это увеличивает затраты, поскольку требуется больше фрагментов (узлов). Более низкое перекрытие уменьшает затраты, но может привести к потере важной информации и менее точным ответам.
  2. Регулировать значение top K: увеличение числа фрагментов (например, с 4 до большего значения) повышает точность за счет учета большего объема данных, но увеличивает и стоимость.

Совет: оптимальные значения перекрытия и top K зависят от сложности документов, характеристик модели векторных представлений и желаемого баланса между точностью и затратами. Эксперименты с разными настройками помогут найти лучшую конфигурацию для ваших целей.

5. Обработка данных

Когда вы будете удовлетворены результатами разбиения, можно переходить к обработке данных.

После обработки данных у вас сохраняется возможность доработать отдельные фрагменты, удаляя или добавляя содержимое. Такой детальный контроль даёт несколько преимуществ:

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

6. Настройка процесса обновления

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

Процесс обновления включает три основных этапа:

  1. Создание векторных представлений: сначала мы выбираем подходящую модель для создания векторных представлений, которая преобразует наш набор данных в числовые векторы.
  2. БД векторы: затем определяем, в каком БД векторе будет храниться наш набор данных.
  3. Менеджер записей (опционально): наконец, при необходимости можно внедрить менеджер записей — компонент, обеспечивающий функции управления набором данных внутри БД вектора.

Шаг 1: Выбор векторизации

Нажмите на карточку «Выбрать векторизации» и выберите предпочитаемую модель векторизации. В нашем случае мы выберем OpenAI как поставщика векторизации и используем модель text-embedding-ada-002 с размерностью 1536.

Векторизация — это процесс преобразования текста в числовое представление, которое отражает его смысл. Такое числовое представление, или вектор векторизации, представляет собой многомерный массив чисел, где каждая размерность соответствует определённому аспекту смысла текста.

Эти векторы позволяют LLM сравнивать и искать похожие фрагменты текста в БД векторе, измеряя расстояние или сходство между ними в этом многомерном пространстве.

Понимание размерности векторизации и БД вектора

Количество размерностей в индексе БД вектора определяется используемой моделью векторизации при обновлении данных, и наоборот. Каждая размерность отражает определённую особенность или концепцию в данных — например, тему, эмоциональную окраску или другой аспект текста.

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

Как правило, большее количество размерностей требует больше ресурсов для хранения, обработки и сравнения векторов векторизации. Например, модель Google embedding-001 с 768 размерностями в теории обходится дешевле, чем OpenAI text-embedding-3-large с 3072 размерностями.

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

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

Шаг 2: Выбор БД вектора

Нажмите на карточку «Выбрать БД вектор» и выберите предпочитаемую базу документов. В нашем случае, так как нам нужна готовая к использованию в продакшене опция, мы выберем Upstash.

БД вектор — это специальный тип базы данных, предназначенный для хранения векторных векторизаций. Мы можем настроить параметры, например «top K», который определяет максимальное количество наиболее похожих фрагментов, извлекаемых из БД вектора в ответ на запрос.

Меньшее значение top K выдаст меньше результатов, но, возможно, более релевантных, в то время как большее значение вернёт более широкий спектр результатов, потенциально охватывая больше информации.

Шаг 3: Выбор менеджера записей

Менеджер записей — это опциональный, но очень полезный элемент процесса обновления. Он позволяет вести учёт всех фрагментов, добавленных в БД векторов, что даёт возможность эффективно добавлять или удалять фрагменты по мере необходимости.

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

Подробные инструкции по настройке и использованию этой функции доступны в отдельном руководстве.

7. Загрузка данных в БД векторов

Для начала процесса обновления и передачи данных в БД векторов нажмите кнопку «Обновить».

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

8. Протестируйте свой набор данных.

Чтобы быстро проверить функциональность вашего набора данных, не покидая базы документов, просто используйте кнопку "Запрос на извлечение". Это инициирует тестовый запрос, позволяя вам проверить точность и эффективность процесса извлечения данных.

В нашем случае, при запросе информации о покрытии напольного покрытия на кухне в нашей страховой полисе, мы получаем 4 релевантных фрагмента из Upstash, выбранного нами БД векторов. Извлечение ограничено 4 фрагментами в соответствии с заданным параметром «top k», что позволяет получать наиболее актуальную информацию без лишних повторов.

9. Проверьте работу вашего RAG

Наконец, наша система Retrieval-Augmented Generation (RAG) запущена в работу. Стоит отметить, как эффективно Large Language Model (LLM) интерпретирует запрос и успешно использует релевантную информацию из разбитых данных для создания полноценного ответа.

Мульти агенты

С помощью узла агента вы можете добавить базу документов:

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

Агенты

Вы можете использовать ранее сконфигурированное БД векторов:

Или же используйте базу документов (Vector):

10. API

Доступны API для создания, обновления и удаления базу документов. Ниже — два самых востребованных: Upsert и Refresh.

Также предусмотрена поддержка API для создания, обновления и удаления базы документов. В этом разделе мы выделим два наиболее часто используемых API:

  • Upsert
  • Refresh

Для деталей смотрите ссылку на API справочник по базе документов.

Upsert API

Есть несколько сценариев upsert — у каждого свой результат.

Сценарий 1

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

docId — это идентификатор существующего загрузчика документов. Обязателен в теле запроса.

import requests
import json

DOC_STORE_ID = "your_doc_store_id"
DOC_LOADER_ID = "your_doc_loader_id"
API_URL = f"http://localhost:3000/api/v1/document-store/upsert/{DOC_STORE_ID}"
API_KEY = "your_api_key_here"

form_data = {
    "files": ('my-another-file.pdf', open('my-another-file.pdf', 'rb'))
}

body_data = {
    "docId": DOC_LOADER_ID
}

headers = {
    "Authorization": f"Bearer {BEARER_TOKEN}"
}

def query(form_data):
    response = requests.post(API_URL, files=form_data, data=body_data, headers=headers)
    print(response)
    return response.json()

output = query(form_data)
print(output)
const DOC_STORE_ID = "your_doc_store_id"
const DOC_LOADER_ID = "your_doc_loader_id"

let formData = new FormData();
formData.append("files", input.files[0]);
formData.append("docId", DOC_LOADER_ID)

async function query(formData) {
    const response = await fetch(
        `http://localhost:3000/api/v1/document-store/upsert/${DOC_STORE_ID}`,
        {
            method: "POST",
            headers: {
                "Authorization": "Bearer <your_api_key_here>"
            },
            body: formData
        }
    );
    const result = await response.json();
    return result;
}

query(formData).then((response) => {
    console.log(response);
});

Сценарий 2

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

В теле запроса для этого сценария обязательно должны быть указаны docId и replaceExisting.

import requests
import json

DOC_STORE_ID = "your_doc_store_id"
DOC_LOADER_ID = "your_doc_loader_id"
API_URL = f"http://localhost:3000/api/v1/document-store/upsert/{DOC_STORE_ID}"
API_KEY = "your_api_key_here"

form_data = {
    "files": ('my-another-file.pdf', open('my-another-file.pdf', 'rb'))
}

body_data = {
    "docId": DOC_LOADER_ID,
    "replaceExisting": True
}

headers = {
    "Authorization": f"Bearer {BEARER_TOKEN}"
}

def query(form_data):
    response = requests.post(API_URL, files=form_data, data=body_data, headers=headers)
    print(response)
    return response.json()

output = query(form_data)
print(output)
const DOC_STORE_ID = "your_doc_store_id";
const DOC_LOADER_ID = "your_doc_loader_id";

let formData = new FormData();
formData.append("files", input.files[0]);
formData.append("docId", DOC_LOADER_ID);
formData.append("replaceExisting", true);

async function query(formData) {
    const response = await fetch(
        `http://localhost:3000/api/v1/document-store/upsert/${DOC_STORE_ID}`,
        {
            method: "POST",
            headers: {
                "Authorization": "Bearer <your_api_key_here>"
            },
            body: formData
        }
    );
    const result = await response.json();
    return result;
}

query(formData).then((response) => {
    console.log(response);
});

Сценарий 3

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

Для этого сценария в теле запроса обязательно должны быть указаныloader, splitter, embedding, vectorStore . recordManager является необязательным.

import requests
import json

DOC_STORE_ID = "your_doc_store_id"
API_URL = f"http://localhost:3000/api/v1/document-store/upsert/{DOC_STORE_ID}"
API_KEY = "your_api_key_here"

form_data = {
    "files": ('my-another-file.pdf', open('my-another-file.pdf', 'rb'))
}

loader = {
    "name": "pdfFile",
    "config": {} # you can leave empty to use default config
}

splitter = {
    "name": "recursiveCharacterTextSplitter",
    "config": {
        "chunkSize": 1400,
        "chunkOverlap": 100
    }
}

embedding = {
    "name": "openAIEmbeddings",
    "config": {
        "modelName": "text-embedding-ada-002",
        "credential": <your_credential_id>
    }
}

vectorStore = {
    "name": "pinecone",
    "config": {
        "pineconeIndex": "exampleindex",
        "pineconeNamespace": "examplenamespace",
        "credential":  <your_credential_i
    }
}

body_data = {
    "docId": DOC_LOADER_ID,
    "loader": json.dumps(loader),
    "splitter": json.dumps(splitter),
    "embedding": json.dumps(embedding),
    "vectorStore": json.dumps(vectorStore)
}

headers = {
    "Authorization": f"Bearer {BEARER_TOKEN}"
}

def query(form_data):
    response = requests.post(API_URL, files=form_data, data=body_data, headers=headers)
    print(response)
    return response.json()

output = query(form_data)
print(output)
const DOC_STORE_ID = "your_doc_store_id";
const API_URL = `http://localhost:3000/api/v1/document-store/upsert/${DOC_STORE_ID}`;
const API_KEY = "your_api_key_here";

const formData = new FormData();
formData.append("files", new Blob([await (await fetch('my-another-file.pdf')).blob()]), "my-another-file.pdf");

const loader = {
    name: "pdfFile",
    config: {} // You can leave empty to use the default config
};

const splitter = {
    name: "recursiveCharacterTextSplitter",
    config: {
        chunkSize: 1400,
        chunkOverlap: 100
    }
};

const embedding = {
    name: "openAIEmbeddings",
    config: {
        modelName: "text-embedding-ada-002",
        credential: "your_credential_id"
    }
};

const vectorStore = {
    name: "pinecone",
    config: {
        pineconeIndex: "exampleindex",
        pineconeNamespace: "examplenamespace",
        credential: "your_credential_id"
    }
};

const bodyData = {
    docId: "DOC_LOADER_ID",
    loader: JSON.stringify(loader),
    splitter: JSON.stringify(splitter),
    embedding: JSON.stringify(embedding),
    vectorStore: JSON.stringify(vectorStore)
};

const headers = {
    "Authorization": `Bearer BEARER_TOKEN`
};

async function query() {
    try {
        const response = await fetch(API_URL, {
            method: "POST",
            headers: headers,
            body: formData
        });

        const result = await response.json();
        console.log(result);
        return result;
    } catch (error) {
        console.error("Error:", error);
    }
}

query();

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

Сценарий 4

Создание новой базы документов документов для каждого upsert.

Для этого сценария обязательно должны быть указаны createNewDocStore и docStore в теле запроса.

import requests
import json

DOC_STORE_ID = "your_doc_store_id"
DOC_LOADER_ID = "your_doc_loader_id"
API_URL = f"http://localhost:3000/api/v1/document-store/upsert/{DOC_STORE_ID}"
API_KEY = "your_api_key_here"

form_data = {
    "files": ('my-another-file.pdf', open('my-another-file.pdf', 'rb'))
}

body_data = {
    "docId": DOC_LOADER_ID,
    "createNewDocStore": True,
    "docStore": json.dumps({"name":"My NEW Doc Store"})
}

headers = {
    "Authorization": f"Bearer {BEARER_TOKEN}"
}

def query(form_data):
    response = requests.post(API_URL, files=form_data, data=body_data, headers=headers)
    print(response)
    return response.json()

output = query(form_data)
print(output)
const DOC_STORE_ID = "your_doc_store_id";
const DOC_LOADER_ID = "your_doc_loader_id";

let formData = new FormData();
formData.append("files", input.files[0]);
formData.append("docId", DOC_LOADER_ID);
formData.append("createNewDocStore", true);
formData.append("docStore", JSON.stringify({ "name": "My NEW Doc Store" }));

async function query(formData) {
    const response = await fetch(
        `http://localhost:3000/api/v1/document-store/upsert/${DOC_STORE_ID}`,
        {
            method: "POST",
            headers: {
                "Authorization": "Bearer <your_api_key_here>"
            },
            body: formData
        }
    );
    const result = await response.json();
    return result;
}

query(formData).then((response) => {
    console.log(response);
});

Вопрос: Где найти ID базы документов и ID загрузчика документов?

Ответ: Их можно найти в URL.

Вопрос: Где можно найти доступные настройки, которые можно переопределить?

Ответ: Такие настройки доступны через кнопку "View API" (Просмотр API) для каждого загрузчика документов.

При каждом upsert участвуют 5 элементов:

  • loader(загрузчик)
  • splitter (разделитель)
  • embedding (встроение)
  • vectorStore (БД векторов)
  • recordManager (менеджер записей)

Вы можете переопределить существующую конфигурацию, отправив соответствующие параметры в теле элемента. Например, с помощью приведенного выше скриншота можно создать новый загрузчик документов с новым URL

import requests

API_URL = "http://localhost:3000/api/v1/document-store/upsert/<storeId>"

def query(payload):
    response = requests.post(API_URL, json=payload)
    return response.json()

output = query({
    "docId": <docLoaderId>,
    # override existing configuration
    "loader": {
        "config": {
            "url": "https://new-url.com"
        }
    }
})
print(output)
async function query(data) {
    const response = await fetch(
        "http://localhost:3000/api/v1/document-store/upsert/<storeId>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(data)
        }
    );
    const result = await response.json();
    return result;
}

query({
    "docId": <docLoaderId>,
    "loader": {
        "config": {
            "url": "https://new-url.com"
        }
    }
}).then((response) => {
    console.log(response);
});

Что делать, если у loader есть загрузка файла? Нужно использовать данные формы (Form Data) в теле запроса.

Приведем пример, как переопределить параметр использования PDF-загрузчика, используя изображение ниже:

import requests
import json

API_URL = "http://localhost:3000/api/v1/document-store/upsert/<storeId>"
API_KEY = "your_api_key_here"

form_data = {
    "files": ('my-another-file.pdf', open('my-another-file.pdf', 'rb'))
}

override_loader_config = {
    "config": {
        "usage": "perPage"
    }
}

body_data = {
    "docId": <docLoaderId>,
    "loader": json.dumps(override_loader_config) # Override existing configuration
}

headers = {
    "Authorization": f"Bearer {BEARER_TOKEN}"
}

def query(form_data):
    response = requests.post(API_URL, files=form_data, data=body_data, headers=headers)
    print(response)
    return response.json()

output = query(form_data)
print(output)
const DOC_STORE_ID = "your_doc_store_id";
const DOC_LOADER_ID = "your_doc_loader_id";

const overrideLoaderConfig = {
    "config": {
        "usage": "perPage"
    }
}

let formData = new FormData();
formData.append("files", input.files[0]);
formData.append("docId", DOC_LOADER_ID);
formData.append("loader", JSON.stringify(overrideLoaderConfig));

async function query(formData) {
    const response = await fetch(
        `http://localhost:3000/api/v1/document-store/upsert/${DOC_STORE_ID}`,
        {
            method: "POST",
            headers: {
                "Authorization": "Bearer <your_api_key_here>"
            },
            body: formData
        }
    )
    const result = await response.json();
    return result;
}

query(formData).then((response) => {
    console.log(response);
});

Вопрос: Когда использовать Form Data, а когда — JSON в теле API-запроса?

Ответ: Для загрузчиков документов с функцией загрузки файлов, таких как PDF, DOCX, TXT и др., тело запроса должно передаваться в формате Form Data.

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

Например, если используется PDF-загрузчик, следует отправлять только файлы с расширением .pdf. Чтобы избежать необходимости создавать отдельные загрузчики для разных типов файлов, рекомендуется использовать универсальный загрузчик файлов

import requests
import json

API_URL = "http://localhost:3000/api/v1/document-store/upsert/<storeId>"

# use form data to upload files
form_data = {
    "files": ('my-another-file.pdf', open('my-another-file.pdf', 'rb'))
}

body_data = {
    "docId": <docId>
}

def query(form_data):
    response = requests.post(API_URL, files=form_data, data=body_data)
    print(response)
    return response.json()

output = query(form_data)
print(output)
let formData = new FormData();
formData.append("files", input.files[0]);
formData.append("docId", <docId>);

async function query(formData) {
    const response = await fetch(
        "http://localhost:3000/api/v1/document-store/upsert/<storeId>",
        {
            method: "POST",
            body: formData
        }
    );
    const result = await response.json();
    return result;
}

query(formData).then((response) => {
    console.log(response);
});

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

import requests

API_URL = "http://localhost:3000/api/v1/document-store/upsert/<storeId>"

def query(payload):
    response = requests.post(API_URL, json=payload)
    return response.json()

output = query({
    "docId": <docId>
})
print(output)
async function query(data) {
    const response = await fetch(
        "http://localhost:3000/api/v1/document-store/upsert/<storeId>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(data)
        }
    );
    const result = await response.json();
    return result;
}

query({
    "docId": <docId>
}).then((response) => {
    console.log(response);
});

Вопрос: Можно ли добавить новые метаданные?

Ответ: Да, вы можете передать новые метаданные внутри тела запроса, указав их в соответствующем поле metadata.

{
    "docId": <doc-id>,
    "metadata": {
        "source: "abc"
    }
}

API для обновления (Refresh API)

Часто бывает необходимо повторно обработать все загрузчики документов внутри базы, чтобы получить актуальные данные, и выполнить upsert в БД векторов, чтобы всё было синхронизировано. Это можно сделать с помощью API Refresh.

import requests

API_URL = "http://localhost:3000/api/v1/document-store/refresh/<storeId>"

def query():
    response = requests.post(API_URL)
    return response.json()

output = query()
print(output)
async function query(data) {
    const response = await fetch(
        "http://localhost:3000/api/v1/document-store/refresh/<storeId>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            }
        }
    );
    const result = await response.json();
    return result;
}

query().then((response) => {
    console.log(response);
});

Вы также можете переопределить существующую конфигурацию конкретного загрузчика документов:

import requests

API_URL = "http://localhost:3000/api/v1/document-store/refresh/<storeId>"

def query(payload):
    response = requests.post(API_URL, json=payload)
    return response.json()

output = query(
{
    "items": [
        {
            "docId": <docId>,
            "splitter": {
                "name": "recursiveCharacterTextSplitter",
                "config": {
                    "chunkSize": 2000,
                    "chunkOverlap": 100
                }
            }
        }
    ]
}
)
print(output)
async function query(data) {
    const response = await fetch(
        "http://localhost:3000/api/v1/document-store/refresh/<storeId>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(data)
        }
    );
    const result = await response.json();
    return result;
}

query({
    "items": [
        {
            "docId": <docId>,
            "splitter": {
                "name": "recursiveCharacterTextSplitter",
                "config": {
                    "chunkSize": 2000,
                    "chunkOverlap": 100
                }
            }
        }
    ]
}).then((response) => {
    console.log(response);
});

11. Резюме

Мы начали с создания базы документов для организации данных по страховой полису LibertyGuard Deluxe Homeowners. Затем эти данные были подготовлены — загружены, разбиты на части, обработаны и загружены (upsert), чтобы они были готовы к использованию в нашей системе RAG.

Преимущества базы документов: Баз документов дают несколько ключевых преимуществ для управления и подготовки данных в системах Retrieval Augmented Generation (RAG): - Организация и управление: обеспечивают централизованное место для хранения, управления и подготовки данных. - Качество данных: процесс разбиения (chunking) структурирует данные для точного поиска и анализа. - Гибкость: позволяют уточнять и корректировать данные по мере необходимости, что повышает точность и релевантность вашей RAG-системы.