mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-25 08:26:21 +02:00
Feat: TrustGraph i18n & Documentation Translation Updates (#781)
Native CLI i18n: The TrustGraph CLI has built-in translation support that dynamically loads language strings. You can test and use different languages by simply passing the --lang flag (e.g., --lang es for Spanish, --lang ru for Russian) or by configuring your environment's LANG variable. Automated Docs Translations: This PR introduces autonomously translated Markdown documentation into several target languages, including Spanish, Swahili, Portuguese, Turkish, Hindi, Hebrew, Arabic, Simplified Chinese, and Russian.
This commit is contained in:
parent
19f73e4cdc
commit
f95fd4f052
560 changed files with 236300 additions and 99 deletions
675
docs/tech-specs/embeddings-batch-processing.pt.md
Normal file
675
docs/tech-specs/embeddings-batch-processing.pt.md
Normal file
|
|
@ -0,0 +1,675 @@
|
|||
---
|
||||
layout: default
|
||||
title: "Especificação Técnica de Processamento em Lote de Embeddings"
|
||||
parent: "Portuguese (Beta)"
|
||||
---
|
||||
|
||||
# Especificação Técnica de Processamento em Lote de Embeddings
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## Visão Geral
|
||||
|
||||
Esta especificação descreve otimizações para o serviço de embeddings para suportar o processamento em lote de vários textos em um único pedido. A implementação atual processa um texto por vez, perdendo os benefícios de desempenho significativos que os modelos de embedding oferecem ao processar lotes.
|
||||
|
||||
1. **Ineficiência no Processamento de Texto Único**: A implementação atual envolve textos únicos em uma lista, subutilizando as capacidades de lote do FastEmbed.
|
||||
2. **Sobrecarga de Pedido por Texto**: Cada texto requer uma viagem de ida e volta separada do Pulsar.
|
||||
3. **Ineficiência na Inferência do Modelo**: Os modelos de embedding têm uma sobrecarga fixa por lote; lotes pequenos desperdiçam recursos de GPU/CPU.
|
||||
4. **Processamento Serial nos Clientes**: Serviços importantes fazem loop sobre itens e chamam embeddings um de cada vez.
|
||||
|
||||
## Objetivos
|
||||
|
||||
**Suporte para API de Lote**: Permitir o processamento de vários textos em um único pedido.
|
||||
**Compatibilidade com Versões Anteriores**: Manter o suporte para pedidos de texto único.
|
||||
**Melhora Significativa no Desempenho**: Almejar uma melhora de desempenho de 5 a 10 vezes para operações em lote.
|
||||
**Latência Reduzida por Texto**: Diminuir a latência amortizada ao incorporar vários textos.
|
||||
**Eficiência de Memória**: Processar lotes sem consumo excessivo de memória.
|
||||
**Independente do Provedor**: Suportar o processamento em lote em FastEmbed, Ollama e outros provedores.
|
||||
**Migração do Cliente**: Atualizar todos os clientes de embedding para usar a API de lote sempre que for benéfico.
|
||||
|
||||
## Contexto
|
||||
|
||||
### Implementação Atual - Serviço de Embeddings
|
||||
|
||||
A implementação de embeddings em `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` apresenta uma ineficiência de desempenho significativa:
|
||||
|
||||
```python
|
||||
# fastembed/processor.py line 56
|
||||
async def on_embeddings(self, text, model=None):
|
||||
use_model = model or self.default_model
|
||||
self._load_model(use_model)
|
||||
|
||||
vecs = self.embeddings.embed([text]) # Single text wrapped in list
|
||||
|
||||
return [v.tolist() for v in vecs]
|
||||
```
|
||||
|
||||
**Problemas:**
|
||||
|
||||
1. **Tamanho do Lote 1**: O método `embed()` do FastEmbed é otimizado para processamento em lote, mas sempre o chamamos com `[text]` - um lote de tamanho 1.
|
||||
|
||||
2. **Sobrecarga por Requisição**: Cada solicitação de incorporação incorre em:
|
||||
Serialização/desserialização de mensagens Pulsar
|
||||
Latência de ida e volta da rede
|
||||
Sobrecarga de inicialização da inferência do modelo
|
||||
Sobrecarga de agendamento assíncrono do Python
|
||||
|
||||
3. **Limitação do Esquema**: O esquema `EmbeddingsRequest` suporta apenas um único texto:
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsRequest:
|
||||
text: str = "" # Single text only
|
||||
```
|
||||
|
||||
### Clientes Atuais - Processamento Serial
|
||||
|
||||
#### 1. Gateway de API
|
||||
|
||||
**Arquivo:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py`
|
||||
|
||||
O gateway aceita solicitações de incorporação de texto único via HTTP/WebSocket e as encaminha para o serviço de incorporação. Atualmente, não existe um endpoint para processamento em lote.
|
||||
|
||||
```python
|
||||
class EmbeddingsRequestor(ServiceRequestor):
|
||||
# Handles single EmbeddingsRequest -> EmbeddingsResponse
|
||||
request_schema=EmbeddingsRequest, # Single text only
|
||||
response_schema=EmbeddingsResponse,
|
||||
```
|
||||
|
||||
**Impacto:** Clientes externos (aplicativos web, scripts) devem fazer N requisições HTTP para incorporar N textos.
|
||||
|
||||
#### 2. Serviço de Incorporação de Documentos
|
||||
|
||||
**Arquivo:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py`
|
||||
|
||||
Processa blocos de documentos um de cada vez:
|
||||
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
v = msg.value()
|
||||
|
||||
# Single chunk per request
|
||||
resp = await flow("embeddings-request").request(
|
||||
EmbeddingsRequest(text=v.chunk)
|
||||
)
|
||||
vectors = resp.vectors
|
||||
```
|
||||
|
||||
**Impacto:** Cada trecho de documento requer uma chamada de embedding separada. Um documento com 100 trechos = 100 requisições de embedding.
|
||||
|
||||
#### 3. Serviço de Embeddings de Grafos
|
||||
|
||||
**Arquivo:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py`
|
||||
|
||||
Percorre as entidades e incorpora cada uma sequencialmente:
|
||||
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
for entity in v.entities:
|
||||
# Serial embedding - one entity at a time
|
||||
vectors = await flow("embeddings-request").embed(
|
||||
text=entity.context
|
||||
)
|
||||
entities.append(EntityEmbeddings(
|
||||
entity=entity.entity,
|
||||
vectors=vectors,
|
||||
chunk_id=entity.chunk_id,
|
||||
))
|
||||
```
|
||||
|
||||
**Impacto:** Uma mensagem com 50 entidades = 50 solicitações de incorporação serial. Isso é um grande gargalo durante a construção do grafo de conhecimento.
|
||||
|
||||
#### 4. Serviço de Incorporação de Linhas
|
||||
|
||||
**Arquivo:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py`
|
||||
|
||||
Percorre textos únicos e incorpora cada um serialmente:
|
||||
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
for text, (index_name, index_value) in texts_to_embed.items():
|
||||
# Serial embedding - one text at a time
|
||||
vectors = await flow("embeddings-request").embed(text=text)
|
||||
|
||||
embeddings_list.append(RowIndexEmbedding(
|
||||
index_name=index_name,
|
||||
index_value=index_value,
|
||||
text=text,
|
||||
vectors=vectors
|
||||
))
|
||||
```
|
||||
|
||||
**Impacto:** Processar uma tabela com 100 valores indexados únicos = 100 solicitações de incorporação seriais.
|
||||
|
||||
#### 5. EmbeddingsClient (Cliente Base)
|
||||
|
||||
**Arquivo:** `trustgraph-base/trustgraph/base/embeddings_client.py`
|
||||
|
||||
O cliente usado por todos os processadores de fluxo suporta apenas a incorporação de texto único:
|
||||
|
||||
```python
|
||||
class EmbeddingsClient(RequestResponse):
|
||||
async def embed(self, text, timeout=30):
|
||||
resp = await self.request(
|
||||
EmbeddingsRequest(text=text), # Single text
|
||||
timeout=timeout
|
||||
)
|
||||
return resp.vectors
|
||||
```
|
||||
|
||||
**Impacto:** Todos os clientes que utilizam este componente estão limitados a operações de texto único.
|
||||
|
||||
#### 6. Ferramentas de Linha de Comando
|
||||
|
||||
**Arquivo:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py`
|
||||
|
||||
A ferramenta de linha de comando aceita um único argumento de texto:
|
||||
|
||||
```python
|
||||
def query(url, flow_id, text, token=None):
|
||||
result = flow.embeddings(text=text) # Single text
|
||||
vectors = result.get("vectors", [])
|
||||
```
|
||||
|
||||
**Impacto:** Os usuários não podem realizar incorporações em lote a partir da linha de comando. O processamento de um arquivo de textos requer N invocações.
|
||||
|
||||
#### 7. SDK Python
|
||||
|
||||
O SDK Python fornece duas classes de cliente para interagir com os serviços da TrustGraph. Ambas suportam apenas a incorporação de um único texto.
|
||||
|
||||
**Arquivo:** `trustgraph-base/trustgraph/api/flow.py`
|
||||
|
||||
```python
|
||||
class FlowInstance:
|
||||
def embeddings(self, text):
|
||||
"""Get embeddings for a single text"""
|
||||
input = {"text": text}
|
||||
return self.request("service/embeddings", input)["vectors"]
|
||||
```
|
||||
|
||||
**Arquivo:** `trustgraph-base/trustgraph/api/socket_client.py`
|
||||
|
||||
```python
|
||||
class SocketFlowInstance:
|
||||
def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]:
|
||||
"""Get embeddings for a single text via WebSocket"""
|
||||
request = {"text": text}
|
||||
return self.client._send_request_sync(
|
||||
"embeddings", self.flow_id, request, False
|
||||
)
|
||||
```
|
||||
|
||||
**Impacto:** Desenvolvedores Python que usam o SDK precisam iterar sobre textos e fazer N chamadas de API separadas. Não existe suporte para processamento em lote de embeddings para usuários do SDK.
|
||||
|
||||
### Impacto no Desempenho
|
||||
|
||||
Para ingestão típica de documentos (1000 trechos de texto):
|
||||
**Atual:** 1000 requisições separadas, 1000 chamadas de inferência de modelo
|
||||
**Em lote (batch_size=32):** 32 requisições, 32 chamadas de inferência de modelo (redução de 96,8%)
|
||||
|
||||
Para embedding de grafos (mensagem com 50 entidades):
|
||||
**Atual:** 50 chamadas `await` sequenciais, ~5-10 segundos
|
||||
**Em lote:** 1-2 chamadas em lote, ~0,5-1 segundo (melhora de 5-10x)
|
||||
|
||||
Bibliotecas como FastEmbed e similares alcançam escalabilidade quase linear no throughput com o tamanho do lote, até os limites do hardware (tipicamente 32-128 textos por lote).
|
||||
|
||||
## Design Técnico
|
||||
|
||||
### Arquitetura
|
||||
|
||||
A otimização de processamento em lote de embeddings requer alterações nos seguintes componentes:
|
||||
|
||||
#### 1. **Aprimoramento do Esquema**
|
||||
Estender `EmbeddingsRequest` para suportar múltiplos textos
|
||||
Estender `EmbeddingsResponse` para retornar múltiplos conjuntos de vetores
|
||||
Manter a compatibilidade retroativa com requisições de texto único
|
||||
|
||||
Módulo: `trustgraph-base/trustgraph/schema/services/llm.py`
|
||||
|
||||
#### 2. **Aprimoramento do Serviço Base**
|
||||
Atualizar `EmbeddingsService` para lidar com requisições em lote
|
||||
Adicionar configuração do tamanho do lote
|
||||
Implementar tratamento de requisições com suporte a lote
|
||||
|
||||
Módulo: `trustgraph-base/trustgraph/base/embeddings_service.py`
|
||||
|
||||
#### 3. **Atualizações do Processador do Provedor**
|
||||
Atualizar o processador FastEmbed para passar o lote completo para `embed()`
|
||||
Atualizar o processador Ollama para lidar com lotes (se suportado)
|
||||
Adicionar processamento sequencial como fallback para provedores sem suporte a lote
|
||||
|
||||
Módulos:
|
||||
`trustgraph-flow/trustgraph/embeddings/fastembed/processor.py`
|
||||
`trustgraph-flow/trustgraph/embeddings/ollama/processor.py`
|
||||
|
||||
#### 4. **Aprimoramento do Cliente**
|
||||
Adicionar método de embedding em lote para `EmbeddingsClient`
|
||||
Suportar APIs de texto único e em lote
|
||||
Adicionar agrupamento automático para grandes entradas
|
||||
|
||||
Módulo: `trustgraph-base/trustgraph/base/embeddings_client.py`
|
||||
|
||||
#### 5. **Atualizações do Chamador - Processadores de Fluxo**
|
||||
Atualizar `graph_embeddings` para agrupar contextos de entidades
|
||||
Atualizar `row_embeddings` para agrupar textos de índice
|
||||
Atualizar `document_embeddings` se o agrupamento de mensagens for viável
|
||||
|
||||
Módulos:
|
||||
`trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py`
|
||||
`trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py`
|
||||
`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py`
|
||||
|
||||
#### 6. **Aprimoramento do Gateway de API**
|
||||
Adicionar endpoint de embedding em lote
|
||||
Suportar array de textos no corpo da requisição
|
||||
|
||||
Módulo: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py`
|
||||
|
||||
#### 7. **Aprimoramento da Ferramenta de Linha de Comando (CLI)**
|
||||
Adicionar suporte para múltiplos textos ou entrada de arquivo
|
||||
Adicionar parâmetro de tamanho do lote
|
||||
|
||||
Módulo: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py`
|
||||
|
||||
#### 8. **Aprimoramento do SDK Python**
|
||||
Adicionar método `embeddings_batch()` para `FlowInstance`
|
||||
Adicionar método `embeddings_batch()` para `SocketFlowInstance`
|
||||
Suportar APIs de texto único e em lote para usuários do SDK
|
||||
|
||||
Módulos:
|
||||
`trustgraph-base/trustgraph/api/flow.py`
|
||||
`trustgraph-base/trustgraph/api/socket_client.py`
|
||||
|
||||
### Modelos de Dados
|
||||
|
||||
#### EmbeddingsRequest
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsRequest:
|
||||
texts: list[str] = field(default_factory=list)
|
||||
```
|
||||
|
||||
Uso:
|
||||
Texto único: `EmbeddingsRequest(texts=["hello world"])`
|
||||
Lote: `EmbeddingsRequest(texts=["text1", "text2", "text3"])`
|
||||
|
||||
#### EmbeddingsResponse
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsResponse:
|
||||
error: Error | None = None
|
||||
vectors: list[list[list[float]]] = field(default_factory=list)
|
||||
```
|
||||
|
||||
Estrutura da resposta:
|
||||
`vectors[i]` contém o conjunto de vetores para `texts[i]`
|
||||
Cada conjunto de vetores é `list[list[float]]` (os modelos podem retornar vários vetores por texto)
|
||||
Exemplo: 3 textos → `vectors` tem 3 entradas, cada uma contendo os embeddings desse texto
|
||||
|
||||
### APIs
|
||||
|
||||
#### EmbeddingsClient
|
||||
|
||||
```python
|
||||
class EmbeddingsClient(RequestResponse):
|
||||
async def embed(
|
||||
self,
|
||||
texts: list[str],
|
||||
timeout: float = 300,
|
||||
) -> list[list[list[float]]]:
|
||||
"""
|
||||
Embed one or more texts in a single request.
|
||||
|
||||
Args:
|
||||
texts: List of texts to embed
|
||||
timeout: Timeout for the operation
|
||||
|
||||
Returns:
|
||||
List of vector sets, one per input text
|
||||
"""
|
||||
resp = await self.request(
|
||||
EmbeddingsRequest(texts=texts),
|
||||
timeout=timeout
|
||||
)
|
||||
if resp.error:
|
||||
raise RuntimeError(resp.error.message)
|
||||
return resp.vectors
|
||||
```
|
||||
|
||||
#### Endpoint de Incorporação do Gateway de API
|
||||
|
||||
Endpoint atualizado que suporta incorporação única ou em lote:
|
||||
|
||||
```
|
||||
POST /api/v1/embeddings
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"texts": ["text1", "text2", "text3"],
|
||||
"flow_id": "default"
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"vectors": [
|
||||
[[0.1, 0.2, ...]],
|
||||
[[0.3, 0.4, ...]],
|
||||
[[0.5, 0.6, ...]]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Detalhes de Implementação
|
||||
|
||||
#### Fase 1: Alterações no Esquema
|
||||
|
||||
**EmbeddingsRequest:**
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsRequest:
|
||||
texts: list[str] = field(default_factory=list)
|
||||
```
|
||||
|
||||
**EmbeddingsResponse:**
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsResponse:
|
||||
error: Error | None = None
|
||||
vectors: list[list[list[float]]] = field(default_factory=list)
|
||||
```
|
||||
|
||||
**Atualizado EmbeddingsService.on_request:**
|
||||
```python
|
||||
async def on_request(self, msg, consumer, flow):
|
||||
request = msg.value()
|
||||
id = msg.properties()["id"]
|
||||
model = flow("model")
|
||||
|
||||
vectors = await self.on_embeddings(request.texts, model=model)
|
||||
response = EmbeddingsResponse(error=None, vectors=vectors)
|
||||
|
||||
await flow("response").send(response, properties={"id": id})
|
||||
```
|
||||
|
||||
#### Fase 2: Atualização do Processador FastEmbed
|
||||
|
||||
**Atual (Ineficiente):**
|
||||
```python
|
||||
async def on_embeddings(self, text, model=None):
|
||||
use_model = model or self.default_model
|
||||
self._load_model(use_model)
|
||||
vecs = self.embeddings.embed([text]) # Batch of 1
|
||||
return [v.tolist() for v in vecs]
|
||||
```
|
||||
|
||||
**Atualizado:**
|
||||
```python
|
||||
async def on_embeddings(self, texts: list[str], model=None):
|
||||
"""Embed texts - processes all texts in single model call"""
|
||||
if not texts:
|
||||
return []
|
||||
|
||||
use_model = model or self.default_model
|
||||
self._load_model(use_model)
|
||||
|
||||
# FastEmbed handles the full batch efficiently
|
||||
all_vecs = list(self.embeddings.embed(texts))
|
||||
|
||||
# Return list of vector sets, one per input text
|
||||
return [[v.tolist()] for v in all_vecs]
|
||||
```
|
||||
|
||||
#### Fase 3: Atualização do Serviço de Incorporação de Grafos
|
||||
|
||||
**Atual (Serial):**
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
entities = []
|
||||
for entity in v.entities:
|
||||
vectors = await flow("embeddings-request").embed(text=entity.context)
|
||||
entities.append(EntityEmbeddings(...))
|
||||
```
|
||||
|
||||
**Atualizado (Lote):**
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
# Collect all contexts
|
||||
contexts = [entity.context for entity in v.entities]
|
||||
|
||||
# Single batch embedding call
|
||||
all_vectors = await flow("embeddings-request").embed(texts=contexts)
|
||||
|
||||
# Pair results with entities
|
||||
entities = [
|
||||
EntityEmbeddings(
|
||||
entity=entity.entity,
|
||||
vectors=vectors[0], # First vector from the set
|
||||
chunk_id=entity.chunk_id,
|
||||
)
|
||||
for entity, vectors in zip(v.entities, all_vectors)
|
||||
]
|
||||
```
|
||||
|
||||
#### Fase 4: Atualização do Serviço de Incorporação de Dados
|
||||
|
||||
**Atual (Serial):**
|
||||
```python
|
||||
for text, (index_name, index_value) in texts_to_embed.items():
|
||||
vectors = await flow("embeddings-request").embed(text=text)
|
||||
embeddings_list.append(RowIndexEmbedding(...))
|
||||
```
|
||||
|
||||
**Atualizado (Lote):**
|
||||
```python
|
||||
# Collect texts and metadata
|
||||
texts = list(texts_to_embed.keys())
|
||||
metadata = list(texts_to_embed.values())
|
||||
|
||||
# Single batch embedding call
|
||||
all_vectors = await flow("embeddings-request").embed(texts=texts)
|
||||
|
||||
# Pair results
|
||||
embeddings_list = [
|
||||
RowIndexEmbedding(
|
||||
index_name=meta[0],
|
||||
index_value=meta[1],
|
||||
text=text,
|
||||
vectors=vectors[0] # First vector from the set
|
||||
)
|
||||
for text, meta, vectors in zip(texts, metadata, all_vectors)
|
||||
]
|
||||
```
|
||||
|
||||
#### Fase 5: Melhoria da Ferramenta de Linha de Comando (CLI)
|
||||
|
||||
**CLI Atualizado:**
|
||||
```python
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(...)
|
||||
|
||||
parser.add_argument(
|
||||
'text',
|
||||
nargs='*', # Zero or more texts
|
||||
help='Text(s) to convert to embedding vectors',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-f', '--file',
|
||||
help='File containing texts (one per line)',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--batch-size',
|
||||
type=int,
|
||||
default=32,
|
||||
help='Batch size for processing (default: 32)',
|
||||
)
|
||||
```
|
||||
|
||||
Uso:
|
||||
```bash
|
||||
# Single text (existing)
|
||||
tg-invoke-embeddings "hello world"
|
||||
|
||||
# Multiple texts
|
||||
tg-invoke-embeddings "text one" "text two" "text three"
|
||||
|
||||
# From file
|
||||
tg-invoke-embeddings -f texts.txt --batch-size 64
|
||||
```
|
||||
|
||||
#### Fase 6: Melhoria do SDK Python
|
||||
|
||||
**FlowInstance (cliente HTTP):**
|
||||
|
||||
```python
|
||||
class FlowInstance:
|
||||
def embeddings(self, texts: list[str]) -> list[list[list[float]]]:
|
||||
"""
|
||||
Get embeddings for one or more texts.
|
||||
|
||||
Args:
|
||||
texts: List of texts to embed
|
||||
|
||||
Returns:
|
||||
List of vector sets, one per input text
|
||||
"""
|
||||
input = {"texts": texts}
|
||||
return self.request("service/embeddings", input)["vectors"]
|
||||
```
|
||||
|
||||
**SocketFlowInstance (cliente WebSocket):**
|
||||
|
||||
```python
|
||||
class SocketFlowInstance:
|
||||
def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]:
|
||||
"""
|
||||
Get embeddings for one or more texts via WebSocket.
|
||||
|
||||
Args:
|
||||
texts: List of texts to embed
|
||||
|
||||
Returns:
|
||||
List of vector sets, one per input text
|
||||
"""
|
||||
request = {"texts": texts}
|
||||
response = self.client._send_request_sync(
|
||||
"embeddings", self.flow_id, request, False
|
||||
)
|
||||
return response["vectors"]
|
||||
```
|
||||
|
||||
**Exemplos de uso do SDK:**
|
||||
|
||||
```python
|
||||
# Single text
|
||||
vectors = flow.embeddings(["hello world"])
|
||||
print(f"Dimensions: {len(vectors[0][0])}")
|
||||
|
||||
# Batch embedding
|
||||
texts = ["text one", "text two", "text three"]
|
||||
all_vectors = flow.embeddings(texts)
|
||||
|
||||
# Process results
|
||||
for text, vecs in zip(texts, all_vectors):
|
||||
print(f"{text}: {len(vecs[0])} dimensions")
|
||||
```
|
||||
|
||||
## Considerações de Segurança
|
||||
|
||||
**Limites de Tamanho da Requisição**: Impor o tamanho máximo do lote para evitar o esgotamento de recursos.
|
||||
**Tratamento de Tempo Limite (Timeout)**: Ajustar os tempos limite de acordo com o tamanho do lote.
|
||||
**Limites de Memória**: Monitorar o uso de memória para grandes lotes.
|
||||
**Validação de Entrada**: Validar todos os textos no lote antes do processamento.
|
||||
|
||||
## Considerações de Desempenho
|
||||
|
||||
### Melhorias Esperadas
|
||||
|
||||
**Taxa de Transferência (Throughput):**
|
||||
Texto único: ~10-50 textos/segundo (dependendo do modelo)
|
||||
Lote (tamanho 32): ~200-500 textos/segundo (melhora de 5 a 10 vezes)
|
||||
|
||||
**Latência por Texto:**
|
||||
Texto único: 50-200ms por texto
|
||||
Lote (tamanho 32): 5-20ms por texto (média)
|
||||
|
||||
**Melhorias Específicas do Serviço:**
|
||||
|
||||
| Serviço | Atual | Em Lote | Melhoria |
|
||||
|---------|---------|---------|-------------|
|
||||
| Incorporações de Grafos (50 entidades) | 5-10s | 0,5-1s | 5-10x |
|
||||
| Incorporações de Linhas (100 textos) | 10-20s | 1-2s | 5-10x |
|
||||
| Ingestão de Documentos (1000 fragmentos) | 100-200s | 10-30s | 5-10x |
|
||||
|
||||
### Parâmetros de Configuração
|
||||
|
||||
```python
|
||||
# Recommended defaults
|
||||
DEFAULT_BATCH_SIZE = 32
|
||||
MAX_BATCH_SIZE = 128
|
||||
BATCH_TIMEOUT_MULTIPLIER = 2.0
|
||||
```
|
||||
|
||||
## Estratégia de Testes
|
||||
|
||||
### Testes Unitários
|
||||
Incorporação de texto única (compatibilidade com versões anteriores)
|
||||
Tratamento de lotes vazios
|
||||
Imposição do tamanho máximo do lote
|
||||
Tratamento de erros para falhas parciais do lote
|
||||
|
||||
### Testes de Integração
|
||||
Incorporação de lote de ponta a ponta através do Pulsar
|
||||
Processamento de lote do serviço de incorporação de grafos
|
||||
Processamento de lote do serviço de incorporação de linhas
|
||||
Endpoint de lote do gateway de API
|
||||
|
||||
### Testes de Desempenho
|
||||
Comparação de benchmark de taxa de transferência única versus lote
|
||||
Uso de memória sob vários tamanhos de lote
|
||||
Análise da distribuição de latência
|
||||
|
||||
## Plano de Migração
|
||||
|
||||
Esta é uma versão que introduz alterações significativas. Todas as fases são implementadas juntas.
|
||||
|
||||
### Fase 1: Alterações no Esquema
|
||||
Substituir `text: str` por `texts: list[str]` em EmbeddingsRequest
|
||||
Alterar o tipo de `vectors` para `list[list[list[float]]]` em EmbeddingsResponse
|
||||
|
||||
### Fase 2: Atualizações do Processador
|
||||
Atualizar a assinatura de `on_embeddings` nos processadores FastEmbed e Ollama
|
||||
Processar o lote completo em uma única chamada de modelo
|
||||
|
||||
### Fase 3: Atualizações do Cliente
|
||||
Atualizar `EmbeddingsClient.embed()` para aceitar `texts: list[str]`
|
||||
|
||||
### Fase 4: Atualizações do Chamador
|
||||
Atualizar graph_embeddings para incorporar contextos de entidades em lote
|
||||
Atualizar row_embeddings para incorporar textos de índice em lote
|
||||
Atualizar document_embeddings para usar o novo esquema
|
||||
Atualizar a ferramenta de linha de comando (CLI)
|
||||
|
||||
### Fase 5: Gateway de API
|
||||
Atualizar o endpoint de incorporação para o novo esquema
|
||||
|
||||
### Fase 6: SDK Python
|
||||
Atualizar a assinatura de `FlowInstance.embeddings()`
|
||||
Atualizar a assinatura de `SocketFlowInstance.embeddings()`
|
||||
|
||||
## Perguntas Abertas
|
||||
|
||||
**Incorporação de Lotes Grandes em Streaming**: Devemos suportar o streaming de resultados para lotes muito grandes (>100 textos)?
|
||||
**Limites Específicos do Provedor**: Como devemos lidar com provedores com tamanhos máximos de lote diferentes?
|
||||
**Tratamento de Falhas Parciais**: Se um texto em um lote falhar, devemos falhar o lote inteiro ou retornar resultados parciais?
|
||||
**Incorporação em Lote de Documentos**: Devemos incorporar em lote em várias mensagens de Chunk ou manter o processamento por mensagem?
|
||||
|
||||
## Referências
|
||||
|
||||
[Documentação do FastEmbed](https://github.com/qdrant/fastembed)
|
||||
[API de Incorporação do Ollama](https://github.com/ollama/ollama)
|
||||
[Implementação do Serviço de Incorporação](trustgraph-base/trustgraph/base/embeddings_service.py)
|
||||
[Otimização de Desempenho do GraphRAG](graphrag-performance-optimization.md)
|
||||
Loading…
Add table
Add a link
Reference in a new issue