mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-08 04:42:11 +02:00
add final docs
Signed-off-by: Alex Jenkins <kjenkins60@gatech.edu>
This commit is contained in:
parent
16c2f12a54
commit
9927022982
16 changed files with 5437 additions and 221 deletions
471
docs/tech-specs/tool-services.ru.md
Normal file
471
docs/tech-specs/tool-services.ru.md
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
# Сервисы инструментов: Динамически подключаемые инструменты для агентов
|
||||
|
||||
## Статус
|
||||
|
||||
Реализовано
|
||||
|
||||
## Обзор
|
||||
|
||||
Эта спецификация определяет механизм динамически подключаемых инструментов для агентов, называемых "сервисами инструментов". В отличие от существующих встроенных типов инструментов (`KnowledgeQueryImpl`, `McpToolImpl` и т.д.), сервисы инструментов позволяют добавлять новые инструменты путем:
|
||||
|
||||
1. Развертывания нового сервиса на базе Pulsar
|
||||
2. Добавления описания конфигурации, которое сообщает агенту, как его вызывать
|
||||
|
||||
Это обеспечивает расширяемость без изменения основной структуры агента.
|
||||
|
||||
## Терминология
|
||||
|
||||
| Термин | Определение |
|
||||
|------|------------|
|
||||
| **Встроенный инструмент** | Существующие типы инструментов с жестко закодированными реализациями в `tools.py` |
|
||||
| **Сервис инструмента** | Сервис Pulsar, который может быть вызван как инструмент для агента, определенный описанием сервиса |
|
||||
| **Инструмент** | Настроенный экземпляр, который ссылается на сервис инструмента и предоставляется агенту/LLM |
|
||||
|
||||
Это двухзвенная модель, аналогичная инструментам MCP:
|
||||
MCP: MCP-сервер определяет интерфейс инструмента → Конфигурация инструмента ссылается на него
|
||||
Сервисы инструментов: Сервис инструмента определяет интерфейс Pulsar → Конфигурация инструмента ссылается на него
|
||||
|
||||
## Обзор: Существующие инструменты
|
||||
|
||||
### Реализация встроенного инструмента
|
||||
|
||||
Инструменты в настоящее время определены в `trustgraph-flow/trustgraph/agent/react/tools.py` с типизированными реализациями:
|
||||
|
||||
```python
|
||||
class KnowledgeQueryImpl:
|
||||
async def invoke(self, question):
|
||||
client = self.context("graph-rag-request")
|
||||
return await client.rag(question, self.collection)
|
||||
```
|
||||
|
||||
Каждый тип инструмента:
|
||||
Имеет жестко заданный сервис Pulsar, к которому он обращается (например, `graph-rag-request`)
|
||||
Знает точный метод, который нужно вызвать у клиента (например, `client.rag()`)
|
||||
Имеет типизированные аргументы, определенные в реализации
|
||||
|
||||
### Регистрация инструментов (service.py:105-214)
|
||||
|
||||
Инструменты загружаются из конфигурации с помощью поля `type`, которое сопоставляется с реализацией:
|
||||
|
||||
```python
|
||||
if impl_id == "knowledge-query":
|
||||
impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection"))
|
||||
elif impl_id == "text-completion":
|
||||
impl = TextCompletionImpl
|
||||
# ... etc
|
||||
```
|
||||
|
||||
## Архитектура
|
||||
|
||||
### Двухуровневая модель
|
||||
|
||||
#### Уровень 1: Описание сервиса инструмента
|
||||
|
||||
Сервис инструмента определяет интерфейс сервиса Pulsar. Он объявляет:
|
||||
Очереди Pulsar для запросов/ответов
|
||||
Параметры конфигурации, которые он требует от инструментов, использующих его
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "custom-rag",
|
||||
"request-queue": "non-persistent://tg/request/custom-rag",
|
||||
"response-queue": "non-persistent://tg/response/custom-rag",
|
||||
"config-params": [
|
||||
{"name": "collection", "required": true}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Сервис, который не требует параметров конфигурации:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "calculator",
|
||||
"request-queue": "non-persistent://tg/request/calc",
|
||||
"response-queue": "non-persistent://tg/response/calc",
|
||||
"config-params": []
|
||||
}
|
||||
```
|
||||
|
||||
#### Уровень 2: Описание инструмента
|
||||
|
||||
Инструмент ссылается на сервис инструмента и предоставляет:
|
||||
Значения параметров конфигурации (соответствующие требованиям сервиса)
|
||||
Метаданные инструмента для агента (название, описание)
|
||||
Определения аргументов для LLM
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "query-customers",
|
||||
"description": "Query the customer knowledge base",
|
||||
"service": "custom-rag",
|
||||
"collection": "customers",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "question",
|
||||
"type": "string",
|
||||
"description": "The question to ask about customers"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Несколько инструментов могут ссылаться на один и тот же сервис с разными конфигурациями:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "query-products",
|
||||
"description": "Query the product knowledge base",
|
||||
"service": "custom-rag",
|
||||
"collection": "products",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "question",
|
||||
"type": "string",
|
||||
"description": "The question to ask about products"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Формат запроса
|
||||
|
||||
Когда вызывается инструмент, запрос к службе инструмента включает в себя:
|
||||
`user`: Из запроса агента (многопользовательский режим)
|
||||
`config`: Значения конфигурации, закодированные в формате JSON, из описания инструмента
|
||||
`arguments`: Аргументы, закодированные в формате JSON, из LLM
|
||||
|
||||
```json
|
||||
{
|
||||
"user": "alice",
|
||||
"config": "{\"collection\": \"customers\"}",
|
||||
"arguments": "{\"question\": \"What are the top customer complaints?\"}"
|
||||
}
|
||||
```
|
||||
|
||||
Сервис инструментов получает это в виде разобранных словарей в методе `invoke`.
|
||||
|
||||
### Общая реализация сервиса инструментов
|
||||
|
||||
Класс `ToolServiceImpl` вызывает сервисы инструментов на основе конфигурации:
|
||||
|
||||
```python
|
||||
class ToolServiceImpl:
|
||||
def __init__(self, context, request_queue, response_queue, config_values, arguments, processor):
|
||||
self.request_queue = request_queue
|
||||
self.response_queue = response_queue
|
||||
self.config_values = config_values # e.g., {"collection": "customers"}
|
||||
# ...
|
||||
|
||||
async def invoke(self, **arguments):
|
||||
client = await self._get_or_create_client()
|
||||
response = await client.call(user, self.config_values, arguments)
|
||||
if isinstance(response, str):
|
||||
return response
|
||||
else:
|
||||
return json.dumps(response)
|
||||
```
|
||||
|
||||
## Принятые решения по проектированию
|
||||
|
||||
### Модель конфигурации с двумя уровнями
|
||||
|
||||
Сервисы инструментов следуют двухслойной модели, аналогичной инструментам MCP:
|
||||
|
||||
1. **Сервис инструмента**: Определяет интерфейс сервиса Pulsar (тема, необходимые параметры конфигурации).
|
||||
2. **Инструмент**: Ссылается на сервис инструмента, предоставляет значения конфигурации, определяет аргументы LLM.
|
||||
|
||||
Это разделение позволяет:
|
||||
Использовать один сервис инструмента несколькими инструментами с разными конфигурациями.
|
||||
Четко различать интерфейс сервиса и конфигурацию инструмента.
|
||||
Повторное использование определений сервисов.
|
||||
|
||||
### Отображение запросов: Прямая передача с оболочкой
|
||||
|
||||
Запрос к сервису инструмента представляет собой структурированную оболочку, содержащую:
|
||||
`user`: Передается из запроса агента для поддержки многопользовательской среды.
|
||||
Значения конфигурации: Из описателя инструмента (например, `collection`).
|
||||
`arguments`: Аргументы, предоставленные LLM, передаются в виде словаря.
|
||||
|
||||
Менеджер агента анализирует ответ LLM в `act.arguments` в виде словаря (`agent_manager.py:117-154`). Этот словарь включается в оболочку запроса.
|
||||
|
||||
### Обработка схем: Без типов
|
||||
|
||||
Запросы и ответы используют нетипизированные словари. Отсутствует проверка схемы на уровне агента - сервис инструмента отвечает за проверку своих входных данных. Это обеспечивает максимальную гибкость при определении новых сервисов.
|
||||
|
||||
### Клиентский интерфейс: Прямые темы Pulsar
|
||||
|
||||
Сервисы инструментов используют прямые темы Pulsar без необходимости настройки потоков. Описатель сервиса инструмента указывает полные имена очередей:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [...]
|
||||
}
|
||||
```
|
||||
|
||||
Это позволяет размещать сервисы в любом пространстве имен.
|
||||
|
||||
### Обработка ошибок: Стандартная конвенция для ошибок
|
||||
|
||||
Ответы сервисов инструментов соответствуют существующей схеме с полем `error`:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Error:
|
||||
type: str = ""
|
||||
message: str = ""
|
||||
```
|
||||
|
||||
Структура ответа:
|
||||
Успех: `error` имеет значение `None`, ответ содержит результат
|
||||
Ошибка: `error` заполняется значениями `type` и `message`
|
||||
|
||||
Это соответствует шаблону, используемому во всех существующих схемах сервисов (например, `PromptResponse`, `QueryResponse`, `AgentResponse`).
|
||||
|
||||
### Корреляция запросов и ответов
|
||||
|
||||
Корреляция запросов и ответов осуществляется с использованием `id` в свойствах сообщения Pulsar:
|
||||
|
||||
Запрос включает `id` в свойствах: `properties={"id": id}`
|
||||
Ответы включают тот же `id`: `properties={"id": id}`
|
||||
|
||||
Это соответствует существующему шаблону, используемому во всей кодовой базе (например, `agent_service.py`, `llm_service.py`).
|
||||
|
||||
### Поддержка потоковой передачи
|
||||
|
||||
Сервисы инструментов могут возвращать потоковые ответы:
|
||||
|
||||
Несколько сообщений ответа с тем же `id` в свойствах
|
||||
Каждый ответ включает поле `end_of_stream: bool`
|
||||
Заключительный ответ имеет `end_of_stream: True`
|
||||
|
||||
Это соответствует шаблону, используемому в `AgentResponse` и других сервисах потоковой передачи.
|
||||
|
||||
### Обработка ответов: Возврат строки
|
||||
|
||||
Все существующие инструменты следуют одному и тому же шаблону: **получение аргументов в виде словаря, возврат наблюдения в виде строки**.
|
||||
|
||||
| Инструмент | Обработка ответов |
|
||||
|------|------------------|
|
||||
| `KnowledgeQueryImpl` | Возвращает `client.rag()` напрямую (строка) |
|
||||
| `TextCompletionImpl` | Возвращает `client.question()` напрямую (строка) |
|
||||
| `McpToolImpl` | Возвращает строку, или `json.dumps(output)`, если это не строка |
|
||||
| `StructuredQueryImpl` | Форматирует результат в строку |
|
||||
| `PromptImpl` | Возвращает `client.prompt()` напрямую (строка) |
|
||||
|
||||
Сервисы инструментов следуют тому же контракту:
|
||||
Сервис возвращает строковый ответ (наблюдение)
|
||||
Если ответ не является строкой, он преобразуется с помощью `json.dumps()`
|
||||
Не требуется конфигурация извлечения в дескрипторе
|
||||
|
||||
Это упрощает дескриптор и возлагает ответственность на сервис по возврату соответствующего текстового ответа для агента.
|
||||
|
||||
## Руководство по настройке
|
||||
|
||||
Для добавления нового сервиса инструмента требуются два элемента конфигурации:
|
||||
|
||||
### 1. Конфигурация сервиса инструмента
|
||||
|
||||
Хранится под ключом конфигурации `tool-service`. Определяет очереди Pulsar и доступные параметры конфигурации.
|
||||
|
||||
| Поле | Обязательно | Описание |
|
||||
|-------|----------|-------------|
|
||||
| `id` | Да | Уникальный идентификатор для сервиса инструмента |
|
||||
| `request-queue` | Да | Полная тема Pulsar для запросов (например, `non-persistent://tg/request/joke`) |
|
||||
| `response-queue` | Да | Полная тема Pulsar для ответов (например, `non-persistent://tg/response/joke`) |
|
||||
| `config-params` | Нет | Массив параметров конфигурации, которые принимает сервис |
|
||||
|
||||
Каждый параметр конфигурации может указывать:
|
||||
`name`: Имя параметра (обязательно)
|
||||
`required`: Должен ли параметр предоставляться инструментами (по умолчанию: false)
|
||||
|
||||
Пример:
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [
|
||||
{"name": "style", "required": false}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Конфигурация инструмента
|
||||
|
||||
Хранится под ключом конфигурации `tool`. Определяет инструмент, которым может пользоваться агент.
|
||||
|
||||
| Поле | Обязательно | Описание |
|
||||
|-------|----------|-------------|
|
||||
| `type` | Да | Должно быть `"tool-service"` |
|
||||
| `name` | Да | Название инструмента, доступное для LLM |
|
||||
| `description` | Да | Описание того, что делает инструмент (отображается для LLM) |
|
||||
| `service` | Да | ID сервиса инструмента, который необходимо вызвать |
|
||||
| `arguments` | Нет | Массив определений аргументов для LLM |
|
||||
| *(параметры конфигурации)* | Зависит | Любые параметры конфигурации, определенные сервисом |
|
||||
|
||||
Каждый аргумент может содержать:
|
||||
`name`: Имя аргумента (обязательно)
|
||||
`type`: Тип данных, например, `"string"` (обязательно)
|
||||
`description`: Описание, отображаемое для LLM (обязательно)
|
||||
|
||||
Пример:
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "tell-joke",
|
||||
"description": "Tell a joke on a given topic",
|
||||
"service": "joke-service",
|
||||
"style": "pun",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "topic",
|
||||
"type": "string",
|
||||
"description": "The topic for the joke (e.g., programming, animals, food)"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Загрузка конфигурации
|
||||
|
||||
Используйте `tg-put-config-item` для загрузки конфигураций:
|
||||
|
||||
```bash
|
||||
# Load tool-service config
|
||||
tg-put-config-item tool-service/joke-service < joke-service.json
|
||||
|
||||
# Load tool config
|
||||
tg-put-config-item tool/tell-joke < tell-joke.json
|
||||
```
|
||||
|
||||
Агент-менеджер должен быть перезапущен для применения новых конфигураций.
|
||||
|
||||
## Детали реализации
|
||||
|
||||
### Схема
|
||||
|
||||
Типы запросов и ответов в `trustgraph-base/trustgraph/schema/services/tool_service.py`:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ToolServiceRequest:
|
||||
user: str = "" # User context for multi-tenancy
|
||||
config: str = "" # JSON-encoded config values from tool descriptor
|
||||
arguments: str = "" # JSON-encoded arguments from LLM
|
||||
|
||||
@dataclass
|
||||
class ToolServiceResponse:
|
||||
error: Error | None = None
|
||||
response: str = "" # String response (the observation)
|
||||
end_of_stream: bool = False
|
||||
```
|
||||
|
||||
### Серверная часть: DynamicToolService
|
||||
|
||||
Базовый класс в `trustgraph-base/trustgraph/base/dynamic_tool_service.py`:
|
||||
|
||||
```python
|
||||
class DynamicToolService(AsyncProcessor):
|
||||
"""Base class for implementing tool services."""
|
||||
|
||||
def __init__(self, **params):
|
||||
topic = params.get("topic", default_topic)
|
||||
# Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic}
|
||||
# Sets up Consumer and Producer
|
||||
|
||||
async def invoke(self, user, config, arguments):
|
||||
"""Override this method to implement the tool's logic."""
|
||||
raise NotImplementedError()
|
||||
```
|
||||
|
||||
### Клиентская часть: ToolServiceImpl
|
||||
|
||||
Реализация в `trustgraph-flow/trustgraph/agent/react/tools.py`:
|
||||
|
||||
```python
|
||||
class ToolServiceImpl:
|
||||
def __init__(self, context, request_queue, response_queue, config_values, arguments, processor):
|
||||
# Uses the provided queue paths directly
|
||||
# Creates ToolServiceClient on first use
|
||||
|
||||
async def invoke(self, **arguments):
|
||||
client = await self._get_or_create_client()
|
||||
response = await client.call(user, config_values, arguments)
|
||||
return response if isinstance(response, str) else json.dumps(response)
|
||||
```
|
||||
|
||||
### Файлы
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|---------|
|
||||
| `trustgraph-base/trustgraph/schema/services/tool_service.py` | Схемы запросов/ответов |
|
||||
| `trustgraph-base/trustgraph/base/tool_service_client.py` | Клиент для вызова сервисов |
|
||||
| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | Базовый класс для реализации сервиса |
|
||||
| `trustgraph-flow/trustgraph/agent/react/tools.py` | Класс `ToolServiceImpl` |
|
||||
| `trustgraph-flow/trustgraph/agent/react/service.py` | Загрузка конфигурации |
|
||||
|
||||
### Пример: Сервис шуток
|
||||
|
||||
Пример сервиса на `trustgraph-flow/trustgraph/tool_service/joke/`:
|
||||
|
||||
```python
|
||||
class Processor(DynamicToolService):
|
||||
async def invoke(self, user, config, arguments):
|
||||
style = config.get("style", "pun")
|
||||
topic = arguments.get("topic", "")
|
||||
joke = pick_joke(topic, style)
|
||||
return f"Hey {user}! Here's a {style} for you:\n\n{joke}"
|
||||
```
|
||||
|
||||
Конфигурация сервиса инструментов:
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [{"name": "style", "required": false}]
|
||||
}
|
||||
```
|
||||
|
||||
Конфигурация инструмента:
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "tell-joke",
|
||||
"description": "Tell a joke on a given topic",
|
||||
"service": "joke-service",
|
||||
"style": "pun",
|
||||
"arguments": [
|
||||
{"name": "topic", "type": "string", "description": "The topic for the joke"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Обратная совместимость
|
||||
|
||||
Существующие встроенные типы инструментов продолжают работать без изменений.
|
||||
`tool-service` - это новый тип инструмента, который существует наряду с существующими типами (`knowledge-query`, `mcp-tool` и т.д.).
|
||||
|
||||
## Будущие соображения
|
||||
|
||||
### Сервисы с автоматическим оповещением
|
||||
|
||||
В будущем можно будет реализовать функцию, позволяющую сервисам публиковать свои собственные описания:
|
||||
|
||||
Сервисы публикуют информацию при запуске в определенной теме `tool-descriptors`.
|
||||
Агент подписывается и динамически регистрирует инструменты.
|
||||
Это обеспечивает возможность подключения и использования без изменения конфигурации.
|
||||
|
||||
Это выходит за рамки первоначальной реализации.
|
||||
|
||||
## Ссылки
|
||||
|
||||
Текущая реализация инструментов: `trustgraph-flow/trustgraph/agent/react/tools.py`
|
||||
Регистрация инструментов: `trustgraph-flow/trustgraph/agent/react/service.py:105-214`
|
||||
Схемы агента: `trustgraph-base/trustgraph/schema/services/agent.py`
|
||||
|
|
@ -6,51 +6,285 @@
|
|||
|
||||
## 概述
|
||||
|
||||
该规范定义了一种动态可插拔的代理工具机制,称为“工具服务”。 与现有的内置工具类型(如 `KnowledgeQueryImpl`、`McpToolImpl` 等),工具服务允许通过以下方式引入新的工具:
|
||||
本规范定义了一种称为“工具服务”的动态可插拔代理工具的机制。 与现有的内置工具类型(`KnowledgeQueryImpl`,`McpToolImpl`等)不同,工具服务允许通过以下方式引入新的工具:
|
||||
|
||||
1. 部署一个新的基于 Pulsar 的服务
|
||||
2. 添加一个配置描述符,告诉代理如何调用它
|
||||
1. 部署一个新的基于Pulsar的服务
|
||||
2. 添加一个配置描述符,该描述符告诉代理如何调用它
|
||||
|
||||
这使得无需修改核心 agent-react 框架即可实现扩展。
|
||||
这实现了可扩展性,而无需修改核心代理响应框架。
|
||||
|
||||
## 术语
|
||||
|
||||
| 术语 | 定义 |
|
||||
|---|---|
|
||||
| **内置工具** | 具有在 `tools.py` 中硬编码实现的现有工具类型 |
|
||||
| **工具服务** | 一个基于 Pulsar 的服务,可以被其他工具调用 |
|
||||
| **配置描述符** | 用于配置工具服务的 JSON 格式文件 |
|
||||
|------|------------|
|
||||
| **内置工具** | 具有硬编码实现的现有工具类型,位于`tools.py` |
|
||||
| **工具服务** | 可以作为代理工具调用的Pulsar服务,由服务描述符定义 |
|
||||
| **工具** | 引用工具服务的已配置实例,暴露给代理/LLM |
|
||||
|
||||
## 实现细节
|
||||
这是一个两层模型,类似于MCP工具:
|
||||
MCP:MCP服务器定义工具接口 → 工具配置引用它
|
||||
工具服务:工具服务定义Pulsar接口 → 工具配置引用它
|
||||
|
||||
### 流程
|
||||
## 背景:现有工具
|
||||
|
||||
1. **服务启动:** 服务将自身注册到 agent,包含服务名称、队列路径等信息
|
||||
2. **工具配置:** 客户端通过加载配置描述符,动态注册服务
|
||||
3. **调用服务:** 客户端使用 `ToolServiceClient` 调用服务
|
||||
### 内置工具实现
|
||||
|
||||
### 架构
|
||||
|
||||
```
|
||||
[客户端 (agent-react)] <-> [ToolServiceClient] <-> [服务 (dynamic_tool_service)] <-> [Pulsar 队列]
|
||||
```
|
||||
|
||||
### 示例
|
||||
当前,工具在`trustgraph-flow/trustgraph/agent/react/tools.py`中定义,并具有类型化的实现:
|
||||
|
||||
```python
|
||||
# 客户端 (agent-react)
|
||||
async def call_service(service_name, args):
|
||||
# 从配置中获取 service_配置
|
||||
service_config = get_config(service_name)
|
||||
# 创建 ToolServiceClient
|
||||
client = ToolServiceClient(service_config)
|
||||
# 调用服务
|
||||
response = await client.call(args)
|
||||
return response
|
||||
class KnowledgeQueryImpl:
|
||||
async def invoke(self, question):
|
||||
client = self.context("graph-rag-request")
|
||||
return await client.rag(question, self.collection)
|
||||
```
|
||||
|
||||
### 示例配置描述符
|
||||
每种工具类型:
|
||||
具有一个硬编码的 Pulsar 服务,它会调用该服务(例如:`graph-rag-request`)
|
||||
知道要调用的客户端上的确切方法(例如:`client.rag()`)
|
||||
在实现中定义了类型化的参数
|
||||
|
||||
### 工具注册 (service.py:105-214)
|
||||
|
||||
工具从配置文件中加载,其中有一个 `type` 字段,它映射到实现:
|
||||
|
||||
```python
|
||||
if impl_id == "knowledge-query":
|
||||
impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection"))
|
||||
elif impl_id == "text-completion":
|
||||
impl = TextCompletionImpl
|
||||
# ... etc
|
||||
```
|
||||
|
||||
## 架构
|
||||
|
||||
### 两层模型
|
||||
|
||||
#### 第一层:工具服务描述器
|
||||
|
||||
一个工具服务定义了 Pulsar 服务接口。它声明:
|
||||
用于请求/响应的 Pulsar 队列
|
||||
它需要的来自使用它的工具的配置参数
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "custom-rag",
|
||||
"request-queue": "non-persistent://tg/request/custom-rag",
|
||||
"response-queue": "non-persistent://tg/response/custom-rag",
|
||||
"config-params": [
|
||||
{"name": "collection", "required": true}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
一种不需要任何配置参数的工具服务:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "calculator",
|
||||
"request-queue": "non-persistent://tg/request/calc",
|
||||
"response-queue": "non-persistent://tg/response/calc",
|
||||
"config-params": []
|
||||
}
|
||||
```
|
||||
|
||||
#### 第二层:工具描述
|
||||
|
||||
一个工具引用一个工具服务,并提供:
|
||||
配置参数值(满足服务的要求)
|
||||
代理的工具元数据(名称、描述)
|
||||
LLM 的参数定义
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "query-customers",
|
||||
"description": "Query the customer knowledge base",
|
||||
"service": "custom-rag",
|
||||
"collection": "customers",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "question",
|
||||
"type": "string",
|
||||
"description": "The question to ask about customers"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
多个工具可以使用不同的配置来引用相同的服务:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "query-products",
|
||||
"description": "Query the product knowledge base",
|
||||
"service": "custom-rag",
|
||||
"collection": "products",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "question",
|
||||
"type": "string",
|
||||
"description": "The question to ask about products"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 请求格式
|
||||
|
||||
当一个工具被调用时,发送给工具服务的请求包括:
|
||||
`user`: 来自代理的请求(多租户)
|
||||
`config`: 来自工具描述的 JSON 编码的配置值
|
||||
`arguments`: 来自 LLM 的 JSON 编码的参数
|
||||
|
||||
```json
|
||||
{
|
||||
"user": "alice",
|
||||
"config": "{\"collection\": \"customers\"}",
|
||||
"arguments": "{\"question\": \"What are the top customer complaints?\"}"
|
||||
}
|
||||
```
|
||||
|
||||
工具服务接收这些数据,并将其解析为字典,在 `invoke` 方法中进行处理。
|
||||
|
||||
### 通用工具服务实现
|
||||
|
||||
一个 `ToolServiceImpl` 类根据配置调用工具服务:
|
||||
|
||||
```python
|
||||
class ToolServiceImpl:
|
||||
def __init__(self, context, request_queue, response_queue, config_values, arguments, processor):
|
||||
self.request_queue = request_queue
|
||||
self.response_queue = response_queue
|
||||
self.config_values = config_values # e.g., {"collection": "customers"}
|
||||
# ...
|
||||
|
||||
async def invoke(self, **arguments):
|
||||
client = await self._get_or_create_client()
|
||||
response = await client.call(user, self.config_values, arguments)
|
||||
if isinstance(response, str):
|
||||
return response
|
||||
else:
|
||||
return json.dumps(response)
|
||||
```
|
||||
|
||||
## 设计决策
|
||||
|
||||
### 双层配置模型
|
||||
|
||||
工具服务遵循类似于 MCP 工具的双层模型:
|
||||
|
||||
1. **工具服务 (Tool Service)**:定义 Pulsar 服务接口(主题、所需的配置参数)。
|
||||
2. **工具 (Tool)**:引用工具服务,提供配置值,定义 LLM 参数。
|
||||
|
||||
这种分离方式允许:
|
||||
一个工具服务可以被多个具有不同配置的工具使用。
|
||||
清晰区分服务接口和工具配置。
|
||||
重用服务定义。
|
||||
|
||||
### 请求映射:带外壳的透传
|
||||
|
||||
发送到工具服务的请求是一个结构化的外壳,包含:
|
||||
`user`:从代理请求中传播,用于多租户。
|
||||
配置值:来自工具描述符(例如,`collection`)。
|
||||
`arguments`:LLM 提供的参数,作为字典传递。
|
||||
|
||||
代理管理器将 LLM 的响应解析为 `act.arguments`(作为字典,`agent_manager.py:117-154`)。此字典包含在请求外壳中。
|
||||
|
||||
### 模式处理:无类型
|
||||
|
||||
请求和响应使用无类型的字典。代理级别不进行任何模式验证 - 工具服务负责验证其输入。这提供了定义新服务的最大灵活性。
|
||||
|
||||
### 客户端接口:直接 Pulsar 主题
|
||||
|
||||
工具服务使用直接的 Pulsar 主题,无需配置流。工具服务描述符指定完整的队列名称:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [...]
|
||||
}
|
||||
```
|
||||
|
||||
这允许服务在任何命名空间中被托管。
|
||||
|
||||
### 错误处理:标准错误约定
|
||||
|
||||
工具服务响应遵循现有的模式约定,包含一个 `error` 字段:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Error:
|
||||
type: str = ""
|
||||
message: str = ""
|
||||
```
|
||||
|
||||
响应结构:
|
||||
成功: `error` 为 `None`,响应包含结果
|
||||
错误: `error` 被填充为 `type` 和 `message`
|
||||
|
||||
这符合现有服务模式(例如:`PromptResponse`,`QueryResponse`,`AgentResponse`)。
|
||||
|
||||
### 请求/响应关联
|
||||
|
||||
请求和响应使用 `id` 在 Pulsar 消息属性中进行关联:
|
||||
|
||||
请求包含 `id` 在属性中:`properties={"id": id}`
|
||||
响应包含相同的 `id`:`properties={"id": id}`
|
||||
|
||||
这遵循代码库中使用的现有模式(例如:`agent_service.py`,`llm_service.py`)。
|
||||
|
||||
### 流式支持
|
||||
|
||||
工具服务可以返回流式响应:
|
||||
|
||||
具有相同 `id` 在属性中的多个响应消息
|
||||
每个响应包含 `end_of_stream: bool` 字段
|
||||
最终响应具有 `end_of_stream: True`
|
||||
|
||||
这符合 `AgentResponse` 和其他流式服务中使用的模式。
|
||||
|
||||
### 响应处理:字符串返回
|
||||
|
||||
所有现有工具都遵循相同的模式:**接收参数作为字典,将观察结果作为字符串返回**。
|
||||
|
||||
| 工具 | 响应处理 |
|
||||
|------|------------------|
|
||||
| `KnowledgeQueryImpl` | 直接返回 `client.rag()` (字符串) |
|
||||
| `TextCompletionImpl` | 直接返回 `client.question()` (字符串) |
|
||||
| `McpToolImpl` | 返回字符串,或如果不是字符串则返回 `json.dumps(output)` |
|
||||
| `StructuredQueryImpl` | 将结果格式化为字符串 |
|
||||
| `PromptImpl` | 直接返回 `client.prompt()` (字符串) |
|
||||
|
||||
工具服务遵循相同的约定:
|
||||
服务返回一个字符串响应(观察结果)
|
||||
如果响应不是字符串,则通过 `json.dumps()` 进行转换
|
||||
描述符中不需要提取配置
|
||||
|
||||
这使描述符保持简单,并将责任放在服务上,使其为代理返回适当的文本响应。
|
||||
|
||||
## 配置指南
|
||||
|
||||
要添加一个新的工具服务,需要两个配置项:
|
||||
|
||||
### 1. 工具服务配置
|
||||
|
||||
存储在 `tool-service` 配置键下。定义了 Pulsar 队列和可用的配置参数。
|
||||
|
||||
| 字段 | 必需 | 描述 |
|
||||
|-------|----------|-------------|
|
||||
| `id` | 是 | 工具服务的唯一标识符 |
|
||||
| `request-queue` | 是 | 用于请求的完整 Pulsar 主题(例如:`non-persistent://tg/request/joke`) |
|
||||
| `response-queue` | 是 | 用于响应的完整 Pulsar 主题(例如:`non-persistent://tg/response/joke`) |
|
||||
| `config-params` | 否 | 服务接受的配置参数数组 |
|
||||
|
||||
每个配置参数可以指定:
|
||||
`name`: 参数名称 (必需)
|
||||
`required`: 是否需要工具提供该参数 (默认: 否)
|
||||
|
||||
示例:
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
|
|
@ -62,8 +296,144 @@ async def call_service(service_name, args):
|
|||
}
|
||||
```
|
||||
|
||||
### 示例工具配置
|
||||
### 2. 工具配置
|
||||
|
||||
存储在 `tool` 配置键下。定义了代理可以使用的工具。
|
||||
|
||||
| 字段 | 必需 | 描述 |
|
||||
|-------|----------|-------------|
|
||||
| `type` | 是 | 必须是 `"tool-service"` |
|
||||
| `name` | 是 | 暴露给 LLM 的工具名称 |
|
||||
| `description` | 是 | 描述工具的功能(显示给 LLM)|
|
||||
| `service` | 是 | 调用工具服务的 ID |
|
||||
| `arguments` | 否 | LLM 的参数定义数组 |
|
||||
| *(配置参数)* | 变化 | 服务定义的任何配置参数 |
|
||||
|
||||
每个参数可以指定:
|
||||
`name`:参数名称(必需)
|
||||
`type`:数据类型,例如 `"string"`(必需)
|
||||
`description`:显示给 LLM 的描述(必需)
|
||||
|
||||
示例:
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "tell-joke",
|
||||
"description": "Tell a joke on a given topic",
|
||||
"service": "joke-service",
|
||||
"style": "pun",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "topic",
|
||||
"type": "string",
|
||||
"description": "The topic for the joke (e.g., programming, animals, food)"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 加载配置
|
||||
|
||||
使用 `tg-put-config-item` 加载配置:
|
||||
|
||||
```bash
|
||||
# Load tool-service config
|
||||
tg-put-config-item tool-service/joke-service < joke-service.json
|
||||
|
||||
# Load tool config
|
||||
tg-put-config-item tool/tell-joke < tell-joke.json
|
||||
```
|
||||
|
||||
必须重启代理服务器才能加载新的配置。
|
||||
|
||||
## 实现细节
|
||||
|
||||
### 模式
|
||||
|
||||
`trustgraph-base/trustgraph/schema/services/tool_service.py` 中的请求和响应类型:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ToolServiceRequest:
|
||||
user: str = "" # User context for multi-tenancy
|
||||
config: str = "" # JSON-encoded config values from tool descriptor
|
||||
arguments: str = "" # JSON-encoded arguments from LLM
|
||||
|
||||
@dataclass
|
||||
class ToolServiceResponse:
|
||||
error: Error | None = None
|
||||
response: str = "" # String response (the observation)
|
||||
end_of_stream: bool = False
|
||||
```
|
||||
|
||||
### 服务器端:DynamicToolService
|
||||
|
||||
基类位于 `trustgraph-base/trustgraph/base/dynamic_tool_service.py`:
|
||||
|
||||
```python
|
||||
class DynamicToolService(AsyncProcessor):
|
||||
"""Base class for implementing tool services."""
|
||||
|
||||
def __init__(self, **params):
|
||||
topic = params.get("topic", default_topic)
|
||||
# Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic}
|
||||
# Sets up Consumer and Producer
|
||||
|
||||
async def invoke(self, user, config, arguments):
|
||||
"""Override this method to implement the tool's logic."""
|
||||
raise NotImplementedError()
|
||||
```
|
||||
|
||||
### 客户端:ToolServiceImpl
|
||||
|
||||
在 `trustgraph-flow/trustgraph/agent/react/tools.py` 中的实现:
|
||||
|
||||
```python
|
||||
class ToolServiceImpl:
|
||||
def __init__(self, context, request_queue, response_queue, config_values, arguments, processor):
|
||||
# Uses the provided queue paths directly
|
||||
# Creates ToolServiceClient on first use
|
||||
|
||||
async def invoke(self, **arguments):
|
||||
client = await self._get_or_create_client()
|
||||
response = await client.call(user, config_values, arguments)
|
||||
return response if isinstance(response, str) else json.dumps(response)
|
||||
```
|
||||
|
||||
### 文件
|
||||
|
||||
| 文件 | 目的 |
|
||||
|------|---------|
|
||||
| `trustgraph-base/trustgraph/schema/services/tool_service.py` | 请求/响应模式 |
|
||||
| `trustgraph-base/trustgraph/base/tool_service_client.py` | 调用服务的客户端 |
|
||||
| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | 服务实现的基类 |
|
||||
| `trustgraph-flow/trustgraph/agent/react/tools.py` | `ToolServiceImpl` 类 |
|
||||
| `trustgraph-flow/trustgraph/agent/react/service.py` | 配置加载 |
|
||||
|
||||
### 示例:笑话服务
|
||||
|
||||
一个用 `trustgraph-flow/trustgraph/tool_service/joke/` 编写的示例服务:
|
||||
|
||||
```python
|
||||
class Processor(DynamicToolService):
|
||||
async def invoke(self, user, config, arguments):
|
||||
style = config.get("style", "pun")
|
||||
topic = arguments.get("topic", "")
|
||||
joke = pick_joke(topic, style)
|
||||
return f"Hey {user}! Here's a {style} for you:\n\n{joke}"
|
||||
```
|
||||
|
||||
工具服务配置:
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [{"name": "style", "required": false}]
|
||||
}
|
||||
```
|
||||
|
||||
工具配置:
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
|
|
@ -77,58 +447,25 @@ async def call_service(service_name, args):
|
|||
}
|
||||
```
|
||||
|
||||
### 示例服务实现
|
||||
### 向后兼容性
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import json
|
||||
from trustgraph.base import dynamic_tool_service
|
||||
from trustgraph.base.tool_service_client import ToolServiceClient
|
||||
from trustgraph.schema.services.tool_service import ToolServiceRequest
|
||||
现有的内置工具类型继续以不变的方式工作。
|
||||
`tool-service` 是一种新的工具类型,与现有类型(`knowledge-query`、`mcp-tool`等)并存。
|
||||
|
||||
class Processor(dynamic_tool_service.DynamicToolService):
|
||||
async def invoke(self, user, config, arguments):
|
||||
style = config.get("style", "pun")
|
||||
topic = arguments.get("topic", "")
|
||||
joke = await self.get_joke(topic, style) # 假设这里调用一个 joke 库
|
||||
return f"Hey {user}! Here's a {style} for you:\n\n{joke}"
|
||||
## 未来考虑事项
|
||||
|
||||
async def get_joke(self, topic, style):
|
||||
# 这是一个占位符,实际需要调用 joke 库来获取笑话
|
||||
if topic == "programming" and style == "pun":
|
||||
return "Why did the programmer quit? Because he didn't get arrays!"
|
||||
else:
|
||||
return "I don't know any jokes right now."
|
||||
```
|
||||
### 自定义服务
|
||||
|
||||
### 例子:加载配置
|
||||
未来的增强功能可能允许服务发布自己的描述:
|
||||
|
||||
```bash
|
||||
# 加载工具服务配置
|
||||
tg-put-config-item tool-service/joke-service < joke-service.json
|
||||
服务在启动时发布到已知的 `tool-descriptors` 主题。
|
||||
代理订阅并动态注册工具。
|
||||
实现了真正的即插即用,无需配置更改。
|
||||
|
||||
# 加载工具配置
|
||||
tg-put-config-item tool/tell-joke < tell-joke.json
|
||||
```
|
||||
这超出了初始实现的范围。
|
||||
|
||||
### 重新启动 agent-react
|
||||
## 参考文献
|
||||
|
||||
`agent-react` 必须重新启动才能拾取新的配置。
|
||||
|
||||
## 未来考虑
|
||||
|
||||
### 自主宣布的服务
|
||||
|
||||
未来的增强可以允许服务发布自己的描述符:
|
||||
|
||||
- 服务将自身注册到 agent,包含服务名称、队列路径等信息
|
||||
- Agent 订阅并动态注册工具
|
||||
- 这使得无需修改配置即可实现真正的可插拔性
|
||||
|
||||
此功能超出了初始实现范围。
|
||||
|
||||
## 参考
|
||||
|
||||
- 现有工具实现:`trustgraph-flow/trustgraph/agent/react/tools.py`
|
||||
- 工具注册:`trustgraph-flow/trustgraph/agent/react/service.py:105-214`
|
||||
- agent 方案:`trustgraph-base/trustgraph/schema/services/agent.py`
|
||||
当前工具实现:`trustgraph-flow/trustgraph/agent/react/tools.py`
|
||||
工具注册:`trustgraph-flow/trustgraph/agent/react/service.py:105-214`
|
||||
代理模式:`trustgraph-base/trustgraph/schema/services/agent.py`
|
||||
|
|
|
|||
|
|
@ -1,36 +1,396 @@
|
|||
# Decodificador de Documentos Universal
|
||||
# Decodificador Universal de Documentos
|
||||
|
||||
## Encabezado
|
||||
## Título
|
||||
|
||||
Decodificador de documentos universal impulsado por `unstructured` — ingiere cualquier formato de documento común a través de un único servicio con total trazabilidad y integración con la biblioteca, registrando las posiciones de origen como metadatos de la red de conocimiento para la trazabilidad completa.
|
||||
Decodificador universal de documentos impulsado por `unstructured`: ingrese cualquier formato de documento común
|
||||
a través de un servicio único con un registro completo de la procedencia y la integración de la biblioteca,
|
||||
registrando las posiciones de origen como metadatos del gráfico de conocimiento para
|
||||
la trazabilidad de extremo a extremo.
|
||||
|
||||
## Problema
|
||||
|
||||
Actualmente, TrustGraph tiene un decodificador específico para PDF. El soporte para formatos adicionales (DOCX, XLSX, HTML, Markdown, texto plano, PPTX, etc.) requiere la implementación de un decodificador que pueda manejar estas variaciones.
|
||||
Actualmente, TrustGraph tiene un decodificador específico para PDF. Para admitir formatos adicionales
|
||||
(DOCX, XLSX, HTML, Markdown, texto plano, PPTX, etc.), es necesario
|
||||
escribir un nuevo decodificador por formato o adoptar una biblioteca de extracción universal.
|
||||
Cada formato tiene una estructura diferente; algunos son basados en páginas, otros no,
|
||||
y la cadena de procedencia debe registrar de dónde se originó cada parte del texto extraído
|
||||
en el documento original.
|
||||
|
||||
## Solución
|
||||
## Enfoque
|
||||
|
||||
Se propone un decodificador de documentos universal que pueda procesar una variedad de formatos de documentos, incluyendo PDF, DOCX, XLSX, HTML, Markdown y texto plano. Este decodificador utilizará la biblioteca `unstructured` para extraer el texto y la estructura de los documentos.
|
||||
### Biblioteca: `unstructured`
|
||||
|
||||
## Ventajas
|
||||
Utilice `unstructured.partition.auto.partition()`, que detecta automáticamente el formato
|
||||
a partir del tipo MIME o la extensión del archivo y extrae elementos estructurados
|
||||
(Título, TextoNarrativo, Tabla, ElementoLista, etc.). Cada elemento lleva
|
||||
metadatos que incluyen:
|
||||
|
||||
* **Soporte para múltiples formatos:** El decodificador de documentos universal puede procesar una variedad de formatos de documentos, lo que permite a los usuarios trabajar con una amplia gama de documentos.
|
||||
* **Trazabilidad:** El decodificador de documentos universal puede rastrear el origen de los datos extraídos, lo que permite a los usuarios comprender cómo se extrajeron los datos y verificar su exactitud.
|
||||
* **Integración con la biblioteca:** El decodificador de documentos universal se integra con la biblioteca `unstructured`, que proporciona una variedad de herramientas para el procesamiento de documentos.
|
||||
`page_number` (para formatos basados en páginas como PDF, PPTX)
|
||||
`element_id` (único para cada elemento)
|
||||
`coordinates` (cuadro delimitador para PDF)
|
||||
`text` (el contenido de texto extraído)
|
||||
`category` (tipo de elemento: Título, TextoNarrativo, Tabla, etc.)
|
||||
|
||||
## Desafíos
|
||||
### Tipos de Elemento
|
||||
|
||||
* **Complejidad:** El desarrollo de un decodificador de documentos universal es un proyecto complejo que requiere experiencia en el procesamiento de documentos, la programación y la administración de sistemas.
|
||||
* **Rendimiento:** El decodificador de documentos universal debe ser capaz de procesar grandes cantidades de documentos de forma eficiente.
|
||||
* **Mantenimiento:** El decodificador de documentos universal debe ser fácil de mantener y actualizar.
|
||||
`unstructured` extrae elementos tipados de los documentos. Cada elemento tiene
|
||||
una categoría y metadatos asociados:
|
||||
|
||||
## Plan de Implementación
|
||||
**Elementos de texto:**
|
||||
`Title` — encabezados de sección
|
||||
`NarrativeText` — párrafos del cuerpo
|
||||
`ListItem` — elementos de lista con viñetas/numerados
|
||||
`Header`, `Footer` — encabezados/pies de página
|
||||
`FigureCaption` — leyendas para figuras/imágenes
|
||||
`Formula` — expresiones matemáticas
|
||||
`Address`, `EmailAddress` — información de contacto
|
||||
`CodeSnippet` — bloques de código (de Markdown)
|
||||
|
||||
1. **Desarrollo:** Se desarrollará un decodificador de documentos universal utilizando la biblioteca `unstructured`. El decodificador se diseñará para ser modular y extensible, para que pueda ser actualizado fácilmente con soporte para nuevos formatos de documentos.
|
||||
2. **Pruebas:** El decodificador de documentos universal se probará exhaustivamente para garantizar su exactitud y rendimiento.
|
||||
3. **Implementación:** El decodificador de documentos universal se implementará en un entorno de producción.
|
||||
4. **Mantenimiento:** El decodificador de documentos universal se mantendrá y actualizará según sea necesario.
|
||||
**Tablas:**
|
||||
`Table` — datos tabulares estructurados. `unstructured` proporciona tanto
|
||||
`element.text` (texto plano) como `element.metadata.text_as_html`
|
||||
(HTML completo `<table>` con filas, columnas y encabezados conservados).
|
||||
Para formatos con una estructura de tabla explícita (DOCX, XLSX, HTML),
|
||||
la extracción es muy fiable. Para PDF, la detección de tablas depende de
|
||||
la estrategia de `hi_res` con el análisis de diseño.
|
||||
|
||||
## Conclusión
|
||||
**Imágenes:**
|
||||
`Image` — imágenes integradas detectadas mediante el análisis de diseño (requiere
|
||||
la estrategia de `hi_res`). Con `extract_image_block_to_payload=True`,
|
||||
devuelve los datos de la imagen como base64 en `element.metadata.image_base64`.
|
||||
El texto OCR de la imagen está disponible en `element.text`.
|
||||
|
||||
El decodificador de documentos universal es una herramienta poderosa que puede ayudar a los usuarios a trabajar con una amplia gama de documentos. Aunque el desarrollo y la implementación de este decodificador son desafiantes, los beneficios potenciales superan los riesgos.
|
||||
### Manejo de Tablas
|
||||
|
||||
Las tablas son una salida de primera clase. Cuando el decodificador encuentra un elemento `Table`,
|
||||
conserva la estructura HTML en lugar de aplanarla a texto plano. Esto proporciona
|
||||
a la biblioteca de extracción LLM descendente una mejor entrada para extraer conocimiento
|
||||
estructurado de los datos tabulares.
|
||||
|
||||
El texto de la página/sección se ensambla de la siguiente manera:
|
||||
Elementos de texto: texto plano, unido con saltos de línea
|
||||
Elementos de tabla: marcado de tabla HTML de `text_as_html`, envuelto en un
|
||||
marcador `<table>` para que el LLM pueda distinguir las tablas del texto narrativo.
|
||||
|
||||
Por ejemplo, una página con un encabezado, un párrafo y una tabla produce:
|
||||
|
||||
```
|
||||
Financial Overview
|
||||
|
||||
Revenue grew 15% year-over-year driven by enterprise adoption.
|
||||
|
||||
<table>
|
||||
<tr><th>Quarter</th><th>Revenue</th><th>Growth</th></tr>
|
||||
<tr><td>Q1</td><td>$12M</td><td>12%</td></tr>
|
||||
<tr><td>Q2</td><td>$14M</td><td>17%</td></tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
Esto preserva la estructura de la tabla mediante la segmentación y en la
|
||||
canalización de extracción, donde el LLM puede extraer relaciones directamente de
|
||||
celdas estructuradas en lugar de adivinar la alineación de columnas a partir de
|
||||
espacios en blanco.
|
||||
|
||||
### Manejo de imágenes
|
||||
|
||||
Las imágenes se extraen y se almacenan en la biblioteca como documentos
|
||||
secundarios con un `document_type="image"` y un ID `urn:image:{uuid}`. Obtienen
|
||||
tripletas de procedencia con el tipo `tg:Image`, vinculadas a su página/sección
|
||||
principal a través de `prov:wasDerivedFrom`. Los metadatos de la imagen (coordenadas,
|
||||
dimensiones, element_id) se registran en la procedencia.
|
||||
|
||||
**Es crucial que las imágenes NO se emitan como salidas de TextDocument.** Se
|
||||
almacenan únicamente; no se envían a la canalización de segmentación ni a ningún
|
||||
proceso de texto. Esto es intencional:
|
||||
|
||||
1. Todavía no existe una canalización de procesamiento de imágenes (la integración
|
||||
del modelo de visión es un trabajo futuro).
|
||||
2. Alimentar datos de imagen en base64 o fragmentos de OCR en la
|
||||
canalización de extracción de texto produciría tripletas de KG basura.
|
||||
|
||||
Las imágenes también se excluyen del texto de la página ensamblada; cualquier `Image`
|
||||
elemento se omite silenciosamente al concatenar los textos de los elementos para una
|
||||
página/sección. La cadena de procedencia registra que las imágenes existen y dónde
|
||||
aparecieron en el documento, por lo que pueden ser recuperadas por una futura
|
||||
canalización de procesamiento de imágenes sin volver a importar el documento.
|
||||
|
||||
#### Trabajo futuro
|
||||
|
||||
Enviar `tg:Image` entidades a un modelo de visión para descripción,
|
||||
interpretación de diagramas o extracción de datos de gráficos.
|
||||
Almacenar las descripciones de las imágenes como documentos de texto secundarios que se integran en
|
||||
la canalización estándar de fragmentación/extracción.
|
||||
Vincular el conocimiento extraído de nuevo a las imágenes de origen a través de la procedencia.
|
||||
|
||||
### Estrategias de sección
|
||||
|
||||
Para formatos basados en páginas (PDF, PPTX, XLSX), los elementos siempre se agrupan
|
||||
por página/diapositiva/hoja primero. Para formatos no basados en páginas (DOCX, HTML, Markdown,
|
||||
etc.), el decodificador necesita una estrategia para dividir el documento en
|
||||
secciones. Esto se puede configurar en tiempo de ejecución a través de `--section-strategy`.
|
||||
|
||||
Cada estrategia es una función de agrupación sobre la lista de `unstructured`
|
||||
elementos. La salida es una lista de grupos de elementos; el resto de la
|
||||
canalización (ensamblaje de texto, almacenamiento en la biblioteca, procedencia,
|
||||
emisión de TextDocument) es idéntico independientemente de la estrategia.
|
||||
|
||||
#### `whole-document` (predeterminado)
|
||||
|
||||
Emite todo el documento como una sola sección. Permite que el
|
||||
fragmentador (chunker) posterior gestione todas las divisiones.
|
||||
|
||||
Enfoque más simple, buena línea de base
|
||||
Puede producir un TextDocument muy grande para archivos grandes, pero el
|
||||
fragmentador se encarga de eso.
|
||||
Mejor cuando se desea el máximo contexto por sección.
|
||||
|
||||
#### `heading`
|
||||
|
||||
Divide en elementos de encabezado (`Title`). Cada sección es un encabezado más
|
||||
todo el contenido hasta el siguiente encabezado de igual o mayor nivel. Los
|
||||
encabezados anidados crean secciones anidadas.
|
||||
|
||||
Produce unidades temáticamente coherentes.
|
||||
Funciona bien para documentos estructurados (informes, manuales, especificaciones).
|
||||
Proporciona al LLM de extracción el contexto del encabezado junto con el contenido.
|
||||
Retrocede a `whole-document` si no se encuentran encabezados.
|
||||
|
||||
#### `element-type`
|
||||
|
||||
Divide cuando el tipo de elemento cambia significativamente; específicamente,
|
||||
comienza una nueva sección en las transiciones entre texto narrativo y tablas.
|
||||
Los elementos consecutivos de la misma categoría general (texto, texto, texto o
|
||||
tabla, tabla) permanecen agrupados.
|
||||
|
||||
Mantiene las tablas como secciones independientes.
|
||||
Bueno para documentos con contenido mixto (informes con tablas de datos).
|
||||
Las tablas reciben una atención de extracción dedicada.
|
||||
|
||||
#### `count`
|
||||
|
||||
Agrupa un número fijo de elementos por sección. Configurable a través de
|
||||
`--section-element-count` (predeterminado: 20).
|
||||
|
||||
Simple y predecible.
|
||||
No respeta la estructura del documento.
|
||||
Útil como alternativa o para la experimentación.
|
||||
|
||||
#### `size`
|
||||
|
||||
Acumula elementos hasta que se alcanza un límite de caracteres, luego comienza una
|
||||
nueva sección. Respeta los límites de los elementos; nunca los divide a la mitad.
|
||||
Configurable a través de `--section-max-size` (por defecto: 4000 caracteres).
|
||||
|
||||
Produce tamaños de sección aproximadamente uniformes.
|
||||
Respeta los límites de los elementos (a diferencia del fragmentador posterior).
|
||||
Buen compromiso entre estructura y control de tamaño.
|
||||
Si un solo elemento excede el límite, se convierte en su propia sección.
|
||||
|
||||
#### Interacción con formatos basados en páginas
|
||||
|
||||
Para formatos basados en páginas, el agrupamiento de páginas siempre tiene prioridad.
|
||||
Las estrategias de sección opcionalmente se pueden aplicar *dentro* de una página si es muy
|
||||
grande (por ejemplo, una página PDF con una tabla enorme), controlado por
|
||||
`--section-within-pages` (por defecto: falso). Cuando es falso, cada página es
|
||||
siempre una sección, independientemente del tamaño.
|
||||
|
||||
### Detección de formato
|
||||
|
||||
El decodificador necesita conocer el tipo MIME del documento para pasarlo a
|
||||
`unstructured`'s `partition()`. Dos caminos:
|
||||
|
||||
**Ruta del bibliotecario** (`document_id` configurado): primero, recupera los metadatos del documento
|
||||
del bibliotecario; esto nos da el `kind` (tipo MIME)
|
||||
que se registró en el momento de la carga. Luego, recupera el contenido del documento.
|
||||
Dos llamadas al bibliotecario, pero la recuperación de metadatos es ligera.
|
||||
**Ruta integrada** (compatibilidad con versiones anteriores, `data` configurado): no hay metadatos
|
||||
disponibles en el mensaje. Usa `python-magic` para detectar el formato
|
||||
a partir de los bytes del contenido como una opción alternativa.
|
||||
|
||||
No se necesitan cambios en el esquema `Document`; el bibliotecario ya almacena el tipo MIME.
|
||||
|
||||
|
||||
### Arquitectura
|
||||
|
||||
Un único servicio `universal-decoder` que:
|
||||
|
||||
1. Recibe un mensaje `Document` (en línea o a través de una referencia a la biblioteca).
|
||||
2. Si la ruta es a través de la biblioteca: recupera los metadatos del documento (obtiene el tipo MIME), luego
|
||||
recupera el contenido. Si la ruta es en línea: detecta el formato a partir de los bytes del contenido.
|
||||
3. Llama a `partition()` para extraer los elementos.
|
||||
4. Agrupa elementos: por página para formatos basados en páginas, por estrategia de sección configurada para formatos no basados en páginas.
|
||||
sección.
|
||||
5. Para cada página/sección:
|
||||
Genera un ID `urn:page:{uuid}` o `urn:section:{uuid}`
|
||||
Ensambla el texto de la página: el texto narrativo como texto plano, las tablas como HTML,
|
||||
imágenes omitidas
|
||||
Calcula los desplazamientos de caracteres para cada elemento dentro del texto de la página.
|
||||
Guarda en el sistema de gestión de documentos como documento hijo.
|
||||
Emite triples de procedencia con metadatos de posición.
|
||||
Envía `TextDocument` a la siguiente etapa para la segmentación.
|
||||
6. Para cada elemento de imagen:
|
||||
Genera un ID `urn:image:{uuid}`.
|
||||
Guarda los datos de la imagen en el sistema de gestión de documentos como documento hijo.
|
||||
Emite triples de procedencia (almacenados solo, no enviados a la siguiente etapa).
|
||||
|
||||
### Manejo de formatos
|
||||
|
||||
| Formato | Tipo MIME | Basado en páginas | Notas |
|
||||
|----------|------------------------------------|------------|--------------------------------|
|
||||
| PDF | application/pdf | Sí | Agrupación por página |
|
||||
| DOCX | application/vnd.openxmlformats... | No | Utiliza estrategia de secciones |
|
||||
| PPTX | application/vnd.openxmlformats... | Sí | Agrupación por diapositiva |
|
||||
| XLSX/XLS | application/vnd.openxmlformats... | Sí | Agrupación por hoja |
|
||||
| HTML | text/html | No | Utiliza estrategia de secciones |
|
||||
| Markdown | text/markdown | No | Utiliza estrategia de secciones |
|
||||
| Texto plano | text/plain | No | Utiliza estrategia de secciones |
|
||||
| CSV | text/csv | No | Utiliza estrategia de secciones |
|
||||
| RST | text/x-rst | No | Utiliza estrategia de secciones |
|
||||
| RTF | application/rtf | No | Utiliza estrategia de secciones |
|
||||
| ODT | application/vnd.oasis... | No | Utiliza estrategia de secciones |
|
||||
| TSV | text/tab-separated-values | No | Utiliza estrategia de secciones |
|
||||
|
||||
### Metadatos de procedencia
|
||||
|
||||
Cada entidad de página/sección registra metadatos de posición como metadatos de procedencia
|
||||
en `GRAPH_SOURCE`, lo que permite una trazabilidad completa desde las triples del grafo de conocimiento
|
||||
hasta las posiciones del documento de origen.
|
||||
|
||||
#### Campos existentes (ya están en `derived_entity_triples`)
|
||||
|
||||
`page_number` — número de página/hoja/diapositiva (indexado desde 1, solo para páginas)
|
||||
`char_offset` — desplazamiento de caracteres de esta página/sección dentro del
|
||||
texto completo del documento.
|
||||
`char_length` — longitud de caracteres del texto de esta página/sección.
|
||||
|
||||
#### Nuevos campos (extender `derived_entity_triples`)
|
||||
|
||||
`mime_type` — formato original del documento (por ejemplo, `application/pdf`)
|
||||
`element_types` — lista separada por comas de categorías de elementos `unstructured`
|
||||
encontradas en esta página/sección (por ejemplo, "Título,TextoNarrativo,Tabla")
|
||||
`table_count` — número de tablas en esta página/sección.
|
||||
`image_count` — número de imágenes en esta página/sección.
|
||||
|
||||
Estos requieren nuevos predicados del espacio de nombres TG:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
TG_IMAGE_TYPE = "https://trustgraph.ai/ns/Image"
|
||||
TG_ELEMENT_TYPES = "https://trustgraph.ai/ns/elementTypes"
|
||||
TG_TABLE_COUNT = "https://trustgraph.ai/ns/tableCount"
|
||||
TG_IMAGE_COUNT = "https://trustgraph.ai/ns/imageCount"
|
||||
```
|
||||
|
||||
Esquema URN de imagen: `urn:image:{uuid}`
|
||||
|
||||
(`TG_MIME_TYPE` ya existe.)
|
||||
|
||||
#### Nuevo tipo de entidad
|
||||
|
||||
Para formatos que no son de página (DOCX, HTML, Markdown, etc.) donde el decodificador
|
||||
emite todo el documento como una sola unidad en lugar de dividirlo por
|
||||
página, la entidad obtiene un nuevo tipo:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
```
|
||||
|
||||
Esto distingue las secciones de las páginas al consultar el origen:
|
||||
|
||||
| Entidad | Tipo | Cuándo se utiliza |
|
||||
|----------|-----------------------------|----------------------------------------|
|
||||
| Documento | `tg:Document` | Archivo original subido |
|
||||
| Página | `tg:Page` | Formatos basados en páginas (PDF, PPTX, XLSX) |
|
||||
| Sección | `tg:Section` | Formatos que no son de página (DOCX, HTML, MD, etc.) |
|
||||
| Imagen | `tg:Image` | Imágenes incrustadas (almacenadas, no procesadas) |
|
||||
| Fragmento | `tg:Chunk` | Resultado del fragmentador |
|
||||
| Subgrafo | `tg:Subgraph` | Resultado de la extracción del grafo de conocimiento |
|
||||
|
||||
El tipo se establece por el decodificador según si se está agrupando por página
|
||||
o emitiendo una sección de todo el documento. `derived_entity_triples` obtiene
|
||||
un parámetro booleano opcional `section`; cuando es verdadero, la entidad se
|
||||
clasifica como `tg:Section` en lugar de `tg:Page`.
|
||||
|
||||
#### Cadena completa de origen
|
||||
|
||||
```
|
||||
KG triple
|
||||
→ subgraph (extraction provenance)
|
||||
→ chunk (char_offset, char_length within page)
|
||||
→ page/section (page_number, char_offset, char_length within doc, mime_type, element_types)
|
||||
→ document (original file in librarian)
|
||||
```
|
||||
|
||||
Cada enlace es un conjunto de triples en el grafo denominado `GRAPH_SOURCE`.
|
||||
|
||||
### Configuración del servicio
|
||||
|
||||
Argumentos de línea de comandos:
|
||||
|
||||
```
|
||||
--strategy Partitioning strategy: auto, hi_res, fast (default: auto)
|
||||
--languages Comma-separated OCR language codes (default: eng)
|
||||
--section-strategy Section grouping: whole-document, heading, element-type,
|
||||
count, size (default: whole-document)
|
||||
--section-element-count Elements per section for 'count' strategy (default: 20)
|
||||
--section-max-size Max chars per section for 'size' strategy (default: 4000)
|
||||
--section-within-pages Apply section strategy within pages too (default: false)
|
||||
```
|
||||
|
||||
Además de los argumentos estándar de `FlowProcessor` y la cola del bibliotecario.
|
||||
|
||||
### Integración del flujo
|
||||
|
||||
El decodificador universal ocupa la misma posición en el flujo de procesamiento
|
||||
que el decodificador PDF actual:
|
||||
|
||||
```
|
||||
Document → [universal-decoder] → TextDocument → [chunker] → Chunk → ...
|
||||
```
|
||||
|
||||
Se registra:
|
||||
`input` consumidor (esquema de documento)
|
||||
`output` productor (esquema de TextDocument)
|
||||
`triples` productor (esquema de Triples)
|
||||
Solicitud/respuesta del bibliotecario (para la recuperación y el almacenamiento de documentos secundarios)
|
||||
|
||||
### Despliegue
|
||||
|
||||
Nuevo contenedor: `trustgraph-flow-universal-decoder`
|
||||
Dependencia: `unstructured[all-docs]` (incluye PDF, DOCX, PPTX, etc.)
|
||||
Puede ejecutarse junto con o reemplazar el decodificador PDF existente, dependiendo de
|
||||
la configuración del flujo.
|
||||
El decodificador PDF existente permanece disponible para entornos donde
|
||||
las dependencias de `unstructured` son demasiado pesadas.
|
||||
|
||||
### ¿Qué Cambia?
|
||||
|
||||
| Component | Change |
|
||||
|------------------------------|-------------------------------------------------|
|
||||
| `provenance/namespaces.py` | Add `TG_SECTION_TYPE`, `TG_IMAGE_TYPE`, `TG_ELEMENT_TYPES`, `TG_TABLE_COUNT`, `TG_IMAGE_COUNT` |
|
||||
| `provenance/triples.py` | Add `mime_type`, `element_types`, `table_count`, `image_count` kwargs |
|
||||
| `provenance/__init__.py` | Export new constants |
|
||||
| New: `decoding/universal/` | New decoder service module |
|
||||
| `setup.cfg` / `pyproject` | Add `unstructured[all-docs]` dependency |
|
||||
| Docker | New container image |
|
||||
| Flow definitions | Wire universal-decoder as document input |
|
||||
|
||||
### What Doesn't Change
|
||||
|
||||
Chunker (receives TextDocument, works as before)
|
||||
Downstream extractors (receive Chunk, unchanged)
|
||||
Librarian (stores child documents, unchanged)
|
||||
Schema (Document, TextDocument, Chunk unchanged)
|
||||
Query-time provenance (unchanged)
|
||||
|
||||
## Risks
|
||||
|
||||
`unstructured[all-docs]` has heavy dependencies (poppler, tesseract,
|
||||
libreoffice for some formats). Container image will be larger.
|
||||
Mitigation: offer a `[light]` variant without OCR/office deps.
|
||||
Some formats may produce poor text extraction (scanned PDFs without
|
||||
OCR, complex XLSX layouts). Mitigation: configurable `strategy`
|
||||
parameter, and the existing Mistral OCR decoder remains available
|
||||
for high-quality PDF OCR.
|
||||
`unstructured` version updates may change element metadata.
|
||||
Mitigation: pin version, test extraction quality per format.
|
||||
|
|
|
|||
|
|
@ -2,195 +2,395 @@
|
|||
|
||||
## כותרת
|
||||
|
||||
מפענח מסמכים אוניברסלי המופעל על ידי `unstructured` — קבלת פורמטים נפוצים של מסמכים באמצעות שירות יחיד, עם תיעוד מלא של מקור הנתונים ושילוב עם ספריית ניהול מסמכים, תוך רישום מיקומי המקור כמטא-דאטה של גרף ידע למעקב מקצה לקצה.
|
||||
מפענח מסמכים אוניברסלי המופעל על ידי `unstructured` - קליטת כל פורמט מסמך נפוץ
|
||||
דרך שירות יחיד עם תיעוד מלא ושילוב עם ספרייה, תוך רישום מיקומי המקור כמטא-נתונים של גרף ידע
|
||||
למעקב מקצה לקצה.
|
||||
|
||||
## בעיה
|
||||
|
||||
ל-TrustGraph כיום יש מפענח ספציפי ל-PDF. תמיכה בפורמטים נוספים (DOCX, XLSX, HTML, Markdown, טקסט רגיל, PPTX וכו') דורשת או כתיבת מפענח חדש לכל פורמט או אימוץ ספריית חילוץ אוניברסלית. לכל פורמט יש מבנה שונה — חלקם מבוססי דפים, חלקם לא — ושרשרת התיעוד חייבת לתעד היכן בכל המסמך המקורי הגיע כל חלק של הטקסט שחולץ.
|
||||
|
||||
כיום, ל-TrustGraph יש מפענח ספציפי ל-PDF. תמיכה בפורמטים נוספים (DOCX, XLSX, HTML, Markdown, טקסט רגיל, PPTX וכו') דורשת
|
||||
או כתיבת מפענח חדש לכל פורמט או אימוץ ספריית חילוץ אוניברסלית. לכל פורמט יש מבנה שונה - חלקם מבוססי דפים, וחלקם לא -
|
||||
ושרשרת התיעוד חייבת לתעד מאיפה בכל מסמך המקורי הגיע כל פיסת טקסט שחולצה.
|
||||
|
||||
## גישה
|
||||
לתעד כל פיסת טקסט שחולצה ולציין את מקורה.
|
||||
|
||||
## גישה
|
||||
|
||||
### ספרייה: `unstructured`
|
||||
### ספריה: `unstructured`
|
||||
|
||||
יש להשתמש ב-`unstructured.partition.auto.partition()` שמזהה באופן אוטומטי את הפורמט מסוג MIME או סיומת הקובץ ומחלצת אלמנטים מובנים (כותרת, טקסט, טבלה, פריט רשימה וכו'). כל אלמנט מכיל מטא-דאטה, כולל:
|
||||
השתמשו ב-`unstructured.partition.auto.partition()` שמזהה אוטומטית את הפורמט
|
||||
מחלק סוג MIME או סיומת קובץ ומחלץ אלמנטים מובנים
|
||||
(כותרת, טקסט, טבלה, פריט רשימה, וכו'). כל אלמנט נושא
|
||||
מטא-דאטה, כולל:
|
||||
|
||||
- `page_number` (לפורמטים מבוססי דפים כמו PDF, PPTX)
|
||||
- `element_id` (ייחודי לכל אלמנט)
|
||||
- `coordinates` (מלבן תחום עבור PDF)
|
||||
- `text` (תוכן הטקסט שחולץ)
|
||||
- `category` (סוג אלמנט: כותרת, טקסט, טבלה וכו')
|
||||
`page_number` (עבור פורמטים מבוססי דפים כמו PDF, PPTX)
|
||||
`element_id` (ייחודי לכל אלמנט)
|
||||
`coordinates` (מלבן תוחם עבור קבצי PDF)
|
||||
`text` (תוכן הטקסט שנחלץ)
|
||||
`category` (סוג האלמנט: כותרת, טקסט, טבלה, וכו')
|
||||
|
||||
### סוגי אלמנטים
|
||||
|
||||
`unstructured` מחלץ אלמנטים מסוגים שונים ממסמכים. לכל אלמנט יש קטגוריה ומטא-דאטה נלווים:
|
||||
`unstructured` מחלץ אלמנטים מסוגים שונים ממסמכים. לכל אלמנט יש
|
||||
קטגוריה ומטא-דאטה נלווים:
|
||||
|
||||
**אלמנטים טקסטואליים:**
|
||||
- `Title` — כותרות סעיפים
|
||||
- `NarrativeText` — פסקאות גוף
|
||||
- `ListItem` — פריטי רשימה/רשימות ממוספרות
|
||||
- `Header`, `Footer` — כותרות/כותרות שוליים של עמודים
|
||||
- `FigureCaption` — כיתובים עבור תמונות/גרפיקה
|
||||
- `Formula` — ביטויים מתמטיים
|
||||
- `Address`, `EmailAddress` — פרטי התקשרות
|
||||
- `CodeSnippet` — בלוקי קוד (מ-Markdown)
|
||||
`Title` — כותרות סעיפים
|
||||
`NarrativeText` — פסקאות גוף הטקסט
|
||||
`ListItem` — פריטי רשימות (ממוספרות או עם נקודות)
|
||||
`Header`, `Footer` — כותרות/שוליים של עמודים
|
||||
`FigureCaption` — כיתובים עבור תמונות/איורים
|
||||
`Formula` — ביטויים מתמטיים
|
||||
`Address`, `EmailAddress` — פרטי יצירת קשר
|
||||
`CodeSnippet` — בלוקי קוד (מתוך markdown)
|
||||
|
||||
**טבלאות:**
|
||||
- `Table` — נתונים טבלאיים מובנים. `unstructured` מספק גם `element.text` (טקסט רגיל) וגם `element.metadata.text_as_html` (תגית HTML מלאה של `<table>` עם שורות, עמודות וכותרות). עבור פורמטים עם מבנה טבלה מוגדר (DOCX, XLSX, HTML), החילוץ אמין מאוד. עבור PDF, זיהוי טבלאות תלוי באסטרטגיית `hi_res` עם ניתוח פריסה.
|
||||
`Table` - נתונים טבלאיים מובנים. `unstructured` מספק גם
|
||||
`element.text` (טקסט רגיל) וגם `element.metadata.text_as_html`
|
||||
(HTML מלא `<table>` עם שורות, עמודות וכותרות שמורות).
|
||||
עבור פורמטים עם מבנה טבלה מפורש (DOCX, XLSX, HTML), החילוץ אמין מאוד. עבור קבצי PDF, זיהוי טבלאות תלוי ב
|
||||
⟦CODE_0⟧. For PDFs, table detection depends on ⟦CODE_0⟧.
|
||||
האסטרטגיה של `hi_res` עם ניתוח פריסה.
|
||||
|
||||
**תמונות:**
|
||||
- `Image` — תמונות מוטמעות שזוהו באמצעות ניתוח פריסה (דורש אסטרטגיית `hi_res`). עם `extract_image_block_to_payload=True`, מחזיר את נתוני התמונה כ-base64 ב-`element.metadata.image_base64`. טקסט OCR מהתמונה זמין ב-`element.text`.
|
||||
`Image` — זיהוי תמונות מוטמעות באמצעות ניתוח פריסה (דורש
|
||||
`hi_res` אסטרטגיה). עם `extract_image_block_to_payload=True`,
|
||||
מחזיר את נתוני התמונה כ-base64 ב-`element.metadata.image_base64`.
|
||||
טקסט OCR מהתמונה זמין ב-`element.text`.
|
||||
|
||||
### טיפול בטבלאות
|
||||
|
||||
טבלאות הן פלט ברמה ראשונה. כאשר המפענח נתקל באלמנט `Table`, הוא שומר על מבנה ה-HTML במקום לפשט לטקסט רגיל. זה נותן למחלץ ה-LLM במעלה הזרם קלט טוב יותר לשליפה של ידע מובנה מנתונים טבלאיים.
|
||||
טבלאות הן פלט ברמה ראשונה. כאשר המפענח נתקל באלמנט `Table`,
|
||||
הוא שומר על מבנה ה-HTML במקום לשטח לטקסט
|
||||
רגיל. זה מספק למחלץ ה-LLM במורד קלט טוב בהרבה
|
||||
לשליפת ידע מובנה מנתונים טבלאיים.
|
||||
|
||||
הטקסט של העמוד/הסעיף מורכב באופן הבא:
|
||||
- אלמנטים טקסטואליים: טקסט רגיל, המחוברים עם שורות חדשות.
|
||||
- אלמנטים של טבלאות: תגית טבלה HTML מ-`text_as_html`, עטופה בתגית `<table>` כך שה-LLM יכול להבחין בין טבלאות לבין טקסט רגיל.
|
||||
הטקסט של העמוד/הקטע מורכב באופן הבא:
|
||||
אלמנטי טקסט: טקסט רגיל, המחוברים בשורות חדשות
|
||||
אלמנטי טבלה: תגי HTML של טבלה מ-`text_as_html`, עטופים ב-
|
||||
`<table>` סימון כך שה-LLM יכול להבחין בין טבלאות לבין טקסט
|
||||
|
||||
לדוגמה, עמוד עם כותרת, פסקה וטבלה מייצר:
|
||||
|
||||
```
|
||||
סקירה פיננסית
|
||||
Financial Overview
|
||||
|
||||
ההכנסות גדלו ב-15% שנה אחר שנה, הודות לאימוץ ארגוני.
|
||||
Revenue grew 15% year-over-year driven by enterprise adoption.
|
||||
|
||||
<table>
|
||||
<tr><th>רבעון</th><th>הכנסות</th><th>צמיחה</th></tr>
|
||||
<tr<td>רבעון 1</td><td>$12 מיליון</td><td>12%</td></tr>
|
||||
<tr<td>רבעון 2</td><td>$14 מיליון</td><td>17%</td></tr>
|
||||
<tr><th>Quarter</th><th>Revenue</th><th>Growth</th></tr>
|
||||
<tr><td>Q1</td><td>$12M</td><td>12%</td></tr>
|
||||
<tr><td>Q2</td><td>$14M</td><td>17%</td></tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
זה שומר על מבנה הטבלה במהלך חלוקה לחלקים ולתוך צינור החילוץ, שבו ה-LLM יכול לחלץ קשרים ישירות מתאים מובנים ולא לנחש על התאמת עמודות מרווח לבן.
|
||||
זה שומר על מבנה הטבלאות באמצעות חלוקה לחלקים וליחידת העיבוד
|
||||
(pipeline), כאשר מודל השפה הגדול (LLM) יכול לחלץ קשרים ישירות מתוך
|
||||
תאים מובנים, ולא לנחש את יישור העמודות על סמך
|
||||
רווחים.
|
||||
|
||||
### טיפול בתמונות
|
||||
|
||||
תמונות מחולצות ומאוחסנות בספריית הניהול כמסמכים משניים עם `document_type="image"` ו-ID `urn:image:{uuid}`. הם מקבלים משולשים של תיעוד מסוג `tg:Image`, המקושרים לעמוד/סעיף האב שלהם באמצעות `prov:wasDerivedFrom`. מטא-דאטה של תמונה (קואורדינטות, מימדים, `element_id`) נרשמים בתיעוד.
|
||||
תמונות מחולצות ונשמרות בספרייה כמסמכים משניים
|
||||
עם `document_type="image"` ו-`urn:image:{uuid}` מזהה. הן מקבלות
|
||||
טריפלים של מקור (provenance) מסוג `tg:Image`, המקושרים לעמוד/קטע
|
||||
הראשי שלהן דרך `prov:wasDerivedFrom`. מטא-נתונים של תמונה (קואורדינטות,
|
||||
מידות, element_id) נרשמים במקור.
|
||||
|
||||
**חשוב, תמונות אינן מופצות כפלט של `TextDocument`.** הן מאוחסנות בלבד — אינן נשלחות במעלה הזרם למחלק או לכל צינור עיבוד טקסט. זה מכוון:
|
||||
**חשוב מאוד: תמונות אינן משודרות כפלט של מסמך טקסט (TextDocument).** הן
|
||||
נשמרות בלבד - אינן נשלחות כלפי מטה ליחידת החלוקה (chunker) או לכל
|
||||
תהליך עיבוד טקסט. זה נעשה בכוונה:
|
||||
|
||||
1. אין עדיין צינור לעיבוד תמונות (שילוב מודל ראייה הוא עבודה עתידית)
|
||||
2. העברת נתוני תמונה ב-base64 או פיסות OCR לצינור חילוץ הטקסט תיצור משולשים של גרף ידע "זבל".
|
||||
1. אין עדיין תהליך עיבוד תמונות (שילוב מודל ראייה הוא עבודה
|
||||
עתידית)
|
||||
2. העברת נתוני תמונה בפורמט base64 או פיסות OCR ליחידת החילוץ
|
||||
של טקסט תייצר טריפלים של גרף ידע (KG) לא מועילים.
|
||||
|
||||
תמונות גם אינן נכללות בטקסט העמוד המורכב — כל אלמנטי `Image` מושמטים בשקט כאשר מחברים טקסט של אלמנטים עבור עמוד/סעיף. שרשרת התיעוד רושמת שתמונות קיימות ואיפה שהן הופיעו במסמך, כך שניתן יהיה לשלוף אותן על ידי צינור עיבוד תמונות עתידי מבלי לטעון מחדש את המסמך.
|
||||
תמונות גם אינן נכללות בטקסט המורכב של העמוד - כל `Image`
|
||||
אלמנטים מתעלמים כאשר מחברים טקסט של אלמנטים עבור
|
||||
עמוד/קטע. שרשרת המקור (provenance) רושמת שתמונות קיימות ואיפה
|
||||
הן הופיעו במסמך, כך שניתן יהיה לאסוף אותן על ידי תהליך
|
||||
עיבוד תמונות עתידי מבלי להכניס מחדש את המסמך.
|
||||
|
||||
#### עבודה עתידית
|
||||
|
||||
- הכוונת ישויות `tg:Image` למודל ראייה לתיאור, פרשנות דיאגרמות או חילוץ נתוני תרשימים.
|
||||
- אחסון תיאורי תמונה כמסמכים טקסטואליים שמוזנים לצינור החלוקה/חילוץ הסטנדרטי.
|
||||
- קישור ידע שנחצה חזרה לתמונות מקור באמצעות תיעוד.
|
||||
להעביר `tg:Image` ישויות למודל ראייה לצורך תיאור,
|
||||
פרשנות דיאגרמות או חילוץ נתוני טבלה.
|
||||
לשמור תיאורי תמונה כמסמכי טקסט משניים שמוזנים
|
||||
לתוך תהליך החלוקה/חילוץ הסטנדרטי.
|
||||
לקשר ידע מחולץ בחזרה לתמונות המקוריות דרך מקור.
|
||||
|
||||
### אסטרטגיות סעיפים
|
||||
|
||||
לפורמטים מבוססי דפים (PDF, PPTX, XLSX), אלמנטים תמיד מקובצים לפי עמוד/שקופית/גיליון תחילה. עבור פורמטים שאינם מבוססי דפים (DOCX, HTML, Markdown וכו'), למפענח יש אסטרטגיה לחלוקת המסמך לסעיפים. זה מוגדר בזמן ריצה באמצעות `--section-strategy`.
|
||||
עבור פורמטים מבוססי עמודים (PDF, PPTX, XLSX), אלמנטים תמיד מקובצים
|
||||
לפי עמוד/שקופית/גיליון. עבור פורמטים שאינם מבוססי עמודים (DOCX, HTML, Markdown,
|
||||
וכו'), למפענח יש אסטרטגיה לחלוקת המסמך לקטעים.
|
||||
זה מוגדר בזמן ריצה באמצעות `--section-strategy`.
|
||||
|
||||
כל אסטרטגיה היא פונקציית קיבוץ על רשימת האלמנטים של `unstructured`. הפלט הוא רשימת קבוצות אלמנטים; שאר הצינור (הרכבת טקסט, אחסון בספריית הניהול, תיעוד, פליטת `TextDocument`) זהים ללא קשר לאסטרטגיה.
|
||||
כל אסטרטגיה היא פונקציית קיבוץ על רשימת `unstructured`
|
||||
אלמנטים. הפלט הוא רשימה של קבוצות אלמנטים; שאר
|
||||
התהליך (הרכבת טקסט, אחסון בספרייה, מקור, פלט של מסמך טקסט
|
||||
(TextDocument)) זהים ללא קשר לאסטרטגיה.
|
||||
|
||||
#### `whole-document` (ברירת מחדל)
|
||||
|
||||
פליטת כל המסמך כסעיף יחיד. תן למחלק במעלה הזרם לטפל בכל החלוקה.
|
||||
להוציא את כל המסמך כקטע יחיד. לאפשר ליחידת החלוקה
|
||||
(chunker) לטפל בכל החלוקה.
|
||||
|
||||
- גישה פשוטה, נקודת התחלה טובה.
|
||||
- עשויה ליצור `TextDocument` גדול מאוד עבור קבצים גדולים, אך המחלק מטפל בכך.
|
||||
- הטוב ביותר כאשר אתה רוצה הקשר מרבי לכל סעיף.
|
||||
גישה פשוטה, קו בסיס טוב
|
||||
עלול לייצר מסמך טקסט גדול מאוד עבור קבצים גדולים, אך יחידת החלוקה
|
||||
מטפלת בכך
|
||||
הטוב ביותר כאשר רוצים הקשר מקסימלי לכל קטע
|
||||
|
||||
#### `heading`
|
||||
|
||||
פיצול בכותרות (`Title`). כל סעיף הוא כותרת וכל התוכן עד לכותרת ברמה שווה או גבוהה יותר. כותרות מקוננות יוצרות סעיפים מקוננים.
|
||||
לחלק בנקודות כותרת (`Title`). כל קטע הוא כותרת וכל
|
||||
התוכן עד הכותרת הבאה באותו רמה או ברמה גבוהה יותר.
|
||||
כותרות מקוננות יוצרות קטעים מקוננים.
|
||||
|
||||
- מייצר יחידות מגובשות מבחינה נושאית.
|
||||
- עובד היטב עבור מסמכים מובנים (דוחות, מדריכים, מפרטים).
|
||||
- נותן למחלץ ה-LLM הקשר של כותרת יחד עם התוכן.
|
||||
- חוזר ל-`whole-document` אם לא נמצאות כותרות.
|
||||
מייצר יחידות בעלות קוהרנטיות נושאית
|
||||
עובד היטב עבור מסמכים מובנים (דוחות, מדריכים, מפרטים)
|
||||
מספק למודל השפה הגדול (LLM) שמבצע חילוץ הקשר של כותרת יחד עם תוכן
|
||||
חוזר ל-`whole-document` אם לא נמצאות כותרות
|
||||
|
||||
#### `element-type`
|
||||
|
||||
פיצול כאשר סוג האלמנט משתנה באופן משמעותי — במיוחד, התחלה של סעיף חדש במעברים בין טקסט נרטיבי לטבלאות. אלמנטים עוקבים מאותה קטגוריה רחבה (טקסט, טקסט, טקסט או טבלה, טבלה) נשארים מקובצים.
|
||||
לחלק כאשר סוג האלמנט משתנה באופן משמעותי - ספציפית,
|
||||
להתחיל קטע חדש במעברים בין טקסט נרטיבי לטבלאות.
|
||||
אלמנטים עוקבים מאותה קטגוריה רחבה (טקסט, טקסט, טקסט או
|
||||
טבלה, טבלה) נשארים מקובצים.
|
||||
|
||||
- שומר על טבלאות כסעיפים עצמאיים.
|
||||
- טוב למסמכים עם תוכן מעורב (דוחות עם טבלאות נתונים).
|
||||
- לטבלאות יש תשומת לב חילוץ ייעודית.
|
||||
שומר על טבלאות כקטעים עצמאיים
|
||||
טוב עבור מסמכים עם תוכן מעורב (דוחות עם טבלאות נתונים)
|
||||
לטבלאות ניתנת תשומת לב ייעודית לחילוץ
|
||||
|
||||
#### `count`
|
||||
|
||||
קיבוץ מספר קבוע של אלמנטים לכל סעיף. ניתן להגדרה באמצעות `--section-element-count` (ברירת מחדל: 20).
|
||||
לקבץ מספר קבוע של אלמנטים לכל קטע. ניתן להגדרה באמצעות
|
||||
`--section-element-count` (ברירת מחדל: 20).
|
||||
|
||||
- פשוט וצפוי.
|
||||
- לא מכבד את מבנה המסמך.
|
||||
- שימושי כברירת מחדל או לניסויים.
|
||||
פשוט וצפוי
|
||||
אינו מכבד את מבנה המסמך
|
||||
שימושי כברירת מחדל או לניסויים
|
||||
|
||||
#### `size`
|
||||
|
||||
צבירת אלמנטים עד שמגיעים לגבול תווים, ואז התחלת סעיף חדש. מכבד את גבולות האלמנטים — לעולם לא מפצל באמצע אלמנט. ניתן להגדרה באמצעות `--section-max-size` (ברירת מחדל: 4000 תווים).
|
||||
צבירה של אלמנטים עד להגעה למגבלת תווים, ולאחר מכן התחלה של
|
||||
סעיף חדש. מכבד גבולות של אלמנטים - לעולם לא מפצל באמצע אלמנט.
|
||||
ניתן להגדיר באמצעות `--section-max-size` (ברירת מחדל: 4000 תווים).
|
||||
|
||||
- מייצר גדלים בערך אחידים של סעיפים.
|
||||
- מכבד את גבולות האלמנטים (בניגוד למחלק במעלה הזרם).
|
||||
- פשרה טובה בין שליטה במבנה ובגודל.
|
||||
- אם אלמנט יחיד חורג מהגבול, הוא הופך לסעיף משלו.
|
||||
מייצר גדלי חלקים אחידים בערך.
|
||||
מכבד גבולות של אלמנטים (בניגוד למחלק החלקים הבא).
|
||||
פשרה טובה בין מבנה לשליטה בגודל.
|
||||
אם אלמנט בודד חורג מהמגבלה, הוא הופך לחלק בפני עצמו.
|
||||
|
||||
#### אינטראקציה עם פורמטים מבוססי דפים
|
||||
#### פורמט מבוסס עמודים - אינטראקציה
|
||||
|
||||
עבור פורמטים מבוססי דפים, הקיבוץ לפי עמוד תמיד מקבל עדיפות. אסטרטגיות סעיפים יכולות באופן אופציונלי להחיל *בתוך* עמוד אם הוא גדול מאוד (לדוגמה, עמוד PDF עם טבלה עצומה), דבר ששולט על ידי `--section-within-pages` (ברירת מחדל: false). כאשר זה כוזב, כל עמוד תמיד סעיף אחד ללא קשר לגודל.
|
||||
עבור פורמטים מבוססי עמודים, קיבוץ העמודים תמיד מקבל עדיפות.
|
||||
ניתן ליישם אסטרטגיות סעיפים באופן אופציונלי *בתוך* עמוד אם הוא גדול מאוד
|
||||
(לדוגמה, עמוד PDF עם טבלה עצומה), תוך שליטה באמצעות
|
||||
`--section-within-pages` (ברירת מחדל: false). כאשר הערך הוא false, כל עמוד הוא
|
||||
תמיד סעיף אחד ללא קשר לגודלו.
|
||||
|
||||
### זיהוי פורמט
|
||||
|
||||
למפענח יש צורך לדעת את סוג MIME של המסמך כדי להעביר ל-`partition()` של `unstructured`. שתי אפשרויות:
|
||||
ה-דקודר צריך לדעת את סוג ה-mime של המסמך כדי להעביר ל-
|
||||
`unstructured`'s `partition()`. שני מסלולים:
|
||||
|
||||
- **נתיב ספריית הניהול** (`document_id` מוגדר): אחסון מטא-דאטה של מסמך מהספרייה תחילה — זה נותן לנו את `kind` (סוג MIME) שנרשם בזמן ההעלאה. ואז אחסון תוכן מסמך. שתי קריאות לספריית הניהול, אך אחזור המטא-דאטה קל משקל.
|
||||
- **נתיב מקומי** (תאימות לאחור, `data` מוגדר): אין מטא-דאטה זמין על ההודעה. השתמש ב-`python-magic` כדי לזהות את הפורמט מתוך בתים של תוכן כגיבוי.
|
||||
**נתיב הספרן** (הגדרת `document_id`): אחזור מטא-דאטה של המסמך
|
||||
מהספרן תחילה - זה נותן לנו את ה-`kind` (סוג ה-mime)
|
||||
שנרשם בזמן ההעלאה. לאחר מכן, אחזור תוכן המסמך.
|
||||
שני שימושים בספרן, אך אחזור המטא-דאטה קל משקל.
|
||||
**נתיב מקוון** (תאימות לאחור, הגדרת `data`): אין מטא-דאטה
|
||||
זמין בהודעה. השתמש ב-`python-magic` כדי לזהות את הפורמט
|
||||
מתוך בייטי התוכן כפתרון חלופי.
|
||||
|
||||
אין צורך בשינויים בסכימה של `Document` - הספרן כבר מאחסן את סוג ה-mime.
|
||||
|
||||
אין צורך בשינויים בסכימת `Document` — ספריית הניהול כבר מאחסנת את סוג ה-MIME.
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
שירות `universal-decoder` יחיד שמבצע את הפעולות הבאות:
|
||||
שירות `universal-decoder` יחיד שמבצע:
|
||||
|
||||
1. מקבל הודעת `Document` (מקומית או באמצעות הפניה לספריית הניהול).
|
||||
2. אם נתיב ספריית הניהול: אחסון מטא-דאטה של מסמך (קבלת סוג MIME), ואז אחסון תוכן. אם נתיב מקומי: זיהוי פורמט מתוך בתים של תוכן.
|
||||
3. קריאה ל-`partition()` כדי לחלץ אלמנטים.
|
||||
4. קיבוץ אלמנטים: לפי עמוד עבור פורמטים מבוססי דפים, לפי אסטרטגיית סעיף מוגדרת עבור פורמטים שאינם מבוססי דפים.
|
||||
5. עבור כל עמוד/סעיף:
|
||||
- יצירת ID `urn:page:{uuid}` או `urn:section:{uuid}`.
|
||||
- הרכבת טקסט עמוד: טקסט רגיל, טבלאות כ-HTML, תמונות מושמטות.
|
||||
- חישוב ההיסט מוחלט של כל אלמנט בתוך טקסט העמוד.
|
||||
- שמירה בספריית הניהול כתיעוד משני.
|
||||
- יצירת משולשים של תיעוד עם מטא-דאטה מיקומי.
|
||||
- שליחת `TextDocument` במעלה הזרם לחלוקה.
|
||||
1. מקבל הודעה `Document` (בשורת הטקסט או דרך הפניה לספרייה).
|
||||
2. אם הנתיב הוא דרך הספרייה: שולף מטא-דאטה של המסמך (מקבל את סוג ה-mime), ואז
|
||||
שולף את התוכן. אם הנתיב הוא בתוך הטקסט: מזהה את הפורמט מהבייטים של התוכן.
|
||||
3. קורא לפונקציה `partition()` כדי לחלץ אלמנטים.
|
||||
4. קיבוץ אלמנטים: לפי עמוד עבור פורמטים מבוססי עמוד, לפי אסטרטגיית סעיפים מוגדרת עבור פורמטים שאינם מבוססי עמוד.
|
||||
סעיף.
|
||||
5. עבור כל עמוד/קטע:
|
||||
מייצר מזהה `urn:page:{uuid}` או `urn:section:{uuid}`
|
||||
מרכיב את תוכן העמוד: טקסט נרטיבי כטקסט רגיל, טבלאות כ-HTML,
|
||||
תמונות מדלגות
|
||||
מחשב את ההיסטים של כל תו בתוך הטקסט של העמוד.
|
||||
שומר ל-librarian כמסמך משני.
|
||||
משדר משולשי מוצא עם מטא-נתונים מיקומיים.
|
||||
שולח `TextDocument` במורד הזרם לצורך חלוקה.
|
||||
6. עבור כל אלמנט תמונה:
|
||||
- יצירת ID `urn:image:{uuid}`.
|
||||
- שמירת נתוני תמונה בספריית הניהול כתיעוד משני.
|
||||
- יצירת משולשים של תיעוד (מאוחסנים בלבד, אינם נשלחים במעלה הזרם).
|
||||
מייצר מזהה `urn:image:{uuid}`.
|
||||
שומר את נתוני התמונה ל-librarian כמסמך משני.
|
||||
משדר משולשי מוצא (נשמרים בלבד, לא נשלחים במורד הזרם).
|
||||
|
||||
### טיפול בפורמטים
|
||||
|
||||
| פורמט | סוג MIME | מבוסס עמוד | הערות |
|
||||
|---|---|---|---|
|
||||
| PDF | application/pdf | כן | קיבוץ לפי עמוד |
|
||||
| DOCX | application/vnd.openxmlformats... | לא | משתמש באסטרטגיית סעיף |
|
||||
| PPTX | application/vnd.openxmlformats... | כן | קיבוץ לפי שקופית |
|
||||
| XLSX/XLS | application/vnd.openxmlformats... | כן | קיבוץ לפי גיליון |
|
||||
| HTML | text/html | לא | משתמש באסטרטגיית סעיף |
|
||||
| Markdown | text/markdown | לא | משתמש באסטרטגיית סעיף |
|
||||
| רגיל | text/plain | לא | משתמש באסטרטגיית סעיף |
|
||||
| CSV | text/csv | לא | משתמש באסטרטגיית סעיף |
|
||||
| RST | text/x-rst | לא | משתמש באסטרטגיית סעיף |
|
||||
| RTF | application/rtf | לא | משתמש באסטרטגיית סעיף |
|
||||
| ODT | application/vnd.oasis... | לא | משתמש באסטרטגיית סעיף |
|
||||
| TSV | text/tab-separated-values | לא | משתמש באסטרטגיית סעיף |
|
||||
| פורמט | סוג MIME | מבוסס דפים | הערות |
|
||||
|----------|------------------------------------|------------|--------------------------------|
|
||||
| PDF | application/pdf | כן | קיבוץ לפי דף |
|
||||
| DOCX | application/vnd.openxmlformats... | לא | משתמש באסטרטגיית סעיפים |
|
||||
| PPTX | application/vnd.openxmlformats... | כן | קיבוץ לפי שקופית |
|
||||
| XLSX/XLS | application/vnd.openxmlformats... | כן | קיבוץ לפי גיליון |
|
||||
| HTML | text/html | לא | משתמש באסטרטגיית סעיפים |
|
||||
| Markdown | text/markdown | לא | משתמש באסטרטגיית סעיפים |
|
||||
| Plain | text/plain | לא | משתמש באסטרטגיית סעיפים |
|
||||
| CSV | text/csv | לא | משתמש באסטרטגיית סעיפים |
|
||||
| RST | text/x-rst | לא | משתמש באסטרטגיית סעיפים |
|
||||
| RTF | application/rtf | לא | משתמש באסטרטגיית סעיפים |
|
||||
| ODT | application/vnd.oasis... | לא | משתמש באסטרטגיית סעיפים |
|
||||
| TSV | text/tab-separated-values | לא | משתמש באסטרטגיית סעיפים |
|
||||
|
||||
### מטא-דאטה של תיעוד
|
||||
### מטא-דאטה של מקור
|
||||
|
||||
כל ישות עמוד/סעיף רושמת מטא-דאטה מיקומי כמשולשים של תיעוד בגרף `GRAPH_SOURCE`, ומאפשרת מעקב מלא מהמשולשים של גרף ידע חזרה למיקומי המסמך המקוריים.
|
||||
כל ישות דף/סעיף מתעדת מטא-דאטה מיקום כמשולשים של מקור
|
||||
ב-`GRAPH_SOURCE`, המאפשר מעקב מלא ממשולשים של גרף ידע
|
||||
חזרה למיקומי המסמך המקורי.
|
||||
|
||||
#### שדות קיימים (כבר ב-`derived_entity_triples`)
|
||||
|
||||
- `page_number` — מספר עמוד/גיליון/שקופית (מוגדר מ-1, רק עבור פורמטים מבוססי עמודים)
|
||||
- `char_offset` — היסט מוחלט של תווים של עמוד/סעיף זה בתוך הטקסט המלא של המסמך.
|
||||
- `char_length` — אורך התווים של הטקסט של עמוד/סעיף זה.
|
||||
`page_number` — מספר דף/גיליון/שקופית (מתחיל מ-1, רק עבור פורמטים מבוססי דפים)
|
||||
`char_offset` — ההיסט של התווים של דף/סעיף זה בתוך
|
||||
הטקסט המלא של המסמך
|
||||
`char_length` — אורך התווים של הטקסט של דף/סעיף זה
|
||||
|
||||
#### שדות חדשים (הרחבת `derived_entity_triples`)
|
||||
#### שדות חדשים (הרחבה של `derived_entity_triples`)
|
||||
|
||||
- `mime_type` — פורמט מסמך מקורי (לדוגמה, `application/pdf`)
|
||||
- `element_types` — רשימה מופרדת בפסיקים של קטגוריות `unstructured` של אלמנטים (לדוגמה, `title, paragraph, table`).
|
||||
- `provenance` — מידע על מקור הנתונים.
|
||||
`mime_type` — פורמט המסמך המקורי (לדוגמה, `application/pdf`)
|
||||
`element_types` — רשימה מופרדת בפסיקים של קטגוריות `unstructured`
|
||||
שנמצאו בדף/סעיף זה (לדוגמה, "כותרת,טקסט נרטיבי,טבלה")
|
||||
`table_count` — מספר הטבלאות בדף/סעיף זה
|
||||
`image_count` — מספר התמונות בדף/סעיף זה
|
||||
|
||||
אלה דורשים טווח שמות של טריגרים חדשים:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
TG_IMAGE_TYPE = "https://trustgraph.ai/ns/Image"
|
||||
TG_ELEMENT_TYPES = "https://trustgraph.ai/ns/elementTypes"
|
||||
TG_TABLE_COUNT = "https://trustgraph.ai/ns/tableCount"
|
||||
TG_IMAGE_COUNT = "https://trustgraph.ai/ns/imageCount"
|
||||
```
|
||||
|
||||
סכימת URN לתמונות: `urn:image:{uuid}`
|
||||
|
||||
(`TG_MIME_TYPE` כבר קיים.)
|
||||
|
||||
#### סוג ישות חדש
|
||||
|
||||
עבור פורמטים שאינם דפי אינטרנט (DOCX, HTML, Markdown, וכו') שבהם
|
||||
ה-דקודר משדר את כל המסמך כיחידה אחת ולא מחלק אותו לדפים,
|
||||
הישות מקבלת סוג חדש:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
```
|
||||
|
||||
זה מבחין בין חלקים לדפים בעת שאילתת מקור:
|
||||
|
||||
| ישות | סוג | מתי משמש |
|
||||
|----------|-----------------------------|----------------------------------------|
|
||||
| מסמך | `tg:Document` | קובץ שהועלה במקור |
|
||||
| דף | `tg:Page` | פורמטים מבוססי דפים (PDF, PPTX, XLSX) |
|
||||
| חלק | `tg:Section` | פורמטים שאינם מבוססי דפים (DOCX, HTML, MD, וכו') |
|
||||
| תמונה | `tg:Image` | תמונות מוטמעות (מאוחסנות, לא מעובדות) |
|
||||
| מקטע | `tg:Chunk` | פלט של מפריד מקטעים |
|
||||
| תת-גרף | `tg:Subgraph` | פלט של חילוץ גרף ידע |
|
||||
|
||||
הסוג נקבע על ידי ה-decoder בהתאם לשאלה האם הוא מקבץ לפי עמוד
|
||||
או פולט חלק שלם מהמסמך. `derived_entity_triples` מקבל
|
||||
פרמטר בוליאני אופציונלי `section` — כאשר הוא מוגדר כ-true, היישות היא
|
||||
הוקלד כ-`tg:Section` במקום `tg:Page`.
|
||||
|
||||
#### שרשרת מקור מלאה
|
||||
|
||||
```
|
||||
KG triple
|
||||
→ subgraph (extraction provenance)
|
||||
→ chunk (char_offset, char_length within page)
|
||||
→ page/section (page_number, char_offset, char_length within doc, mime_type, element_types)
|
||||
→ document (original file in librarian)
|
||||
```
|
||||
|
||||
כל קישור הוא קבוצה של שלשות בגרף המכונה `GRAPH_SOURCE`.
|
||||
|
||||
### תצורת שירות
|
||||
|
||||
ארגומנטים של שורת הפקודה:
|
||||
|
||||
```
|
||||
--strategy Partitioning strategy: auto, hi_res, fast (default: auto)
|
||||
--languages Comma-separated OCR language codes (default: eng)
|
||||
--section-strategy Section grouping: whole-document, heading, element-type,
|
||||
count, size (default: whole-document)
|
||||
--section-element-count Elements per section for 'count' strategy (default: 20)
|
||||
--section-max-size Max chars per section for 'size' strategy (default: 4000)
|
||||
--section-within-pages Apply section strategy within pages too (default: false)
|
||||
```
|
||||
|
||||
בנוסף ל-`FlowProcessor` הסטנדרטי ולטיעוני תור המאפשרים גישה לספרייה.
|
||||
|
||||
### אינטגרציה של זרימת העבודה
|
||||
|
||||
ה-דקודר האוניברסלי תופס את אותו מיקום בזרימת העיבוד
|
||||
כמו ה-דקודר של PDF הנוכחי:
|
||||
|
||||
```
|
||||
Document → [universal-decoder] → TextDocument → [chunker] → Chunk → ...
|
||||
```
|
||||
|
||||
זה רושם:
|
||||
`input` צרכן (סכימת מסמכים)
|
||||
`output` מפיק (סכימת TextDocument)
|
||||
`triples` מפיק (סכימת Triples)
|
||||
בקשה/תגובה של ספרן (לשליפה ואחסון של מסמכים משניים)
|
||||
|
||||
### פריסה
|
||||
|
||||
קונטיינר חדש: `trustgraph-flow-universal-decoder`
|
||||
תלות: `unstructured[all-docs]` (כולל PDF, DOCX, PPTX, וכו')
|
||||
ניתן להפעיל לצד או להחליף את מפענח ה-PDF הקיים, בהתאם
|
||||
לתצורת זרימת העבודה
|
||||
מפענח ה-PDF הקיים נשאר זמין עבור סביבות שבהן
|
||||
התלויות של `unstructured` כבדות מדי
|
||||
|
||||
### מה משתנה
|
||||
|
||||
| רכיב | שינוי |
|
||||
|------------------------------|-------------------------------------------------|
|
||||
| `provenance/namespaces.py` | הוספת `TG_SECTION_TYPE`, `TG_IMAGE_TYPE`, `TG_ELEMENT_TYPES`, `TG_TABLE_COUNT`, `TG_IMAGE_COUNT` |
|
||||
| `provenance/triples.py` | הוספת ארגומנטים `mime_type`, `element_types`, `table_count`, `image_count` (kwargs) |
|
||||
| `provenance/__init__.py` | ייצוא קבועים חדשים |
|
||||
| חדש: `decoding/universal/` | מודול שירות פענוח חדש |
|
||||
| `setup.cfg` / `pyproject` | הוספת תלות `unstructured[all-docs]` |
|
||||
| Docker | תמונת קונטיינר חדשה |
|
||||
| הגדרות זרימה | חיבור universal-decoder כקלט מסמך |
|
||||
|
||||
### מה שלא משתנה
|
||||
|
||||
Chunker (מקבל TextDocument, פועל כרגיל)
|
||||
מודולים לחילוץ מידע (מקבלים Chunk, ללא שינוי)
|
||||
Librarian (מאחסן מסמכים משניים, ללא שינוי)
|
||||
Schema (Document, TextDocument, Chunk ללא שינוי)
|
||||
מקור מידע בזמן שאילתה (ללא שינוי)
|
||||
|
||||
## סיכונים
|
||||
|
||||
ל-`unstructured[all-docs]` יש תלות רבה (poppler, tesseract,
|
||||
libreoffice עבור פורמטים מסוימים). תמונת המכולה תהיה גדולה יותר.
|
||||
פתרון אפשרי: להציע גרסה של `[light]` ללא תלות ב-OCR/office.
|
||||
פורמטים מסוימים עשויים לייצר חילוץ טקסט באיכות ירודה (קבצי PDF מסרוקים ללא
|
||||
OCR, פריסות מורכבות של קבצי XLSX). אמצעי מניעה: פרמטר הניתן להגדרה `strategy`.
|
||||
ומפענח ה-OCR של Mistral הקיים זמין
|
||||
עבור OCR באיכות גבוהה של קבצי PDF.
|
||||
עדכוני גרסה של `unstructured` עשויים לשנות מטא-נתונים של אלמנטים.
|
||||
אמצעי מניעה: קביעת גרסה, בדיקת איכות החילוץ עבור כל פורמט.
|
||||
|
|
|
|||
|
|
@ -1,31 +1,396 @@
|
|||
## सार्वभौमिक दस्तावेज़ डीकोडर
|
||||
# यूनिवर्सल डॉक्यूमेंट डिकोडर
|
||||
|
||||
## शीर्षक
|
||||
|
||||
`unstructured` द्वारा संचालित, सार्वभौमिक दस्तावेज़ डीकोडर - एकल सेवा के माध्यम से किसी भी सामान्य दस्तावेज़ प्रारूप को इनपुट करें, जिसमें पूर्ण उत्पत्ति और लाइब्रेरियन एकीकरण के साथ पूर्ण ट्रेसबिलिटी के लिए स्रोत स्थितियों को रिकॉर्ड किया जाता है।
|
||||
यूनिवर्सल डॉक्यूमेंट डिकोडर जो `unstructured` द्वारा संचालित है — किसी भी सामान्य
|
||||
डॉक्यूमेंट फॉर्मेट को एक ही सेवा के माध्यम से संसाधित करें, जिसमें पूर्ण उत्पत्ति और लाइब्रेरियन
|
||||
एकीकरण शामिल है, जो स्रोत स्थितियों को ज्ञान ग्राफ मेटाडेटा के रूप में रिकॉर्ड करता है ताकि
|
||||
एंड-टू-एंड पता लगाया जा सके।
|
||||
|
||||
## समस्या
|
||||
|
||||
ट्रस्टग्राफ वर्तमान में केवल पीडीएफ के लिए डीकोडर प्रदान करता है। DOCX, XLSX, HTML, Markdown, सरल टेक्स्ट, PPTX, आदि जैसे अतिरिक्त प्रारूपों का समर्थन करने के लिए, एक पूर्ण समाधान की आवश्यकता है।
|
||||
वर्तमान में ट्रस्टग्राफ में एक पीडीएफ-विशिष्ट डिकोडर है। अतिरिक्त
|
||||
फॉर्मेट (DOCX, XLSX, HTML, Markdown, प्लेन टेक्स्ट, PPTX, आदि) का समर्थन करने के लिए
|
||||
या तो प्रत्येक फॉर्मेट के लिए एक नया डिकोडर लिखना होगा या एक सार्वभौमिक निष्कर्षण
|
||||
लाइब्रेरी को अपनाना होगा। प्रत्येक फॉर्मेट की संरचना अलग होती है — कुछ पृष्ठ-आधारित होते हैं, कुछ
|
||||
नहीं होते हैं — और निष्कर्षित पाठ के प्रत्येक टुकड़े की उत्पत्ति मूल
|
||||
डॉक्यूमेंट में कहां से हुई, इसे उत्पत्ति श्रृंखला में रिकॉर्ड किया जाना चाहिए।
|
||||
|
||||
## समाधान
|
||||
## दृष्टिकोण
|
||||
|
||||
इस दस्तावेज़ में, हम एक सार्वभौमिक डीकोडर प्रदान करते हैं जो विभिन्न प्रारूपों के दस्तावेज़ों को संसाधित कर सकता है। यह डीकोडर `unstructured` लाइब्रेरी का उपयोग करता है, जो विभिन्न प्रारूपों के दस्तावेज़ों को पार करने के लिए डिज़ाइन किया गया है।
|
||||
### लाइब्रेरी: `unstructured`
|
||||
|
||||
## कार्यान्वयन
|
||||
`unstructured.partition.auto.partition()` का उपयोग करें जो फॉर्मेट को स्वचालित रूप से पहचानता है
|
||||
mime टाइप या फ़ाइल एक्सटेंशन से और संरचित तत्वों को निकालता है
|
||||
(शीर्षक, वर्णनात्मक पाठ, तालिका, सूची आइटम, आदि)। प्रत्येक तत्व में
|
||||
मेटाडेटा शामिल है:
|
||||
|
||||
डीकोडर निम्नलिखित चरणों में दस्तावेज़ों को संसाधित करता है:
|
||||
`page_number` (पीडीएफ, पीपीटीएक्स जैसे पृष्ठ-आधारित फॉर्मेट के लिए)
|
||||
`element_id` (प्रत्येक तत्व के लिए अद्वितीय)
|
||||
`coordinates` (पीडीएफ के लिए बाउंडिंग बॉक्स)
|
||||
`text` (निष्कर्षित पाठ सामग्री)
|
||||
`category` (तत्व प्रकार: शीर्षक, वर्णनात्मक पाठ, तालिका, आदि)
|
||||
|
||||
1. दस्तावेज़ को इनपुट के रूप में स्वीकार करता है।
|
||||
2. दस्तावेज़ को संसाधित करने के लिए उपयुक्त प्रारूप का पता लगाता है।
|
||||
3. दस्तावेज़ को संसाधित करने के लिए आवश्यक डेटा निकालता है।
|
||||
4. निकाले गए डेटा को एक संरचित प्रारूप में संग्रहीत करता है।
|
||||
5. संरचित डेटा को अन्य घटकों को प्रदान करता है।
|
||||
### तत्व प्रकार
|
||||
|
||||
## परीक्षण
|
||||
`unstructured` डॉक्यूमेंट से टाइप किए गए तत्वों को निकालता है। प्रत्येक तत्व में
|
||||
एक श्रेणी और संबंधित मेटाडेटा होता है:
|
||||
|
||||
डीकोडर को विभिन्न प्रकार के दस्तावेज़ों पर परीक्षण किया गया है, जिनमें पीडीएफ, DOCX, HTML और Markdown शामिल हैं। परीक्षणों के परिणामों से पता चला है कि डीकोडर विभिन्न प्रारूपों के दस्तावेज़ों को सफलतापूर्वक संसाधित कर सकता है।
|
||||
**पाठ तत्व:**
|
||||
`Title` — अनुभाग शीर्षक
|
||||
`NarrativeText` — पैराग्राफ
|
||||
`ListItem` — बुलेट/क्रमांकित सूची आइटम
|
||||
`Header`, `Footer` — पृष्ठ हेडर/फुटर
|
||||
`FigureCaption` — चित्रों/छवियों के लिए कैप्शन
|
||||
`Formula` — गणितीय व्यंजक
|
||||
`Address`, `EmailAddress` — संपर्क जानकारी
|
||||
`CodeSnippet` — कोड ब्लॉक (मार्कडाउन से)
|
||||
|
||||
## निष्कर्ष
|
||||
**तालिकाएँ:**
|
||||
`Table` — संरचित सारणीबद्ध डेटा। `unstructured` दोनों प्रदान करता है
|
||||
`element.text` (सादा पाठ) और `element.metadata.text_as_html`
|
||||
(पंक्तियों, स्तंभों और शीर्षकों को संरक्षित करते हुए पूर्ण HTML `<table>`)।
|
||||
DOCX, XLSX, HTML जैसे स्पष्ट तालिका संरचना वाले फॉर्मेट के लिए,
|
||||
निष्कर्षण अत्यधिक विश्वसनीय है। पीडीएफ के लिए, तालिका का पता लगाना
|
||||
लेआउट विश्लेषण के साथ `hi_res` रणनीति पर निर्भर करता है।
|
||||
|
||||
यह सार्वभौमिक दस्तावेज़ डीकोडर विभिन्न प्रारूपों के दस्तावेज़ों को संसाधित करने के लिए एक शक्तिशाली और लचीला उपकरण है।
|
||||
**छवियाँ:**
|
||||
`Image` — लेआउट विश्लेषण के माध्यम से पता लगाई गई एम्बेडेड छवियां (आवश्यक
|
||||
`hi_res` रणनीति)। `extract_image_block_to_payload=True` के साथ,
|
||||
छवि डेटा को `element.metadata.image_base64` में base64 के रूप में लौटाता है।
|
||||
छवि से OCR पाठ `element.text` में उपलब्ध है।
|
||||
|
||||
### तालिका हैंडलिंग
|
||||
|
||||
तालिकाओं को एक प्राथमिक आउटपुट माना जाता है। जब डिकोडर एक `Table`
|
||||
तत्व का सामना करता है, तो यह सादे पाठ में समतल करने के बजाय HTML संरचना को संरक्षित करता है।
|
||||
यह डाउनस्ट्रीम एलएलएम निष्कर्षण को सारणीबद्ध डेटा से संरचित ज्ञान निकालने के लिए
|
||||
बहुत बेहतर इनपुट देता है।
|
||||
|
||||
पृष्ठ/अनुभाग पाठ को इस प्रकार जोड़ा जाता है:
|
||||
पाठ तत्व: सादा पाठ, नई पंक्तियों के साथ जोड़ा गया
|
||||
तालिका तत्व: `text_as_html` से HTML तालिका मार्कअप, एक
|
||||
`<table>` मार्कर में लपेटा गया ताकि एलएलएम तालिकाओं को वर्णनात्मक
|
||||
पाठ से अलग कर सके।
|
||||
उदाहरण के लिए, एक शीर्षक, पैराग्राफ और तालिका वाला पृष्ठ इस प्रकार होगा:
|
||||
|
||||
```
|
||||
Financial Overview
|
||||
|
||||
Revenue grew 15% year-over-year driven by enterprise adoption.
|
||||
|
||||
<table>
|
||||
<tr><th>Quarter</th><th>Revenue</th><th>Growth</th></tr>
|
||||
<tr><td>Q1</td><td>$12M</td><td>12%</td></tr>
|
||||
<tr><td>Q2</td><td>$14M</td><td>17%</td></tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
यह चंकिंग के माध्यम से तालिका संरचना को संरक्षित करता है और निष्कर्षण
|
||||
पाइपलाइन में, जहां एलएलएम सीधे संरचित कोशिकाओं से संबंधों को निकाल सकता है,
|
||||
कॉलम संरेखण का अनुमान लगाने के बजाय खाली स्थान से।
|
||||
|
||||
|
||||
### छवि प्रबंधन
|
||||
|
||||
छवियों को लाइब्रेरियन में चाइल्ड दस्तावेज़ों के रूप में निकाला और संग्रहीत किया जाता है
|
||||
`document_type="image"` और एक `urn:image:{uuid}` आईडी के साथ। उन्हें
|
||||
प्रकार `tg:Image` के साथ प्रामाणिकता ट्रिपल मिलते हैं, जो उनके मूल
|
||||
पृष्ठ/अनुभाग से `prov:wasDerivedFrom` के माध्यम से जुड़े होते हैं। छवि मेटाडेटा (निर्देशांक,
|
||||
आयाम, तत्व_आईडी) को प्रामाणिकता में दर्ज किया जाता है।
|
||||
|
||||
**महत्वपूर्ण रूप से, छवियों को टेक्स्टडॉक्यूमेंट आउटपुट के रूप में उत्सर्जित नहीं किया जाता है।** वे
|
||||
केवल संग्रहीत होते हैं - चंकर या किसी भी टेक्स्ट प्रोसेसिंग
|
||||
पाइपलाइन में नीचे की ओर नहीं भेजे जाते हैं। यह जानबूझकर है:
|
||||
|
||||
1. अभी तक कोई छवि प्रसंस्करण पाइपलाइन नहीं है (विज़न मॉडल एकीकरण
|
||||
भविष्य का कार्य है)
|
||||
2. आधार64 छवि डेटा या ओसीआर टुकड़ों को टेक्स्ट निष्कर्षण
|
||||
पाइपलाइन में फीड करने से कचरा केजी ट्रिपल उत्पन्न होंगे
|
||||
|
||||
छवियों को असेंबल किए गए पृष्ठ टेक्स्ट से भी बाहर रखा गया है - कोई भी `Image`
|
||||
तत्व एक पृष्ठ/अनुभाग के लिए तत्व टेक्स्ट को संयोजित करते समय चुपचाप छोड़ दिए जाते हैं। प्रामाणिकता श्रृंखला में दर्ज किया गया है कि छवियां मौजूद हैं और वे दस्तावेज़ में कहां दिखाई दीं, ताकि उन्हें भविष्य के
|
||||
पृष्ठ/अनुभाग। उत्पत्ति श्रृंखला में दर्ज है कि चित्र मौजूद हैं और वे कहाँ स्थित हैं।
|
||||
छवि प्रसंस्करण पाइपलाइन द्वारा दस्तावेज़ को फिर से संसाधित किए बिना प्राप्त किया जा सके।
|
||||
|
||||
|
||||
#### भविष्य का कार्य
|
||||
|
||||
`tg:Image` संस्थाओं को विवरण,
|
||||
आरेख व्याख्या या चार्ट डेटा निष्कर्षण के लिए एक विज़न मॉडल में रूट करें
|
||||
छवि विवरण को टेक्स्ट चाइल्ड दस्तावेज़ों के रूप में संग्रहीत करें जो
|
||||
मानक चंकिंग/निष्कर्षण पाइपलाइन में फीड करते हैं
|
||||
निकाले गए ज्ञान को प्रामाणिकता के माध्यम से स्रोत छवियों से लिंक करें
|
||||
|
||||
### अनुभाग रणनीतियाँ
|
||||
|
||||
पृष्ठ-आधारित प्रारूपों (पीडीएफ, पीपीटीएक्स, एक्सएलएसएक्स) के लिए, तत्वों को हमेशा
|
||||
पहले पृष्ठ/स्लाइड/शीट द्वारा समूहीकृत किया जाता है। गैर-पृष्ठ प्रारूपों (डीओसीएक्स, एचटीएमएल, मार्कडाउन,
|
||||
आदि) के लिए, डिकोडर को दस्तावेज़ को अनुभागों में विभाजित करने के लिए एक रणनीति की आवश्यकता होती है। यह ⟦CODE_0⟧ के माध्यम से रनटाइम पर कॉन्फ़िगर करने योग्य है।
|
||||
अनुभाग। यह `--section-strategy` के माध्यम से रनटाइम पर कॉन्फ़िगर किया जा सकता है।
|
||||
|
||||
प्रत्येक रणनीति `unstructured` तत्वों की सूची पर एक समूहीकरण फ़ंक्शन है। आउटपुट तत्वों के समूहों की एक सूची है; बाकी
|
||||
तत्व। आउटपुट तत्वों के समूहों की एक सूची है; बाकी का
|
||||
पाइपलाइन (टेक्स्ट असेंबली, लाइब्रेरियन स्टोरेज, प्रामाणिकता, टेक्स्टडॉक्यूमेंट
|
||||
उत्सर्जन) रणनीति की परवाह किए बिना समान है।
|
||||
|
||||
#### `whole-document` (डिफ़ॉल्ट)
|
||||
|
||||
पूरे दस्तावेज़ को एक ही अनुभाग के रूप में उत्सर्जित करें। डाउनस्ट्रीम
|
||||
चंकर को सभी विभाजन को संभालने दें।
|
||||
|
||||
सबसे सरल दृष्टिकोण, अच्छा आधार रेखा
|
||||
बड़ी फ़ाइलों के लिए बहुत बड़ा टेक्स्टडॉक्यूमेंट उत्पन्न कर सकता है, लेकिन चंकर
|
||||
इसे संभालता है
|
||||
जब आप प्रति अनुभाग अधिकतम संदर्भ चाहते हैं तो सबसे अच्छा
|
||||
|
||||
#### `heading`
|
||||
|
||||
शीर्षलेख तत्वों (`Title`) पर विभाजित करें। प्रत्येक अनुभाग एक शीर्षलेख प्लस
|
||||
सभी सामग्री है जब तक कि समान या उच्च स्तर का अगला शीर्षलेख न हो। नेस्टेड
|
||||
शीर्षलेख नेस्टेड अनुभाग बनाते हैं।
|
||||
|
||||
विषयगत रूप से सुसंगत इकाइयाँ उत्पन्न करता है
|
||||
संरचित दस्तावेज़ों (रिपोर्ट, मैनुअल, विनिर्देश) के लिए अच्छा काम करता है
|
||||
निष्कर्षण एलएलएम को सामग्री के साथ शीर्षलेख संदर्भ देता है
|
||||
यदि कोई शीर्षलेख नहीं मिला है तो `whole-document` पर वापस आ जाता है
|
||||
|
||||
#### `element-type`
|
||||
|
||||
जब तत्व प्रकार में महत्वपूर्ण परिवर्तन होता है तो विभाजित करें - विशेष रूप से,
|
||||
वर्णनात्मक पाठ और तालिकाओं के बीच संक्रमण पर एक नया अनुभाग शुरू करें। लगातार
|
||||
समान व्यापक श्रेणी (पाठ, पाठ, पाठ या
|
||||
तालिका, तालिका) के तत्व एक साथ समूहीकृत रहते हैं।
|
||||
|
||||
तालिकाओं को स्टैंडअलोन अनुभागों के रूप में रखता है
|
||||
मिश्रित सामग्री वाले दस्तावेज़ों (डेटा तालिकाओं वाली रिपोर्ट) के लिए अच्छा है
|
||||
तालिकाओं को समर्पित निष्कर्षण ध्यान मिलता है
|
||||
|
||||
#### `count`
|
||||
|
||||
तत्वों की एक निश्चित संख्या को प्रति अनुभाग समूहीकृत करें। ⟦CODE_0⟧ के माध्यम से कॉन्फ़िगर करने योग्य (डिफ़ॉल्ट: 20)।
|
||||
`--section-element-count` (डिफ़ॉल्ट: 20)।
|
||||
|
||||
सरल और अनुमानित
|
||||
दस्तावेज़ संरचना का सम्मान नहीं करता है
|
||||
प्रयोग के लिए एक फ़ॉलबैक या उपयोगी
|
||||
|
||||
#### `size`
|
||||
|
||||
तत्वों को तब तक जमा करें जब तक कि एक वर्ण सीमा तक न पहुँच जाए, फिर एक नया अनुभाग शुरू करें। तत्वों की सीमाओं का सम्मान करता है - कभी भी किसी तत्व के बीच में विभाजन नहीं करता है।
|
||||
नए अनुभाग। तत्वों की सीमाओं का सम्मान करता है - कभी भी किसी तत्व के बीच में विभाजन नहीं करता है।
|
||||
`--section-max-size` के माध्यम से कॉन्फ़िगर किया जा सकता है (डिफ़ॉल्ट: 4000 अक्षर)।
|
||||
|
||||
लगभग समान खंड आकार उत्पन्न करता है।
|
||||
तत्वों की सीमाओं का सम्मान करता है (डाउनस्ट्रीम चंकर के विपरीत)।
|
||||
संरचना और आकार नियंत्रण के बीच एक अच्छा समझौता।
|
||||
यदि कोई एकल तत्व सीमा से अधिक है, तो वह अपने आप में एक खंड बन जाता है।
|
||||
|
||||
#### पृष्ठ-आधारित प्रारूप इंटरैक्शन
|
||||
|
||||
पृष्ठ-आधारित स्वरूपों के लिए, पृष्ठ समूहीकरण हमेशा प्राथमिकता लेता है।
|
||||
अनुभाग रणनीतियों को वैकल्पिक रूप से एक पृष्ठ के *अंदर* लागू किया जा सकता है यदि वह बहुत बड़ा है (उदाहरण के लिए, एक बहुत बड़े तालिका वाला पीडीएफ पृष्ठ), जिसे द्वारा नियंत्रित किया जाता है।
|
||||
बड़ा (उदाहरण के लिए, एक पीडीएफ पृष्ठ जिसमें एक बहुत बड़ा तालिका है), जिसे नियंत्रित किया जाता है।
|
||||
`--section-within-pages` (डिफ़ॉल्ट: गलत)। जब गलत होता है, तो प्रत्येक पृष्ठ का
|
||||
आकार की परवाह किए बिना हमेशा एक ही खंड होता है।
|
||||
|
||||
### प्रारूप का पता लगाना
|
||||
|
||||
डीकोडर को दस्तावेज़ के एमआईएमई प्रकार के बारे में पता होना चाहिए ताकि इसे आगे बढ़ाया जा सके।
|
||||
`unstructured` का `partition()`। दो रास्ते:
|
||||
|
||||
**लाइब्रेरियन पथ** (`document_id` सेट): दस्तावेज़ मेटाडेटा प्राप्त करें।
|
||||
सबसे पहले लाइब्रेरियन से जानकारी प्राप्त करें - यह हमें `kind` (मिम टाइप) देता है।
|
||||
जो अपलोड के समय दर्ज किया गया था। फिर दस्तावेज़ सामग्री प्राप्त करें।
|
||||
दो लाइब्रेरियन कॉल, लेकिन मेटाडेटा प्राप्त करना आसान है।
|
||||
**इनलाइन पथ** (पिछला संगतता, `data` सेट): संदेश पर कोई मेटाडेटा उपलब्ध नहीं है।
|
||||
प्रारूप का पता लगाने के लिए `python-magic` का उपयोग करें।
|
||||
सामग्री बाइट्स से एक वैकल्पिक विधि के रूप में।
|
||||
|
||||
`Document` स्कीमा में कोई बदलाव आवश्यक नहीं है - लाइब्रेरियन पहले से ही MIME प्रकार संग्रहीत करता है।
|
||||
|
||||
|
||||
### वास्तुकला
|
||||
|
||||
एक एकल `universal-decoder` सेवा जो:
|
||||
|
||||
1. एक `Document` संदेश प्राप्त होता है (इनलाइन या लाइब्रेरियन संदर्भ के माध्यम से)।
|
||||
2. यदि लाइब्रेरियन पथ है: दस्तावेज़ मेटाडेटा प्राप्त करें (मिम प्रकार प्राप्त करें), फिर
|
||||
सामग्री प्राप्त करें। यदि इनलाइन पथ है: सामग्री बाइट्स से प्रारूप का पता लगाएं।
|
||||
3. तत्वों को निकालने के लिए `partition()` को कॉल करता है।
|
||||
4. तत्वों को समूहीकृत करता है: पृष्ठ-आधारित प्रारूपों के लिए पृष्ठ द्वारा, गैर-पृष्ठ प्रारूपों के लिए कॉन्फ़िगर किए गए
|
||||
अनुभाग रणनीति द्वारा।
|
||||
5. प्रत्येक पृष्ठ/अनुभाग के लिए:
|
||||
एक `urn:page:{uuid}` या `urn:section:{uuid}` आईडी उत्पन्न करता है।
|
||||
पृष्ठ पाठ को असेंबल करता है: वर्णनात्मक पाठ को सादे पाठ के रूप में, तालिकाओं को HTML के रूप में,
|
||||
छवियों को छोड़ दिया जाता है।
|
||||
पृष्ठ पाठ के भीतर प्रत्येक तत्व के लिए वर्ण अद्ययनों की गणना करता है।
|
||||
लाइब्रेरियन में एक चाइल्ड दस्तावेज़ के रूप में सहेजता है।
|
||||
स्थिति संबंधी मेटाडेटा के साथ प्रामाणिकता ट्रिपल उत्सर्जित करता है।
|
||||
टुकड़ों में विभाजित करने के लिए `TextDocument` को आगे भेजता है।
|
||||
6. प्रत्येक छवि तत्व के लिए:
|
||||
एक `urn:image:{uuid}` आईडी उत्पन्न करता है।
|
||||
छवि डेटा को लाइब्रेरियन में एक चाइल्ड दस्तावेज़ के रूप में सहेजता है।
|
||||
प्रामाणिकता ट्रिपल उत्सर्जित करता है (केवल संग्रहीत, आगे नहीं भेजा गया)।
|
||||
|
||||
### प्रारूप प्रबंधन
|
||||
|
||||
| प्रारूप | MIME प्रकार | पृष्ठ-आधारित | नोट्स |
|
||||
|----------|------------------------------------|------------|--------------------------------|
|
||||
| PDF | application/pdf | हाँ | प्रति-पृष्ठ समूहीकरण |
|
||||
| DOCX | application/vnd.openxmlformats... | नहीं | अनुभाग रणनीति का उपयोग करता है |
|
||||
| PPTX | application/vnd.openxmlformats... | हाँ | प्रति-स्लाइड समूहीकरण |
|
||||
| XLSX/XLS | application/vnd.openxmlformats... | हाँ | प्रति-शीट समूहीकरण |
|
||||
| HTML | text/html | नहीं | अनुभाग रणनीति का उपयोग करता है |
|
||||
| Markdown | text/markdown | नहीं | अनुभाग रणनीति का उपयोग करता है |
|
||||
| सादा | text/plain | नहीं | अनुभाग रणनीति का उपयोग करता है |
|
||||
| CSV | text/csv | नहीं | अनुभाग रणनीति का उपयोग करता है |
|
||||
| RST | text/x-rst | नहीं | अनुभाग रणनीति का उपयोग करता है |
|
||||
| RTF | application/rtf | नहीं | अनुभाग रणनीति का उपयोग करता है |
|
||||
| ODT | application/vnd.oasis... | नहीं | अनुभाग रणनीति का उपयोग करता है |
|
||||
| TSV | text/tab-separated-values | नहीं | अनुभाग रणनीति का उपयोग करता है |
|
||||
|
||||
### उत्पत्ति मेटाडेटा
|
||||
|
||||
प्रत्येक पृष्ठ/अनुभाग इकाई, प्रामाणिकता के रूप में स्थिति संबंधी मेटाडेटा को रिकॉर्ड करती है।
|
||||
`GRAPH_SOURCE` में ट्रिपल, जो नॉलेज ग्राफ (KG) ट्रिपल से स्रोत दस्तावेज़ की स्थिति तक पूर्ण पता लगाने की क्षमता प्रदान करते हैं।
|
||||
|
||||
|
||||
#### मौजूदा फ़ील्ड (पहले से ही `derived_entity_triples` में)
|
||||
|
||||
`page_number` — पृष्ठ/शीट/स्लाइड संख्या (1 से शुरू, केवल पृष्ठ-आधारित)
|
||||
`char_offset` — इस पृष्ठ/खंड के भीतर का वर्ण ऑफ़सेट।
|
||||
पूर्ण दस्तावेज़ पाठ
|
||||
`char_length` — इस पृष्ठ/खंड के पाठ की वर्ण संख्या
|
||||
|
||||
#### नए फ़ील्ड (`derived_entity_triples` का विस्तार करें)
|
||||
|
||||
`mime_type` — मूल दस्तावेज़ का प्रारूप (उदाहरण के लिए, `application/pdf`)
|
||||
`element_types` — `unstructured` तत्वों की अल्पविराम-विभाजित सूची
|
||||
इस पृष्ठ/अनुभाग में पाए गए श्रेणियाँ (उदाहरण के लिए, "शीर्षक, वर्णनात्मक पाठ, तालिका")
|
||||
`table_count` — इस पृष्ठ/अनुभाग में तालिकाओं की संख्या
|
||||
`image_count` — इस पृष्ठ/अनुभाग में छवियों की संख्या
|
||||
|
||||
इनके लिए नए टीजी नेमस्पेस विधेयकों की आवश्यकता है:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
TG_IMAGE_TYPE = "https://trustgraph.ai/ns/Image"
|
||||
TG_ELEMENT_TYPES = "https://trustgraph.ai/ns/elementTypes"
|
||||
TG_TABLE_COUNT = "https://trustgraph.ai/ns/tableCount"
|
||||
TG_IMAGE_COUNT = "https://trustgraph.ai/ns/imageCount"
|
||||
```
|
||||
|
||||
इमेज यूआरएन योजना: `urn:image:{uuid}`
|
||||
|
||||
(`TG_MIME_TYPE` पहले से मौजूद है।)
|
||||
|
||||
#### नया इकाई प्रकार
|
||||
|
||||
गैर-पेज प्रारूपों (DOCX, HTML, Markdown, आदि) के लिए जहां डिकोडर
|
||||
पूरे दस्तावेज़ को एक इकाई के रूप में उत्सर्जित करता है, न कि पृष्ठों में विभाजित करके,
|
||||
इकाई को एक नया प्रकार मिलता है:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
```
|
||||
|
||||
यह अनुभागों को पृष्ठों से अलग करता है जब मूल जानकारी प्राप्त करने के लिए क्वेरी की जाती है:
|
||||
|
||||
| इकाई | प्रकार | उपयोग कब |
|
||||
|---|---|---|
|
||||
| दस्तावेज़ | `tg:Document` | मूल अपलोड की गई फ़ाइल |
|
||||
| पृष्ठ | `tg:Page` | पृष्ठ-आधारित प्रारूप (पीडीएफ, पीपीटीएक्स, एक्सएलएसएक्स) |
|
||||
| अनुभाग | `tg:Section` | गैर-पृष्ठ प्रारूप (डीओएक्स, एचटीएमएल, एमडी, आदि) |
|
||||
| छवि | `tg:Image` | एम्बेडेड छवियां (संग्रहित, संसाधित नहीं) |
|
||||
| भाग | `tg:Chunk` | चंकर का आउटपुट |
|
||||
| उपग्राफ | `tg:Subgraph` | केजी निष्कर्षण आउटपुट |
|
||||
|
||||
प्रकार को डिकोडर द्वारा यह निर्धारित किया जाता है कि यह पृष्ठ द्वारा समूहीकृत है या पूरे दस्तावेज़ अनुभाग को उत्सर्जित कर रहा है। ⟦CODE_0⟧ प्राप्त होता है।
|
||||
या पूरे दस्तावेज़ अनुभाग को उत्सर्जित कर रहा है। `derived_entity_triples` प्राप्त होता है।
|
||||
एक वैकल्पिक `section` बूलियन पैरामीटर - जब सत्य होता है, तो इकाई को
|
||||
`tg:Section` के रूप में टाइप किया जाता है, `tg:Page` के बजाय।
|
||||
|
||||
#### पूर्ण उत्पत्ति श्रृंखला
|
||||
|
||||
```
|
||||
KG triple
|
||||
→ subgraph (extraction provenance)
|
||||
→ chunk (char_offset, char_length within page)
|
||||
→ page/section (page_number, char_offset, char_length within doc, mime_type, element_types)
|
||||
→ document (original file in librarian)
|
||||
```
|
||||
|
||||
प्रत्येक लिंक, `GRAPH_SOURCE` नामक ग्राफ में ट्रिपल के एक सेट का प्रतिनिधित्व करता है।
|
||||
|
||||
### सेवा कॉन्फ़िगरेशन
|
||||
|
||||
कमांड-लाइन तर्क:
|
||||
|
||||
```
|
||||
--strategy Partitioning strategy: auto, hi_res, fast (default: auto)
|
||||
--languages Comma-separated OCR language codes (default: eng)
|
||||
--section-strategy Section grouping: whole-document, heading, element-type,
|
||||
count, size (default: whole-document)
|
||||
--section-element-count Elements per section for 'count' strategy (default: 20)
|
||||
--section-max-size Max chars per section for 'size' strategy (default: 4000)
|
||||
--section-within-pages Apply section strategy within pages too (default: false)
|
||||
```
|
||||
|
||||
साथ ही मानक `FlowProcessor` और लाइब्रेरियन क्यू तर्क।
|
||||
|
||||
### फ्लो इंटीग्रेशन (प्रवाह एकीकरण)
|
||||
|
||||
सार्वभौमिक डिकोडर प्रसंस्करण प्रवाह में उसी स्थिति पर होता है
|
||||
जैसा कि वर्तमान पीडीएफ डिकोडर:
|
||||
|
||||
```
|
||||
Document → [universal-decoder] → TextDocument → [chunker] → Chunk → ...
|
||||
```
|
||||
|
||||
यह पंजीकृत करता है:
|
||||
`input` उपभोक्ता (दस्तावेज़ स्कीमा)
|
||||
`output` उत्पादक (टेक्स्टडॉक्यूमेंट स्कीमा)
|
||||
`triples` उत्पादक (ट्रिपल्स स्कीमा)
|
||||
लाइब्रेरियन अनुरोध/प्रतिक्रिया (फ़ेच और चाइल्ड दस्तावेज़ भंडारण के लिए)
|
||||
|
||||
### परिनियोजन
|
||||
|
||||
नया कंटेनर: `trustgraph-flow-universal-decoder`
|
||||
निर्भरता: `unstructured[all-docs]` (इसमें पीडीएफ, डॉक्स, पीपीटीएक्स, आदि शामिल हैं)
|
||||
यह मौजूदा पीडीएफ डिकोडर के साथ समानांतर रूप से चल सकता है या उसकी जगह ले सकता है, यह इस बात पर निर्भर करता है।
|
||||
प्रवाह विन्यास
|
||||
मौजूदा पीडीएफ डिकोडर उन वातावरणों में भी उपलब्ध रहेगा जहाँ
|
||||
`unstructured` निर्भरताएँ बहुत अधिक हैं
|
||||
|
||||
### क्या बदलाव
|
||||
|
||||
| घटक (Component) | परिवर्तन (Change) |
|
||||
|------------------------------|-------------------------------------------------|
|
||||
| `provenance/namespaces.py` | `TG_SECTION_TYPE`, `TG_IMAGE_TYPE`, `TG_ELEMENT_TYPES`, `TG_TABLE_COUNT`, `TG_IMAGE_COUNT` जोड़ें (Add `TG_SECTION_TYPE`, `TG_IMAGE_TYPE`, `TG_ELEMENT_TYPES`, `TG_TABLE_COUNT`, `TG_IMAGE_COUNT`) |
|
||||
| `provenance/triples.py` | `mime_type`, `element_types`, `table_count`, `image_count` kwargs जोड़ें (Add `mime_type`, `element_types`, `table_count`, `image_count` kwargs) |
|
||||
| `provenance/__init__.py` | नए स्थिरांकों को निर्यात करें (Export new constants) |
|
||||
| नया: `decoding/universal/` | नया डिकोडर सेवा मॉड्यूल (New decoder service module) |
|
||||
| `setup.cfg` / `pyproject` | `unstructured[all-docs]` निर्भरता जोड़ें (Add `unstructured[all-docs]` dependency) |
|
||||
| डॉकर (Docker) | नया कंटेनर इमेज (New container image) |
|
||||
| फ्लो परिभाषाएँ (Flow definitions) | यूनिवर्सल-डिकोडर को दस्तावेज़ इनपुट के रूप में उपयोग करें (Wire universal-decoder as document input) |
|
||||
|
||||
### क्या नहीं बदलता (What Doesn't Change)
|
||||
|
||||
चंकर (टेक्स्टडॉक्यूमेंट प्राप्त करता है, पहले की तरह काम करता है)
|
||||
डाउनस्ट्रीम एक्सट्रैक्टर (चंक प्राप्त करते हैं, अपरिवर्तित)
|
||||
लाइब्रेरियन (चाइल्ड डॉक्यूमेंट्स को संग्रहीत करता है, अपरिवर्तित)
|
||||
स्कीमा (डॉक्यूमेंट, टेक्स्टडॉक्यूमेंट, चंक अपरिवर्तित)
|
||||
क्वेरी-टाइम प्रोवेनेंस (अपरिवर्तित)
|
||||
|
||||
## जोखिम
|
||||
|
||||
`unstructured[all-docs]` में भारी निर्भरताएँ हैं (पोप्लर, टेसेरैक्ट,
|
||||
लिब्रेऑफिस कुछ प्रारूपों के लिए)। कंटेनर इमेज का आकार बड़ा होगा।
|
||||
निवारण: ओसीआर/ऑफिस निर्भरताओं के बिना `[light]` का एक संस्करण प्रदान करें।
|
||||
कुछ प्रारूपों से खराब टेक्स्ट निष्कर्षण हो सकता है (बिना ओसीआर वाले स्कैन किए गए पीडीएफ)।
|
||||
ओसीआर, जटिल एक्सेल (XLSX) लेआउट)। निवारण: कॉन्फ़िगर करने योग्य `strategy`
|
||||
पैरामीटर, और मौजूदा मिस्ट्रल ओसीआर डिकोडर अभी भी उपलब्ध है।
|
||||
उच्च-गुणवत्ता वाले पीडीएफ ओसीआर के लिए।
|
||||
`unstructured` संस्करण अपडेट से तत्व मेटाडेटा में परिवर्तन हो सकता है।
|
||||
निवारण: संस्करण को स्थिर करें, प्रत्येक प्रारूप के लिए निष्कर्षण गुणवत्ता का परीक्षण करें।
|
||||
|
|
|
|||
396
docs/tech-specs/universal-decoder.pt.md
Normal file
396
docs/tech-specs/universal-decoder.pt.md
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
# Decodificador Universal de Documentos
|
||||
|
||||
## Título
|
||||
|
||||
Decodificador universal de documentos alimentado por `unstructured` — ingira qualquer formato de documento comum
|
||||
através de um único serviço com total rastreabilidade e integração com o sistema de gerenciamento de informações,
|
||||
registrando as posições de origem como metadados de gráfico de conhecimento para
|
||||
rastreabilidade de ponta a ponta.
|
||||
|
||||
## Problema
|
||||
|
||||
Atualmente, o TrustGraph possui um decodificador específico para PDF. Suportar formatos adicionais
|
||||
(DOCX, XLSX, HTML, Markdown, texto simples, PPTX, etc.) requer
|
||||
ou a escrita de um novo decodificador para cada formato ou a adoção de uma biblioteca de extração universal.
|
||||
Cada formato tem uma estrutura diferente — alguns são baseados em páginas, outros não — e a cadeia de rastreabilidade
|
||||
deve registrar de onde em cada documento original cada trecho de texto extraído se originou.
|
||||
|
||||
|
||||
## Abordagem
|
||||
|
||||
### Biblioteca: `unstructured`
|
||||
|
||||
Utilize `unstructured.partition.auto.partition()`, que detecta automaticamente o formato
|
||||
a partir do tipo MIME ou da extensão do arquivo e extrai elementos estruturados
|
||||
(Título, TextoNarrativo, Tabela, ItemDeLista, etc.). Cada elemento carrega
|
||||
metadados, incluindo:
|
||||
|
||||
`page_number` (para formatos baseados em páginas, como PDF, PPTX)
|
||||
`element_id` (único para cada elemento)
|
||||
`coordinates` (caixa delimitadora para PDFs)
|
||||
`text` (o conteúdo de texto extraído)
|
||||
`category` (tipo de elemento: Título, TextoNarrativo, Tabela, etc.)
|
||||
|
||||
### Tipos de Elementos
|
||||
|
||||
`unstructured` extrai elementos tipados de documentos. Cada elemento tem
|
||||
uma categoria e metadados associados:
|
||||
|
||||
**Elementos de texto:**
|
||||
`Title` — títulos de seções
|
||||
`NarrativeText` — parágrafos do corpo do texto
|
||||
`ListItem` — itens de listas (com marcadores/numerados)
|
||||
`Header`, `Footer` — cabeçalhos/rodapés de página
|
||||
`FigureCaption` — legendas para figuras/imagens
|
||||
`Formula` — expressões matemáticas
|
||||
`Address`, `EmailAddress` — informações de contato
|
||||
`CodeSnippet` — blocos de código (do Markdown)
|
||||
|
||||
**Tabelas:**
|
||||
`Table` — dados tabulares estruturados. `unstructured` fornece ambos
|
||||
`element.text` (texto simples) e `element.metadata.text_as_html`
|
||||
(HTML completo `<table>` com linhas, colunas e cabeçalhos preservados).
|
||||
Para formatos com estrutura de tabela explícita (DOCX, XLSX, HTML), a
|
||||
extração é altamente confiável. Para PDFs, a detecção de tabelas depende da
|
||||
estratégia `hi_res` com análise de layout.
|
||||
|
||||
**Imagens:**
|
||||
`Image` — imagens incorporadas detectadas por meio de análise de layout (requer
|
||||
`hi_res` estratégia). Com `extract_image_block_to_payload=True`,
|
||||
retorna os dados da imagem como base64 em `element.metadata.image_base64`.
|
||||
O texto OCR da imagem está disponível em `element.text`.
|
||||
|
||||
### Tratamento de Tabelas
|
||||
|
||||
Tabelas são um tipo de saída de primeira classe. Quando o decodificador encontra um elemento `Table`,
|
||||
ele preserva a estrutura HTML em vez de converter para
|
||||
texto simples. Isso fornece ao extrator LLM downstream uma entrada muito melhor
|
||||
para extrair conhecimento estruturado de dados tabulares.
|
||||
|
||||
O texto da página/seção é montado da seguinte forma:
|
||||
Elementos de texto: texto simples, unidos por quebras de linha
|
||||
Elementos de tabela: marcação de tabela HTML de `text_as_html`, envolvida em um
|
||||
marcador `<table>` para que o LLM possa distinguir tabelas de texto narrativo
|
||||
|
||||
Por exemplo, uma página com um título, um parágrafo e uma tabela produz:
|
||||
|
||||
```
|
||||
Financial Overview
|
||||
|
||||
Revenue grew 15% year-over-year driven by enterprise adoption.
|
||||
|
||||
<table>
|
||||
<tr><th>Quarter</th><th>Revenue</th><th>Growth</th></tr>
|
||||
<tr><td>Q1</td><td>$12M</td><td>12%</td></tr>
|
||||
<tr><td>Q2</td><td>$14M</td><td>17%</td></tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
Isso preserva a estrutura da tabela por meio da divisão em partes e no processo de extração
|
||||
pipeline, onde o LLM pode extrair relacionamentos diretamente de
|
||||
células estruturadas, em vez de adivinhar o alinhamento das colunas a partir de
|
||||
espaços em branco.
|
||||
|
||||
### Tratamento de Imagens
|
||||
|
||||
As imagens são extraídas e armazenadas no sistema como documentos filhos
|
||||
com `document_type="image"` e um ID `urn:image:{uuid}`. Elas recebem
|
||||
triplas de procedência com o tipo `tg:Image`, vinculadas à página/seção pai
|
||||
por meio de `prov:wasDerivedFrom`. Os metadados da imagem (coordenadas,
|
||||
dimensões, element_id) são registrados na procedência.
|
||||
|
||||
**É crucial que as imagens NÃO sejam emitidas como saídas do tipo TextDocument.** Elas são
|
||||
armazenadas apenas — não enviadas para o chunker ou qualquer processo de texto
|
||||
pipeline. Isso é intencional:
|
||||
|
||||
1. Ainda não existe um pipeline de processamento de imagens (a integração do modelo de visão
|
||||
é um trabalho futuro).
|
||||
2. Alimentar dados de imagem em base64 ou fragmentos de OCR no processo de extração de texto
|
||||
produziria triplas de grafo de conhecimento (KG) inúteis.
|
||||
|
||||
As imagens também são excluídas do texto da página montado — quaisquer elementos `Image`
|
||||
são ignorados silenciosamente ao concatenar os textos dos elementos para uma
|
||||
página/seção. A cadeia de procedência registra que as imagens existem e onde
|
||||
elas apareceram no documento, para que possam ser recuperadas por um futuro
|
||||
pipeline de processamento de imagens sem reingestão do documento.
|
||||
|
||||
#### Trabalho futuro
|
||||
|
||||
Direcionar entidades `tg:Image` para um modelo de visão para descrição,
|
||||
interpretação de diagramas ou extração de dados de gráficos.
|
||||
Armazenar descrições de imagens como documentos de texto filhos que são alimentados no
|
||||
processo de divisão/extração padrão.
|
||||
Vincular o conhecimento extraído de volta às imagens de origem por meio da procedência.
|
||||
|
||||
### Estratégias de Seção
|
||||
|
||||
Para formatos baseados em páginas (PDF, PPTX, XLSX), os elementos são sempre agrupados
|
||||
por página/slide/planilha primeiro. Para formatos não baseados em páginas (DOCX, HTML, Markdown,
|
||||
etc.), o decodificador precisa de uma estratégia para dividir o documento em
|
||||
seções. Isso é configurável em tempo de execução por meio de `--section-strategy`.
|
||||
|
||||
Cada estratégia é uma função de agrupamento sobre a lista de `unstructured`
|
||||
elementos. A saída é uma lista de grupos de elementos; o restante do
|
||||
pipeline (montagem de texto, armazenamento do bibliotecário, rastreabilidade, emissão de TextDocument
|
||||
) é idêntico, independentemente da estratégia.
|
||||
|
||||
#### `whole-document` (padrão)
|
||||
|
||||
Emita todo o documento como uma única seção. Deixe que o
|
||||
divisor de blocos (chunker) lide com toda a divisão.
|
||||
|
||||
Abordagem mais simples, bom ponto de partida
|
||||
Pode produzir um TextDocument muito grande para arquivos grandes, mas o divisor de blocos
|
||||
lida com isso
|
||||
Melhor quando você deseja o máximo de contexto por seção
|
||||
|
||||
#### `heading`
|
||||
|
||||
Divida nos elementos de cabeçalho (`Title`). Cada seção é um cabeçalho mais
|
||||
todo o conteúdo até o próximo cabeçalho de nível igual ou superior. Cabeçalhos
|
||||
aninhados criam seções aninhadas.
|
||||
|
||||
Produz unidades coerentes em termos de tópico
|
||||
Funciona bem para documentos estruturados (relatórios, manuais, especificações)
|
||||
Fornece ao LLM de extração o contexto do cabeçalho junto com o conteúdo
|
||||
Recua para `whole-document` se nenhum cabeçalho for encontrado
|
||||
|
||||
#### `element-type`
|
||||
|
||||
Divida quando o tipo de elemento muda significativamente — especificamente,
|
||||
comece uma nova seção nas transições entre texto narrativo e tabelas.
|
||||
Elementos consecutivos da mesma categoria ampla (texto, texto, texto ou
|
||||
tabela, tabela) permanecem agrupados.
|
||||
|
||||
Mantém as tabelas como seções independentes
|
||||
Bom para documentos com conteúdo misto (relatórios com tabelas de dados)
|
||||
As tabelas recebem atenção especial na extração
|
||||
|
||||
#### `count`
|
||||
|
||||
Agrupe um número fixo de elementos por seção. Configurável via
|
||||
`--section-element-count` (padrão: 20).
|
||||
|
||||
Simples e previsível
|
||||
Não respeita a estrutura do documento
|
||||
Útil como uma opção de fallback ou para experimentação
|
||||
|
||||
#### `size`
|
||||
|
||||
Acumula elementos até que um limite de caracteres seja atingido, então inicia uma
|
||||
nova seção. Respeita os limites dos elementos — nunca divide no meio de um elemento.
|
||||
Configurável via `--section-max-size` (padrão: 4000 caracteres).
|
||||
|
||||
Produz tamanhos de seção aproximadamente uniformes
|
||||
Respeita os limites dos elementos (ao contrário do "chunker" subsequente)
|
||||
Bom compromisso entre estrutura e controle de tamanho
|
||||
Se um único elemento exceder o limite, ele se torna sua própria seção
|
||||
|
||||
#### Interação com formatos baseados em página
|
||||
|
||||
Para formatos baseados em página, o agrupamento de páginas sempre tem prioridade.
|
||||
As estratégias de seção podem ser aplicadas opcionalmente *dentro* de uma página se ela for muito
|
||||
grande (por exemplo, uma página PDF com uma tabela enorme), controlado por
|
||||
`--section-within-pages` (padrão: falso). Quando falso, cada página é
|
||||
sempre uma seção, independentemente do tamanho.
|
||||
|
||||
### Detecção de Formato
|
||||
|
||||
O decodificador precisa saber o tipo MIME do documento para passar para
|
||||
`unstructured`'s `partition()`. Dois caminhos:
|
||||
|
||||
**Caminho do "Librarian"** (`document_id` definido): busca os metadados do documento
|
||||
do "librarian" primeiro — isso nos dá o `kind` (tipo MIME)
|
||||
que foi registrado no momento do upload. Em seguida, busca o conteúdo do documento.
|
||||
Duas chamadas ao "librarian", mas a busca de metadados é leve.
|
||||
**Caminho "inline"** (compatibilidade com versões anteriores, `data` definido): sem metadados
|
||||
disponíveis na mensagem. Use `python-magic` para detectar o formato
|
||||
a partir dos bytes do conteúdo como uma alternativa.
|
||||
|
||||
Não são necessárias alterações no esquema `Document` — o bibliotecário já armazena o tipo MIME.
|
||||
|
||||
|
||||
### Arquitetura
|
||||
|
||||
Um único serviço `universal-decoder` que:
|
||||
|
||||
1. Recebe uma mensagem `Document` (inline ou via referência ao bibliotecário).
|
||||
2. Se o caminho for o do bibliotecário: busca os metadados do documento (obtém o tipo MIME), então
|
||||
busca o conteúdo. Se o caminho for inline: detecta o formato a partir dos bytes do conteúdo.
|
||||
3. Chama `partition()` para extrair os elementos.
|
||||
4. Agrupa elementos: por página para formatos baseados em página, por estratégia de seção configurada para formatos não baseados em página.
|
||||
seção.
|
||||
5. Para cada página/seção:
|
||||
Gera um ID `urn:page:{uuid}` ou `urn:section:{uuid}`
|
||||
Monta o texto da página: narrativa como texto simples, tabelas como HTML,
|
||||
imagens ignoradas
|
||||
Calcula os deslocamentos de caracteres para cada elemento dentro do texto da página.
|
||||
Salva no "librarian" como documento filho.
|
||||
Emite triplas de procedência com metadados posicionais.
|
||||
Envia `TextDocument` para o processo de divisão em partes (chunking).
|
||||
6. Para cada elemento de imagem:
|
||||
Gera um ID `urn:image:{uuid}`.
|
||||
Salva os dados da imagem no "librarian" como documento filho.
|
||||
Emite triplas de procedência (armazenadas apenas, não enviadas para o processo de divisão em partes).
|
||||
|
||||
### Manipulação de Formato
|
||||
|
||||
| Formato | Tipo MIME | Baseado em Página | Notas |
|
||||
|----------|------------------------------------|------------|--------------------------------|
|
||||
| PDF | application/pdf | Sim | Agrupamento por página |
|
||||
| DOCX | application/vnd.openxmlformats... | Não | Usa estratégia de seção |
|
||||
| PPTX | application/vnd.openxmlformats... | Sim | Agrupamento por slide |
|
||||
| XLSX/XLS | application/vnd.openxmlformats... | Sim | Agrupamento por planilha |
|
||||
| HTML | text/html | Não | Usa estratégia de seção |
|
||||
| Markdown | text/markdown | Não | Usa estratégia de seção |
|
||||
| Texto Simples | text/plain | Não | Usa estratégia de seção |
|
||||
| CSV | text/csv | Não | Usa estratégia de seção |
|
||||
| RST | text/x-rst | Não | Usa estratégia de seção |
|
||||
| RTF | application/rtf | Não | Usa estratégia de seção |
|
||||
| ODT | application/vnd.oasis... | Não | Usa estratégia de seção |
|
||||
| TSV | text/tab-separated-values | Não | Usa estratégia de seção |
|
||||
|
||||
### Metadados de Proveniência
|
||||
|
||||
Cada entidade de página/seção registra metadados de posição como triplas de proveniência
|
||||
em `GRAPH_SOURCE`, permitindo rastreabilidade completa desde as triplas do grafo
|
||||
até as posições no documento de origem.
|
||||
|
||||
#### Campos existentes (já em `derived_entity_triples`)
|
||||
|
||||
`page_number` — número da página/planilha/slide (indexado a partir de 1, apenas para documentos baseados em página)
|
||||
`char_offset` — deslocamento de caractere desta página/seção dentro do
|
||||
texto completo do documento
|
||||
`char_length` — comprimento do caractere do texto desta página/seção
|
||||
|
||||
#### Novos campos (extender `derived_entity_triples`)
|
||||
|
||||
`mime_type` — formato original do documento (por exemplo, `application/pdf`)
|
||||
`element_types` — lista separada por vírgula de categorias de `unstructured`
|
||||
encontradas nesta página/seção (por exemplo, "Título,TextoNarrativo,Tabela")
|
||||
`table_count` — número de tabelas nesta página/seção
|
||||
`image_count` — número de imagens nesta página/seção
|
||||
|
||||
Estes requerem novos predicados do namespace TG:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
TG_IMAGE_TYPE = "https://trustgraph.ai/ns/Image"
|
||||
TG_ELEMENT_TYPES = "https://trustgraph.ai/ns/elementTypes"
|
||||
TG_TABLE_COUNT = "https://trustgraph.ai/ns/tableCount"
|
||||
TG_IMAGE_COUNT = "https://trustgraph.ai/ns/imageCount"
|
||||
```
|
||||
|
||||
Esquema URN de imagem: `urn:image:{uuid}`
|
||||
|
||||
(`TG_MIME_TYPE` já existe.)
|
||||
|
||||
#### Novo tipo de entidade
|
||||
|
||||
Para formatos não paginados (DOCX, HTML, Markdown, etc.) onde o decodificador
|
||||
emite todo o documento como uma única unidade em vez de dividi-lo por
|
||||
página, a entidade recebe um novo tipo:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
```
|
||||
|
||||
Isso distingue seções de páginas ao consultar a procedência:
|
||||
|
||||
| Entidade | Tipo | Quando usado |
|
||||
|----------|-----------------------------|----------------------------------------|
|
||||
| Documento | `tg:Document` | Arquivo original carregado |
|
||||
| Página | `tg:Page` | Formatos baseados em páginas (PDF, PPTX, XLSX) |
|
||||
| Seção | `tg:Section` | Formatos não baseados em páginas (DOCX, HTML, MD, etc.) |
|
||||
| Imagem | `tg:Image` | Imagens incorporadas (armazenadas, não processadas) |
|
||||
| Trecho | `tg:Chunk` | Saída do processador de trechos |
|
||||
| Subgrafo | `tg:Subgraph` | Saída da extração de grafo de conhecimento |
|
||||
|
||||
O tipo é definido pelo decodificador com base em se está agrupando por página
|
||||
ou emitindo uma seção de documento inteiro. `derived_entity_triples` recebe
|
||||
um parâmetro booleano opcional `section` — quando verdadeiro, a entidade é
|
||||
classificada como `tg:Section` em vez de `tg:Page`.
|
||||
|
||||
#### Cadeia completa de procedência
|
||||
|
||||
```
|
||||
KG triple
|
||||
→ subgraph (extraction provenance)
|
||||
→ chunk (char_offset, char_length within page)
|
||||
→ page/section (page_number, char_offset, char_length within doc, mime_type, element_types)
|
||||
→ document (original file in librarian)
|
||||
```
|
||||
|
||||
Cada link é um conjunto de triplas no grafo nomeado `GRAPH_SOURCE`.
|
||||
|
||||
### Configuração do Serviço
|
||||
|
||||
Argumentos de linha de comando:
|
||||
|
||||
```
|
||||
--strategy Partitioning strategy: auto, hi_res, fast (default: auto)
|
||||
--languages Comma-separated OCR language codes (default: eng)
|
||||
--section-strategy Section grouping: whole-document, heading, element-type,
|
||||
count, size (default: whole-document)
|
||||
--section-element-count Elements per section for 'count' strategy (default: 20)
|
||||
--section-max-size Max chars per section for 'size' strategy (default: 4000)
|
||||
--section-within-pages Apply section strategy within pages too (default: false)
|
||||
```
|
||||
|
||||
Além dos argumentos padrão `FlowProcessor` e da fila de bibliotecários.
|
||||
|
||||
### Integração de Fluxo
|
||||
|
||||
O decodificador universal ocupa a mesma posição no fluxo de processamento
|
||||
que o decodificador PDF atual:
|
||||
|
||||
```
|
||||
Document → [universal-decoder] → TextDocument → [chunker] → Chunk → ...
|
||||
```
|
||||
|
||||
Ele registra:
|
||||
`input` consumidor (schema de documento)
|
||||
`output` produtor (schema TextDocument)
|
||||
`triples` produtor (schema de triplas)
|
||||
Requisição/resposta do bibliotecário (para busca e armazenamento de documentos filhos)
|
||||
|
||||
### Implantação
|
||||
|
||||
Novo contêiner: `trustgraph-flow-universal-decoder`
|
||||
Dependência: `unstructured[all-docs]` (inclui PDF, DOCX, PPTX, etc.)
|
||||
Pode ser executado em conjunto ou substituir o decodificador PDF existente, dependendo
|
||||
da configuração do fluxo
|
||||
O decodificador PDF existente permanece disponível para ambientes onde
|
||||
as dependências `unstructured` são muito pesadas
|
||||
|
||||
### O que Muda
|
||||
|
||||
| Componento | Alteração |
|
||||
|------------------------------|-------------------------------------------------|
|
||||
| `provenance/namespaces.py` | Adicionar `TG_SECTION_TYPE`, `TG_IMAGE_TYPE`, `TG_ELEMENT_TYPES`, `TG_TABLE_COUNT`, `TG_IMAGE_COUNT` |
|
||||
| `provenance/triples.py` | Adicionar argumentos `mime_type`, `element_types`, `table_count`, `image_count` (kwargs) |
|
||||
| `provenance/__init__.py` | Exportar novas constantes |
|
||||
| Novo: `decoding/universal/` | Novo módulo de serviço de decodificação |
|
||||
| `setup.cfg` / `pyproject` | Adicionar dependência `unstructured[all-docs]` |
|
||||
| Docker | Nova imagem de contêiner |
|
||||
| Definições de fluxo | Conectar universal-decoder como entrada de documento |
|
||||
|
||||
### O que não muda
|
||||
|
||||
Chunker (recebe TextDocument, funciona como antes)
|
||||
Extratores subsequentes (recebem Chunk, inalterados)
|
||||
Librarian (armazena documentos filhos, inalterado)
|
||||
Schema (Document, TextDocument, Chunk inalterados)
|
||||
Proveniência em tempo de consulta (inalterado)
|
||||
|
||||
## Riscos
|
||||
|
||||
`unstructured[all-docs]` tem muitas dependências (poppler, tesseract,
|
||||
libreoffice para alguns formatos). A imagem do contêiner será maior.
|
||||
Mitigação: oferecer uma variante de `[light]` sem dependências de OCR/office.
|
||||
Alguns formatos podem produzir extração de texto de baixa qualidade (PDFs digitalizados sem
|
||||
OCR, layouts complexos de XLSX). Mitigação: parâmetro `strategy` configurável
|
||||
e o decodificador OCR Mistral existente permanece disponível
|
||||
para OCR de PDF de alta qualidade.
|
||||
As atualizações de versão de `unstructured` podem alterar os metadados dos elementos.
|
||||
Mitigação: fixar a versão, testar a qualidade da extração por formato.
|
||||
396
docs/tech-specs/universal-decoder.tr.md
Normal file
396
docs/tech-specs/universal-decoder.tr.md
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
# Evrensel Belge Kodlayıcı
|
||||
|
||||
## Başlık
|
||||
|
||||
`unstructured` tarafından desteklenen evrensel belge kodlayıcı — tüm kaynak konumlarını, uçtan uca izlenebilirlik için bilgi grafiği meta verisi olarak kaydederek, tam kökenli ve kütüphaneci entegrasyonu ile herhangi bir yaygın belge formatını tek bir hizmet aracılığıyla işleyin.
|
||||
|
||||
|
||||
|
||||
|
||||
## Sorun
|
||||
|
||||
TrustGraph şu anda PDF'ye özel bir çözücüye (decoder) sahip. Ek
|
||||
formatları (DOCX, XLSX, HTML, Markdown, düz metin, PPTX, vb.) desteklemek,
|
||||
ya her format için yeni bir çözücü yazmayı veya evrensel bir çıkarma
|
||||
kütüphanesini kullanmayı gerektirir. Her formatın farklı bir yapısı vardır — bazıları sayfa tabanlıyken, bazıları değildir — ve köken zinciri, çıkarılan her metin parçasının orijinal
|
||||
belgede nereden geldiğini kaydetmelidir.
|
||||
|
||||
## Yaklaşım
|
||||
## Yaklaşım
|
||||
|
||||
### Kütüphane: `unstructured`
|
||||
|
||||
`unstructured.partition.auto.partition()`'ı kullanın, bu, formatı otomatik olarak algılar
|
||||
MIME türünden veya dosya uzantısından yapılandırılmış öğeleri ayıklar
|
||||
(Başlık, AnlatıMetni, Tablo, Madde, vb.). Her öğe aşağıdaki bilgileri içerir:
|
||||
|
||||
|
||||
`page_number` (sayfa tabanlı formatlar için, örneğin PDF, PPTX)
|
||||
`element_id` (her öğe için benzersiz)
|
||||
`coordinates` (PDF'ler için sınırlayıcı kutu)
|
||||
`text` (çıkarılan metin içeriği)
|
||||
`category` (öğe türü: Başlık, AnlatıMetni, Tablo, vb.)
|
||||
|
||||
### Öğe Türleri
|
||||
|
||||
`unstructured`, belgelerden türlenmiş öğeleri çıkarır. Her öğenin bir kategorisi ve ilişkili meta verileri vardır:
|
||||
|
||||
|
||||
**Metin öğeleri:**
|
||||
`Title` — bölüm başlıkları
|
||||
`NarrativeText` — ana metin paragrafları
|
||||
`ListItem` — madde işaretli/numaralandırılmış liste öğeleri
|
||||
`Header`, `Footer` — sayfa başlıkları/altbilgileri
|
||||
`FigureCaption` — şekiller/görseller için başlıklar
|
||||
`Formula` — matematiksel ifadeler
|
||||
`Address`, `EmailAddress` — iletişim bilgileri
|
||||
`CodeSnippet` — kod blokları (markdown'dan)
|
||||
|
||||
**Tablolar:**
|
||||
`Table` — yapılandırılmış tablo verileri. `unstructured`, hem
|
||||
`element.text` (düz metin) hem de `element.metadata.text_as_html`
|
||||
(satırlar, sütunlar ve başlıklar korunmuş, tam HTML `<table>`) sağlar.
|
||||
Açık tablo yapısına sahip formatlar (DOCX, XLSX, HTML) için,
|
||||
çıkarma işlemi son derece güvenilirdir. PDF'ler için, tablo tespiti,
|
||||
düzen analizini içeren `hi_res` stratejisine bağlıdır.
|
||||
|
||||
**Görseller:**
|
||||
`Image` — düzen analizi yoluyla algılanan yerleşik görseller (gerektirir
|
||||
`hi_res` stratejisi). `extract_image_block_to_payload=True` ile,
|
||||
görüntü verilerini `element.metadata.image_base64` içinde base64 olarak döndürür.
|
||||
Görüntüden elde edilen OCR metni `element.text` içinde mevcuttur.
|
||||
|
||||
### Tablo İşleme
|
||||
|
||||
Tablolar, birincil bir çıktı türüdür. Kod çözücü, bir `Table`
|
||||
öğesiyle karşılaştığında, düz metne dönüştürmek yerine HTML yapısını korur.
|
||||
Bu, aşağı akış LLM çıkarıcısının, yapılandırılmış verileri içeren
|
||||
tablo verilerinden daha iyi bilgi almasını sağlar.
|
||||
|
||||
Sayfa/bölüm metni aşağıdaki gibi birleştirilir:
|
||||
Metin öğeleri: yeni satırlarla birleştirilmiş düz metin
|
||||
Tablo öğeleri: `text_as_html`'dan HTML tablo işaretlemesi, bir
|
||||
`<table>` işaretinin içine sarılır, böylece LLM tabloları, anlatıdan
|
||||
ayırt edebilir.
|
||||
Örneğin, bir başlık, paragraf ve tablo içeren bir sayfa şu şekilde üretilir:
|
||||
|
||||
```
|
||||
Financial Overview
|
||||
|
||||
Revenue grew 15% year-over-year driven by enterprise adoption.
|
||||
|
||||
<table>
|
||||
<tr><th>Quarter</th><th>Revenue</th><th>Growth</th></tr>
|
||||
<tr><td>Q1</td><td>$12M</td><td>12%</td></tr>
|
||||
<tr><td>Q2</td><td>$14M</td><td>17%</td></tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
Bu, tablo yapısını parçalara ayırarak ve çıkarma işlemine aktararak korur.
|
||||
Bu sayede, LLM (Büyük Dil Modeli), sütun hizalamasını boşluklardan tahmin etmek yerine, doğrudan yapılandırılmış hücrelerden ilişkileri çıkarabilir.
|
||||
|
||||
|
||||
### Resim İşleme
|
||||
|
||||
|
||||
Görüntüler çıkarılır ve kütüphanede alt belgeler olarak saklanır.
|
||||
`document_type="image"` ile ve `urn:image:{uuid}` kimlik numarasına sahip. Bunlar
|
||||
`tg:Image` türündeki köken bilgisi üçlülerini içerir ve bunlar, ebeveynlerine bağlanmıştır.
|
||||
sayfa/bölüm, `prov:wasDerivedFrom` aracılığıyla. Görüntü meta verileri (koordinatlar,
|
||||
boyutlar, element_id) provenians kısmında kaydedilir.
|
||||
|
||||
**Önemli olarak, resimler, TextDocument çıktıları olarak YAYINLANMAMAKTIR.**
|
||||
Bunlar yalnızca saklanır; parçalayıcıya veya herhangi bir metin işleme
|
||||
işlem hattına gönderilmez. Bu kasıtlıdır:
|
||||
|
||||
1. Henüz bir resim işleme işlem hattı yoktur (görsel model entegrasyonu
|
||||
gelecekteki bir çalışmadır)
|
||||
2. Base64 resim verilerini veya OCR parçalarını metin çıkarma
|
||||
işlem hattına vermek, hatalı KG üçlüleri üretir.
|
||||
|
||||
Görüntüler de birleştirilmiş sayfa metninden hariç tutulur; herhangi bir `Image`
|
||||
öğesi, bir sayfa/bölüm için öğe metinlerini birleştirirken sessizce atlanır.
|
||||
Kaynak zinciri, görüntülerin var olduğunu ve belgede nerede
|
||||
bulunduğunu kaydeder, böylece gelecekte bir görüntü işleme hattı tarafından
|
||||
belgenin yeniden yüklenmesi olmadan da alınabilirler.
|
||||
|
||||
#### Gelecek çalışmalar
|
||||
|
||||
`tg:Image` varlıklarını, açıklama,
|
||||
diyagram yorumlama veya grafik veri çıkarma için bir görsel modele yönlendirin.
|
||||
Görüntü açıklamalarını, standart parçalama/çıkarma işlem hattına beslenen metin alt belgeleri olarak kaydedin.
|
||||
Çıkarılan bilgileri, kaynak görüntüleriyle köken bilgisi aracılığıyla ilişkilendirin.
|
||||
|
||||
|
||||
### Bölüm Stratejileri
|
||||
|
||||
Sayfa tabanlı formatlar (PDF, PPTX, XLSX) için, öğeler her zaman önce sayfa/slayt/sayfa içinde gruplandırılır.
|
||||
Sayfa tabanlı olmayan formatlar (DOCX, HTML, Markdown,
|
||||
vb.) için, kodlayıcının belgeyi bölümlere ayırmak için bir stratejiye ihtiyacı vardır.
|
||||
Bu, çalışma zamanında `--section-strategy` aracılığıyla yapılandırılabilir.
|
||||
|
||||
Her strateji, `unstructured` öğelerinin listesi üzerinde bir gruplama fonksiyonudur.
|
||||
Çıktı, öğe gruplarının bir listesidir; geri kalan işlem hattı (metin birleştirme, kütüphane depolama, köken, TextDocument
|
||||
oluşturma) stratejiden bağımsız olarak aynıdır.
|
||||
|
||||
|
||||
#### `whole-document` (varsayılan)
|
||||
|
||||
Tüm belgeyi tek bir bölüm olarak yayınlayın. Bölme işlemlerinin tümü, sonraki
|
||||
parçalayıcı tarafından gerçekleştirilir.
|
||||
|
||||
En basit yaklaşım, iyi bir başlangıç noktası.
|
||||
Büyük dosyalar için çok büyük TextDocument'ler oluşturabilir, ancak parçalayıcı
|
||||
bunu yönetir.
|
||||
Her bölüm için maksimum bağlam istediğinizde en iyisidir.
|
||||
|
||||
#### `heading`
|
||||
|
||||
Başlık öğelerinde (`Title`) bölün. Her bölüm, bir başlık ve bir sonraki
|
||||
aynı veya daha yüksek seviyedeki başlığa kadar olan tüm içeriktir. İç içe
|
||||
başlıklar, iç içe bölümler oluşturur.
|
||||
|
||||
Konuyla ilgili tutarlı birimler oluşturur.
|
||||
Yapılandırılmış belgeler (raporlar, kılavuzlar, teknik özellikler) için iyi çalışır.
|
||||
Çıkarma LLM'sine, içerikle birlikte başlık bağlamı sağlar.
|
||||
Başlık bulunamazsa `whole-document`'a geri döner.
|
||||
|
||||
#### `element-type`
|
||||
|
||||
Eleman türü önemli ölçüde değiştiğinde bölmeyi yapın — özellikle,
|
||||
anlatısal metin ile tablolar arasındaki geçişlerde yeni bir bölüm başlatın.
|
||||
Aynı geniş kategoriye ait ardışık öğeler (metin, metin, metin veya
|
||||
tablo, tablo) gruplandırılır.
|
||||
|
||||
Tabloları bağımsız bölümler olarak tutar
|
||||
Karışık içerikli belgeler için uygundur (veri tabloları içeren raporlar)
|
||||
Tablolar, özel bir çıkarma işlemine tabi tutulur
|
||||
|
||||
#### `count`
|
||||
|
||||
Bir bölümdeki öğe sayısını sabit bir sayıda gruplandırın. ⟦CODE_0⟧ aracılığıyla yapılandırılabilir (varsayılan: 20).
|
||||
`--section-element-count` (varsayılan: 20).
|
||||
|
||||
Basit ve öngörülebilir
|
||||
Belge yapısını dikkate almaz
|
||||
Yedek çözüm olarak veya deneme yapmak için kullanışlıdır
|
||||
|
||||
#### `size`
|
||||
|
||||
Öğeleri, bir karakter limiti dolana kadar biriktirin, ardından yeni bir bölüm başlatın. Öğeler arasındaki sınırları dikkate alır; hiçbir zaman bir öğenin ortasında bölünme yapmaz.
|
||||
⟦CODE_0⟧ gibi yer tutucuları veya ⟦URL_0⟧ gibi URL'leri çevirmeyin; bunları olduğu gibi bırakın.
|
||||
`--section-max-size` aracılığıyla yapılandırılabilir (varsayılan: 4000 karakter).
|
||||
|
||||
Yaklaşık olarak homojen bölüm boyutları üretir.
|
||||
Eleman sınırlarına saygı gösterir (aşağıdaki parçalayıcıdan farklı olarak).
|
||||
Yapı ve boyut kontrolü arasında iyi bir denge sağlar.
|
||||
Tek bir eleman limiti aşarsa, kendi bölümü haline gelir.
|
||||
|
||||
#### Sayfa tabanlı format etkileşimi
|
||||
|
||||
Sayfa tabanlı formatlar için, sayfa gruplandırması her zaman önceliklidir.
|
||||
Bölüm stratejileri, isteğe bağlı olarak, çok büyükse (örneğin, devasa bir tablo içeren bir PDF sayfası) bir sayfa *içinde* uygulanabilir, bu durum ⟦CODE_0⟧ ile kontrol edilir (varsayılan: false). Yanlış olduğunda, her sayfa boyuttan bağımsız olarak her zaman bir bölümdür.
|
||||
|
||||
`--section-within-pages` (varsayılan: false).
|
||||
|
||||
|
||||
### Biçim Algılama
|
||||
|
||||
Kodlayıcının, belgeyi ⟦CODE_0⟧'ın ⟦CODE_1⟧'ine iletebilmesi için belgenin MIME türünü bilmesi gerekir. İki yol:
|
||||
`unstructured`'ın `partition()`'i.
|
||||
|
||||
**Kütüphaneci yolu** (`document_id` ayarı): belge meta verilerini alın.
|
||||
Öncelikle kütüphaneciden belge meta verilerini alın — bu, `kind` (mime türü) değerini verir.
|
||||
Ardından belge içeriğini alın.
|
||||
İki kütüphaneci çağrısı, ancak meta veri alma işlemi hafiftir.
|
||||
**Satır içi yol** (geriye dönük uyumluluk, `data` ayarı): mesaj üzerinde herhangi bir meta veri bulunmamaktadır.
|
||||
Biçimi tespit etmek için `python-magic`'ı kullanın.
|
||||
Bu, içerik baytlarından biçimi algılamak için bir yedek yöntemdir.
|
||||
|
||||
`Document` şemasına herhangi bir değişiklik yapılmasına gerek yok — kütüphaneci zaten MIME türünü saklar.
|
||||
|
||||
|
||||
### Mimari
|
||||
|
||||
Tek bir `universal-decoder` hizmeti:
|
||||
|
||||
1. Bir `Document` mesajı alır (doğrudan veya kütüphaneci referansı aracılığıyla)
|
||||
2. Kütüphaneci yoluysa: belge meta verilerini alır (MIME türünü alır), ardından
|
||||
içeriği alır. Doğrudan yol ise: içeriğin baytlarından formatı algılar.
|
||||
3. Öğeleri çıkarmak için `partition()`'ı çağırır
|
||||
4. Öğeleri gruplandırır: sayfa tabanlı formatlar için sayfalara göre, sayfa dışı formatlar için yapılandırılmış
|
||||
bölüm stratejisine göre
|
||||
5. Her sayfa/bölüm için:
|
||||
Bir `urn:page:{uuid}` veya `urn:section:{uuid}` kimliği oluşturur
|
||||
Sayfa metnini birleştirir: anlatı düz metin olarak, tablolar HTML olarak,
|
||||
resimler atlanır
|
||||
Sayfa metnindeki her öğe için karakter ofsetlerini hesaplar
|
||||
Kütüphaneciye alt belge olarak kaydeder
|
||||
Konumsal meta verilerle birlikte kaynak üçlüleri yayınlar
|
||||
Parçalama için `TextDocument`'ı aşağı akışa gönderir
|
||||
6. Her resim öğesi için:
|
||||
Bir `urn:image:{uuid}` kimliği oluşturur
|
||||
Resim verilerini kütüphaneciye alt belge olarak kaydeder
|
||||
Kaynak üçlülerini yayınlar (sadece saklanır, aşağı akışa gönderilmez)
|
||||
|
||||
### Biçimlendirme İşlemi
|
||||
|
||||
| Biçim | MIME Tipi | Sayfa Tabanlı | Notlar |
|
||||
|----------|------------------------------------|------------|--------------------------------|
|
||||
| PDF | application/pdf | Evet | Sayfaya göre gruplandırma |
|
||||
| DOCX | application/vnd.openxmlformats... | Hayır | Bölüm stratejisi kullanır |
|
||||
| PPTX | application/vnd.openxmlformats... | Evet | Slayda göre gruplandırma |
|
||||
| XLSX/XLS | application/vnd.openxmlformats... | Evet | Sayfaya göre gruplandırma |
|
||||
| HTML | text/html | Hayır | Bölüm stratejisi kullanır |
|
||||
| Markdown | text/markdown | Hayır | Bölüm stratejisi kullanır |
|
||||
| Düz Metin | text/plain | Hayır | Bölüm stratejisi kullanır |
|
||||
| CSV | text/csv | Hayır | Bölüm stratejisi kullanır |
|
||||
| RST | text/x-rst | Hayır | Bölüm stratejisi kullanır |
|
||||
| RTF | application/rtf | Hayır | Bölüm stratejisi kullanır |
|
||||
| ODT | application/vnd.oasis... | Hayır | Bölüm stratejisi kullanır |
|
||||
| TSV | text/tab-separated-values | Hayır | Bölüm stratejisi kullanır |
|
||||
|
||||
### Kaynak Veri Meta Verileri
|
||||
|
||||
Her sayfa/bölüm öğesi, köken bilgisi olarak konum bilgisi meta verilerini kaydeder.
|
||||
`GRAPH_SOURCE` içindeki üçlüler, KG üçlülerinden tam bir izlenebilirlik sağlamaktadır.
|
||||
Kaynak belge konumlarına geri dönme.
|
||||
|
||||
#### Mevcut alanlar (zaten `derived_entity_triples` içinde)
|
||||
|
||||
`page_number` — sayfa/tablo/slayt numarası (1'den başlayarak, yalnızca sayfa tabanlı)
|
||||
`char_offset` — bu sayfa/bölümün,
|
||||
tam belge metni içindeki karakter ofseti
|
||||
`char_length` — bu sayfa/bölümün metninin karakter uzunluğu
|
||||
|
||||
#### Yeni alanlar (`derived_entity_triples`'ı genişletin)
|
||||
|
||||
`mime_type` — orijinal belge formatı (örneğin, `application/pdf`)
|
||||
`element_types` — `unstructured` öğelerinden oluşan virgülle ayrılmış liste
|
||||
bu sayfada/bölümde bulunan kategoriler (örneğin, "Başlık,AnlatıMetni,Tablo")
|
||||
`table_count` — bu sayfada/bölümdeki tablo sayısı
|
||||
`image_count` — bu sayfada/bölümdeki resim sayısı
|
||||
|
||||
Bunlar, yeni TG ad alanı özniteliklerini gerektirir:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
TG_IMAGE_TYPE = "https://trustgraph.ai/ns/Image"
|
||||
TG_ELEMENT_TYPES = "https://trustgraph.ai/ns/elementTypes"
|
||||
TG_TABLE_COUNT = "https://trustgraph.ai/ns/tableCount"
|
||||
TG_IMAGE_COUNT = "https://trustgraph.ai/ns/imageCount"
|
||||
```
|
||||
|
||||
Görüntü URN şeması: `urn:image:{uuid}`
|
||||
|
||||
(`TG_MIME_TYPE` zaten mevcut.)
|
||||
|
||||
#### Yeni varlık türü
|
||||
|
||||
Sayfa formatı olmayan (DOCX, HTML, Markdown, vb.) belgeler için,
|
||||
kodlayıcı, belgeyi sayfalara ayırmak yerine tek bir birim olarak yayınladığında,
|
||||
varlığa yeni bir tür atanır:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
```
|
||||
|
||||
Bu, sorgulama sırasında kökeni belirlerken bölümleri sayfalardan ayırır:
|
||||
|
||||
| Varlık | Tür | Ne zaman kullanılır |
|
||||
|----------|-----------------------------|----------------------------------------|
|
||||
| Belge | `tg:Document` | Orijinal yüklenen dosya |
|
||||
| Sayfa | `tg:Page` | Sayfaya dayalı formatlar (PDF, PPTX, XLSX) |
|
||||
| Bölüm | `tg:Section` | Sayfaya dayalı olmayan formatlar (DOCX, HTML, MD, vb.) |
|
||||
| Resim | `tg:Image` | Gömülü resimler (saklanan, işlenmeyen) |
|
||||
| Parça | `tg:Chunk` | Parçalayıcının çıktısı |
|
||||
| Alt Grafik | `tg:Subgraph` | KG çıkarma çıktısı |
|
||||
|
||||
Tür, kodlayıcı tarafından, sayfalara göre gruplandırılıp gruplandırılmadığına veya tüm belge bölümünün gönderilip gönderilmediğine bağlı olarak belirlenir. ⟦CODE_0⟧ elde edilir.
|
||||
veya tüm belge bölümünün gönderilip gönderilmediğine bağlı olarak belirlenir. `derived_entity_triples` kazanır.
|
||||
isteğe bağlı bir `section` boolean parametresi — doğru olduğunda, bu, varlığı belirtir.
|
||||
`tg:Section` olarak yazılmış, `tg:Page` yerine.
|
||||
|
||||
#### Tam kaynak zinciri
|
||||
|
||||
```
|
||||
KG triple
|
||||
→ subgraph (extraction provenance)
|
||||
→ chunk (char_offset, char_length within page)
|
||||
→ page/section (page_number, char_offset, char_length within doc, mime_type, element_types)
|
||||
→ document (original file in librarian)
|
||||
```
|
||||
|
||||
Her bağlantı, `GRAPH_SOURCE` adlı grafikte tanımlanan üçlülerden oluşan bir kümedir.
|
||||
|
||||
### Hizmet Yapılandırması
|
||||
|
||||
Komut satırı argümanları:
|
||||
|
||||
```
|
||||
--strategy Partitioning strategy: auto, hi_res, fast (default: auto)
|
||||
--languages Comma-separated OCR language codes (default: eng)
|
||||
--section-strategy Section grouping: whole-document, heading, element-type,
|
||||
count, size (default: whole-document)
|
||||
--section-element-count Elements per section for 'count' strategy (default: 20)
|
||||
--section-max-size Max chars per section for 'size' strategy (default: 4000)
|
||||
--section-within-pages Apply section strategy within pages too (default: false)
|
||||
```
|
||||
|
||||
Ayrıca standart `FlowProcessor` ve kütüphaneci kuyruk argümanlarını da içerir.
|
||||
|
||||
### Akış Entegrasyonu
|
||||
|
||||
Evrensel kod çözücü, işleme akışında mevcut PDF kod çözücünün bulunduğu aynı konumu işgal eder:
|
||||
|
||||
|
||||
```
|
||||
Document → [universal-decoder] → TextDocument → [chunker] → Chunk → ...
|
||||
```
|
||||
|
||||
Aşağıdakileri kaydeder:
|
||||
`input` tüketici (Belge şeması)
|
||||
`output` üretici (MetinBelgesi şeması)
|
||||
`triples` üretici (Üçlüler şeması)
|
||||
Kütüphaneci isteği/yanıtı (veri çekme ve alt belge depolama için)
|
||||
|
||||
### Dağıtım
|
||||
|
||||
Yeni kapsayıcı: `trustgraph-flow-universal-decoder`
|
||||
Bağımlılık: `unstructured[all-docs]` (PDF, DOCX, PPTX vb. içerir)
|
||||
Mevcut PDF çözücüyü tamamlayıcı olarak veya onun yerine çalışabilir.
|
||||
akış yapılandırması
|
||||
Mevcut PDF çözücü, ortamlar için kullanılabilir durumda kalacaktır.
|
||||
`unstructured` bağımlılıkları çok ağır.
|
||||
|
||||
### Değişiklikler
|
||||
|
||||
| Bileşen | Değişiklik |
|
||||
|------------------------------|-------------------------------------------------|
|
||||
| `provenance/namespaces.py` | `TG_SECTION_TYPE`, `TG_IMAGE_TYPE`, `TG_ELEMENT_TYPES`, `TG_TABLE_COUNT`, `TG_IMAGE_COUNT` ekleyin |
|
||||
| `provenance/triples.py` | `mime_type`, `element_types`, `table_count`, `image_count` argümanlarını ekleyin |
|
||||
| `provenance/__init__.py` | Yeni sabit değerleri dışa aktarın |
|
||||
| Yeni: `decoding/universal/` | Yeni bir kod çözücü hizmet modülü |
|
||||
| `setup.cfg` / `pyproject` | `unstructured[all-docs]` bağımlılığını ekleyin |
|
||||
| Docker | Yeni bir konteyner imajı |
|
||||
| Akış tanımları | Evrensel kod çözücüyü belge girişi olarak kullanın |
|
||||
|
||||
### Değişmeyenler
|
||||
|
||||
Chunker (MetinBelgesi'ni alır, önceki gibi çalışır)
|
||||
Aşağı akış ayıklayıcıları (Parçayı alır, değişmeden)
|
||||
Kütüphaneci (çocuk belgeleri saklar, değişmeden)
|
||||
Şema (Belge, MetinBelgesi, Parça değişmeden)
|
||||
Sorgu zamanı köken bilgisi (değişmeden)
|
||||
|
||||
## Riskler
|
||||
|
||||
`unstructured[all-docs]`, önemli bağımlılıklara sahiptir (poppler, tesseract,
|
||||
libreoffice, bazı formatlar için). Container imajı daha büyük olacaktır.
|
||||
Çözüm: OCR/ofis bağımlılıkları olmadan `[light]`'ın bir varyantını sunun.
|
||||
Bazı formatlar, zayıf metin çıkarma sonuçları verebilir (OCR uygulanmamış PDF'ler,
|
||||
OCR, karmaşık XLSX düzenleri). Çözüm: yapılandırılabilir `strategy`
|
||||
parametresi ve mevcut Mistral OCR çözücü kullanılabilir durumda.
|
||||
Yüksek kaliteli PDF OCR için.
|
||||
`unstructured` sürüm güncellemeleri, öğe meta verilerini değiştirebilir.
|
||||
Çözüm: sürümü sabitleyin, her format için çıkarma kalitesini test edin.
|
||||
299
docs/tech-specs/vector-store-lifecycle.ar.md
Normal file
299
docs/tech-specs/vector-store-lifecycle.ar.md
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# إدارة دورة حياة مستودع المتجهات
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
يصف هذا المستند كيفية إدارة TrustGraph لمجموعات مستودعات المتجهات عبر تطبيقات خلفية مختلفة (Qdrant، Pinecone، Milvus). يعالج التصميم تحدي دعم التضمينات بأبعاد مختلفة دون ترميز قيم الأبعاد بشكل ثابت.
|
||||
|
||||
## بيان المشكلة
|
||||
|
||||
تتطلب مستودعات المتجهات تحديد بُعد التضمين عند إنشاء المجموعات/الفهارس. ومع ذلك:
|
||||
تنتج نماذج التضمين المختلفة أبعادًا مختلفة (مثل 384، 768، 1536)
|
||||
لا يتم معرفة البُعد حتى يتم إنشاء أول تضمين
|
||||
قد تتلقى مجموعة TrustGraph واحدة تضمينات من نماذج متعددة
|
||||
يؤدي ترميز بُعد (مثل 384) إلى حدوث أعطال مع أحجام تضمين أخرى
|
||||
|
||||
## مبادئ التصميم
|
||||
|
||||
1. **الإنشاء الكسول (Lazy Creation):** يتم إنشاء المجموعات عند الطلب أثناء الكتابة الأولى، وليس أثناء عمليات إدارة المجموعة.
|
||||
2. **تسمية قائمة على البُعد (Dimension-Based Naming):** تتضمن أسماء المجموعات بُعد التضمين كلاحقة.
|
||||
3. **التدهور السلس (Graceful Degradation):** تُرجع الاستعلامات التي تستهدف مجموعات غير موجودة نتائج فارغة، وليس أخطاء.
|
||||
4. **دعم متعدد الأبعاد (Multi-Dimension Support):** يمكن أن تحتوي مجموعة منطقية واحدة على مجموعات فعلية متعددة (واحدة لكل بُعد).
|
||||
|
||||
## البنية
|
||||
|
||||
### اصطلاح تسمية المجموعة
|
||||
|
||||
تستخدم مجموعات مستودعات المتجهات لاحقات الأبعاد لدعم أحجام تضمين متعددة:
|
||||
|
||||
**تضمينات المستندات:**
|
||||
Qdrant: `d_{user}_{collection}_{dimension}`
|
||||
Pinecone: `d-{user}-{collection}-{dimension}`
|
||||
Milvus: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**تضمينات الرسم البياني:**
|
||||
Qdrant: `t_{user}_{collection}_{dimension}`
|
||||
Pinecone: `t-{user}-{collection}-{dimension}`
|
||||
Milvus: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
أمثلة:
|
||||
`d_alice_papers_384` - مجموعة أوراق أليس مع تضمينات ذات أبعاد 384.
|
||||
`d_alice_papers_768` - نفس المجموعة المنطقية مع تضمينات ذات أبعاد 768.
|
||||
`t_bob_knowledge_1536` - رسم بياني معرفة بوب مع تضمينات ذات أبعاد 1536.
|
||||
|
||||
### مراحل دورة الحياة
|
||||
|
||||
#### 1. طلب إنشاء المجموعة
|
||||
|
||||
**تدفق الطلب:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**السلوك:**
|
||||
يقوم أمين المكتبة ببث طلبات `create-collection` إلى جميع أنظمة التخزين الخلفية.
|
||||
تقوم معالجات مخازن المتجهات بالاعتراف بالطلب ولكن **لا تقوم بإنشاء مجموعات فعلية**.
|
||||
يتم إرجاع الاستجابة على الفور مع الإشارة إلى النجاح.
|
||||
يتم تأجيل إنشاء المجموعة الفعلي حتى أول عملية كتابة.
|
||||
|
||||
**السبب:**
|
||||
الأبعاد غير معروفة في وقت الإنشاء.
|
||||
يتجنب إنشاء مجموعات بأبعاد خاطئة.
|
||||
يبسط منطق إدارة المجموعات.
|
||||
|
||||
#### 2. عمليات الكتابة (الإنشاء المؤجل)
|
||||
|
||||
**تدفق الكتابة:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**السلوك:**
|
||||
1. استخراج بُعد التضمين من المتجه: `dim = len(vector)`
|
||||
2. إنشاء اسم المجموعة مع لاحقة البُعد
|
||||
3. التحقق مما إذا كانت المجموعة موجودة بهذا البُعد المحدد
|
||||
4. إذا لم تكن موجودة:
|
||||
إنشاء مجموعة بالبُعد الصحيح
|
||||
تسجيل: `"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. إدراج التضمين في المجموعة الخاصة بالبُعد
|
||||
|
||||
**سيناريو مثال:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. عمليات الاستعلام
|
||||
|
||||
**تدفق الاستعلام:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**السلوك:**
|
||||
1. استخراج البُعد من متجه الاستعلام: `dim = len(vector)`
|
||||
2. إنشاء اسم المجموعة مع لاحقة البُعد
|
||||
3. التحقق مما إذا كانت المجموعة موجودة
|
||||
4. إذا كانت موجودة:
|
||||
إجراء بحث عن التشابه
|
||||
إرجاع النتائج
|
||||
5. إذا لم تكن موجودة:
|
||||
تسجيل: `"Collection {name} does not exist, returning empty results"`
|
||||
إرجاع قائمة فارغة (دون إثارة أي خطأ)
|
||||
|
||||
**أبعاد متعددة في نفس الاستعلام:**
|
||||
إذا كان الاستعلام يحتوي على متجهات بأبعاد مختلفة
|
||||
تستعلم كل بُعد عن المجموعة المقابلة له
|
||||
يتم تجميع النتائج
|
||||
يتم تخطي المجموعات المفقودة (ولا يتم التعامل معها كأخطاء)
|
||||
|
||||
**السبب:**
|
||||
الاستعلام عن مجموعة فارغة هو حالة استخدام صالحة
|
||||
إرجاع نتائج فارغة هو أمر منطقي
|
||||
يتجنب الأخطاء أثناء بدء تشغيل النظام أو قبل استيعاب البيانات
|
||||
|
||||
#### 4. حذف المجموعة
|
||||
|
||||
**عملية الحذف:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**السلوك:**
|
||||
1. إنشاء نمط البادئة: `d_{user}_{collection}_` (لاحظ الشرطة السفلية في النهاية)
|
||||
2. سرد جميع المجموعات في مخزن المتجهات.
|
||||
3. تصفية المجموعات التي تتطابق مع البادئة.
|
||||
4. حذف جميع المجموعات المتطابقة.
|
||||
5. تسجيل كل عملية حذف: `"Deleted collection {name}"`
|
||||
6. سجل ملخص: `"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**مثال:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**الأساس المنطقي:**
|
||||
يضمن التنظيف الكامل لجميع المتغيرات الأبعاد.
|
||||
يمنع مطابقة الأنماط الحذف العرضي للمجموعات غير المرتبطة.
|
||||
عملية ذرية من وجهة نظر المستخدم (يتم حذف جميع الأبعاد معًا).
|
||||
|
||||
## الخصائص السلوكية
|
||||
|
||||
### العمليات العادية
|
||||
|
||||
**إنشاء المجموعة:**
|
||||
✓ يُرجع النجاح على الفور.
|
||||
✓ لا يتم تخصيص مساحة تخزين فعلية.
|
||||
✓ عملية سريعة (لا يوجد إدخال/إخراج خلفي).
|
||||
|
||||
**الكتابة الأولى:**
|
||||
✓ ينشئ مجموعة بالبعد الصحيح.
|
||||
✓ أبطأ قليلاً بسبب تكلفة إنشاء المجموعة.
|
||||
✓ عمليات الكتابة اللاحقة لنفس البعد سريعة.
|
||||
|
||||
**الاستعلامات قبل أي عمليات كتابة:**
|
||||
✓ تُرجع نتائج فارغة.
|
||||
✓ لا توجد أخطاء أو استثناءات.
|
||||
✓ يظل النظام مستقرًا.
|
||||
|
||||
**عمليات كتابة الأبعاد المختلطة:**
|
||||
✓ ينشئ تلقائيًا مجموعات منفصلة لكل بُعد.
|
||||
✓ يتم عزل كل بُعد في مجموعته الخاصة.
|
||||
✓ لا توجد تعارضات في الأبعاد أو أخطاء في المخطط.
|
||||
|
||||
**حذف المجموعة:**
|
||||
✓ يزيل جميع متغيرات الأبعاد.
|
||||
✓ تنظيف كامل.
|
||||
✓ لا توجد مجموعات يتيمة.
|
||||
|
||||
### الحالات الخاصة
|
||||
|
||||
**نماذج تضمين متعددة:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**الكتابات الأولية المتزامنة:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**ترحيل الأبعاد:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**استعلامات المجموعة الفارغة:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## ملاحظات حول التنفيذ
|
||||
|
||||
### تفاصيل حول نظام التخزين الخاص
|
||||
|
||||
**Qdrant:**
|
||||
يستخدم `collection_exists()` للتحقق من الوجود
|
||||
يستخدم `get_collections()` لعرض القائمة أثناء الحذف
|
||||
يتطلب إنشاء المجموعة `VectorParams(size=dim, distance=Distance.COSINE)`
|
||||
|
||||
**Pinecone:**
|
||||
يستخدم `has_index()` للتحقق من الوجود
|
||||
يستخدم `list_indexes()` لعرض القائمة أثناء الحذف
|
||||
يتطلب إنشاء الفهرس الانتظار حتى حالة "جاهز"
|
||||
يتم تكوين المواصفات بدون خادم مع السحابة/المنطقة
|
||||
|
||||
**Milvus:**
|
||||
تدير الفئات المباشرة (`DocVectors`، `EntityVectors`) دورة الحياة
|
||||
ذاكرة تخزين مؤقت داخلية `self.collections[(dim, user, collection)]` للأداء
|
||||
يتم تنظيف أسماء المجموعات (أحرف وأرقام وشرطة سفلية فقط)
|
||||
يدعم مخططًا بمعرفات متزايدة تلقائيًا
|
||||
|
||||
### اعتبارات الأداء
|
||||
|
||||
**زمن الوصول للكتابة الأولية:**
|
||||
تكلفة إضافية بسبب إنشاء المجموعة
|
||||
Qdrant: ~100-500 مللي ثانية
|
||||
Pinecone: ~10-30 ثانية (توفير بدون خادم)
|
||||
Milvus: ~500-2000 مللي ثانية (يتضمن الفهرسة)
|
||||
|
||||
**أداء الاستعلام:**
|
||||
يضيف التحقق من الوجود تكلفة إضافية ضئيلة (~1-10 مللي ثانية)
|
||||
لا يوجد تأثير على الأداء بمجرد وجود المجموعة
|
||||
يتم تحسين كل مجموعة أبعاد بشكل مستقل
|
||||
|
||||
**تكلفة التخزين:**
|
||||
بيانات وصفية قليلة لكل مجموعة
|
||||
التكلفة الرئيسية هي التخزين لكل بُعد
|
||||
مقايضة: مساحة التخزين مقابل مرونة الأبعاد
|
||||
|
||||
## اعتبارات مستقبلية
|
||||
|
||||
**توحيد الأبعاد التلقائي:**
|
||||
يمكن إضافة عملية خلفية لتحديد ودمج متغيرات الأبعاد غير المستخدمة
|
||||
سيتطلب ذلك إعادة تضمين أو تقليل الأبعاد
|
||||
|
||||
**اكتشاف الأبعاد:**
|
||||
يمكن تعريض واجهة برمجة تطبيقات لسرد جميع الأبعاد المستخدمة لمجموعة
|
||||
مفيد للإدارة والمراقبة
|
||||
|
||||
**تفضيل الأبعاد الافتراضي:**
|
||||
يمكن تتبع "البُعد الأساسي" لكل مجموعة
|
||||
يستخدم للاستعلامات عندما يكون سياق البُعد غير متاح
|
||||
|
||||
**حصص التخزين:**
|
||||
قد تكون هناك حاجة إلى حدود الأبعاد لكل مجموعة
|
||||
يمنع الانتشار المفرط لمتغيرات الأبعاد
|
||||
|
||||
## ملاحظات حول الترحيل
|
||||
|
||||
**من نظام لاحقة الأبعاد القديم:**
|
||||
المجموعات القديمة: `d_{user}_{collection}` (بدون لاحقة البُعد)
|
||||
المجموعات الجديدة: `d_{user}_{collection}_{dim}` (مع لاحقة البُعد)
|
||||
لا يوجد ترحيل تلقائي - تظل المجموعات القديمة قابلة للوصول
|
||||
ضع في اعتبارك برنامج ترحيل يدوي إذا لزم الأمر
|
||||
يمكن تشغيل كلا نظامي التسمية في وقت واحد
|
||||
|
||||
## المراجع
|
||||
|
||||
إدارة المجموعات: `docs/tech-specs/collection-management.md`
|
||||
مخطط التخزين: `trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
خدمة أمين المكتبة: `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
299
docs/tech-specs/vector-store-lifecycle.es.md
Normal file
299
docs/tech-specs/vector-store-lifecycle.es.md
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# Gestión del ciclo de vida del almacén de vectores
|
||||
|
||||
## Resumen
|
||||
|
||||
Este documento describe cómo TrustGraph gestiona las colecciones de almacenes de vectores en diferentes implementaciones de backend (Qdrant, Pinecone, Milvus). El diseño aborda el desafío de admitir incrustaciones con diferentes dimensiones sin codificar valores de dimensión.
|
||||
|
||||
## Declaración del problema
|
||||
|
||||
Los almacenes de vectores requieren que se especifique la dimensión de la incrustación al crear colecciones/índices. Sin embargo:
|
||||
Los diferentes modelos de incrustación producen diferentes dimensiones (por ejemplo, 384, 768, 1536)
|
||||
La dimensión no se conoce hasta que se genera la primera incrustación
|
||||
Una sola colección de TrustGraph puede recibir incrustaciones de múltiples modelos
|
||||
Codificar una dimensión (por ejemplo, 384) causa fallos con otros tamaños de incrustación
|
||||
|
||||
## Principios de diseño
|
||||
|
||||
1. **Creación perezosa**: Las colecciones se crean bajo demanda durante la primera escritura, no durante las operaciones de gestión de colecciones.
|
||||
2. **Nombres basados en la dimensión**: Los nombres de las colecciones incluyen la dimensión de la incrustación como sufijo.
|
||||
3. **Degradación gradual**: Las consultas contra colecciones inexistentes devuelven resultados vacíos, no errores.
|
||||
4. **Soporte para múltiples dimensiones**: Una sola colección lógica puede tener múltiples colecciones físicas (una por dimensión).
|
||||
|
||||
## Arquitectura
|
||||
|
||||
### Convención de nombres de colecciones
|
||||
|
||||
Las colecciones del almacén de vectores utilizan sufijos de dimensión para admitir múltiples tamaños de incrustación:
|
||||
|
||||
**Incrustaciones de documentos:**
|
||||
Qdrant: `d_{user}_{collection}_{dimension}`
|
||||
Pinecone: `d-{user}-{collection}-{dimension}`
|
||||
Milvus: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**Incrustaciones de gráficos:**
|
||||
Qdrant: `t_{user}_{collection}_{dimension}`
|
||||
Pinecone: `t-{user}-{collection}-{dimension}`
|
||||
Milvus: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
Ejemplos:
|
||||
`d_alice_papers_384` - Colección de documentos de Alice con incrustaciones de 384 dimensiones
|
||||
`d_alice_papers_768` - Misma colección lógica con incrustaciones de 768 dimensiones
|
||||
`t_bob_knowledge_1536` - Gráfico de conocimiento de Bob con incrustaciones de 1536 dimensiones
|
||||
|
||||
### Fases del ciclo de vida
|
||||
|
||||
#### 1. Solicitud de creación de colección
|
||||
|
||||
**Flujo de solicitud:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**Comportamiento:**
|
||||
El bibliotecario transmite las solicitudes `create-collection` a todos los backends de almacenamiento.
|
||||
Los procesadores de almacenes vectoriales reconocen la solicitud, pero **no crean colecciones físicas**.
|
||||
La respuesta se devuelve inmediatamente con éxito.
|
||||
La creación real de la colección se pospone hasta la primera escritura.
|
||||
|
||||
**Justificación:**
|
||||
La dimensión es desconocida en el momento de la creación.
|
||||
Evita la creación de colecciones con dimensiones incorrectas.
|
||||
Simplifica la lógica de gestión de colecciones.
|
||||
|
||||
#### 2. Operaciones de escritura (Creación diferida)
|
||||
|
||||
**Flujo de escritura:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**Comportamiento:**
|
||||
1. Extraer la dimensión de incrustación del vector: `dim = len(vector)`
|
||||
2. Construir el nombre de la colección con el sufijo de dimensión
|
||||
3. Verificar si la colección existe con esa dimensión específica
|
||||
4. Si no existe:
|
||||
Crear la colección con la dimensión correcta
|
||||
Registrar: `"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. Insertar la incrustación en la colección específica de la dimensión
|
||||
|
||||
**Escenario de ejemplo:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. Operaciones de consulta
|
||||
|
||||
**Flujo de consulta:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**Comportamiento:**
|
||||
1. Extraer la dimensión del vector de consulta: `dim = len(vector)`
|
||||
2. Construir el nombre de la colección con el sufijo de dimensión
|
||||
3. Comprobar si la colección existe
|
||||
4. Si existe:
|
||||
Realizar una búsqueda de similitud
|
||||
Devolver los resultados
|
||||
5. Si no existe:
|
||||
Registrar: `"Collection {name} does not exist, returning empty results"`
|
||||
Devolver una lista vacía (no se genera ningún error)
|
||||
|
||||
**Múltiples Dimensiones en la Misma Consulta:**
|
||||
Si la consulta contiene vectores de diferentes dimensiones
|
||||
Cada dimensión consulta su colección correspondiente
|
||||
Los resultados se agregan
|
||||
Las colecciones faltantes se omiten (no se consideran errores)
|
||||
|
||||
**Justificación:**
|
||||
Consultar una colección vacía es un caso de uso válido
|
||||
Devolver resultados vacíos es semánticamente correcto
|
||||
Evita errores durante el inicio del sistema o antes de la ingesta de datos
|
||||
|
||||
#### 4. Eliminación de Colecciones
|
||||
|
||||
**Flujo de Eliminación:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**Comportamiento:**
|
||||
1. Construir el patrón de prefijo: `d_{user}_{collection}_` (observar el guion bajo al final)
|
||||
2. Listar todas las colecciones en el almacén vectorial
|
||||
3. Filtrar las colecciones que coincidan con el prefijo
|
||||
4. Eliminar todas las colecciones que coincidan
|
||||
5. Registrar cada eliminación: `"Deleted collection {name}"`
|
||||
6. Registro resumido: `"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**Ejemplo:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**Justificación:**
|
||||
Asegura una limpieza completa de todas las variantes de dimensión.
|
||||
La coincidencia de patrones evita la eliminación accidental de colecciones no relacionadas.
|
||||
Operación atómica desde la perspectiva del usuario (todas las dimensiones se eliminan juntas).
|
||||
|
||||
## Características de comportamiento
|
||||
|
||||
### Operaciones normales
|
||||
|
||||
**Creación de colecciones:**
|
||||
✓ Devuelve éxito inmediatamente.
|
||||
✓ No se asigna almacenamiento físico.
|
||||
✓ Operación rápida (sin E/S de backend).
|
||||
|
||||
**Primera escritura:**
|
||||
✓ Crea la colección con la dimensión correcta.
|
||||
✓ Ligeramente más lenta debido a la sobrecarga de la creación de la colección.
|
||||
✓ Las escrituras posteriores a la misma dimensión son rápidas.
|
||||
|
||||
**Consultas antes de cualquier escritura:**
|
||||
✓ Devuelve resultados vacíos.
|
||||
✓ No hay errores ni excepciones.
|
||||
✓ El sistema permanece estable.
|
||||
|
||||
**Escrituras de dimensiones mixtas:**
|
||||
✓ Crea automáticamente colecciones separadas por dimensión.
|
||||
✓ Cada dimensión está aislada en su propia colección.
|
||||
✓ No hay conflictos de dimensiones ni errores de esquema.
|
||||
|
||||
**Eliminación de colecciones:**
|
||||
✓ Elimina todas las variantes de dimensión.
|
||||
✓ Limpieza completa.
|
||||
✓ No hay colecciones huérfanas.
|
||||
|
||||
### Casos límite
|
||||
|
||||
**Múltiples modelos de incrustación:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**Primeras Escrituras Concurrentes:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**Migración de Dimensiones:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**Consultas de Colecciones Vacías:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## Notas de Implementación
|
||||
|
||||
### Detalles Específicos del Backend de Almacenamiento
|
||||
|
||||
**Qdrant:**
|
||||
Utiliza `collection_exists()` para verificaciones de existencia
|
||||
Utiliza `get_collections()` para listar durante la eliminación
|
||||
La creación de colecciones requiere `VectorParams(size=dim, distance=Distance.COSINE)`
|
||||
|
||||
**Pinecone:**
|
||||
Utiliza `has_index()` para verificaciones de existencia
|
||||
Utiliza `list_indexes()` para listar durante la eliminación
|
||||
La creación de índices requiere esperar el estado "ready"
|
||||
La especificación serverless se configura con la región de la nube
|
||||
|
||||
**Milvus:**
|
||||
Las clases directas (`DocVectors`, `EntityVectors`) gestionan el ciclo de vida
|
||||
Caché interno `self.collections[(dim, user, collection)]` para mejorar el rendimiento
|
||||
Los nombres de las colecciones se sanitizan (solo alfanumérico y guión bajo)
|
||||
Admite esquemas con IDs de auto-incremento
|
||||
|
||||
### Consideraciones de Rendimiento
|
||||
|
||||
**Latencia de la Primera Escritura:**
|
||||
Sobrecarga adicional debido a la creación de la colección
|
||||
Qdrant: ~100-500ms
|
||||
Pinecone: ~10-30 segundos (provisionamiento serverless)
|
||||
Milvus: ~500-2000ms (incluye indexación)
|
||||
|
||||
**Rendimiento de la Consulta:**
|
||||
La verificación de existencia agrega una sobrecarga mínima (~1-10ms)
|
||||
No hay impacto en el rendimiento una vez que la colección existe
|
||||
Cada colección de dimensiones se optimiza de forma independiente
|
||||
|
||||
**Sobrecarga de Almacenamiento:**
|
||||
Metadatos mínimos por colección
|
||||
La principal sobrecarga es el almacenamiento por dimensión
|
||||
Compromiso: Espacio de almacenamiento vs. flexibilidad de las dimensiones
|
||||
|
||||
## Consideraciones Futuras
|
||||
|
||||
**Consolidación Automática de Dimensiones:**
|
||||
Se podría agregar un proceso en segundo plano para identificar y fusionar variantes de dimensiones no utilizadas
|
||||
Requeriría re-embedding o reducción de dimensiones
|
||||
|
||||
**Descubrimiento de Dimensiones:**
|
||||
Se podría exponer una API para listar todas las dimensiones utilizadas para una colección
|
||||
Útil para la administración y el monitoreo
|
||||
|
||||
**Preferencia de Dimensión Predeterminada:**
|
||||
Se podría rastrear la dimensión "primaria" por colección
|
||||
Utilizar para consultas cuando el contexto de la dimensión no está disponible
|
||||
|
||||
**Cuotas de Almacenamiento:**
|
||||
Es posible que se necesiten límites de dimensiones por colección
|
||||
Prevenir la proliferación de variantes de dimensiones
|
||||
|
||||
## Notas de Migración
|
||||
|
||||
**Desde el Sistema de Sufijo de Dimensión Anterior:**
|
||||
Colecciones antiguas: `d_{user}_{collection}` (sin sufijo de dimensión)
|
||||
Colecciones nuevas: `d_{user}_{collection}_{dim}` (con sufijo de dimensión)
|
||||
No hay migración automática: las colecciones antiguas permanecen accesibles
|
||||
Considere un script de migración manual si es necesario
|
||||
Se pueden ejecutar ambos esquemas de nombres simultáneamente
|
||||
|
||||
## Referencias
|
||||
|
||||
Gestión de Colecciones: `docs/tech-specs/collection-management.md`
|
||||
Esquema de Almacenamiento: `trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
Servicio de Bibliotecario: `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
299
docs/tech-specs/vector-store-lifecycle.he.md
Normal file
299
docs/tech-specs/vector-store-lifecycle.he.md
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# ניהול מחזור החיים של מאגר וקטורים
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מסמך זה מתאר כיצד TrustGraph מנהלת אוספי מאגרי וקטורים על פני יישומים שונים (Qdrant, Pinecone, Milvus). העיצוב מתמודד עם האתגר של תמיכה בהטבעות עם ממדים שונים מבלי לקודד ערכי ממדים באופן קשיח.
|
||||
|
||||
## הצהרת בעיה
|
||||
|
||||
מאגרי וקטורים דורשים ציון הממד של ההטבעה בעת יצירת אוספים/אינדקסים. עם זאת:
|
||||
מודלים שונים של הטבעה מייצרים ממדים שונים (לדוגמה, 384, 768, 1536)
|
||||
הממד אינו ידוע עד ליצירת ההטבעה הראשונה
|
||||
אוסף TrustGraph יחיד עשוי לקבל הטבעות ממודלים מרובים
|
||||
קידוד קשיח של ממד (לדוגמה, 384) גורם לכשלים עם גדלי הטבעה אחרים
|
||||
|
||||
## עקרונות עיצוב
|
||||
|
||||
1. **יצירה עצלה**: אוספים נוצרים לפי דרישה במהלך הכתיבה הראשונה, ולא במהלך פעולות ניהול אוספים.
|
||||
2. **שמות המבוססים על ממד**: שמות האוספים כוללים את הממד כסיומת.
|
||||
3. **התדרדרות חלקה**: שאילתות לאוספים שאינם קיימים מחזירות תוצאות ריקות, ולא שגיאות.
|
||||
4. **תמיכה במספר ממדים**: אוסף לוגי יחיד יכול לכלול מספר אוספים פיזיים (אחד לכל ממד).
|
||||
|
||||
## ארכיטקטורה
|
||||
|
||||
### מוסכמות מתן שמות לאוספים
|
||||
|
||||
אוספי מאגרי וקטורים משתמשים בסיומות ממד כדי לתמוך במספר גדלי הטבעה:
|
||||
|
||||
**הטבעות מסמכים:**
|
||||
Qdrant: `d_{user}_{collection}_{dimension}`
|
||||
Pinecone: `d-{user}-{collection}-{dimension}`
|
||||
Milvus: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**הטבעות גרף:**
|
||||
Qdrant: `t_{user}_{collection}_{dimension}`
|
||||
Pinecone: `t-{user}-{collection}-{dimension}`
|
||||
Milvus: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
דוגמאות:
|
||||
`d_alice_papers_384` - אוסף המאמרים של אליס עם הטבעות ממדיות של 384.
|
||||
`d_alice_papers_768` - אותו אוסף לוגי עם הטבעות ממדיות של 768.
|
||||
`t_bob_knowledge_1536` - גרף הידע של בוב עם הטבעות ממדיות של 1536.
|
||||
|
||||
### שלבי מחזור חיים
|
||||
|
||||
#### 1. בקשת יצירת אוסף
|
||||
|
||||
**זרימת בקשה:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**התנהגות:**
|
||||
הספרן משדר בקשות `create-collection` לכל אחסוני הנתונים.
|
||||
מעבדי אחסון וקטורים מאשרים את הבקשה, אך **אינם יוצרים אוספים פיזיים**.
|
||||
התגובה מוחזרת מיד עם הצלחה.
|
||||
יצירת האוסף בפועל נדחית עד לכתיבה הראשונה.
|
||||
|
||||
**ההצדקה:**
|
||||
המימד אינו ידוע בזמן היצירה.
|
||||
מונע יצירת אוספים עם מימדים שגויים.
|
||||
מפשט את לוגיקת ניהול האוספים.
|
||||
|
||||
#### 2. פעולות כתיבה (יצירה עצלה)
|
||||
|
||||
**זרימת הכתיבה:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**התנהגות:**
|
||||
1. חילוץ ממד ההטבעה מהווקטור: `dim = len(vector)`
|
||||
2. יצירת שם אוסף עם סיומת הממד
|
||||
3. בדיקה האם קיים אוסף עם אותו ממד ספציפי
|
||||
4. אם לא קיים:
|
||||
יצירת אוסף עם הממד הנכון
|
||||
רישום: `"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. הכנסת ההטבעה לאוסף הספציפי לממד
|
||||
|
||||
**תרחיש לדוגמה:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. פעולות שאילתה
|
||||
|
||||
**זרימת השאילתה:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**התנהגות:**
|
||||
1. חילוץ מימד מהווקטור של השאילתה: `dim = len(vector)`
|
||||
2. יצירת שם אוסף עם סיומת המציינת את המימד
|
||||
3. בדיקה האם האוסף קיים
|
||||
4. אם קיים:
|
||||
ביצוע חיפוש דמיון
|
||||
החזרת תוצאות
|
||||
5. אם לא קיים:
|
||||
רישום: `"Collection {name} does not exist, returning empty results"`
|
||||
החזרת רשימה ריקה (ללא העלאת שגיאה)
|
||||
|
||||
**מימדים מרובים באותה שאילתה:**
|
||||
אם השאילתה מכילה וקטורים של מימדים שונים
|
||||
כל מימד מבצע שאילתה על האוסף המתאים לו
|
||||
התוצאות מאוחדות
|
||||
אוספים חסרים מדלגים (לא מטופלים כשגיאות)
|
||||
|
||||
**ההצדקה:**
|
||||
שאילתה על אוסף ריק היא מקרה שימוש חוקי
|
||||
החזרת תוצאות ריקות היא נכונה מבחינה סמנטית
|
||||
מונע שגיאות במהלך אתחול המערכת או לפני טעינת נתונים
|
||||
|
||||
#### 4. מחיקת אוסף
|
||||
|
||||
**תהליך מחיקה:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**התנהגות:**
|
||||
1. בניית תבנית קידומת: `d_{user}_{collection}_` (שימו לב לקו התחתון בסוף)
|
||||
2. רשימת כל האוספים במאגר הווקטורים
|
||||
3. סינון אוספים התואמים לקידומת
|
||||
4. מחיקת כל האוספים התואמים
|
||||
5. רישום כל מחיקה: `"Deleted collection {name}"`
|
||||
6. רישום סיכום: `"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**דוגמה:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**הסבר:**
|
||||
מבטיח ניקוי מלא של כל וריאציות המימדים.
|
||||
התאמת תבניות מונעת מחיקה בשוגע של אוספים לא קשורים.
|
||||
פעולה אטומית מנקודת מבטו של המשתמש (כל המימדים נמחקים יחד).
|
||||
|
||||
## מאפיינים התנהגותיים
|
||||
|
||||
### פעולות רגילות
|
||||
|
||||
**יצירת אוסף:**
|
||||
✓ מחזיר הצלחה באופן מיידי.
|
||||
✓ לא מוקצה אחסון פיזי.
|
||||
✓ פעולה מהירה (ללא קלט/פלט של מערכת הפעלה).
|
||||
|
||||
**כתיבה ראשונה:**
|
||||
✓ יוצר אוסף עם מימד נכון.
|
||||
✓ מעט איטי יותר עקב תקורה של יצירת האוסף.
|
||||
✓ כתיבות עוקבות לאותו מימד מהירות.
|
||||
|
||||
**שאילתות לפני כל כתיבה:**
|
||||
✓ מחזיר תוצאות ריקות.
|
||||
✓ אין שגיאות או חריגות.
|
||||
✓ המערכת נשארת יציבה.
|
||||
|
||||
**כתיבות של מימדים שונים:**
|
||||
✓ יוצר באופן אוטומטי אוספים נפרדים לכל מימד.
|
||||
✓ כל מימד מבודד באוסף משלו.
|
||||
✓ אין התנגשויות מימדים או שגיאות סכימה.
|
||||
|
||||
**מחיקת אוסף:**
|
||||
✓ מסיר את כל וריאציות המימדים.
|
||||
✓ ניקוי מלא.
|
||||
✓ אין אוספים יתומים.
|
||||
|
||||
### מקרים קצה
|
||||
|
||||
**מודלים משובצים מרובים:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**כתיבות ראשוניות מקבילות:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**הגירה של ממדים:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**שאילתות לאוספים ריקים:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## הערות יישום
|
||||
|
||||
### פרטים ספציפיים לגבי אחסון
|
||||
|
||||
**Qdrant:**
|
||||
משתמש ב-`collection_exists()` לבדיקות קיום
|
||||
משתמש ב-`get_collections()` לרשימה במהלך מחיקה
|
||||
יצירת אוסף דורשת `VectorParams(size=dim, distance=Distance.COSINE)`
|
||||
|
||||
**Pinecone:**
|
||||
משתמש ב-`has_index()` לבדיקות קיום
|
||||
משתמש ב-`list_indexes()` לרשימה במהלך מחיקה
|
||||
יצירת אינדקס דורשת המתנה למצב "מוכן"
|
||||
מפרט שרת חסר מוגדר עם ענן/אזור
|
||||
|
||||
**Milvus:**
|
||||
מחלקות ישירות (`DocVectors`, `EntityVectors`) מנהלות את מחזור החיים
|
||||
מטמון פנימי `self.collections[(dim, user, collection)]` לביצועים
|
||||
שמות אוספים עוברים סינון (רק תווים אלפאנומריים וקו תחתון)
|
||||
תומך בסכימה עם מזהים עם הגדלה אוטומטית
|
||||
|
||||
### שיקולי ביצועים
|
||||
|
||||
**זמן השהייה לכתיבה ראשונה:**
|
||||
תקורה נוספת עקב יצירת אוסף
|
||||
Qdrant: ~100-500ms
|
||||
Pinecone: ~10-30 שניות (הקצאת שרת חסר)
|
||||
Milvus: ~500-2000ms (כולל אינדקס)
|
||||
|
||||
**ביצועי שאילתות:**
|
||||
בדיקת קיום מוסיפה תקורה מינימלית (~1-10ms)
|
||||
אין השפעה על הביצועים לאחר יצירת האוסף
|
||||
כל אוסף ממד מותאם באופן עצמאי
|
||||
|
||||
**תקורה של אחסון:**
|
||||
מטא-דאטה מינימלי לכל אוסף
|
||||
התקורה העיקרית היא אחסון לכל ממד
|
||||
פשרה: שטח אחסון לעומת גמישות ממדים
|
||||
|
||||
## שיקולים עתידיים
|
||||
|
||||
**איחוד ממדים אוטומטי:**
|
||||
ניתן להוסיף תהליך רקע לזיהוי ומיזוג גרסאות ממדים לא בשימוש
|
||||
זה ידרוש הטמעה מחדש או צמצום ממדים
|
||||
|
||||
**גילוי ממדים:**
|
||||
ניתן לחשוף API לרשימת כל הממדים בשימוש עבור אוסף
|
||||
שימושי לניהול וניטור
|
||||
|
||||
**העדפה ברירת מחדל לממד:**
|
||||
ניתן לעקוב אחר "ממד ראשי" לכל אוסף
|
||||
להשתמש עבור שאילתות כאשר הקשר הממד אינו זמין
|
||||
|
||||
**מכסות אחסון:**
|
||||
ייתכן שיהיה צורך במגבלות ממדים לכל אוסף
|
||||
למנוע התרבות של גרסאות ממדים
|
||||
|
||||
## הערות העברה
|
||||
|
||||
**ממערכת קודמת עם סיומת ממד:**
|
||||
אוספים ישנים: `d_{user}_{collection}` (ללא סיומת ממד)
|
||||
אוספים חדשים: `d_{user}_{collection}_{dim}` (עם סיומת ממד)
|
||||
אין העברה אוטומטית - אוספים ישנים נשארים נגישים
|
||||
שקול סקריפט העברה ידני אם יש צורך
|
||||
ניתן להפעיל שני סכימות שמות בו זמנית
|
||||
|
||||
## הפניות
|
||||
|
||||
ניהול אוספים: `docs/tech-specs/collection-management.md`
|
||||
סכימת אחסון: `trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
שירות ספרית: `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
299
docs/tech-specs/vector-store-lifecycle.hi.md
Normal file
299
docs/tech-specs/vector-store-lifecycle.hi.md
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# वेक्टर स्टोर लाइफसाइकिल प्रबंधन
|
||||
|
||||
## अवलोकन
|
||||
|
||||
यह दस्तावेज़ बताता है कि ट्रस्टग्राफ विभिन्न बैकएंड कार्यान्वयन (क्यूड्रेंट, पाइनकोन, मिल्वस) में वेक्टर स्टोर संग्रहों का प्रबंधन कैसे करता है। डिज़ाइन विभिन्न आयामों वाले एम्बेडिंग का समर्थन करने की चुनौती को संबोधित करता है बिना आयाम मानों को हार्डकोड किए।
|
||||
|
||||
## समस्या विवरण
|
||||
|
||||
वेक्टर स्टोर को संग्रह/इंडेक्स बनाते समय एम्बेडिंग आयाम को निर्दिष्ट करने की आवश्यकता होती है। हालाँकि:
|
||||
विभिन्न एम्बेडिंग मॉडल अलग-अलग आयाम उत्पन्न करते हैं (उदाहरण के लिए, 384, 768, 1536)
|
||||
आयाम तब तक ज्ञात नहीं होता है जब तक कि पहला एम्बेडिंग उत्पन्न नहीं हो जाता
|
||||
एक ही ट्रस्टग्राफ संग्रह कई मॉडलों से एम्बेडिंग प्राप्त कर सकता है
|
||||
एक आयाम को हार्डकोड करना (उदाहरण के लिए, 384) अन्य एम्बेडिंग आकारों के साथ विफलताओं का कारण बनता है
|
||||
|
||||
## डिज़ाइन सिद्धांत
|
||||
|
||||
1. **आलसी निर्माण**: संग्रह पहली बार लिखने के दौरान ऑन-डिमांड बनाए जाते हैं, संग्रह प्रबंधन कार्यों के दौरान नहीं।
|
||||
2. **आयाम-आधारित नामकरण**: संग्रह नामों में एम्बेडिंग आयाम को एक प्रत्यय के रूप में शामिल किया जाता है।
|
||||
3. **सुचारू गिरावट**: गैर-मौजूदा संग्रहों के खिलाफ किए गए प्रश्नों से त्रुटियां नहीं, बल्कि खाली परिणाम मिलते हैं।
|
||||
4. **बहु-आयाम समर्थन**: एक ही तार्किक संग्रह में कई भौतिक संग्रह (प्रत्येक आयाम के लिए एक) हो सकते हैं।
|
||||
|
||||
## वास्तुकला
|
||||
|
||||
### संग्रह नामकरण सम्मेलन
|
||||
|
||||
वेक्टर स्टोर संग्रह कई एम्बेडिंग आकारों का समर्थन करने के लिए आयाम प्रत्ययों का उपयोग करते हैं:
|
||||
|
||||
**दस्तावेज़ एम्बेडिंग:**
|
||||
क्यूड्रेंट: `d_{user}_{collection}_{dimension}`
|
||||
पाइनकोन: `d-{user}-{collection}-{dimension}`
|
||||
मिल्वस: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**ग्राफ एम्बेडिंग:**
|
||||
क्यूड्रेंट: `t_{user}_{collection}_{dimension}`
|
||||
पाइनकोन: `t-{user}-{collection}-{dimension}`
|
||||
मिल्वस: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
उदाहरण:
|
||||
`d_alice_papers_384` - 384-आयामी एम्बेडिंग वाले एलिस के पेपर संग्रह
|
||||
`d_alice_papers_768` - 768-आयामी एम्बेडिंग वाले समान तार्किक संग्रह
|
||||
`t_bob_knowledge_1536` - 1536-आयामी एम्बेडिंग वाले बॉब के ज्ञान ग्राफ
|
||||
|
||||
### जीवनचक्र चरण
|
||||
|
||||
#### 1. संग्रह निर्माण अनुरोध
|
||||
|
||||
**अनुरोध प्रवाह:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**व्यवहार:**
|
||||
लाइब्रेरियन `create-collection` अनुरोधों को सभी स्टोरेज बैकएंड्स को भेजता है।
|
||||
वेक्टर स्टोर प्रोसेसर अनुरोध को स्वीकार करते हैं लेकिन **भौतिक संग्रह नहीं बनाते हैं।**
|
||||
प्रतिक्रिया तुरंत सफलता के साथ वापस की जाती है।
|
||||
वास्तविक संग्रह निर्माण पहले लिखने तक स्थगित रहता है।
|
||||
|
||||
**तर्क:**
|
||||
निर्माण के समय आयाम अज्ञात होता है।
|
||||
गलत आयाम वाले संग्रह बनाने से बचा जाता है।
|
||||
संग्रह प्रबंधन तर्क को सरल बनाता है।
|
||||
|
||||
#### 2. लेखन संचालन (आलसी निर्माण)
|
||||
|
||||
**लेखन प्रवाह:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**व्यवहार:**
|
||||
1. वेक्टर से एम्बेडिंग आयाम निकालें: `dim = len(vector)`
|
||||
2. आयाम प्रत्यय के साथ संग्रह का नाम बनाएं
|
||||
3. जांचें कि क्या उस विशिष्ट आयाम के साथ कोई संग्रह मौजूद है
|
||||
4. यदि मौजूद नहीं है:
|
||||
सही आयाम के साथ संग्रह बनाएं
|
||||
लॉग करें: `"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. एम्बेडिंग को आयाम-विशिष्ट संग्रह में डालें
|
||||
|
||||
**उदाहरण परिदृश्य:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. क्वेरी ऑपरेशन
|
||||
|
||||
**क्वेरी प्रवाह:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**व्यवहार:**
|
||||
1. क्वेरी वेक्टर से आयाम निकालें: `dim = len(vector)`
|
||||
2. आयाम प्रत्यय के साथ संग्रह नाम बनाएं
|
||||
3. जांचें कि संग्रह मौजूद है या नहीं
|
||||
4. यदि मौजूद है:
|
||||
समानता खोज करें
|
||||
परिणाम लौटाएं
|
||||
5. यदि मौजूद नहीं है:
|
||||
लॉग करें: `"Collection {name} does not exist, returning empty results"`
|
||||
खाली सूची लौटाएं (कोई त्रुटि नहीं)
|
||||
|
||||
**एक ही क्वेरी में कई आयाम:**
|
||||
यदि क्वेरी में विभिन्न आयामों वाले वेक्टर हैं
|
||||
प्रत्येक आयाम अपने संबंधित संग्रह को क्वेरी करता है
|
||||
परिणाम एकत्रित किए जाते हैं
|
||||
गुम संग्रह को छोड़ दिया जाता है (त्रुटियों के रूप में नहीं माना जाता है)
|
||||
|
||||
**तर्क:**
|
||||
एक खाली संग्रह को क्वेरी करना एक वैध उपयोग मामला है
|
||||
खाली परिणाम लौटाना अर्थपूर्ण रूप से सही है
|
||||
सिस्टम स्टार्टअप के दौरान या डेटा इनपुट से पहले त्रुटियों से बचाता है
|
||||
|
||||
#### 4. संग्रह हटाना
|
||||
|
||||
**हटाने की प्रक्रिया:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**व्यवहार:**
|
||||
1. उपसर्ग पैटर्न का निर्माण करें: `d_{user}_{collection}_` (अंतिम अंडरस्कोर पर ध्यान दें)
|
||||
2. वेक्टर स्टोर में सभी संग्रहों की सूची बनाएं
|
||||
3. उपसर्ग से मेल खाने वाले संग्रहों को फ़िल्टर करें
|
||||
4. सभी मेल खाने वाले संग्रहों को हटाएं
|
||||
5. प्रत्येक हटाने को लॉग करें: `"Deleted collection {name}"`
|
||||
6. सारांश लॉग: `"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**उदाहरण:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**तर्क:**
|
||||
सभी आयाम रूपों की पूरी तरह से सफाई सुनिश्चित करता है।
|
||||
पैटर्न मिलान से असंबंधित संग्रहों को गलती से हटाने से रोका जाता है।
|
||||
उपयोगकर्ता के दृष्टिकोण से परमाणु ऑपरेशन (सभी आयाम एक साथ हटा दिए जाते हैं)।
|
||||
|
||||
## व्यवहार संबंधी विशेषताएं
|
||||
|
||||
### सामान्य संचालन
|
||||
|
||||
**संग्रह निर्माण:**
|
||||
✓ तुरंत सफलता देता है।
|
||||
✓ कोई भौतिक भंडारण आवंटित नहीं किया जाता है।
|
||||
✓ तेज़ ऑपरेशन (कोई बैकएंड I/O नहीं)।
|
||||
|
||||
**पहला लेखन:**
|
||||
✓ सही आयाम के साथ संग्रह बनाता है।
|
||||
✓ संग्रह निर्माण के ओवरहेड के कारण थोड़ा धीमा।
|
||||
✓ उसी आयाम में बाद के लेखन तेज़ होते हैं।
|
||||
|
||||
**किसी भी लेखन से पहले प्रश्न:**
|
||||
✓ खाली परिणाम देता है।
|
||||
✓ कोई त्रुटि या अपवाद नहीं।
|
||||
✓ सिस्टम स्थिर रहता है।
|
||||
|
||||
**मिश्रित आयाम लेखन:**
|
||||
✓ स्वचालित रूप से प्रत्येक आयाम के लिए अलग-अलग संग्रह बनाता है।
|
||||
✓ प्रत्येक आयाम अपने स्वयं के संग्रह में अलग-थलग होता है।
|
||||
✓ कोई आयाम संघर्ष या स्कीमा त्रुटि नहीं होती है।
|
||||
|
||||
**संग्रह हटाना:**
|
||||
✓ सभी आयाम रूपों को हटा देता है।
|
||||
✓ पूर्ण सफाई।
|
||||
✓ कोई अनाथ संग्रह नहीं।
|
||||
|
||||
### विशेष स्थितियाँ
|
||||
|
||||
**एकाधिक एम्बेडिंग मॉडल:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**एक साथ प्रारंभिक लेखन:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**आयाम प्रवासन:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**खाली संग्रह प्रश्नों:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## कार्यान्वयन नोट्स
|
||||
|
||||
### स्टोरेज बैकएंड विशिष्ट विवरण
|
||||
|
||||
**Qdrant:**
|
||||
अस्तित्व जांच के लिए `collection_exists()` का उपयोग करता है
|
||||
हटाने के दौरान लिस्टिंग के लिए `get_collections()` का उपयोग करता है
|
||||
संग्रह निर्माण के लिए `VectorParams(size=dim, distance=Distance.COSINE)` की आवश्यकता होती है
|
||||
|
||||
**Pinecone:**
|
||||
अस्तित्व जांच के लिए `has_index()` का उपयोग करता है
|
||||
हटाने के दौरान लिस्टिंग के लिए `list_indexes()` का उपयोग करता है
|
||||
इंडेक्स निर्माण के लिए "तैयार" स्थिति की प्रतीक्षा करने की आवश्यकता होती है
|
||||
सर्वरलेस विनिर्देश क्लाउड/क्षेत्र के साथ कॉन्फ़िगर किया गया है
|
||||
|
||||
**Milvus:**
|
||||
डायरेक्ट क्लासेस (`DocVectors`, `EntityVectors`) लाइफसाइकिल का प्रबंधन करती हैं
|
||||
प्रदर्शन के लिए आंतरिक कैश `self.collections[(dim, user, collection)]`
|
||||
संग्रह नामों को सैनिटाइज किया जाता है (केवल अल्फ़ान्यूमेरिक + अंडरस्कोर)
|
||||
ऑटो-इंक्रीमेंटिंग आईडी के साथ स्कीमा का समर्थन करता है
|
||||
|
||||
### प्रदर्शन संबंधी विचार
|
||||
|
||||
**पहली लेखन विलंबता:**
|
||||
संग्रह निर्माण के कारण अतिरिक्त ओवरहेड
|
||||
Qdrant: ~100-500ms
|
||||
Pinecone: ~10-30 सेकंड (सर्वरलेस प्रावधान)
|
||||
Milvus: ~500-2000ms (इसमें इंडेक्सिंग शामिल है)
|
||||
|
||||
**क्वेरी प्रदर्शन:**
|
||||
अस्तित्व जांच से न्यूनतम ओवरहेड जुड़ता है (~1-10ms)
|
||||
एक बार संग्रह मौजूद होने पर कोई प्रदर्शन प्रभाव नहीं पड़ता है
|
||||
प्रत्येक आयाम संग्रह स्वतंत्र रूप से अनुकूलित है
|
||||
|
||||
**स्टोरेज ओवरहेड:**
|
||||
प्रति संग्रह न्यूनतम मेटाडेटा
|
||||
मुख्य ओवरहेड प्रति-आयाम स्टोरेज है
|
||||
ट्रेड-ऑफ: स्टोरेज स्पेस बनाम आयाम लचीलापन
|
||||
|
||||
## भविष्य के विचार
|
||||
|
||||
**स्वचालित आयाम समेकन:**
|
||||
अप्रयुक्त आयाम वेरिएंट की पहचान और विलय करने के लिए एक पृष्ठभूमि प्रक्रिया जोड़ी जा सकती है
|
||||
इसके लिए पुनः एम्बेडिंग या आयाम में कमी की आवश्यकता होगी
|
||||
|
||||
**आयाम खोज:**
|
||||
एक संग्रह के लिए उपयोग किए जा रहे सभी आयामों को सूचीबद्ध करने के लिए एपीआई उजागर किया जा सकता है
|
||||
प्रशासन और निगरानी के लिए उपयोगी
|
||||
|
||||
**डिफ़ॉल्ट आयाम प्राथमिकता:**
|
||||
प्रति संग्रह "प्राथमिक" आयाम को ट्रैक किया जा सकता है
|
||||
जब आयाम संदर्भ अनुपलब्ध हो तो प्रश्नों के लिए इसका उपयोग करें
|
||||
|
||||
**स्टोरेज कोटा:**
|
||||
प्रति-संग्रह आयाम सीमाएं आवश्यक हो सकती हैं
|
||||
आयाम वेरिएंट के प्रसार को रोकें
|
||||
|
||||
## माइग्रेशन नोट्स
|
||||
|
||||
**प्री-डायमेंशन-सफिक्स सिस्टम से:**
|
||||
पुराने संग्रह: `d_{user}_{collection}` (कोई आयाम प्रत्यय नहीं)
|
||||
नए संग्रह: `d_{user}_{collection}_{dim}` (आयाम प्रत्यय के साथ)
|
||||
कोई स्वचालित माइग्रेशन नहीं - पुराने संग्रह सुलभ रहते हैं
|
||||
यदि आवश्यक हो तो एक मैनुअल माइग्रेशन स्क्रिप्ट पर विचार करें
|
||||
दोनों नामकरण योजनाओं को एक साथ चलाया जा सकता है
|
||||
|
||||
## संदर्भ
|
||||
|
||||
संग्रह प्रबंधन: `docs/tech-specs/collection-management.md`
|
||||
स्टोरेज स्कीमा: `trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
लाइब्रेरियन सेवा: `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
299
docs/tech-specs/vector-store-lifecycle.pt.md
Normal file
299
docs/tech-specs/vector-store-lifecycle.pt.md
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# Gerenciamento do Ciclo de Vida do Vector Store
|
||||
|
||||
## Visão Geral
|
||||
|
||||
Este documento descreve como o TrustGraph gerencia coleções de vector store em diferentes implementações de backend (Qdrant, Pinecone, Milvus). O design aborda o desafio de suportar embeddings com diferentes dimensões sem codificar valores de dimensão.
|
||||
|
||||
## Declaração do Problema
|
||||
|
||||
Os vector stores exigem que a dimensão do embedding seja especificada ao criar coleções/índices. No entanto:
|
||||
Modelos de embedding diferentes produzem dimensões diferentes (por exemplo, 384, 768, 1536)
|
||||
A dimensão não é conhecida até que o primeiro embedding seja gerado
|
||||
Uma única coleção do TrustGraph pode receber embeddings de vários modelos
|
||||
A codificação de uma dimensão (por exemplo, 384) causa falhas com outros tamanhos de embedding
|
||||
|
||||
## Princípios de Design
|
||||
|
||||
1. **Criação Preguiçosa (Lazy Creation)**: As coleções são criadas sob demanda durante a primeira escrita, e não durante as operações de gerenciamento de coleção.
|
||||
2. **Nomeação Baseada em Dimensão**: Os nomes das coleções incluem a dimensão do embedding como um sufixo.
|
||||
3. **Degradação Graciosa**: As consultas contra coleções inexistentes retornam resultados vazios, e não erros.
|
||||
4. **Suporte a Múltiplas Dimensões**: Uma única coleção lógica pode ter várias coleções físicas (uma por dimensão).
|
||||
|
||||
## Arquitetura
|
||||
|
||||
### Convenção de Nomenclatura de Coleções
|
||||
|
||||
As coleções de vector store usam sufixos de dimensão para suportar vários tamanhos de embedding:
|
||||
|
||||
**Embeddings de Documentos:**
|
||||
Qdrant: `d_{user}_{collection}_{dimension}`
|
||||
Pinecone: `d-{user}-{collection}-{dimension}`
|
||||
Milvus: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**Embeddings de Grafos:**
|
||||
Qdrant: `t_{user}_{collection}_{dimension}`
|
||||
Pinecone: `t-{user}-{collection}-{dimension}`
|
||||
Milvus: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
Exemplos:
|
||||
`d_alice_papers_384` - Coleção de artigos da Alice com embeddings de 384 dimensões
|
||||
`d_alice_papers_768` - Mesma coleção lógica com embeddings de 768 dimensões
|
||||
`t_bob_knowledge_1536` - Grafo de conhecimento do Bob com embeddings de 1536 dimensões
|
||||
|
||||
### Fases do Ciclo de Vida
|
||||
|
||||
#### 1. Solicitação de Criação de Coleção
|
||||
|
||||
**Fluxo da Solicitação:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**Comportamento:**
|
||||
O bibliotecário transmite solicitações `create-collection` para todos os backends de armazenamento.
|
||||
Os processadores de armazenamento vetorial confirmam a solicitação, mas **não criam coleções físicas**.
|
||||
A resposta é retornada imediatamente com sucesso.
|
||||
A criação real da coleção é adiada até a primeira escrita.
|
||||
|
||||
**Justificativa:**
|
||||
A dimensão é desconhecida no momento da criação.
|
||||
Evita a criação de coleções com dimensões incorretas.
|
||||
Simplifica a lógica de gerenciamento de coleções.
|
||||
|
||||
#### 2. Operações de Escrita (Criação Preguiçosa)
|
||||
|
||||
**Fluxo de Escrita:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**Comportamento:**
|
||||
1. Extrair a dimensão do embedding do vetor: `dim = len(vector)`
|
||||
2. Construir o nome da coleção com o sufixo da dimensão
|
||||
3. Verificar se a coleção existe com essa dimensão específica
|
||||
4. Se não existir:
|
||||
Criar a coleção com a dimensão correta
|
||||
Registrar: `"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. Inserir o embedding na coleção específica da dimensão
|
||||
|
||||
**Cenário de Exemplo:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. Operações de Consulta
|
||||
|
||||
**Fluxo de Consulta:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**Comportamento:**
|
||||
1. Extrair a dimensão do vetor de consulta: `dim = len(vector)`
|
||||
2. Construir o nome da coleção com o sufixo da dimensão
|
||||
3. Verificar se a coleção existe
|
||||
4. Se existir:
|
||||
Realizar uma busca de similaridade
|
||||
Retornar os resultados
|
||||
5. Se não existir:
|
||||
Registrar: `"Collection {name} does not exist, returning empty results"`
|
||||
Retornar uma lista vazia (nenhum erro é gerado)
|
||||
|
||||
**Múltiplas Dimensões na Mesma Consulta:**
|
||||
Se a consulta contiver vetores de dimensões diferentes
|
||||
Cada dimensão consulta sua coleção correspondente
|
||||
Os resultados são agregados
|
||||
As coleções ausentes são ignoradas (não são tratadas como erros)
|
||||
|
||||
**Justificativa:**
|
||||
Consultar uma coleção vazia é um caso de uso válido
|
||||
Retornar resultados vazios é semanticamente correto
|
||||
Evita erros durante a inicialização do sistema ou antes da ingestão de dados
|
||||
|
||||
#### 4. Exclusão de Coleção
|
||||
|
||||
**Fluxo de Exclusão:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**Comportamento:**
|
||||
1. Construir o padrão de prefixo: `d_{user}_{collection}_` (observe o sublinhado no final)
|
||||
2. Listar todas as coleções no armazenamento vetorial
|
||||
3. Filtrar as coleções que correspondem ao prefixo
|
||||
4. Excluir todas as coleções correspondentes
|
||||
5. Registrar cada exclusão: `"Deleted collection {name}"`
|
||||
6. Registro resumido: `"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**Exemplo:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**Justificativa:**
|
||||
Garante a limpeza completa de todas as variantes de dimensão.
|
||||
A correspondência de padrões evita a exclusão acidental de coleções não relacionadas.
|
||||
Operação atômica da perspectiva do usuário (todas as dimensões são excluídas juntas).
|
||||
|
||||
## Características Comportamentais
|
||||
|
||||
### Operações Normais
|
||||
|
||||
**Criação de Coleção:**
|
||||
✓ Retorna sucesso imediatamente.
|
||||
✓ Nenhum armazenamento físico é alocado.
|
||||
✓ Operação rápida (sem E/S de backend).
|
||||
|
||||
**Primeira Escrita:**
|
||||
✓ Cria a coleção com a dimensão correta.
|
||||
✓ Ligeiramente mais lenta devido à sobrecarga da criação da coleção.
|
||||
✓ Escritas subsequentes na mesma dimensão são rápidas.
|
||||
|
||||
**Consultas Antes de Qualquer Escrita:**
|
||||
✓ Retorna resultados vazios.
|
||||
✓ Nenhum erro ou exceção.
|
||||
✓ O sistema permanece estável.
|
||||
|
||||
**Escritas de Dimensões Mistas:**
|
||||
✓ Cria automaticamente coleções separadas por dimensão.
|
||||
✓ Cada dimensão é isolada em sua própria coleção.
|
||||
✓ Nenhum conflito de dimensão ou erro de esquema.
|
||||
|
||||
**Exclusão de Coleção:**
|
||||
✓ Remove todas as variantes de dimensão.
|
||||
✓ Limpeza completa.
|
||||
✓ Nenhuma coleção órfã.
|
||||
|
||||
### Casos Limite
|
||||
|
||||
**Múltiplos Modelos de Incorporação:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**Primeiras Escritas Concorrentes:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**Migração de Dimensões:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**Consultas de Coleção Vazia:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## Notas de Implementação
|
||||
|
||||
### Especificidades do Backend de Armazenamento
|
||||
|
||||
**Qdrant:**
|
||||
Usa `collection_exists()` para verificações de existência
|
||||
Usa `get_collections()` para listagem durante a exclusão
|
||||
A criação de coleções requer `VectorParams(size=dim, distance=Distance.COSINE)`
|
||||
|
||||
**Pinecone:**
|
||||
Usa `has_index()` para verificações de existência
|
||||
Usa `list_indexes()` para listagem durante a exclusão
|
||||
A criação de índices requer esperar pelo status "ready"
|
||||
Especificação serverless configurada com cloud/região
|
||||
|
||||
**Milvus:**
|
||||
Classes diretas (`DocVectors`, `EntityVectors`) gerenciam o ciclo de vida
|
||||
Cache interno `self.collections[(dim, user, collection)]` para desempenho
|
||||
Nomes de coleções são sanitizados (apenas alfanumérico + underscore)
|
||||
Suporta esquema com IDs de incremento automático
|
||||
|
||||
### Considerações de Desempenho
|
||||
|
||||
**Latência da Primeira Gravação:**
|
||||
Overhead adicional devido à criação da coleção
|
||||
Qdrant: ~100-500ms
|
||||
Pinecone: ~10-30 segundos (provisionamento serverless)
|
||||
Milvus: ~500-2000ms (inclui indexação)
|
||||
|
||||
**Desempenho da Consulta:**
|
||||
A verificação de existência adiciona um overhead mínimo (~1-10ms)
|
||||
Nenhum impacto no desempenho depois que a coleção existe
|
||||
Cada coleção de dimensões é otimizada independentemente
|
||||
|
||||
**Overhead de Armazenamento:**
|
||||
Metadados mínimos por coleção
|
||||
O principal overhead é por armazenamento de dimensão
|
||||
Compromisso: Espaço de armazenamento vs. flexibilidade de dimensão
|
||||
|
||||
## Considerações Futuras
|
||||
|
||||
**Consolidação Automática de Dimensões:**
|
||||
Poderia adicionar um processo em segundo plano para identificar e mesclar variantes de dimensões não utilizadas
|
||||
Requereria re-embedding ou redução de dimensão
|
||||
|
||||
**Descoberta de Dimensões:**
|
||||
Poderia expor uma API para listar todas as dimensões em uso para uma coleção
|
||||
Útil para administração e monitoramento
|
||||
|
||||
**Preferência de Dimensão Padrão:**
|
||||
Poderia rastrear a "dimensão primária" por coleção
|
||||
Usar para consultas quando o contexto da dimensão não está disponível
|
||||
|
||||
**Quotas de Armazenamento:**
|
||||
Pode ser necessário limites de dimensão por coleção
|
||||
Prevenir a proliferação de variantes de dimensão
|
||||
|
||||
## Notas de Migração
|
||||
|
||||
**Do Sistema de Sufixo de Pré-Dimensão:**
|
||||
Coleções antigas: `d_{user}_{collection}` (sem sufixo de dimensão)
|
||||
Coleções novas: `d_{user}_{collection}_{dim}` (com sufixo de dimensão)
|
||||
Nenhuma migração automática - coleções antigas permanecem acessíveis
|
||||
Considere um script de migração manual, se necessário
|
||||
Pode executar ambos os esquemas de nomenclatura simultaneamente
|
||||
|
||||
## Referências
|
||||
|
||||
Gerenciamento de Coleções: `docs/tech-specs/collection-management.md`
|
||||
Esquema de Armazenamento: `trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
Serviço Librarian: `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
299
docs/tech-specs/vector-store-lifecycle.ru.md
Normal file
299
docs/tech-specs/vector-store-lifecycle.ru.md
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# Управление жизненным циклом векторных хранилищ
|
||||
|
||||
## Обзор
|
||||
|
||||
Этот документ описывает, как TrustGraph управляет коллекциями векторных хранилищ в различных реализациях бэкенда (Qdrant, Pinecone, Milvus). Проект решает проблему поддержки вложений с разными размерностями без жесткой кодировки значений размерностей.
|
||||
|
||||
## Описание проблемы
|
||||
|
||||
Векторные хранилища требуют указания размерности вложений при создании коллекций/индексов. Однако:
|
||||
Разные модели вложений генерируют разные размерности (например, 384, 768, 1536).
|
||||
Размерность неизвестна до генерации первого вложения.
|
||||
Одна коллекция TrustGraph может получать вложения из нескольких моделей.
|
||||
Жесткая кодировка размерности (например, 384) приводит к сбоям при использовании других размеров вложений.
|
||||
|
||||
## Принципы проектирования
|
||||
|
||||
1. **Отложенное создание**: Коллекции создаются по запросу при первой записи, а не во время операций управления коллекциями.
|
||||
2. **Именование на основе размерности**: Имена коллекций включают размерность вложения в качестве суффикса.
|
||||
3. **Плавное снижение функциональности**: Запросы к несуществующим коллекциям возвращают пустые результаты, а не ошибки.
|
||||
4. **Поддержка нескольких размерностей**: Одна логическая коллекция может иметь несколько физических коллекций (по одной для каждой размерности).
|
||||
|
||||
## Архитектура
|
||||
|
||||
### Соглашение об именовании коллекций
|
||||
|
||||
Коллекции векторных хранилищ используют суффиксы, указывающие размерность, для поддержки нескольких размеров вложений:
|
||||
|
||||
**Вложения документов:**
|
||||
Qdrant: `d_{user}_{collection}_{dimension}`
|
||||
Pinecone: `d-{user}-{collection}-{dimension}`
|
||||
Milvus: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**Вложения графов:**
|
||||
Qdrant: `t_{user}_{collection}_{dimension}`
|
||||
Pinecone: `t-{user}-{collection}-{dimension}`
|
||||
Milvus: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
Примеры:
|
||||
`d_alice_papers_384` - Коллекция статей Алисы с вложениями размерностью 384.
|
||||
`d_alice_papers_768` - Та же логическая коллекция с вложениями размерностью 768.
|
||||
`t_bob_knowledge_1536` - Граф знаний Боба с вложениями размерностью 1536.
|
||||
|
||||
### Фазы жизненного цикла
|
||||
|
||||
#### 1. Запрос на создание коллекции
|
||||
|
||||
**Поток запросов:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**Поведение:**
|
||||
Библиотекарь отправляет запросы `create-collection` всем хранилищам данных.
|
||||
Процессоры векторных хранилищ подтверждают запрос, но **не создают физические коллекции**.
|
||||
Ответ возвращается немедленно с сообщением об успехе.
|
||||
Фактическое создание коллекции откладывается до первой записи.
|
||||
|
||||
**Обоснование:**
|
||||
Размерность неизвестна на момент создания.
|
||||
Предотвращает создание коллекций с неправильными размерами.
|
||||
Упрощает логику управления коллекциями.
|
||||
|
||||
#### 2. Операции записи (отложенное создание)
|
||||
|
||||
**Поток записи:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**Поведение:**
|
||||
1. Извлечь размерность вложения из вектора: `dim = len(vector)`
|
||||
2. Сформировать имя коллекции с суффиксом, указывающим на размерность.
|
||||
3. Проверить, существует ли коллекция с указанной размерностью.
|
||||
4. Если коллекция не существует:
|
||||
Создать коллекцию с правильной размерностью.
|
||||
Записать в лог: `"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. Вставить вложение в коллекцию, специфичную для данной размерности.
|
||||
|
||||
**Пример сценария:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. Операции запросов
|
||||
|
||||
**Поток запросов:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**Поведение:**
|
||||
1. Извлечение размерности из вектора запроса: `dim = len(vector)`
|
||||
2. Формирование имени коллекции с суффиксом, указывающим размерность.
|
||||
3. Проверка наличия коллекции.
|
||||
4. Если коллекция существует:
|
||||
Выполнение поиска по схожести.
|
||||
Возврат результатов.
|
||||
5. Если коллекция не существует:
|
||||
Запись в журнал: `"Collection {name} does not exist, returning empty results"`
|
||||
Возврат пустого списка (без возникновения ошибки).
|
||||
|
||||
**Несколько размерностей в одном запросе:**
|
||||
Если запрос содержит векторы разных размерностей.
|
||||
Для каждой размерности выполняется поиск в соответствующей коллекции.
|
||||
Результаты объединяются.
|
||||
Отсутствующие коллекции пропускаются (не рассматриваются как ошибки).
|
||||
|
||||
**Обоснование:**
|
||||
Запрос к пустой коллекции является допустимым сценарием использования.
|
||||
Возврат пустых результатов является семантически правильным.
|
||||
Предотвращает ошибки при запуске системы или до загрузки данных.
|
||||
|
||||
#### 4. Удаление коллекции
|
||||
|
||||
**Процесс удаления:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**Поведение:**
|
||||
1. Создание префиксного шаблона: `d_{user}_{collection}_` (обратите внимание на завершающий символ подчеркивания)
|
||||
2. Перечисление всех коллекций в векторной базе данных.
|
||||
3. Фильтрация коллекций, соответствующих префиксу.
|
||||
4. Удаление всех соответствующих коллекций.
|
||||
5. Запись каждого удаления в журнал: `"Deleted collection {name}"`
|
||||
6. Итоговый журнал: `"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**Пример:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**Обоснование:**
|
||||
Обеспечивает полную очистку всех вариантов измерений.
|
||||
Сопоставление с образцом предотвращает случайное удаление несвязанных коллекций.
|
||||
Атомарная операция с точки зрения пользователя (все измерения удаляются вместе).
|
||||
|
||||
## Поведенческие характеристики
|
||||
|
||||
### Нормальная работа
|
||||
|
||||
**Создание коллекции:**
|
||||
✓ Немедленно возвращает успешный результат.
|
||||
✓ Не выделяется физическое хранилище.
|
||||
✓ Быстрая операция (без операций ввода-вывода на стороне сервера).
|
||||
|
||||
**Первая запись:**
|
||||
✓ Создает коллекцию с правильным измерением.
|
||||
✓ Немного медленнее из-за накладных расходов на создание коллекции.
|
||||
✓ Последующие записи в то же измерение выполняются быстро.
|
||||
|
||||
**Запросы до любых записей:**
|
||||
✓ Возвращает пустые результаты.
|
||||
✓ Без ошибок или исключений.
|
||||
✓ Система остается стабильной.
|
||||
|
||||
**Смешанные записи измерений:**
|
||||
✓ Автоматически создает отдельные коллекции для каждого измерения.
|
||||
✓ Каждое измерение изолировано в своей коллекции.
|
||||
✓ Отсутствуют конфликты измерений или ошибки схемы.
|
||||
|
||||
**Удаление коллекции:**
|
||||
✓ Удаляет все варианты измерений.
|
||||
✓ Полная очистка.
|
||||
✓ Отсутствуют "осиротевшие" коллекции.
|
||||
|
||||
### Крайние случаи
|
||||
|
||||
**Несколько моделей встраивания:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**Одновременные первые записи:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**Миграция измерений:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**Запросы к пустой коллекции:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## Заметки об реализации
|
||||
|
||||
### Особенности используемого хранилища данных
|
||||
|
||||
**Qdrant:**
|
||||
Использует `collection_exists()` для проверок существования
|
||||
Использует `get_collections()` для перечисления при удалении
|
||||
Создание коллекции требует `VectorParams(size=dim, distance=Distance.COSINE)`
|
||||
|
||||
**Pinecone:**
|
||||
Использует `has_index()` для проверок существования
|
||||
Использует `list_indexes()` для перечисления при удалении
|
||||
Создание индекса требует ожидания статуса "ready"
|
||||
Serverless режим конфигурируется с указанием облака/региона
|
||||
|
||||
**Milvus:**
|
||||
Прямые классы (`DocVectors`, `EntityVectors`) управляют жизненным циклом
|
||||
Внутренний кэш `self.collections[(dim, user, collection)]` для повышения производительности
|
||||
Имена коллекций очищаются (только буквенно-цифровые символы и подчеркивание)
|
||||
Поддерживает схему с автоматически увеличивающимися идентификаторами
|
||||
|
||||
### Вопросы производительности
|
||||
|
||||
**Задержка при первой записи:**
|
||||
Дополнительные накладные расходы, связанные с созданием коллекции
|
||||
Qdrant: ~100-500 мс
|
||||
Pinecone: ~10-30 секунд (подготовка serverless режима)
|
||||
Milvus: ~500-2000 мс (включая индексацию)
|
||||
|
||||
**Производительность запросов:**
|
||||
Проверка существования добавляет минимальные накладные расходы (~1-10 мс)
|
||||
Отсутствие влияния на производительность после создания коллекции
|
||||
Каждая коллекция, соответствующая определенной размерности, оптимизируется независимо
|
||||
|
||||
**Накладные расходы на хранение:**
|
||||
Минимальный объем метаданных на коллекцию
|
||||
Основные накладные расходы связаны с хранением данных для каждой размерности
|
||||
Компромисс: объем хранимых данных против гибкости размерностей
|
||||
|
||||
## Будущие улучшения
|
||||
|
||||
**Автоматическая консолидация размерностей:**
|
||||
Можно добавить фоновый процесс для выявления и объединения неиспользуемых вариантов размерностей
|
||||
Это потребует повторной встраиваемости или уменьшения размерности
|
||||
|
||||
**Обнаружение размерностей:**
|
||||
Можно предоставить API для перечисления всех используемых размерностей для коллекции
|
||||
Полезно для администрирования и мониторинга
|
||||
|
||||
**Предпочтительная размерность по умолчанию:**
|
||||
Можно отслеживать "основную" размерность для каждой коллекции
|
||||
Использовать для запросов, когда контекст размерности недоступен
|
||||
|
||||
**Квоты на хранение:**
|
||||
Возможно, потребуются ограничения на количество размерностей на коллекцию
|
||||
Предотвращение чрезмерного количества вариантов размерностей
|
||||
|
||||
## Примечания по миграции
|
||||
|
||||
**Из системы с суффиксом размерности:**
|
||||
Старые коллекции: `d_{user}_{collection}` (без суффикса размерности)
|
||||
Новые коллекции: `d_{user}_{collection}_{dim}` (с суффиксом размерности)
|
||||
Отсутствует автоматическая миграция - старые коллекции остаются доступными
|
||||
Рассмотрите возможность использования скрипта для ручной миграции, если это необходимо
|
||||
Можно использовать обе схемы именования одновременно
|
||||
|
||||
## Ссылки
|
||||
|
||||
Управление коллекциями: `docs/tech-specs/collection-management.md`
|
||||
Схема хранения: `trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
Сервис Librarian: `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
299
docs/tech-specs/vector-store-lifecycle.sw.md
Normal file
299
docs/tech-specs/vector-store-lifecycle.sw.md
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# Usimamizi wa Mzunguko wa Hifadhi ya Vektor
|
||||
|
||||
## Muhtasari
|
||||
|
||||
Hati hii inaeleza jinsi TrustGraph inavyosimamia mkusanyiko wa hifadhi ya vektor katika matumizi tofauti ya backend (Qdrant, Pinecone, Milvus). Muundo huu unashughulikia changamoto ya kusaidia embeddings zenye vipimo tofauti bila kuweka maadili ya vipimo yaliyopangwa awali.
|
||||
|
||||
## Tatizo
|
||||
|
||||
Hifadhi za vektor zinahitaji kipimo cha embedding kuainishwa wakati wa kuunda mkusanyiko/fahirisi. Hata hivyo:
|
||||
Modeli tofauti za embedding hutoa vipimo tofauti (k.m., 384, 768, 1536)
|
||||
Kipimo hakijulikani hadi embedding ya kwanza itengenezwe
|
||||
Mkusaniko mmoja wa TrustGraph unaweza kupokea embeddings kutoka kwa modeli nyingi
|
||||
Kuweka kipimo (k.m., 384) husababisha hitilafu na saizi zingine za embedding
|
||||
|
||||
## Kanuni za Muundo
|
||||
|
||||
1. **Uundaji wa Kila Mara:** Mikusanyiko huundwa wakati wa kuandika mara ya kwanza, sio wakati wa shughuli za usimamizi wa mkusanyiko.
|
||||
2. **Jina Kulingana na Kipimo:** Majina ya mkusanyiko yanajumuisha kipimo cha embedding kama sehemu ya mwisho.
|
||||
3. **Ufanisi:** Maswali dhidi ya mikusanyiko isiyopo hurudisha matokeo tupu, sio makosa.
|
||||
4. **Usaidizi wa Vipimo Vingi:** Mkusaniko mmoja wa kimantiki unaweza kuwa na mikusanyiko mingi ya kimwili (moja kwa kila kipimo).
|
||||
|
||||
## Muundo
|
||||
|
||||
### Mfumo wa Majina ya Mkusaniko
|
||||
|
||||
Mikusanyiko ya hifadhi ya vektor hutumia sehemu za mwisho za kipimo ili kusaidia saizi nyingi za embedding:
|
||||
|
||||
**Embeddings za Hati:**
|
||||
Qdrant: `d_{user}_{collection}_{dimension}`
|
||||
Pinecone: `d-{user}-{collection}-{dimension}`
|
||||
Milvus: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**Embeddings za Grafu:**
|
||||
Qdrant: `t_{user}_{collection}_{dimension}`
|
||||
Pinecone: `t-{user}-{collection}-{dimension}`
|
||||
Milvus: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
Mifano:
|
||||
`d_alice_papers_384` - Mkusaniko wa "makala za Alice" wenye embeddings za vipimo 384
|
||||
`d_alice_papers_768` - Mkusaniko huo huo wa kimantiki wenye embeddings za vipimo 768
|
||||
`t_bob_knowledge_1536` - Grafu ya maarifa ya "Bob" yenye embeddings za vipimo 1536
|
||||
|
||||
### Awamu za Mzunguko
|
||||
|
||||
#### 1. Ombi la Uundaji wa Mkusaniko
|
||||
|
||||
**Mwendo wa Ombi:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**Tabia:**
|
||||
Msimamizi wa maktaba hutuma ombi la `create-collection` kwa kila mfumo wa kuhifadhi data.
|
||||
Vifaa vya usindikaji vya hifadhi ya vector hutambua ombi hilo lakini **havitaunda makusanyo halisi**
|
||||
Jibu hurudishwa mara moja kwa mafanikio.
|
||||
Uundaji halisi wa makusanyo huahirishwa hadi wakati wa kuandika wa kwanza.
|
||||
|
||||
**Sababu:**
|
||||
Vipimo havijulikani wakati wa uundaji.
|
||||
Inazuia uundaji wa makusanyo yenye vipimo vibaya.
|
||||
Inarahisha mantiki ya usimamizi wa makusanyo.
|
||||
|
||||
#### 2. Operesheni za Kuandika (Uundaji Ulioahirishwa)
|
||||
|
||||
**Mchakato wa Kuandika:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**Tabia:**
|
||||
1. Pata kipimo cha pembejeo kutoka kwenye vektari: `dim = len(vector)`
|
||||
2. Unda jina la mkusanyiko pamoja na kiambishi cha kipimo
|
||||
3. Angalia ikiwa mkusanyiko unapatikana na kipimo hicho maalum
|
||||
4. Ikiwa haupo:
|
||||
Unda mkusanyiko wenye kipimo sahihi
|
||||
Rekodi: `"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. Ingiza pembejeo kwenye mkusanyiko maalum wa kipimo
|
||||
|
||||
**Mfano wa Matukio:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. Operesheni za Uchunguzi
|
||||
|
||||
**Mwendo wa Uchunguzi:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**Tabia:**
|
||||
1. Pata kipimo kutoka kwa vektor ya swali: `dim = len(vector)`
|
||||
2. Unda jina la mkusanyiko pamoja na kiambishi cha kipimo
|
||||
3. Angalia ikiwa mkusanyiko unapatikana
|
||||
4. Ikiwa unapatikana:
|
||||
Fanya utafutaji wa kufanana
|
||||
Rudi na matokeo
|
||||
5. Ikiwa haupatikani:
|
||||
Rekodi: `"Collection {name} does not exist, returning empty results"`
|
||||
Rudi na orodha tupu (hakuna kosa lililotokea)
|
||||
|
||||
**Vipimo Vingi katika Swali Moja:**
|
||||
Ikiwa swali lina vektor za vipimo tofauti
|
||||
Kila kipimo hufanya utafutaji katika mkusanyiko wake unaohusiana
|
||||
Matokeo huunganishwa
|
||||
Mikusanyiko inayokosekana huachwa (hayatibiwi kama madosa)
|
||||
|
||||
**Sababu:**
|
||||
Kuuliza mkusanyiko ambao hauna data ni matumizi halali
|
||||
Kurudi na matokeo tupu ni sahihi kwa maana
|
||||
Inazuia madosa wakati wa kuanza kwa mfumo au kabla ya kuingiza data
|
||||
|
||||
#### 4. Ufutilishaji wa Mkusaniko
|
||||
|
||||
**Mchakato wa Ufutilishaji:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**Tabia:**
|
||||
1. Unda muundo wa kielelezo: `d_{user}_{collection}_` (angalia alama ya chini)
|
||||
2. Orodha zote za makusanyo katika hifadhi ya vekta
|
||||
3. Chuja makusanyo yanayolingana na kielelezo
|
||||
4. Futa makusanyo yote yanayolingana
|
||||
5. Rekodi kila kufutwa: `"Deleted collection {name}"`
|
||||
6. Rekodi ya jumla: `"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**Mfano:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**Sababu:**
|
||||
Inahakikisha usafishaji kamili wa aina zote za vipimo.
|
||||
Ulinganishaji wa muundo huuzuia kufutwa kwa makusudi kwa mkusanyiko usiohusiana.
|
||||
Operesheni ya atomu kutoka kwa mtazamo wa mtumiaji (vipimo vyote hufutwa pamoja).
|
||||
|
||||
## Tabia za Utendaji
|
||||
|
||||
### Operesheni za Kawaida
|
||||
|
||||
**Uundaji wa Mkusanyiko:**
|
||||
✓ Inarudisha mafanikio mara moja.
|
||||
✓ Hakuna uhifadhi wa kimwili unaoombwa.
|
||||
✓ Operesheni ya haraka (hakuna pembejeo/patto la nyuma).
|
||||
|
||||
**Uandishi wa Kwanza:**
|
||||
✓ Huunda mkusanyiko na kipimo sahihi.
|
||||
✓ Huwa polepole kidogo kwa sababu ya gharama ya uundaji wa mkusanyiko.
|
||||
✓ Uandishi wa baadaye kwenye kipimo sawa huwa wa haraka.
|
||||
|
||||
**Umasilisho Kabla ya Uandishi Wowote:**
|
||||
✓ Inarudisha matokeo tupu.
|
||||
✓ Hakuna makosa au ubaguzi.
|
||||
✓ Mfumo unaendelea kuwa thabiti.
|
||||
|
||||
**Uandishi Mseto wa Vipimo:**
|
||||
✓ Huunda moja kwa moja makusanyiko tofauti kwa kila kipimo.
|
||||
✓ Kila kipimo kimetengwa katika mkusanyiko wake mwenyewe.
|
||||
✓ Hakuna migogoro ya kipimo au makosa ya muundo.
|
||||
|
||||
**Ufutaji wa Mkusanyiko:**
|
||||
✓ Huondoa aina zote za vipimo.
|
||||
✓ Usafishaji kamili.
|
||||
✓ Hakuna makusanyiko yaliyotelekezwa.
|
||||
|
||||
### Hali Maalum
|
||||
|
||||
**Miundo Mbalimbali ya Uingizaji:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**Uandikaji wa Kwanza Unaofanyika Pamoja:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**Uhamisho wa Vipimo:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**Maswali ya Mkusanyiko Tupu:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## Maelekezo ya Utendaji
|
||||
|
||||
### Maelezo Maalum ya Hifadhi ya Data
|
||||
|
||||
**Qdrant:**
|
||||
Hutumia `collection_exists()` kwa upangaji wa kuangalia uwepo
|
||||
Hutumia `get_collections()` kwa orodha wakati wa kufuta
|
||||
Uundaji wa mkusanyiko unahitaji `VectorParams(size=dim, distance=Distance.COSINE)`
|
||||
|
||||
**Pinecone:**
|
||||
Hutumia `has_index()` kwa upangaji wa kuangalia uwepo
|
||||
Hutumia `list_indexes()` kwa orodha wakati wa kufuta
|
||||
Uundaji wa faharasa unahitaji kusubiri hali ya "tayari"
|
||||
Vipimo vya seva zisizo na utunzaji vimepangwa na eneo la wingu
|
||||
|
||||
**Milvus:**
|
||||
Darasa za moja kwa moja (`DocVectors`, `EntityVectors`) husimamia mzunguko wa maisha
|
||||
Kumbukumbu ya ndani `self.collections[(dim, user, collection)]` kwa utendaji
|
||||
Majina ya mkusanyiko husafishwa (herufi na nambari pekee + alama ya nukta)
|
||||
Inasaidia schema na vitambulisho ambavyo huongezeka kiotomatiki
|
||||
|
||||
### Mambo ya Kuzingatia ya Utendaji
|
||||
|
||||
**Ucheleweshaji wa Uandikishaji wa Kwanza:**
|
||||
Gharama ya ziada kutokana na uundaji wa mkusanyiko
|
||||
Qdrant: ~100-500ms
|
||||
Pinecone: ~10-30 sekunde (utayarishaji wa seva zisizo na utunzaji)
|
||||
Milvus: ~500-2000ms (pamoja na uwekaji wa faharasa)
|
||||
|
||||
**Utendaji wa Umasilisho:**
|
||||
Uangaliaji wa uwepo unaongeza gharama ndogo (~1-10ms)
|
||||
Hakuna athari ya utendaji mara tu mkusanyiko ukiwepo
|
||||
Kila mkusanyiko wa vipimo unafanywa kazi kwa kujitegemea
|
||||
|
||||
**Gharama ya Hifadhi:**
|
||||
Meta-data ndogo kwa kila mkusanyiko
|
||||
Gharama kuu ni kwa kila kipimo
|
||||
Ulinganisho: Nafasi ya hifadhi dhidi ya uwezekano wa vipimo
|
||||
|
||||
## Mambo ya Kuzingatia ya Baadaye
|
||||
|
||||
**Uunganishaji Otomatiki wa Vipimo:**
|
||||
Inaweza kuongeza mchakato wa asilia wa kutambua na kuunganisha toleo lisilo la vipimo
|
||||
Itahitaji kuweka upya au kupunguza vipimo
|
||||
|
||||
**Unyonyaji wa Vipimo:**
|
||||
Inaweza kuonyesha API ya kuorodhesha vipimo vyote vinavyotumika kwa mkusanyiko
|
||||
Ni muhimu kwa utawala na ufuatiliaji
|
||||
|
||||
**Upendeleo wa Vipimo vya Msingi:**
|
||||
Inaweza kufuatilia kipimo "cha msingi" kwa kila mkusanyiko
|
||||
Tumia kwa masilisho wakati hali ya kipimo haipatikani
|
||||
|
||||
**Mgao wa Hifadhi:**
|
||||
Inaweza kuhitaji mipaka ya kipimo kwa kila mkusanyiko
|
||||
Kuzuia ongezeko la toleo la vipimo
|
||||
|
||||
## Maelekezo ya Uhamishaji
|
||||
|
||||
**Kutoka kwa Mfumo wa Zamani wa Jina la Kipimo:**
|
||||
Mkusanyiko wa zamani: `d_{user}_{collection}` (hakuna jina la kipimo)
|
||||
Mkusanyiko mpya: `d_{user}_{collection}_{dim}` (na jina la kipimo)
|
||||
Hakuna uhamishaji otomatiki - mkusanyiko wa zamani wanaendelea kuwa na ufikiaji
|
||||
Fikiria programu ya uhamishaji ya mwongozo ikiwa inahitajika
|
||||
Unaweza kuendesha mifumo miwili ya majina kwa wakati mmoja
|
||||
|
||||
## Marejeleo
|
||||
|
||||
Usimamizi wa Mkusanyiko: `docs/tech-specs/collection-management.md`
|
||||
Schema ya Hifadhi: `trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
Huduma ya Maktaba: `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
299
docs/tech-specs/vector-store-lifecycle.tr.md
Normal file
299
docs/tech-specs/vector-store-lifecycle.tr.md
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# Vektör Depolama Yaşam Döngüsü Yönetimi
|
||||
|
||||
## Genel Bakış
|
||||
|
||||
Bu belge, TrustGraph'ın farklı arka uç uygulamaları (Qdrant, Pinecone, Milvus) arasında vektör depolama koleksiyonlarını nasıl yönettiğini açıklamaktadır. Tasarım, sabit boyut değerleri kullanmadan farklı boyutlara sahip gömülmeleri destekleme zorluğunu ele almaktadır.
|
||||
|
||||
## Problem Tanımı
|
||||
|
||||
Vektör depoları, koleksiyonlar/indeksler oluşturulurken gömme boyutunun belirtilmesini gerektirir. Ancak:
|
||||
Farklı gömme modelleri farklı boyutlar üretir (örneğin, 384, 768, 1536).
|
||||
Boyut, ilk gömme oluşturulana kadar bilinmemektedir.
|
||||
Tek bir TrustGraph koleksiyonu, birden fazla modelden gömmeler alabilir.
|
||||
Bir boyutu (örneğin, 384) sabit kodlamak, diğer gömme boyutlarıyla uyumsuzluğa neden olur.
|
||||
|
||||
## Tasarım İlkeleri
|
||||
|
||||
1. **Gecikmeli Oluşturma**: Koleksiyonlar, koleksiyon yönetimi işlemlerinin aksine, ilk yazma sırasında talep üzerine oluşturulur.
|
||||
2. **Boyut Tabanlı İsimlendirme**: Koleksiyon adları, gömme boyutunu bir sonek olarak içerir.
|
||||
3. **Nazik Bozulma**: Var olmayan koleksiyonlara yapılan sorgular, hatalar yerine boş sonuçlar döndürür.
|
||||
4. **Çok Boyutlu Destek**: Tek bir mantıksal koleksiyon, birden fazla fiziksel koleksiyona (her biri bir boyut için bir tane) sahip olabilir.
|
||||
|
||||
## Mimari
|
||||
|
||||
### Koleksiyon İsimlendirme Kuralı
|
||||
|
||||
Vektör depolama koleksiyonları, birden fazla gömme boyutunu desteklemek için boyut soneklerini kullanır:
|
||||
|
||||
**Belge Gömme:**
|
||||
Qdrant: `d_{user}_{collection}_{dimension}`
|
||||
Pinecone: `d-{user}-{collection}-{dimension}`
|
||||
Milvus: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**Graf Gömme:**
|
||||
Qdrant: `t_{user}_{collection}_{dimension}`
|
||||
Pinecone: `t-{user}-{collection}-{dimension}`
|
||||
Milvus: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
Örnekler:
|
||||
`d_alice_papers_384` - 384 boyutlu gömmelere sahip Alice'in makale koleksiyonu
|
||||
`d_alice_papers_768` - Aynı mantıksal koleksiyon, 768 boyutlu gömmelerle
|
||||
`t_bob_knowledge_1536` - 1536 boyutlu gömmelere sahip Bob'un bilgi grafiği
|
||||
|
||||
### Yaşam Döngüsü Aşamaları
|
||||
|
||||
#### 1. Koleksiyon Oluşturma İsteği
|
||||
|
||||
**İstek Akışı:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**Davranış:**
|
||||
Kütüphaneci, `create-collection` isteklerini tüm depolama arka uçlarına yayınlar.
|
||||
Vektör depolama işlemcileri isteği kabul eder, ancak **fiziksel koleksiyonlar oluşturmaz**.
|
||||
Yanıt, başarıyla birlikte hemen döndürülür.
|
||||
Gerçek koleksiyon oluşturma, ilk yazma işlemine kadar ertelenir.
|
||||
|
||||
**Gerekçe:**
|
||||
Boyut, oluşturma zamanında bilinmemektedir.
|
||||
Yanlış boyutlara sahip koleksiyonların oluşturulması engellenir.
|
||||
Koleksiyon yönetimi mantığını basitleştirir.
|
||||
|
||||
#### 2. Yazma İşlemleri (Gecikmeli Oluşturma)
|
||||
|
||||
**Yazma Akışı:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**Davranış:**
|
||||
1. Vektörden gömme boyutunu çıkarın: `dim = len(vector)`
|
||||
2. Boyut sonekiyle koleksiyon adını oluşturun
|
||||
3. Belirli o boyuta sahip koleksiyonun var olup olmadığını kontrol edin
|
||||
4. Yoksa:
|
||||
Doğru boyuta sahip bir koleksiyon oluşturun
|
||||
Kaydı tutun: `"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. Gömme değerini, boyutuna özel koleksiyona ekleyin
|
||||
|
||||
**Örnek Senaryo:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. Sorgu İşlemleri
|
||||
|
||||
**Sorgu Akışı:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**Davranış:**
|
||||
1. Sorgu vektöründen boyutu çıkarın: `dim = len(vector)`
|
||||
2. Boyut sonekiyle koleksiyon adını oluşturun
|
||||
3. Koleksiyonun var olup olmadığını kontrol edin
|
||||
4. Varsa:
|
||||
Benzerlik araması yapın
|
||||
Sonuçları döndürün
|
||||
5. Yoksa:
|
||||
Kaydı tutun: `"Collection {name} does not exist, returning empty results"`
|
||||
Boş bir liste döndürün (hata yükseltilmez)
|
||||
|
||||
**Aynı Sorguda Birden Fazla Boyut:**
|
||||
Sorgu farklı boyutlardaki vektörler içeriyorsa
|
||||
Her boyut, ilgili koleksiyonunu sorgular
|
||||
Sonuçlar birleştirilir
|
||||
Eksik koleksiyonlar atlanır (hata olarak değerlendirilmez)
|
||||
|
||||
**Gerekçe:**
|
||||
Boş bir koleksiyonu sorgulamak geçerli bir kullanım durumudur
|
||||
Boş sonuçlar döndürmek anlamsal olarak doğrudur
|
||||
Sistem başlatılırken veya veri yüklemesinden önce hataları önler
|
||||
|
||||
#### 4. Koleksiyon Silme
|
||||
|
||||
**Silme Akışı:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**Davranış:**
|
||||
1. Önek kalıbını oluştur: `d_{user}_{collection}_` (sonundaki alt çizgiye dikkat edin)
|
||||
2. Vektör deposundaki tüm koleksiyonları listele
|
||||
3. Öneğe uyan koleksiyonları filtrele
|
||||
4. Tüm eşleşen koleksiyonları sil
|
||||
5. Her silme işlemini kaydet: `"Deleted collection {name}"`
|
||||
6. Özet günlük: `"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**Örnek:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**Gerekçe:**
|
||||
Tüm boyut varyantlarının tamamen temizlenmesini sağlar.
|
||||
Desen eşleştirme, yanlışlıkla ilgili olmayan koleksiyonların silinmesini önler.
|
||||
Kullanıcı açısından atomik bir işlem (tüm boyutlar birlikte silinir).
|
||||
|
||||
## Davranışsal Özellikler
|
||||
|
||||
### Normal İşlemler
|
||||
|
||||
**Koleksiyon Oluşturma:**
|
||||
✓ Hemen başarı döndürür.
|
||||
✓ Herhangi bir fiziksel depolama alanı ayrılmaz.
|
||||
✓ Hızlı işlem (arka uç G/Ç yok).
|
||||
|
||||
**İlk Yazma:**
|
||||
✓ Doğru boyuta sahip koleksiyon oluşturur.
|
||||
✓ Koleksiyon oluşturma ek yükü nedeniyle biraz daha yavaştır.
|
||||
✓ Aynı boyuta yapılan sonraki yazmalar hızlıdır.
|
||||
|
||||
**Herhangi Bir Yazmadan Önce Sorgular:**
|
||||
✓ Boş sonuçlar döndürür.
|
||||
✓ Herhangi bir hata veya istisna oluşmaz.
|
||||
✓ Sistem kararlı kalır.
|
||||
|
||||
**Farklı Boyutlara Yazma:**
|
||||
✓ Otomatik olarak her boyut için ayrı koleksiyonlar oluşturur.
|
||||
✓ Her boyut kendi koleksiyonunda izole edilir.
|
||||
✓ Herhangi bir boyut çakışması veya şema hatası oluşmaz.
|
||||
|
||||
**Koleksiyon Silme:**
|
||||
✓ Tüm boyut varyantlarını kaldırır.
|
||||
✓ Tam temizleme.
|
||||
✓ Herhangi bir yetim koleksiyon kalmaz.
|
||||
|
||||
### Sınır Durumlar
|
||||
|
||||
**Çoklu Gömülü Model:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**Eşzamanlı İlk Yazma İşlemleri:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**Boyutların Taşınması:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**Boş Koleksiyon Sorguları:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## Uygulama Notları
|
||||
|
||||
### Depolama Arka Ucu Özellikleri
|
||||
|
||||
**Qdrant:**
|
||||
Varlık kontrolleri için `collection_exists()` kullanılır.
|
||||
Silme sırasında listeleme için `get_collections()` kullanılır.
|
||||
Koleksiyon oluşturma `VectorParams(size=dim, distance=Distance.COSINE)` gerektirir.
|
||||
|
||||
**Pinecone:**
|
||||
Varlık kontrolleri için `has_index()` kullanılır.
|
||||
Silme sırasında listeleme için `list_indexes()` kullanılır.
|
||||
İndeks oluşturma, "hazır" durumunu bekleme gerektirir.
|
||||
Sunucusuz yapılandırma, bulut/bölge ile yapılır.
|
||||
|
||||
**Milvus:**
|
||||
Doğrudan sınıflar (`DocVectors`, `EntityVectors`), yaşam döngüsünü yönetir.
|
||||
Performans için dahili önbellek `self.collections[(dim, user, collection)]`.
|
||||
Koleksiyon adları, yalnızca alfanümerik ve alt çizgi içeren şekilde temizlenir.
|
||||
Otomatik artan kimliklere sahip şema desteği.
|
||||
|
||||
### Performans Hususları
|
||||
|
||||
**İlk Yazma Gecikmesi:**
|
||||
Koleksiyon oluşturma nedeniyle ek yük.
|
||||
Qdrant: ~100-500ms
|
||||
Pinecone: ~10-30 saniye (sunucusuz sağlama)
|
||||
Milvus: ~500-2000ms (indekslemeyi içerir)
|
||||
|
||||
**Sorgu Performansı:**
|
||||
Varlık kontrolü, minimum ek yük ekler (~1-10ms).
|
||||
Koleksiyon mevcut olduğunda performans üzerinde etkisi yoktur.
|
||||
Her boyut koleksiyonu, bağımsız olarak optimize edilir.
|
||||
|
||||
**Depolama Yükü:**
|
||||
Her koleksiyon için minimum meta veri.
|
||||
Ana yük, boyut başına depolamadır.
|
||||
Dengeleme: Depolama alanı ile boyut esnekliği.
|
||||
|
||||
## Gelecek Hususlar
|
||||
|
||||
**Otomatik Boyut Birleştirme:**
|
||||
Kullanılmayan boyut varyantlarını belirlemek ve birleştirmek için arka plan işlemi eklenebilir.
|
||||
Yeniden gömme veya boyut azaltma gerektirecektir.
|
||||
|
||||
**Boyut Keşfi:**
|
||||
Bir koleksiyon için kullanılan tüm boyutları listelemek için bir API açılabilir.
|
||||
Yönetim ve izleme için kullanışlıdır.
|
||||
|
||||
**Varsayılan Boyut Tercihi:**
|
||||
Her koleksiyon için "birincil" boyut izlenebilir.
|
||||
Boyut bağlamı kullanılamadığında sorgular için kullanılır.
|
||||
|
||||
**Depolama Kotaları:**
|
||||
Her koleksiyon için boyut limitleri gerekebilir.
|
||||
Boyut varyantlarının yayılmasını önler.
|
||||
|
||||
## Geçiş Notları
|
||||
|
||||
**Ön Boyut-Sonek Sisteminden:**
|
||||
Eski koleksiyonlar: `d_{user}_{collection}` (boyut soneki yok)
|
||||
Yeni koleksiyonlar: `d_{user}_{collection}_{dim}` (boyut soneki ile)
|
||||
Otomatik geçiş yok - eski koleksiyonlar erişilebilir durumda kalır.
|
||||
Gerekirse, manuel bir geçiş betiği düşünülmelidir.
|
||||
Her iki adlandırma şeması de aynı anda kullanılabilir.
|
||||
|
||||
## Referanslar
|
||||
|
||||
Koleksiyon Yönetimi: `docs/tech-specs/collection-management.md`
|
||||
Depolama Şeması: `trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
Kütüphaneci Hizmeti: `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
299
docs/tech-specs/vector-store-lifecycle.zh-cn.md
Normal file
299
docs/tech-specs/vector-store-lifecycle.zh-cn.md
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# 向量存储生命周期管理
|
||||
|
||||
## 概述
|
||||
|
||||
本文档描述了 TrustGraph 如何管理跨不同后端实现(Qdrant、Pinecone、Milvus)的向量存储集合。该设计解决了在不硬编码维度值的情况下,支持具有不同维度的嵌入向量的挑战。
|
||||
|
||||
## 问题陈述
|
||||
|
||||
向量存储在创建集合/索引时需要指定嵌入维度。但是:
|
||||
不同的嵌入模型会产生不同的维度(例如,384、768、1536)
|
||||
直到生成第一个嵌入向量,维度才已知
|
||||
单个 TrustGraph 集合可能会接收来自多个模型的嵌入向量
|
||||
强制指定一个维度(例如,384)会导致使用其他嵌入向量大小时出现故障
|
||||
|
||||
## 设计原则
|
||||
|
||||
1. **延迟创建**: 集合是在首次写入时按需创建的,而不是在集合管理操作期间创建的。
|
||||
2. **基于维度的命名**: 集合名称包含嵌入维度作为后缀。
|
||||
3. **优雅降级**: 对不存在的集合执行的查询返回空结果,而不是错误。
|
||||
4. **多维度支持**: 单个逻辑集合可以有多个物理集合(每个维度一个)。
|
||||
|
||||
## 架构
|
||||
|
||||
### 集合命名约定
|
||||
|
||||
向量存储集合使用维度后缀来支持多种嵌入向量大小:
|
||||
|
||||
**文档嵌入:**
|
||||
Qdrant: `d_{user}_{collection}_{dimension}`
|
||||
Pinecone: `d-{user}-{collection}-{dimension}`
|
||||
Milvus: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**图嵌入:**
|
||||
Qdrant: `t_{user}_{collection}_{dimension}`
|
||||
Pinecone: `t-{user}-{collection}-{dimension}`
|
||||
Milvus: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
示例:
|
||||
`d_alice_papers_384` - Alice 的论文集合,使用 384 维的嵌入向量
|
||||
`d_alice_papers_768` - 相同的逻辑集合,使用 768 维的嵌入向量
|
||||
`t_bob_knowledge_1536` - Bob 的知识图谱,使用 1536 维的嵌入向量
|
||||
|
||||
### 生命周期阶段
|
||||
|
||||
#### 1. 集合创建请求
|
||||
|
||||
**请求流程:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**行为:**
|
||||
库管理员将 `create-collection` 请求广播到所有存储后端。
|
||||
向量存储处理器确认该请求,但**不创建物理集合**。
|
||||
立即返回成功响应。
|
||||
实际集合的创建将在第一次写入时延迟。
|
||||
|
||||
**理由:**
|
||||
在创建时,维度是未知的。
|
||||
避免创建具有错误维度的集合。
|
||||
简化集合管理逻辑。
|
||||
|
||||
#### 2. 写入操作(延迟创建)
|
||||
|
||||
**写入流程:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**行为:**
|
||||
1. 从向量中提取嵌入维度:`dim = len(vector)`
|
||||
2. 使用维度后缀构建集合名称
|
||||
3. 检查是否存在具有该特定维度的集合
|
||||
4. 如果不存在:
|
||||
创建具有正确维度的集合
|
||||
记录:`"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. 将嵌入信息插入到特定维度的集合中
|
||||
|
||||
**示例场景:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. 查询操作
|
||||
|
||||
**查询流程:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**行为:**
|
||||
1. 从查询向量中提取维度:`dim = len(vector)`
|
||||
2. 使用维度后缀构建集合名称
|
||||
3. 检查集合是否存在
|
||||
4. 如果存在:
|
||||
执行相似度搜索
|
||||
返回结果
|
||||
5. 如果不存在:
|
||||
记录日志:`"Collection {name} does not exist, returning empty results"`
|
||||
返回空列表(不引发错误)
|
||||
|
||||
**同一查询中的多个维度:**
|
||||
如果查询包含不同维度的向量
|
||||
每个维度查询其对应的集合
|
||||
结果进行聚合
|
||||
缺失的集合将被跳过(不被视为错误)
|
||||
|
||||
**原理:**
|
||||
查询空集合是一种有效的用例
|
||||
返回空结果在语义上是正确的
|
||||
避免在系统启动或在数据摄取之前发生的错误
|
||||
|
||||
#### 4. 集合删除
|
||||
|
||||
**删除流程:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**行为:**
|
||||
1. 构造前缀模式:`d_{user}_{collection}_` (注意尾随的下划线)
|
||||
2. 列出向量存储中的所有集合
|
||||
3. 过滤与前缀匹配的集合
|
||||
4. 删除所有匹配的集合
|
||||
5. 记录每个删除操作:`"Deleted collection {name}"`
|
||||
6. 汇总日志:`"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**示例:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**原理:**
|
||||
确保彻底清理所有维度变体。
|
||||
模式匹配可防止意外删除不相关的集合。
|
||||
从用户角度来看,这是一个原子操作(所有维度一起删除)。
|
||||
|
||||
## 行为特性
|
||||
|
||||
### 正常操作
|
||||
|
||||
**集合创建:**
|
||||
✓ 立即返回成功。
|
||||
✓ 不分配任何物理存储空间。
|
||||
✓ 快速操作(没有后端 I/O)。
|
||||
|
||||
**首次写入:**
|
||||
✓ 创建具有正确维度的集合。
|
||||
✓ 由于集合创建的开销,速度略慢。
|
||||
✓ 之后对同一维度的写入速度很快。
|
||||
|
||||
**在任何写入之前进行查询:**
|
||||
✓ 返回空结果。
|
||||
✓ 没有错误或异常。
|
||||
✓ 系统保持稳定。
|
||||
|
||||
**混合维度写入:**
|
||||
✓ 自动为每个维度创建单独的集合。
|
||||
✓ 每个维度都隔离在自己的集合中。
|
||||
✓ 没有维度冲突或模式错误。
|
||||
|
||||
**集合删除:**
|
||||
✓ 移除所有维度变体。
|
||||
✓ 彻底清理。
|
||||
✓ 没有孤立的集合。
|
||||
|
||||
### 边界情况
|
||||
|
||||
**多个嵌入模型:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**并发首次写入:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**维度迁移:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**空集合查询:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## 实现说明
|
||||
|
||||
### 存储后端特定说明
|
||||
|
||||
**Qdrant:**
|
||||
使用 `collection_exists()` 进行存在性检查
|
||||
使用 `get_collections()` 在删除期间进行列表操作
|
||||
集合创建需要 `VectorParams(size=dim, distance=Distance.COSINE)`
|
||||
|
||||
**Pinecone:**
|
||||
使用 `has_index()` 进行存在性检查
|
||||
使用 `list_indexes()` 在删除期间进行列表操作
|
||||
索引创建需要等待 "ready" 状态
|
||||
Serverless 规格配置为云/区域
|
||||
|
||||
**Milvus:**
|
||||
直接类 (`DocVectors`, `EntityVectors`) 管理生命周期
|
||||
内部缓存 `self.collections[(dim, user, collection)]` 用于提高性能
|
||||
集合名称经过清理(仅限字母数字 + 下划线)
|
||||
支持具有自动递增 ID 的模式
|
||||
|
||||
### 性能考虑
|
||||
|
||||
**首次写入延迟:**
|
||||
由于集合创建而产生的额外开销
|
||||
Qdrant: ~100-500 毫秒
|
||||
Pinecone: ~10-30 秒 (serverless 预配置)
|
||||
Milvus: ~500-2000 毫秒 (包括索引)
|
||||
|
||||
**查询性能:**
|
||||
存在性检查会增加最小的开销 (~1-10 毫秒)
|
||||
集合存在后,不会对性能产生影响
|
||||
每个维度集合都独立优化
|
||||
|
||||
**存储开销:**
|
||||
每个集合的元数据非常少
|
||||
主要开销是每个维度的存储
|
||||
权衡:存储空间与维度灵活性
|
||||
|
||||
## 未来考虑
|
||||
|
||||
**自动维度合并:**
|
||||
可以添加后台进程来识别和合并未使用的维度变体
|
||||
这将需要重新嵌入或降维
|
||||
|
||||
**维度发现:**
|
||||
可以公开 API 来列出集合中使用的所有维度
|
||||
对于管理和监控非常有用
|
||||
|
||||
**默认维度偏好:**
|
||||
可以跟踪每个集合的 "主" 维度
|
||||
用于在维度上下文不可用的情况下进行查询
|
||||
|
||||
**存储配额:**
|
||||
可能需要每个集合的维度限制
|
||||
防止维度变体的过度繁殖
|
||||
|
||||
## 迁移说明
|
||||
|
||||
**从预维度后缀系统:**
|
||||
旧集合:`d_{user}_{collection}` (没有维度后缀)
|
||||
新集合:`d_{user}_{collection}_{dim}` (带有维度后缀)
|
||||
没有自动迁移 - 旧集合仍然可以访问
|
||||
如果需要,请考虑手动迁移脚本
|
||||
可以同时运行这两种命名方案
|
||||
|
||||
## 引用
|
||||
|
||||
集合管理:`docs/tech-specs/collection-management.md`
|
||||
存储模式:`trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
Librarian 服务:`trustgraph-flow/trustgraph/librarian/service.py`
|
||||
Loading…
Add table
Add a link
Reference in a new issue