From 835acaa70efffb486a746debd467576918a72bb8 Mon Sep 17 00:00:00 2001 From: "Jenkins, Kenneth Alexander" Date: Fri, 10 Apr 2026 12:22:20 -0400 Subject: [PATCH] add more docs Signed-off-by: Jenkins, Kenneth Alexander --- docs/README.api-docs.pt.md | 48 + docs/README.api-docs.tr.md | 48 + docs/README.pt.md | 21 + docs/README.sw.md | 21 + docs/README.tr.md | 21 + docs/api-gateway-changes-v1.8-to-v2.1.pt.md | 108 + docs/api-gateway-changes-v1.8-to-v2.1.tr.md | 108 + docs/cli-changes-v1.8-to-v2.1.pt.md | 112 + docs/cli-changes-v1.8-to-v2.1.tr.md | 112 + docs/contributor-licence-agreement.pt.md | 19 + docs/contributor-licence-agreement.tr.md | 19 + docs/python-api.es.md | 4071 +++++++++++++++++ docs/python-api.he.md | 4071 +++++++++++++++++ docs/python-api.hi.md | 4071 +++++++++++++++++ docs/python-api.pt.md | 4071 +++++++++++++++++ docs/python-api.sw.md | 4071 +++++++++++++++++ docs/python-api.tr.md | 4071 +++++++++++++++++ .../architecture-principles.zh-cn.md | 38 +- .../extraction-provenance-subgraph.ar.md | 205 + .../extraction-provenance-subgraph.he.md | 205 + .../extraction-provenance-subgraph.hi.md | 205 + .../extraction-provenance-subgraph.pt.md | 205 + .../extraction-provenance-subgraph.ru.md | 205 + .../extraction-provenance-subgraph.sw.md | 205 + .../extraction-provenance-subgraph.tr.md | 205 + .../extraction-provenance-subgraph.zh-cn.md | 205 + .../extraction-time-provenance.ar.md | 619 +++ .../extraction-time-provenance.es.md | 619 +++ .../extraction-time-provenance.he.md | 619 +++ .../extraction-time-provenance.hi.md | 619 +++ .../extraction-time-provenance.pt.md | 619 +++ .../extraction-time-provenance.ru.md | 619 +++ .../extraction-time-provenance.sw.md | 619 +++ .../extraction-time-provenance.tr.md | 619 +++ .../extraction-time-provenance.zh-cn.md | 619 +++ docs/tech-specs/flow-class-definition.ar.md | 277 ++ docs/tech-specs/flow-class-definition.es.md | 277 ++ docs/tech-specs/flow-class-definition.he.md | 277 ++ docs/tech-specs/flow-class-definition.hi.md | 277 ++ docs/tech-specs/flow-class-definition.pt.md | 277 ++ docs/tech-specs/flow-class-definition.ru.md | 277 ++ docs/tech-specs/flow-class-definition.sw.md | 277 ++ docs/tech-specs/flow-class-definition.tr.md | 277 ++ .../tech-specs/flow-class-definition.zh-cn.md | 277 ++ .../flow-configurable-parameters.ar.md | 485 ++ .../flow-configurable-parameters.es.md | 485 ++ .../flow-configurable-parameters.he.md | 485 ++ .../flow-configurable-parameters.hi.md | 485 ++ .../flow-configurable-parameters.pt.md | 485 ++ .../flow-configurable-parameters.ru.md | 485 ++ .../flow-configurable-parameters.sw.md | 485 ++ .../flow-configurable-parameters.tr.md | 485 ++ .../flow-configurable-parameters.zh-cn.md | 485 ++ docs/tech-specs/graph-contexts.pt.md | 573 +++ docs/tech-specs/graph-contexts.tr.md | 573 +++ docs/tech-specs/graphql-query.ar.md | 383 ++ docs/tech-specs/graphql-query.es.md | 383 ++ docs/tech-specs/graphql-query.he.md | 383 ++ docs/tech-specs/graphql-query.hi.md | 383 ++ docs/tech-specs/graphql-query.pt.md | 383 ++ docs/tech-specs/graphql-query.ru.md | 383 ++ docs/tech-specs/graphql-query.sw.md | 383 ++ docs/tech-specs/graphql-query.tr.md | 383 ++ docs/tech-specs/graphql-query.zh-cn.md | 383 ++ .../graphrag-performance-optimization.ar.md | 727 ++- .../graphrag-performance-optimization.he.md | 664 ++- .../graphrag-performance-optimization.hi.md | 637 ++- .../graphrag-performance-optimization.pt.md | 629 +++ .../graphrag-performance-optimization.ru.md | 661 ++- .../graphrag-performance-optimization.sw.md | 691 ++- .../graphrag-performance-optimization.tr.md | 629 +++ ...graphrag-performance-optimization.zh-cn.md | 645 ++- .../import-export-graceful-shutdown.ar.md | 682 +++ .../import-export-graceful-shutdown.es.md | 682 +++ .../import-export-graceful-shutdown.he.md | 682 +++ .../import-export-graceful-shutdown.hi.md | 682 +++ .../import-export-graceful-shutdown.pt.md | 682 +++ .../import-export-graceful-shutdown.ru.md | 682 +++ .../import-export-graceful-shutdown.sw.md | 682 +++ .../import-export-graceful-shutdown.tr.md | 682 +++ .../import-export-graceful-shutdown.zh-cn.md | 682 +++ docs/tech-specs/jsonl-prompt-output.ar.md | 465 +- docs/tech-specs/jsonl-prompt-output.es.md | 466 +- docs/tech-specs/jsonl-prompt-output.he.md | 458 +- docs/tech-specs/jsonl-prompt-output.hi.md | 469 +- docs/tech-specs/jsonl-prompt-output.pt.md | 455 ++ docs/tech-specs/jsonl-prompt-output.ru.md | 507 +- docs/tech-specs/jsonl-prompt-output.tr.md | 455 ++ docs/tech-specs/jsonl-prompt-output.zh-cn.md | 503 +- docs/tech-specs/large-document-loading.es.md | 984 ++++ docs/tech-specs/large-document-loading.pt.md | 984 ++++ docs/tech-specs/large-document-loading.sw.md | 984 ++++ translate_docs.py | 45 +- updates.md | 21 + 94 files changed, 60854 insertions(+), 1126 deletions(-) create mode 100644 docs/README.api-docs.pt.md create mode 100644 docs/README.api-docs.tr.md create mode 100644 docs/README.pt.md create mode 100644 docs/README.sw.md create mode 100644 docs/README.tr.md create mode 100644 docs/api-gateway-changes-v1.8-to-v2.1.pt.md create mode 100644 docs/api-gateway-changes-v1.8-to-v2.1.tr.md create mode 100644 docs/cli-changes-v1.8-to-v2.1.pt.md create mode 100644 docs/cli-changes-v1.8-to-v2.1.tr.md create mode 100644 docs/contributor-licence-agreement.pt.md create mode 100644 docs/contributor-licence-agreement.tr.md create mode 100644 docs/python-api.es.md create mode 100644 docs/python-api.he.md create mode 100644 docs/python-api.hi.md create mode 100644 docs/python-api.pt.md create mode 100644 docs/python-api.sw.md create mode 100644 docs/python-api.tr.md create mode 100644 docs/tech-specs/extraction-provenance-subgraph.ar.md create mode 100644 docs/tech-specs/extraction-provenance-subgraph.he.md create mode 100644 docs/tech-specs/extraction-provenance-subgraph.hi.md create mode 100644 docs/tech-specs/extraction-provenance-subgraph.pt.md create mode 100644 docs/tech-specs/extraction-provenance-subgraph.ru.md create mode 100644 docs/tech-specs/extraction-provenance-subgraph.sw.md create mode 100644 docs/tech-specs/extraction-provenance-subgraph.tr.md create mode 100644 docs/tech-specs/extraction-provenance-subgraph.zh-cn.md create mode 100644 docs/tech-specs/extraction-time-provenance.ar.md create mode 100644 docs/tech-specs/extraction-time-provenance.es.md create mode 100644 docs/tech-specs/extraction-time-provenance.he.md create mode 100644 docs/tech-specs/extraction-time-provenance.hi.md create mode 100644 docs/tech-specs/extraction-time-provenance.pt.md create mode 100644 docs/tech-specs/extraction-time-provenance.ru.md create mode 100644 docs/tech-specs/extraction-time-provenance.sw.md create mode 100644 docs/tech-specs/extraction-time-provenance.tr.md create mode 100644 docs/tech-specs/extraction-time-provenance.zh-cn.md create mode 100644 docs/tech-specs/flow-class-definition.ar.md create mode 100644 docs/tech-specs/flow-class-definition.es.md create mode 100644 docs/tech-specs/flow-class-definition.he.md create mode 100644 docs/tech-specs/flow-class-definition.hi.md create mode 100644 docs/tech-specs/flow-class-definition.pt.md create mode 100644 docs/tech-specs/flow-class-definition.ru.md create mode 100644 docs/tech-specs/flow-class-definition.sw.md create mode 100644 docs/tech-specs/flow-class-definition.tr.md create mode 100644 docs/tech-specs/flow-class-definition.zh-cn.md create mode 100644 docs/tech-specs/flow-configurable-parameters.ar.md create mode 100644 docs/tech-specs/flow-configurable-parameters.es.md create mode 100644 docs/tech-specs/flow-configurable-parameters.he.md create mode 100644 docs/tech-specs/flow-configurable-parameters.hi.md create mode 100644 docs/tech-specs/flow-configurable-parameters.pt.md create mode 100644 docs/tech-specs/flow-configurable-parameters.ru.md create mode 100644 docs/tech-specs/flow-configurable-parameters.sw.md create mode 100644 docs/tech-specs/flow-configurable-parameters.tr.md create mode 100644 docs/tech-specs/flow-configurable-parameters.zh-cn.md create mode 100644 docs/tech-specs/graph-contexts.pt.md create mode 100644 docs/tech-specs/graph-contexts.tr.md create mode 100644 docs/tech-specs/graphql-query.ar.md create mode 100644 docs/tech-specs/graphql-query.es.md create mode 100644 docs/tech-specs/graphql-query.he.md create mode 100644 docs/tech-specs/graphql-query.hi.md create mode 100644 docs/tech-specs/graphql-query.pt.md create mode 100644 docs/tech-specs/graphql-query.ru.md create mode 100644 docs/tech-specs/graphql-query.sw.md create mode 100644 docs/tech-specs/graphql-query.tr.md create mode 100644 docs/tech-specs/graphql-query.zh-cn.md create mode 100644 docs/tech-specs/graphrag-performance-optimization.pt.md create mode 100644 docs/tech-specs/graphrag-performance-optimization.tr.md create mode 100644 docs/tech-specs/import-export-graceful-shutdown.ar.md create mode 100644 docs/tech-specs/import-export-graceful-shutdown.es.md create mode 100644 docs/tech-specs/import-export-graceful-shutdown.he.md create mode 100644 docs/tech-specs/import-export-graceful-shutdown.hi.md create mode 100644 docs/tech-specs/import-export-graceful-shutdown.pt.md create mode 100644 docs/tech-specs/import-export-graceful-shutdown.ru.md create mode 100644 docs/tech-specs/import-export-graceful-shutdown.sw.md create mode 100644 docs/tech-specs/import-export-graceful-shutdown.tr.md create mode 100644 docs/tech-specs/import-export-graceful-shutdown.zh-cn.md create mode 100644 docs/tech-specs/jsonl-prompt-output.pt.md create mode 100644 docs/tech-specs/jsonl-prompt-output.tr.md create mode 100644 docs/tech-specs/large-document-loading.es.md create mode 100644 docs/tech-specs/large-document-loading.pt.md create mode 100644 docs/tech-specs/large-document-loading.sw.md create mode 100644 updates.md diff --git a/docs/README.api-docs.pt.md b/docs/README.api-docs.pt.md new file mode 100644 index 00000000..cffb4417 --- /dev/null +++ b/docs/README.api-docs.pt.md @@ -0,0 +1,48 @@ + +# Geração automática de documentação + +## Documentação da API REST e WebSocket + +`specs/build-docs.sh` - Constrói a documentação REST e WebSocket a partir das + especificações OpenAPI e AsyncAPI. + +## Documentação da API Python + +A documentação da API Python é gerada a partir de docstrings usando um script Python personalizado que inspeciona o pacote `trustgraph.api`. + +### Pré-requisitos + +O pacote trustgraph deve ser importável. Se você estiver trabalhando em um ambiente de desenvolvimento: + +```bash +cd trustgraph-base +pip install -e . +``` + +### Gerando Documentação + +A partir do diretório de documentação: + +```bash +cd docs +python3 generate-api-docs.py > python-api.md +``` + +Isso gera um único arquivo Markdown com documentação completa da API, mostrando: +Instruções de instalação e guia de início rápido +Declarações de importação para cada classe/tipo +Documentação completa com exemplos +Sumário organizado por categoria + +### Estilo da Documentação + +Todas as documentações seguem o formato do Google: +Resumo breve de uma linha +Descrição detalhada +Seção "Args" com descrições dos parâmetros +Seção "Returns" +Seção "Raises" (quando aplicável) +Blocos de código de exemplo com realce de sintaxe adequado + +A documentação gerada mostra a API pública exatamente como os usuários a importam de `trustgraph.api`, sem expor a estrutura interna do módulo. + diff --git a/docs/README.api-docs.tr.md b/docs/README.api-docs.tr.md new file mode 100644 index 00000000..e3be27e8 --- /dev/null +++ b/docs/README.api-docs.tr.md @@ -0,0 +1,48 @@ + +# Otomatik olarak dokümantasyon oluşturma + +## REST ve WebSocket API Dokümantasyonu + +`specs/build-docs.sh` - REST ve websocket dokümantasyonunu OpenAPI ve AsyncAPI özelliklerinden oluşturur. + +## Python API Dokümantasyonu + + +Python API dokümantasyonu, `trustgraph.api` paketini inceleyen özel bir Python betiği kullanılarak, dokümantasyon dizelerinden (docstrings) oluşturulur. + +### Ön Koşullar + +trustgraph paketi içe aktarılabilir olmalıdır. Geliştirme ortamında çalışıyorsanız: + +```bash +cd trustgraph-base +pip install -e . +``` + +### Belgeler Oluşturma + +"docs" dizininden: + +```bash +cd docs +python3 generate-api-docs.py > python-api.md +``` + +Bu, eksiksiz API dokümantasyonunu içeren tek bir Markdown dosyası oluşturur ve şunları gösterir: +Kurulum ve hızlı başlangıç kılavuzu +Her sınıf/tip için içe aktarma ifadeleri +Örneklerle birlikte tam dokümanlar +Kategoriye göre düzenlenmiş içindekiler tablosu + +### Dokümantasyon Stili + +Tüm dokümanlar, Google stili biçimini izler: +Kısa, tek satırlık özet +Ayrıntılı açıklama +Parametre açıklamalarıyla birlikte "Args" bölümü +"Returns" bölümü +"Raises" bölümü (uygulanabilir olduğunda) +Doğru sözdizimi vurgulamasıyla birlikte örnek kod blokları + +Oluşturulan dokümantasyon, kullanıcıların `trustgraph.api`'dan içe aktardığı şekilde, tam olarak kamu API'sini gösterir ve dahili modül yapısını ortaya çıkarmaz. + diff --git a/docs/README.pt.md b/docs/README.pt.md new file mode 100644 index 00000000..8e903c8d --- /dev/null +++ b/docs/README.pt.md @@ -0,0 +1,21 @@ +# Documentação do TrustGraph + +Bem-vindo ao TrustGraph! Para documentação completa, visite: + +## 📖 [https://docs.trustgraph.ai](https://docs.trustgraph.ai) + +O site de documentação principal inclui: + +**[Visão Geral](https://docs.trustgraph.ai/overview)** - Introdução aos conceitos e arquitetura do TrustGraph +**[Guias](https://docs.trustgraph.ai/guides)** - Tutoriais passo a passo e guias de como fazer +**[Implantação](https://docs.trustgraph.ai/deployment)** - Opções de implantação e configuração +**[Referência](https://docs.trustgraph.ai/reference)** - Especificações da API e documentação da CLI + +## Começando + +**Novo no TrustGraph?** Comece com a [Visão Geral](https://docs.trustgraph.ai/overview) para entender o sistema. + +**Pronto para implantar?** Consulte o [Guia de Implantação](https://docs.trustgraph.ai/deployment). + +**Integrando com código?** Consulte a [Referência da API](https://docs.trustgraph.ai/reference) para documentação REST, WebSocket e SDK. + diff --git a/docs/README.sw.md b/docs/README.sw.md new file mode 100644 index 00000000..4c22adee --- /dev/null +++ b/docs/README.sw.md @@ -0,0 +1,21 @@ +# Miongozo ya TrustGraph + +Karibu kwenye TrustGraph! Kwa miongozo kamili, tafadhali tembelea: + +## 📖 [https://docs.trustgraph.ai](https://docs.trustgraph.ai) + +Tovuti kuu ya miongozo inajumuisha: + +**[Mawasilisho](https://docs.trustgraph.ai/overview)** - Utangulizi wa dhana na muundo wa TrustGraph +**[Mwongozo](https://docs.trustgraph.ai/guides)** - Mafunzo ya hatua kwa hatua na mwongozo wa jinsi ya +**[Ufungaji](https://docs.trustgraph.ai/deployment)** - Chaguo za ufungaji na usanidi +**[Marejeleo](https://docs.trustgraph.ai/reference)** - Vipimo vya API na miongozo ya CLI + +## Kuanza + +**Je, wewe ni mpya katika TrustGraph?** Anza na [Mawasilisho](https://docs.trustgraph.ai/overview) ili kuelewa mfumo. + +**Uko tayari kufunga?** Angalia [Mwongozo wa Ufungaji](https://docs.trustgraph.ai/deployment). + +**Je, unataka kuunganisha na programu?** Angalia [Marejeleo ya API](https://docs.trustgraph.ai/reference) kwa miongozo ya REST, WebSocket, na SDK. + diff --git a/docs/README.tr.md b/docs/README.tr.md new file mode 100644 index 00000000..7d4e4726 --- /dev/null +++ b/docs/README.tr.md @@ -0,0 +1,21 @@ +# TrustGraph Belgeleri + +TrustGraph'a hoş geldiniz! Kapsamlı belgeler için lütfen şu adresi ziyaret edin: + +## 📖 [https://docs.trustgraph.ai](https://docs.trustgraph.ai) + +Ana belge sitesi şunları içerir: + +**[Genel Bakış](https://docs.trustgraph.ai/overview)** - TrustGraph kavramlarına ve mimarisine giriş +**[Kılavuzlar](https://docs.trustgraph.ai/guides)** - Adım adım eğitimler ve nasıl yapılır kılavuzları +**[Dağıtım](https://docs.trustgraph.ai/deployment)** - Dağıtım seçenekleri ve yapılandırma +**[Referans](https://docs.trustgraph.ai/reference)** - API özellikleri ve CLI belgeleri + +## Başlangıç + +**TrustGraph'e yeni mi geldiniz?** Sistemi anlamak için [Genel Bakış](https://docs.trustgraph.ai/overview) bölümüne bakın. + +**Dağıtıma hazır mısınız?** [Dağıtım Kılavuzu](https://docs.trustgraph.ai/deployment) bölümüne göz atın. + +**Koduyla entegre mi olmak istiyorsunuz?** REST, WebSocket ve SDK belgeleri için [API Referansı](https://docs.trustgraph.ai/reference) bölümüne bakın. + diff --git a/docs/api-gateway-changes-v1.8-to-v2.1.pt.md b/docs/api-gateway-changes-v1.8-to-v2.1.pt.md new file mode 100644 index 00000000..3c2232c6 --- /dev/null +++ b/docs/api-gateway-changes-v1.8-to-v2.1.pt.md @@ -0,0 +1,108 @@ +# Alterações no API Gateway: da versão 1.8 para a versão 2.1 + +## Resumo + +O gateway de API ganhou novos distribuidores de serviços WebSocket para consultas de incorporações +e um novo endpoint REST para streaming de conteúdo de documentos, e passou por +uma mudança significativa no formato de comunicação, de `Value` para `Term`. O serviço "objects" +foi renomeado para "rows". + +-- + +## Novos Distribuidores de Serviços WebSocket + +Estes são novos serviços de solicitação/resposta disponíveis através do +multiplexador WebSocket em `/api/v1/socket` (com escopo de fluxo): + +| Chave do Serviço | Descrição | +|-------------|-------------| +| `document-embeddings` | Consulta de trechos de documentos por similaridade de texto. Solicitação/resposta usa os esquemas `DocumentEmbeddingsRequest`/`DocumentEmbeddingsResponse`. | +| `row-embeddings` | Consulta de linhas de dados estruturados por similaridade de texto em campos indexados. Solicitação/resposta usa os esquemas `RowEmbeddingsRequest`/`RowEmbeddingsResponse`. | + +Estes se juntam ao distribuidor existente `graph-embeddings` (que já +estava presente na versão 1.8, mas pode ter sido atualizado). + +### Lista completa de distribuidores de serviços de fluxo WebSocket (versão 2.1) + +Serviços de solicitação/resposta (via `/api/v1/flow/{flow}/service/{kind}` ou +multiplexador WebSocket): + +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `rows`, `nlp-query`, `structured-query`, `structured-diag` +`row-embeddings` + +-- + +## Novo Endpoint REST + +| Método | Caminho | Descrição | +|--------|------|-------------| +| `GET` | `/api/v1/document-stream` | Transmite o conteúdo do documento da biblioteca como bytes brutos. Parâmetros de consulta: `user` (obrigatório), `document-id` (obrigatório), `chunk-size` (opcional, padrão 1MB). Retorna o conteúdo do documento em codificação de transferência em blocos, decodificado de base64 internamente. | + +-- + +## Serviço Renomeado: "objects" para "rows" + +| v1.8 | v2.1 | Notas | +|------|------|-------| +| `objects_query.py` / `ObjectsQueryRequestor` | `rows_query.py` / `RowsQueryRequestor` | Esquema alterado de `ObjectsQueryRequest`/`ObjectsQueryResponse` para `RowsQueryRequest`/`RowsQueryResponse`. | +| `objects_import.py` / `ObjectsImport` | `rows_import.py` / `RowsImport` | Distribuidor de importação para dados estruturados. | + +A chave do serviço WebSocket foi alterada de `"objects"` para `"rows"`, e a +chave do distribuidor de importação foi alterada de `"objects"` para `"rows"`. + +-- + +## Mudança no Formato de Comunicação: Valor para Termo + +A camada de serialização (`serialize.py`) foi reescrita para usar o novo tipo `Term` +em vez do tipo antigo `Value`. + +### Formato antigo (v1.8 — `Value`) + +```json +{"v": "http://example.org/entity", "e": true} +``` + +`v`: o valor (string) +`e`: flag booleano que indica se o valor é um URI + +### Novo formato (v2.1 — `Term`) + +IRIs: +```json +{"t": "i", "i": "http://example.org/entity"} +``` + +Literais: +```json +{"t": "l", "v": "some text", "d": "datatype-uri", "l": "en"} +``` + +Triplas citadas (RDF-star): +```json +{"t": "r", "r": {"s": {...}, "p": {...}, "o": {...}}} +``` + +`t`: tipo de discriminador — `"i"` (IRI), `"l"` (literal), `"r"` (tripla entre aspas), `"b"` (nó vazio) +A serialização agora delega para `TermTranslator` e `TripleTranslator` a partir de `trustgraph.messaging.translators.primitives` + +### Outras alterações de serialização + +| Campo | v1.8 | v2.1 | +|-------|------|------| +| Metadados | `metadata.metadata` (subgrafo) | `metadata.root` (valor simples) | +| Incorporação de entidade | `entity.vectors` (plural) | `entity.vector` (singular) | +| Incorporação de fragmento de documento | `chunk.vectors` + `chunk.chunk` (texto) | `chunk.vector` + `chunk.chunk_id` (referência de ID) | + +-- + +## Alterações Incompatíveis + +**Formato de fio de `Value` para `Term`**: Todos os clientes que enviam ou recebem triplas, incorporações ou contextos de entidade através do gateway devem atualizar para o novo formato de Termo. +**Renomeação de `objects` para `rows`**: A chave do serviço WebSocket e a chave de importação foram alteradas. +**Alteração do campo de metadados**: `metadata.metadata` (um subgrafo serializado) foi substituído por `metadata.root` (um valor simples). +**Alterações nos campos de incorporação**: `vectors` (plural) se tornou `vector` (singular); as incorporações de documento agora fazem referência a `chunk_id` em vez de texto `chunk` inline. +**Novo endpoint `/api/v1/document-stream`**: Aditivo, não quebra a compatibilidade. diff --git a/docs/api-gateway-changes-v1.8-to-v2.1.tr.md b/docs/api-gateway-changes-v1.8-to-v2.1.tr.md new file mode 100644 index 00000000..5d0650d9 --- /dev/null +++ b/docs/api-gateway-changes-v1.8-to-v2.1.tr.md @@ -0,0 +1,108 @@ +# API Ağ Geçidi Değişiklikleri: v1.8'den v2.1'e + +## Özet + +API ağ geçidi, gömülü sorgular için yeni WebSocket hizmet yönlendiricileri, belge içeriği için yeni bir REST akış uç noktası kazandı ve ⟦CODE_0⟧'dan ⟦CODE_1⟧'e önemli bir veri formatı değişikliğine uğradı. "objects" hizmeti "rows" olarak yeniden adlandırıldı. +sorguları, belge içeriği için yeni bir REST akış uç noktası ve aşağıdaki değişiklikleri içerdi: +önemli bir tel format değişikliği, `Value`'dan `Term`'e geçiş. "Nesneler" + + +-- + +## Yeni WebSocket Hizmet Yönlendiricileri + +Bunlar, WebSocket üzerinden sunulan yeni istek/yanıt servisleridir. +`/api/v1/socket` adresindeki çoklayıcı (akış kapsamlı): + +| Servis Anahtarı | Açıklama | +|-------------|-------------| +| `document-embeddings` | Metin benzerliği ile belge parçalarını sorgular. İstek/yanıt, `DocumentEmbeddingsRequest`/`DocumentEmbeddingsResponse` şemalarını kullanır. | +| `row-embeddings` | İndekslenmiş alanlarda metin benzerliği ile yapılandırılmış veri satırlarını sorgular. İstek/yanıt, `RowEmbeddingsRequest`/`RowEmbeddingsResponse` şemalarını kullanır. | + +Bunlar, mevcut `graph-embeddings` dağıtım aracına (v1.8'de zaten +bulunan ancak güncellenmiş olabilecek) eklenir. + +### WebSocket akış hizmeti dağıtım araçlarının tam listesi (v2.1) + +İstek/yanıt hizmetleri (`/api/v1/flow/{flow}/service/{kind}` veya +WebSocket çoklayıcısı aracılığıyla): + +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `rows`, `nlp-query`, `structured-query`, `structured-diag` +`row-embeddings` + +-- + +## Yeni REST Uç Noktası + +| Yöntem | Yol | Açıklama | +|--------|------|-------------| +| `GET` | `/api/v1/document-stream` | Kütüphaneden belge içeriğini ham baytlar olarak aktarır. Sorgu parametreleri: `user` (gerekli), `document-id` (gerekli), `chunk-size` (isteğe bağlı, varsayılan 1MB). Belge içeriğini, dahili olarak base64'ten çözülmüş olarak, parçalı aktarım kodlamasıyla döndürür. | + +-- + +## Yeniden Adlandırılan Hizmet: "objects" -> "rows" + +| v1.8 | v2.1 | Notlar | +|------|------|-------| +| `objects_query.py` / `ObjectsQueryRequestor` | `rows_query.py` / `RowsQueryRequestor` | Şema, `ObjectsQueryRequest`/`ObjectsQueryResponse`'den `RowsQueryRequest`/`RowsQueryResponse`'ye dönüştürüldü. | +| `objects_import.py` / `ObjectsImport` | `rows_import.py` / `RowsImport` | Yapılandırılmış veri için import yöneticisi. | + +WebSocket hizmet anahtarı `"objects"`'dan `"rows"`'e değişti ve +import yöneticisi anahtarı da benzer şekilde `"objects"`'dan `"rows"`'e değişti. + +-- + +## Kablo Formatındaki Değişiklik: Değerden Terime + +Seri hale getirme katmanı (`serialize.py`), yeni `Term`'i kullanmak üzere yeniden yazıldı. +eski `Value` türünün yerine bu türü kullanın. + +### Eski format (v1.8 — `Value`) + +```json +{"v": "http://example.org/entity", "e": true} +``` + +`v`: değer (string) +`e`: değerin bir URI olup olmadığını gösteren boolean işaretleyici + +### Yeni format (v2.1 — `Term`) + +IRIs: +```json +{"t": "i", "i": "http://example.org/entity"} +``` + +Sabitler: +```json +{"t": "l", "v": "some text", "d": "datatype-uri", "l": "en"} +``` + +Tırnak içinde belirtilen üçlüler (RDF-star): +```json +{"t": "r", "r": {"s": {...}, "p": {...}, "o": {...}}} +``` + +`t`: tür belirleyici — `"i"` (IRI), `"l"` (literal), `"r"` (tırnak içinde belirtilmiş üçlü), `"b"` (boş düğüm) +Serileştirme artık `trustgraph.messaging.translators.primitives`'den `TermTranslator` ve `TripleTranslator`'e devrediliyor. + +### Diğer serileştirme değişiklikleri + +| Alan | v1.8 | v2.1 | +|-------|------|------| +| Meta veri | `metadata.metadata` (alt grafik) | `metadata.root` (basit değer) | +| Grafik gömme varlığı | `entity.vectors` (çoğul) | `entity.vector` (tekil) | +| Belge gömme parçası | `chunk.vectors` + `chunk.chunk` (metin) | `chunk.vector` + `chunk.chunk_id` (ID referansı) | + +-- + +## Uyumsuz Değişiklikler + +**`Value`'dan `Term`'e kablo formatı**: Ağ geçidi üzerinden üçlü, gömme veya varlık bağlamı gönderen/alan tüm istemcilerin, yeni Terim formatına güncellenmesi gerekir. +**`objects`'dan `rows`'e yeniden adlandırma**: WebSocket hizmet anahtarı ve içe aktarma anahtarı değiştirildi. +**Meta veri alanı değişikliği**: `metadata.metadata` (serileştirilmiş bir alt grafik), `metadata.root` (basit bir değer) ile değiştirildi. +**Gömme alanı değişiklikleri**: `vectors` (çoğul), `vector` (tekil) haline geldi; belge gömmeleri artık iç içe `chunk` metni yerine `chunk_id`'yi referans alıyor. +**Yeni `/api/v1/document-stream` uç noktası**: Uyumsuz değil, eklemeli. diff --git a/docs/cli-changes-v1.8-to-v2.1.pt.md b/docs/cli-changes-v1.8-to-v2.1.pt.md new file mode 100644 index 00000000..e4dac87c --- /dev/null +++ b/docs/cli-changes-v1.8-to-v2.1.pt.md @@ -0,0 +1,112 @@ +# Alterações na CLI: da v1.8 para v2.1 + +## Resumo + +A CLI (`trustgraph-cli`) possui adições significativas focadas em três temas: +**explicabilidade/proveniência**, **acesso a embeddings** e **consulta de grafos**. +Duas ferramentas legadas foram removidas, uma foi renomeada e várias ferramentas existentes +adquiriram novas funcionalidades. + +-- + +## Novas Ferramentas da CLI + +### Explicabilidade e Proveniência + +| Comando | Descrição | +|---------|-------------| +| `tg-list-explain-traces` | Lista todas as sessões de explicabilidade (GraphRAG e Agent) em uma coleção, mostrando IDs de sessão, tipo, texto da pergunta e carimbos de data/hora. | +| `tg-show-explain-trace` | Exibe o rastreamento completo de explicabilidade para uma sessão. Para GraphRAG: Estágios de Pergunta, Exploração, Foco, Síntese. Para Agent: Sessão, Iterações (pensamento/ação/observação), Resposta Final. Detecta automaticamente o tipo de rastreamento. Suporta `--show-provenance` para rastrear arestas de volta para documentos de origem. | +| `tg-show-extraction-provenance` | Dado um ID de documento, percorre a cadeia de proveniência: Documento -> Páginas -> Trechos -> Arestas, usando relacionamentos `prov:wasDerivedFrom`. Suporta opções `--show-content` e `--max-content`. | + +### Embeddings + +| Comando | Descrição | +|---------|-------------| +| `tg-invoke-embeddings` | Converte texto em um embedding vetorial por meio do serviço de embeddings. Aceita uma ou mais entradas de texto, retorna vetores como listas de floats. | +| `tg-invoke-graph-embeddings` | Consulta entidades de grafo por similaridade de texto usando embeddings vetoriais. Retorna entidades correspondentes com pontuações de similaridade. | +| `tg-invoke-document-embeddings` | Consulta trechos de documentos por similaridade de texto usando embeddings vetoriais. Retorna IDs de trechos correspondentes com pontuações de similaridade. | +| `tg-invoke-row-embeddings` | Consulta linhas de dados estruturados por similaridade de texto em campos indexados. Retorna linhas correspondentes com valores de índice e pontuações. Requer `--schema-name` e suporta `--index-name`. | + +### Consulta de Grafos + +| Comando | Descrição | +|---------|-------------| +| `tg-query-graph` | Consulta de grafo baseada em padrões. Diferentemente de `tg-show-graph` (que despeja tudo), isso permite consultas seletivas por qualquer combinação de sujeito, predicado, objeto e grafo. Detecta automaticamente os tipos de valor: IRIs (`http://...`, `urn:...`, `<...>`), triplas entre aspas (`<>`) e literais. | +| `tg-get-document-content` | Recupera o conteúdo do documento da biblioteca por ID do documento. Pode ser direcionado para um arquivo ou stdout, lida com conteúdo de texto e binário. | + +-- + +## Ferramentas da CLI Removidas + +| Comando | Notas | +|---------|-------| +| `tg-load-pdf` | Removido. O carregamento de documentos é agora tratado por meio do pipeline de biblioteca/processamento. | +| `tg-load-text` | Removido. O carregamento de documentos é agora tratado por meio do pipeline de biblioteca/processamento. | + +-- + +## Ferramentas da CLI Renomeadas + +| Nome Antigo | Novo Nome | Notas | +|----------|----------|-------| +| `tg-invoke-objects-query` | `tg-invoke-rows-query` | Reflete a alteração de terminologia de "objetos" para "linhas" para dados estruturados. | + +-- + +## Mudanças Significativas em Ferramentas Existentes + +### `tg-invoke-graph-rag` + +**Suporte para explicabilidade**: Agora suporta um pipeline de explicabilidade de 4 etapas (Pergunta, Fundamentação/Exploração, Foco, Síntese) com exibição inline de eventos de rastreabilidade. +**Streaming**: Utiliza streaming WebSocket para saída em tempo real. +**Rastreabilidade**: Pode rastrear arestas selecionadas de volta para documentos de origem por meio de reificação e cadeias `prov:wasDerivedFrom`. +Cresceu de ~30 linhas para ~760 linhas para acomodar o pipeline completo de explicabilidade. + +### `tg-invoke-document-rag` + +**Suporte para explicabilidade**: Adicionado modo `question_explainable()` que transmite respostas do Document RAG com eventos de rastreabilidade inline (etapas de Pergunta, Fundamentação, Exploração, Síntese). + +### `tg-invoke-agent` + +**Suporte para explicabilidade**: Adicionado modo `question_explainable()` que exibe eventos de rastreabilidade inline durante a execução do agente (etapas de Pergunta, Análise, Conclusão, AgentThought, AgentObservation, AgentAnswer). +O modo verboso exibe fluxos de pensamento/observação com prefixos de emoji. + +### `tg-show-graph` + +**Modo de streaming**: Agora usa `triples_query_stream()` com tamanhos de lote configuráveis para um tempo de primeiro resultado menor e menor sobrecarga de memória. +**Suporte para grafos nomeados**: Nova opção de filtro `--graph`. Reconhece grafos nomeados: + Grafo padrão (vazio): Fatos de conhecimento principais + `urn:graph:source`: Rastreabilidade de extração + `urn:graph:retrieval`: Explicabilidade no momento da consulta +**Mostrar coluna do grafo**: Nova flag `--show-graph` para exibir o grafo nomeado para cada tripla. +**Limites configuráveis**: Novas opções `--limit` e `--batch-size`. + +### `tg-graph-to-turtle` + +**Suporte para RDF-star**: Agora lida com triplas citadas (reificação RDF-star). +**Modo de streaming**: Utiliza streaming para um tempo de processamento inicial menor. +**Manipulação de formato de fio**: Atualizado para usar o novo formato de fio de termos (`{"t": "i", "i": uri}` para IRIs, `{"t": "l", "v": value}` para literais, `{"t": "r", "r": {...}}` para triplas citadas). +**Suporte para grafos nomeados**: Nova opção de filtro `--graph`. + +### `tg-set-tool` + +**Novo tipo de ferramenta**: `row-embeddings-query` para pesquisa semântica em índices de dados estruturados. +**Novas opções**: `--schema-name`, `--index-name`, `--limit` para configurar ferramentas de consulta de incorporações de linhas. + +### `tg-show-tools` + +Exibe o novo tipo de ferramenta `row-embeddings-query` com seus campos `schema-name`, `index-name` e `limit`. + +### `tg-load-knowledge` + +**Relatório de progresso**: Agora conta e relata triplas e contextos de entidade carregados por arquivo e no total. +**Atualização do formato de termo**: Os contextos de entidade agora usam o novo formato de Termo (`{"t": "i", "i": uri}`) em vez do formato de Valor antigo (`{"v": entity, "e": True}`). + +-- + +## Mudanças Incompatíveis + +**Renomeação de terminologia**: O esquema `Value` foi renomeado para `Term` em todo o sistema (PR #622). Isso afeta o formato de fio usado por ferramentas de linha de comando que interagem com o armazenamento de grafo. O novo formato usa `{"t": "i", "i": uri}` para IRIs e `{"t": "l", "v": value}` para literais, substituindo o formato antigo `{"v": ..., "e": ...}`. +**`tg-invoke-objects-query` renomeado** para `tg-invoke-rows-query`. +**`tg-load-pdf` e `tg-load-text` removidos**. diff --git a/docs/cli-changes-v1.8-to-v2.1.tr.md b/docs/cli-changes-v1.8-to-v2.1.tr.md new file mode 100644 index 00000000..ec744d8f --- /dev/null +++ b/docs/cli-changes-v1.8-to-v2.1.tr.md @@ -0,0 +1,112 @@ +# CLI Değişiklikleri: v1.8'den v2.1'e + +## Özet + +CLI (`trustgraph-cli`), üç tema üzerine odaklanmış önemli eklemeler içerir: +**açıklanabilirlik/kaynak**, **gömme erişimi** ve **graf sorgulama**. +İki eski araç kaldırıldı, biri yeniden adlandırıldı ve birkaç mevcut araç +yeni yetenekler kazandı. + +-- + +## Yeni CLI Araçları + +### Açıklanabilirlik ve Kaynak + +| Komut | Açıklama | +|---------|-------------| +| `tg-list-explain-traces` | Bir koleksiyondaki tüm açıklanabilirlik oturumlarını (GraphRAG ve Agent) listeler, oturum kimliklerini, türü, soru metnini ve zaman damgalarını gösterir. | +| `tg-show-explain-trace` | Bir oturum için tam açıklanabilirlik izini görüntüler. GraphRAG için: Soru, Keşif, Odak, Sentez aşamaları. Agent için: Oturum, Yinelemeler (düşünce/eylem/gözlem), Son Cevap. İz türünü otomatik olarak algılar. `--show-provenance` ile kaynak belgelere kadar kenarları izlemeyi destekler. | +| `tg-show-extraction-provenance` | Bir belge kimliği verildiğinde, kaynak zincirini izler: Belge -> Sayfalar -> Parçalar -> Kenarlar, `prov:wasDerivedFrom` ilişkilerini kullanarak. `--show-content` ve `--max-content` seçeneklerini destekler. | + +### Gömme (Embeddings) + +| Komut | Açıklama | +|---------|-------------| +| `tg-invoke-embeddings` | Metni, gömme hizmeti aracılığıyla bir vektör gömmesine dönüştürür. Bir veya daha fazla metin girişi alır, vektörleri kayan nokta listeleri olarak döndürür. | +| `tg-invoke-graph-embeddings` | Vektör gömmelerini kullanarak grafik varlıklarını metin benzerliğiyle sorgular. Eşleşen varlıkları benzerlik puanlarıyla döndürür. | +| `tg-invoke-document-embeddings` | Vektör gömmelerini kullanarak belge parçalarını metin benzerliğiyle sorgular. Eşleşen parça kimliklerini benzerlik puanlarıyla döndürür. | +| `tg-invoke-row-embeddings` | Vektör gömmelerini kullanarak dizinlenmiş alanlarda yapılandırılmış veri satırlarını metin benzerliğiyle sorgular. Eşleşen satırları, indeks değerlerini ve puanları döndürür. `--schema-name` gerektirir ve `--index-name`'yi destekler. | + +### Graf Sorgulama + +| Komut | Açıklama | +|---------|-------------| +| `tg-query-graph` | Desen tabanlı üçlü depolama sorgusu. `tg-show-graph`'in aksine (her şeyi dökerek), bu, herhangi bir konu, yüklem, nesne ve graf kombinasyonuyla seçici sorgular yapmayı sağlar. Değer türlerini otomatik olarak algılar: IRI'lar (`http://...`, `urn:...`, `<...>`), tırnak işaretli üçlüler (`<>`) ve literal'lar. | +| `tg-get-document-content` | Belge kimliğine göre kütüphaneden belge içeriğini alır. Dosyaya veya standart çıktıya yazabilir, hem metin hem de ikili içeriği işler. | + +-- + +## Kaldırılan CLI Araçları + +| Komut | Notlar | +|---------|-------| +| `tg-load-pdf` | Kaldırıldı. Belge yükleme artık kütüphane/işlem hattı aracılığıyla yapılır. | +| `tg-load-text` | Kaldırıldı. Belge yükleme artık kütüphane/işlem hattı aracılığıyla yapılır. | + +-- + +## Yeniden Adlandırılan CLI Araçları + +| Eski Ad | Yeni Ad | Notlar | +|----------|----------|-------| +| `tg-invoke-objects-query` | `tg-invoke-rows-query` | Yapılandırılmış veri için "nesneler" teriminin "satırlar" terimine dönüştürülmesini yansıtır. | + +-- + +## Mevcut Araçlara Yönelik Önemli Değişiklikler + +### `tg-invoke-graph-rag` + +**Açıklanabilirlik desteği**: Artık, yerleşik kaynak olay gösterimiyle (Question, Grounding/Exploration, Focus, Synthesis) 4 aşamalı bir açıklanabilirlik işlem hattını destekler. +**Akış**: Gerçek zamanlı çıktı için WebSocket akışını kullanır. +**Kaynak takibi**: Seçilen kenarları yeniden yapılandırma ve `prov:wasDerivedFrom` zincirleri aracılığıyla kaynak belgelere kadar izleyebilir. +Tam açıklanabilirlik işlem hattını barındırmak için ~30 satırdan ~760 satıra yükseldi. + +### `tg-invoke-document-rag` + +**Açıklanabilirlik desteği**: İçerik tabanlı yanıtları (Document RAG) yerleşik kaynak olaylarıyla (Question, Grounding, Exploration, Synthesis aşamaları) akışla gönderen `question_explainable()` modunu ekledi. + +### `tg-invoke-agent` + +**Açıklanabilirlik desteği**: Ajan yürütülmesi sırasında kaynak olaylarını yerleşik olarak gösteren `question_explainable()` modunu ekledi (Question, Analysis, Conclusion, AgentThought, AgentObservation, AgentAnswer). +Ayrıntılı mod, düşünce/gözlem akışlarını emoji ön ekleriyle gösterir. + +### `tg-show-graph` + +**Akış modu**: Daha düşük ilk sonuç süresi ve azaltılmış bellek yükü için yapılandırılabilir toplu boyutlarla `triples_query_stream()`'ı kullanır. +**Adlandırılmış grafik desteği**: Yeni `--graph` filtre seçeneği. Adlandırılmış grafikleri tanır: + Varsayılan grafik (boş): Temel bilgi gerçekleri + `urn:graph:source`: Çıkarma kaynağı + `urn:graph:retrieval`: Sorgu zamanı açıklanabilirliği +**Grafik sütununu göster**: Her üçlü için adlandırılmış grafiği görüntülemek için yeni `--show-graph` bayrağı. +**Yapılandırılabilir sınırlar**: Yeni `--limit` ve `--batch-size` seçenekleri. + +### `tg-graph-to-turtle` + +**RDF-star desteği**: Artık tırnaklı üçlüleri (RDF-star yeniden yapılandırması) işler. +**Akış modu**: Daha düşük ilk işleme süresi için akışı kullanır. +**Tel formatı işleme**: IRIs için `{"t": "i", "i": uri}`, literal'lar için `{"t": "l", "v": value}` ve tırnaklı üçlüler için `{"t": "r", "r": {...}}` kullanan yeni terim tel formatını kullanmak üzere güncellendi. +**Adlandırılmış grafik desteği**: Yeni `--graph` filtre seçeneği. + +### `tg-set-tool` + +**Yeni araç türü**: Yapılandırılmış veri dizinlerinde semantik arama için `row-embeddings-query`. +**Yeni seçenekler**: Satır gömme sorgu araçlarını yapılandırmak için `--schema-name`, `--index-name`, `--limit`. + +### `tg-show-tools` + +`schema-name`, `index-name` ve `limit` alanlarıyla yeni `row-embeddings-query` araç türünü görüntüler. + +### `tg-load-knowledge` + +**İlerleme raporlama**: Her dosya ve toplamda yüklenen üçlü ve varlık bağlamlarının sayısını sayar ve raporlar. +**Terim formatı güncellemesi**: Varlık bağlamları artık eski Değer formatının (`{"v": entity, "e": True}`) yerine yeni Terim formatını (`{"t": "i", "i": uri}`) kullanır. + +-- + +## Uyumluluk Sorunları + +**Terminoloji yeniden adlandırması**: `Value` şeması, sistem genelinde `Term` olarak yeniden adlandırıldı (PR #622). Bu, grafik deposuyla etkileşimde bulunan CLI araçları tarafından kullanılan tel formatını etkiler. Yeni format, eski `{"v": ..., "e": ...}` formatının yerini alarak IRIs için `{"t": "i", "i": uri}` ve literal'lar için `{"t": "l", "v": value}` kullanır. +`tg-invoke-objects-query` yeniden adlandırıldı `tg-invoke-rows-query`. +`tg-load-pdf` ve `tg-load-text` kaldırıldı. diff --git a/docs/contributor-licence-agreement.pt.md b/docs/contributor-licence-agreement.pt.md new file mode 100644 index 00000000..9689a866 --- /dev/null +++ b/docs/contributor-licence-agreement.pt.md @@ -0,0 +1,19 @@ +# Acordo de Licença para Contribuintes (CLA) + +Pedimos a cada contribuinte que assine um Acordo de Licença para Contribuintes antes +que possamos mesclar um pull request. O CLA não transfere os direitos autorais — +você mantém a propriedade total do seu trabalho. Ele simplesmente concede ao projeto TrustGraph +uma licença perpétua e sem royalties para distribuir sua +contribuição sob a licença +[Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) do projeto, e +confirma que você tem o direito de fazer a contribuição. Isso protege +tanto o projeto quanto seus usuários, garantindo que cada contribuição tenha +uma base legal clara. + +Quando você abre um pull request, o bot do CLA postará um comentário pedindo que você +revise e assine o acordo apropriado — leva apenas um momento +e você só precisa fazer isso uma vez em todos os repositórios do TrustGraph. + +Contribuindo como um **indivíduo**? Assine o [CLA Individual](https://github.com/trustgraph-ai/contributor-license-agreement/blob/main/Fiduciary-Contributor-License-Agreement.md) +Contribuindo em nome de uma **empresa ou organização**? Assine o [CLA para Entidades](https://github.com/trustgraph-ai/contributor-license-agreement/blob/main/Entity-Fiduciary-Contributor-License-Agreement.md) + diff --git a/docs/contributor-licence-agreement.tr.md b/docs/contributor-licence-agreement.tr.md new file mode 100644 index 00000000..21aaf9f3 --- /dev/null +++ b/docs/contributor-licence-agreement.tr.md @@ -0,0 +1,19 @@ +# Katkıda Bulunanlar Lisans Sözleşmesi (KBL) + +Her katkıda bulunan kişiden, bir çekme isteğini (pull request) birleştirmeden önce, bir Katkıda Bulunan Lisans Sözleşmesi (Contributor Licence Agreement) imzalamasını rica ediyoruz. +CLA, telif hakkını devretmez; +siz, yaptığınız işin tam mülkiyetini koruyorsunuz. Sadece TrustGraph +projesine, katkınızı projenin +altında dağıtmak için kalıcı, telifsiz bir lisans verir. +[Apache 2.0 lisansı](https://www.apache.org/licenses/LICENSE-2.0) ve +katkıyı yapma hakkınız olduğunu teyit eder. Bu, her katkının açık bir yasal temele sahip olmasını sağlayarak hem projeyi hem de kullanıcılarını korur. + + + +Bir çekme isteği (pull request) açtığınızda, CLA bot'u size uygun sözleşmeyi incelemeniz ve imzalamanız için bir yorum yayınlayacaktır; bu sadece birkaç dakika sürer. +Ve bunu yalnızca TrustGraph'taki tüm depolarda bir kez yapmanız gerekir. + + +**Bireysel** olarak katkıda bulunuyor musunuz? [Bireysel CLA](https://github.com/trustgraph-ai/contributor-license-agreement/blob/main/Fiduciary-Contributor-License-Agreement.md) sözleşmesini imzalayın. +Bir **şirket veya kuruluş** adına katkıda bulunuyor musunuz? [Kuruluş CLA](https://github.com/trustgraph-ai/contributor-license-agreement/blob/main/Entity-Fiduciary-Contributor-License-Agreement.md) sözleşmesini imzalayın. + diff --git a/docs/python-api.es.md b/docs/python-api.es.md new file mode 100644 index 00000000..41cada97 --- /dev/null +++ b/docs/python-api.es.md @@ -0,0 +1,4071 @@ +# Referencia de la API de Python de TrustGraph + +## Instalación + +```bash +pip install trustgraph +``` + +## Inicio rápido + +Todas las clases y tipos se importan del paquete `trustgraph.api`: + +```python +from trustgraph.api import Api, Triple, ConfigKey + +# Create API client +api = Api(url="http://localhost:8088/") + +# Get a flow instance +flow = api.flow().id("default") + +# Execute a graph RAG query +response = flow.graph_rag( + query="What are the main topics?", + user="trustgraph", + collection="default" +) +``` + +## Tabla de Contenidos + +### Núcleo + +[Api](#api) + +### Clientes de Flujo + +[Flow](#flow) +[FlowInstance](#flowinstance) +[AsyncFlow](#asyncflow) +[AsyncFlowInstance](#asyncflowinstance) + +### Clientes de WebSocket + +[SocketClient](#socketclient) +[SocketFlowInstance](#socketflowinstance) +[AsyncSocketClient](#asyncsocketclient) +[AsyncSocketFlowInstance](#asyncsocketflowinstance) + +### Operaciones Masivas + +[BulkClient](#bulkclient) +[AsyncBulkClient](#asyncbulkclient) + +### Métricas + +[Metrics](#metrics) +[AsyncMetrics](#asyncmetrics) + +### Tipos de Datos + +[Triple](#triple) +[ConfigKey](#configkey) +[ConfigValue](#configvalue) +[DocumentMetadata](#documentmetadata) +[ProcessingMetadata](#processingmetadata) +[CollectionMetadata](#collectionmetadata) +[StreamingChunk](#streamingchunk) +[AgentThought](#agentthought) +[AgentObservation](#agentobservation) +[AgentAnswer](#agentanswer) +[RAGChunk](#ragchunk) + +### Excepciones + +[ProtocolException](#protocolexception) +[TrustGraphException](#trustgraphexception) +[AgentError](#agenterror) +[ConfigError](#configerror) +[DocumentRagError](#documentragerror) +[FlowError](#flowerror) +[GatewayError](#gatewayerror) +[GraphRagError](#graphragerror) +[LLMError](#llmerror) +[LoadError](#loaderror) +[LookupError](#lookuperror) +[NLPQueryError](#nlpqueryerror) +[RowsQueryError](#rowsqueryerror) +[RequestError](#requesterror) +[StructuredQueryError](#structuredqueryerror) +[UnexpectedError](#unexpectederror) +[ApplicationException](#applicationexception) + +-- + +## `Api` + +```python +from trustgraph.api import Api +``` + +Cliente principal de la API TrustGraph para operaciones sincrónicas y asincrónicas. + +Esta clase proporciona acceso a todos los servicios de TrustGraph, incluyendo la gestión de flujos, +operaciones de grafos de conocimiento, procesamiento de documentos, consultas RAG y más. Soporta +tanto patrones de comunicación basados en REST como en WebSocket. + +El cliente se puede utilizar como un administrador de contexto para la limpieza automática de recursos: + ```python + with Api(url="http://localhost:8088/") as api: + result = api.flow().id("default").graph_rag(query="test") + ``` + +### Métodos + +### `__aenter__(self)` + +Ingrese al administrador de contexto asíncrono. + +### `__aexit__(self, *args)` + +Salga del administrador de contexto asíncrono y cierre las conexiones. + +### `__enter__(self)` + +Ingrese al administrador de contexto síncrono. + +### `__exit__(self, *args)` + +Salga del administrador de contexto síncrono y cierre las conexiones. + +### `__init__(self, url='http://localhost:8088/', timeout=60, token: str | None = None)` + +Inicialice el cliente de la API TrustGraph. + +**Argumentos:** + +`url`: URL base para la API TrustGraph (por defecto: "http://localhost:8088/"") +`timeout`: Tiempo de espera de la solicitud en segundos (por defecto: 60) +`token`: Token de portador opcional para la autenticación + +**Ejemplo:** + +```python +# Local development +api = Api() + +# Production with authentication +api = Api( + url="https://trustgraph.example.com/", + timeout=120, + token="your-api-token" +) +``` + +### `aclose(self)` + +Cerrar todas las conexiones de cliente asíncronas. + +Este método cierra las conexiones asíncronas de WebSocket, las operaciones masivas y los flujos. +Se llama automáticamente al salir de un administrador de contexto asíncrono. + +**Ejemplo:** + +```python +api = Api() +async_socket = api.async_socket() +# ... use async_socket +await api.aclose() # Clean up connections + +# Or use async context manager (automatic cleanup) +async with Api() as api: + async_socket = api.async_socket() + # ... use async_socket +# Automatically closed +``` + +### `async_bulk(self)` + +Obtenga un cliente para operaciones masivas asíncronas. + +Proporciona operaciones de importación/exportación masivas en estilo async/await a través de WebSocket +para un manejo eficiente de grandes conjuntos de datos. + +**Devuelve:** AsyncBulkClient: Cliente para operaciones masivas asíncronas. + +**Ejemplo:** + +```python +async_bulk = api.async_bulk() + +# Export triples asynchronously +async for triple in async_bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import with async generator +async def triple_gen(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +await async_bulk.import_triples( + flow="default", + triples=triple_gen() +) +``` + +### `async_flow(self)` + +Obtenga un cliente de flujo basado en REST asíncrono. + +Proporciona acceso al estilo async/await a las operaciones de flujo. Esto es preferible +para aplicaciones y marcos de trabajo de Python asíncronos (FastAPI, aiohttp, etc.). + +**Devuelve:** AsyncFlow: Cliente de flujo asíncrono + +**Ejemplo:** + +```python +async_flow = api.async_flow() + +# List flows +flow_ids = await async_flow.list() + +# Execute operations +instance = async_flow.id("default") +result = await instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `async_metrics(self)` + +Obtenga un cliente de métricas asíncrono. + +Proporciona acceso al estilo async/await a las métricas de Prometheus. + +**Retorna:** AsyncMetrics: Cliente de métricas asíncrono + +**Ejemplo:** + +```python +async_metrics = api.async_metrics() +prometheus_text = await async_metrics.get() +print(prometheus_text) +``` + +### `async_socket(self)` + +Obtenga un cliente WebSocket asíncrono para operaciones de transmisión. + +Proporciona acceso a WebSocket con estilo async/await y soporte para transmisión. +Este es el método preferido para la transmisión asíncrona en Python. + +**Retorna:** AsyncSocketClient: Cliente WebSocket asíncrono + +**Ejemplo:** + +```python +async_socket = api.async_socket() +flow = async_socket.flow("default") + +# Stream agent responses +async for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + +### `bulk(self)` + +Obtenga un cliente de operaciones masivas sincrónicas para la importación/exportación. + +Las operaciones masivas permiten la transferencia eficiente de grandes conjuntos de datos a través de conexiones WebSocket, +incluyendo triples, incrustaciones, contextos de entidades y objetos. + +**Devuelve:** BulkClient: Cliente de operaciones masivas sincrónicas. + +**Ejemplo:** + +```python +bulk = api.bulk() + +# Export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import triples +def triple_generator(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +bulk.import_triples(flow="default", triples=triple_generator()) +``` + +### `close(self)` + +Cerrar todas las conexiones de cliente sincrónicas. + +Este método cierra las conexiones de WebSocket y de operaciones masivas. +Se llama automáticamente al salir de un administrador de contexto. + +**Ejemplo:** + +```python +api = Api() +socket = api.socket() +# ... use socket +api.close() # Clean up connections + +# Or use context manager (automatic cleanup) +with Api() as api: + socket = api.socket() + # ... use socket +# Automatically closed +``` + +### `collection(self)` + +Obtenga un cliente de Collection para administrar colecciones de datos. + +Las colecciones organizan documentos y datos de grafos de conocimiento en +agrupaciones lógicas para el aislamiento y el control de acceso. + +**Devuelve:** Collection: Cliente de administración de colecciones + +**Ejemplo:** + +```python +collection = api.collection() + +# List collections +colls = collection.list_collections(user="trustgraph") + +# Update collection metadata +collection.update_collection( + user="trustgraph", + collection="default", + name="Default Collection", + description="Main data collection" +) +``` + +### `config(self)` + +Obtenga un cliente de Config para administrar la configuración. + +**Retorna:** Config: Cliente de administración de configuración + +**Ejemplo:** + +```python +config = api.config() + +# Get configuration values +values = config.get([ConfigKey(type="llm", key="model")]) + +# Set configuration +config.put([ConfigValue(type="llm", key="model", value="gpt-4")]) +``` + +### `flow(self)` + +Obtenga un cliente de Flow para administrar e interactuar con flujos. + +Los flujos son las unidades de ejecución principales en TrustGraph, y proporcionan acceso a +servicios como agentes, consultas RAG, incrustaciones y procesamiento de documentos. + +**Devuelve:** Flow: Cliente de administración de flujos. + +**Ejemplo:** + +```python +flow_client = api.flow() + +# List available blueprints +blueprints = flow_client.list_blueprints() + +# Get a specific flow instance +flow_instance = flow_client.id("default") +response = flow_instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `knowledge(self)` + +Obtenga un cliente de Knowledge para administrar los núcleos de grafos de conocimiento. + +**Retorna:** Knowledge: Cliente de administración de grafos de conocimiento. + +**Ejemplo:** + +```python +knowledge = api.knowledge() + +# List available KG cores +cores = knowledge.list_kg_cores(user="trustgraph") + +# Load a KG core +knowledge.load_kg_core(id="core-123", user="trustgraph") +``` + +### `library(self)` + +Obtenga un cliente de la biblioteca para la gestión de documentos. + +La biblioteca proporciona almacenamiento de documentos, gestión de metadatos y +coordinación del flujo de trabajo de procesamiento. + +**Devuelve:** Biblioteca: Cliente de gestión de la biblioteca de documentos + +**Ejemplo:** + +```python +library = api.library() + +# Add a document +library.add_document( + document=b"Document content", + id="doc-123", + metadata=[], + user="trustgraph", + title="My Document", + comments="Test document" +) + +# List documents +docs = library.get_documents(user="trustgraph") +``` + +### `metrics(self)` + +Obtiene un cliente de métricas sincrónico para la monitorización. + +Recupera métricas en formato Prometheus del servicio TrustGraph +para la monitorización y la observabilidad. + +**Devuelve:** Métricas: Cliente de métricas sincrónico + +**Ejemplo:** + +```python +metrics = api.metrics() +prometheus_text = metrics.get() +print(prometheus_text) +``` + +### `request(self, path, request)` + +Realizar una solicitud de API REST de bajo nivel. + +Este método se utiliza principalmente para uso interno, pero se puede utilizar para acceder directamente +a la API cuando sea necesario. + +**Argumentos:** + +`path`: Ruta del punto final de la API (relativa a la URL base) +`request`: Carga útil de la solicitud como un diccionario + +**Retorna:** dict: Objeto de respuesta + +**Lanza:** + +`ProtocolException`: Si el estado de la respuesta no es 200 o la respuesta no es JSON +`ApplicationException`: Si la respuesta contiene un error + +**Ejemplo:** + +```python +response = api.request("flow", { + "operation": "list-flows" +}) +``` + +### `socket(self)` + +Obtenga un cliente WebSocket síncrono para operaciones de transmisión. + +Las conexiones WebSocket proporcionan soporte de transmisión para respuestas en tiempo real +de agentes, consultas RAG y finalizaciones de texto. Este método devuelve un +envoltorio síncrono alrededor del protocolo WebSocket. + +**Retorna:** SocketClient: Cliente WebSocket síncrono + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `Flow` + +```python +from trustgraph.api import Flow +``` + +Cliente de gestión de flujo para operaciones de planos de flujo y instancias de flujo. + +Esta clase proporciona métodos para administrar planos de flujo (plantillas) y +instancias de flujo (flujos en ejecución). Los planos definen la estructura y +los parámetros de los flujos, mientras que las instancias representan flujos activos que +pueden ejecutar servicios. + +### Métodos + +### `__init__(self, api)` + +Inicializar el cliente de flujo. + +**Argumentos:** + +`api`: Instancia de Api principal para realizar solicitudes. + +### `delete_blueprint(self, blueprint_name)` + +Eliminar un plano de flujo. + +**Argumentos:** + +`blueprint_name`: Nombre del plano a eliminar. + +**Ejemplo:** + +```python +api.flow().delete_blueprint("old-blueprint") +``` + +### `get(self, id)` + +Obtener la definición de una instancia de flujo en ejecución. + +**Argumentos:** + +`id`: ID de la instancia de flujo + +**Retorna:** dict: Definición de la instancia de flujo + +**Ejemplo:** + +```python +flow_def = api.flow().get("default") +print(flow_def) +``` + +### `get_blueprint(self, blueprint_name)` + +Obtener una definición de diagrama de flujo por nombre. + +**Argumentos:** + +`blueprint_name`: Nombre del diagrama de flujo a recuperar + +**Retorna:** dict: Definición del diagrama de flujo como un diccionario + +**Ejemplo:** + +```python +blueprint = api.flow().get_blueprint("default") +print(blueprint) # Blueprint configuration +``` + +### `id(self, id='default')` + +Obtener una instancia de FlowInstance para ejecutar operaciones en un flujo específico. + +**Argumentos:** + +`id`: Identificador del flujo (predeterminado: "default") + +**Retorna:** FlowInstance: Instancia de flujo para operaciones de servicio + +**Ejemplo:** + +```python +flow = api.flow().id("my-flow") +response = flow.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `list(self)` + +Listar todas las instancias de flujo activas. + +**Retorna:** list[str]: Lista de identificadores de instancias de flujo. + +**Ejemplo:** + +```python +flows = api.flow().list() +print(flows) # ['default', 'flow-1', 'flow-2', ...] +``` + +### `list_blueprints(self)` + +Listar todos los planos de flujo disponibles. + +**Retorna:** list[str]: Lista de nombres de planos. + +**Ejemplo:** + +```python +blueprints = api.flow().list_blueprints() +print(blueprints) # ['default', 'custom-flow', ...] +``` + +### `put_blueprint(self, blueprint_name, definition)` + +Crear o actualizar un esquema de flujo. + +**Argumentos:** + +`blueprint_name`: Nombre para el esquema. +`definition`: Diccionario de definición del esquema. + +**Ejemplo:** + +```python +definition = { + "services": ["text-completion", "graph-rag"], + "parameters": {"model": "gpt-4"} +} +api.flow().put_blueprint("my-blueprint", definition) +``` + +### `request(self, path=None, request=None)` + +Realizar una solicitud de API con ámbito de flujo. + +**Argumentos:** + +`path`: Sufijo de ruta opcional para los puntos finales de flujo. +`request`: Diccionario de carga útil de la solicitud. + +**Retorna:** dict: Objeto de respuesta. + +**Genera:** + +`RuntimeError`: Si no se especifica el parámetro de solicitud. + +### `start(self, blueprint_name, id, description, parameters=None)` + +Iniciar una nueva instancia de flujo a partir de un plano. + +**Argumentos:** + +`blueprint_name`: Nombre del plano a instanciar. +`id`: Identificador único para la instancia de flujo. +`description`: Descripción legible por humanos. +`parameters`: Diccionario de parámetros opcionales. + +**Ejemplo:** + +```python +api.flow().start( + blueprint_name="default", + id="my-flow", + description="My custom flow", + parameters={"model": "gpt-4"} +) +``` + +### `stop(self, id)` + +Detener una instancia de flujo en ejecución. + +**Argumentos:** + +`id`: ID de la instancia de flujo a detener. + +**Ejemplo:** + +```python +api.flow().stop("my-flow") +``` + + +-- + +## `FlowInstance` + +```python +from trustgraph.api import FlowInstance +``` + +Cliente de instancia de flujo para ejecutar servicios en un flujo específico. + +Esta clase proporciona acceso a todos los servicios de TrustGraph, incluyendo: +Completado de texto y embeddings +Operaciones de agentes con gestión de estado +Consultas RAG de gráficos y documentos +Operaciones de grafos de conocimiento (triples, objetos) +Carga y procesamiento de documentos +Conversión de lenguaje natural a consulta GraphQL +Análisis de datos estructurados y detección de esquemas +Ejecución de herramientas MCP +Plantillas de prompts + +Los servicios se acceden a través de una instancia de flujo en ejecución identificada por ID. + +### Métodos + +### `__init__(self, api, id)` + +Inicializar FlowInstance. + +**Argumentos:** + +`api`: Cliente de flujo padre +`id`: Identificador de la instancia de flujo + +### `agent(self, question, user='trustgraph', state=None, group=None, history=None)` + +Ejecutar una operación de agente con capacidades de razonamiento y uso de herramientas. + +Los agentes pueden realizar razonamiento en múltiples pasos, usar herramientas y mantener el +estado de la conversación en las interacciones. Esta es una versión síncrona no basada en streaming. + +**Argumentos:** + +`question`: Pregunta o instrucción del usuario +`user`: Identificador del usuario (por defecto: "trustgraph") +`state`: Diccionario de estado opcional para conversaciones con estado +`group`: Identificador de grupo opcional para contextos multiusuario +`history`: Historial de conversación opcional como lista de diccionarios de mensajes + +**Retorna:** str: Respuesta final del agente + +**Ejemplo:** + +```python +flow = api.flow().id("default") + +# Simple question +answer = flow.agent( + question="What is the capital of France?", + user="trustgraph" +) + +# With conversation history +history = [ + {"role": "user", "content": "Hello"}, + {"role": "assistant", "content": "Hi! How can I help?"} +] +answer = flow.agent( + question="Tell me about Paris", + user="trustgraph", + history=history +) +``` + +### `detect_type(self, sample)` + +Detectar el tipo de datos de una muestra de datos estructurados. + +**Argumentos:** + +`sample`: Muestra de datos a analizar (contenido de cadena) + +**Retorna:** diccionario con detected_type, confidence y metadatos opcionales. + +### `diagnose_data(self, sample, schema_name=None, options=None)` + +Realizar un diagnóstico de datos combinado: detectar el tipo y generar un descriptor. + +**Argumentos:** + +`sample`: Muestra de datos a analizar (contenido de cadena) +`schema_name`: Nombre de esquema de destino opcional para la generación del descriptor. +`options`: Parámetros opcionales (por ejemplo, delimitador para CSV). + +**Retorna:** diccionario con detected_type, confidence, descriptor y metadatos. + +### `document_embeddings_query(self, text, user, collection, limit=10)` + +Consultar fragmentos de documentos utilizando similitud semántica. + +Encuentra fragmentos de documentos cuyo contenido sea semánticamente similar al +texto de entrada, utilizando incrustaciones vectoriales. + +**Argumentos:** + +`text`: Texto de consulta para la búsqueda semántica. +`user`: Identificador de usuario/espacio de claves. +`collection`: Identificador de colección. +`limit`: Número máximo de resultados (por defecto: 10). + +**Retorna:** diccionario: Resultados de la consulta con fragmentos que contienen chunk_id y score. + +**Ejemplo:** + +```python +flow = api.flow().id("default") +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "doc1/p0/c0", "score": 0.95}, ...]} +``` + +### `document_rag(self, query, user='trustgraph', collection='default', doc_limit=10)` + +Ejecutar una consulta de Generación Aumentada por Recuperación (RAG) basada en documentos. + +RAG basada en documentos utiliza incrustaciones vectoriales para encontrar fragmentos de documentos relevantes, +y luego genera una respuesta utilizando un LLM con esos fragmentos como contexto. + +**Argumentos:** + +`query`: Consulta en lenguaje natural +`user`: Identificador de usuario/espacio de claves (por defecto: "trustgraph") +`collection`: Identificador de colección (por defecto: "default") +`doc_limit`: Número máximo de fragmentos de documentos a recuperar (por defecto: 10) + +**Retorna:** str: Respuesta generada que incorpora el contexto del documento + +**Ejemplo:** + +```python +flow = api.flow().id("default") +response = flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts)` + +Genera incrustaciones vectoriales para uno o más textos. + +Convierte textos en representaciones vectoriales densas adecuadas para la +búsqueda semántica y la comparación de similitud. + +**Argumentos:** + +`texts`: Lista de textos de entrada para incrustar + +**Retorna:** list[list[list[float]]]: Incrustaciones vectoriales, un conjunto por texto de entrada + +**Ejemplo:** + +```python +flow = api.flow().id("default") +vectors = flow.embeddings(["quantum computing"]) +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `generate_descriptor(self, sample, data_type, schema_name, options=None)` + +Generar un descriptor para el mapeo de datos estructurados a un esquema específico. + +**Argumentos:** + +`sample`: Muestra de datos a analizar (contenido de cadena) +`data_type`: Tipo de datos (csv, json, xml) +`schema_name`: Nombre del esquema de destino para la generación del descriptor +`options`: Parámetros opcionales (por ejemplo, delimitador para CSV) + +**Retorna:** diccionario con el descriptor y metadatos + +### `graph_embeddings_query(self, text, user, collection, limit=10)` + +Consultar entidades de un grafo de conocimiento utilizando similitud semántica. + +Encuentra entidades en el grafo de conocimiento cuyas descripciones son semánticamente +similares al texto de entrada, utilizando incrustaciones vectoriales. + +**Argumentos:** + +`text`: Texto de consulta para la búsqueda semántica +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`limit`: Número máximo de resultados (por defecto: 10) + +**Retorna:** diccionario: Resultados de la consulta con entidades similares + +**Ejemplo:** + +```python +flow = api.flow().id("default") +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +# results contains {"entities": [{"entity": {...}, "score": 0.95}, ...]} +``` + +### `graph_rag(self, query, user='trustgraph', collection='default', entity_limit=50, triple_limit=30, max_subgraph_size=150, max_path_length=2)` + +Ejecutar una consulta de Generación Aumentada por Recuperación (RAG) basada en grafos. + +Graph RAG utiliza la estructura del grafo de conocimiento para encontrar el contexto relevante mediante +el recorrido de las relaciones entre entidades, y luego genera una respuesta utilizando un LLM. + +**Argumentos:** + +`query`: Consulta en lenguaje natural +`user`: Identificador de usuario/espacio de claves (por defecto: "trustgraph") +`collection`: Identificador de colección (por defecto: "default") +`entity_limit`: Número máximo de entidades a recuperar (por defecto: 50) +`triple_limit`: Número máximo de triples por entidad (por defecto: 30) +`max_subgraph_size`: Número máximo total de triples en el subgrafo (por defecto: 150) +`max_path_length`: Profundidad máxima de recorrido (por defecto: 2) + +**Retorna:** str: Respuesta generada que incorpora el contexto del grafo + +**Ejemplo:** + +```python +flow = api.flow().id("default") +response = flow.graph_rag( + query="Tell me about Marie Curie's discoveries", + user="trustgraph", + collection="scientists", + entity_limit=20, + max_path_length=3 +) +print(response) +``` + +### `load_document(self, document, id=None, metadata=None, user=None, collection=None)` + +Cargar un documento binario para su procesamiento. + +Sube un documento (PDF, DOCX, imágenes, etc.) para la extracción y +procesamiento a través de la canalización de documentos del flujo. + +**Argumentos:** + +`document`: Contenido del documento como bytes +`id`: Identificador de documento opcional (se genera automáticamente si es None) +`metadata`: Metadatos opcionales (lista de Triples o objeto con método emit) +`user`: Identificador de usuario/espacio de claves (opcional) +`collection`: Identificador de colección (opcional) + +**Retorna:** dict: Respuesta de procesamiento + +**Lanza:** + +`RuntimeError`: Si se proporcionan metadatos sin id + +**Ejemplo:** + +```python +flow = api.flow().id("default") + +# Load a PDF document +with open("research.pdf", "rb") as f: + result = flow.load_document( + document=f.read(), + id="research-001", + user="trustgraph", + collection="papers" + ) +``` + +### `load_text(self, text, id=None, metadata=None, charset='utf-8', user=None, collection=None)` + +Cargar contenido de texto para su procesamiento. + +Carga contenido de texto para la extracción y el procesamiento a través de la +canalización de texto del flujo. + +**Argumentos:** + +`text`: Contenido de texto como bytes +`id`: Identificador de documento opcional (se genera automáticamente si es None) +`metadata`: Metadatos opcionales (lista de Triples o objeto con método emit) +`charset`: Codificación de caracteres (predeterminado: "utf-8") +`user`: Identificador de usuario/espacio de claves (opcional) +`collection`: Identificador de colección (opcional) + +**Retorna:** dict: Respuesta de procesamiento + +**Genera:** + +`RuntimeError`: Si se proporcionan metadatos sin id + +**Ejemplo:** + +```python +flow = api.flow().id("default") + +# Load text content +text_content = b"This is the document content..." +result = flow.load_text( + text=text_content, + id="text-001", + charset="utf-8", + user="trustgraph", + collection="documents" +) +``` + +### `mcp_tool(self, name, parameters={})` + +Ejecutar una herramienta de Protocolo de Contexto de Modelo (MCP). + +Las herramientas MCP proporcionan funcionalidades extensibles para agentes y flujos de trabajo, +permitiendo la integración con sistemas y servicios externos. + +**Argumentos:** + +`name`: Nombre/identificador de la herramienta +`parameters`: Diccionario de parámetros de la herramienta (por defecto: {}) + +**Retorna:** str o dict: Resultado de la ejecución de la herramienta + +**Genera:** + +`ProtocolException`: Si el formato de la respuesta no es válido + +**Ejemplo:** + +```python +flow = api.flow().id("default") + +# Execute a tool +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `nlp_query(self, question, max_results=100)` + +Convertir una pregunta en lenguaje natural en una consulta GraphQL. + +**Argumentos:** + +`question`: Pregunta en lenguaje natural +`max_results`: Número máximo de resultados a devolver (por defecto: 100) + +**Retorna:** diccionario con graphql_query, variables, detected_schemas, confidence + +### `prompt(self, id, variables)` + +Ejecutar una plantilla de prompt con sustitución de variables. + +Las plantillas de solicitud permiten patrones de solicitud reutilizables con variables dinámicas. +de sustitución, útiles para una ingeniería de solicitudes consistente. + +**Argumentos:** + +`id`: Identificador de la plantilla de solicitud. +`variables`: Diccionario de mapeos de nombres de variables a valores. + +**Retorna:** str o dict: Resultado de la solicitud renderizada (texto u objeto estructurado). + +**Genera:** + +`ProtocolException`: Si el formato de la respuesta no es válido. + +**Ejemplo:** + +```python +flow = api.flow().id("default") + +# Text template +result = flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"} +) + +# Structured template +result = flow.prompt( + id="extract-entities", + variables={"text": "Marie Curie won Nobel Prizes"} +) +``` + +### `request(self, path, request)` + +Realice una solicitud de servicio en esta instancia de flujo. + +**Argumentos:** + +`path`: Ruta del servicio (por ejemplo, "service/text-completion") +`request`: Diccionario de carga útil de la solicitud + +**Retorna:** dict: Respuesta del servicio + +### `row_embeddings_query(self, text, schema_name, user='trustgraph', collection='default', index_name=None, limit=10)` + +Consulta datos de fila utilizando similitud semántica en campos indexados. + +Encuentra filas cuyos valores de campo indexados son semánticamente similares al +texto de entrada, utilizando incrustaciones vectoriales. Esto permite la coincidencia difusa/semántica +en datos estructurados. + +**Argumentos:** + +`text`: Texto de consulta para la búsqueda semántica +`schema_name`: Nombre del esquema para buscar +`user`: Identificador de usuario/espacio de claves (predeterminado: "trustgraph") +`collection`: Identificador de colección (predeterminado: "default") +`index_name`: Nombre de índice opcional para filtrar la búsqueda a un índice específico +`limit`: Número máximo de resultados (predeterminado: 10) + +**Retorna:** dict: Resultados de la consulta con coincidencias que contienen index_name, index_value, text y score + +**Ejemplo:** + +```python +flow = api.flow().id("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query, user='trustgraph', collection='default', variables=None, operation_name=None)` + +Ejecutar una consulta GraphQL contra filas estructuradas en el grafo de conocimiento. + +Consulta datos estructurados utilizando la sintaxis GraphQL, lo que permite consultas complejas +con filtrado, agregación y recorrido de relaciones. + +**Argumentos:** + +`query`: Cadena de consulta GraphQL +`user`: Identificador de usuario/espacio de claves (por defecto: "trustgraph") +`collection`: Identificador de colección (por defecto: "default") +`variables`: Diccionario opcional de variables de consulta +`operation_name`: Nombre de operación opcional para documentos de múltiples operaciones + +**Retorna:** dict: Respuesta GraphQL con los campos 'data', 'errors' y/o 'extensions' + +**Genera:** + +`ProtocolException`: Si ocurre un error a nivel del sistema + +**Ejemplo:** + +```python +flow = api.flow().id("default") + +# Simple query +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) + +# Query with variables +query = ''' +query GetScientist($name: String!) { + scientists(name: $name) { + name + nobelPrizes + } +} +''' +result = flow.rows_query( + query=query, + variables={"name": "Marie Curie"} +) +``` + +### `schema_selection(self, sample, options=None)` + +Seleccionar esquemas coincidentes para una muestra de datos utilizando análisis de consultas. + +**Argumentos:** + +`sample`: Muestra de datos a analizar (contenido de cadena) +`options`: Parámetros opcionales + +**Retorna:** diccionario con el array schema_matches y metadatos + +### `structured_query(self, question, user='trustgraph', collection='default')` + +Ejecutar una pregunta en lenguaje natural contra datos estructurados. +Combina la conversión de consultas NLP y la ejecución de GraphQL. + +**Argumentos:** + +`question`: Pregunta en lenguaje natural +`user`: Identificador de keyspace de Cassandra (por defecto: "trustgraph") +`collection`: Identificador de colección de datos (por defecto: "default") + +**Retorna:** diccionario con datos y posibles errores + +### `text_completion(self, system, prompt)` + +Ejecutar la finalización de texto utilizando el LLM del flujo. + +**Argumentos:** + +`system`: Prompt del sistema que define el comportamiento del asistente +`prompt`: Prompt/pregunta del usuario + +**Retorna:** str: Texto de respuesta generado + +**Ejemplo:** + +```python +flow = api.flow().id("default") +response = flow.text_completion( + system="You are a helpful assistant", + prompt="What is quantum computing?" +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=10000)` + +Consultar tripletas del grafo de conocimiento utilizando la coincidencia de patrones. + +Busca tripletas RDF que coincidan con los patrones de sujeto, predicado y/o +objeto dados. Los parámetros no especificados actúan como comodines. + +**Argumentos:** + +`s`: URI del sujeto (opcional, usar None para comodín) +`p`: URI del predicado (opcional, usar None para comodín) +`o`: URI del objeto o Literal (opcional, usar None para comodín) +`user`: Identificador de usuario/espacio de claves (opcional) +`collection`: Identificador de colección (opcional) +`limit`: Número máximo de resultados a devolver (por defecto: 10000) + +**Devuelve:** list[Triple]: Lista de objetos Triple coincidentes + +**Genera:** + +`RuntimeError`: Si s o p no son un Uri, o o no es un Uri/Literal + +**Ejemplo:** + +```python +from trustgraph.knowledge import Uri, Literal + +flow = api.flow().id("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s=Uri("http://example.org/person/marie-curie"), + user="trustgraph", + collection="scientists" +) + +# Find all instances of a specific relationship +triples = flow.triples_query( + p=Uri("http://example.org/ontology/discovered"), + limit=100 +) +``` + + +-- + +## `AsyncFlow` + +```python +from trustgraph.api import AsyncFlow +``` + +Cliente de gestión de flujos asíncronos que utiliza la API REST. + +Proporciona operaciones de gestión de flujos basadas en async/await, incluyendo listar, +iniciar, detener flujos y gestionar definiciones de clases de flujos. También proporciona +acceso a servicios específicos del flujo, como agentes, RAG y consultas, a través de +puntos finales REST no basados en transmisión. + +Nota: Para el soporte de transmisión, utilice AsyncSocketClient en su lugar. + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicializa el cliente de flujo asíncrono. + +**Argumentos:** + +`url`: URL base para la API de TrustGraph +`timeout`: Tiempo de espera de la solicitud en segundos +`token`: Token de portador opcional para la autenticación + +### `aclose(self) -> None` + +Cierra el cliente asíncrono y libera recursos. + +Nota: La limpieza se gestiona automáticamente por los administradores de contexto de sesión de aiohttp. +Este método se proporciona para mantener la coherencia con otros clientes asíncronos. + +### `delete_class(self, class_name: str)` + +Elimina una definición de clase de flujo. + +Elimina una plantilla de clase de flujo del sistema. No afecta a +instancias de flujo en ejecución. + +**Argumentos:** + +`class_name`: Nombre de la clase de flujo a eliminar + +**Ejemplo:** + +```python +async_flow = await api.async_flow() + +# Delete a flow class +await async_flow.delete_class("old-flow-class") +``` + +### `get(self, id: str) -> Dict[str, Any]` + +Obtener la definición del flujo. + +Recupera la configuración completa del flujo, incluyendo su nombre de clase, +descripción y parámetros. + +**Argumentos:** + +`id`: Identificador del flujo + +**Retorna:** dict: Objeto de definición del flujo + +**Ejemplo:** + +```python +async_flow = await api.async_flow() + +# Get flow definition +flow_def = await async_flow.get("default") +print(f"Flow class: {flow_def.get('class-name')}") +print(f"Description: {flow_def.get('description')}") +``` + +### `get_class(self, class_name: str) -> Dict[str, Any]` + +Obtener la definición de la clase de flujo. + +Recupera la definición del esquema para una clase de flujo, incluyendo su +esquema de configuración y enlaces de servicio. + +**Argumentos:** + +`class_name`: Nombre de la clase de flujo + +**Retorna:** dict: Objeto de definición de la clase de flujo + +**Ejemplo:** + +```python +async_flow = await api.async_flow() + +# Get flow class definition +class_def = await async_flow.get_class("default") +print(f"Services: {class_def.get('services')}") +``` + +### `id(self, flow_id: str)` + +Obtener una instancia de cliente de flujo asíncrono. + +Devuelve un cliente para interactuar con los servicios de un flujo específico +(agente, RAG, consultas, incrustaciones, etc.). + +**Argumentos:** + +`flow_id`: Identificador del flujo + +**Devuelve:** AsyncFlowInstance: Cliente para operaciones específicas del flujo + +**Ejemplo:** + +```python +async_flow = await api.async_flow() + +# Get flow instance +flow = async_flow.id("default") + +# Use flow services +result = await flow.graph_rag( + query="What is TrustGraph?", + user="trustgraph", + collection="default" +) +``` + +### `list(self) -> List[str]` + +Listar todos los identificadores de flujo. + +Recupera los ID de todos los flujos actualmente implementados en el sistema. + +**Retorna:** list[str]: Lista de identificadores de flujo. + +**Ejemplo:** + +```python +async_flow = await api.async_flow() + +# List all flows +flows = await async_flow.list() +print(f"Available flows: {flows}") +``` + +### `list_classes(self) -> List[str]` + +Listar todos los nombres de las clases de flujo. + +Recupera los nombres de todas las clases de flujo (plantillas) disponibles en el sistema. + +**Retorna:** list[str]: Lista de nombres de clases de flujo. + +**Ejemplo:** + +```python +async_flow = await api.async_flow() + +# List available flow classes +classes = await async_flow.list_classes() +print(f"Available flow classes: {classes}") +``` + +### `put_class(self, class_name: str, definition: Dict[str, Any])` + +Crear o actualizar una definición de clase de flujo. + +Almacena un esquema de clase de flujo que se puede utilizar para instanciar flujos. + +**Argumentos:** + +`class_name`: Nombre de la clase de flujo +`definition`: Objeto de definición de la clase de flujo + +**Ejemplo:** + +```python +async_flow = await api.async_flow() + +# Create a custom flow class +class_def = { + "services": { + "agent": {"module": "agent", "config": {...}}, + "graph-rag": {"module": "graph-rag", "config": {...}} + } +} +await async_flow.put_class("custom-flow", class_def) +``` + +### `request(self, path: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +Realizar una solicitud HTTP POST asíncrona a la API de Gateway. + +Método interno para realizar solicitudes autenticadas a la API de TrustGraph. + +**Argumentos:** + +`path`: Ruta de punto final de la API (relativa a la URL base) +`request_data`: Diccionario de carga útil de la solicitud + +**Retorna:** dict: Objeto de respuesta de la API + +**Genera:** + +`ProtocolException`: Si el estado HTTP no es 200 o la respuesta no es un JSON válido +`ApplicationException`: Si la API devuelve una respuesta de error + +### `start(self, class_name: str, id: str, description: str, parameters: Dict | None = None)` + +Inicia una nueva instancia de flujo. + +Crea e inicia un flujo a partir de una definición de clase de flujo con los +parámetros especificados. + +**Argumentos:** + +`class_name`: Nombre de la clase de flujo a instanciar +`id`: Identificador para la nueva instancia de flujo +`description`: Descripción legible por humanos del flujo +`parameters`: Parámetros de configuración opcionales para el flujo + +**Ejemplo:** + +```python +async_flow = await api.async_flow() + +# Start a flow from a class +await async_flow.start( + class_name="default", + id="my-flow", + description="Custom flow instance", + parameters={"model": "claude-3-opus"} +) +``` + +### `stop(self, id: str)` + +Detener un flujo en ejecución. + +Detiene y elimina una instancia de flujo, liberando sus recursos. + +**Argumentos:** + +`id`: Identificador del flujo a detener + +**Ejemplo:** + +```python +async_flow = await api.async_flow() + +# Stop a flow +await async_flow.stop("my-flow") +``` + + +-- + +## `AsyncFlowInstance` + +```python +from trustgraph.api import AsyncFlowInstance +``` + +Cliente de instancia de flujo asíncrono. + +Proporciona acceso async/await a servicios con ámbito de flujo, incluyendo agentes, +consultas RAG, incrustaciones y consultas de grafos. Todas las operaciones devuelven +respuestas completas (no en streaming). + +Nota: Para soporte de streaming, utilice AsyncSocketFlowInstance en su lugar. + +### Métodos + +### `__init__(self, flow: trustgraph.api.async_flow.AsyncFlow, flow_id: str)` + +Inicializa una instancia de flujo asíncrono. + +**Argumentos:** + +`flow`: Cliente AsyncFlow padre +`flow_id`: Identificador de flujo + +### `agent(self, question: str, user: str, state: Dict | None = None, group: str | None = None, history: List | None = None, **kwargs: Any) -> Dict[str, Any]` + +Ejecuta una operación de agente (no en streaming). + +Ejecuta un agente para responder a una pregunta, con un estado de conversación opcional y +historial. Devuelve la respuesta completa después de que el agente haya terminado de +procesar. + +Nota: Este método no admite streaming. Para los pensamientos y observaciones del agente en tiempo real, +utilice AsyncSocketFlowInstance.agent() en su lugar. + +**Argumentos:** + +`question`: Pregunta o instrucción del usuario +`user`: Identificador del usuario +`state`: Diccionario de estado opcional para el contexto de la conversación +`group`: Identificador de grupo opcional para la gestión de sesiones +`history`: Lista de historial de conversación opcional +`**kwargs`: Parámetros adicionales específicos del servicio + +**Devuelve:** dict: Respuesta completa del agente, incluyendo la respuesta y los metadatos + +**Ejemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute agent +result = await flow.agent( + question="What is the capital of France?", + user="trustgraph" +) +print(f"Answer: {result.get('response')}") +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> str` + +Ejecutar consulta RAG basada en documentos (no en streaming). + +Realiza Generación Aumentada por Recuperación utilizando incrustaciones de documentos. +Recupera fragmentos de documentos relevantes mediante búsqueda semántica y luego genera +una respuesta basada en los documentos recuperados. Devuelve la respuesta completa. + +Nota: Este método no admite el streaming. Para respuestas RAG en streaming, +utilice AsyncSocketFlowInstance.document_rag() en su lugar. + +**Argumentos:** + +`query`: Texto de la consulta del usuario +`user`: Identificador del usuario +`collection`: Identificador de la colección que contiene los documentos +`doc_limit`: Número máximo de fragmentos de documentos a recuperar (por defecto: 10) +`**kwargs`: Parámetros adicionales específicos del servicio + +**Devuelve:** str: Respuesta generada completa basada en los datos del documento + +**Ejemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query documents +response = await flow.document_rag( + query="What does the documentation say about authentication?", + user="trustgraph", + collection="docs", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts: list, **kwargs: Any)` + +Generar incrustaciones (embeddings) para textos de entrada. + +Convierte textos en representaciones vectoriales numéricas utilizando el modelo de incrustación configurado en el flujo. Útil para la búsqueda semántica y comparaciones de similitud. + + + +**Argumentos:** + +`texts`: Lista de textos de entrada para incrustar +`**kwargs`: Parámetros adicionales específicos del servicio + +**Retorna:** dict: Respuesta que contiene vectores de incrustación + +**Ejemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate embeddings +result = await flow.embeddings(texts=["Sample text to embed"]) +vectors = result.get("vectors") +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any)` + +Consulta incrustaciones de grafos para la búsqueda semántica de entidades. + +Realiza una búsqueda semántica sobre las incrustaciones de entidades de grafos para encontrar entidades +más relevantes para el texto de entrada. Devuelve entidades clasificadas por similitud. + +**Argumentos:** + +`text`: Texto de consulta para la búsqueda semántica +`user`: Identificador de usuario +`collection`: Identificador de la colección que contiene las incrustaciones de grafos +`limit`: Número máximo de resultados a devolver (por defecto: 10) +`**kwargs`: Parámetros adicionales específicos del servicio + +**Devuelve:** dict: Respuesta que contiene coincidencias de entidades clasificadas con puntuaciones de similitud + +**Ejemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find related entities +results = await flow.graph_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="tech-kb", + limit=5 +) + +for entity in results.get("entities", []): + print(f"{entity['name']}: {entity['score']}") +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> str` + +Ejecutar consulta RAG basada en grafos (no en streaming). + +Realiza la generación aumentada con recuperación utilizando datos de grafos de conocimiento. +Identifica entidades relevantes y sus relaciones, y luego genera una +respuesta basada en la estructura del grafo. Devuelve la respuesta completa. + +Nota: Este método no admite el streaming. Para respuestas RAG en streaming, +utilice AsyncSocketFlowInstance.graph_rag() en su lugar. + +**Argumentos:** + +`query`: Texto de la consulta del usuario +`user`: Identificador del usuario +`collection`: Identificador de la colección que contiene el grafo de conocimiento +`max_subgraph_size`: Número máximo de triples por subgrafo (por defecto: 1000) +`max_subgraph_count`: Número máximo de subgrafos a recuperar (por defecto: 5) +`max_entity_distance`: Distancia máxima del grafo para la expansión de entidades (por defecto: 3) +`**kwargs`: Parámetros adicionales específicos del servicio + +**Devuelve:** str: Respuesta completa generada basada en datos del grafo + +**Ejemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query knowledge graph +response = await flow.graph_rag( + query="What are the relationships between these entities?", + user="trustgraph", + collection="medical-kb", + max_subgraph_count=3 +) +print(response) +``` + +### `request(self, service: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +Realizar una solicitud a un servicio con ámbito de flujo. + +Método interno para llamar a servicios dentro de esta instancia de flujo. + +**Argumentos:** + +`service`: Nombre del servicio (por ejemplo, "agent", "graph-rag", "triples") +`request_data`: Carga útil de la solicitud al servicio + +**Retorna:** dict: Objeto de respuesta del servicio + +**Lanza:** + +`ProtocolException`: Si la solicitud falla o la respuesta es inválida +`ApplicationException`: Si el servicio devuelve un error + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any)` + +Consultar incrustaciones de filas para la búsqueda semántica en datos estructurados. + +Realiza una búsqueda semántica sobre las incrustaciones del índice de filas para encontrar filas cuyas +valores de campo indexados sean más similares al texto de entrada. Permite +la coincidencia difusa/semántica en datos estructurados. + +**Argumentos:** + +`text`: Texto de consulta para la búsqueda semántica +`schema_name`: Nombre del esquema para buscar +`user`: Identificador de usuario (por defecto: "trustgraph") +`collection`: Identificador de colección (por defecto: "default") +`index_name`: Nombre de índice opcional para filtrar la búsqueda a un índice específico +`limit`: Número máximo de resultados a devolver (por defecto: 10) +`**kwargs`: Parámetros adicionales específicos del servicio + +**Retorna:** dict: Respuesta que contiene coincidencias con index_name, index_value, text y score + +**Ejemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Search for customers by name similarity +results = await flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +for match in results.get("matches", []): + print(f"{match['index_name']}: {match['index_value']} (score: {match['score']})") +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs: Any)` + +Ejecutar una consulta GraphQL en filas almacenadas. + +Consulta filas de datos estructurados utilizando la sintaxis GraphQL. Soporta consultas complejas +con variables y operaciones con nombre. + +**Argumentos:** + +`query`: Cadena de consulta GraphQL +`user`: Identificador de usuario +`collection`: Identificador de la colección que contiene las filas +`variables`: Variables de consulta GraphQL opcionales +`operation_name`: Nombre de operación opcional para consultas con múltiples operaciones +`**kwargs`: Parámetros adicionales específicos del servicio + +**Retorna:** dict: Respuesta GraphQL con datos y/o errores + +**Ejemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute GraphQL query +query = ''' + query GetUsers($status: String!) { + users(status: $status) { + id + name + email + } + } +''' + +result = await flow.rows_query( + query=query, + user="trustgraph", + collection="users", + variables={"status": "active"} +) + +for user in result.get("data", {}).get("users", []): + print(f"{user['name']}: {user['email']}") +``` + +### `text_completion(self, system: str, prompt: str, **kwargs: Any) -> str` + +Generar finalización de texto (no en tiempo real). + +Genera una respuesta de texto a partir de un modelo de lenguaje grande (LLM) dado un mensaje del sistema y un mensaje del usuario. +Devuelve el texto de la respuesta completo. + +Nota: Este método no admite la transmisión. Para la generación de texto en tiempo real, +utilice AsyncSocketFlowInstance.text_completion() en su lugar. + +**Argumentos:** + +`system`: Mensaje del sistema que define el comportamiento del LLM. +`prompt`: Mensaje del usuario o pregunta. +`**kwargs`: Parámetros adicionales específicos del servicio. + +**Devuelve:** str: Respuesta de texto generada completa. + +**Ejemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate text +response = await flow.text_completion( + system="You are a helpful assistant.", + prompt="Explain quantum computing in simple terms." +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs: Any)` + +Consultar triples RDF utilizando la coincidencia de patrones. + +Busca triples que coincidan con los patrones especificados de sujeto, predicado y/o +objeto. Los patrones utilizan None como comodín para coincidir con cualquier valor. + +**Argumentos:** + +`s`: Patrón de sujeto (None para comodín) +`p`: Patrón de predicado (None para comodín) +`o`: Patrón de objeto (None para comodín) +`user`: Identificador de usuario (None para todos los usuarios) +`collection`: Identificador de colección (None para todas las colecciones) +`limit`: Número máximo de triples a devolver (por defecto: 100) +`**kwargs`: Parámetros adicionales específicos del servicio + +**Devuelve:** dict: Respuesta que contiene los triples coincidentes + +**Ejemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find all triples with a specific predicate +results = await flow.triples_query( + p="knows", + user="trustgraph", + collection="social", + limit=50 +) + +for triple in results.get("triples", []): + print(f"{triple['s']} knows {triple['o']}") +``` + + +-- + +## `SocketClient` + +```python +from trustgraph.api import SocketClient +``` + +Cliente WebSocket sincrónico para operaciones de transmisión. + +Proporciona una interfaz sincrónica a los servicios TrustGraph basados en WebSocket, +envolviendo la biblioteca de WebSockets asíncronos con generadores sincrónicos para facilitar su uso. +Admite respuestas de transmisión de agentes, consultas RAG y finalizaciones de texto. + +Nota: Este es un envoltorio sincrónico alrededor de operaciones de WebSocket asíncronas. Para +un soporte asíncrono real, utilice AsyncSocketClient en su lugar. + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicializa el cliente WebSocket sincrónico. + +**Argumentos:** + +`url`: URL base para la API de TrustGraph (HTTP/HTTPS se convertirá a WS/WSS) +`timeout`: Tiempo de espera de WebSocket en segundos +`token`: Token de portador opcional para la autenticación + +### `close(self) -> None` + +Cierra las conexiones WebSocket. + +Nota: La limpieza se gestiona automáticamente por los administradores de contexto en el código asíncrono. + +### `flow(self, flow_id: str) -> 'SocketFlowInstance'` + +Obtiene una instancia de flujo para operaciones de transmisión de WebSocket. + +**Argumentos:** + +`flow_id`: Identificador de flujo + +**Devuelve:** SocketFlowInstance: Instancia de flujo con métodos de transmisión + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent(question="Hello", user="trustgraph", streaming=True): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `SocketFlowInstance` + +```python +from trustgraph.api import SocketFlowInstance +``` + +Instancia de flujo WebSocket sincrónico para operaciones de transmisión. + +Proporciona la misma interfaz que FlowInstance de REST, pero con soporte de transmisión basado en WebSocket +para respuestas en tiempo real. Todos los métodos admiten un parámetro opcional +`streaming` para habilitar la entrega incremental de resultados. + +### Métodos + +### `__init__(self, client: trustgraph.api.socket_client.SocketClient, flow_id: str) -> None` + +Inicializar instancia de flujo de socket. + +**Argumentos:** + +`client`: SocketClient padre +`flow_id`: Identificador de flujo + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, streaming: bool = False, **kwargs: Any) -> Dict[str, Any] | Iterator[trustgraph.api.types.StreamingChunk]` + +Ejecutar una operación de agente con soporte de transmisión. + +Los agentes pueden realizar razonamientos de varios pasos con el uso de herramientas. Este método siempre +devuelve fragmentos de transmisión (pensamientos, observaciones, respuestas) incluso cuando +streaming=False, para mostrar el proceso de razonamiento del agente. + +**Argumentos:** + +`question`: Pregunta o instrucción del usuario +`user`: Identificador del usuario +`state`: Diccionario de estado opcional para conversaciones con estado +`group`: Identificador de grupo opcional para contextos multiusuario +`history`: Historial de conversación opcional como lista de diccionarios de mensajes +`streaming`: Habilitar el modo de transmisión (predeterminado: False) +`**kwargs`: Parámetros adicionales pasados al servicio del agente + +**Devuelve:** Iterator[StreamingChunk]: Flujo de pensamientos, observaciones y respuestas del agente + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent reasoning +for chunk in flow.agent( + question="What is quantum computing?", + user="trustgraph", + streaming=True +): + if isinstance(chunk, AgentThought): + print(f"[Thinking] {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"[Observation] {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"[Answer] {chunk.content}") +``` + +### `agent_explain(self, question: str, user: str, collection: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, **kwargs: Any) -> Iterator[trustgraph.api.types.StreamingChunk | trustgraph.api.types.ProvenanceEvent]` + +Ejecutar una operación de agente con soporte de explicabilidad. + +Transmite tanto los fragmentos de contenido (AgentThought, AgentObservation, AgentAnswer) +como los eventos de procedencia (ProvenanceEvent). Los eventos de procedencia contienen URIs +que se pueden recuperar utilizando ExplainabilityClient para obtener información detallada +sobre el proceso de razonamiento del agente. + +El rastro del agente consiste en: +Sesión: La pregunta inicial y los metadatos de la sesión. +Iteraciones: Cada ciclo de pensamiento/acción/observación. +Conclusión: La respuesta final. + +**Argumentos:** + +`question`: Pregunta o instrucción del usuario. +`user`: Identificador del usuario. +`collection`: Identificador de la colección para el almacenamiento de la procedencia. +`state`: Diccionario de estado opcional para conversaciones con estado. +`group`: Identificador de grupo opcional para contextos multiusuario. +`history`: Historial de conversación opcional como una lista de diccionarios de mensajes. +`**kwargs`: Parámetros adicionales pasados al servicio del agente. +`Yields`: +`Union[StreamingChunk, ProvenanceEvent]`: Fragmentos del agente y eventos de procedencia. + +**Ejemplo:** + +```python +from trustgraph.api import Api, ExplainabilityClient, ProvenanceEvent +from trustgraph.api import AgentThought, AgentObservation, AgentAnswer + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +for item in flow.agent_explain( + question="What is the capital of France?", + user="trustgraph", + collection="default" +): + if isinstance(item, AgentThought): + print(f"[Thought] {item.content}") + elif isinstance(item, AgentObservation): + print(f"[Observation] {item.content}") + elif isinstance(item, AgentAnswer): + print(f"[Answer] {item.content}") + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.explain_id) + +# Fetch session trace after completion +if provenance_ids: + trace = explain_client.fetch_agent_trace( + provenance_ids[0], # Session URI is first + graph="urn:graph:retrieval", + user="trustgraph", + collection="default" + ) +``` + +### `document_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Consultar fragmentos de documentos utilizando similitud semántica. + +**Argumentos:** + +`text`: Texto de consulta para la búsqueda semántica +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`limit`: Número máximo de resultados (por defecto: 10) +`**kwargs`: Parámetros adicionales pasados al servicio + +**Retorna:** dict: Resultados de la consulta con los ID de los fragmentos de los documentos coincidentes + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "...", "score": 0.95}, ...]} +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Ejecutar una consulta RAG basada en documentos con transmisión opcional. + +Utiliza incrustaciones vectoriales para encontrar fragmentos de documentos relevantes y luego genera +una respuesta utilizando un LLM. El modo de transmisión entrega resultados de forma incremental. + +**Argumentos:** + +`query`: Consulta en lenguaje natural +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`doc_limit`: Número máximo de fragmentos de documentos a recuperar (predeterminado: 10) +`streaming`: Habilitar el modo de transmisión (predeterminado: Falso) +`**kwargs`: Parámetros adicionales pasados al servicio + +**Retorna:** Union[str, Iterator[str]]: Respuesta completa o flujo de fragmentos de texto + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming document RAG +for chunk in flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `document_rag_explain(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +Ejecutar una consulta RAG basada en documentos con soporte para la explicabilidad. + +Transmite tanto los fragmentos de contenido (RAGChunk) como los eventos de procedencia (ProvenanceEvent). +Los eventos de procedencia contienen URIs que se pueden recuperar utilizando ExplainabilityClient +para obtener información detallada sobre cómo se generó la respuesta. + +El rastro RAG del documento consiste en: +Pregunta: La consulta del usuario +Exploración: Fragmentos recuperados de la tienda de documentos (chunk_count) +Síntesis: La respuesta generada + +**Argumentos:** + +`query`: Consulta en lenguaje natural +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`doc_limit`: Número máximo de fragmentos de documento a recuperar (por defecto: 10) +`**kwargs`: Parámetros adicionales pasados al servicio +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: Fragmentos de contenido y eventos de procedencia + +**Ejemplo:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +for item in flow.document_rag_explain( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +): + if isinstance(item, RAGChunk): + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + # Fetch entity details + entity = explain_client.fetch_entity( + item.explain_id, + graph=item.explain_graph, + user="trustgraph", + collection="research-papers" + ) + print(f"Event: {entity}", file=sys.stderr) +``` + +### `embeddings(self, texts: list, **kwargs: Any) -> Dict[str, Any]` + +Generar incrustaciones vectoriales para uno o más textos. + +**Argumentos:** + +`texts`: Lista de textos de entrada para incrustar. +`**kwargs`: Parámetros adicionales pasados al servicio. + +**Retorna:** dict: Respuesta que contiene vectores (un conjunto por texto de entrada). + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.embeddings(["quantum computing"]) +vectors = result.get("vectors", []) +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Consultar entidades de un grafo de conocimiento utilizando similitud semántica. + +**Argumentos:** + +`text`: Texto de la consulta para la búsqueda semántica +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`limit`: Número máximo de resultados (por defecto: 10) +`**kwargs`: Parámetros adicionales pasados al servicio + +**Retorna:** dict: Resultados de la consulta con entidades similares + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Ejecutar una consulta RAG basada en grafos con transmisión opcional. + +Utiliza la estructura del grafo de conocimiento para encontrar el contexto relevante y luego genera +una respuesta utilizando un LLM. El modo de transmisión entrega los resultados de forma incremental. + +**Argumentos:** + +`query`: Consulta en lenguaje natural +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`max_subgraph_size`: Número máximo total de triples en el subgrafo (por defecto: 1000) +`max_subgraph_count`: Número máximo de subgrafos (por defecto: 5) +`max_entity_distance`: Profundidad máxima de recorrido (por defecto: 3) +`streaming`: Habilitar el modo de transmisión (por defecto: False) +`**kwargs`: Parámetros adicionales pasados al servicio + +**Retorna:** Union[str, Iterator[str]]: Respuesta completa o flujo de fragmentos de texto + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming graph RAG +for chunk in flow.graph_rag( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `graph_rag_explain(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +Ejecutar consulta RAG basada en grafos con soporte de explicabilidad. + +Transmite tanto fragmentos de contenido (RAGChunk) como eventos de procedencia (ProvenanceEvent). +Los eventos de procedencia contienen URIs que se pueden recuperar utilizando ExplainabilityClient +para obtener información detallada sobre cómo se generó la respuesta. + +**Argumentos:** + +`query`: Consulta en lenguaje natural +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`max_subgraph_size`: Número máximo total de triples en el subgrafo (predeterminado: 1000) +`max_subgraph_count`: Número máximo de subgrafos (predeterminado: 5) +`max_entity_distance`: Profundidad máxima de recorrido (predeterminado: 3) +`**kwargs`: Parámetros adicionales pasados al servicio +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: Fragmentos de contenido y eventos de procedencia + +**Ejemplo:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +response_text = "" + +for item in flow.graph_rag_explain( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists" +): + if isinstance(item, RAGChunk): + response_text += item.content + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.provenance_id) + +# Fetch explainability details +for prov_id in provenance_ids: + entity = explain_client.fetch_entity( + prov_id, + graph="urn:graph:retrieval", + user="trustgraph", + collection="scientists" + ) + print(f"Entity: {entity}") +``` + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]` + +Ejecutar una herramienta de Protocolo de Contexto de Modelo (MCP). + +**Argumentos:** + +`name`: Nombre/identificador de la herramienta +`parameters`: Diccionario de parámetros de la herramienta +`**kwargs`: Parámetros adicionales pasados al servicio + +**Retorna:** dict: Resultado de la ejecución de la herramienta + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Ejecutar una plantilla de prompt con transmisión opcional. + +**Argumentos:** + +`id`: Identificador de la plantilla de prompt. +`variables`: Diccionario de mapeos de nombres de variables a valores. +`streaming`: Habilitar el modo de transmisión (predeterminado: False). +`**kwargs`: Parámetros adicionales pasados al servicio. + +**Retorna:** Union[str, Iterator[str]]: Respuesta completa o flujo de fragmentos de texto. + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming prompt execution +for chunk in flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"}, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Consulta datos de filas utilizando la similitud semántica en campos indexados. + +Encuentra filas cuyos valores de campos indexados son semánticamente similares a +el texto de entrada, utilizando incrustaciones vectoriales. Esto permite la coincidencia difusa/semántica +en datos estructurados. + +**Argumentos:** + +`text`: Texto de consulta para la búsqueda semántica +`schema_name`: Nombre del esquema para buscar +`user`: Identificador de usuario/espacio de claves (predeterminado: "trustgraph") +`collection`: Identificador de colección (predeterminado: "default") +`index_name`: Nombre de índice opcional para filtrar la búsqueda a un índice específico +`limit`: Número máximo de resultados (predeterminado: 10) +`**kwargs`: Parámetros adicionales pasados al servicio + +**Retorna:** dict: Resultados de la consulta con coincidencias que contienen index_name, index_value, text y score + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict[str, Any] | None = None, operation_name: str | None = None, **kwargs: Any) -> Dict[str, Any]` + +Ejecutar una consulta GraphQL contra filas estructuradas. + +**Argumentos:** + +`query`: Cadena de consulta GraphQL +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`variables`: Diccionario opcional de variables de consulta +`operation_name`: Nombre de operación opcional para documentos de múltiples operaciones +`**kwargs`: Parámetros adicionales pasados al servicio + +**Retorna:** dict: Respuesta GraphQL con datos, errores y/o extensiones + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) +``` + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs) -> str | Iterator[str]` + +Ejecutar la finalización de texto con transmisión opcional. + +**Argumentos:** + +`system`: Instrucción del sistema que define el comportamiento del asistente. +`prompt`: Instrucción/pregunta del usuario. +`streaming`: Habilitar el modo de transmisión (predeterminado: False). +`**kwargs`: Parámetros adicionales pasados al servicio. + +**Retorna:** Union[str, Iterator[str]]: Respuesta completa o flujo de fragmentos de texto. + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Non-streaming +response = flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=False +) +print(response) + +# Streaming +for chunk in flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `triples_query(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, **kwargs: Any) -> List[Dict[str, Any]]` + +Consultar triples del grafo de conocimiento utilizando la coincidencia de patrones. + +**Argumentos:** + +`s`: Filtro de sujeto - Cadena URI, diccionario de términos o None para comodín. +`p`: Filtro de predicado - Cadena URI, diccionario de términos o None para comodín. +`o`: Filtro de objeto - Cadena URI/literal, diccionario de términos o None para comodín. +`g`: Filtro de grafo con nombre - Cadena URI o None para todos los grafos. +`user`: Identificador de usuario/espacio de claves (opcional). +`collection`: Identificador de colección (opcional). +`limit`: Número máximo de resultados a devolver (por defecto: 100). +`**kwargs`: Parámetros adicionales pasados al servicio. + +**Retorna:** List[Dict]: Lista de triples coincidentes en formato de cable. + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s="http://example.org/person/marie-curie", + user="trustgraph", + collection="scientists" +) + +# Query with named graph filter +triples = flow.triples_query( + s="urn:trustgraph:session:abc123", + g="urn:graph:retrieval", + user="trustgraph", + collection="default" +) +``` + +### `triples_query_stream(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, batch_size: int = 20, **kwargs: Any) -> Iterator[List[Dict[str, Any]]]` + +Consultar triples del grafo de conocimiento con lotes de transmisión. + +Produce lotes de triples a medida que llegan, reduciendo el tiempo para obtener el primer resultado +y la sobrecarga de memoria para conjuntos de resultados grandes. + +**Argumentos:** + +`s`: Filtro de sujeto - Cadena URI, diccionario de términos o None para comodín +`p`: Filtro de predicado - Cadena URI, diccionario de términos o None para comodín +`o`: Filtro de objeto - Cadena URI/literal, diccionario de términos o None para comodín +`g`: Filtro de grafo con nombre - Cadena URI o None para todos los grafos +`user`: Identificador de usuario/espacio de claves (opcional) +`collection`: Identificador de colección (opcional) +`limit`: Número máximo de resultados a devolver (por defecto: 100) +`batch_size`: Triples por lote (por defecto: 20) +`**kwargs`: Parámetros adicionales pasados al servicio +`Yields`: +`List[Dict]`: Lotes de triples en formato de cable + +**Ejemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +for batch in flow.triples_query_stream( + user="trustgraph", + collection="default" +): + for triple in batch: + print(triple["s"], triple["p"], triple["o"]) +``` + + +-- + +## `AsyncSocketClient` + +```python +from trustgraph.api import AsyncSocketClient +``` + +Cliente WebSocket asíncrono + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None)` + +Inicializar self. Consulte help(type(self)) para obtener la firma precisa. + +### `aclose(self)` + +Cerrar conexión WebSocket + +### `flow(self, flow_id: str)` + +Obtener la instancia de flujo asíncrono para operaciones de WebSocket + + +-- + +## `AsyncSocketFlowInstance` + +```python +from trustgraph.api import AsyncSocketFlowInstance +``` + +Flujo de WebSocket asíncrono. + +### Métodos + +### `__init__(self, client: trustgraph.api.async_socket_client.AsyncSocketClient, flow_id: str)` + +Inicializar self. Consulte help(type(self)) para obtener la firma correcta. + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: list | None = None, streaming: bool = False, **kwargs) -> Dict[str, Any] | AsyncIterator` + +Agente con transmisión opcional. + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs)` + +Documento RAG con transmisión opcional. + +### `embeddings(self, texts: list, **kwargs)` + +Generar incrustaciones de texto. + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs)` + +Consultar incrustaciones de grafos para búsqueda semántica. + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs)` + +RAG de grafos con transmisión opcional. + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs)` + +Ejecutar herramienta MCP. + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs)` + +Ejecutar prompt con transmisión opcional. + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs)` + +Consultar incrustaciones de filas para búsqueda semántica en datos estructurados. + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs)` + +Consulta GraphQL contra filas estructuradas. + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs)` + +Completar texto con transmisión opcional. + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs)` + +Consulta de patrones triples. + + +-- + +### `build_term(value: Any, term_type: str | None = None, datatype: str | None = None, language: str | None = None) -> Dict[str, Any] | None` + +Construir un diccionario de términos en formato de cable a partir de un valor. + +Reglas de detección automática (cuando term_type es None): + Ya es un diccionario con la clave 't' -> devolver tal cual (ya es un Term) + Comienza con http://, https://, urn: -> IRI + Está encerrado entre < (por ejemplo, ) -> IRI (se eliminan los corchetes) + Cualquier otra cosa -> literal + +**Argumentos:** + +`value`: El valor del término (cadena, diccionario o None). +`term_type`: Uno de 'iri', 'literal' o None para la detección automática. +`datatype`: Tipo de datos para objetos literales (por ejemplo, xsd:integer). +`language`: Etiqueta de idioma para objetos literales (por ejemplo, en). + +**Devuelve:** dict: Diccionario de términos en formato de cable, o None si el valor es None. + + +-- + +## `BulkClient` + +```python +from trustgraph.api import BulkClient +``` + +Cliente para operaciones masivas sincrónicas para la importación/exportación. + +Proporciona una transferencia de datos masiva eficiente a través de WebSocket para conjuntos de datos grandes. +Envuelve las operaciones asíncronas de WebSocket con generadores sincrónicos para facilitar su uso. + +Nota: Para un soporte asíncrono real, utilice AsyncBulkClient en su lugar. + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicializa el cliente de operaciones masivas sincrónico. + +**Argumentos:** + +`url`: URL base para la API de TrustGraph (HTTP/HTTPS se convertirá a WS/WSS) +`timeout`: Tiempo de espera de WebSocket en segundos +`token`: Token de portador opcional para la autenticación + +### `close(self) -> None` + +Cierra las conexiones. + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Exporta masivamente las incrustaciones de documentos desde un flujo. + +Descarga de forma eficiente todas las incrustaciones de fragmentos de documentos a través de la transmisión de WebSocket. + +**Argumentos:** + +`flow`: Identificador del flujo +`**kwargs`: Parámetros adicionales (reservados para uso futuro) + +**Devuelve:** Iterator[Dict[str, Any]]: Flujo de diccionarios de incrustaciones + +**Ejemplo:** + +```python +bulk = api.bulk() + +# Export and process document embeddings +for embedding in bulk.export_document_embeddings(flow="default"): + chunk_id = embedding.get("chunk_id") + vector = embedding.get("embedding") + print(f"{chunk_id}: {len(vector)} dimensions") +``` + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Exportación masiva de contextos de entidades desde un flujo. + +Descarga de manera eficiente toda la información del contexto de la entidad a través de transmisión WebSocket. + +**Argumentos:** + +`flow`: Identificador del flujo. +`**kwargs`: Parámetros adicionales (reservados para uso futuro). + +**Retorna:** Iterator[Dict[str, Any]]: Flujo de diccionarios de contexto. + +**Ejemplo:** + +```python +bulk = api.bulk() + +# Export and process entity contexts +for context in bulk.export_entity_contexts(flow="default"): + entity = context.get("entity") + text = context.get("context") + print(f"{entity}: {text[:100]}...") +``` + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Exportación masiva de incrustaciones de grafos desde un flujo. + +Descarga de manera eficiente todas las incrustaciones de entidades de grafos a través de transmisión WebSocket. + +**Argumentos:** + +`flow`: Identificador del flujo. +`**kwargs`: Parámetros adicionales (reservados para uso futuro). + +**Retorna:** Iterator[Dict[str, Any]]: Flujo de diccionarios de incrustaciones. + +**Ejemplo:** + +```python +bulk = api.bulk() + +# Export and process embeddings +for embedding in bulk.export_graph_embeddings(flow="default"): + entity = embedding.get("entity") + vector = embedding.get("embedding") + print(f"{entity}: {len(vector)} dimensions") +``` + +### `export_triples(self, flow: str, **kwargs: Any) -> Iterator[trustgraph.api.types.Triple]` + +Exportación masiva de triples RDF desde un flujo. + +Descarga de manera eficiente todos los triples a través de transmisión WebSocket. + +**Argumentos:** + +`flow`: Identificador del flujo. +`**kwargs`: Parámetros adicionales (reservados para uso futuro). + +**Retorna:** Iterator[Triple]: Flujo de objetos Triple. + +**Ejemplo:** + +```python +bulk = api.bulk() + +# Export and process triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +### `import_document_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importación masiva de incrustaciones de documentos en un flujo. + +Carga de manera eficiente las incrustaciones de fragmentos de documentos a través de transmisión WebSocket +para su uso en consultas RAG de documentos. + +**Argumentos:** + +`flow`: Identificador del flujo. +`embeddings`: Iterador que produce diccionarios de incrustaciones. +`**kwargs`: Parámetros adicionales (reservados para uso futuro). + +**Ejemplo:** + +```python +bulk = api.bulk() + +# Generate document embeddings to import +def doc_embedding_generator(): + yield {"chunk_id": "doc1/p0/c0", "embedding": [0.1, 0.2, ...]} + yield {"chunk_id": "doc1/p0/c1", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_document_embeddings( + flow="default", + embeddings=doc_embedding_generator() +) +``` + +### `import_entity_contexts(self, flow: str, contexts: Iterator[Dict[str, Any]], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +Importación masiva de contextos de entidades en un flujo. + +Carga de manera eficiente la información del contexto de la entidad a través de transmisión WebSocket. +Los contextos de entidades proporcionan un contexto textual adicional sobre las entidades del gráfico +para mejorar el rendimiento de RAG. + +**Argumentos:** + +`flow`: Identificador del flujo. +`contexts`: Iterador que devuelve diccionarios de contexto. +`metadata`: Diccionario de metadatos con id, metadatos, usuario, colección. +`batch_size`: Número de contextos por lote (por defecto 100). +`**kwargs`: Parámetros adicionales (reservados para uso futuro). + +**Ejemplo:** + +```python +bulk = api.bulk() + +# Generate entity contexts to import +def context_generator(): + yield {"entity": {"v": "entity1", "e": True}, "context": "Description..."} + yield {"entity": {"v": "entity2", "e": True}, "context": "Description..."} + # ... more contexts + +bulk.import_entity_contexts( + flow="default", + contexts=context_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + +### `import_graph_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importación masiva de incrustaciones de grafos en un flujo. + +Carga de manera eficiente las incrustaciones de entidades de grafos a través de transmisión WebSocket. + +**Argumentos:** + +`flow`: Identificador del flujo. +`embeddings`: Iterador que produce diccionarios de incrustaciones. +`**kwargs`: Parámetros adicionales (reservados para uso futuro). + +**Ejemplo:** + +```python +bulk = api.bulk() + +# Generate embeddings to import +def embedding_generator(): + yield {"entity": "entity1", "embedding": [0.1, 0.2, ...]} + yield {"entity": "entity2", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_graph_embeddings( + flow="default", + embeddings=embedding_generator() +) +``` + +### `import_rows(self, flow: str, rows: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importación masiva de filas estructuradas en un flujo. + +Carga de manera eficiente datos estructurados a través de transmisión WebSocket +para su uso en consultas GraphQL. + +**Argumentos:** + +`flow`: Identificador del flujo +`rows`: Iterador que produce diccionarios de filas +`**kwargs`: Parámetros adicionales (reservados para uso futuro) + +**Ejemplo:** + +```python +bulk = api.bulk() + +# Generate rows to import +def row_generator(): + yield {"id": "row1", "name": "Row 1", "value": 100} + yield {"id": "row2", "name": "Row 2", "value": 200} + # ... more rows + +bulk.import_rows( + flow="default", + rows=row_generator() +) +``` + +### `import_triples(self, flow: str, triples: Iterator[trustgraph.api.types.Triple], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +Importación masiva de triples RDF en un flujo. + +Carga de manera eficiente un gran número de triples a través de transmisión WebSocket. + +**Argumentos:** + +`flow`: Identificador del flujo. +`triples`: Iterador que produce objetos Triple. +`metadata`: Diccionario de metadatos con id, metadatos, usuario, colección. +`batch_size`: Número de triples por lote (por defecto 100). +`**kwargs`: Parámetros adicionales (reservados para uso futuro). + +**Ejemplo:** + +```python +from trustgraph.api import Triple + +bulk = api.bulk() + +# Generate triples to import +def triple_generator(): + yield Triple(s="subj1", p="pred", o="obj1") + yield Triple(s="subj2", p="pred", o="obj2") + # ... more triples + +# Import triples +bulk.import_triples( + flow="default", + triples=triple_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + + +-- + +## `AsyncBulkClient` + +```python +from trustgraph.api import AsyncBulkClient +``` + +Cliente para operaciones masivas asíncronas. + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicializar self. Consulte help(type(self)) para obtener la firma precisa. + +### `aclose(self) -> None` + +Cerrar conexiones. + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +Exportación masiva de incrustaciones de documentos a través de WebSocket. + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +Exportación masiva de contextos de entidades a través de WebSocket. + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +Exportación masiva de incrustaciones de grafos a través de WebSocket. + +### `export_triples(self, flow: str, **kwargs: Any) -> AsyncIterator[trustgraph.api.types.Triple]` + +Exportación masiva de triples a través de WebSocket. + +### `import_document_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importación masiva de incrustaciones de documentos a través de WebSocket. + +### `import_entity_contexts(self, flow: str, contexts: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importación masiva de contextos de entidades a través de WebSocket. + +### `import_graph_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importación masiva de incrustaciones de grafos a través de WebSocket. + +### `import_rows(self, flow: str, rows: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importación masiva de filas a través de WebSocket. + +### `import_triples(self, flow: str, triples: AsyncIterator[trustgraph.api.types.Triple], **kwargs: Any) -> None` + +Importación masiva de triples a través de WebSocket. + + +-- + +## `Metrics` + +```python +from trustgraph.api import Metrics +``` + +Cliente de métricas sincrónicas + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicializar self. Consulte help(type(self)) para obtener la firma precisa. + +### `get(self) -> str` + +Obtener métricas de Prometheus como texto + + +-- + +## `AsyncMetrics` + +```python +from trustgraph.api import AsyncMetrics +``` + +Cliente de métricas asíncronas + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicializar self. Consulte help(type(self)) para obtener la firma correcta. + +### `aclose(self) -> None` + +Cerrar conexiones + +### `get(self) -> str` + +Obtener métricas de Prometheus como texto + + +-- + +## `ExplainabilityClient` + +```python +from trustgraph.api import ExplainabilityClient +``` + +Cliente para obtener entidades de explicabilidad con manejo de consistencia eventual. + +Utiliza la detección de quiescencia: obtener, esperar, obtener de nuevo, comparar. +Si los resultados son los mismos, los datos son estables. + +### Métodos + +### `__init__(self, flow_instance, retry_delay: float = 0.2, max_retries: int = 10)` + +Inicializar el cliente de explicabilidad. + +**Argumentos:** + +`flow_instance`: Una instancia de SocketFlowInstance para consultar triples. +`retry_delay`: Retraso entre reintentos en segundos (por defecto: 0.2). +`max_retries`: Número máximo de intentos de reintento (por defecto: 10). + +### `detect_session_type(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> str` + +Detectar si una sesión es de tipo GraphRAG o Agent. + +**Argumentos:** + +`session_uri`: La URI de la sesión/pregunta. +`graph`: Grafo nombrado. +`user`: Identificador de usuario/espacio de claves. +`collection`: Identificador de colección. + +**Retorna:** "graphrag" o "agent". + +### `fetch_agent_trace(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Obtener el rastro completo del Agent a partir de una URI de sesión. + +Sigue la cadena de procedencia: Pregunta -> Análisis(es) -> Conclusión. + +**Argumentos:** + +`session_uri`: La URI de la sesión/pregunta del agente. +`graph`: Grafo nombrado (por defecto: urn:graph:retrieval). +`user`: Identificador de usuario/espacio de claves. +`collection`: Identificador de colección. +`api`: Instancia de la API de TrustGraph para el acceso al bibliotecario (opcional). +`max_content`: Longitud máxima del contenido para la conclusión. + +**Retorna:** Diccionario con la pregunta, las iteraciones (lista de Análisis) y las entidades de conclusión. + +### `fetch_docrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Obtener el rastro completo de DocumentRAG a partir de una URI de pregunta. + +Sigue la cadena de procedencia: + Pregunta -> Fundamentación -> Exploración -> Síntesis. + +**Argumentos:** + +`question_uri`: La URI de la entidad de pregunta. +`graph`: Grafo nombrado (por defecto: urn:graph:retrieval). +`user`: Identificador de usuario/espacio de claves. +`collection`: Identificador de colección. +`api`: Instancia de la API de TrustGraph para el acceso al bibliotecario (opcional). +`max_content`: Longitud máxima del contenido para la síntesis. + +**Retorna:** Diccionario con la pregunta, la fundamentación, la exploración y las entidades de síntesis. + +### `fetch_document_content(self, document_uri: str, api: Any, user: str | None = None, max_content: int = 10000) -> str` + +Obtener contenido del bibliotecario por URI de documento. + +**Argumentos:** + +`document_uri`: La URI del documento en el bibliotecario. +`api`: Instancia de la API de TrustGraph para el acceso al bibliotecario. +`user`: Identificador de usuario para el bibliotecario. +`max_content`: Longitud máxima del contenido a retornar. + +**Retorna:** El contenido del documento como una cadena. + +### `fetch_edge_selection(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.EdgeSelection | None` + +Obtener una entidad de selección de borde (utilizada por Focus). + +**Argumentos:** + +`uri`: La URI de la selección de borde. +`graph`: Grafo nombrado a consultar. +`user`: Identificador de usuario/espacio de claves. +`collection`: Identificador de colección. + +**Retorna:** EdgeSelection o None si no se encuentra. + +### `fetch_entity(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.ExplainEntity | None` + +Obtener una entidad de explicabilidad por URI con manejo de consistencia eventual. + +Utiliza la detección de quiescencia: +1. Obtener triples para el URI +2. Si no hay resultados, reintentar +3. Si hay resultados, esperar y obtener de nuevo +4. Si los resultados son los mismos, los datos son estables: analizar y devolver +5. Si los resultados son diferentes, los datos aún se están escribiendo: reintentar + +**Argumentos:** + +`uri`: El URI de la entidad a obtener +`graph`: Grafo con nombre para consultar (por ejemplo, "urn:graph:retrieval") +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección + +**Devuelve:** Subclase ExplainEntity o None si no se encuentra + +### `fetch_focus_with_edges(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.Focus | None` + +Obtener una entidad Focus y todas sus selecciones de aristas. + +**Argumentos:** + +`uri`: El URI de la entidad Focus +`graph`: Grafo con nombre para consultar +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección + +**Devuelve:** Focus con edge_selections pobladas, o None + +### `fetch_graphrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Obtener el rastro completo de GraphRAG a partir de un URI de pregunta. + +Sigue la cadena de procedencia: Pregunta -> Grounding -> Exploración -> Focus -> Síntesis + +**Argumentos:** + +`question_uri`: El URI de la entidad de pregunta +`graph`: Grafo (por defecto: urn:graph:retrieval) +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`api`: Instancia de la API TrustGraph para el acceso de bibliotecario (opcional) +`max_content`: Longitud máxima del contenido para la síntesis + +**Devuelve:** Diccionario con las entidades de pregunta, grounding, exploración, focus y síntesis + +### `list_sessions(self, graph: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 50) -> List[trustgraph.api.explainability.Question]` + +Listar todas las sesiones de explicabilidad (preguntas) en una colección. + +**Argumentos:** + +`graph`: Grafo (por defecto: urn:graph:retrieval) +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección +`limit`: Número máximo de sesiones a devolver + +**Devuelve:** Lista de entidades de Pregunta ordenadas por marca de tiempo (más reciente primero) + +### `resolve_edge_labels(self, edge: Dict[str, str], user: str | None = None, collection: str | None = None) -> Tuple[str, str, str]` + +Resolver las etiquetas para todos los componentes de una tripleta de arista. + +**Argumentos:** + +`edge`: Diccionario con claves "s", "p" y "o" +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección + +**Devuelve:** Tupla de (s_label, p_label, o_label) + +### `resolve_label(self, uri: str, user: str | None = None, collection: str | None = None) -> str` + +Resolver rdfs:label para un URI, con almacenamiento en caché. + +**Argumentos:** + +`uri`: El URI para obtener la etiqueta +`user`: Identificador de usuario/espacio de claves +`collection`: Identificador de colección + +**Devuelve:** La etiqueta si se encuentra, de lo contrario, el propio URI + + +-- + +## `ExplainEntity` + +```python +from trustgraph.api import ExplainEntity +``` + +Clase base para entidades de explicabilidad. + +**Campos:** + +`uri`: +`entity_type`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '') -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `Question` + +```python +from trustgraph.api import Question +``` + +Entidad de pregunta: la consulta del usuario que inició la sesión. + +**Campos:** + +`uri`: +`entity_type`: +`query`: +`timestamp`: +`question_type`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', query: str = '', timestamp: str = '', question_type: str = '') -> None` + +Inicializar self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `Exploration` + +```python +from trustgraph.api import Exploration +``` + +Entidad de exploración: bordes/fragmentos recuperados del almacén de conocimiento. + +**Campos:** + +`uri`: +`entity_type`: +`edge_count`: +`chunk_count`: +`entities`: typing.List[str] + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', edge_count: int = 0, chunk_count: int = 0, entities: List[str] = ) -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `Focus` + +```python +from trustgraph.api import Focus +``` + +Entidad de enfoque: bordes seleccionados con razonamiento LLM (solo GraphRAG). + +**Campos:** + +`uri`: +`entity_type`: +`selected_edge_uris`: typing.List[str] +`edge_selections`: typing.List[trustgraph.api.explainability.EdgeSelection] + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', selected_edge_uris: List[str] = , edge_selections: List[trustgraph.api.explainability.EdgeSelection] = ) -> None` + +Inicializa self. Consulta help(type(self)) para obtener la firma precisa. + + +-- + +## `Synthesis` + +```python +from trustgraph.api import Synthesis +``` + +Entidad de síntesis: la respuesta final. + +**Campos:** + +`uri`: +`entity_type`: +`document`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +Inicializa self. Consulta help(type(self)) para obtener la firma precisa. + + +-- + +## `Analysis` + +```python +from trustgraph.api import Analysis +``` + +Entidad de análisis: un ciclo de pensar/actuar/observar (solo para el Agente). + +**Campos:** + +`uri`: +`entity_type`: +`action`: +`arguments`: +`thought`: +`observation`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', action: str = '', arguments: str = '', thought: str = '', observation: str = '') -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma correcta. + + +-- + +## `Conclusion` + +```python +from trustgraph.api import Conclusion +``` + +Conclusión de la entidad - respuesta final (solo para el agente). + +**Campos:** + +`uri`: +`entity_type`: +`document`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +Inicializa self. Consulta help(type(self)) para obtener la firma precisa. + + +-- + +## `EdgeSelection` + +```python +from trustgraph.api import EdgeSelection +``` + +Un borde seleccionado con razonamiento del paso GraphRAG Focus. + +**Campos:** + +`uri`: +`edge`: typing.Dict[str, str] | None +`reasoning`: + +### Métodos + +### `__init__(self, uri: str, edge: Dict[str, str] | None = None, reasoning: str = '') -> None` + +Inicializa self. Consulta help(type(self)) para obtener la firma precisa. + + +-- + +### `wire_triples_to_tuples(wire_triples: List[Dict[str, Any]]) -> List[Tuple[str, str, Any]]` + +Convierte las triples en formato de cable a tuplas (s, p, o). + + +-- + +### `extract_term_value(term: Dict[str, Any]) -> Any` + +Extrae el valor de un diccionario de términos en formato de cable. + + +-- + +## `Triple` + +```python +from trustgraph.api import Triple +``` + +Triple RDF que representa una declaración de un grafo de conocimiento. + +**Campos:** + +`s`: +`p`: +`o`: + +### Métodos + +### `__init__(self, s: str, p: str, o: str) -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `Uri` + +```python +from trustgraph.api import Uri +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +Crea un nuevo objeto de cadena a partir del objeto dado. Si se especifica encoding o +errors, entonces el objeto debe exponer un búfer de datos +que se decodificará utilizando la codificación y el controlador de errores especificados. +De lo contrario, devuelve el resultado de object.__str__() (si está definido) +o repr(object). +encoding tiene como valor predeterminado 'utf-8'. +errors tiene como valor predeterminado 'strict'. + +### Métodos + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `Literal` + +```python +from trustgraph.api import Literal +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +Crea un nuevo objeto de cadena a partir del objeto dado. Si se especifica encoding o +errors, entonces el objeto debe exponer un búfer de datos +que se decodificará utilizando la codificación y el controlador de errores especificados. +De lo contrario, devuelve el resultado de object.__str__() (si está definido) +o repr(object). +encoding tiene como valor predeterminado 'utf-8'. +errors tiene como valor predeterminado 'strict'. + +### Métodos + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `ConfigKey` + +```python +from trustgraph.api import ConfigKey +``` + +Identificador de clave de configuración. + +**Campos:** + +`type`: +`key`: + +### Métodos + +### `__init__(self, type: str, key: str) -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `ConfigValue` + +```python +from trustgraph.api import ConfigValue +``` + +Par clave-valor de configuración. + +**Campos:** + +`type`: +`key`: +`value`: + +### Métodos + +### `__init__(self, type: str, key: str, value: str) -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `DocumentMetadata` + +```python +from trustgraph.api import DocumentMetadata +``` + +Metadatos para un documento en la biblioteca. + +**Atributos:** + +`parent_id: Parent document ID for child documents (empty for top`: level docs) + +**Campos:** + +`id`: +`time`: +`kind`: +`title`: +`comments`: +`metadata`: typing.List[trustgraph.api.types.Triple] +`user`: +`tags`: typing.List[str] +`parent_id`: +`document_type`: + +### Métodos + +### `__init__(self, id: str, time: datetime.datetime, kind: str, title: str, comments: str, metadata: List[trustgraph.api.types.Triple], user: str, tags: List[str], parent_id: str = '', document_type: str = 'source') -> None` + +Inicializar self. Consulte help(type(self)) para obtener la firma correcta. + + +-- + +## `ProcessingMetadata` + +```python +from trustgraph.api import ProcessingMetadata +``` + +Metadatos para un trabajo de procesamiento de documentos activo. + +**Campos:** + +`id`: +`document_id`: +`time`: +`flow`: +`user`: +`collection`: +`tags`: typing.List[str] + +### Métodos + +### `__init__(self, id: str, document_id: str, time: datetime.datetime, flow: str, user: str, collection: str, tags: List[str]) -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma correcta. + + +-- + +## `CollectionMetadata` + +```python +from trustgraph.api import CollectionMetadata +``` + +Metadatos para una colección de datos. + +Las colecciones proporcionan un agrupamiento lógico y un aislamiento para documentos y +datos de grafos de conocimiento. + +**Atributos:** + +`name: Human`: nombre de colección legible + +**Campos:** + +`user`: +`collection`: +`name`: +`description`: +`tags`: typing.List[str] + +### Métodos + +### `__init__(self, user: str, collection: str, name: str, description: str, tags: List[str]) -> None` + +Inicializar self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `StreamingChunk` + +```python +from trustgraph.api import StreamingChunk +``` + +Clase base para fragmentos de respuesta de transmisión. + +Se utiliza para operaciones de transmisión basadas en WebSocket, donde las respuestas se entregan +de forma incremental a medida que se generan. + +**Campos:** + +`content`: +`end_of_message`: + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False) -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `AgentThought` + +```python +from trustgraph.api import AgentThought +``` + +Fragmento del razonamiento/proceso de pensamiento del agente. + +Representa el razonamiento interno o los pasos de planificación del agente durante la ejecución. +Estos fragmentos muestran cómo el agente está pensando sobre el problema. + +**Campos:** + +`content`: +`end_of_message`: +`chunk_type`: + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'thought') -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `AgentObservation` + +```python +from trustgraph.api import AgentObservation +``` + +Fragmento de observación de la ejecución de la herramienta del agente. + +Representa el resultado u observación de la ejecución de una herramienta o acción. +Estos fragmentos muestran lo que el agente aprendió al usar herramientas. + +**Campos:** + +`content`: +`end_of_message`: +`chunk_type`: + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'observation') -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `AgentAnswer` + +```python +from trustgraph.api import AgentAnswer +``` + +Fragmento de la respuesta final del agente. + +Representa la respuesta final del agente al usuario después de completar +su razonamiento y el uso de herramientas. + +**Atributos:** + +`chunk_type: Always "final`: answer" + +**Campos:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_dialog`: + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'final-answer', end_of_dialog: bool = False) -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `RAGChunk` + +```python +from trustgraph.api import RAGChunk +``` + +Fragmento de transmisión RAG (Generación Aumentada por Recuperación). + +Utilizado para transmitir respuestas de RAG de grafos, RAG de documentos, finalización de texto, +y otros servicios generativos. + +**Campos:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_stream`: +`error`: typing.Dict[str, str] | None + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'rag', end_of_stream: bool = False, error: Dict[str, str] | None = None) -> None` + +Inicializa self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `ProvenanceEvent` + +```python +from trustgraph.api import ProvenanceEvent +``` + +Evento de procedencia para la explicabilidad. + +Emitido durante las consultas de GraphRAG cuando el modo de explicabilidad está habilitado. +Cada evento representa un nodo de procedencia creado durante el procesamiento de la consulta. + +**Campos:** + +`explain_id`: +`explain_graph`: +`event_type`: + +### Métodos + +### `__init__(self, explain_id: str, explain_graph: str = '', event_type: str = '') -> None` + +Inicializar self. Consulte help(type(self)) para obtener la firma precisa. + + +-- + +## `ProtocolException` + +```python +from trustgraph.api import ProtocolException +``` + +Se genera cuando ocurren errores en el protocolo WebSocket. + + +-- + +## `TrustGraphException` + +```python +from trustgraph.api import TrustGraphException +``` + +Clase base para todos los errores del servicio TrustGraph. + + +-- + +## `AgentError` + +```python +from trustgraph.api import AgentError +``` + +Error en el servicio del agente + + +-- + +## `ConfigError` + +```python +from trustgraph.api import ConfigError +``` + +Error del servicio de configuración + + +-- + +## `DocumentRagError` + +```python +from trustgraph.api import DocumentRagError +``` + +Error de recuperación de documentos RAG. + + +-- + +## `FlowError` + +```python +from trustgraph.api import FlowError +``` + +Error de gestión de flujo + + +-- + +## `GatewayError` + +```python +from trustgraph.api import GatewayError +``` + +Error de la API Gateway + + +-- + +## `GraphRagError` + +```python +from trustgraph.api import GraphRagError +``` + +Error de recuperación de Graph RAG. + + +-- + +## `LLMError` + +```python +from trustgraph.api import LLMError +``` + +Error del servicio de modelo de lenguaje grande. + + +-- + +## `LoadError` + +```python +from trustgraph.api import LoadError +``` + +Error de carga de datos + + +-- + +## `LookupError` + +```python +from trustgraph.api import LookupError +``` + +Error de búsqueda/consulta + + +-- + +## `NLPQueryError` + +```python +from trustgraph.api import NLPQueryError +``` + +Error en el servicio de consulta de procesamiento del lenguaje natural. + + +-- + +## `RowsQueryError` + +```python +from trustgraph.api import RowsQueryError +``` + +Error en el servicio de consulta de filas. + + +-- + +## `RequestError` + +```python +from trustgraph.api import RequestError +``` + +Error en el procesamiento de la solicitud. + + +-- + +## `StructuredQueryError` + +```python +from trustgraph.api import StructuredQueryError +``` + +Error en el servicio de consulta estructurada. + + +-- + +## `UnexpectedError` + +```python +from trustgraph.api import UnexpectedError +``` + +Error inesperado/desconocido + + +-- + +## `ApplicationException` + +```python +from trustgraph.api import ApplicationException +``` + +Clase base para todos los errores del servicio TrustGraph. + + +-- + diff --git a/docs/python-api.he.md b/docs/python-api.he.md new file mode 100644 index 00000000..bb274eb2 --- /dev/null +++ b/docs/python-api.he.md @@ -0,0 +1,4071 @@ +# מדריך הפניות ל-API של TrustGraph בפייתון + +## התקנה + +```bash +pip install trustgraph +``` + +## התחלה מהירה + +כל המחלקות והטיפוסים מיובאים מהחבילה `trustgraph.api`: + +```python +from trustgraph.api import Api, Triple, ConfigKey + +# Create API client +api = Api(url="http://localhost:8088/") + +# Get a flow instance +flow = api.flow().id("default") + +# Execute a graph RAG query +response = flow.graph_rag( + query="What are the main topics?", + user="trustgraph", + collection="default" +) +``` + +## תוכן עניינים + +### ליבה + +[Api](#api) + +### לקוחות זרימה + +[Flow](#flow) +[FlowInstance](#flowinstance) +[AsyncFlow](#asyncflow) +[AsyncFlowInstance](#asyncflowinstance) + +### לקוחות WebSocket + +[SocketClient](#socketclient) +[SocketFlowInstance](#socketflowinstance) +[AsyncSocketClient](#asyncsocketclient) +[AsyncSocketFlowInstance](#asyncsocketflowinstance) + +### פעולות מרובות + +[BulkClient](#bulkclient) +[AsyncBulkClient](#asyncbulkclient) + +### מדדים + +[Metrics](#metrics) +[AsyncMetrics](#asyncmetrics) + +### סוגי נתונים + +[Triple](#triple) +[ConfigKey](#configkey) +[ConfigValue](#configvalue) +[DocumentMetadata](#documentmetadata) +[ProcessingMetadata](#processingmetadata) +[CollectionMetadata](#collectionmetadata) +[StreamingChunk](#streamingchunk) +[AgentThought](#agentthought) +[AgentObservation](#agentobservation) +[AgentAnswer](#agentanswer) +[RAGChunk](#ragchunk) + +### חריגות + +[ProtocolException](#protocolexception) +[TrustGraphException](#trustgraphexception) +[AgentError](#agenterror) +[ConfigError](#configerror) +[DocumentRagError](#documentragerror) +[FlowError](#flowerror) +[GatewayError](#gatewayerror) +[GraphRagError](#graphragerror) +[LLMError](#llmerror) +[LoadError](#loaderror) +[LookupError](#lookuperror) +[NLPQueryError](#nlpqueryerror) +[RowsQueryError](#rowsqueryerror) +[RequestError](#requesterror) +[StructuredQueryError](#structuredqueryerror) +[UnexpectedError](#unexpectederror) +[ApplicationException](#applicationexception) + +-- + +## `Api` + +```python +from trustgraph.api import Api +``` + +לקוח API הראשי של TrustGraph לפעולות סינכרוניות ואסינכרוניות. + +מחלקה זו מספקת גישה לכל שירותי TrustGraph, כולל ניהול זרימות, +פעולות גרף ידע, עיבוד מסמכים, שאילתות RAG ועוד. היא תומכת +הן בדפוסי תקשורת מבוססי REST והן בדפוסי תקשורת מבוססי WebSocket. + +ניתן להשתמש בלקוח כמנהל הקשר לניקוי אוטומטי של משאבים: + ```python + with Api(url="http://localhost:8088/") as api: + result = api.flow().id("default").graph_rag(query="test") + ``` + +### שיטות + +### `__aenter__(self)` + +כניסה למנהל הקשר אסינכרוני. + +### `__aexit__(self, *args)` + +יציאה ממנהל הקשר האסינכרוני וסגירת חיבורים. + +### `__enter__(self)` + +כניסה למנהל הקשר סינכרוני. + +### `__exit__(self, *args)` + +יציאה ממנהל הקשר הסינכרוני וסגירת חיבורים. + +### `__init__(self, url='http://localhost:8088/', timeout=60, token: str | None = None)` + +אתחול לקוח ה-API של TrustGraph. + +**ארגומנטים:** + +`url`: כתובת הבסיס עבור ה-API של TrustGraph (ברירת מחדל: "http://localhost:8088/"") +`timeout`: זמן אחזור מקסימלי בשניות (ברירת מחדל: 60) +`token`: טוקן bearer אופציונלי לאימות + +**דוגמה:** + +```python +# Local development +api = Api() + +# Production with authentication +api = Api( + url="https://trustgraph.example.com/", + timeout=120, + token="your-api-token" +) +``` + +### `aclose(self)` + +סגור את כל החיבורים של הלקוח האסינכרוניים. + +שיטה זו סוגרת חיבורי WebSocket אסינכרוניים, פעולות סיטונאיות וחיבורי זרימה. +היא נקראת אוטומטית כאשר יוצאים מתוך מנהל הקשר האסינכרוני. + +**דוגמה:** + +```python +api = Api() +async_socket = api.async_socket() +# ... use async_socket +await api.aclose() # Clean up connections + +# Or use async context manager (automatic cleanup) +async with Api() as api: + async_socket = api.async_socket() + # ... use async_socket +# Automatically closed +``` + +### `async_bulk(self)` + +קבל לקוח לפעולות אסינכרוניות מרובות. + +מספק פעולות ייבוא/ייצוא מרובות בסגנון async/await באמצעות WebSocket +לטיפול יעיל בערכות נתונים גדולות. + +**מחזיר:** AsyncBulkClient: לקוח לפעולות אסינכרוניות מרובות. + +**דוגמה:** + +```python +async_bulk = api.async_bulk() + +# Export triples asynchronously +async for triple in async_bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import with async generator +async def triple_gen(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +await async_bulk.import_triples( + flow="default", + triples=triple_gen() +) +``` + +### `async_flow(self)` + +קבל לקוח זרימה מבוסס REST אסינכרוני. + +מספק גישה בסגנון async/await לפעולות זרימה. זה מועדף +עבור יישומי ומסגרות Python אסינכרוניות (FastAPI, aiohttp, וכו'). + +**מחזיר:** AsyncFlow: לקוח זרימה אסינכרוני + +**דוגמה:** + +```python +async_flow = api.async_flow() + +# List flows +flow_ids = await async_flow.list() + +# Execute operations +instance = async_flow.id("default") +result = await instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `async_metrics(self)` + +קבל לקוח מדדים אסינכרוני. + +מספק גישה בסגנון async/await למדדי Prometheus. + +**מחזיר:** AsyncMetrics: לקוח מדדים אסינכרוני + +**דוגמה:** + +```python +async_metrics = api.async_metrics() +prometheus_text = await async_metrics.get() +print(prometheus_text) +``` + +### `async_socket(self)` + +קבל לקוח WebSocket אסינכרוני לפעולות סטרימינג. + +מספק גישה ל-WebSocket בסגנון async/await עם תמיכה בסטרימינג. +זוהי השיטה המועדפת לסטרימינג אסינכרוני בפייתון. + +**מחזיר:** AsyncSocketClient: לקוח WebSocket אסינכרוני. + +**דוגמה:** + +```python +async_socket = api.async_socket() +flow = async_socket.flow("default") + +# Stream agent responses +async for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + +### `bulk(self)` + +קבל לקוח לפעולות סינכרוניות מרובות לצורך ייבוא/ייצוא. + +פעולות מרובות מאפשרות העברת כמויות גדולות של נתונים בצורה יעילה באמצעות חיבורי WebSocket, כולל משולשות, הטמעות, הקשרים של ישויות ואובייקטים. + +**מחזיר:** BulkClient: לקוח לפעולות סינכרוניות מרובות. + +**דוגמה:** + + +```python +bulk = api.bulk() + +# Export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import triples +def triple_generator(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +bulk.import_triples(flow="default", triples=triple_generator()) +``` + +### `close(self)` + +סגור את כל החיבורים של הלקוח הסינכרוניים. + +שיטה זו סוגרת חיבורי WebSocket וחיבורים לפעולות מרובות. +היא נקראת באופן אוטומטי כאשר יוצאים מתוך מנהל הקשר. + +**דוגמה:** + +```python +api = Api() +socket = api.socket() +# ... use socket +api.close() # Clean up connections + +# Or use context manager (automatic cleanup) +with Api() as api: + socket = api.socket() + # ... use socket +# Automatically closed +``` + +### `collection(self)` + +קבלת לקוח Collection לניהול אוספי נתונים. + +אוספים מארגנים מסמכים ונתוני גרף ידע לקבוצות +לוגיות לצורך בידוד ובקרת גישה. + +**מחזיר:** Collection: לקוח לניהול אוספים + +**דוגמה:** + +```python +collection = api.collection() + +# List collections +colls = collection.list_collections(user="trustgraph") + +# Update collection metadata +collection.update_collection( + user="trustgraph", + collection="default", + name="Default Collection", + description="Main data collection" +) +``` + +### `config(self)` + +קבל לקוח Config לניהול הגדרות תצורה. + +**מחזיר:** Config: לקוח לניהול תצורה + +**דוגמה:** + +```python +config = api.config() + +# Get configuration values +values = config.get([ConfigKey(type="llm", key="model")]) + +# Set configuration +config.put([ConfigValue(type="llm", key="model", value="gpt-4")]) +``` + +### `flow(self)` + +קבל לקוח Flow לניהול ולביצוע אינטראקציה עם זרימות. + +זרימות הן יחידות הביצוע העיקריות ב-TrustGraph, המספקות גישה ל +שירותים כמו סוכנים, שאילתות RAG, הטמעות ועיבוד מסמכים. + +**מחזיר:** Flow: לקוח לניהול זרימות + +**דוגמה:** + +```python +flow_client = api.flow() + +# List available blueprints +blueprints = flow_client.list_blueprints() + +# Get a specific flow instance +flow_instance = flow_client.id("default") +response = flow_instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `knowledge(self)` + +קבל לקוח Knowledge לניהול ליבות גרף ידע. + +**מחזיר:** לקוח לניהול גרף ידע: Knowledge + +**דוגמה:** + +```python +knowledge = api.knowledge() + +# List available KG cores +cores = knowledge.list_kg_cores(user="trustgraph") + +# Load a KG core +knowledge.load_kg_core(id="core-123", user="trustgraph") +``` + +### `library(self)` + +קבלת לקוח לספרייה לניהול מסמכים. + +הספרייה מספקת אחסון מסמכים, ניהול מטא-דאטה ו +תיאום זרימת עבודה לעיבוד. + +**החזר:** Library: לקוח לניהול ספריית מסמכים + +**דוגמה:** + +```python +library = api.library() + +# Add a document +library.add_document( + document=b"Document content", + id="doc-123", + metadata=[], + user="trustgraph", + title="My Document", + comments="Test document" +) + +# List documents +docs = library.get_documents(user="trustgraph") +``` + +### `metrics(self)` + +קבל לקוח מדדים סינכרוני למטרות ניטור. + +שולף מדדים בפורמט Prometheus מהשירות TrustGraph +לצורך ניטור וניתוח. + +**מחזיר:** מדדים: לקוח מדדים סינכרוני + +**דוגמה:** + +```python +metrics = api.metrics() +prometheus_text = metrics.get() +print(prometheus_text) +``` + +### `request(self, path, request)` + +ביצוע בקשת REST ברמה נמוכה. + +שיטה זו מיועדת בעיקר לשימוש פנימי, אך ניתן להשתמש בה לגישה ישירה +ל-API כאשר נדרש. + +**ארגומנטים:** + +`path`: נתיב נקודת הקצה של ה-API (ביחס לכתובת הבסיס) +`request`: מטען הבקשה כמילון + +**החזרות:** dict: אובייקט תגובה + +**מעלה:** + +`ProtocolException`: אם מצב התגובה אינו 200 או שהתגובה אינה JSON +`ApplicationException`: אם התגובה מכילה שגיאה + +**דוגמה:** + +```python +response = api.request("flow", { + "operation": "list-flows" +}) +``` + +### `socket(self)` + +קבל לקוח WebSocket סינכרוני לפעולות סטרימינג. + +חיבורי WebSocket מספקים תמיכה בסטרימינג לתגובות בזמן אמת +מסוכנים, שאילתות RAG והשלמות טקסט. שיטה זו מחזירה עטיפה סינכרונית +סביב פרוטוקול ה-WebSocket. + +**מחזיר:** SocketClient: לקוח WebSocket סינכרוני + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `Flow` + +```python +from trustgraph.api import Flow +``` + +לקוח לניהול זרימות עבור פעולות על תוכניות זרימה ומצבי זרימה. + +מחלקה זו מספקת שיטות לניהול תוכניות זרימה (תבניות) ו- +מצבי זרימה (זרימות פעילות). תוכניות זרימה מגדירות את המבנה ואת +הפרמטרים של הזרימות, בעוד שמצבי זרימה מייצגים זרימות פעילות שניתן +להפעיל שירותים. + +### שיטות + +### `__init__(self, api)` + +אתחול לקוח זרימה. + +**ארגומנטים:** + +`api`: מופע Api הורה לביצוע בקשות + +### `delete_blueprint(self, blueprint_name)` + +מחיקת תוכנית זרימה. + +**ארגומנטים:** + +`blueprint_name`: שם התוכנית למחיקה + +**דוגמה:** + +```python +api.flow().delete_blueprint("old-blueprint") +``` + +### `get(self, id)` + +קבלת ההגדרה של מופע זרימה פעיל. + +**ארגומנטים:** + +`id`: מזהה מופע זרימה + +**החזר:** dict: הגדרת מופע זרימה + +**דוגמה:** + +```python +flow_def = api.flow().get("default") +print(flow_def) +``` + +### `get_blueprint(self, blueprint_name)` + +קבלת הגדרה של תבנית זרימה לפי שם. + +**ארגומנטים:** + +`blueprint_name`: שם התבנית שיש לשלוף + +**החזר:** dict: הגדרת התבנית כמילון + +**דוגמה:** + +```python +blueprint = api.flow().get_blueprint("default") +print(blueprint) # Blueprint configuration +``` + +### `id(self, id='default')` + +קבלת מופע FlowInstance לביצוע פעולות על זרימה ספציפית. + +**ארגומנטים:** + +`id`: מזהה זרימה (ברירת מחדל: "default") + +**החזרות:** FlowInstance: מופע זרימה לפעולות שירות + +**דוגמה:** + +```python +flow = api.flow().id("my-flow") +response = flow.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `list(self)` + +רשום את כל מופעי ה-flow הפעילים. + +**מחזיר:** list[str]: רשימה של מזהי מופעי flow + +**דוגמה:** + +```python +flows = api.flow().list() +print(flows) # ['default', 'flow-1', 'flow-2', ...] +``` + +### `list_blueprints(self)` + +רשום את כל תבניות העבודה הזמינות. + +**מחזיר:** list[str]: רשימה של שמות תבניות. + +**דוגמה:** + +```python +blueprints = api.flow().list_blueprints() +print(blueprints) # ['default', 'custom-flow', ...] +``` + +### `put_blueprint(self, blueprint_name, definition)` + +יצירת או עדכון תבנית זרימה. + +**ארגומנטים:** + +`blueprint_name`: שם עבור התבנית +`definition`: מילון הגדרת התבנית + +**דוגמה:** + +```python +definition = { + "services": ["text-completion", "graph-rag"], + "parameters": {"model": "gpt-4"} +} +api.flow().put_blueprint("my-blueprint", definition) +``` + +### `request(self, path=None, request=None)` + +ביצוע בקשת API בתחום (flow). + +**ארגומנטים:** + +`path`: סיומת נתיב אופציונלית עבור נקודות קצה של flow. +`request`: מילון מטען בקשה. + +**מחזיר:** dict: אובייקט תגובה. + +**מעלה:** + +`RuntimeError`: אם פרמטר הבקשה לא מצוין. + +### `start(self, blueprint_name, id, description, parameters=None)` + +התחלת מופע flow חדש מתבנית (blueprint). + +**ארגומנטים:** + +`blueprint_name`: שם התבנית (blueprint) לשימוש. +`id`: מזהה ייחודי למופע ה-flow. +`description`: תיאור קריא. +`parameters`: מילון פרמטרים אופציונלי. + +**דוגמה:** + +```python +api.flow().start( + blueprint_name="default", + id="my-flow", + description="My custom flow", + parameters={"model": "gpt-4"} +) +``` + +### `stop(self, id)` + +עצירת מופע זרימה פעיל. + +**ארגומנטים:** + +`id`: מזהה של מופע הזרימה שיש לעצור. + +**דוגמה:** + +```python +api.flow().stop("my-flow") +``` + + +-- + +## `FlowInstance` + +```python +from trustgraph.api import FlowInstance +``` + +מופע לקוח של Flow לביצוע שירותים ב-flow ספציפי. + +מחלקה זו מספקת גישה לכל שירותי TrustGraph, כולל: +השלמת טקסט והטמעות +פעולות סוכן עם ניהול מצב +שאילתות RAG עבור גרפים ומסמכים +פעולות גרף ידע (טריפלטים, אובייקטים) +טעינה ועיבוד מסמכים +המרה משפה טבעית לשאילתת GraphQL +ניתוח נתונים מובנים וזיהוי סכימה +ביצוע כלי MCP +תבניות הנחיה + +לשירותים ניגשים באמצעות מופע Flow פעיל, המזוהה באמצעות מזהה. + +### שיטות + +### `__init__(self, api, id)` + +אתחול FlowInstance. + +**ארגומנטים:** + +`api`: לקוח Flow ראשי +`id`: מזהה מופע Flow + +### `agent(self, question, user='trustgraph', state=None, group=None, history=None)` + +ביצוע פעולת סוכן עם יכולות חשיבה ושימוש בכלים. + +סוכנים יכולים לבצע חשיבה רב-שלבית, להשתמש בכלים ולשמור על שיחה +מצב בין אינטראקציות. זו גרסה סינכרונית שאינה זורמת. + +**ארגומנטים:** + +`question`: שאלה או הוראה של משתמש +`user`: מזהה משתמש (ברירת מחדל: "trustgraph") +`state`: מילון מצב אופציונלי לשיחות עם מצב +`group`: מזהה קבוצה אופציונלי עבור הקשרים מרובי משתמשים +`history`: היסטוריית שיחה אופציונלית כרשימה של מילוני הודעות + +**מחזיר:** str: תשובה סופית של הסוכן + +**דוגמה:** + +```python +flow = api.flow().id("default") + +# Simple question +answer = flow.agent( + question="What is the capital of France?", + user="trustgraph" +) + +# With conversation history +history = [ + {"role": "user", "content": "Hello"}, + {"role": "assistant", "content": "Hi! How can I help?"} +] +answer = flow.agent( + question="Tell me about Paris", + user="trustgraph", + history=history +) +``` + +### `detect_type(self, sample)` + +זיהוי סוג הנתונים של דוגמת נתונים מובנים. + +**ארגומנטים:** + +`sample`: דוגמת נתונים לניתוח (תוכן מחרוזת) + +**החזרות:** מילון עם detected_type, confidence, ומטא-נתונים אופציונליים + +### `diagnose_data(self, sample, schema_name=None, options=None)` + +ביצוע אבחון נתונים משולב: זיהוי סוג ויצירת תיאור. + +**ארגומנטים:** + +`sample`: דוגמת נתונים לניתוח (תוכן מחרוזת) +`schema_name`: שם סכימה יעד אופציונלי ליצירת תיאור +`options`: פרמטרים אופציונליים (לדוגמה, מפריד עבור CSV) + +**החזרות:** מילון עם detected_type, confidence, descriptor, ומטא-נתונים + +### `document_embeddings_query(self, text, user, collection, limit=10)` + +שאילתת מקטעי מסמכים באמצעות דמיון סמנטי. + +מוצאת מקטעי מסמכים שהתוכן שלהם דומה מבחינה סמנטית לטקסט +הקלט, תוך שימוש בהטמעות וקטוריות. + +**ארגומנטים:** + +`text`: טקסט שאילתה לחיפוש סמנטי +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`limit`: מספר מקסימלי של תוצאות (ברירת מחדל: 10) + +**החזרות:** מילון: תוצאות שאילתה עם מקטעים המכילים chunk_id וציון + +**דוגמה:** + +```python +flow = api.flow().id("default") +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "doc1/p0/c0", "score": 0.95}, ...]} +``` + +### `document_rag(self, query, user='trustgraph', collection='default', doc_limit=10)` + +הפעל שאילתה של יצירת טקסט מבוססת אחזור מוגבר (RAG) על מסמכים. + +RAG מבוסס מסמכים משתמש בהטמעות וקטוריות כדי למצוא מקטעי מסמכים רלוונטיים, +ולאחר מכן מייצר תגובה באמצעות מודל שפה גדול (LLM) תוך שימוש במקטעים אלה כהקשר. + +**ארגומנטים:** + +`query`: שאילתה בשפה טבעית +`user`: מזהה משתמש/מרחב מפתחות (ברירת מחדל: "trustgraph") +`collection`: מזהה אוסף (ברירת מחדל: "default") +`doc_limit`: מספר מקסימלי של מקטעי מסמכים שיש לשלוף (ברירת מחדל: 10) + +**החזרות:** str: תגובה שנוצרה המשלבת הקשר של מסמכים + +**דוגמה:** + +```python +flow = api.flow().id("default") +response = flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts)` + +יצירת הטמעות וקטוריות עבור טקסט אחד או יותר. + +ממיר טקסטים לייצוגים וקטוריים צפופים המתאימים לחיפוש סמנטי +והשוואת דמיון. + +**ארגומנטים:** + +`texts`: רשימה של טקסטים קלט ליצירת הטמעות + +**החזרות:** list[list[list[float]]]: הטמעות וקטוריות, סט אחד לכל טקסט קלט + +**דוגמה:** + +```python +flow = api.flow().id("default") +vectors = flow.embeddings(["quantum computing"]) +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `generate_descriptor(self, sample, data_type, schema_name, options=None)` + +יצירת תיאור עבור מיפוי נתונים מובנים לתוך סכימה ספציפית. + +**ארגומנטים:** + +`sample`: דוגמת נתונים לניתוח (תוכן מחרוזת) +`data_type`: סוג נתונים (csv, json, xml) +`schema_name`: שם הסכימה המיועדת ליצירת התיאור +`options`: פרמטרים אופציונליים (לדוגמה, מפריד עבור CSV) + +**החזרות:** מילון עם התיאור ומטא-נתונים + +### `graph_embeddings_query(self, text, user, collection, limit=10)` + +שאילתת ישויות גרף ידע באמצעות דמיון סמנטי. + +מציאת ישויות בגרף הידע שעבורן התיאורים שלהן דומים מבחינה סמנטית +לטקסט הקלט, תוך שימוש בהטמעות וקטוריות. + +**ארגומנטים:** + +`text`: טקסט שאילתה לחיפוש סמנטי +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`limit`: מספר מקסימלי של תוצאות (ברירת מחדל: 10) + +**החזרות:** מילון: תוצאות שאילתה עם ישויות דומות + +**דוגמה:** + +```python +flow = api.flow().id("default") +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +# results contains {"entities": [{"entity": {...}, "score": 0.95}, ...]} +``` + +### `graph_rag(self, query, user='trustgraph', collection='default', entity_limit=50, triple_limit=30, max_subgraph_size=150, max_path_length=2)` + +הפעל שאילתה מבוססת גרפים של יצירת טקסט משופרת באמצעות אחזור (RAG). + +Graph RAG משתמש במבנה של גרף ידע כדי למצוא הקשר רלוונטי על ידי +מעבר בין קשרים של ישויות, ולאחר מכן מייצר תגובה באמצעות מודל שפה גדול (LLM). + +**ארגומנטים:** + +`query`: שאילתה בשפה טבעית +`user`: מזהה משתמש/מרחב מפתחות (ברירת מחדל: "trustgraph") +`collection`: מזהה אוסף (ברירת מחדל: "default") +`entity_limit`: מספר הישויות המקסימלי שיש להחזיר (ברירת מחדל: 50) +`triple_limit`: מספר הטריפלים המקסימלי לישות (ברירת מחדל: 30) +`max_subgraph_size`: מספר הטריפלים הכולל המקסימלי בתת-גרף (ברירת מחדל: 150) +`max_path_length`: עומק מעבר מקסימלי (ברירת מחדל: 2) + +**החזרות:** str: תגובה שנוצרה המשלבת הקשר גרפי + +**דוגמה:** + +```python +flow = api.flow().id("default") +response = flow.graph_rag( + query="Tell me about Marie Curie's discoveries", + user="trustgraph", + collection="scientists", + entity_limit=20, + max_path_length=3 +) +print(response) +``` + +### `load_document(self, document, id=None, metadata=None, user=None, collection=None)` + +טען מסמך בינארי לעיבוד. + +העלאת מסמך (PDF, DOCX, תמונות וכו') לצורך חילוץ ו +עיבוד דרך צינור המסמכים של ה-flow. + +**ארגומנטים:** + +`document`: תוכן המסמך כבייטים +`id`: מזהה מסמך אופציונלי (נוצר אוטומטית אם לא קיים) +`metadata`: מטא-דאטה אופציונלי (רשימה של טריפלטים או אובייקט עם שיטת emit) +`user`: מזהה משתמש/מרחב מפתחות (אופציונלי) +`collection`: מזהה אוסף (אופציונלי) + +**החזרות:** dict: תגובת עיבוד + +**מעלה:** + +`RuntimeError`: אם סופק מטא-דאטה ללא מזהה + +**דוגמה:** + +```python +flow = api.flow().id("default") + +# Load a PDF document +with open("research.pdf", "rb") as f: + result = flow.load_document( + document=f.read(), + id="research-001", + user="trustgraph", + collection="papers" + ) +``` + +### `load_text(self, text, id=None, metadata=None, charset='utf-8', user=None, collection=None)` + +טעינת תוכן טקסטואלי לצורך עיבוד. + +העלאת תוכן טקסטואלי לצורך חילוץ ועיבוד דרך צינור הטקסט של ה-flow. + + +**ארגומנטים:** + +`text`: תוכן טקסטואלי בפורמט של בתים +`id`: מזהה מסמך אופציונלי (נוצר אוטומטית אם לא סופק) +`metadata`: מטא-דאטה אופציונלי (רשימה של טריפלטים או אובייקט עם שיטת emit) +`charset`: קידוד תווים (ברירת מחדל: "utf-8") +`user`: מזהה משתמש/מרחב מפתחות (אופציונלי) +`collection`: מזהה אוסף (אופציונלי) + +**החזרות:** dict: תגובת עיבוד + +**גורם לשגיאה:** + +`RuntimeError`: אם סופק מטא-דאטה ללא מזהה + +**דוגמה:** + +```python +flow = api.flow().id("default") + +# Load text content +text_content = b"This is the document content..." +result = flow.load_text( + text=text_content, + id="text-001", + charset="utf-8", + user="trustgraph", + collection="documents" +) +``` + +### `mcp_tool(self, name, parameters={})` + +הפעלת כלי פרוטוקול הקשר מודל (Model Context Protocol - MCP). + +כלי MCP מספקים פונקציונליות ניתנת להרחבה עבור סוכנים ותהליכי עבודה, +ומאפשרים שילוב עם מערכות ושירותים חיצוניים. + +**ארגומנטים:** + +`name`: שם/מזהה הכלי +`parameters`: מילון פרמטרים של הכלי (ברירת מחדל: {}) + +**החזרות:** str או dict: תוצאת ביצוע הכלי + +**מעלה:** + +`ProtocolException`: אם פורמט התגובה אינו תקין + +**דוגמה:** + +```python +flow = api.flow().id("default") + +# Execute a tool +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `nlp_query(self, question, max_results=100)` + +המרת שאלה בשפה טבעית לשאילתת GraphQL. + +**ארגומנטים:** + +`question`: שאלה בשפה טבעית +`max_results`: מספר מקסימלי של תוצאות להחזרה (ברירת מחדל: 100) + +**החזרות:** מילון עם graphql_query, variables, detected_schemas, confidence + +### `prompt(self, id, variables)` + +ביצוע תבנית שאילתה עם החלפת משתנים. + +תבניות שאילתה מאפשרות דפוסי שאילתה לשימוש חוזר עם החלפת משתנים דינמית, +שימושי עבור הנדסת שאילתות עקבית. + +**ארגומנטים:** + +`id`: מזהה תבנית שאילתה +`variables`: מילון של התאמות בין שם משתנה לערך + +**החזרות:** מחרוזת או מילון: תוצאת שאילתה מעובדת (טקסט או אובייקט מובנה) + +**מעלה:** + +`ProtocolException`: אם פורמט התגובה אינו תקין + +**דוגמה:** + +```python +flow = api.flow().id("default") + +# Text template +result = flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"} +) + +# Structured template +result = flow.prompt( + id="extract-entities", + variables={"text": "Marie Curie won Nobel Prizes"} +) +``` + +### `request(self, path, request)` + +הגשת בקשה לשירות במקרה זה. + +**ארגומנטים:** + +`path`: נתיב השירות (לדוגמה, "service/text-completion") +`request`: מילון מטען הבקשה + +**החזר:** dict: תגובת השירות + +### `row_embeddings_query(self, text, schema_name, user='trustgraph', collection='default', index_name=None, limit=10)` + +שאילתת נתוני שורה באמצעות דמיון סמנטי בשדות ממופים. + +מוצאת שורות שבהן ערכי השדות הממופים דומים מבחינה סמנטית לטקסט +הקלט, תוך שימוש בהטמעות וקטוריות. זה מאפשר התאמה מעורפלת/סמנטית +בנתונים מובנים. + +**ארגומנטים:** + +`text`: טקסט שאילתה לחיפוש סמנטי +`schema_name`: שם הסכימה לחיפוש בתוכה +`user`: מזהה משתמש/אזור מפתחות (ברירת מחדל: "trustgraph") +`collection`: מזהה אוסף (ברירת מחדל: "default") +`index_name`: שם אינדקס אופציונלי לסינון החיפוש לאינדקס ספציפי +`limit`: מספר מקסימלי של תוצאות (ברירת מחדל: 10) + +**החזר:** dict: תוצאות שאילתה עם התאמות המכילות index_name, index_value, text ו-score + +**דוגמה:** + +```python +flow = api.flow().id("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query, user='trustgraph', collection='default', variables=None, operation_name=None)` + +הפעל שאילתת GraphQL על שורות מובנות בגרף הידע. + +שאילתות נתונים מובנים באמצעות תחביר GraphQL, המאפשר שאילתות מורכבות +עם סינון, אגרגציה וניווט ביחסים. + +**ארגומנטים:** + +`query`: מחרוזת שאילתת GraphQL +`user`: מזהה משתמש/מרחב (ברירת מחדל: "trustgraph") +`collection`: מזהה אוסף (ברירת מחדל: "default") +`variables`: מילון אופציונלי של משתני שאילתה +`operation_name`: שם פעולה אופציונלי עבור מסמכים מרובי פעולות + +**החזרות:** dict: תגובת GraphQL עם השדות 'data', 'errors' ו/או 'extensions' + +**מעלה:** + +`ProtocolException`: אם מתרחשת שגיאה ברמת המערכת + +**דוגמה:** + +```python +flow = api.flow().id("default") + +# Simple query +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) + +# Query with variables +query = ''' +query GetScientist($name: String!) { + scientists(name: $name) { + name + nobelPrizes + } +} +''' +result = flow.rows_query( + query=query, + variables={"name": "Marie Curie"} +) +``` + +### `schema_selection(self, sample, options=None)` + +בחירת סכימות מתאימות עבור מדגם נתונים באמצעות ניתוח שאילתות. + +**ארגומנטים:** + +`sample`: מדגם נתונים לניתוח (תוכן מחרוזת) +`options`: פרמטרים אופציונליים + +**החזרות:** מילון עם מערך schema_matches ומטא-נתונים + +### `structured_query(self, question, user='trustgraph', collection='default')` + +ביצוע שאילתה בשפה טבעית על נתונים מובנים. +משלב המרת שאילתות NLP וביצוע GraphQL. + +**ארגומנטים:** + +`question`: שאילתה בשפה טבעית +`user`: מזהה מרחב מפתחות Cassandra (ברירת מחדל: "trustgraph") +`collection`: מזהה אוסף נתונים (ברירת מחדל: "default") + +**החזרות:** מילון עם נתונים ושגיאות אופציונליות + +### `text_completion(self, system, prompt)` + +ביצוע השלמת טקסט באמצעות מודל LLM של ה-flow. + +**ארגומנטים:** + +`system`: הנחיה מערכתית המגדירה את התנהגות העוזר +`prompt`: הנחיה/שאלה של משתמש + +**החזרות:** מחרוזת: טקסט תגובה שנוצר + +**דוגמה:** + +```python +flow = api.flow().id("default") +response = flow.text_completion( + system="You are a helpful assistant", + prompt="What is quantum computing?" +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=10000)` + +שאילת משולשים בגרף ידע באמצעות התאמת תבניות. + +מחפש משולשים RDF התואמים לתבניות נתונות של נושא, נשוא ואובייקט. +פרמטרים לא מוגדרים פועלים כתווים מתחלפים. + +**ארגומנטים:** + +`s`: מזהה URI של נושא (אופציונלי, השתמש ב-None עבור תו מתחלף) +`p`: מזהה URI של נשוא (אופציונלי, השתמש ב-None עבור תו מתחלף) +`o`: מזהה URI של אובייקט או ליטרל (אופציונלי, השתמש ב-None עבור תו מתחלף) +`user`: מזהה משתמש/מרחב מפתחות (אופציונלי) +`collection`: מזהה אוסף (אופציונלי) +`limit`: מספר תוצאות מקסימלי להחזרה (ברירת מחדל: 10000) + +**מחזיר:** list[Triple]: רשימה של אובייקטי Triple התואמים + +**מעלה:** + +`RuntimeError`: אם s או p אינם Uri, או o אינם Uri/Literal + +**דוגמה:** + +```python +from trustgraph.knowledge import Uri, Literal + +flow = api.flow().id("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s=Uri("http://example.org/person/marie-curie"), + user="trustgraph", + collection="scientists" +) + +# Find all instances of a specific relationship +triples = flow.triples_query( + p=Uri("http://example.org/ontology/discovered"), + limit=100 +) +``` + + +-- + +## `AsyncFlow` + +```python +from trustgraph.api import AsyncFlow +``` + +לקוח לניהול זרימות אסינכרוניות באמצעות ממשק REST API. + +מספק פעולות ניהול זרימות מבוססות async/await, כולל הצגת רשימה, +התחלה, עצירה וניהול הגדרות של סוגי זרימות. כמו כן, מספק +גישה לשירותים הקשורים לזרימה, כגון סוכנים, RAG ושאילתות, באמצעות נקודות קצה (endpoints) של REST שאינן מבוססות סטרימינג. + + +הערה: לתמיכה בסטרימינג, השתמשו ב-AsyncSocketClient. + +### שיטות + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +אתחול לקוח זרימות אסינכרוני. + +**ארגומנטים:** + +`url`: כתובת URL בסיסית עבור ממשק ה-API של TrustGraph +`timeout`: זמן אחזור (timeout) לבקשות בשניות +`token`: טוקן bearer אופציונלי לאימות + +### `aclose(self) -> None` + +סגירת הלקוח האסינכרוני ושחרור משאבים. + +הערה: ניקוי (cleanup) מטופל באופן אוטומטי על ידי מנהלי הקשר (context managers) של aiohttp. +שיטה זו מסופקת לשמירה על עקביות עם לקוחות אסינכרוניים אחרים. + +### `delete_class(self, class_name: str)` + +מחיקת הגדרת סוג זרימה. + +מסירה תבנית (blueprint) של סוג זרימה מהמערכת. אינה משפיעה על +מופעי זרימה פעילים. + +**ארגומנטים:** + +`class_name`: שם סוג הזרימה למחיקה + +**דוגמה:** + +```python +async_flow = await api.async_flow() + +# Delete a flow class +await async_flow.delete_class("old-flow-class") +``` + +### `get(self, id: str) -> Dict[str, Any]` + +קבלת הגדרת זרימה. + +מאחזר את תצורת הזרימה המלאה, כולל שם המחלקה שלה, +התיאור שלה והפרמטרים שלה. + +**ארגומנטים:** + +`id`: מזהה זרימה + +**החזרות:** dict: אובייקט הגדרת זרימה + +**דוגמה:** + +```python +async_flow = await api.async_flow() + +# Get flow definition +flow_def = await async_flow.get("default") +print(f"Flow class: {flow_def.get('class-name')}") +print(f"Description: {flow_def.get('description')}") +``` + +### `get_class(self, class_name: str) -> Dict[str, Any]` + +קבלת הגדרת מחלקת זרימה. + +מאחזר את הגדרת התוכנית עבור מחלקת זרימה, כולל +הסכימה שלה והקישורים לשירותים. + +**ארגומנטים:** + +`class_name`: שם מחלקת הזרימה + +**החזרות:** dict: אובייקט הגדרת מחלקת זרימה + +**דוגמה:** + +```python +async_flow = await api.async_flow() + +# Get flow class definition +class_def = await async_flow.get_class("default") +print(f"Services: {class_def.get('services')}") +``` + +### `id(self, flow_id: str)` + +קבלת מופע לקוח של זרימה אסינכרונית. + +מחזיר לקוח לצורך אינטראקציה עם השירותים של זרימה ספציפית (סוכן, RAG, שאילתות, הטמעות, וכו'). + + +**ארגומנטים:** + +`flow_id`: מזהה זרימה + +**מחזיר:** AsyncFlowInstance: לקוח לפעולות ספציפיות לזרימה + +**דוגמה:** + +```python +async_flow = await api.async_flow() + +# Get flow instance +flow = async_flow.id("default") + +# Use flow services +result = await flow.graph_rag( + query="What is TrustGraph?", + user="trustgraph", + collection="default" +) +``` + +### `list(self) -> List[str]` + +רשום את כל מזהי הזרימות. + +שולף את ה-IDs של כל הזרימות הפרוסות כרגע במערכת. + +**מחזיר:** list[str]: רשימה של מזהי זרימות + +**דוגמה:** + +```python +async_flow = await api.async_flow() + +# List all flows +flows = await async_flow.list() +print(f"Available flows: {flows}") +``` + +### `list_classes(self) -> List[str]` + +רשום את כל שמות מחלקות הזרימה. + +שולף את שמות כל מחלקות הזרימה (תבניות) הזמינות במערכת. + +**מחזיר:** list[str]: רשימה של שמות מחלקות זרימה. + +**דוגמה:** + +```python +async_flow = await api.async_flow() + +# List available flow classes +classes = await async_flow.list_classes() +print(f"Available flow classes: {classes}") +``` + +### `put_class(self, class_name: str, definition: Dict[str, Any])` + +יצירה או עדכון של הגדרה של מחלקת זרימה. + +מאחסן תוכנית אב למחלקת זרימה שניתן להשתמש בה כדי ליצור מופעים של זרימות. + +**ארגומנטים:** + +`class_name`: שם מחלקת הזרימה +`definition`: אובייקט הגדרת מחלקת הזרימה + +**דוגמה:** + +```python +async_flow = await api.async_flow() + +# Create a custom flow class +class_def = { + "services": { + "agent": {"module": "agent", "config": {...}}, + "graph-rag": {"module": "graph-rag", "config": {...}} + } +} +await async_flow.put_class("custom-flow", class_def) +``` + +### `request(self, path: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +ביצוע בקשת HTTP POST אסינכרונית ל-API של ה-Gateway. + +שיטה פנימית לביצוע בקשות מאומתות ל-API של TrustGraph. + +**ארגומנטים:** + +`path`: נתיב נקודת הקצה של ה-API (ביחס לכתובת הבסיס) +`request_data`: מילון מטען הבקשה + +**מחזיר:** dict: אובייקט תגובה מה-API + +**מעלה:** + +`ProtocolException`: אם קוד ה-HTTP אינו 200 או שהתגובה אינה JSON חוקי. +`ApplicationException`: אם ה-API מחזיר תגובת שגיאה. + +### `start(self, class_name: str, id: str, description: str, parameters: Dict | None = None)` + +התחל מופע זרימה חדש. + +יוצר ומפעיל זרימה מתוך הגדרת מחלקת זרימה עם הפרמטרים שצוינו. + + +**ארגומנטים:** + +`class_name`: שם המחלקה של הזרימה שצריך ליצור מופע עבורה. +`id`: מזהה עבור מופע הזרימה החדש. +`description`: תיאור קריא של הזרימה. +`parameters`: פרמטרי תצורה אופציונליים עבור הזרימה. + +**דוגמה:** + +```python +async_flow = await api.async_flow() + +# Start a flow from a class +await async_flow.start( + class_name="default", + id="my-flow", + description="Custom flow instance", + parameters={"model": "claude-3-opus"} +) +``` + +### `stop(self, id: str)` + +עצירת תהליך פעיל. + +עוצרת ומסירה מופע של תהליך, תוך שחרור המשאבים שלו. + +**ארגומנטים:** + +`id`: מזהה של התהליך שיש לעצור + +**דוגמה:** + +```python +async_flow = await api.async_flow() + +# Stop a flow +await async_flow.stop("my-flow") +``` + + +-- + +## `AsyncFlowInstance` + +```python +from trustgraph.api import AsyncFlowInstance +``` + +לקוח מופע זרימה אסינכרוני. + +מספק גישה ל-async/await לשירותים המוגדרים בזרימה, כולל סוכנים, +שאילתות RAG, הטמעות ושאילתות גרף. כל הפעולות מחזירות +תגובות מלאות (לא בסטרימינג). + +הערה: לצורך תמיכה בסטרימינג, השתמשו ב-AsyncSocketFlowInstance. + +### שיטות + +### `__init__(self, flow: trustgraph.api.async_flow.AsyncFlow, flow_id: str)` + +אתחול מופע זרימה אסינכרוני. + +**ארגומנטים:** + +`flow`: לקוח AsyncFlow הראשי +`flow_id`: מזהה הזרימה + +### `agent(self, question: str, user: str, state: Dict | None = None, group: str | None = None, history: List | None = None, **kwargs: Any) -> Dict[str, Any]` + +ביצוע פעולה של סוכן (לא בסטרימינג). + +מפעיל סוכן כדי לענות על שאלה, עם מצב שיחה ואפשרויות +היסטוריה. מחזיר את התגובה המלאה לאחר שהסוכן סיים +לעבד. + +הערה: שיטה זו אינה תומכת בסטרימינג. לצורך מחשבות ותצפיות של הסוכן בזמן אמת, +השתמשו ב-AsyncSocketFlowInstance.agent() במקום. + +**ארגומנטים:** + +`question`: שאלה או הוראה של המשתמש +`user`: מזהה המשתמש +`state`: מילון מצב אופציונלי עבור הקשר שיחה +`group`: מזהה קבוצה אופציונלי לניהול סשנים +`history`: רשימת היסטוריית שיחה אופציונלית +`**kwargs`: פרמטרים נוספים ספציפיים לשירות + +**מחזיר:** dict: תגובת סוכן מלאה הכוללת תשובה ומטא-נתונים + +**דוגמה:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute agent +result = await flow.agent( + question="What is the capital of France?", + user="trustgraph" +) +print(f"Answer: {result.get('response')}") +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> str` + +ביצוע שאילתת RAG מבוססת מסמכים (לא סטרימינג). + +מבצע יצירת טקסט מועשרת באמצעות הטמעות מסמכים. +שולף קטעי מסמכים רלוונטיים באמצעות חיפוש סמנטי, ולאחר מכן מייצר +תשובה המבוססת על המסמכים שנשלפו. מחזיר תשובה מלאה. + +הערה: שיטה זו אינה תומכת בסטרימינג. עבור תגובות RAG בסטרימינג, +השתמשו ב-AsyncSocketFlowInstance.document_rag() במקום זאת. + +**ארגומנטים:** + +`query`: טקסט השאילתה של המשתמש +`user`: מזהה המשתמש +`collection`: מזהה האוסף המכיל מסמכים +`doc_limit`: מספר מרבי של קטעי מסמכים לשליפה (ברירת מחדל: 10) +`**kwargs`: פרמטרים נוספים ספציפיים לשירות + +**החזרות:** str: תשובה מלאה שנוצרה המבוססת על נתוני המסמכים + +**דוגמה:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query documents +response = await flow.document_rag( + query="What does the documentation say about authentication?", + user="trustgraph", + collection="docs", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts: list, **kwargs: Any)` + +יצירת הטמעות עבור טקסטים קלט. + +ממיר טקסטים לייצוגים וקטוריים מספריים באמצעות מודל ההטמעה המוגדר של ה-flow. +שימושי לחיפוש סמנטי והשוואות דמיון. + + +**ארגומנטים:** + +`texts`: רשימה של טקסטים קלט ליצירת הטמעה +`**kwargs`: פרמטרים נוספים ספציפיים לשירות + +**החזרות:** dict: תגובה המכילה וקטורי הטמעה + +**דוגמה:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate embeddings +result = await flow.embeddings(texts=["Sample text to embed"]) +vectors = result.get("vectors") +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any)` + +שאילתת הטמעות גרף לחיפוש ישויות סמנטי. + +מבצעת חיפוש סמנטי על הטמעות ישויות גרף כדי למצוא ישויות +הרלוונטיות ביותר לטקסט הקלט. מחזירה ישויות מדורגות לפי מידת הדמיון. + +**ארגומנטים:** + +`text`: טקסט שאילתה לחיפוש סמנטי +`user`: מזהה משתמש +`collection`: מזהה אוסף המכיל הטמעות גרף +`limit`: מספר מקסימלי של תוצאות להחזרה (ברירת מחדל: 10) +`**kwargs`: פרמטרים נוספים ספציפיים לשירות + +**החזרות:** dict: תגובה המכילה התאמות ישויות מדורגות עם ציוני דמיון + +**דוגמה:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find related entities +results = await flow.graph_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="tech-kb", + limit=5 +) + +for entity in results.get("entities", []): + print(f"{entity['name']}: {entity['score']}") +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> str` + +ביצוע שאילתת RAG מבוססת גרפים (לא בסטרימינג). + +מבצע יצירת טקסט מועשרת באמצעות נתוני גרף ידע. +מזהה ישויות רלוונטיות ויחסים ביניהן, ולאחר מכן מייצר +תשובה המבוססת על מבנה הגרף. מחזיר תשובה מלאה. + +הערה: שיטה זו אינה תומכת בסטרימינג. עבור תשובות RAG בסטרימינג, +השתמשו ב-AsyncSocketFlowInstance.graph_rag() במקום זאת. + +**ארגומנטים:** + +`query`: טקסט השאילתה של המשתמש +`user`: מזהה המשתמש +`collection`: מזהה אוסף המכיל את גרף הידע +`max_subgraph_size`: מספר מקסימלי של משולשים לכל תת-גרף (ברירת מחדל: 1000) +`max_subgraph_count`: מספר מקסימלי של תת-גרפים לשליפה (ברירת מחדל: 5) +`max_entity_distance`: מרחק גרף מקסימלי עבור הרחבת ישויות (ברירת מחדל: 3) +`**kwargs`: פרמטרים נוספים ספציפיים לשירות + +**החזרות:** str: תשובה מלאה שנוצרה המבוססת על נתוני גרף + +**דוגמה:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query knowledge graph +response = await flow.graph_rag( + query="What are the relationships between these entities?", + user="trustgraph", + collection="medical-kb", + max_subgraph_count=3 +) +print(response) +``` + +### `request(self, service: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +בקשת שימוש בשירות המוגדר בתוך ה-flow. + +שיטה פנימית לביצוע קריאות לשירותים בתוך מופע ה-flow הנוכחי. + +**ארגומנטים:** + +`service`: שם השירות (לדוגמה, "agent", "graph-rag", "triples") +`request_data`: עומס (payload) של הבקשה לשירות + +**החזר:** dict: אובייקט תגובה מהשירות + +**יוצא מכלל אפשרות (Raises):** + +`ProtocolException`: אם הבקשה נכשלת או שהתגובה אינה תקינה +`ApplicationException`: אם השירות מחזיר שגיאה + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any)` + +שאילתת הטמעות שורות לחיפוש סמנטי בנתונים מובנים. + +מבצעת חיפוש סמנטי על הטמעות אינדקס השורות כדי למצוא שורות שעבורן +ערכי השדות המאונדקסים דומים ביותר לטקסט הקלט. מאפשרת +התאמה מעורפלת/סמנטית על נתונים מובנים. + +**ארגומנטים:** + +`text`: טקסט השאילתה לחיפוש סמנטי +`schema_name`: שם הסכימה לחיפוש בתוכה +`user`: מזהה משתמש (ברירת מחדל: "trustgraph") +`collection`: מזהה אוסף (ברירת מחדל: "default") +`index_name`: שם אינדקס אופציונלי לסינון החיפוש לאינדקס ספציפי +`limit`: מספר מקסימלי של תוצאות להחזרה (ברירת מחדל: 10) +`**kwargs`: פרמטרים נוספים ספציפיים לשירות + +**החזר:** dict: תגובה המכילה התאמות עם index_name, index_value, text ו-score + +**דוגמה:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Search for customers by name similarity +results = await flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +for match in results.get("matches", []): + print(f"{match['index_name']}: {match['index_value']} (score: {match['score']})") +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs: Any)` + +הפעלת שאילתת GraphQL על שורות שמורות. + +שאילתות שורות נתונים מובנים באמצעות תחביר GraphQL. תומך בשאילתות מורכבות +עם משתנים ופעולות בעלות שם. + +**ארגומנטים:** + +`query`: מחרוזת שאילתת GraphQL +`user`: מזהה משתמש +`collection`: מזהה אוסף המכיל שורות +`variables`: משתנים אופציונליים לשאילתת GraphQL +`operation_name`: שם פעולה אופציונלי עבור שאילתות מרובות פעולות +`**kwargs`: פרמטרים נוספים ספציפיים לשירות + +**החזרות:** dict: תגובת GraphQL עם נתונים ושגיאות + +**דוגמה:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute GraphQL query +query = ''' + query GetUsers($status: String!) { + users(status: $status) { + id + name + email + } + } +''' + +result = await flow.rows_query( + query=query, + user="trustgraph", + collection="users", + variables={"status": "active"} +) + +for user in result.get("data", {}).get("users", []): + print(f"{user['name']}: {user['email']}") +``` + +### `text_completion(self, system: str, prompt: str, **kwargs: Any) -> str` + +יצירת השלמת טקסט (לא בזמן אמת). + +מייצרת תגובת טקסט ממודל שפה גדול (LLM) בהתבסס על הנחיה מערכתית והנחיה ממשתמש. +מחזירה את טקסט התגובה השלם. + +הערה: שיטה זו אינה תומכת בסטרימינג. לטקסט שנוצר בזמן אמת, +השתמשו ב-AsyncSocketFlowInstance.text_completion() במקום זאת. + +**ארגומנטים:** + +`system`: הנחיה מערכתית המגדירה את התנהגות ה-LLM. +`prompt`: הנחיה ממשתמש או שאלה. +`**kwargs`: פרמטרים נוספים ספציפיים לשירות. + +**מחזיר:** str: תגובת טקסט שנוצרת בשלמותה. + +**דוגמה:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate text +response = await flow.text_completion( + system="You are a helpful assistant.", + prompt="Explain quantum computing in simple terms." +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs: Any)` + +שאילת משולשות RDF באמצעות התאמת תבניות. + +מחפשת משולשות התואמות לתבניות הנקובות עבור הנושא, הנשוא ו/או +האובייקט. תבניות משתמשות ב-None כתווית מתקן כדי להתאים לכל ערך. + +**ארגומנטים:** + +`s`: תבנית נושא (None עבור תווית מתקן) +`p`: תבנית נשוא (None עבור תווית מתקן) +`o`: תבנית אובייקט (None עבור תווית מתקן) +`user`: מזהה משתמש (None עבור כל המשתמשים) +`collection`: מזהה אוסף (None עבור כל האוספים) +`limit`: מספר מקסימלי של משולשות להחזרה (ברירת מחדל: 100) +`**kwargs`: פרמטרים נוספים ספציפיים לשירות + +**החזרות:** dict: תגובה המכילה משולשות תואמות + +**דוגמה:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find all triples with a specific predicate +results = await flow.triples_query( + p="knows", + user="trustgraph", + collection="social", + limit=50 +) + +for triple in results.get("triples", []): + print(f"{triple['s']} knows {triple['o']}") +``` + + +-- + +## `SocketClient` + +```python +from trustgraph.api import SocketClient +``` + +לקוח WebSocket סינכרוני לפעולות סטרימינג. + +מספק ממשק סינכרוני לשירותי TrustGraph המבוססים על WebSocket, +תוך שימוש בספריית websockets אסינכרונית עם גנרטורים סינכרוניים לנוחות השימוש. +תומך בתגובות סטרימינג מסוכנים, שאילתות RAG והשלמות טקסט. + +הערה: זהו עטיפה סינכרונית סביב פעולות WebSocket אסינכרוניות. לצורך +תמיכה אסינכרונית אמיתית, השתמש ב-AsyncSocketClient. + +### שיטות + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +אתחול לקוח WebSocket סינכרוני. + +**ארגומנטים:** + +`url`: כתובת URL בסיסית עבור ממשק ה-API של TrustGraph (HTTP/HTTPS יומרו ל-WS/WSS) +`timeout`: זמן קצוב של WebSocket בשניות +`token`: טוקן bearer אופציונלי לאימות + +### `close(self) -> None` + +סגירת חיבורי WebSocket. + +הערה: ניקוי מתבצע באופן אוטומטי על ידי מנהלי הקשר באסינכרוני. + +### `flow(self, flow_id: str) -> 'SocketFlowInstance'` + +קבלת מופע זרימה לפעולות סטרימינג של WebSocket. + +**ארגומנטים:** + +`flow_id`: מזהה זרימה + +**מחזיר:** SocketFlowInstance: מופע זרימה עם שיטות סטרימינג + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent(question="Hello", user="trustgraph", streaming=True): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `SocketFlowInstance` + +```python +from trustgraph.api import SocketFlowInstance +``` + +מופע של זרימת WebSocket סינכרונית עבור פעולות סטרימינג. + +מספק את אותו ממשק כמו FlowInstance של REST, אך עם תמיכה בסטרימינג מבוסס WebSocket +עבור תגובות בזמן אמת. כל השיטות תומכות בפרמטר אופציונלי +`streaming` כדי לאפשר שליחת תוצאות מצטברות. + +### שיטות + +### `__init__(self, client: trustgraph.api.socket_client.SocketClient, flow_id: str) -> None` + +אתחול מופע זרימת שקע. + +**ארגומנטים:** + +`client`: שרת שקעים הורה (Parent SocketClient) +`flow_id`: מזהה זרימה + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, streaming: bool = False, **kwargs: Any) -> Dict[str, Any] | Iterator[trustgraph.api.types.StreamingChunk]` + +ביצוע פעולת סוכן עם תמיכה בסטרימינג. + +סוכנים יכולים לבצע ניתוח רב-שלבי עם שימוש בכלים. שיטה זו תמיד +מחזירה מקטעי סטרימינג (מחשבות, תצפיות, תשובות), גם כאשר +streaming=False, כדי להציג את תהליך החשיבה של הסוכן. + +**ארגומנטים:** + +`question`: שאלה או הוראה מהמשתמש +`user`: מזהה משתמש +`state`: מילון מצב אופציונלי לשיחות עם מצב (stateful) +`group`: מזהה קבוצה אופציונלי עבור הקשרים מרובי משתמשים +`history`: היסטוריית שיחה אופציונלית כרשימה של מילוני הודעות +`streaming`: הפעלת מצב סטרימינג (ברירת מחדל: False) +`**kwargs`: פרמטרים נוספים המועברים לשירות הסוכן + +**מחזיר:** Iterator[StreamingChunk]: זרם של מחשבות, תצפיות ותשובות של הסוכן + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent reasoning +for chunk in flow.agent( + question="What is quantum computing?", + user="trustgraph", + streaming=True +): + if isinstance(chunk, AgentThought): + print(f"[Thinking] {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"[Observation] {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"[Answer] {chunk.content}") +``` + +### `agent_explain(self, question: str, user: str, collection: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, **kwargs: Any) -> Iterator[trustgraph.api.types.StreamingChunk | trustgraph.api.types.ProvenanceEvent]` + +הפעל פעולה של סוכן עם תמיכה בהסבר. + +מעביר גם חלקי תוכן (AgentThought, AgentObservation, AgentAnswer) +וגם אירועי מקור (ProvenanceEvent). אירועי מקור מכילים URI שניתן לשלוף +באמצעות ExplainabilityClient כדי לקבל מידע מפורט על תהליך החשיבה של הסוכן. + + +מעקב אחר הסוכן מורכב מ: +Session: השאלה הראשונית ומטא-נתונים של הסשן +Iterations: כל מחזור מחשבה/פעולה/תצפית +Conclusion: התשובה הסופית + +**ארגומנטים:** + +`question`: שאלה או הוראה של המשתמש +`user`: מזהה משתמש +`collection`: מזהה אוסף לאחסון מקור +`state`: מילון מצב אופציונלי לשיחות עם מצב +`group`: מזהה קבוצה אופציונלי עבור הקשרים מרובי משתמשים +`history`: היסטוריית שיחה אופציונלית כרשימה של מילוני הודעות +`**kwargs`: פרמטרים נוספים המועברים לשירות הסוכן +`Yields`: +`Union[StreamingChunk, ProvenanceEvent]`: חלקי סוכן ואירועי מקור + +**דוגמה:** + +```python +from trustgraph.api import Api, ExplainabilityClient, ProvenanceEvent +from trustgraph.api import AgentThought, AgentObservation, AgentAnswer + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +for item in flow.agent_explain( + question="What is the capital of France?", + user="trustgraph", + collection="default" +): + if isinstance(item, AgentThought): + print(f"[Thought] {item.content}") + elif isinstance(item, AgentObservation): + print(f"[Observation] {item.content}") + elif isinstance(item, AgentAnswer): + print(f"[Answer] {item.content}") + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.explain_id) + +# Fetch session trace after completion +if provenance_ids: + trace = explain_client.fetch_agent_trace( + provenance_ids[0], # Session URI is first + graph="urn:graph:retrieval", + user="trustgraph", + collection="default" + ) +``` + +### `document_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +שאילתת מקטעי מסמכים באמצעות דמיון סמנטי. + +**ארגומנטים:** + +`text`: טקסט שאילתה לחיפוש סמנטי +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`limit`: מספר מקסימלי של תוצאות (ברירת מחדל: 10) +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**החזרות:** dict: תוצאות שאילתה עם מזהי מקטעים של מקטעי מסמכים תואמים + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "...", "score": 0.95}, ...]} +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +הפעל שאילתת RAG מבוססת מסמכים עם אפשרות של סטרימינג. + +משתמש בהטמעות וקטוריות כדי למצוא מקטעי מסמכים רלוונטיים, ולאחר מכן מייצר +תגובה באמצעות מודל שפה גדול (LLM). מצב הסטרימינג מספק תוצאות באופן מצטבר. + +**ארגומנטים:** + +`query`: שאילתה בשפה טבעית +`user`: מזהה משתמש/מרחב +`collection`: מזהה אוסף +`doc_limit`: מספר מקסימלי של מקטעי מסמכים לשליפה (ברירת מחדל: 10) +`streaming`: הפעל מצב סטרימינג (ברירת מחדל: False) +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**החזרות:** Union[str, Iterator[str]]: תגובה מלאה או זרם של מקטעי טקסט + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming document RAG +for chunk in flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `document_rag_explain(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +הפעל שאילתת RAG מבוססת מסמכים עם תמיכה בהסבר. + +מעביר גם מקטעי תוכן (RAGChunk) וגם אירועי מקור (ProvenanceEvent). +אירועי מקור מכילים URI שניתן לשלוף באמצעות ExplainabilityClient +כדי לקבל מידע מפורט על האופן שבו התגובה נוצרה. + +מעקב RAG של מסמך מורכב מ: +שאלה: השאילתה של המשתמש +חיפוש: מקטעים שנשלפו ממאגר המסמכים (chunk_count) +סינתזה: התשובה שנוצרה + +**ארגומנטים:** + +`query`: שאילתה בשפה טבעית +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`doc_limit`: מספר מקסימלי של מקטעי מסמכים לשליפה (ברירת מחדל: 10) +`**kwargs`: פרמטרים נוספים המועברים לשירות +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: מקטעי תוכן ואירועי מקור + +**דוגמה:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +for item in flow.document_rag_explain( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +): + if isinstance(item, RAGChunk): + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + # Fetch entity details + entity = explain_client.fetch_entity( + item.explain_id, + graph=item.explain_graph, + user="trustgraph", + collection="research-papers" + ) + print(f"Event: {entity}", file=sys.stderr) +``` + +### `embeddings(self, texts: list, **kwargs: Any) -> Dict[str, Any]` + +יצירת הטמעות וקטוריות עבור טקסט אחד או יותר. + +**ארגומנטים:** + +`texts`: רשימה של טקסטים קלט ליצירת הטמעות +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**החזרות:** dict: תגובה המכילה וקטורים (סט אחד לכל טקסט קלט) + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.embeddings(["quantum computing"]) +vectors = result.get("vectors", []) +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +שאילת שאילתות לישות גרף ידע באמצעות דמיון סמנטי. + +**ארגומנטים:** + +`text`: טקסט שאילתה לחיפוש סמנטי +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`limit`: מספר מקסימלי של תוצאות (ברירת מחדל: 10) +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**החזרות:** dict: תוצאות שאילתה עם ישויות דומות + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +הפעל שאילתת RAG מבוססת גרפים עם סטרימינג אופציונלי. + +משתמש במבנה גרף ידע כדי למצוא הקשר רלוונטי, ולאחר מכן מייצר +תגובה באמצעות מודל שפה גדול (LLM). מצב הסטרימינג מספק תוצאות באופן מצטבר. + +**ארגומנטים:** + +`query`: שאילתה בשפה טבעית +`user`: מזהה משתמש/מרחב +`collection`: מזהה אוסף +`max_subgraph_size`: מספר מקסימלי של משולשים בסך הכל בגרף המשנה (ברירת מחדל: 1000) +`max_subgraph_count`: מספר מקסימלי של גרפים משניים (ברירת מחדל: 5) +`max_entity_distance`: עומק מעבר מקסימלי (ברירת מחדל: 3) +`streaming`: הפעל מצב סטרימינג (ברירת מחדל: False) +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**מחזיר:** Union[str, Iterator[str]]: תגובה מלאה או זרם של פיסות טקסט + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming graph RAG +for chunk in flow.graph_rag( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `graph_rag_explain(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +הפעל שאילתת RAG מבוססת גרפים עם תמיכה בהסבר. + +מעביר גם מקטעי תוכן (RAGChunk) וגם אירועי מקור (ProvenanceEvent). +אירועי מקור מכילים URI שניתן לשלוף באמצעות ExplainabilityClient +כדי לקבל מידע מפורט על האופן שבו התגובה נוצרה. + +**ארגומנטים:** + +`query`: שאילתה בשפה טבעית +`user`: מזהה משתמש/מרחב +`collection`: מזהה אוסף +`max_subgraph_size`: מספר מקסימלי של משולשים בסך הכל בגרף המשנה (ברירת מחדל: 1000) +`max_subgraph_count`: מספר מקסימלי של גרפי משנה (ברירת מחדל: 5) +`max_entity_distance`: עומק מעבר מקסימלי (ברירת מחדל: 3) +`**kwargs`: פרמטרים נוספים המועברים לשירות +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: מקטעי תוכן ואירועי מקור + +**דוגמה:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +response_text = "" + +for item in flow.graph_rag_explain( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists" +): + if isinstance(item, RAGChunk): + response_text += item.content + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.provenance_id) + +# Fetch explainability details +for prov_id in provenance_ids: + entity = explain_client.fetch_entity( + prov_id, + graph="urn:graph:retrieval", + user="trustgraph", + collection="scientists" + ) + print(f"Entity: {entity}") +``` + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]` + +הפעלת כלי פרוטוקול הקשר מודל (MCP). + +**ארגומנטים:** + +`name`: שם/מזהה הכלי +`parameters`: מילון פרמטרים של הכלי +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**החזר:** dict: תוצאת ביצוע הכלי + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +הפעל תבנית פקודה עם אפשרות של סטרימינג. + +**ארגומנטים:** + +`id`: מזהה של תבנית הפקודה +`variables`: מילון של התאמות בין שם משתנה לערך +`streaming`: הפעל מצב סטרימינג (ברירת מחדל: False) +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**החזר:** Union[str, Iterator[str]]: תגובה מלאה או סטרימינג של פיסות טקסט + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming prompt execution +for chunk in flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"}, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +שליפת נתוני שורה באמצעות דמיון סמנטי בשדות ממופים. + +מאתר שורות שבהן ערכי השדות הממופים דומים מבחינה סמנטית ל- +הטקסט הקלט, תוך שימוש בהטמעות וקטוריות. זה מאפשר התאמה מעורפלת/סמנטית +לנתונים מובנים. + +**ארגומנטים:** + +`text`: טקסט שאילתה לחיפוש סמנטי +`schema_name`: שם הסכימה לחיפוש בתוכה +`user`: מזהה משתמש/אזור מפתחות (ברירת מחדל: "trustgraph") +`collection`: מזהה אוסף (ברירת מחדל: "default") +`index_name`: שם אינדקס אופציונלי לסינון החיפוש לאינדקס ספציפי +`limit`: מספר מקסימלי של תוצאות (ברירת מחדל: 10) +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**החזרות:** dict: תוצאות שאילתה עם התאמות המכילות index_name, index_value, text ו-score + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict[str, Any] | None = None, operation_name: str | None = None, **kwargs: Any) -> Dict[str, Any]` + +הפעלת שאילתת GraphQL על שורות מובנות. + +**ארגומנטים:** + +`query`: מחרוזת שאילתת GraphQL +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`variables`: מילון אופציונלי של משתני שאילתה +`operation_name`: שם פעולה אופציונלי עבור מסמכים מרובי פעולות +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**החזרות:** dict: תגובת GraphQL עם נתונים, שגיאות ו/או הרחבות + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) +``` + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs) -> str | Iterator[str]` + +הפעלת השלמת טקסט עם אפשרות של סטרימינג. + +**ארגומנטים:** + +`system`: הנחיה למערכת המגדירה את התנהגות העוזר. +`prompt`: הנחיה/שאלה מהמשתמש. +`streaming`: הפעל מצב סטרימינג (ברירת מחדל: False). +`**kwargs`: פרמטרים נוספים המועברים לשירות. + +**החזר:** Union[str, Iterator[str]]: תשובה מלאה או סטרימינג של פיסות טקסט. + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Non-streaming +response = flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=False +) +print(response) + +# Streaming +for chunk in flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `triples_query(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, **kwargs: Any) -> List[Dict[str, Any]]` + +שאילתת משולשים בגרף ידע באמצעות התאמת תבניות. + +**ארגומנטים:** + +`s`: מסנן נושא - מחרוזת URI, מילון מונחים, או None עבור wildcard +`p`: מסנן נשוא - מחרוזת URI, מילון מונחים, או None עבור wildcard +`o`: מסנן אובייקט - מחרוזת URI/literal, מילון מונחים, או None עבור wildcard +`g`: מסנן גרף מוגדר - מחרוזת URI או None עבור כל הגרפים +`user`: מזהה משתמש/מרחב מפתחות (אופציונלי) +`collection`: מזהה אוסף (אופציונלי) +`limit`: מספר תוצאות מקסימלי להחזרה (ברירת מחדל: 100) +`**kwargs`: פרמטרים נוספים המועברים לשירות + +**החזרות:** List[Dict]: רשימה של משולשים תואמים בפורמט פנימי + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s="http://example.org/person/marie-curie", + user="trustgraph", + collection="scientists" +) + +# Query with named graph filter +triples = flow.triples_query( + s="urn:trustgraph:session:abc123", + g="urn:graph:retrieval", + user="trustgraph", + collection="default" +) +``` + +### `triples_query_stream(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, batch_size: int = 20, **kwargs: Any) -> Iterator[List[Dict[str, Any]]]` + +שאילת משולשים בגרף ידע באמצעות אצוות סטרימינג. + +מחזירה אצוות של משולשים כשהם מגיעים, מה שמקטין את הזמן לקבלת התוצאה הראשונה +ואת צריכת הזיכרון עבור קבוצות תוצאות גדולות. + +**ארגומנטים:** + +`s`: מסנן נושא - מחרוזת URI, מילון מונחים, או None עבור wildcard +`p`: מסנן נשוא - מחרוזת URI, מילון מונחים, או None עבור wildcard +`o`: מסנן אובייקט - מחרוזת URI/ליטרל, מילון מונחים, או None עבור wildcard +`g`: מסנן גרף מוגדר - מחרוזת URI או None עבור כל הגרפים +`user`: מזהה משתמש/מרחב מפתחות (אופציונלי) +`collection`: מזהה אוסף (אופציונלי) +`limit`: מספר תוצאות מקסימלי להחזרה (ברירת מחדל: 100) +`batch_size`: משולשים לאצווה (ברירת מחדל: 20) +`**kwargs`: פרמטרים נוספים המועברים לשירות +`Yields`: +`List[Dict]`: אצוות של משולשים בפורמט wire + +**דוגמה:** + +```python +socket = api.socket() +flow = socket.flow("default") + +for batch in flow.triples_query_stream( + user="trustgraph", + collection="default" +): + for triple in batch: + print(triple["s"], triple["p"], triple["o"]) +``` + + +-- + +## `AsyncSocketClient` + +```python +from trustgraph.api import AsyncSocketClient +``` + +לקוח WebSocket אסינכרוני + +### שיטות + +### `__init__(self, url: str, timeout: int, token: str | None)` + +אתחול עצמי. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + +### `aclose(self)` + +סגירת חיבור WebSocket + +### `flow(self, flow_id: str)` + +קבלת מופע זרימה אסינכרוני עבור פעולות WebSocket + + +-- + +## `AsyncSocketFlowInstance` + +```python +from trustgraph.api import AsyncSocketFlowInstance +``` + +מופע של זרימת WebSocket אסינכרונית + +### שיטות + +### `__init__(self, client: trustgraph.api.async_socket_client.AsyncSocketClient, flow_id: str)` + +אתחול של self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: list | None = None, streaming: bool = False, **kwargs) -> Dict[str, Any] | AsyncIterator` + +סוכן עם סטרימינג אופציונלי + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs)` + +תיעוד RAG עם סטרימינג אופציונלי + +### `embeddings(self, texts: list, **kwargs)` + +יצירת הטמעות טקסט + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs)` + +שאילתא של הטמעות גרף לחיפוש סמנטי + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs)` + +RAG גרפי עם סטרימינג אופציונלי + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs)` + +הרצת כלי MCP + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs)` + +הרצת שאילתא עם סטרימינג אופציונלי + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs)` + +שאילתא של הטמעות שורות לחיפוש סמנטי על נתונים מובנים + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs)` + +שאילתא GraphQL על שורות מובנות + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs)` + +השלמת טקסט עם סטרימינג אופציונלי + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs)` + +שאילתא של תבנית משולשת + + +-- + +### `build_term(value: Any, term_type: str | None = None, datatype: str | None = None, language: str | None = None) -> Dict[str, Any] | None` + +בניית מילון Term בפורמט wire מתוך ערך. + +כללי זיהוי אוטומטיים (כאשר term_type הוא None): + כבר מילון עם מפתח 't' -> החזר כפי שהוא (כבר Term) + מתחיל עם http://, https://, urn: -> IRI + עטוף בסוגריים זוויתיים (לדוגמה, ) -> IRI (סוגריים זוויתיים מוסרים) + כל דבר אחר -> מילולי + +**ארגומנטים:** + +`value`: ערך ה-term (מחרוזת, מילון או None) +`term_type`: אחד מ-'iri', 'literal' או None לזיהוי אוטומטי +`datatype`: סוג נתונים עבור אובייקטים מילוליים (לדוגמה, xsd:integer) +`language`: תג שפה עבור אובייקטים מילוליים (לדוגמה, en) + +**החזרות:** dict: מילון Term בפורמט wire, או None אם הערך הוא None + + +-- + +## `BulkClient` + +```python +from trustgraph.api import BulkClient +``` + +לקוח לפעולות מרובות סינכרוניות לייבוא/ייצוא. + +מספק העברת נתונים מרובה יעילה באמצעות WebSocket עבור מערכי נתונים גדולים. +עוטף פעולות WebSocket אסינכרוניות עם גנרטורים סינכרוניים לנוחות השימוש. + +הערה: לתמיכה אסינכרונית אמיתית, השתמש ב-AsyncBulkClient במקום. + +### שיטות + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +אתחול לקוח מרובה סינכרוני. + +**ארגומנטים:** + +`url`: כתובת URL בסיסית עבור ממשק ה-API של TrustGraph (HTTP/HTTPS יומרו ל-WS/WSS) +`timeout`: זמן קצוב של WebSocket בשניות +`token`: טוקן bearer אופציונלי לאימות + +### `close(self) -> None` + +סגירת חיבורים + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +ייצוא מרובה של הטמעות מסמכים מתוך זרימה. + +מוריד ביעילות את כל הטמעות חלקי המסמכים באמצעות סטרימינג של WebSocket. + +**ארגומנטים:** + +`flow`: מזהה זרימה +`**kwargs`: פרמטרים נוספים (שמורים לשימוש עתידי) + +**מחזיר:** Iterator[Dict[str, Any]]: זרם של מילוני הטמעה + +**דוגמה:** + +```python +bulk = api.bulk() + +# Export and process document embeddings +for embedding in bulk.export_document_embeddings(flow="default"): + chunk_id = embedding.get("chunk_id") + vector = embedding.get("embedding") + print(f"{chunk_id}: {len(vector)} dimensions") +``` + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +ייצוא בכמות גדולה של הקשרים של ישויות מתוך זרימה. + +מוריד ביעילות את כל מידע ההקשר של הישויות באמצעות סטרימינג WebSocket. + +**ארגומנטים:** + +`flow`: מזהה זרימה +`**kwargs`: פרמטרים נוספים (שמורים לשימוש עתידי) + +**מחזיר:** Iterator[Dict[str, Any]]: זרם של מילוני הקשר + +**דוגמה:** + +```python +bulk = api.bulk() + +# Export and process entity contexts +for context in bulk.export_entity_contexts(flow="default"): + entity = context.get("entity") + text = context.get("context") + print(f"{entity}: {text[:100]}...") +``` + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +ייצוא המוני של הטמעות גרפים מתוך זרימה. + +מוריד ביעילות את כל הטמעות ישויות הגרף באמצעות סטרימינג WebSocket. + +**ארגומנטים:** + +`flow`: מזהה זרימה +`**kwargs`: פרמטרים נוספים (שמורים לשימוש עתידי) + +**מחזיר:** Iterator[Dict[str, Any]]: זרם של מילוני הטמעות + +**דוגמה:** + +```python +bulk = api.bulk() + +# Export and process embeddings +for embedding in bulk.export_graph_embeddings(flow="default"): + entity = embedding.get("entity") + vector = embedding.get("embedding") + print(f"{entity}: {len(vector)} dimensions") +``` + +### `export_triples(self, flow: str, **kwargs: Any) -> Iterator[trustgraph.api.types.Triple]` + +ייצוא בכמות גדולה של משולשים RDF מתוך זרימה. + +מוריד ביעילות את כל המשולשים באמצעות סטרימינג WebSocket. + +**ארגומנטים:** + +`flow`: מזהה זרימה +`**kwargs`: פרמטרים נוספים (שמורים לשימוש עתידי) + +**מחזיר:** Iterator[Triple]: זרם של אובייקטי Triple + +**דוגמה:** + +```python +bulk = api.bulk() + +# Export and process triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +### `import_document_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +ייבוא המוני של הטמעות מסמכים לתוך זרימה. + +העלאה יעילה של הטמעות מקטעי מסמכים באמצעות סטרימינג WebSocket +לשימוש בשאילתות RAG של מסמכים. + +**ארגומנטים:** + +`flow`: מזהה זרימה +`embeddings`: איטרטור המפיק מילוני הטמעות +`**kwargs`: פרמטרים נוספים (שמורים לשימוש עתידי) + +**דוגמה:** + +```python +bulk = api.bulk() + +# Generate document embeddings to import +def doc_embedding_generator(): + yield {"chunk_id": "doc1/p0/c0", "embedding": [0.1, 0.2, ...]} + yield {"chunk_id": "doc1/p0/c1", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_document_embeddings( + flow="default", + embeddings=doc_embedding_generator() +) +``` + +### `import_entity_contexts(self, flow: str, contexts: Iterator[Dict[str, Any]], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +ייבוא בכמות גדולה של הקשרים של ישויות לתוך זרימה. + +מעלה ביעילות מידע על הקשר של ישויות באמצעות סטרימינג WebSocket. +הקשרים של ישויות מספקים הקשר טקסטואלי נוסף לגבי ישויות גרף +לשיפור ביצועי RAG. + +**ארגומנטים:** + +`flow`: מזהה של זרימה +`contexts`: איטרטור המפיק מילוני הקשר +`metadata`: מילון מטא-נתונים עם id, מטא-נתונים, משתמש, אוסף +`batch_size`: מספר הקשרים בכל אצווה (ברירת מחדל 100) +`**kwargs`: פרמטרים נוספים (שמורים לשימוש עתידי) + +**דוגמה:** + +```python +bulk = api.bulk() + +# Generate entity contexts to import +def context_generator(): + yield {"entity": {"v": "entity1", "e": True}, "context": "Description..."} + yield {"entity": {"v": "entity2", "e": True}, "context": "Description..."} + # ... more contexts + +bulk.import_entity_contexts( + flow="default", + contexts=context_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + +### `import_graph_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +ייבוא המוני של הטמעות גרפים לתוך זרימה. + +העלאה יעילה של הטמעות ישויות גרפים באמצעות סטרימינג WebSocket. + +**ארגומנטים:** + +`flow`: מזהה זרימה +`embeddings`: איטרטור המפיק מילוני הטמעות +`**kwargs`: פרמטרים נוספים (שמורים לשימוש עתידי) + +**דוגמה:** + +```python +bulk = api.bulk() + +# Generate embeddings to import +def embedding_generator(): + yield {"entity": "entity1", "embedding": [0.1, 0.2, ...]} + yield {"entity": "entity2", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_graph_embeddings( + flow="default", + embeddings=embedding_generator() +) +``` + +### `import_rows(self, flow: str, rows: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +ייבוא בכמות גדולה של שורות מובנות לתוך זרימה. + +העלאה יעילה של שורות נתונים מובנים באמצעות סטרימינג WebSocket +לשימוש בשאילתות GraphQL. + +**ארגומנטים:** + +`flow`: מזהה זרימה +`rows`: איטרטור המפיק מילוני שורות +`**kwargs`: פרמטרים נוספים (שמורים לשימוש עתידי) + +**דוגמה:** + +```python +bulk = api.bulk() + +# Generate rows to import +def row_generator(): + yield {"id": "row1", "name": "Row 1", "value": 100} + yield {"id": "row2", "name": "Row 2", "value": 200} + # ... more rows + +bulk.import_rows( + flow="default", + rows=row_generator() +) +``` + +### `import_triples(self, flow: str, triples: Iterator[trustgraph.api.types.Triple], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +ייבוא בכמות גדולה של משולשים RDF לתוך זרימה. + +מעלה ביעילות מספר גדול של משולשים באמצעות סטרימינג WebSocket. + +**ארגומנטים:** + +`flow`: מזהה של הזרימה +`triples`: איטרטור המפיק אובייקטי Triple +`metadata`: מילון מטא-דאטה עם מזהה, מטא-דאטה, משתמש, אוסף +`batch_size`: מספר המשולשים בכל אצווה (ברירת מחדל 100) +`**kwargs`: פרמטרים נוספים (שמורים לשימוש עתידי) + +**דוגמה:** + +```python +from trustgraph.api import Triple + +bulk = api.bulk() + +# Generate triples to import +def triple_generator(): + yield Triple(s="subj1", p="pred", o="obj1") + yield Triple(s="subj2", p="pred", o="obj2") + # ... more triples + +# Import triples +bulk.import_triples( + flow="default", + triples=triple_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + + +-- + +## `AsyncBulkClient` + +```python +from trustgraph.api import AsyncBulkClient +``` + +לקוח לפעולות אסינכרוניות בכמות גדולה + +### שיטות + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +אתחול של self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + +### `aclose(self) -> None` + +סגירת חיבורים + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +ייצוא בכמות גדולה של הטמעות מסמכים באמצעות WebSocket + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +ייצוא בכמות גדולה של הקשרים של ישויות באמצעות WebSocket + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +ייצוא בכמות גדולה של הטמעות גרפים באמצעות WebSocket + +### `export_triples(self, flow: str, **kwargs: Any) -> AsyncIterator[trustgraph.api.types.Triple]` + +ייצוא בכמות גדולה של משולשות באמצעות WebSocket + +### `import_document_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +ייבוא בכמות גדולה של הטמעות מסמכים באמצעות WebSocket + +### `import_entity_contexts(self, flow: str, contexts: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +ייבוא בכמות גדולה של הקשרים של ישויות באמצעות WebSocket + +### `import_graph_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +ייבוא בכמות גדולה של הטמעות גרפים באמצעות WebSocket + +### `import_rows(self, flow: str, rows: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +ייבוא בכמות גדולה של שורות באמצעות WebSocket + +### `import_triples(self, flow: str, triples: AsyncIterator[trustgraph.api.types.Triple], **kwargs: Any) -> None` + +ייבוא בכמות גדולה של משולשות באמצעות WebSocket + + +-- + +## `Metrics` + +```python +from trustgraph.api import Metrics +``` + +לקוח למדדי סינכרוניים + +### שיטות + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +אתחול של self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + +### `get(self) -> str` + +קבלת מדדי Prometheus כטקסט + + +-- + +## `AsyncMetrics` + +```python +from trustgraph.api import AsyncMetrics +``` + +לקוח מדדים אסינכרוני + +### שיטות + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + +### `aclose(self) -> None` + +סגירת חיבורים + +### `get(self) -> str` + +קבלת מדדי Prometheus כטקסט + + +-- + +## `ExplainabilityClient` + +```python +from trustgraph.api import ExplainabilityClient +``` + +לקוח לשליפת ישויות הסברתיות עם טיפול בעקביות סופית. + +משתמש בגילוי שקט: שליפה, המתנה, שליפה חוזרת, השוואה. +אם התוצאות זהות, הנתונים יציבים. + +### שיטות + +### `__init__(self, flow_instance, retry_delay: float = 0.2, max_retries: int = 10)` + +אתחול לקוח הסברתי. + +**ארגומנטים:** + +`flow_instance`: מופע SocketFlowInstance לשליפת משולשות +`retry_delay`: השהייה בין ניסיונות חוזרים בשניות (ברירת מחדל: 0.2) +`max_retries`: מספר מקסימלי של ניסיונות חוזרים (ברירת מחדל: 10) + +### `detect_session_type(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> str` + +זיהוי האם סשן הוא מסוג GraphRAG או Agent. + +**ארגומנטים:** + +`session_uri`: ה-URI של הסשן/שאלה +`graph`: גרף מוגדר +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף + +**מחזיר:** "graphrag" או "agent" + +### `fetch_agent_trace(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +שליפת רצף ה-Agent השלם החל מ-URI של סשן. + +עוקב אחר שרשרת המוצא: שאלה -> ניתוח (ים) -> מסקנה + +**ארגומנטים:** + +`session_uri`: ה-URI של סשן/שאלה של ה-agent +`graph`: גרף מוגדר (ברירת מחדל: urn:graph:retrieval) +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`api`: מופע TrustGraph Api לגישה לספרן (אופציונלי) +`max_content`: אורך תוכן מקסימלי למסקנה + +**מחזיר:** מילון עם שאלה, איטרציות (רשימת ניתוחים), ישויות מסקנה + +### `fetch_docrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +שליפת רצף ה-DocumentRAG השלם החל מ-URI של שאלה. + +עוקב אחר שרשרת המוצא: + שאלה -> עיגון -> חקירה -> סינתזה + +**ארגומנטים:** + +`question_uri`: ה-URI של ישות השאלה +`graph`: גרף מוגדר (ברירת מחדל: urn:graph:retrieval) +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`api`: מופע TrustGraph Api לגישה לספרן (אופציונלי) +`max_content`: אורך תוכן מקסימלי לסינתזה + +**מחזיר:** מילון עם שאלה, עיגון, חקירה, ישויות סינתזה + +### `fetch_document_content(self, document_uri: str, api: Any, user: str | None = None, max_content: int = 10000) -> str` + +שליפת תוכן מהספרן לפי URI של מסמך. + +**ארגומנטים:** + +`document_uri`: ה-URI של המסמך בספרן +`api`: מופע TrustGraph Api לגישה לספרן +`user`: מזהה משתמש עבור הספרן +`max_content`: אורך תוכן מקסימלי להחזרה + +**מחזיר:** התוכן של המסמך כרצף + +### `fetch_edge_selection(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.EdgeSelection | None` + +שליפת ישות בחירת קצה (משמשת על ידי Focus). + +**ארגומנטים:** + +`uri`: ה-URI של בחירת הקצה +`graph`: גרף מוגדר לשליפה +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף + +**מחזיר:** EdgeSelection או None אם לא נמצא + +### `fetch_entity(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.ExplainEntity | None` + +שליפת ישות הסברות באמצעות URI עם טיפול בעקביות סופית. + +משתמש בגילוי שקטות: +1. שליפת משולשים עבור URI +2. אם אין תוצאות, לנסות שוב +3. אם יש תוצאות, לחכות ולשלוף שוב +4. אם התוצאות זהות, הנתונים יציבים - לנתח ולהחזיר +5. אם התוצאות שונות, הנתונים עדיין נכתבים - לנסות שוב + +**ארגומנטים:** + +`uri`: ה-URI של הישות שיש לשלוף +`graph`: גרף בעל שם לשאילתה (לדוגמה, "urn:graph:retrieval") +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף + +**החזרות:** תת-מחלקה של ExplainEntity או None אם לא נמצא + +### `fetch_focus_with_edges(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.Focus | None` + +שליפת ישות Focus וכל בחירות הקצוות שלה. + +**ארגומנטים:** + +`uri`: ה-URI של ישות ה-Focus +`graph`: גרף בעל שם לשאילתה +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף + +**החזרות:** Focus עם edge_selections מאוכלס, או None + +### `fetch_graphrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +שליפת עקבות GraphRAG מלאים החל מ-URI של שאלה. + +עוקבים אחר שרשרת המוצא: שאלה -> עיגון -> חקירה -> Focus -> סינתזה + +**ארגומנטים:** + +`question_uri`: ה-URI של ישות השאלה +`graph`: גרף (ברירת מחדל: urn:graph:retrieval) +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`api`: מופע של TrustGraph Api לגישה לספרן (אופציונלי) +`max_content`: אורך תוכן מקסימלי לסינתזה + +**החזרות:** מילון עם ישויות שאלה, עיגון, חקירה, focus, סינתזה + +### `list_sessions(self, graph: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 50) -> List[trustgraph.api.explainability.Question]` + +רשימת כל סשנים של הסברות (שאלות) באוסף. + +**ארגומנטים:** + +`graph`: גרף (ברירת מחדל: urn:graph:retrieval) +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף +`limit`: מספר הסשנים המקסימלי להחזרה + +**החזרות:** רשימה של ישויות שאלה ממוינות לפי חותם זמן (חדש ביותר קודם) + +### `resolve_edge_labels(self, edge: Dict[str, str], user: str | None = None, collection: str | None = None) -> Tuple[str, str, str]` + +פתרון תוויות עבור כל רכיבים של משולש קצה. + +**ארגומנטים:** + +`edge`: מילון עם מפתחות "s", "p", "o" +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף + +**החזרות:** טאפל של (s_label, p_label, o_label) + +### `resolve_label(self, uri: str, user: str | None = None, collection: str | None = None) -> str` + +פתרון rdfs:label עבור URI, עם שמירה במטמון. + +**ארגומנטים:** + +`uri`: ה-URI לקבלת התווית +`user`: מזהה משתמש/מרחב מפתחות +`collection`: מזהה אוסף + +**החזרות:** התווית אם נמצאה, אחרת ה-URI עצמו + + +-- + +## `ExplainEntity` + +```python +from trustgraph.api import ExplainEntity +``` + +מחלקה בסיסית עבור ישויות הסברתיות. + +**שדות:** + +`uri`: +`entity_type`: + +### שיטות + +### `__init__(self, uri: str, entity_type: str = '') -> None` + +אתחול עצמי. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `Question` + +```python +from trustgraph.api import Question +``` + +שאילתת משתמש - השאלה שהתחילה את הסשן. + +**שדות:** + +`uri`: +`entity_type`: +`query`: +`timestamp`: +`question_type`: + +### שיטות + +### `__init__(self, uri: str, entity_type: str = '', query: str = '', timestamp: str = '', question_type: str = '') -> None` + +אתחול עצמי. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `Exploration` + +```python +from trustgraph.api import Exploration +``` + +ישות חקירה - קצוות/חלקים שאוחזרו ממאגר הידע. + +**שדות:** + +`uri`: +`entity_type`: +`edge_count`: +`chunk_count`: +`entities`: typing.List[str] + +### שיטות + +### `__init__(self, uri: str, entity_type: str = '', edge_count: int = 0, chunk_count: int = 0, entities: List[str] = ) -> None` + +אתחול עצמי. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `Focus` + +```python +from trustgraph.api import Focus +``` + +ישות ממוקדת - קצוות נבחרים עם ניתוח באמצעות מודל שפה גדול (GraphRAG בלבד). + +**שדות:** + +`uri`: +`entity_type`: +`selected_edge_uris`: typing.List[str] +`edge_selections`: typing.List[trustgraph.api.explainability.EdgeSelection] + +### שיטות + +### `__init__(self, uri: str, entity_type: str = '', selected_edge_uris: List[str] = , edge_selections: List[trustgraph.api.explainability.EdgeSelection] = ) -> None` + +אתחול עצמי. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `Synthesis` + +```python +from trustgraph.api import Synthesis +``` + +ישות סינתטית - התשובה הסופית. + +**שדות:** + +`uri`: +`entity_type`: +`document`: + +### שיטות + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `Analysis` + +```python +from trustgraph.api import Analysis +``` + +ישות ניתוח - מחזור מחשבה/פעולה/תצפית (לסוכן בלבד). + +**שדות:** + +`uri`: +`entity_type`: +`action`: +`arguments`: +`thought`: +`observation`: + +### שיטות + +### `__init__(self, uri: str, entity_type: str = '', action: str = '', arguments: str = '', thought: str = '', observation: str = '') -> None` + +אתחול עצמי. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `Conclusion` + +```python +from trustgraph.api import Conclusion +``` + +סיכום - תשובה סופית (לסוכן בלבד). + +**שדות:** + +`uri`: +`entity_type`: +`document`: + +### שיטות + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `EdgeSelection` + +```python +from trustgraph.api import EdgeSelection +``` + +צומת שנבחר עם הסבר משלב GraphRAG Focus. + +**שדות:** + +`uri`: +`edge`: typing.Dict[str, str] | None +`reasoning`: + +### שיטות + +### `__init__(self, uri: str, edge: Dict[str, str] | None = None, reasoning: str = '') -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +### `wire_triples_to_tuples(wire_triples: List[Dict[str, Any]]) -> List[Tuple[str, str, Any]]` + +המרת משולשות בפורמט wire לטופלים (s, p, o). + + +-- + +### `extract_term_value(term: Dict[str, Any]) -> Any` + +חילוץ ערך ממילון Term בפורמט wire. + + +-- + +## `Triple` + +```python +from trustgraph.api import Triple +``` + +משפט גרף ידע המיוצג על ידי טריפל RDF. + +**שדות:** + +`s`: +`p`: +`o`: + +### שיטות + +### `__init__(self, s: str, p: str, o: str) -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `Uri` + +```python +from trustgraph.api import Uri +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +יצירת אובייקט מחרוזת חדש מהאובייקט הנתון. אם צוינו קידוד (encoding) או +טיפול בשגיאות (errors), אז האובייקט חייב לחשוף מאגר נתונים +שייקוד באמצעות הקידוד ומטפל השגיאות שצוינו. +אחרת, מוחזר התוצאה של object.__str__() (אם מוגדר) +או repr(object). +ברירת המחדל של הקידוד היא 'utf-8'. +ברירת המחדל של טיפול בשגיאות היא 'strict'. + +### שיטות + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `Literal` + +```python +from trustgraph.api import Literal +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +יצירת אובייקט מחרוזת חדש מהאובייקט הנתון. אם צוינו קידוד (encoding) או +טיפול בשגיאות (errors), אז האובייקט חייב לחשוף מאגר נתונים +שייקוד באמצעות הקידוד ומטפל השגיאות שצוינו. +אחרת, מוחזר התוצאה של object.__str__() (אם מוגדר) +או repr(object). +ברירת המחדל של קידוד היא 'utf-8'. +ברירת המחדל של טיפול בשגיאות היא 'strict'. + +### שיטות + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `ConfigKey` + +```python +from trustgraph.api import ConfigKey +``` + +מזהה מפתח תצורה. + +**שדות:** + +`type`: +`key`: + +### שיטות + +### `__init__(self, type: str, key: str) -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `ConfigValue` + +```python +from trustgraph.api import ConfigValue +``` + +זוג מפתח-ערך של תצורה. + +**שדות:** + +`type`: +`key`: +`value`: + +### שיטות + +### `__init__(self, type: str, key: str, value: str) -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `DocumentMetadata` + +```python +from trustgraph.api import DocumentMetadata +``` + +מטא-נתונים עבור מסמך בספרייה. + +**תכונות:** + +`parent_id: Parent document ID for child documents (empty for top`: level docs) + +**שדות:** + +`id`: +`time`: +`kind`: +`title`: +`comments`: +`metadata`: typing.List[trustgraph.api.types.Triple] +`user`: +`tags`: typing.List[str] +`parent_id`: +`document_type`: + +### שיטות + +### `__init__(self, id: str, time: datetime.datetime, kind: str, title: str, comments: str, metadata: List[trustgraph.api.types.Triple], user: str, tags: List[str], parent_id: str = '', document_type: str = 'source') -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `ProcessingMetadata` + +```python +from trustgraph.api import ProcessingMetadata +``` + +מטא-נתונים עבור משימת עיבוד מסמכים פעילה. + +**שדות:** + +`id`: +`document_id`: +`time`: +`flow`: +`user`: +`collection`: +`tags`: typing.List[str] + +### שיטות + +### `__init__(self, id: str, document_id: str, time: datetime.datetime, flow: str, user: str, collection: str, tags: List[str]) -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `CollectionMetadata` + +```python +from trustgraph.api import CollectionMetadata +``` + +מטא-נתונים עבור אוסף נתונים. + +אוספים מספקים קיבוץ והפרדה לוגיים עבור מסמכים ונתוני גרף ידע. + + +**תכונות:** + +`name: Human`: שם אוסף הניתן לקריאה + +**שדות:** + +`user`: +`collection`: +`name`: +`description`: +`tags`: typing.List[str] + +### שיטות + +### `__init__(self, user: str, collection: str, name: str, description: str, tags: List[str]) -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `StreamingChunk` + +```python +from trustgraph.api import StreamingChunk +``` + +מחלקה בסיסית עבור חלקי תגובה בסטרימינג. + +משמשת לפעולות סטרימינג מבוססות WebSocket שבהן התגובות מועברות +בהדרגה כשהן נוצרות. + +**שדות:** + +`content`: +`end_of_message`: + +### שיטות + +### `__init__(self, content: str, end_of_message: bool = False) -> None` + +אתחול עצמי. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `AgentThought` + +```python +from trustgraph.api import AgentThought +``` + +קטע של נימוקים/תהליך חשיבה של הסוכן. + +מייצג את תהליך החשיבה או שלבי התכנון הפנימיים של הסוכן במהלך הביצוע. +קטעים אלה מראים כיצד הסוכן חושב על הבעיה. + +**שדות:** + +`content`: +`end_of_message`: +`chunk_type`: + +### שיטות + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'thought') -> None` + +אתחול עצמי. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `AgentObservation` + +```python +from trustgraph.api import AgentObservation +``` + +קטע תצפית על ביצוע כלי. + +מייצג את התוצאה או התצפית מהפעלת כלי או פעולה. +קטעים אלה מציגים מה שהסוכן למד משימוש בכלים. + +**שדות:** + +`content`: +`end_of_message`: +`chunk_type`: + +### שיטות + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'observation') -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `AgentAnswer` + +```python +from trustgraph.api import AgentAnswer +``` + +חלק תשובה סופי של הסוכן. + +מייצג את התגובה הסופית של הסוכן למשאלה של המשתמש לאחר השלמת +הניתוח והשימוש בכלי. + +**מאפיינים:** + +`chunk_type: Always "final`: answer" + +**שדות:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_dialog`: + +### שיטות + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'final-answer', end_of_dialog: bool = False) -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `RAGChunk` + +```python +from trustgraph.api import RAGChunk +``` + +מקטע סטרימינג של RAG (יצירת טקסט מועשרת בשליפה). + +משמש למענה סטרימינג מ-RAG גרפי, RAG של מסמכים, השלמת טקסט, +ושירותי יצירה אחרים. + +**שדות:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_stream`: +`error`: typing.Dict[str, str] | None + +### שיטות + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'rag', end_of_stream: bool = False, error: Dict[str, str] | None = None) -> None` + +אתחול עצמי. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `ProvenanceEvent` + +```python +from trustgraph.api import ProvenanceEvent +``` + +אירוע מקור עבור הסברתיות. + +נשלח במהלך שאילתות GraphRAG כאשר מצב ההסבר מופעל. +כל אירוע מייצג צומת מקור שנוצר במהלך עיבוד השאילתה. + +**שדות:** + +`explain_id`: +`explain_graph`: +`event_type`: + +### שיטות + +### `__init__(self, explain_id: str, explain_graph: str = '', event_type: str = '') -> None` + +אתחול self. עיין ב-help(type(self)) לקבלת חתימה מדויקת. + + +-- + +## `ProtocolException` + +```python +from trustgraph.api import ProtocolException +``` + +מופעל כאשר מתרחשות שגיאות בפרוטוקול WebSocket. + + +-- + +## `TrustGraphException` + +```python +from trustgraph.api import TrustGraphException +``` + +מחלקה בסיסית עבור כל שגיאות השירות של TrustGraph. + + +-- + +## `AgentError` + +```python +from trustgraph.api import AgentError +``` + +שגיאת שירות סוכן + + +-- + +## `ConfigError` + +```python +from trustgraph.api import ConfigError +``` + +שגיאת שירות תצורה + + +-- + +## `DocumentRagError` + +```python +from trustgraph.api import DocumentRagError +``` + +שגיאת שליפה של מסמכים. + + +-- + +## `FlowError` + +```python +from trustgraph.api import FlowError +``` + +שגיאת ניהול זרימה + + +-- + +## `GatewayError` + +```python +from trustgraph.api import GatewayError +``` + +שגיאת שער API + + +-- + +## `GraphRagError` + +```python +from trustgraph.api import GraphRagError +``` + +שגיאת שליפה של גרף RAG + + +-- + +## `LLMError` + +```python +from trustgraph.api import LLMError +``` + +שגיאת שירות מודל שפה גדול (LLM). + + +-- + +## `LoadError` + +```python +from trustgraph.api import LoadError +``` + +שגיאת טעינת נתונים + + +-- + +## `LookupError` + +```python +from trustgraph.api import LookupError +``` + +שגיאת חיפוש/איתור + + +-- + +## `NLPQueryError` + +```python +from trustgraph.api import NLPQueryError +``` + +שגיאת שירות שאילתות NLP. + + +-- + +## `RowsQueryError` + +```python +from trustgraph.api import RowsQueryError +``` + +שגיאת שירות שאילתות שורות + + +-- + +## `RequestError` + +```python +from trustgraph.api import RequestError +``` + +שגיאת עיבוד בקשה + + +-- + +## `StructuredQueryError` + +```python +from trustgraph.api import StructuredQueryError +``` + +שגיאת שירות שאילתות מובנה. + + +-- + +## `UnexpectedError` + +```python +from trustgraph.api import UnexpectedError +``` + +שגיאה בלתי צפויה/לא ידועה + + +-- + +## `ApplicationException` + +```python +from trustgraph.api import ApplicationException +``` + +מחלקה בסיסית עבור כל שגיאות השירות של TrustGraph. + + +-- + diff --git a/docs/python-api.hi.md b/docs/python-api.hi.md new file mode 100644 index 00000000..a6b8f222 --- /dev/null +++ b/docs/python-api.hi.md @@ -0,0 +1,4071 @@ +# ट्रस्टग्राफ पायथन एपीआई संदर्भ + +## स्थापना + +```bash +pip install trustgraph +``` + +## त्वरित शुरुआत + +सभी कक्षाएं और प्रकार `trustgraph.api` पैकेज से आयात किए गए हैं: + +```python +from trustgraph.api import Api, Triple, ConfigKey + +# Create API client +api = Api(url="http://localhost:8088/") + +# Get a flow instance +flow = api.flow().id("default") + +# Execute a graph RAG query +response = flow.graph_rag( + query="What are the main topics?", + user="trustgraph", + collection="default" +) +``` + +## सामग्री तालिका + +### मुख्य भाग + +[Api](#api) + +### फ्लो क्लाइंट + +[Flow](#flow) +[FlowInstance](#flowinstance) +[AsyncFlow](#asyncflow) +[AsyncFlowInstance](#asyncflowinstance) + +### वेबसॉकेट क्लाइंट + +[SocketClient](#socketclient) +[SocketFlowInstance](#socketflowinstance) +[AsyncSocketClient](#asyncsocketclient) +[AsyncSocketFlowInstance](#asyncsocketflowinstance) + +### बल्क ऑपरेशन + +[BulkClient](#bulkclient) +[AsyncBulkClient](#asyncbulkclient) + +### मेट्रिक्स + +[Metrics](#metrics) +[AsyncMetrics](#asyncmetrics) + +### डेटा प्रकार + +[Triple](#triple) +[ConfigKey](#configkey) +[ConfigValue](#configvalue) +[DocumentMetadata](#documentmetadata) +[ProcessingMetadata](#processingmetadata) +[CollectionMetadata](#collectionmetadata) +[StreamingChunk](#streamingchunk) +[AgentThought](#agentthought) +[AgentObservation](#agentobservation) +[AgentAnswer](#agentanswer) +[RAGChunk](#ragchunk) + +### अपवाद + +[ProtocolException](#protocolexception) +[TrustGraphException](#trustgraphexception) +[AgentError](#agenterror) +[ConfigError](#configerror) +[DocumentRagError](#documentragerror) +[FlowError](#flowerror) +[GatewayError](#gatewayerror) +[GraphRagError](#graphragerror) +[LLMError](#llmerror) +[LoadError](#loaderror) +[LookupError](#lookuperror) +[NLPQueryError](#nlpqueryerror) +[RowsQueryError](#rowsqueryerror) +[RequestError](#requesterror) +[StructuredQueryError](#structuredqueryerror) +[UnexpectedError](#unexpectederror) +[ApplicationException](#applicationexception) + +-- + +## `Api` + +```python +from trustgraph.api import Api +``` + +सिंक्रोनस और एसिंक्रोनस कार्यों के लिए मुख्य ट्रस्टग्राफ एपीआई क्लाइंट। + +यह क्लास सभी ट्रस्टग्राफ सेवाओं तक पहुंच प्रदान करती है, जिसमें फ्लो प्रबंधन, +नॉलेज ग्राफ ऑपरेशन, दस्तावेज़ प्रसंस्करण, आरएजी क्वेरी और बहुत कुछ शामिल हैं। यह +रेस्ट-आधारित और वेबसॉकेट-आधारित दोनों संचार पैटर्न का समर्थन करता है। + +क्लाइंट का उपयोग स्वचालित संसाधन सफाई के लिए एक संदर्भ प्रबंधक के रूप में किया जा सकता है: + ```python + with Api(url="http://localhost:8088/") as api: + result = api.flow().id("default").graph_rag(query="test") + ``` + +### विधियाँ + +### `__aenter__(self)` + +एसिंक्रोनस संदर्भ प्रबंधक में प्रवेश करें। + +### `__aexit__(self, *args)` + +एसिंक्रोनस संदर्भ प्रबंधक से बाहर निकलें और कनेक्शन बंद करें। + +### `__enter__(self)` + +सिंक्रोनस संदर्भ प्रबंधक में प्रवेश करें। + +### `__exit__(self, *args)` + +सिंक्रोनस संदर्भ प्रबंधक से बाहर निकलें और कनेक्शन बंद करें। + +### `__init__(self, url='http://localhost:8088/', timeout=60, token: str | None = None)` + +ट्रस्टग्राफ एपीआई क्लाइंट को आरंभ करें। + +**तर्क:** + +`url`: ट्रस्टग्राफ एपीआई के लिए आधार यूआरएल (डिफ़ॉल्ट: "http://localhost:8088/"") +`timeout`: सेकंड में अनुरोध समय-सीमा (डिफ़ॉल्ट: 60) +`token`: प्रमाणीकरण के लिए वैकल्पिक बेयरर टोकन + +**उदाहरण:** + +```python +# Local development +api = Api() + +# Production with authentication +api = Api( + url="https://trustgraph.example.com/", + timeout=120, + token="your-api-token" +) +``` + +### `aclose(self)` + +सभी एसिंक्रोनस क्लाइंट कनेक्शन बंद करें। + +यह विधि एसिंक्रोनस वेबसॉकेट, बल्क ऑपरेशन और फ्लो कनेक्शन को बंद करती है। +यह स्वचालित रूप से तब कॉल किया जाता है जब किसी एसिंक्रोनस कॉन्टेक्स्ट मैनेजर से बाहर निकलते हैं। + +**उदाहरण:** + +```python +api = Api() +async_socket = api.async_socket() +# ... use async_socket +await api.aclose() # Clean up connections + +# Or use async context manager (automatic cleanup) +async with Api() as api: + async_socket = api.async_socket() + # ... use async_socket +# Automatically closed +``` + +### `async_bulk(self)` + +एसिंक्रोनस बल्क ऑपरेशंस क्लाइंट प्राप्त करें। + +वेबसॉकेट के माध्यम से एसिंक्रोनस/अवेइट शैली के बल्क इम्पोर्ट/एक्सपोर्ट ऑपरेशंस प्रदान करता है +बड़े डेटासेट के कुशल प्रबंधन के लिए। + +**रिटर्न:** AsyncBulkClient: एसिंक्रोनस बल्क ऑपरेशंस क्लाइंट + +**उदाहरण:** + +```python +async_bulk = api.async_bulk() + +# Export triples asynchronously +async for triple in async_bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import with async generator +async def triple_gen(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +await async_bulk.import_triples( + flow="default", + triples=triple_gen() +) +``` + +### `async_flow(self)` + +एक एसिंक्रोनस, REST-आधारित फ्लो क्लाइंट प्राप्त करें। + +यह फ्लो ऑपरेशन्स तक एसिंक्रोनस/अवेइट शैली में एक्सेस प्रदान करता है। यह एसिंक्रोनस पायथन एप्लिकेशन और फ्रेमवर्क (फास्टएपीआई, एआईओएचटीटीपी, आदि) के लिए पसंदीदा है। + + +**रिटर्न:** AsyncFlow: एसिंक्रोनस फ्लो क्लाइंट + +**उदाहरण:** + +```python +async_flow = api.async_flow() + +# List flows +flow_ids = await async_flow.list() + +# Execute operations +instance = async_flow.id("default") +result = await instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `async_metrics(self)` + +एक एसिंक्रोनस मेट्रिक्स क्लाइंट प्राप्त करें। + +प्रोमेथियस मेट्रिक्स तक एसिंक्रोनस/अवेइट शैली में पहुँच प्रदान करता है। + +**वापसी:** AsyncMetrics: एसिंक्रोनस मेट्रिक्स क्लाइंट + +**उदाहरण:** + +```python +async_metrics = api.async_metrics() +prometheus_text = await async_metrics.get() +print(prometheus_text) +``` + +### `async_socket(self)` + +स्ट्रीमिंग कार्यों के लिए एक एसिंक्रोनस वेबसॉकेट क्लाइंट प्राप्त करें। + +यह स्ट्रीमिंग समर्थन के साथ एसिंक/अवेट शैली वेबसॉकेट एक्सेस प्रदान करता है। +यह पायथन में एसिंक स्ट्रीमिंग के लिए पसंदीदा तरीका है। + +**रिटर्न:** AsyncSocketClient: एसिंक्रोनस वेबसॉकेट क्लाइंट + +**उदाहरण:** + +```python +async_socket = api.async_socket() +flow = async_socket.flow("default") + +# Stream agent responses +async for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + +### `bulk(self)` + +आयात/निर्यात के लिए एक सिंक्रोनस बल्क ऑपरेशंस क्लाइंट प्राप्त करें। + +बल्क ऑपरेशंस, वेबसॉकेट कनेक्शन के माध्यम से बड़े डेटासेट के कुशल हस्तांतरण की अनुमति देते हैं, जिसमें ट्रिपल, एम्बेडिंग, एंटिटी कॉन्टेक्स्ट और ऑब्जेक्ट शामिल हैं। + +**रिटर्न:** BulkClient: सिंक्रोनस बल्क ऑपरेशंस क्लाइंट + +**उदाहरण:** + + +```python +bulk = api.bulk() + +# Export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import triples +def triple_generator(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +bulk.import_triples(flow="default", triples=triple_generator()) +``` + +### `close(self)` + +सभी सिंक्रोनस क्लाइंट कनेक्शन बंद करें। + +यह विधि WebSocket और बल्क ऑपरेशन कनेक्शन बंद करती है। +यह स्वचालित रूप से तब कॉल किया जाता है जब किसी कॉन्टेक्स्ट मैनेजर से बाहर निकलते हैं। + +**उदाहरण:** + +```python +api = Api() +socket = api.socket() +# ... use socket +api.close() # Clean up connections + +# Or use context manager (automatic cleanup) +with Api() as api: + socket = api.socket() + # ... use socket +# Automatically closed +``` + +### `collection(self)` + +डेटा संग्रहों को प्रबंधित करने के लिए एक कलेक्शन क्लाइंट प्राप्त करें। + +कलेक्शन दस्तावेजों और नॉलेज ग्राफ डेटा को व्यवस्थित करते हैं +तार्किक समूहों में, अलगाव और एक्सेस नियंत्रण के लिए। + +**रिटर्न:** कलेक्शन: कलेक्शन प्रबंधन क्लाइंट + +**उदाहरण:** + +```python +collection = api.collection() + +# List collections +colls = collection.list_collections(user="trustgraph") + +# Update collection metadata +collection.update_collection( + user="trustgraph", + collection="default", + name="Default Collection", + description="Main data collection" +) +``` + +### `config(self)` + +कॉन्फ़िगरेशन सेटिंग्स को प्रबंधित करने के लिए एक कॉन्फ़िग क्लाइंट प्राप्त करें। + +**रिटर्न:** कॉन्फ़िग: कॉन्फ़िगरेशन प्रबंधन क्लाइंट + +**उदाहरण:** + +```python +config = api.config() + +# Get configuration values +values = config.get([ConfigKey(type="llm", key="model")]) + +# Set configuration +config.put([ConfigValue(type="llm", key="model", value="gpt-4")]) +``` + +### `flow(self)` + +फ्लो को प्रबंधित करने और उसके साथ इंटरैक्ट करने के लिए एक फ्लो क्लाइंट प्राप्त करें। + +फ्लो, ट्रस्टग्राफ में प्राथमिक निष्पादन इकाइयाँ हैं, जो एजेंट, आरएजी क्वेरी, एम्बेडिंग और दस्तावेज़ प्रसंस्करण जैसी सेवाओं तक पहुंच प्रदान करती हैं। + +**रिटर्न:** फ्लो: फ्लो प्रबंधन क्लाइंट + +**उदाहरण:** + + +```python +flow_client = api.flow() + +# List available blueprints +blueprints = flow_client.list_blueprints() + +# Get a specific flow instance +flow_instance = flow_client.id("default") +response = flow_instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `knowledge(self)` + +ज्ञान ग्राफ कोर को प्रबंधित करने के लिए एक नॉलेज क्लाइंट प्राप्त करें। + +**रिटर्न:** नॉलेज: ज्ञान ग्राफ प्रबंधन क्लाइंट + +**उदाहरण:** + +```python +knowledge = api.knowledge() + +# List available KG cores +cores = knowledge.list_kg_cores(user="trustgraph") + +# Load a KG core +knowledge.load_kg_core(id="core-123", user="trustgraph") +``` + +### `library(self)` + +दस्तावेज़ प्रबंधन के लिए एक लाइब्रेरी क्लाइंट प्राप्त करें। + +यह लाइब्रेरी दस्तावेज़ भंडारण, मेटाडेटा प्रबंधन और +प्रसंस्करण कार्यप्रवाह समन्वय प्रदान करती है। + +**रिटर्न:** लाइब्रेरी: दस्तावेज़ लाइब्रेरी प्रबंधन क्लाइंट + +**उदाहरण:** + +```python +library = api.library() + +# Add a document +library.add_document( + document=b"Document content", + id="doc-123", + metadata=[], + user="trustgraph", + title="My Document", + comments="Test document" +) + +# List documents +docs = library.get_documents(user="trustgraph") +``` + +### `metrics(self)` + +निगरानी के लिए एक सिंक्रोनस मेट्रिक्स क्लाइंट प्राप्त करें। + +यह ट्रस्टग्राफ सेवा से प्रोमेथियस-स्वरूपित मेट्रिक्स प्राप्त करता है +निगरानी और अवलोकन के लिए। + +**रिटर्न:** मेट्रिक्स: सिंक्रोनस मेट्रिक्स क्लाइंट + +**उदाहरण:** + +```python +metrics = api.metrics() +prometheus_text = metrics.get() +print(prometheus_text) +``` + +### `request(self, path, request)` + +एक निम्न-स्तरीय REST API अनुरोध करें। + +यह विधि मुख्य रूप से आंतरिक उपयोग के लिए है, लेकिन जब आवश्यक हो तो इसका उपयोग सीधे +API एक्सेस के लिए किया जा सकता है। + +**तर्क:** + +`path`: API एंडपॉइंट पथ (बेस URL के सापेक्ष) +`request`: अनुरोध पेलोड एक डिक्शनरी के रूप में + +**रिटर्न:** dict: प्रतिक्रिया ऑब्जेक्ट + +**अपवाद:** + +`ProtocolException`: यदि प्रतिक्रिया स्थिति 200 नहीं है या प्रतिक्रिया JSON नहीं है +`ApplicationException`: यदि प्रतिक्रिया में कोई त्रुटि है + +**उदाहरण:** + +```python +response = api.request("flow", { + "operation": "list-flows" +}) +``` + +### `socket(self)` + +स्ट्रीमिंग कार्यों के लिए एक सिंक्रोनस वेबसॉकेट क्लाइंट प्राप्त करें। + +वेबसॉकेट कनेक्शन वास्तविक समय प्रतिक्रियाओं के लिए स्ट्रीमिंग समर्थन प्रदान करते हैं +एजेंटों, आरएजी प्रश्नों और टेक्स्ट पूर्णता से। यह विधि वेबसॉकेट प्रोटोकॉल के चारों ओर एक सिंक्रोनस रैपर लौटाती है। + + +**रिटर्न:** SocketClient: सिंक्रोनस वेबसॉकेट क्लाइंट + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `Flow` + +```python +from trustgraph.api import Flow +``` + +ब्लूप्रिंट और फ्लो इंस्टेंस ऑपरेशन्स के लिए फ्लो मैनेजमेंट क्लाइंट। + +यह क्लास फ्लो ब्लूप्रिंट (टेम्प्लेट) और +फ्लो इंस्टेंस (चल रहे फ्लो) को प्रबंधित करने के लिए विधियाँ प्रदान करती है। ब्लूप्रिंट फ्लो की संरचना और +पैरामीटर को परिभाषित करते हैं, जबकि इंस्टेंस सक्रिय फ्लो का प्रतिनिधित्व करते हैं जो +सेवाओं को निष्पादित कर सकते हैं। + +### विधियाँ + +### `__init__(self, api)` + +फ्लो क्लाइंट को इनिशियलाइज़ करें। + +**तर्क:** + +`api`: अनुरोध करने के लिए पैरेंट एपीआई इंस्टेंस। + +### `delete_blueprint(self, blueprint_name)` + +एक फ्लो ब्लूप्रिंट को हटाएं। + +**तर्क:** + +`blueprint_name`: हटाने के लिए ब्लूप्रिंट का नाम। + +**उदाहरण:** + +```python +api.flow().delete_blueprint("old-blueprint") +``` + +### `get(self, id)` + +एक चल रहे फ्लो इंस्टेंस की परिभाषा प्राप्त करें। + +**तर्क:** + +`id`: फ्लो इंस्टेंस आईडी + +**वापसी:** डिक्ट: फ्लो इंस्टेंस परिभाषा + +**उदाहरण:** + +```python +flow_def = api.flow().get("default") +print(flow_def) +``` + +### `get_blueprint(self, blueprint_name)` + +नाम से एक फ्लो ब्लूप्रिंट परिभाषा प्राप्त करें। + +**तर्क:** + +`blueprint_name`: प्राप्त करने के लिए ब्लूप्रिंट का नाम + +**वापसी:** dict: ब्लूप्रिंट परिभाषा एक शब्दकोश के रूप में + +**उदाहरण:** + +```python +blueprint = api.flow().get_blueprint("default") +print(blueprint) # Blueprint configuration +``` + +### `id(self, id='default')` + +किसी विशिष्ट प्रवाह पर संचालन निष्पादित करने के लिए एक फ्लोइंस्टेंस प्राप्त करें। + +**तर्क:** + +`id`: प्रवाह पहचानकर्ता (डिफ़ॉल्ट: "default") + +**वापसी:** फ्लोइंस्टेंस: सेवा संचालन के लिए फ्लो इंस्टेंस + +**उदाहरण:** + +```python +flow = api.flow().id("my-flow") +response = flow.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `list(self)` + +सभी सक्रिय फ्लो इंस्टेंस की सूची बनाएं। + +**रिटर्न:** list[str]: फ्लो इंस्टेंस आईडी की सूची + +**उदाहरण:** + +```python +flows = api.flow().list() +print(flows) # ['default', 'flow-1', 'flow-2', ...] +``` + +### `list_blueprints(self)` + +उपलब्ध सभी फ्लो ब्लूप्रिंट की सूची बनाएं। + +**रिटर्न:** list[str]: ब्लूप्रिंट नामों की सूची + +**उदाहरण:** + +```python +blueprints = api.flow().list_blueprints() +print(blueprints) # ['default', 'custom-flow', ...] +``` + +### `put_blueprint(self, blueprint_name, definition)` + +एक फ्लो ब्लूप्रिंट बनाएं या अपडेट करें। + +**तर्क:** + +`blueprint_name`: ब्लूप्रिंट के लिए नाम +`definition`: ब्लूप्रिंट परिभाषा डिक्शनरी + +**उदाहरण:** + +```python +definition = { + "services": ["text-completion", "graph-rag"], + "parameters": {"model": "gpt-4"} +} +api.flow().put_blueprint("my-blueprint", definition) +``` + +### `request(self, path=None, request=None)` + +एक फ्लो-स्कोपेड एपीआई अनुरोध करें। + +**तर्क:** + +`path`: फ्लो एंडपॉइंट्स के लिए वैकल्पिक पथ प्रत्यय +`request`: अनुरोध पेलोड डिक्शनरी + +**रिटर्न:** डिक्ट: प्रतिक्रिया ऑब्जेक्ट + +**अपवाद:** + +`RuntimeError`: यदि अनुरोध पैरामीटर निर्दिष्ट नहीं है + +### `start(self, blueprint_name, id, description, parameters=None)` + +एक ब्लूप्रिंट से एक नया फ्लो इंस्टेंस शुरू करें। + +**तर्क:** + +`blueprint_name`: इंस्टेंट करने के लिए ब्लूप्रिंट का नाम +`id`: फ्लो इंस्टेंस के लिए अद्वितीय पहचानकर्ता +`description`: मानव-पठनीय विवरण +`parameters`: वैकल्पिक पैरामीटर डिक्शनरी + +**उदाहरण:** + +```python +api.flow().start( + blueprint_name="default", + id="my-flow", + description="My custom flow", + parameters={"model": "gpt-4"} +) +``` + +### `stop(self, id)` + +एक चल रहे फ्लो इंस्टेंस को रोकें। + +**तर्क:** + +`id`: रोकने के लिए फ्लो इंस्टेंस आईडी + +**उदाहरण:** + +```python +api.flow().stop("my-flow") +``` + + +-- + +## `FlowInstance` + +```python +from trustgraph.api import FlowInstance +``` + +किसी विशिष्ट प्रवाह पर सेवाओं को निष्पादित करने के लिए फ्लो इंस्टेंस क्लाइंट। + +यह क्लास सभी ट्रस्टग्राफ सेवाओं तक पहुंच प्रदान करता है, जिनमें शामिल हैं: +टेक्स्ट पूर्णता और एम्बेडिंग +राज्य प्रबंधन के साथ एजेंट ऑपरेशन +ग्राफ और दस्तावेज़ RAG क्वेरी +नॉलेज ग्राफ ऑपरेशन (ट्रिपल्स, ऑब्जेक्ट) +दस्तावेज़ लोडिंग और प्रोसेसिंग +प्राकृतिक भाषा से GraphQL क्वेरी रूपांतरण +संरचित डेटा विश्लेषण और स्कीमा डिटेक्शन +MCP टूल निष्पादन +प्रॉम्प्ट टेम्पलेटिंग + +सेवाओं को एक चल रहे फ्लो इंस्टेंस के माध्यम से एक्सेस किया जाता है जिसकी पहचान ID से होती है। + +### विधियाँ + +### `__init__(self, api, id)` + +फ्लोइंस्टेंस को इनिशियलाइज़ करें। + +**तर्क:** + +`api`: पैरेंट फ्लो क्लाइंट +`id`: फ्लो इंस्टेंस पहचानकर्ता + +### `agent(self, question, user='trustgraph', state=None, group=None, history=None)` + +तर्क और टूल उपयोग क्षमताओं के साथ एक एजेंट ऑपरेशन निष्पादित करें। + +एजेंट बहु-चरणीय तर्क कर सकते हैं, टूल का उपयोग कर सकते हैं और बातचीत में संवादी +स्थिति को बनाए रख सकते हैं। यह एक सिंक्रोनस, नॉन-स्ट्रीमिंग संस्करण है। + +**तर्क:** + +`question`: उपयोगकर्ता का प्रश्न या निर्देश +`user`: उपयोगकर्ता पहचानकर्ता (डिफ़ॉल्ट: "trustgraph") +`state`: राज्यपूर्ण वार्तालापों के लिए वैकल्पिक राज्य शब्दकोश +`group`: बहु-उपयोगकर्ता संदर्भों के लिए वैकल्पिक समूह पहचानकर्ता +`history`: संदेशों की सूची के रूप में वैकल्पिक वार्तालाप इतिहास + +**रिटर्न:** str: एजेंट का अंतिम उत्तर + +**उदाहरण:** + +```python +flow = api.flow().id("default") + +# Simple question +answer = flow.agent( + question="What is the capital of France?", + user="trustgraph" +) + +# With conversation history +history = [ + {"role": "user", "content": "Hello"}, + {"role": "assistant", "content": "Hi! How can I help?"} +] +answer = flow.agent( + question="Tell me about Paris", + user="trustgraph", + history=history +) +``` + +### `detect_type(self, sample)` + +संरचित डेटा नमूने के डेटा प्रकार का पता लगाएं। + +**तर्क:** + +`sample`: विश्लेषण करने के लिए डेटा नमूना (स्ट्रिंग सामग्री) + +**रिटर्न:** detected_type, confidence और वैकल्पिक मेटाडेटा के साथ एक डिक्शनरी। + +### `diagnose_data(self, sample, schema_name=None, options=None)` + +संयुक्त डेटा निदान करें: प्रकार का पता लगाएं और विवरणिका उत्पन्न करें। + +**तर्क:** + +`sample`: विश्लेषण करने के लिए डेटा नमूना (स्ट्रिंग सामग्री) +`schema_name`: विवरणिका पीढ़ी के लिए वैकल्पिक लक्ष्य स्कीमा नाम। +`options`: वैकल्पिक पैरामीटर (जैसे, CSV के लिए विभाजक)। + +**वापसी:** `detected_type`, `confidence`, `descriptor` और `metadata` के साथ एक डिक्शनरी। + +### `document_embeddings_query(self, text, user, collection, limit=10)` + +सिमेंटिक समानता का उपयोग करके दस्तावेज़ के टुकड़ों को क्वेरी करें। + +वे दस्तावेज़ के टुकड़े खोजें जिनके सामग्री वेक्टर एम्बेडिंग का उपयोग करके इनपुट टेक्स्ट के सिमेंटिक रूप से समान हैं। + + +**तर्क:** + +`text`: सिमेंटिक खोज के लिए क्वेरी टेक्स्ट। +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता। +`collection`: संग्रह पहचानकर्ता। +`limit`: अधिकतम परिणामों की संख्या (डिफ़ॉल्ट: 10)। + +**वापसी:** `dict`: क्वेरी परिणाम जिनमें `chunk_id` और `score` वाले टुकड़े शामिल हैं। + +**उदाहरण:** + +```python +flow = api.flow().id("default") +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "doc1/p0/c0", "score": 0.95}, ...]} +``` + +### `document_rag(self, query, user='trustgraph', collection='default', doc_limit=10)` + +दस्तावेज़-आधारित पुनर्प्राप्ति-संवर्धित पीढ़ी (RAG) क्वेरी निष्पादित करें। + +दस्तावेज़ RAG प्रासंगिक दस्तावेज़ अंशों को खोजने के लिए वेक्टर एम्बेडिंग का उपयोग करता है, +फिर उन अंशों को संदर्भ के रूप में उपयोग करके एक LLM के साथ एक प्रतिक्रिया उत्पन्न करता है। + +**तर्क:** + +`query`: प्राकृतिक भाषा क्वेरी +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (डिफ़ॉल्ट: "ट्रस्टग्राफ") +`collection`: संग्रह पहचानकर्ता (डिफ़ॉल्ट: "डिफ़ॉल्ट") +`doc_limit`: पुनर्प्राप्त किए जाने वाले अधिकतम दस्तावेज़ अंश (डिफ़ॉल्ट: 10) + +**रिटर्न:** स्ट्रिंग: दस्तावेज़ संदर्भ को शामिल करने वाली उत्पन्न प्रतिक्रिया + +**उदाहरण:** + +```python +flow = api.flow().id("default") +response = flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts)` + +एक या अधिक ग्रंथों के लिए वेक्टर एम्बेडिंग उत्पन्न करें। + +ग्रंथों को घने वेक्टर निरूपण में परिवर्तित करता है जो सिमेंटिक +खोज और समानता तुलना के लिए उपयुक्त है। + +**तर्क:** + +`texts`: एम्बेड करने के लिए इनपुट ग्रंथों की सूची + +**रिटर्न:** list[list[list[float]]]: वेक्टर एम्बेडिंग, प्रत्येक इनपुट टेक्स्ट के लिए एक सेट + +**उदाहरण:** + +```python +flow = api.flow().id("default") +vectors = flow.embeddings(["quantum computing"]) +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `generate_descriptor(self, sample, data_type, schema_name, options=None)` + +संरचित डेटा के लिए एक विवरण उत्पन्न करें जो एक विशिष्ट स्कीमा से मेल खाता हो। + +**तर्क:** + +`sample`: विश्लेषण करने के लिए डेटा नमूना (स्ट्रिंग सामग्री) +`data_type`: डेटा प्रकार (csv, json, xml) +`schema_name`: विवरण पीढ़ी के लिए लक्षित स्कीमा नाम +`options`: वैकल्पिक पैरामीटर (जैसे, CSV के लिए विभाजक) + +**रिटर्न:** विवरण और मेटाडेटा के साथ डिक्ट + +### `graph_embeddings_query(self, text, user, collection, limit=10)` + +सिमेंटिक समानता का उपयोग करके नॉलेज ग्राफ एंटिटीज को क्वेरी करें। + +नॉलेज ग्राफ में उन एंटिटीज को खोजें जिनके विवरण इनपुट टेक्स्ट के समान अर्थ वाले हों, +वेक्टर एम्बेडिंग का उपयोग करके। + +**तर्क:** + +`text`: सिमेंटिक खोज के लिए क्वेरी टेक्स्ट +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`limit`: अधिकतम परिणामों की संख्या (डिफ़ॉल्ट: 10) + +**रिटर्न:** डिक्ट: समान एंटिटीज के साथ क्वेरी परिणाम + +**उदाहरण:** + +```python +flow = api.flow().id("default") +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +# results contains {"entities": [{"entity": {...}, "score": 0.95}, ...]} +``` + +### `graph_rag(self, query, user='trustgraph', collection='default', entity_limit=50, triple_limit=30, max_subgraph_size=150, max_path_length=2)` + +ग्राफ-आधारित रिट्रीवल-ऑगमेंटेड जनरेशन (RAG) क्वेरी निष्पादित करें। + +ग्राफ RAG प्रासंगिक संदर्भ खोजने के लिए नॉलेज ग्राफ संरचना का उपयोग करता है, +एंटिटी संबंधों को पार करके, और फिर एक एलएलएम का उपयोग करके एक प्रतिक्रिया उत्पन्न करता है। + +**तर्क:** + +`query`: प्राकृतिक भाषा क्वेरी +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (डिफ़ॉल्ट: "ट्रस्टग्राफ") +`collection`: संग्रह पहचानकर्ता (डिफ़ॉल्ट: "डिफ़ॉल्ट") +`entity_limit`: पुनः प्राप्त करने के लिए अधिकतम एंटिटीज (डिफ़ॉल्ट: 50) +`triple_limit`: प्रति एंटिटी अधिकतम ट्रिपल (डिफ़ॉल्ट: 30) +`max_subgraph_size`: सबग्राफ में अधिकतम कुल ट्रिपल (डिफ़ॉल्ट: 150) +`max_path_length`: अधिकतम ट्रैवर्सल गहराई (डिफ़ॉल्ट: 2) + +**रिटर्न:** स्ट्र: ग्राफ संदर्भ को शामिल करने वाली उत्पन्न प्रतिक्रिया + +**उदाहरण:** + +```python +flow = api.flow().id("default") +response = flow.graph_rag( + query="Tell me about Marie Curie's discoveries", + user="trustgraph", + collection="scientists", + entity_limit=20, + max_path_length=3 +) +print(response) +``` + +### `load_document(self, document, id=None, metadata=None, user=None, collection=None)` + +प्रसंस्करण के लिए एक बाइनरी दस्तावेज़ लोड करें। + +एक दस्तावेज़ (पीडीएफ, डॉक्स, चित्र, आदि) को निष्कर्षण और +प्रसंस्करण के लिए अपलोड करें, जो प्रवाह के दस्तावेज़ पाइपलाइन के माध्यम से होता है। + +**तर्क:** + +`document`: बाइट्स के रूप में दस्तावेज़ सामग्री +`id`: वैकल्पिक दस्तावेज़ पहचानकर्ता (यदि None है तो स्वचालित रूप से उत्पन्न) +`metadata`: वैकल्पिक मेटाडेटा (ट्रिपल्स की सूची या emit विधि वाला ऑब्जेक्ट) +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (वैकल्पिक) +`collection`: संग्रह पहचानकर्ता (वैकल्पिक) + +**रिटर्न:** dict: प्रसंस्करण प्रतिक्रिया + +**अपवाद:** + +`RuntimeError`: यदि आईडी के बिना मेटाडेटा प्रदान किया गया है + +**उदाहरण:** + +```python +flow = api.flow().id("default") + +# Load a PDF document +with open("research.pdf", "rb") as f: + result = flow.load_document( + document=f.read(), + id="research-001", + user="trustgraph", + collection="papers" + ) +``` + +### `load_text(self, text, id=None, metadata=None, charset='utf-8', user=None, collection=None)` + +प्रसंस्करण के लिए पाठ सामग्री लोड करें। + +प्रवाह के पाठ पाइपलाइन के माध्यम से निष्कर्षण और प्रसंस्करण के लिए पाठ सामग्री अपलोड करें। +पाठ पाइपलाइन। + +**तर्क:** + +`text`: बाइट्स के रूप में पाठ सामग्री +`id`: वैकल्पिक दस्तावेज़ पहचानकर्ता (यदि None है तो स्वचालित रूप से उत्पन्न) +`metadata`: वैकल्पिक मेटाडेटा (ट्रिपल की सूची या emit विधि वाला ऑब्जेक्ट) +`charset`: वर्ण एन्कोडिंग (डिफ़ॉल्ट: "utf-8") +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (वैकल्पिक) +`collection`: संग्रह पहचानकर्ता (वैकल्पिक) + +**रिटर्न:** dict: प्रसंस्करण प्रतिक्रिया + +**अपवाद:** + +`RuntimeError`: यदि आईडी के बिना मेटाडेटा प्रदान किया गया है + +**उदाहरण:** + +```python +flow = api.flow().id("default") + +# Load text content +text_content = b"This is the document content..." +result = flow.load_text( + text=text_content, + id="text-001", + charset="utf-8", + user="trustgraph", + collection="documents" +) +``` + +### `mcp_tool(self, name, parameters={})` + +एक मॉडल कॉन्टेक्स्ट प्रोटोकॉल (MCP) टूल को निष्पादित करें। + +MCP टूल एजेंटों और वर्कफ़्लो के लिए विस्तारित कार्यक्षमता प्रदान करते हैं, +जो बाहरी प्रणालियों और सेवाओं के साथ एकीकरण की अनुमति देते हैं। + +**तर्क:** + +`name`: टूल का नाम/पहचानकर्ता +`parameters`: टूल पैरामीटर डिक्शनरी (डिफ़ॉल्ट: {}) + +**रिटर्न:** स्ट्र या डिक्ट: टूल निष्पादन परिणाम + +**अपवाद:** + +`ProtocolException`: यदि प्रतिक्रिया प्रारूप अमान्य है + +**उदाहरण:** + +```python +flow = api.flow().id("default") + +# Execute a tool +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `nlp_query(self, question, max_results=100)` + +एक प्राकृतिक भाषा प्रश्न को GraphQL क्वेरी में बदलें। + +**तर्क:** + +`question`: प्राकृतिक भाषा प्रश्न +`max_results`: वापस करने के लिए अधिकतम परिणामों की संख्या (डिफ़ॉल्ट: 100) + +**वापसी:** graphql_query, variables, detected_schemas, confidence के साथ एक शब्दकोश। + +### `prompt(self, id, variables)` + +चर प्रतिस्थापन के साथ एक प्रॉम्प्ट टेम्पलेट निष्पादित करें। + +प्रॉम्प्ट टेम्प्लेट, गतिशील चर के साथ पुन: प्रयोज्य प्रॉम्प्ट पैटर्न की अनुमति देते हैं, जो सुसंगत प्रॉम्प्ट इंजीनियरिंग के लिए उपयोगी है। +चर प्रतिस्थापन, सुसंगत प्रॉम्प्ट इंजीनियरिंग के लिए उपयोगी। + +**तर्क:** + +`id`: प्रॉम्प्ट टेम्प्लेट पहचानकर्ता +`variables`: चर नाम से मान मैपिंग का शब्दकोश + +**रिटर्न:** स्ट्र या डिक्ट: प्रस्तुत प्रॉम्प्ट परिणाम (टेक्स्ट या संरचित ऑब्जेक्ट) + +**अपवाद:** + +`ProtocolException`: यदि प्रतिक्रिया प्रारूप अमान्य है + +**उदाहरण:** + +```python +flow = api.flow().id("default") + +# Text template +result = flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"} +) + +# Structured template +result = flow.prompt( + id="extract-entities", + variables={"text": "Marie Curie won Nobel Prizes"} +) +``` + +### `request(self, path, request)` + +इस फ्लो इंस्टेंस पर एक सेवा अनुरोध करें। + +**तर्क:** + +`path`: सेवा पथ (उदाहरण के लिए, "service/text-completion") +`request`: अनुरोध पेलोड डिक्शनरी + +**रिटर्न:** डिक्ट: सेवा प्रतिक्रिया + +### `row_embeddings_query(self, text, schema_name, user='trustgraph', collection='default', index_name=None, limit=10)` + +अनुक्रमित फ़ील्ड पर सिमेंटिक समानता का उपयोग करके पंक्ति डेटा क्वेरी करें। + +उन पंक्तियों को खोजता है जिनके अनुक्रमित फ़ील्ड मान इनपुट टेक्स्ट के अर्थ के समान हों, वेक्टर एम्बेडिंग का उपयोग करके। यह संरचित डेटा पर अस्पष्ट/अर्थ संबंधी मिलान को सक्षम बनाता है। + +**तर्क:** + + + +`text`: सिमेंटिक खोज के लिए क्वेरी टेक्स्ट। +`schema_name`: खोज करने के लिए स्कीमा का नाम। +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (डिफ़ॉल्ट: "trustgraph")। +`collection`: संग्रह पहचानकर्ता (डिफ़ॉल्ट: "default")। +`index_name`: वैकल्पिक इंडेक्स नाम, जिससे खोज को विशिष्ट इंडेक्स तक सीमित किया जा सके। +`limit`: अधिकतम परिणामों की संख्या (डिफ़ॉल्ट: 10)। + +**रिटर्न:** डिक्ट: क्वेरी परिणाम जिनमें index_name, index_value, text और score शामिल हैं। + +**उदाहरण:** + +```python +flow = api.flow().id("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query, user='trustgraph', collection='default', variables=None, operation_name=None)` + +ज्ञान ग्राफ में संरचित पंक्तियों के विरुद्ध एक GraphQL क्वेरी निष्पादित करें। + +यह GraphQL सिंटैक्स का उपयोग करके संरचित डेटा पर क्वेरी करता है, जो जटिल क्वेरी की अनुमति देता है +फ़िल्टरिंग, एग्रीगेशन और संबंध ट्रैवर्सल के साथ। + +**तर्क:** + +`query`: GraphQL क्वेरी स्ट्रिंग +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (डिफ़ॉल्ट: "trustgraph") +`collection`: संग्रह पहचानकर्ता (डिफ़ॉल्ट: "default") +`variables`: वैकल्पिक क्वेरी चर शब्दकोश +`operation_name`: मल्टी-ऑपरेशन दस्तावेज़ों के लिए वैकल्पिक ऑपरेशन नाम + +**रिटर्न:** dict: 'data', 'errors' और/या 'extensions' फ़ील्ड के साथ GraphQL प्रतिक्रिया + +**अपवाद:** + +`ProtocolException`: यदि सिस्टम-स्तरीय त्रुटि होती है + +**उदाहरण:** + +```python +flow = api.flow().id("default") + +# Simple query +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) + +# Query with variables +query = ''' +query GetScientist($name: String!) { + scientists(name: $name) { + name + nobelPrizes + } +} +''' +result = flow.rows_query( + query=query, + variables={"name": "Marie Curie"} +) +``` + +### `schema_selection(self, sample, options=None)` + +प्रॉम्प्ट विश्लेषण का उपयोग करके डेटा नमूने के लिए मिलान करने वाले स्कीमा का चयन करें। + +**तर्क:** + +`sample`: विश्लेषण करने के लिए डेटा नमूना (स्ट्रिंग सामग्री) +`options`: वैकल्पिक पैरामीटर + +**रिटर्न:** schema_matches सरणी और मेटाडेटा के साथ डिक्ट + +### `structured_query(self, question, user='trustgraph', collection='default')` + +संरचित डेटा के खिलाफ एक प्राकृतिक भाषा प्रश्न निष्पादित करें। +एनएलपी क्वेरी रूपांतरण और GraphQL निष्पादन को जोड़ता है। + +**तर्क:** + +`question`: प्राकृतिक भाषा प्रश्न +`user`: कैसेंड्रा कीस्पेस पहचानकर्ता (डिफ़ॉल्ट: "trustgraph") +`collection`: डेटा संग्रह पहचानकर्ता (डिफ़ॉल्ट: "default") + +**रिटर्न:** डेटा और वैकल्पिक त्रुटियों के साथ डिक्ट + +### `text_completion(self, system, prompt)` + +फ़्लो के एलएलएम का उपयोग करके टेक्स्ट कंप्लीशन निष्पादित करें। + +**तर्क:** + +`system`: सिस्टम प्रॉम्प्ट जो सहायक के व्यवहार को परिभाषित करता है +`prompt`: उपयोगकर्ता प्रॉम्प्ट/प्रश्न + +**रिटर्न:** स्ट्र: उत्पन्न प्रतिक्रिया पाठ + +**उदाहरण:** + +```python +flow = api.flow().id("default") +response = flow.text_completion( + system="You are a helpful assistant", + prompt="What is quantum computing?" +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=10000)` + +पैटर्न मिलान का उपयोग करके ज्ञान ग्राफ त्रिकों को क्वेरी करें। + +यह आरडीएफ त्रिकों की खोज करता है जो दिए गए विषय, विधेय और/या +ऑब्जेक्ट पैटर्न से मेल खाते हैं। अनिश्चित पैरामीटर वाइल्डकार्ड के रूप में कार्य करते हैं। + +**तर्क:** + +`s`: विषय यूआरआई (वैकल्पिक, वाइल्डकार्ड के लिए None का उपयोग करें) +`p`: विधेय यूआरआई (वैकल्पिक, वाइल्डकार्ड के लिए None का उपयोग करें) +`o`: ऑब्जेक्ट यूआरआई या लिटरल (वैकल्पिक, वाइल्डकार्ड के लिए None का उपयोग करें) +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (वैकल्पिक) +`collection`: संग्रह पहचानकर्ता (वैकल्पिक) +`limit`: वापस करने के लिए अधिकतम परिणाम (डिफ़ॉल्ट: 10000) + +**रिटर्न:** list[Triple]: मिलान करने वाले ट्रिपल ऑब्जेक्ट की सूची + +**उठाता है:** + +`RuntimeError`: यदि s या p यूआरआई नहीं है, या o यूआरआई/लिटरल नहीं है + +**उदाहरण:** + +```python +from trustgraph.knowledge import Uri, Literal + +flow = api.flow().id("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s=Uri("http://example.org/person/marie-curie"), + user="trustgraph", + collection="scientists" +) + +# Find all instances of a specific relationship +triples = flow.triples_query( + p=Uri("http://example.org/ontology/discovered"), + limit=100 +) +``` + + +-- + +## `AsyncFlow` + +```python +from trustgraph.api import AsyncFlow +``` + +REST API का उपयोग करके एसिंक्रोनस फ्लो प्रबंधन क्लाइंट। + +यह एसिंक/अवेट पर आधारित फ्लो प्रबंधन संचालन प्रदान करता है, जिसमें लिस्टिंग, +फ्लो शुरू करना, बंद करना और फ्लो क्लास परिभाषाओं का प्रबंधन शामिल है। यह एजेंटों, RAG और प्रश्नों जैसी फ्लो-स्कोप सेवाओं तक गैर-स्ट्रीमिंग +REST एंडपॉइंट के माध्यम से पहुंच भी प्रदान करता है। + + +ध्यान दें: स्ट्रीमिंग समर्थन के लिए, AsyncSocketClient का उपयोग करें। + +### विधियाँ + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +एसिंक्रोनस फ्लो क्लाइंट को इनिशियलाइज़ करें। + +**तर्क:** + +`url`: ट्रस्टग्राफ API के लिए बेस URL +`timeout`: सेकंड में अनुरोध टाइमआउट +`token`: प्रमाणीकरण के लिए वैकल्पिक बेयरर टोकन + +### `aclose(self) -> None` + +एसिंक्रोनस क्लाइंट को बंद करें और संसाधनों को साफ़ करें। + +ध्यान दें: सफाई aiohttp सत्र संदर्भ प्रबंधकों द्वारा स्वचालित रूप से संभाली जाती है। +यह विधि अन्य एसिंक्रोनस क्लाइंट के साथ स्थिरता के लिए प्रदान की गई है। + +### `delete_class(self, class_name: str)` + +एक फ्लो क्लास परिभाषा को हटाएं। + +यह सिस्टम से एक फ्लो क्लास ब्लूप्रिंट को हटा देता है। यह चल रहे फ्लो उदाहरणों को प्रभावित नहीं करता है। + + +**तर्क:** + +`class_name`: हटाने के लिए फ्लो क्लास का नाम + +**उदाहरण:** + +```python +async_flow = await api.async_flow() + +# Delete a flow class +await async_flow.delete_class("old-flow-class") +``` + +### `get(self, id: str) -> Dict[str, Any]` + +प्रवाह परिभाषा प्राप्त करें। + +यह पूर्ण प्रवाह कॉन्फ़िगरेशन प्राप्त करता है, जिसमें इसका क्लास नाम, +विवरण और पैरामीटर शामिल हैं। + +**तर्क:** + +`id`: प्रवाह पहचानकर्ता + +**वापसी:** dict: प्रवाह परिभाषा ऑब्जेक्ट + +**उदाहरण:** + +```python +async_flow = await api.async_flow() + +# Get flow definition +flow_def = await async_flow.get("default") +print(f"Flow class: {flow_def.get('class-name')}") +print(f"Description: {flow_def.get('description')}") +``` + +### `get_class(self, class_name: str) -> Dict[str, Any]` + +प्रवाह वर्ग परिभाषा प्राप्त करें। + +यह एक प्रवाह वर्ग के लिए ब्लूप्रिंट परिभाषा प्राप्त करता है, जिसमें इसका +कॉन्फ़िगरेशन स्कीमा और सेवा बाइंडिंग शामिल हैं। + +**तर्क:** + +`class_name`: प्रवाह वर्ग का नाम + +**वापसी:** dict: प्रवाह वर्ग परिभाषा ऑब्जेक्ट + +**उदाहरण:** + +```python +async_flow = await api.async_flow() + +# Get flow class definition +class_def = await async_flow.get_class("default") +print(f"Services: {class_def.get('services')}") +``` + +### `id(self, flow_id: str)` + +एक एसिंक्रोनस फ्लो इंस्टेंस क्लाइंट प्राप्त करें। + +यह एक विशिष्ट फ्लो की सेवाओं के साथ इंटरैक्ट करने के लिए एक क्लाइंट लौटाता है +(एजेंट, आरएजी, प्रश्न, एम्बेडिंग, आदि)। + +**तर्क:** + +`flow_id`: प्रवाह पहचानकर्ता + +**वापसी:** AsyncFlowInstance: प्रवाह-विशिष्ट कार्यों के लिए क्लाइंट + +**उदाहरण:** + +```python +async_flow = await api.async_flow() + +# Get flow instance +flow = async_flow.id("default") + +# Use flow services +result = await flow.graph_rag( + query="What is TrustGraph?", + user="trustgraph", + collection="default" +) +``` + +### `list(self) -> List[str]` + +सभी फ्लो पहचानकर्ताओं की सूची बनाएं। + +सिस्टम में वर्तमान में तैनात सभी फ्लो के आईडी प्राप्त करता है। + +**रिटर्न:** list[str]: फ्लो पहचानकर्ताओं की सूची + +**उदाहरण:** + +```python +async_flow = await api.async_flow() + +# List all flows +flows = await async_flow.list() +print(f"Available flows: {flows}") +``` + +### `list_classes(self) -> List[str]` + +सभी फ्लो क्लास नामों की सूची बनाएं। + +सिस्टम में उपलब्ध सभी फ्लो क्लास (ब्लूप्रिंट) के नामों को प्राप्त करता है। + +**रिटर्न:** list[str]: फ्लो क्लास नामों की सूची + +**उदाहरण:** + +```python +async_flow = await api.async_flow() + +# List available flow classes +classes = await async_flow.list_classes() +print(f"Available flow classes: {classes}") +``` + +### `put_class(self, class_name: str, definition: Dict[str, Any])` + +एक फ्लो क्लास परिभाषा बनाएं या अपडेट करें। + +यह एक फ्लो क्लास ब्लूप्रिंट संग्रहीत करता है जिसका उपयोग फ्लो को इंस्टेंटिएट करने के लिए किया जा सकता है। + +**तर्क:** + +`class_name`: फ्लो क्लास का नाम +`definition`: फ्लो क्लास परिभाषा ऑब्जेक्ट + +**उदाहरण:** + +```python +async_flow = await api.async_flow() + +# Create a custom flow class +class_def = { + "services": { + "agent": {"module": "agent", "config": {...}}, + "graph-rag": {"module": "graph-rag", "config": {...}} + } +} +await async_flow.put_class("custom-flow", class_def) +``` + +### `request(self, path: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +गेटवे एपीआई को एसिंक्रोनस एचटीटीपी पोस्ट अनुरोध भेजें। + +ट्रस्टग्राफ एपीआई को प्रमाणित अनुरोध भेजने के लिए आंतरिक विधि। + +**तर्क:** + +`path`: एपीआई एंडपॉइंट पथ (बेस यूआरएल के सापेक्ष) +`request_data`: अनुरोध पेलोड डिक्शनरी + +**रिटर्न:** डिक्ट: एपीआई से प्रतिक्रिया ऑब्जेक्ट + +**अपवाद:** + +`ProtocolException`: यदि HTTP स्थिति 200 नहीं है या प्रतिक्रिया मान्य JSON नहीं है +`ApplicationException`: यदि API एक त्रुटि प्रतिक्रिया देता है + +### `start(self, class_name: str, id: str, description: str, parameters: Dict | None = None)` + +एक नया फ्लो इंस्टेंस शुरू करें। + +निर्दिष्ट मापदंडों के साथ एक फ्लो क्लास परिभाषा से एक फ्लो बनाता है और शुरू करता है। + + +**तर्क:** + +`class_name`: फ्लो क्लास का नाम जिसे इंस्टेंट किया जाना है +`id`: नए फ्लो इंस्टेंस के लिए पहचानकर्ता +`description`: फ्लो का मानव-पठनीय विवरण +`parameters`: फ्लो के लिए वैकल्पिक कॉन्फ़िगरेशन पैरामीटर + +**उदाहरण:** + +```python +async_flow = await api.async_flow() + +# Start a flow from a class +await async_flow.start( + class_name="default", + id="my-flow", + description="Custom flow instance", + parameters={"model": "claude-3-opus"} +) +``` + +### `stop(self, id: str)` + +किसी चल रही प्रक्रिया को रोकें। + +यह एक प्रक्रिया के उदाहरण को रोकता है और उसे हटा देता है, जिससे उसके संसाधनों को मुक्त किया जा सकता है। + +**तर्क:** + +`id`: रोकने के लिए प्रक्रिया की पहचानकर्ता। + +**उदाहरण:** + +```python +async_flow = await api.async_flow() + +# Stop a flow +await async_flow.stop("my-flow") +``` + + +-- + +## `AsyncFlowInstance` + +```python +from trustgraph.api import AsyncFlowInstance +``` + +एसिंक्रोनस फ्लो इंस्टेंस क्लाइंट। + +यह एजेंटों, +आरएजी प्रश्नों, एम्बेडिंग और ग्राफ प्रश्नों सहित फ्लो-स्कोप सेवाओं तक एसिंक्रोनस/अवेट एक्सेस प्रदान करता है। सभी ऑपरेशन पूर्ण +प्रतिक्रियाएं (गैर-स्ट्रीमिंग) लौटाते हैं। + +ध्यान दें: स्ट्रीमिंग समर्थन के लिए, AsyncSocketFlowInstance का उपयोग करें। + +### विधियाँ + +### `__init__(self, flow: trustgraph.api.async_flow.AsyncFlow, flow_id: str)` + +एसिंक्रोनस फ्लो इंस्टेंस को इनिशियलाइज़ करें। + +**तर्क:** + +`flow`: पैरेंट AsyncFlow क्लाइंट +`flow_id`: फ्लो पहचानकर्ता + +### `agent(self, question: str, user: str, state: Dict | None = None, group: str | None = None, history: List | None = None, **kwargs: Any) -> Dict[str, Any]` + +एक एजेंट ऑपरेशन निष्पादित करें (गैर-स्ट्रीमिंग)। + +यह एक प्रश्न का उत्तर देने के लिए एक एजेंट चलाता है, जिसमें वैकल्पिक वार्तालाप स्थिति और +इतिहास शामिल है। यह एजेंट द्वारा प्रसंस्करण पूरा करने के बाद पूरी प्रतिक्रिया लौटाता है। + + +ध्यान दें: यह विधि स्ट्रीमिंग का समर्थन नहीं करती है। वास्तविक समय में एजेंट के विचारों और +टिप्पणियों के लिए, AsyncSocketFlowInstance.agent() का उपयोग करें। + +**तर्क:** + +`question`: उपयोगकर्ता का प्रश्न या निर्देश +`user`: उपयोगकर्ता पहचानकर्ता +`state`: वार्तालाप संदर्भ के लिए वैकल्पिक स्थिति शब्दकोश +`group`: सत्र प्रबंधन के लिए वैकल्पिक समूह पहचानकर्ता +`history`: वैकल्पिक वार्तालाप इतिहास सूची +`**kwargs`: अतिरिक्त सेवा-विशिष्ट पैरामीटर + +**रिटर्न:** dict: उत्तर और मेटाडेटा सहित एजेंट की पूरी प्रतिक्रिया + +**उदाहरण:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute agent +result = await flow.agent( + question="What is the capital of France?", + user="trustgraph" +) +print(f"Answer: {result.get('response')}") +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> str` + +दस्तावेज़-आधारित आरएजी क्वेरी (गैर-स्ट्रीमिंग) निष्पादित करें। + +दस्तावेज़ एम्बेडिंग का उपयोग करके पुनर्प्राप्ति-संवर्धित पीढ़ी करता है। +प्रासंगिक दस्तावेज़ अंशों को सिमेंटिक खोज के माध्यम से पुनर्प्राप्त करता है, फिर पुनर्प्राप्त दस्तावेज़ों के आधार पर +एक प्रतिक्रिया उत्पन्न करता है। पूर्ण प्रतिक्रिया लौटाता है। + +ध्यान दें: यह विधि स्ट्रीमिंग का समर्थन नहीं करती है। स्ट्रीमिंग आरएजी प्रतिक्रियाओं के लिए, +AsyncSocketFlowInstance.document_rag() का उपयोग करें। + +**तर्क:** + +`query`: उपयोगकर्ता क्वेरी टेक्स्ट +`user`: उपयोगकर्ता पहचानकर्ता +`collection`: दस्तावेज़ युक्त संग्रह पहचानकर्ता +`doc_limit`: पुनर्प्राप्त किए जाने वाले दस्तावेज़ अंशों की अधिकतम संख्या (डिफ़ॉल्ट: 10) +`**kwargs`: अतिरिक्त सेवा-विशिष्ट पैरामीटर + +**रिटर्न:** str: दस्तावेज़ डेटा के आधार पर उत्पन्न पूर्ण प्रतिक्रिया + +**उदाहरण:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query documents +response = await flow.document_rag( + query="What does the documentation say about authentication?", + user="trustgraph", + collection="docs", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts: list, **kwargs: Any)` + +इनपुट टेक्स्ट के लिए एम्बेडिंग उत्पन्न करें। + +टेक्स्ट को संख्यात्मक वेक्टर प्रतिनिधित्व में परिवर्तित करता है, जो कि फ्लो के +कॉन्फ़िगर किए गए एम्बेडिंग मॉडल का उपयोग करके किया जाता है। सिमेंटिक खोज और समानता +तुलना के लिए उपयोगी। + +**तर्क:** + +`texts`: एम्बेड करने के लिए इनपुट टेक्स्ट की सूची। +`**kwargs`: अतिरिक्त सेवा-विशिष्ट पैरामीटर। + +**रिटर्न:** dict: एम्बेडिंग वेक्टर युक्त प्रतिक्रिया। + +**उदाहरण:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate embeddings +result = await flow.embeddings(texts=["Sample text to embed"]) +vectors = result.get("vectors") +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any)` + +सिमेंटिक इकाई खोज के लिए क्वेरी ग्राफ एम्बेडिंग। + +यह इनपुट टेक्स्ट के लिए सबसे प्रासंगिक इकाइयों को खोजने के लिए ग्राफ इकाई एम्बेडिंग पर सिमेंटिक खोज करता है। समानता के आधार पर रैंक की गई इकाइयों को लौटाता है। + + +**तर्क:** + +`text`: सिमेंटिक खोज के लिए क्वेरी टेक्स्ट। +`user`: उपयोगकर्ता पहचानकर्ता। +`collection`: ग्राफ एम्बेडिंग युक्त संग्रह पहचानकर्ता। +`limit`: लौटाने के लिए अधिकतम परिणामों की संख्या (डिफ़ॉल्ट: 10)। +`**kwargs`: अतिरिक्त सेवा-विशिष्ट पैरामीटर। + +**रिटर्न:** dict: रैंक किए गए इकाई मिलानों के साथ प्रतिक्रिया, जिसमें समानता स्कोर शामिल हैं। + +**उदाहरण:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find related entities +results = await flow.graph_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="tech-kb", + limit=5 +) + +for entity in results.get("entities", []): + print(f"{entity['name']}: {entity['score']}") +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> str` + +ग्राफ-आधारित आरएजी क्वेरी (गैर-स्ट्रीमिंग) निष्पादित करें। + +यह ज्ञान ग्राफ डेटा का उपयोग करके पुनर्प्राप्ति-संवर्धित पीढ़ी करता है। +यह प्रासंगिक संस्थाओं और उनके संबंधों की पहचान करता है, और फिर ग्राफ संरचना पर आधारित एक +प्रतिक्रिया उत्पन्न करता है। यह पूर्ण प्रतिक्रिया लौटाता है। + +ध्यान दें: यह विधि स्ट्रीमिंग का समर्थन नहीं करती है। स्ट्रीमिंग आरएजी प्रतिक्रियाओं के लिए, +AsyncSocketFlowInstance.graph_rag() का उपयोग करें। + +**तर्क:** + +`query`: उपयोगकर्ता क्वेरी टेक्स्ट +`user`: उपयोगकर्ता पहचानकर्ता +`collection`: ज्ञान ग्राफ युक्त संग्रह पहचानकर्ता +`max_subgraph_size`: प्रति सबग्राफ अधिकतम त्रिकों की संख्या (डिफ़ॉल्ट: 1000) +`max_subgraph_count`: पुनर्प्राप्त किए जाने वाले अधिकतम सबग्राफ की संख्या (डिफ़ॉल्ट: 5) +`max_entity_distance`: इकाई विस्तार के लिए अधिकतम ग्राफ दूरी (डिफ़ॉल्ट: 3) +`**kwargs`: अतिरिक्त सेवा-विशिष्ट पैरामीटर + +**रिटर्न:** स्ट्रिंग: ग्राफ डेटा पर आधारित पूर्ण उत्पन्न प्रतिक्रिया + +**उदाहरण:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query knowledge graph +response = await flow.graph_rag( + query="What are the relationships between these entities?", + user="trustgraph", + collection="medical-kb", + max_subgraph_count=3 +) +print(response) +``` + +### `request(self, service: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +किसी फ्लो-स्कोप सेवा को अनुरोध भेजें। + +इस फ्लो इंस्टेंस के भीतर सेवाओं को कॉल करने के लिए आंतरिक विधि। + +**तर्क:** + +`service`: सेवा का नाम (उदाहरण के लिए, "एजेंट", "ग्राफ-आरएजी", "ट्रिपल्स") +`request_data`: सेवा अनुरोध पेलोड + +**रिटर्न:** डिक्ट: सेवा प्रतिक्रिया ऑब्जेक्ट + +**अपवाद:** + +`ProtocolException`: यदि अनुरोध विफल हो जाता है या प्रतिक्रिया अमान्य है +`ApplicationException`: यदि सेवा कोई त्रुटि लौटाती है + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any)` + +संरचित डेटा पर सिमेंटिक खोज के लिए क्वेरी रो एम्बेडिंग। + +पंक्तियों के रो इंडेक्स एम्बेडिंग पर सिमेंटिक खोज करता है ताकि उन पंक्तियों को खोजा जा सके जिनके +अनुक्रमित फ़ील्ड मान इनपुट टेक्स्ट के सबसे समान हैं। संरचित डेटा पर अस्पष्ट/सिमेंटिक मिलान को सक्षम करता है। + +**तर्क:** + + +`text`: सिमेंटिक खोज के लिए क्वेरी टेक्स्ट। +`schema_name`: खोज के लिए स्कीमा नाम। +`user`: उपयोगकर्ता पहचानकर्ता (डिफ़ॉल्ट: "trustgraph")। +`collection`: संग्रह पहचानकर्ता (डिफ़ॉल्ट: "default")। +`index_name`: वैकल्पिक इंडेक्स नाम जिसका उपयोग खोज को विशिष्ट इंडेक्स तक सीमित करने के लिए किया जा सकता है। +`limit`: वापस करने के लिए अधिकतम परिणामों की संख्या (डिफ़ॉल्ट: 10)। +`**kwargs`: अतिरिक्त सेवा-विशिष्ट पैरामीटर। + +**रिटर्न:** dict: मिलान वाले उत्तर जिसमें index_name, index_value, text और score शामिल हैं। + +**उदाहरण:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Search for customers by name similarity +results = await flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +for match in results.get("matches", []): + print(f"{match['index_name']}: {match['index_value']} (score: {match['score']})") +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs: Any)` + +संग्रहीत पंक्तियों पर एक GraphQL क्वेरी निष्पादित करें। + +यह संरचित डेटा पंक्तियों को GraphQL सिंटैक्स का उपयोग करके क्वेरी करता है। यह चर और नामित ऑपरेशनों के साथ जटिल +क्वेरी का समर्थन करता है। + +**तर्क:** + +`query`: GraphQL क्वेरी स्ट्रिंग +`user`: उपयोगकर्ता पहचानकर्ता +`collection`: पंक्तियों वाले संग्रह पहचानकर्ता +`variables`: वैकल्पिक GraphQL क्वेरी चर +`operation_name`: मल्टी-ऑपरेशन क्वेरी के लिए वैकल्पिक ऑपरेशन नाम +`**kwargs`: अतिरिक्त सेवा-विशिष्ट पैरामीटर + +**रिटर्न:** dict: डेटा और/या त्रुटियों के साथ GraphQL प्रतिक्रिया + +**उदाहरण:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute GraphQL query +query = ''' + query GetUsers($status: String!) { + users(status: $status) { + id + name + email + } + } +''' + +result = await flow.rows_query( + query=query, + user="trustgraph", + collection="users", + variables={"status": "active"} +) + +for user in result.get("data", {}).get("users", []): + print(f"{user['name']}: {user['email']}") +``` + +### `text_completion(self, system: str, prompt: str, **kwargs: Any) -> str` + +पाठ पूर्णता उत्पन्न करें (गैर-स्ट्रीमिंग)। + +यह विधि, एक सिस्टम प्रॉम्प्ट और उपयोगकर्ता प्रॉम्प्ट के आधार पर, एक एलएलएम से पाठ प्रतिक्रिया उत्पन्न करती है। +यह पूर्ण प्रतिक्रिया पाठ लौटाता है। + +ध्यान दें: यह विधि स्ट्रीमिंग का समर्थन नहीं करती है। स्ट्रीमिंग पाठ पीढ़ी के लिए, +AsyncSocketFlowInstance.text_completion() का उपयोग करें। + +**तर्क:** + +`system`: सिस्टम प्रॉम्प्ट जो एलएलएम के व्यवहार को परिभाषित करता है। +`prompt`: उपयोगकर्ता प्रॉम्प्ट या प्रश्न। +`**kwargs`: अतिरिक्त, सेवा-विशिष्ट पैरामीटर। + +**रिटर्न:** str: पूर्ण उत्पन्न पाठ प्रतिक्रिया। + +**उदाहरण:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate text +response = await flow.text_completion( + system="You are a helpful assistant.", + prompt="Explain quantum computing in simple terms." +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs: Any)` + +पैटर्न मिलान का उपयोग करके RDF त्रिगुणों की खोज करें। + +यह निर्दिष्ट विषय, विधेय और/या +ऑब्जेक्ट पैटर्न से मेल खाने वाले त्रिगुणों की खोज करता है। पैटर्न किसी भी मान से मेल खाने के लिए 'None' का उपयोग करते हैं। + +**तर्क:** + +`s`: विषय पैटर्न (किसी भी मान से मेल खाने के लिए 'None') +`p`: विधेय पैटर्न (किसी भी मान से मेल खाने के लिए 'None') +`o`: ऑब्जेक्ट पैटर्न (किसी भी मान से मेल खाने के लिए 'None') +`user`: उपयोगकर्ता पहचानकर्ता (सभी उपयोगकर्ताओं के लिए 'None') +`collection`: संग्रह पहचानकर्ता (सभी संग्रहों के लिए 'None') +`limit`: लौटाने के लिए त्रिगुणों की अधिकतम संख्या (डिफ़ॉल्ट: 100) +`**kwargs`: अतिरिक्त सेवा-विशिष्ट पैरामीटर + +**वापसी:** dict: मिलान करने वाले त्रिगुणों वाली प्रतिक्रिया + +**उदाहरण:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find all triples with a specific predicate +results = await flow.triples_query( + p="knows", + user="trustgraph", + collection="social", + limit=50 +) + +for triple in results.get("triples", []): + print(f"{triple['s']} knows {triple['o']}") +``` + + +-- + +## `SocketClient` + +```python +from trustgraph.api import SocketClient +``` + +स्ट्रीमिंग कार्यों के लिए सिंक्रोनस वेबसॉकेट क्लाइंट। + +यह वेबसॉकेट-आधारित ट्रस्टग्राफ सेवाओं के लिए एक सिंक्रोनस इंटरफ़ेस प्रदान करता है, +जो उपयोग में आसानी के लिए सिंक्रोनस जनरेटर के साथ एसिंक्रोनस वेबसॉकेट लाइब्रेरी को रैप करता है। +यह एजेंटों, आरएजी प्रश्नों और टेक्स्ट पूर्णता से स्ट्रीमिंग प्रतिक्रियाओं का समर्थन करता है। + +ध्यान दें: यह एसिंक्रोनस वेबसॉकेट ऑपरेशनों के चारों ओर एक सिंक्रोनस रैपर है। +वास्तविक एसिंक्रोनस समर्थन के लिए, AsyncSocketClient का उपयोग करें। + +### विधियाँ + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +सिंक्रोनस वेबसॉकेट क्लाइंट को इनिशियलाइज़ करें। + +**तर्क:** + +`url`: ट्रस्टग्राफ एपीआई के लिए बेस यूआरएल (HTTP/HTTPS को WS/WSS में परिवर्तित किया जाएगा) +`timeout`: सेकंड में वेबसॉकेट टाइमआउट +`token`: प्रमाणीकरण के लिए वैकल्पिक बेयरर टोकन + +### `close(self) -> None` + +वेबसॉकेट कनेक्शन बंद करें। + +ध्यान दें: एसिंक्रोनस कोड में संदर्भ प्रबंधकों द्वारा सफाई स्वचालित रूप से संभाली जाती है। + +### `flow(self, flow_id: str) -> 'SocketFlowInstance'` + +वेबसॉकेट स्ट्रीमिंग ऑपरेशनों के लिए एक फ्लो इंस्टेंस प्राप्त करें। + +**तर्क:** + +`flow_id`: फ्लो पहचानकर्ता + +**रिटर्न:** SocketFlowInstance: स्ट्रीमिंग विधियों वाला फ्लो इंस्टेंस + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent(question="Hello", user="trustgraph", streaming=True): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `SocketFlowInstance` + +```python +from trustgraph.api import SocketFlowInstance +``` + +सिंक्रोनस वेबसॉकेट फ्लो इंस्टेंस, स्ट्रीमिंग कार्यों के लिए। + +यह REST फ्लोइंस्टेंस के समान इंटरफ़ेस प्रदान करता है, लेकिन वास्तविक समय प्रतिक्रियाओं के लिए वेबसॉकेट-आधारित +स्ट्रीमिंग समर्थन के साथ। सभी विधियाँ एक वैकल्पिक +`streaming` पैरामीटर का समर्थन करती हैं, जो वृद्धिशील परिणाम वितरण को सक्षम करता है। + +### विधियाँ + +### `__init__(self, client: trustgraph.api.socket_client.SocketClient, flow_id: str) -> None` + +सॉकेट फ्लो इंस्टेंस को आरंभ करें। + +**तर्क:** + +`client`: पैरेंट सॉकेटक्लाइंट +`flow_id`: फ्लो पहचानकर्ता + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, streaming: bool = False, **kwargs: Any) -> Dict[str, Any] | Iterator[trustgraph.api.types.StreamingChunk]` + +एक एजेंट ऑपरेशन को स्ट्रीमिंग समर्थन के साथ निष्पादित करें। + +एजेंट टूल का उपयोग करके बहु-चरणीय तर्क कर सकते हैं। यह विधि हमेशा +स्ट्रीमिंग चंक्स (विचार, अवलोकन, उत्तर) लौटाती है, भले ही +streaming=False हो, ताकि एजेंट की तर्क प्रक्रिया दिखाई जा सके। + +**तर्क:** + +`question`: उपयोगकर्ता का प्रश्न या निर्देश +`user`: उपयोगकर्ता पहचानकर्ता +`state`: स्टेटफुल वार्तालापों के लिए वैकल्पिक स्टेट डिक्शनरी +`group`: मल्टी-यूजर संदर्भों के लिए वैकल्पिक समूह पहचानकर्ता +`history`: वैकल्पिक रूप से संदेशों की सूची के रूप में वार्तालाप इतिहास +`streaming`: स्ट्रीमिंग मोड सक्षम करें (डिफ़ॉल्ट: False) +`**kwargs`: एजेंट सेवा को पास किए गए अतिरिक्त पैरामीटर + +**रिटर्न:** Iterator[StreamingChunk]: एजेंट के विचारों, अवलोकनों और उत्तरों का स्ट्रीम + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent reasoning +for chunk in flow.agent( + question="What is quantum computing?", + user="trustgraph", + streaming=True +): + if isinstance(chunk, AgentThought): + print(f"[Thinking] {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"[Observation] {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"[Answer] {chunk.content}") +``` + +### `agent_explain(self, question: str, user: str, collection: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, **kwargs: Any) -> Iterator[trustgraph.api.types.StreamingChunk | trustgraph.api.types.ProvenanceEvent]` + +स्पष्टीकरण समर्थन के साथ एक एजेंट ऑपरेशन निष्पादित करें। + +यह सामग्री खंडों (AgentThought, AgentObservation, AgentAnswer) +और प्रामाणिकता घटनाओं (ProvenanceEvent) दोनों को स्ट्रीम करता है। प्रामाणिकता घटनाओं में URI होते हैं +जिन्हें विस्तृत जानकारी प्राप्त करने के लिए ExplainabilityClient का उपयोग करके प्राप्त किया जा सकता है +एजेंट के तर्क प्रक्रिया के बारे में। + +एजेंट ट्रेस में शामिल हैं: +सत्र: प्रारंभिक प्रश्न और सत्र मेटाडेटा +पुनरावृत्तियाँ: प्रत्येक विचार/क्रिया/अवलोकन चक्र +निष्कर्ष: अंतिम उत्तर + +**तर्क:** + +`question`: उपयोगकर्ता का प्रश्न या निर्देश +`user`: उपयोगकर्ता पहचानकर्ता +`collection`: प्रामाणिकता भंडारण के लिए संग्रह पहचानकर्ता +`state`: राज्यपूर्ण वार्ता के लिए वैकल्पिक राज्य शब्दकोश +`group`: बहु-उपयोगकर्ता संदर्भों के लिए वैकल्पिक समूह पहचानकर्ता +`history`: संदेशों की सूची के रूप में वैकल्पिक वार्ता इतिहास +`**kwargs`: एजेंट सेवा को अतिरिक्त पैरामीटर +`Yields`: +`Union[StreamingChunk, ProvenanceEvent]`: एजेंट खंड और प्रामाणिकता घटनाएँ + +**उदाहरण:** + +```python +from trustgraph.api import Api, ExplainabilityClient, ProvenanceEvent +from trustgraph.api import AgentThought, AgentObservation, AgentAnswer + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +for item in flow.agent_explain( + question="What is the capital of France?", + user="trustgraph", + collection="default" +): + if isinstance(item, AgentThought): + print(f"[Thought] {item.content}") + elif isinstance(item, AgentObservation): + print(f"[Observation] {item.content}") + elif isinstance(item, AgentAnswer): + print(f"[Answer] {item.content}") + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.explain_id) + +# Fetch session trace after completion +if provenance_ids: + trace = explain_client.fetch_agent_trace( + provenance_ids[0], # Session URI is first + graph="urn:graph:retrieval", + user="trustgraph", + collection="default" + ) +``` + +### `document_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +सिमेंटिक समानता का उपयोग करके दस्तावेज़ के टुकड़ों को क्वेरी करें। + +**तर्क:** + +`text`: सिमेंटिक खोज के लिए क्वेरी टेक्स्ट +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`limit`: अधिकतम परिणामों की संख्या (डिफ़ॉल्ट: 10) +`**kwargs`: सेवा को अतिरिक्त पैरामीटर + +**रिटर्न:** डिक्ट: मिलान करने वाले दस्तावेज़ टुकड़ों के chunk_ids के साथ क्वेरी परिणाम + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "...", "score": 0.95}, ...]} +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +दस्तावेज़-आधारित आरएजी क्वेरी को वैकल्पिक स्ट्रीमिंग के साथ निष्पादित करें। + +यह प्रासंगिक दस्तावेज़ टुकड़ों को खोजने के लिए वेक्टर एम्बेडिंग का उपयोग करता है, फिर एक एलएलएम का उपयोग करके +प्रतिक्रिया उत्पन्न करता है। स्ट्रीमिंग मोड क्रमिक रूप से परिणाम प्रदान करता है। + +**तर्क:** + +`query`: प्राकृतिक भाषा क्वेरी +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`doc_limit`: पुनर्प्राप्त किए जाने वाले अधिकतम दस्तावेज़ टुकड़ों की संख्या (डिफ़ॉल्ट: 10) +`streaming`: स्ट्रीमिंग मोड सक्षम करें (डिफ़ॉल्ट: False) +`**kwargs`: सेवा को पारित अतिरिक्त पैरामीटर + +**रिटर्न:** Union[str, Iterator[str]]: पूर्ण प्रतिक्रिया या पाठ टुकड़ों की धारा + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming document RAG +for chunk in flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `document_rag_explain(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +दस्तावेज़-आधारित आरएजी क्वेरी को व्याख्यात्मकता समर्थन के साथ निष्पादित करें। + +यह सामग्री के टुकड़ों (RAGChunk) और उत्पत्ति घटनाओं (ProvenanceEvent) दोनों को स्ट्रीम करता है। +उत्पत्ति घटनाओं में यूआरआई होते हैं जिन्हें ExplainabilityClient का उपयोग करके प्राप्त किया जा सकता है +ताकि प्रतिक्रिया कैसे उत्पन्न हुई, इसके बारे में विस्तृत जानकारी प्राप्त की जा सके। + +दस्तावेज़ आरएजी ट्रेस में निम्नलिखित शामिल हैं: +प्रश्न: उपयोगकर्ता की क्वेरी +अन्वेषण: दस्तावेज़ भंडार से प्राप्त किए गए टुकड़े (chunk_count) +संश्लेषण: उत्पन्न उत्तर + +**तर्क:** + +`query`: प्राकृतिक भाषा क्वेरी +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`doc_limit`: पुनर्प्राप्त करने के लिए अधिकतम दस्तावेज़ टुकड़े (डिफ़ॉल्ट: 10) +`**kwargs`: सेवा को पारित अतिरिक्त पैरामीटर +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: सामग्री के टुकड़े और उत्पत्ति घटनाएं + +**उदाहरण:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +for item in flow.document_rag_explain( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +): + if isinstance(item, RAGChunk): + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + # Fetch entity details + entity = explain_client.fetch_entity( + item.explain_id, + graph=item.explain_graph, + user="trustgraph", + collection="research-papers" + ) + print(f"Event: {entity}", file=sys.stderr) +``` + +### `embeddings(self, texts: list, **kwargs: Any) -> Dict[str, Any]` + +एक या अधिक ग्रंथों के लिए वेक्टर एम्बेडिंग उत्पन्न करें। + +**तर्क:** + +`texts`: एम्बेड करने के लिए इनपुट ग्रंथों की सूची +`**kwargs`: सेवा को पास किए गए अतिरिक्त पैरामीटर + +**रिटर्न:** dict: वैक्टर युक्त प्रतिक्रिया (प्रत्येक इनपुट टेक्स्ट के लिए एक सेट) + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.embeddings(["quantum computing"]) +vectors = result.get("vectors", []) +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +सिमेंटिक समानता का उपयोग करके ज्ञान ग्राफ संस्थाओं को क्वेरी करें। + +**तर्क:** + +`text`: सिमेंटिक खोज के लिए क्वेरी टेक्स्ट +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`limit`: अधिकतम परिणामों की संख्या (डिफ़ॉल्ट: 10) +`**kwargs`: सेवा को अतिरिक्त पैरामीटर + +**रिटर्न:** dict: समान संस्थाओं के साथ क्वेरी परिणाम + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +ग्राफ-आधारित आरएजी क्वेरी को वैकल्पिक स्ट्रीमिंग के साथ निष्पादित करें। + +यह प्रासंगिक संदर्भ खोजने के लिए ज्ञान ग्राफ संरचना का उपयोग करता है, और फिर +एक एलएलएम का उपयोग करके प्रतिक्रिया उत्पन्न करता है। स्ट्रीमिंग मोड क्रमिक रूप से परिणाम प्रदान करता है। + +**तर्क:** + +`query`: प्राकृतिक भाषा क्वेरी +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`max_subgraph_size`: सबग्राफ में अधिकतम कुल त्रिगुण (डिफ़ॉल्ट: 1000) +`max_subgraph_count`: उपग्राफ की अधिकतम संख्या (डिफ़ॉल्ट: 5) +`max_entity_distance`: अधिकतम ट्रैवर्सल गहराई (डिफ़ॉल्ट: 3) +`streaming`: स्ट्रीमिंग मोड सक्षम करें (डिफ़ॉल्ट: False) +`**kwargs`: सेवा को अतिरिक्त पैरामीटर जो भेजे जाते हैं + +**रिटर्न:** यूनियन[स्ट्रिंग, इटरेटर[स्ट्रिंग]]: पूर्ण प्रतिक्रिया या टेक्स्ट चंक्स की स्ट्रीम + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming graph RAG +for chunk in flow.graph_rag( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `graph_rag_explain(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +स्पष्टीकरण समर्थन के साथ ग्राफ-आधारित आरएजी क्वेरी निष्पादित करें। + +यह सामग्री खंडों (RAGChunk) और उत्पत्ति घटनाओं (ProvenanceEvent) दोनों को स्ट्रीम करता है। +उत्पत्ति घटनाओं में यूआरआई होते हैं जिन्हें ExplainabilityClient का उपयोग करके प्राप्त किया जा सकता है +ताकि प्रतिक्रिया कैसे उत्पन्न हुई, इसके बारे में विस्तृत जानकारी प्राप्त की जा सके। + +**तर्क:** + +`query`: प्राकृतिक भाषा क्वेरी +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`max_subgraph_size`: सबग्राफ में अधिकतम कुल त्रिगुण (डिफ़ॉल्ट: 1000) +`max_subgraph_count`: उपग्राफों की अधिकतम संख्या (डिफ़ॉल्ट: 5) +`max_entity_distance`: अधिकतम ट्रैवर्सल गहराई (डिफ़ॉल्ट: 3) +`**kwargs`: सेवा को अतिरिक्त पैरामीटर +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: सामग्री खंड और उत्पत्ति घटनाएं + +**उदाहरण:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +response_text = "" + +for item in flow.graph_rag_explain( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists" +): + if isinstance(item, RAGChunk): + response_text += item.content + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.provenance_id) + +# Fetch explainability details +for prov_id in provenance_ids: + entity = explain_client.fetch_entity( + prov_id, + graph="urn:graph:retrieval", + user="trustgraph", + collection="scientists" + ) + print(f"Entity: {entity}") +``` + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]` + +मॉडल कॉन्टेक्स्ट प्रोटोकॉल (MCP) टूल को निष्पादित करें। + +**तर्क:** + +`name`: टूल का नाम/पहचानकर्ता +`parameters`: टूल पैरामीटर डिक्शनरी +`**kwargs`: सेवा को पास किए गए अतिरिक्त पैरामीटर + +**रिटर्न:** डिक्ट: टूल निष्पादन परिणाम + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +एक वैकल्पिक स्ट्रीमिंग विकल्प के साथ एक प्रॉम्प्ट टेम्पलेट निष्पादित करें। + +**तर्क:** + +`id`: प्रॉम्प्ट टेम्पलेट पहचानकर्ता +`variables`: चर नाम से मान मैपिंग का शब्दकोश +`streaming`: स्ट्रीमिंग मोड सक्षम करें (डिफ़ॉल्ट: False) +`**kwargs`: सेवा को अतिरिक्त पैरामीटर + +**रिटर्न:** Union[str, Iterator[str]]: पूर्ण प्रतिक्रिया या टेक्स्ट चंक्स की धारा + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming prompt execution +for chunk in flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"}, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +अनुक्रमित फ़ील्ड पर सिमेंटिक समानता का उपयोग करके पंक्ति डेटा क्वेरी करें। + +उन पंक्तियों को खोजें जिनके अनुक्रमित फ़ील्ड मान इनपुट टेक्स्ट के सिमेंटिक रूप से समान हैं, +वेक्टर एम्बेडिंग का उपयोग करके। यह संरचित डेटा पर अस्पष्ट/सिमेंटिक मिलान को सक्षम बनाता है। + + +**तर्क:** + +`text`: सिमेंटिक खोज के लिए क्वेरी टेक्स्ट +`schema_name`: खोज के लिए स्कीमा का नाम +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (डिफ़ॉल्ट: "trustgraph") +`collection`: संग्रह पहचानकर्ता (डिफ़ॉल्ट: "default") +`index_name`: वैकल्पिक इंडेक्स नाम जिससे खोज को विशिष्ट इंडेक्स तक सीमित किया जा सके +`limit`: अधिकतम परिणामों की संख्या (डिफ़ॉल्ट: 10) +`**kwargs`: सेवा को अतिरिक्त पैरामीटर जो पास किए जाते हैं + +**रिटर्न:** dict: मिलान वाले क्वेरी परिणाम जिनमें index_name, index_value, text और score शामिल हैं + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict[str, Any] | None = None, operation_name: str | None = None, **kwargs: Any) -> Dict[str, Any]` + +संरचित पंक्तियों के विरुद्ध एक GraphQL क्वेरी निष्पादित करें। + +**तर्क:** + +`query`: GraphQL क्वेरी स्ट्रिंग +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`variables`: वैकल्पिक क्वेरी चर शब्दकोश +`operation_name`: मल्टी-ऑपरेशन दस्तावेज़ों के लिए वैकल्पिक ऑपरेशन नाम +`**kwargs`: सेवा को पारित अतिरिक्त पैरामीटर + +**रिटर्न:** dict: डेटा, त्रुटियों और/या एक्सटेंशन के साथ GraphQL प्रतिक्रिया + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) +``` + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs) -> str | Iterator[str]` + +वैकल्पिक स्ट्रीमिंग के साथ टेक्स्ट पूर्णता निष्पादित करें। + +**तर्क:** + +`system`: सिस्टम प्रॉम्प्ट जो सहायक के व्यवहार को परिभाषित करता है। +`prompt`: उपयोगकर्ता प्रॉम्प्ट/प्रश्न। +`streaming`: स्ट्रीमिंग मोड सक्षम करें (डिफ़ॉल्ट: False)। +`**kwargs`: सेवा को पारित अतिरिक्त पैरामीटर। + +**रिटर्न:** Union[str, Iterator[str]]: पूर्ण प्रतिक्रिया या टेक्स्ट टुकड़ों की धारा। + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Non-streaming +response = flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=False +) +print(response) + +# Streaming +for chunk in flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `triples_query(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, **kwargs: Any) -> List[Dict[str, Any]]` + +पैटर्न मिलान का उपयोग करके ज्ञान ग्राफ त्रिकों को क्वेरी करें। + +**तर्क:** + +`s`: विषय फ़िल्टर - URI स्ट्रिंग, टर्म डिक्शनरी, या वाइल्डकार्ड के लिए None +`p`: विधेय फ़िल्टर - URI स्ट्रिंग, टर्म डिक्शनरी, या वाइल्डकार्ड के लिए None +`o`: वस्तु फ़िल्टर - URI/लिटरल स्ट्रिंग, टर्म डिक्शनरी, या वाइल्डकार्ड के लिए None +`g`: नामित ग्राफ फ़िल्टर - URI स्ट्रिंग या सभी ग्राफों के लिए None +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (वैकल्पिक) +`collection`: संग्रह पहचानकर्ता (वैकल्पिक) +`limit`: वापस करने के लिए अधिकतम परिणाम (डिफ़ॉल्ट: 100) +`**kwargs`: सेवा को अतिरिक्त पैरामीटर + +**वापसी:** List[Dict]: वायर प्रारूप में मिलान किए गए त्रिकों की सूची + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s="http://example.org/person/marie-curie", + user="trustgraph", + collection="scientists" +) + +# Query with named graph filter +triples = flow.triples_query( + s="urn:trustgraph:session:abc123", + g="urn:graph:retrieval", + user="trustgraph", + collection="default" +) +``` + +### `triples_query_stream(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, batch_size: int = 20, **kwargs: Any) -> Iterator[List[Dict[str, Any]]]` + +स्ट्रीमिंग बैचों के साथ नॉलेज ग्राफ ट्रिपल क्वेरी करें। + +जैसे ही ट्रिपल आते हैं, वे बैचों में उपलब्ध होते हैं, जिससे पहले परिणाम प्राप्त करने का समय कम होता है +और बड़े परिणाम सेट के लिए मेमोरी ओवरहेड कम होता है। + +**तर्क:** + +`s`: विषय फ़िल्टर - URI स्ट्रिंग, टर्म डिक्ट, या वाइल्डकार्ड के लिए None +`p`: विधेय फ़िल्टर - URI स्ट्रिंग, टर्म डिक्ट, या वाइल्डकार्ड के लिए None +`o`: वस्तु फ़िल्टर - URI/लिटरल स्ट्रिंग, टर्म डिक्ट, या वाइल्डकार्ड के लिए None +`g`: नामित ग्राफ फ़िल्टर - URI स्ट्रिंग या सभी ग्राफ के लिए None +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता (वैकल्पिक) +`collection`: संग्रह पहचानकर्ता (वैकल्पिक) +`limit`: वापस करने के लिए अधिकतम परिणाम (डिफ़ॉल्ट: 100) +`batch_size`: प्रति बैच ट्रिपल (डिफ़ॉल्ट: 20) +`**kwargs`: सेवा को पास किए गए अतिरिक्त पैरामीटर +`Yields`: +`List[Dict]`: वायर प्रारूप में ट्रिपल के बैच + +**उदाहरण:** + +```python +socket = api.socket() +flow = socket.flow("default") + +for batch in flow.triples_query_stream( + user="trustgraph", + collection="default" +): + for triple in batch: + print(triple["s"], triple["p"], triple["o"]) +``` + + +-- + +## `AsyncSocketClient` + +```python +from trustgraph.api import AsyncSocketClient +``` + +एसिंक्रोनस वेबसॉकेट क्लाइंट + +### विधियाँ + +### `__init__(self, url: str, timeout: int, token: str | None)` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + +### `aclose(self)` + +वेबसॉकेट कनेक्शन बंद करें + +### `flow(self, flow_id: str)` + +वेबसॉकेट संचालन के लिए एसिंक्रोनस फ्लो इंस्टेंस प्राप्त करें + + +-- + +## `AsyncSocketFlowInstance` + +```python +from trustgraph.api import AsyncSocketFlowInstance +``` + +एसिंक्रोनस वेबसॉकेट फ्लो इंस्टेंस + +### विधियाँ + +### `__init__(self, client: trustgraph.api.async_socket_client.AsyncSocketClient, flow_id: str)` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: list | None = None, streaming: bool = False, **kwargs) -> Dict[str, Any] | AsyncIterator` + +वैकल्पिक स्ट्रीमिंग के साथ एजेंट + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs)` + +वैकल्पिक स्ट्रीमिंग के साथ RAG दस्तावेज़ + +### `embeddings(self, texts: list, **kwargs)` + +टेक्स्ट एम्बेडिंग उत्पन्न करें + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs)` + +सिमेंटिक खोज के लिए ग्राफ एम्बेडिंग क्वेरी करें + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs)` + +वैकल्पिक स्ट्रीमिंग के साथ ग्राफ RAG + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs)` + +MCP टूल निष्पादित करें + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs)` + +वैकल्पिक स्ट्रीमिंग के साथ प्रॉम्प्ट निष्पादित करें + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs)` + +संरचित डेटा पर सिमेंटिक खोज के लिए पंक्ति एम्बेडिंग क्वेरी करें + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs)` + +संरचित पंक्तियों के खिलाफ GraphQL क्वेरी + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs)` + +वैकल्पिक स्ट्रीमिंग के साथ टेक्स्ट पूर्णता + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs)` + +ट्रिपल पैटर्न क्वेरी + + +-- + +### `build_term(value: Any, term_type: str | None = None, datatype: str | None = None, language: str | None = None) -> Dict[str, Any] | None` + +एक मान से वायर-फॉर्मेट टर्म डिक्ट बनाएं। + +ऑटो-डिटेक्शन नियम (जब term_type None है): + पहले से ही 't' कुंजी वाला डिक्ट -> यथावत लौटाएं (पहले से ही एक टर्म) + http://, https://, urn: से शुरू होता है -> IRI + <> (जैसे, ) में संलग्न -> IRI (कोण कोष्ठक हटा दिए गए) + कुछ भी और -> शाब्दिक + +**तर्क:** + +`value`: टर्म मान (स्ट्रिंग, डिक्ट या None) +`term_type`: 'iri', 'literal' या ऑटो-डिटेक्शन के लिए None में से एक +`datatype`: शाब्दिक ऑब्जेक्ट के लिए डेटाटाइप (जैसे, xsd:integer) +`language`: शाब्दिक ऑब्जेक्ट के लिए भाषा टैग (जैसे, en) + +**रिटर्न:** डिक्ट: वायर-फॉर्मेट टर्म डिक्ट, या यदि मान None है तो None + + +-- + +## `BulkClient` + +```python +from trustgraph.api import BulkClient +``` + +आयात/निर्यात के लिए सिंक्रोनस बल्क ऑपरेशंस क्लाइंट। + +बड़े डेटासेट के लिए कुशल बल्क डेटा ट्रांसफर वेबसॉकेट के माध्यम से प्रदान करता है। +उपयोग में आसानी के लिए सिंक्रोनस जनरेटर के साथ एसिंक्रोनस वेबसॉकेट ऑपरेशंस को रैप करता है। + +ध्यान दें: वास्तविक एसिंक्रोनस समर्थन के लिए, AsyncBulkClient का उपयोग करें। + +### विधियाँ + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +सिंक्रोनस बल्क क्लाइंट को इनिशियलाइज़ करें। + +**तर्क:** + +`url`: ट्रस्टग्राफ एपीआई के लिए बेस यूआरएल (HTTP/HTTPS को WS/WSS में परिवर्तित किया जाएगा) +`timeout`: सेकंड में वेबसॉकेट टाइमआउट +`token`: प्रमाणीकरण के लिए वैकल्पिक बेयरर टोकन + +### `close(self) -> None` + +कनेक्शन बंद करें + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +एक फ्लो से बल्क एक्सपोर्ट डॉक्यूमेंट एम्बेडिंग। + +वेबसॉकेट स्ट्रीमिंग के माध्यम से सभी डॉक्यूमेंट चंक एम्बेडिंग को कुशलतापूर्वक डाउनलोड करता है। + +**तर्क:** + +`flow`: फ्लो आइडेंटिफायर +`**kwargs`: अतिरिक्त पैरामीटर (भविष्य के उपयोग के लिए आरक्षित) + +**रिटर्न:** Iterator[Dict[str, Any]]: एम्बेडिंग डिक्शनरी का स्ट्रीम + +**उदाहरण:** + +```python +bulk = api.bulk() + +# Export and process document embeddings +for embedding in bulk.export_document_embeddings(flow="default"): + chunk_id = embedding.get("chunk_id") + vector = embedding.get("embedding") + print(f"{chunk_id}: {len(vector)} dimensions") +``` + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +किसी फ्लो से बल्क एक्सपोर्ट एंटिटी कॉन्टेक्स्ट। + +वेबसॉकेट स्ट्रीमिंग के माध्यम से सभी एंटिटी कॉन्टेक्स्ट जानकारी को कुशलतापूर्वक डाउनलोड करता है। + +**तर्क:** + +`flow`: फ्लो आइडेंटिफायर +`**kwargs`: अतिरिक्त पैरामीटर (भविष्य के उपयोग के लिए आरक्षित) + +**रिटर्न:** Iterator[Dict[str, Any]]: कॉन्टेक्स्ट डिक्शनरी का स्ट्रीम + +**उदाहरण:** + +```python +bulk = api.bulk() + +# Export and process entity contexts +for context in bulk.export_entity_contexts(flow="default"): + entity = context.get("entity") + text = context.get("context") + print(f"{entity}: {text[:100]}...") +``` + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +एक फ्लो से ग्राफ एम्बेडिंग का बल्क एक्सपोर्ट। + +वेबसॉकेट स्ट्रीमिंग के माध्यम से सभी ग्राफ एंटिटी एम्बेडिंग को कुशलतापूर्वक डाउनलोड करता है। + +**तर्क:** + +`flow`: फ्लो आइडेंटिफायर +`**kwargs`: अतिरिक्त पैरामीटर (भविष्य के उपयोग के लिए आरक्षित) + +**रिटर्न:** Iterator[Dict[str, Any]]: एम्बेडिंग डिक्शनरी का स्ट्रीम + +**उदाहरण:** + +```python +bulk = api.bulk() + +# Export and process embeddings +for embedding in bulk.export_graph_embeddings(flow="default"): + entity = embedding.get("entity") + vector = embedding.get("embedding") + print(f"{entity}: {len(vector)} dimensions") +``` + +### `export_triples(self, flow: str, **kwargs: Any) -> Iterator[trustgraph.api.types.Triple]` + +एक प्रवाह से RDF त्रिगुणों का बल्क निर्यात करें। + +सभी त्रिगुणों को कुशलतापूर्वक WebSocket स्ट्रीमिंग के माध्यम से डाउनलोड करता है। + +**तर्क:** + +`flow`: प्रवाह पहचानकर्ता +`**kwargs`: अतिरिक्त पैरामीटर (भविष्य के उपयोग के लिए आरक्षित) + +**रिटर्न:** Iterator[Triple]: ट्रिपल ऑब्जेक्ट्स की स्ट्रीम + +**उदाहरण:** + +```python +bulk = api.bulk() + +# Export and process triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +### `import_document_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +एक फ्लो में दस्तावेज़ एम्बेडिंग को बल्क में इम्पोर्ट करें। + +दस्तावेज़ RAG प्रश्नों में उपयोग के लिए, वेबसॉकेट स्ट्रीमिंग के माध्यम से कुशलतापूर्वक दस्तावेज़ चंक एम्बेडिंग अपलोड करता है। + + +**तर्क:** + +`flow`: फ्लो पहचानकर्ता +`embeddings`: एम्बेडिंग डिक्शनरी उत्पन्न करने वाला इटरेटर +`**kwargs`: अतिरिक्त पैरामीटर (भविष्य के उपयोग के लिए आरक्षित) + +**उदाहरण:** + +```python +bulk = api.bulk() + +# Generate document embeddings to import +def doc_embedding_generator(): + yield {"chunk_id": "doc1/p0/c0", "embedding": [0.1, 0.2, ...]} + yield {"chunk_id": "doc1/p0/c1", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_document_embeddings( + flow="default", + embeddings=doc_embedding_generator() +) +``` + +### `import_entity_contexts(self, flow: str, contexts: Iterator[Dict[str, Any]], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +एक फ्लो में एंटिटी कॉन्टेक्स्ट को बल्क में इम्पोर्ट करें। + +वेबसॉकेट स्ट्रीमिंग के माध्यम से एंटिटी कॉन्टेक्स्ट जानकारी को कुशलतापूर्वक अपलोड करता है। +एंटिटी कॉन्टेक्स्ट, ग्राफ एंटिटीज के बारे में अतिरिक्त पाठ्य संदर्भ प्रदान करते हैं +बेहतर RAG प्रदर्शन के लिए। + +**तर्क:** + +`flow`: फ्लो आइडेंटिफायर +`contexts`: कॉन्टेक्स्ट डिक्शनरी उत्पन्न करने वाला इटरेटर +`metadata`: आईडी, मेटाडेटा, उपयोगकर्ता, संग्रह के साथ मेटाडेटा डिक्ट +`batch_size`: बैच प्रति कॉन्टेक्स्ट की संख्या (डिफ़ॉल्ट 100) +`**kwargs`: अतिरिक्त पैरामीटर (भविष्य के उपयोग के लिए आरक्षित) + +**उदाहरण:** + +```python +bulk = api.bulk() + +# Generate entity contexts to import +def context_generator(): + yield {"entity": {"v": "entity1", "e": True}, "context": "Description..."} + yield {"entity": {"v": "entity2", "e": True}, "context": "Description..."} + # ... more contexts + +bulk.import_entity_contexts( + flow="default", + contexts=context_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + +### `import_graph_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +एक फ्लो में ग्राफ एम्बेडिंग को बल्क में इम्पोर्ट करें। + +वेबसॉकेट स्ट्रीमिंग के माध्यम से ग्राफ एंटिटी एम्बेडिंग को कुशलतापूर्वक अपलोड करता है। + +**तर्क:** + +`flow`: फ्लो पहचानकर्ता +`embeddings`: एम्बेडिंग डिक्शनरी उत्पन्न करने वाला इटरेटर +`**kwargs`: अतिरिक्त पैरामीटर (भविष्य के उपयोग के लिए आरक्षित) + +**उदाहरण:** + +```python +bulk = api.bulk() + +# Generate embeddings to import +def embedding_generator(): + yield {"entity": "entity1", "embedding": [0.1, 0.2, ...]} + yield {"entity": "entity2", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_graph_embeddings( + flow="default", + embeddings=embedding_generator() +) +``` + +### `import_rows(self, flow: str, rows: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +एक फ्लो में संरचित पंक्तियों को बल्क में आयात करें। + +कुशलतापूर्वक संरचित डेटा पंक्तियों को WebSocket स्ट्रीमिंग के माध्यम से अपलोड करता है +जिसका उपयोग GraphQL प्रश्नों में किया जाता है। + +**तर्क:** + +`flow`: फ्लो पहचानकर्ता +`rows`: पंक्ति शब्दकोशों को उत्पन्न करने वाला इटरेटर +`**kwargs`: अतिरिक्त पैरामीटर (भविष्य के उपयोग के लिए आरक्षित) + +**उदाहरण:** + +```python +bulk = api.bulk() + +# Generate rows to import +def row_generator(): + yield {"id": "row1", "name": "Row 1", "value": 100} + yield {"id": "row2", "name": "Row 2", "value": 200} + # ... more rows + +bulk.import_rows( + flow="default", + rows=row_generator() +) +``` + +### `import_triples(self, flow: str, triples: Iterator[trustgraph.api.types.Triple], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +एक फ्लो में RDF ट्रिपल का बल्क इम्पोर्ट करें। + +वेबसॉकेट स्ट्रीमिंग के माध्यम से बड़ी संख्या में ट्रिपल को कुशलतापूर्वक अपलोड करता है। + +**तर्क:** + +`flow`: फ्लो आइडेंटिफायर +`triples`: ट्रिपल ऑब्जेक्ट्स उत्पन्न करने वाला इटरेटर +`metadata`: आईडी, मेटाडेटा, यूजर, कलेक्शन के साथ मेटाडेटा डिक्ट +`batch_size`: प्रति बैच ट्रिपल की संख्या (डिफ़ॉल्ट 100) +`**kwargs`: अतिरिक्त पैरामीटर (भविष्य के उपयोग के लिए आरक्षित) + +**उदाहरण:** + +```python +from trustgraph.api import Triple + +bulk = api.bulk() + +# Generate triples to import +def triple_generator(): + yield Triple(s="subj1", p="pred", o="obj1") + yield Triple(s="subj2", p="pred", o="obj2") + # ... more triples + +# Import triples +bulk.import_triples( + flow="default", + triples=triple_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + + +-- + +## `AsyncBulkClient` + +```python +from trustgraph.api import AsyncBulkClient +``` + +एसिंक्रोनस बल्क ऑपरेशंस क्लाइंट + +### विधियाँ + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +स्वयं को इनिशियलाइज़ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + +### `aclose(self) -> None` + +कनेक्शन बंद करें + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +वेबसॉकेट के माध्यम से दस्तावेज़ एम्बेडिंग का बल्क एक्सपोर्ट + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +वेबसॉकेट के माध्यम से एंटिटी कॉन्टेक्स्ट का बल्क एक्सपोर्ट + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +वेबसॉकेट के माध्यम से ग्राफ एम्बेडिंग का बल्क एक्सपोर्ट + +### `export_triples(self, flow: str, **kwargs: Any) -> AsyncIterator[trustgraph.api.types.Triple]` + +वेबसॉकेट के माध्यम से ट्रिपल्स का बल्क एक्सपोर्ट + +### `import_document_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +वेबसॉकेट के माध्यम से दस्तावेज़ एम्बेडिंग का बल्क इम्पोर्ट + +### `import_entity_contexts(self, flow: str, contexts: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +वेबसॉकेट के माध्यम से एंटिटी कॉन्टेक्स्ट का बल्क इम्पोर्ट + +### `import_graph_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +वेबसॉकेट के माध्यम से ग्राफ एम्बेडिंग का बल्क इम्पोर्ट + +### `import_rows(self, flow: str, rows: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +वेबसॉकेट के माध्यम से पंक्तियों का बल्क इम्पोर्ट + +### `import_triples(self, flow: str, triples: AsyncIterator[trustgraph.api.types.Triple], **kwargs: Any) -> None` + +वेबसॉकेट के माध्यम से ट्रिपल्स का बल्क इम्पोर्ट + + +-- + +## `Metrics` + +```python +from trustgraph.api import Metrics +``` + +सिंक्रोनस मेट्रिक्स क्लाइंट + +### विधियाँ + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + +### `get(self) -> str` + +प्रोमेथियस मेट्रिक्स को टेक्स्ट के रूप में प्राप्त करें + + +-- + +## `AsyncMetrics` + +```python +from trustgraph.api import AsyncMetrics +``` + +एसिंक्रोनस मेट्रिक्स क्लाइंट + +### विधियाँ + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + +### `aclose(self) -> None` + +कनेक्शन बंद करें + +### `get(self) -> str` + +प्रोमेथियस मेट्रिक्स को टेक्स्ट के रूप में प्राप्त करें + + +-- + +## `ExplainabilityClient` + +```python +from trustgraph.api import ExplainabilityClient +``` + +स्पष्टीकरण संस्थाओं को लाने के लिए क्लाइंट, जिसमें अंततः स्थिरता प्रबंधन शामिल है। + +यह शांत अवस्था का पता लगाने का उपयोग करता है: प्राप्त करें, प्रतीक्षा करें, फिर से प्राप्त करें, तुलना करें। +यदि परिणाम समान हैं, तो डेटा स्थिर है। + +### विधियाँ + +### `__init__(self, flow_instance, retry_delay: float = 0.2, max_retries: int = 10)` + +स्पष्टीकरण क्लाइंट को आरंभ करें। + +**तर्क:** + +`flow_instance`: त्रिकों को क्वेरी करने के लिए एक SocketFlowInstance +`retry_delay`: पुन: प्रयास के बीच का विलंब (डिफ़ॉल्ट: 0.2) +`max_retries`: अधिकतम पुन: प्रयास (डिफ़ॉल्ट: 10) + +### `detect_session_type(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> str` + +पता करें कि क्या सत्र GraphRAG या Agent प्रकार का है। + +**तर्क:** + +`session_uri`: सत्र/प्रश्न URI +`graph`: नामित ग्राफ +`user`: उपयोगकर्ता/keyspace पहचानकर्ता +`collection`: संग्रह पहचानकर्ता + +**रिटर्न:** "graphrag" या "agent" + +### `fetch_agent_trace(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +एक सत्र URI से शुरू होने वाला संपूर्ण Agent ट्रेस प्राप्त करें। + +यह उत्पत्ति श्रृंखला का अनुसरण करता है: प्रश्न -> विश्लेषण (s) -> निष्कर्ष + +**तर्क:** + +`session_uri`: एजेंट सत्र/प्रश्न URI +`graph`: नामित ग्राफ (डिफ़ॉल्ट: urn:graph:retrieval) +`user`: उपयोगकर्ता/keyspace पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`api`: लाइब्रेरियन एक्सेस के लिए TrustGraph Api उदाहरण (वैकल्पिक) +`max_content`: निष्कर्ष के लिए अधिकतम सामग्री लंबाई + +**रिटर्न:** प्रश्न, पुनरावृत्तियों (विश्लेषण सूची), निष्कर्ष संस्थाओं के साथ डिक्ट + +### `fetch_docrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +एक प्रश्न URI से शुरू होने वाला संपूर्ण DocumentRAG ट्रेस प्राप्त करें। + +यह उत्पत्ति श्रृंखला का अनुसरण करता है: + प्रश्न -> ग्राउंडिंग -> अन्वेषण -> संश्लेषण + +**तर्क:** + +`question_uri`: प्रश्न इकाई URI +`graph`: नामित ग्राफ (डिफ़ॉल्ट: urn:graph:retrieval) +`user`: उपयोगकर्ता/keyspace पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`api`: लाइब्रेरियन एक्सेस के लिए TrustGraph Api उदाहरण (वैकल्पिक) +`max_content`: संश्लेषण के लिए अधिकतम सामग्री लंबाई + +**रिटर्न:** प्रश्न, ग्राउंडिंग, अन्वेषण, संश्लेषण संस्थाओं के साथ डिक्ट + +### `fetch_document_content(self, document_uri: str, api: Any, user: str | None = None, max_content: int = 10000) -> str` + +दस्तावेज़ URI द्वारा लाइब्रेरियन से सामग्री प्राप्त करें। + +**तर्क:** + +`document_uri`: लाइब्रेरियन में दस्तावेज़ URI +`api`: लाइब्रेरियन एक्सेस के लिए TrustGraph Api उदाहरण +`user`: लाइब्रेरियन के लिए उपयोगकर्ता पहचानकर्ता +`max_content`: वापस करने के लिए अधिकतम सामग्री लंबाई + +**रिटर्न:** स्ट्रिंग के रूप में दस्तावेज़ सामग्री + +### `fetch_edge_selection(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.EdgeSelection | None` + +एक एज सिलेक्शन एंटिटी प्राप्त करें (जो फोकस द्वारा उपयोग किया जाता है)। + +**तर्क:** + +`uri`: एज सिलेक्शन URI +`graph`: क्वेरी करने के लिए नामित ग्राफ +`user`: उपयोगकर्ता/keyspace पहचानकर्ता +`collection`: संग्रह पहचानकर्ता + +**रिटर्न:** एज सिलेक्शन या यदि नहीं मिला तो None + +### `fetch_entity(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.ExplainEntity | None` + +URI के माध्यम से एक व्याख्यात्मकता इकाई प्राप्त करें और संभावित स्थिरता प्रबंधन के साथ। + +शांत अवस्था का पता लगाने का उपयोग करता है: +1. URI के लिए ट्रिपल प्राप्त करें +2. यदि शून्य परिणाम हैं, तो पुनः प्रयास करें +3. यदि गैर-शून्य परिणाम हैं, तो प्रतीक्षा करें और फिर से प्राप्त करें +4. यदि समान परिणाम हैं, तो डेटा स्थिर है - पार्स करें और वापस करें +5. यदि अलग-अलग परिणाम हैं, तो डेटा अभी भी लिखा जा रहा है - पुनः प्रयास करें + +**तर्क:** + +`uri`: प्राप्त करने के लिए इकाई URI +`graph`: क्वेरी करने के लिए नामित ग्राफ (जैसे, "urn:graph:retrieval") +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता + +**वापसी:** ExplainEntity उपवर्ग या यदि नहीं मिला तो None + +### `fetch_focus_with_edges(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.Focus | None` + +एक फोकस इकाई और उसके सभी किनारे चयन प्राप्त करें। + +**तर्क:** + +`uri`: फोकस इकाई URI +`graph`: क्वेरी करने के लिए नामित ग्राफ +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता + +**वापसी:** भरे हुए edge_selections के साथ Focus, या None + +### `fetch_graphrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +एक प्रश्न URI से शुरू होकर संपूर्ण GraphRAG ट्रेस प्राप्त करें। + +उत्पत्ति श्रृंखला का पालन करें: प्रश्न -> ग्राउंडिंग -> अन्वेषण -> फोकस -> संश्लेषण + +**तर्क:** + +`question_uri`: प्रश्न इकाई URI +`graph`: नामित ग्राफ (डिफ़ॉल्ट: urn:graph:retrieval) +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`api`: लाइब्रेरियन एक्सेस के लिए ट्रस्टग्राफ एपीआई उदाहरण (वैकल्पिक) +`max_content`: संश्लेषण के लिए अधिकतम सामग्री लंबाई + +**वापसी:** प्रश्न, ग्राउंडिंग, अन्वेषण, फोकस, संश्लेषण संस्थाओं के साथ डिक्ट + +### `list_sessions(self, graph: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 50) -> List[trustgraph.api.explainability.Question]` + +एक संग्रह में सभी व्याख्यात्मकता सत्र (प्रश्न) सूचीबद्ध करें। + +**तर्क:** + +`graph`: नामित ग्राफ (डिफ़ॉल्ट: urn:graph:retrieval) +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता +`limit`: वापस करने के लिए सत्रों की अधिकतम संख्या + +**वापसी:** टाइमस्टैम्प द्वारा क्रमबद्ध प्रश्न संस्थाओं की सूची (नवीनतम पहले) + +### `resolve_edge_labels(self, edge: Dict[str, str], user: str | None = None, collection: str | None = None) -> Tuple[str, str, str]` + +एक किनारे ट्रिपल के सभी घटकों के लिए लेबल हल करें। + +**तर्क:** + +`edge`: "s", "p", "o" कुंजियों वाला डिक्ट +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता + +**वापसी:** (s_label, p_label, o_label) का टपल + +### `resolve_label(self, uri: str, user: str | None = None, collection: str | None = None) -> str` + +कैशिंग के साथ एक URI के लिए rdfs:label हल करें। + +**तर्क:** + +`uri`: URI जिसके लिए लेबल प्राप्त करना है +`user`: उपयोगकर्ता/कीस्पेस पहचानकर्ता +`collection`: संग्रह पहचानकर्ता + +**वापसी:** यदि पाया जाता है तो लेबल, अन्यथा URI स्वयं + + +-- + +## `ExplainEntity` + +```python +from trustgraph.api import ExplainEntity +``` + +व्याख्यात्मक संस्थाओं के लिए आधार वर्ग। + +**फ़ील्ड:** + +`uri`: +`entity_type`: + +### विधियाँ + +### `__init__(self, uri: str, entity_type: str = '') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `Question` + +```python +from trustgraph.api import Question +``` + +प्रश्न इकाई - उपयोगकर्ता का वह प्रश्न जिसने सत्र शुरू किया। + +**फ़ील्ड:** + +`uri`: +`entity_type`: +`query`: +`timestamp`: +`question_type`: + +### विधियाँ + +### `__init__(self, uri: str, entity_type: str = '', query: str = '', timestamp: str = '', question_type: str = '') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `Exploration` + +```python +from trustgraph.api import Exploration +``` + +अन्वेषण इकाई - ज्ञान भंडार से प्राप्त किनारे/खंड। + +**फ़ील्ड:** + +`uri`: +`entity_type`: +`edge_count`: +`chunk_count`: +`entities`: typing.List[str] + +### विधियाँ + +### `__init__(self, uri: str, entity_type: str = '', edge_count: int = 0, chunk_count: int = 0, entities: List[str] = ) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `Focus` + +```python +from trustgraph.api import Focus +``` + +मुख्य इकाई - एलएलएम तर्क के साथ चयनित किनारे (केवल GraphRAG)। + +**फ़ील्ड:** + +`uri`: +`entity_type`: +`selected_edge_uris`: typing.List[str] +`edge_selections`: typing.List[trustgraph.api.explainability.EdgeSelection] + +### विधियाँ + +### `__init__(self, uri: str, entity_type: str = '', selected_edge_uris: List[str] = , edge_selections: List[trustgraph.api.explainability.EdgeSelection] = ) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `Synthesis` + +```python +from trustgraph.api import Synthesis +``` + +संश्लेषण इकाई - अंतिम उत्तर। + +**फ़ील्ड:** + +`uri`: +`entity_type`: +`document`: + +### विधियाँ + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `Analysis` + +```python +from trustgraph.api import Analysis +``` + +विश्लेषण इकाई - एक विचार/कार्य/अवलोकन चक्र (केवल एजेंट)। + +**फ़ील्ड:** + +`uri`: +`entity_type`: +`action`: +`arguments`: +`thought`: +`observation`: + +### विधियाँ + +### `__init__(self, uri: str, entity_type: str = '', action: str = '', arguments: str = '', thought: str = '', observation: str = '') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `Conclusion` + +```python +from trustgraph.api import Conclusion +``` + +निष्कर्ष इकाई - अंतिम उत्तर (केवल एजेंट)। + +**फ़ील्ड:** + +`uri`: +`entity_type`: +`document`: + +### विधियाँ + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `EdgeSelection` + +```python +from trustgraph.api import EdgeSelection +``` + +ग्राफआरएजी फोकस चरण से तर्क के साथ एक चयनित किनारा। + +**फ़ील्ड:** + +`uri`: +`edge`: typing.Dict[str, str] | None +`reasoning`: + +### विधियाँ + +### `__init__(self, uri: str, edge: Dict[str, str] | None = None, reasoning: str = '') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +### `wire_triples_to_tuples(wire_triples: List[Dict[str, Any]]) -> List[Tuple[str, str, Any]]` + +वायर-फॉर्मेट ट्रिपल को (s, p, o) टुपल्स में बदलें। + + +-- + +### `extract_term_value(term: Dict[str, Any]) -> Any` + +एक वायर-फॉर्मेट टर्म डिक्ट से मान निकालें। + + +-- + +## `Triple` + +```python +from trustgraph.api import Triple +``` + +आरडीएफ ट्रिपल जो एक ज्ञान ग्राफ कथन का प्रतिनिधित्व करता है। + +**फ़ील्ड:** + +`s`: +`p`: +`o`: + +### विधियाँ + +### `__init__(self, s: str, p: str, o: str) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `Uri` + +```python +from trustgraph.api import Uri +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +दिए गए ऑब्जेक्ट से एक नया स्ट्रिंग ऑब्जेक्ट बनाएं। यदि एन्कोडिंग या +त्रुटियां निर्दिष्ट हैं, तो ऑब्जेक्ट में एक डेटा बफर होना चाहिए +जिसे दिए गए एन्कोडिंग और त्रुटि हैंडलर का उपयोग करके डिकोड किया जाएगा। +अन्यथा, यह ऑब्जेक्ट.__str__() (यदि परिभाषित है) का परिणाम लौटाता है +या repr(object)। +एन्कोडिंग डिफ़ॉल्ट रूप से 'utf-8' है। +त्रुटियां डिफ़ॉल्ट रूप से 'strict' हैं। + +### विधियाँ + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `Literal` + +```python +from trustgraph.api import Literal +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +दिए गए ऑब्जेक्ट से एक नया स्ट्रिंग ऑब्जेक्ट बनाएं। यदि एन्कोडिंग या +त्रुटियां निर्दिष्ट हैं, तो ऑब्जेक्ट में एक डेटा बफर होना चाहिए +जिसे दिए गए एन्कोडिंग और त्रुटि हैंडलर का उपयोग करके डिकोड किया जाएगा। +अन्यथा, यह ऑब्जेक्ट.__str__() (यदि परिभाषित है) का परिणाम लौटाता है +या repr(object)। +एन्कोडिंग डिफ़ॉल्ट रूप से 'utf-8' है। +त्रुटियां डिफ़ॉल्ट रूप से 'strict' हैं। + +### विधियाँ + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `ConfigKey` + +```python +from trustgraph.api import ConfigKey +``` + +कॉन्फ़िगरेशन कुंजी पहचानकर्ता। + +**फ़ील्ड:** + +`type`: +`key`: + +### विधियाँ + +### `__init__(self, type: str, key: str) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `ConfigValue` + +```python +from trustgraph.api import ConfigValue +``` + +कॉन्फ़िगरेशन कुंजी-मान जोड़ी। + +**फ़ील्ड:** + +`type`: +`key`: +`value`: + +### विधियाँ + +### `__init__(self, type: str, key: str, value: str) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `DocumentMetadata` + +```python +from trustgraph.api import DocumentMetadata +``` + +पुस्तकालय में एक दस्तावेज़ के लिए मेटाडेटा। + +**विशेषताएं:** + +`parent_id: Parent document ID for child documents (empty for top`: स्तर (docs) + +**फ़ील्ड:** + +`id`: +`time`: +`kind`: +`title`: +`comments`: +`metadata`: typing.List[trustgraph.api.types.Triple] +`user`: +`tags`: typing.List[str] +`parent_id`: +`document_type`: + +### विधियाँ + +### `__init__(self, id: str, time: datetime.datetime, kind: str, title: str, comments: str, metadata: List[trustgraph.api.types.Triple], user: str, tags: List[str], parent_id: str = '', document_type: str = 'source') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `ProcessingMetadata` + +```python +from trustgraph.api import ProcessingMetadata +``` + +एक सक्रिय दस्तावेज़ प्रसंस्करण कार्य के लिए मेटाडेटा। + +**फ़ील्ड:** + +`id`: +`document_id`: +`time`: +`flow`: +`user`: +`collection`: +`tags`: typing.List[str] + +### विधियाँ + +### `__init__(self, id: str, document_id: str, time: datetime.datetime, flow: str, user: str, collection: str, tags: List[str]) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `CollectionMetadata` + +```python +from trustgraph.api import CollectionMetadata +``` + +डेटा संग्रह के लिए मेटाडेटा। + +संग्रह दस्तावेज़ों और +ज्ञान ग्राफ डेटा के लिए तार्किक समूहीकरण और अलगाव प्रदान करते हैं। + +**विशेषताएं:** + +`name: Human`: पढ़ने योग्य संग्रह नाम + +**फ़ील्ड:** + +`user`: +`collection`: +`name`: +`description`: +`tags`: typing.List[str] + +### विधियाँ + +### `__init__(self, user: str, collection: str, name: str, description: str, tags: List[str]) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `StreamingChunk` + +```python +from trustgraph.api import StreamingChunk +``` + +स्ट्रीमिंग प्रतिक्रिया खंडों के लिए आधार वर्ग। + +वेबसॉकेट-आधारित स्ट्रीमिंग कार्यों के लिए उपयोग किया जाता है, जहाँ प्रतिक्रियाएँ उत्पन्न होने पर क्रमिक रूप से भेजी जाती हैं। + + +**फ़ील्ड:** + +`content`: +`end_of_message`: + +### विधियाँ + +### `__init__(self, content: str, end_of_message: bool = False) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `AgentThought` + +```python +from trustgraph.api import AgentThought +``` + +एजेंट की तर्क/विचार प्रक्रिया का खंड। + +यह एजेंट के निष्पादन के दौरान आंतरिक तर्क या योजना चरणों का प्रतिनिधित्व करता है। +ये खंड दर्शाते हैं कि एजेंट समस्या के बारे में कैसे सोच रहा है। + +**फ़ील्ड:** + +`content`: +`end_of_message`: +`chunk_type`: + +### विधियाँ + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'thought') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `AgentObservation` + +```python +from trustgraph.api import AgentObservation +``` + +एजेंट टूल निष्पादन अवलोकन खंड। + +यह किसी टूल या क्रिया को निष्पादित करने के परिणाम या अवलोकन को दर्शाता है। +ये खंड दिखाते हैं कि एजेंट ने टूल का उपयोग करके क्या सीखा। + +**फ़ील्ड:** + +`content`: +`end_of_message`: +`chunk_type`: + +### विधियाँ + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'observation') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `AgentAnswer` + +```python +from trustgraph.api import AgentAnswer +``` + +एजेंट का अंतिम उत्तर खंड। + +यह एजेंट की अंतिम प्रतिक्रिया का प्रतिनिधित्व करता है जो उपयोगकर्ता के प्रश्न का उत्तर देने के लिए +अपनी तर्क क्षमता और टूल उपयोग को पूरा करने के बाद देता है। + +**विशेषताएं:** + +`chunk_type: Always "final`: उत्तर" + +**फ़ील्ड:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_dialog`: + +### विधियाँ + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'final-answer', end_of_dialog: bool = False) -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `RAGChunk` + +```python +from trustgraph.api import RAGChunk +``` + +आरएजी (रीट्रिवल-ऑगमेंटेड जनरेशन) स्ट्रीमिंग चंक। + +ग्राफ आरएजी, दस्तावेज़ आरएजी, टेक्स्ट कंप्लीशन, +और अन्य जेनरेटिव सेवाओं से प्रतिक्रियाओं को स्ट्रीम करने के लिए उपयोग किया जाता है। + +**फ़ील्ड:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_stream`: +`error`: typing.Dict[str, str] | None + +### मेथड + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'rag', end_of_stream: bool = False, error: Dict[str, str] | None = None) -> None` + +स्वयं को इनिशियलाइज़ करें। सटीक सिग्नेचर के लिए help(type(self)) देखें। + + +-- + +## `ProvenanceEvent` + +```python +from trustgraph.api import ProvenanceEvent +``` + +व्याख्यात्मकता के लिए उत्पत्ति घटना। + +जब व्याख्यात्मक मोड सक्षम होता है तो GraphRAG प्रश्नों के दौरान उत्सर्जित। +प्रत्येक घटना एक उत्पत्ति नोड का प्रतिनिधित्व करती है जो प्रश्न प्रसंस्करण के दौरान बनाई जाती है। + +**फ़ील्ड:** + +`explain_id`: +`explain_graph`: +`event_type`: + +### विधियाँ + +### `__init__(self, explain_id: str, explain_graph: str = '', event_type: str = '') -> None` + +स्वयं को आरंभ करें। सटीक हस्ताक्षर के लिए help(type(self)) देखें। + + +-- + +## `ProtocolException` + +```python +from trustgraph.api import ProtocolException +``` + +जब वेबसॉकेट प्रोटोकॉल त्रुटियां होती हैं, तो यह त्रुटि उत्पन्न होती है। + + +-- + +## `TrustGraphException` + +```python +from trustgraph.api import TrustGraphException +``` + +सभी ट्रस्टग्राफ सेवा त्रुटियों के लिए आधार वर्ग। + + +-- + +## `AgentError` + +```python +from trustgraph.api import AgentError +``` + +एजेंट सेवा त्रुटि + + +-- + +## `ConfigError` + +```python +from trustgraph.api import ConfigError +``` + +कॉन्फ़िगरेशन सेवा त्रुटि + + +-- + +## `DocumentRagError` + +```python +from trustgraph.api import DocumentRagError +``` + +दस्तावेज़ पुनर्प्राप्ति त्रुटि। + + +-- + +## `FlowError` + +```python +from trustgraph.api import FlowError +``` + +प्रवाह प्रबंधन त्रुटि + + +-- + +## `GatewayError` + +```python +from trustgraph.api import GatewayError +``` + +एपीआई गेटवे त्रुटि + + +-- + +## `GraphRagError` + +```python +from trustgraph.api import GraphRagError +``` + +ग्राफ आरएजी पुनर्प्राप्ति त्रुटि + + +-- + +## `LLMError` + +```python +from trustgraph.api import LLMError +``` + +एलएलएम सेवा त्रुटि + + +-- + +## `LoadError` + +```python +from trustgraph.api import LoadError +``` + +डेटा लोड करने में त्रुटि + + +-- + +## `LookupError` + +```python +from trustgraph.api import LookupError +``` + +खोज/खोज त्रुटि + + +-- + +## `NLPQueryError` + +```python +from trustgraph.api import NLPQueryError +``` + +एनएलपी क्वेरी सेवा त्रुटि + + +-- + +## `RowsQueryError` + +```python +from trustgraph.api import RowsQueryError +``` + +पंक्तियों के क्वेरी सेवा त्रुटि + + +-- + +## `RequestError` + +```python +from trustgraph.api import RequestError +``` + +अनुरोध प्रसंस्करण त्रुटि + + +-- + +## `StructuredQueryError` + +```python +from trustgraph.api import StructuredQueryError +``` + +संरचित क्वेरी सेवा त्रुटि + + +-- + +## `UnexpectedError` + +```python +from trustgraph.api import UnexpectedError +``` + +अप्रत्याशित/अज्ञात त्रुटि + + +-- + +## `ApplicationException` + +```python +from trustgraph.api import ApplicationException +``` + +सभी ट्रस्टग्राफ सेवा त्रुटियों के लिए आधार वर्ग। + + +-- + diff --git a/docs/python-api.pt.md b/docs/python-api.pt.md new file mode 100644 index 00000000..699fe6d9 --- /dev/null +++ b/docs/python-api.pt.md @@ -0,0 +1,4071 @@ +# Referência da API Python do TrustGraph + +## Instalação + +```bash +pip install trustgraph +``` + +## Início Rápido + +Todas as classes e tipos são importados do pacote `trustgraph.api`: + +```python +from trustgraph.api import Api, Triple, ConfigKey + +# Create API client +api = Api(url="http://localhost:8088/") + +# Get a flow instance +flow = api.flow().id("default") + +# Execute a graph RAG query +response = flow.graph_rag( + query="What are the main topics?", + user="trustgraph", + collection="default" +) +``` + +## Tabela de Conteúdo + +### Núcleo + +[Api](#api) + +### Clientes de Fluxo + +[Flow](#flow) +[FlowInstance](#flowinstance) +[AsyncFlow](#asyncflow) +[AsyncFlowInstance](#asyncflowinstance) + +### Clientes WebSocket + +[SocketClient](#socketclient) +[SocketFlowInstance](#socketflowinstance) +[AsyncSocketClient](#asyncsocketclient) +[AsyncSocketFlowInstance](#asyncsocketflowinstance) + +### Operações em Massa + +[BulkClient](#bulkclient) +[AsyncBulkClient](#asyncbulkclient) + +### Métricas + +[Metrics](#metrics) +[AsyncMetrics](#asyncmetrics) + +### Tipos de Dados + +[Triple](#triple) +[ConfigKey](#configkey) +[ConfigValue](#configvalue) +[DocumentMetadata](#documentmetadata) +[ProcessingMetadata](#processingmetadata) +[CollectionMetadata](#collectionmetadata) +[StreamingChunk](#streamingchunk) +[AgentThought](#agentthought) +[AgentObservation](#agentobservation) +[AgentAnswer](#agentanswer) +[RAGChunk](#ragchunk) + +### Exceções + +[ProtocolException](#protocolexception) +[TrustGraphException](#trustgraphexception) +[AgentError](#agenterror) +[ConfigError](#configerror) +[DocumentRagError](#documentragerror) +[FlowError](#flowerror) +[GatewayError](#gatewayerror) +[GraphRagError](#graphragerror) +[LLMError](#llmerror) +[LoadError](#loaderror) +[LookupError](#lookuperror) +[NLPQueryError](#nlpqueryerror) +[RowsQueryError](#rowsqueryerror) +[RequestError](#requesterror) +[StructuredQueryError](#structuredqueryerror) +[UnexpectedError](#unexpectederror) +[ApplicationException](#applicationexception) + +-- + +## `Api` + +```python +from trustgraph.api import Api +``` + +Cliente principal da API TrustGraph para operações síncronas e assíncronas. + +Esta classe fornece acesso a todos os serviços do TrustGraph, incluindo gerenciamento de fluxo, +operações de grafo de conhecimento, processamento de documentos, consultas RAG e muito mais. Ele suporta +tanto padrões de comunicação baseados em REST quanto baseados em WebSocket. + +O cliente pode ser usado como um gerenciador de contexto para limpeza automática de recursos: + ```python + with Api(url="http://localhost:8088/") as api: + result = api.flow().id("default").graph_rag(query="test") + ``` + +### Métodos + +### `__aenter__(self)` + +Entre no gerenciador de contexto assíncrono. + +### `__aexit__(self, *args)` + +Saia do gerenciador de contexto assíncrono e feche as conexões. + +### `__enter__(self)` + +Entre no gerenciador de contexto síncrono. + +### `__exit__(self, *args)` + +Saia do gerenciador de contexto síncrono e feche as conexões. + +### `__init__(self, url='http://localhost:8088/', timeout=60, token: str | None = None)` + +Inicialize o cliente da API TrustGraph. + +**Argumentos:** + +`url`: URL base para a API TrustGraph (padrão: "http://localhost:8088/"") +`timeout`: Tempo limite de solicitação em segundos (padrão: 60) +`token`: Token de autorização opcional para autenticação + +**Exemplo:** + +```python +# Local development +api = Api() + +# Production with authentication +api = Api( + url="https://trustgraph.example.com/", + timeout=120, + token="your-api-token" +) +``` + +### `aclose(self)` + +Fechar todas as conexões de cliente assíncronas. + +Este método fecha as conexões assíncronas WebSocket, de operação em lote e de fluxo. +Ele é chamado automaticamente ao sair de um gerenciador de contexto assíncrono. + +**Exemplo:** + +```python +api = Api() +async_socket = api.async_socket() +# ... use async_socket +await api.aclose() # Clean up connections + +# Or use async context manager (automatic cleanup) +async with Api() as api: + async_socket = api.async_socket() + # ... use async_socket +# Automatically closed +``` + +### `async_bulk(self)` + +Obtenha um cliente para operações em lote assíncronas. + +Fornece operações de importação/exportação em lote com estilo async/await via WebSocket +para o tratamento eficiente de grandes conjuntos de dados. + +**Retorna:** AsyncBulkClient: Cliente para operações em lote assíncronas. + +**Exemplo:** + +```python +async_bulk = api.async_bulk() + +# Export triples asynchronously +async for triple in async_bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import with async generator +async def triple_gen(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +await async_bulk.import_triples( + flow="default", + triples=triple_gen() +) +``` + +### `async_flow(self)` + +Obtenha um cliente de fluxo baseado em REST assíncrono. + +Fornece acesso com estilo async/await às operações de fluxo. Isso é preferível +para aplicativos e frameworks Python assíncronos (FastAPI, aiohttp, etc.). + +**Retorna:** AsyncFlow: Cliente de fluxo assíncrono + +**Exemplo:** + +```python +async_flow = api.async_flow() + +# List flows +flow_ids = await async_flow.list() + +# Execute operations +instance = async_flow.id("default") +result = await instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `async_metrics(self)` + +Obtenha um cliente de métricas assíncrono. + +Fornece acesso com estilo async/await às métricas do Prometheus. + +**Retorna:** AsyncMetrics: Cliente de métricas assíncrono + +**Exemplo:** + +```python +async_metrics = api.async_metrics() +prometheus_text = await async_metrics.get() +print(prometheus_text) +``` + +### `async_socket(self)` + +Obtenha um cliente WebSocket assíncrono para operações de streaming. + +Fornece acesso WebSocket no estilo async/await com suporte a streaming. +Este é o método preferido para streaming assíncrono em Python. + +**Retorna:** AsyncSocketClient: Cliente WebSocket assíncrono + +**Exemplo:** + +```python +async_socket = api.async_socket() +flow = async_socket.flow("default") + +# Stream agent responses +async for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + +### `bulk(self)` + +Obtenha um cliente de operações em lote síncronas para importação/exportação. + +As operações em lote permitem a transferência eficiente de grandes conjuntos de dados via conexões WebSocket, +incluindo triplas, embeddings, contextos de entidades e objetos. + +**Retorna:** BulkClient: Cliente de operações em lote síncronas. + +**Exemplo:** + +```python +bulk = api.bulk() + +# Export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import triples +def triple_generator(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +bulk.import_triples(flow="default", triples=triple_generator()) +``` + +### `close(self)` + +Fechar todas as conexões de cliente síncronas. + +Este método fecha as conexões WebSocket e de operações em lote. +Ele é chamado automaticamente quando sai de um gerenciador de contexto. + +**Exemplo:** + +```python +api = Api() +socket = api.socket() +# ... use socket +api.close() # Clean up connections + +# Or use context manager (automatic cleanup) +with Api() as api: + socket = api.socket() + # ... use socket +# Automatically closed +``` + +### `collection(self)` + +Obtenha um cliente de Coleção para gerenciar coleções de dados. + +As Coleções organizam documentos e dados de grafos de conhecimento em +agrupamentos lógicos para isolamento e controle de acesso. + +**Retorna:** Coleção: Cliente de gerenciamento de Coleção + +**Exemplo:** + +```python +collection = api.collection() + +# List collections +colls = collection.list_collections(user="trustgraph") + +# Update collection metadata +collection.update_collection( + user="trustgraph", + collection="default", + name="Default Collection", + description="Main data collection" +) +``` + +### `config(self)` + +Obtenha um cliente de Config para gerenciar as configurações. + +**Retorna:** Config: Cliente de gerenciamento de configuração + +**Exemplo:** + +```python +config = api.config() + +# Get configuration values +values = config.get([ConfigKey(type="llm", key="model")]) + +# Set configuration +config.put([ConfigValue(type="llm", key="model", value="gpt-4")]) +``` + +### `flow(self)` + +Obtenha um cliente Flow para gerenciar e interagir com fluxos. + +Os fluxos são as unidades de execução primárias no TrustGraph, fornecendo acesso a +serviços como agentes, consultas RAG, embeddings e processamento de documentos. + +**Retorna:** Flow: Cliente de gerenciamento de fluxos + +**Exemplo:** + +```python +flow_client = api.flow() + +# List available blueprints +blueprints = flow_client.list_blueprints() + +# Get a specific flow instance +flow_instance = flow_client.id("default") +response = flow_instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `knowledge(self)` + +Obtenha um cliente Knowledge para gerenciar os núcleos do grafo de conhecimento. + +**Retorna:** Knowledge: Cliente de gerenciamento de grafo de conhecimento + +**Exemplo:** + +```python +knowledge = api.knowledge() + +# List available KG cores +cores = knowledge.list_kg_cores(user="trustgraph") + +# Load a KG core +knowledge.load_kg_core(id="core-123", user="trustgraph") +``` + +### `library(self)` + +Obtenha um cliente da Biblioteca para gerenciamento de documentos. + +A biblioteca fornece armazenamento de documentos, gerenciamento de metadados e +coordenação do fluxo de trabalho de processamento. + +**Retorna:** Biblioteca: Cliente de gerenciamento de biblioteca de documentos + +**Exemplo:** + +```python +library = api.library() + +# Add a document +library.add_document( + document=b"Document content", + id="doc-123", + metadata=[], + user="trustgraph", + title="My Document", + comments="Test document" +) + +# List documents +docs = library.get_documents(user="trustgraph") +``` + +### `metrics(self)` + +Obtém um cliente de métricas síncronas para monitoramento. + +Recupera métricas formatadas em Prometheus do serviço TrustGraph +para monitoramento e observabilidade. + +**Retorna:** Métricas: Cliente de métricas síncronas + +**Exemplo:** + +```python +metrics = api.metrics() +prometheus_text = metrics.get() +print(prometheus_text) +``` + +### `request(self, path, request)` + +Faça uma requisição de API REST de baixo nível. + +Este método é principalmente para uso interno, mas pode ser usado para acesso direto +à API quando necessário. + +**Argumentos:** + +`path`: Caminho do endpoint da API (relativo à URL base) +`request`: Payload da requisição como um dicionário + +**Retorna:** dict: Objeto de resposta + +**Levanta:** + +`ProtocolException`: Se o status da resposta não for 200 ou a resposta não for JSON +`ApplicationException`: Se a resposta contiver um erro + +**Exemplo:** + +```python +response = api.request("flow", { + "operation": "list-flows" +}) +``` + +### `socket(self)` + +Obtenha um cliente WebSocket síncrono para operações de streaming. + +As conexões WebSocket fornecem suporte de streaming para respostas em tempo real +de agentes, consultas RAG e preenchimentos de texto. Este método retorna um +wrapper síncrono em torno do protocolo WebSocket. + +**Retorna:** SocketClient: Cliente WebSocket síncrono + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `Flow` + +```python +from trustgraph.api import Flow +``` + +Cliente de gerenciamento de fluxo para operações de blueprint e instância de fluxo. + +Esta classe fornece métodos para gerenciar blueprints de fluxo (modelos) e +instâncias de fluxo (fluxos em execução). Blueprints definem a estrutura e +os parâmetros dos fluxos, enquanto as instâncias representam fluxos ativos que podem +executar serviços. + +### Métodos + +### `__init__(self, api)` + +Inicializar o cliente de fluxo. + +**Argumentos:** + +`api`: Instância pai da API para fazer requisições + +### `delete_blueprint(self, blueprint_name)` + +Excluir um blueprint de fluxo. + +**Argumentos:** + +`blueprint_name`: Nome do blueprint a ser excluído + +**Exemplo:** + +```python +api.flow().delete_blueprint("old-blueprint") +``` + +### `get(self, id)` + +Obtenha a definição de uma instância de fluxo em execução. + +**Argumentos:** + +`id`: ID da instância de fluxo + +**Retorna:** dict: Definição da instância de fluxo + +**Exemplo:** + +```python +flow_def = api.flow().get("default") +print(flow_def) +``` + +### `get_blueprint(self, blueprint_name)` + +Obtenha uma definição de blueprint de fluxo por nome. + +**Argumentos:** + +`blueprint_name`: Nome do blueprint a ser recuperado + +**Retorna:** dict: Definição do blueprint como um dicionário + +**Exemplo:** + +```python +blueprint = api.flow().get_blueprint("default") +print(blueprint) # Blueprint configuration +``` + +### `id(self, id='default')` + +Obtenha uma instância de FlowInstance para executar operações em um fluxo específico. + +**Argumentos:** + +`id`: Identificador do fluxo (padrão: "default") + +**Retorna:** FlowInstance: Instância do fluxo para operações de serviço + +**Exemplo:** + +```python +flow = api.flow().id("my-flow") +response = flow.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `list(self)` + +Listar todas as instâncias de fluxo ativas. + +**Retorna:** list[str]: Lista de IDs de instâncias de fluxo + +**Exemplo:** + +```python +flows = api.flow().list() +print(flows) # ['default', 'flow-1', 'flow-2', ...] +``` + +### `list_blueprints(self)` + +Listar todos os diagramas de fluxo disponíveis. + +**Retorna:** list[str]: Lista de nomes de diagramas. + +**Exemplo:** + +```python +blueprints = api.flow().list_blueprints() +print(blueprints) # ['default', 'custom-flow', ...] +``` + +### `put_blueprint(self, blueprint_name, definition)` + +Criar ou atualizar um modelo de fluxo. + +**Argumentos:** + +`blueprint_name`: Nome para o modelo +`definition`: Dicionário de definição do modelo + +**Exemplo:** + +```python +definition = { + "services": ["text-completion", "graph-rag"], + "parameters": {"model": "gpt-4"} +} +api.flow().put_blueprint("my-blueprint", definition) +``` + +### `request(self, path=None, request=None)` + +Faça uma solicitação de API com escopo de fluxo. + +**Argumentos:** + +`path`: Sufixo de caminho opcional para os endpoints de fluxo. +`request`: Dicionário de carga útil da solicitação. + +**Retorna:** dict: Objeto de resposta. + +**Levanta:** + +`RuntimeError`: Se o parâmetro da solicitação não for especificado. + +### `start(self, blueprint_name, id, description, parameters=None)` + +Inicie uma nova instância de fluxo a partir de um modelo. + +**Argumentos:** + +`blueprint_name`: Nome do modelo a ser instanciado. +`id`: Identificador exclusivo para a instância do fluxo. +`description`: Descrição legível por humanos. +`parameters`: Dicionário de parâmetros opcionais. + +**Exemplo:** + +```python +api.flow().start( + blueprint_name="default", + id="my-flow", + description="My custom flow", + parameters={"model": "gpt-4"} +) +``` + +### `stop(self, id)` + +Interromper uma instância de fluxo em execução. + +**Argumentos:** + +`id`: ID da instância de fluxo a ser interrompida + +**Exemplo:** + +```python +api.flow().stop("my-flow") +``` + + +-- + +## `FlowInstance` + +```python +from trustgraph.api import FlowInstance +``` + +Cliente de instância de fluxo para executar serviços em um fluxo específico. + +Esta classe fornece acesso a todos os serviços do TrustGraph, incluindo: +Preenchimento de texto e incorporações +Operações de agente com gerenciamento de estado +Consultas RAG de grafos e documentos +Operações de grafo de conhecimento (triplas, objetos) +Carregamento e processamento de documentos +Conversão de linguagem natural para consulta GraphQL +Análise de dados estruturados e detecção de esquema +Execução de ferramentas MCP +Modelagem de prompts + +Os serviços são acessados através de uma instância de fluxo em execução, identificada por um ID. + +### Métodos + +### `__init__(self, api, id)` + +Inicializa FlowInstance. + +**Argumentos:** + +`api`: Cliente Flow pai +`id`: Identificador da instância de fluxo + +### `agent(self, question, user='trustgraph', state=None, group=None, history=None)` + +Executa uma operação de agente com capacidades de raciocínio e uso de ferramentas. + +Os agentes podem realizar raciocínio em várias etapas, usar ferramentas e manter o estado da conversa +em várias interações. Esta é uma versão síncrona não transmitida. + +**Argumentos:** + +`question`: Pergunta ou instrução do usuário +`user`: Identificador do usuário (padrão: "trustgraph") +`state`: Dicionário de estado opcional para conversas com estado +`group`: Identificador de grupo opcional para contextos multiusuário +`history`: Histórico de conversa opcional como uma lista de dicionários de mensagens + +**Retorna:** str: Resposta final do agente + +**Exemplo:** + +```python +flow = api.flow().id("default") + +# Simple question +answer = flow.agent( + question="What is the capital of France?", + user="trustgraph" +) + +# With conversation history +history = [ + {"role": "user", "content": "Hello"}, + {"role": "assistant", "content": "Hi! How can I help?"} +] +answer = flow.agent( + question="Tell me about Paris", + user="trustgraph", + history=history +) +``` + +### `detect_type(self, sample)` + +Detectar o tipo de dado de uma amostra de dados estruturados. + +**Argumentos:** + +`sample`: Amostra de dados a ser analisada (conteúdo em string) + +**Retorna:** Dicionário com detected_type, confidence e metadados opcionais. + +### `diagnose_data(self, sample, schema_name=None, options=None)` + +Realizar diagnóstico de dados combinado: detectar tipo e gerar descritor. + +**Argumentos:** + +`sample`: Amostra de dados a ser analisada (conteúdo em string) +`schema_name`: Nome de esquema de destino opcional para geração de descritor. +`options`: Parâmetros opcionais (por exemplo, delimitador para CSV). + +**Retorna:** Dicionário com detected_type, confidence, descriptor e metadados. + +### `document_embeddings_query(self, text, user, collection, limit=10)` + +Consultar trechos de documentos usando similaridade semântica. + +Encontra trechos de documentos cujo conteúdo é semanticamente similar ao +texto de entrada, usando embeddings vetoriais. + +**Argumentos:** + +`text`: Texto de consulta para busca semântica. +`user`: Identificador de usuário/espaço de chaves. +`collection`: Identificador de coleção. +`limit`: Número máximo de resultados (padrão: 10). + +**Retorna:** Dicionário: Resultados da consulta com trechos contendo chunk_id e score. + +**Exemplo:** + +```python +flow = api.flow().id("default") +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "doc1/p0/c0", "score": 0.95}, ...]} +``` + +### `document_rag(self, query, user='trustgraph', collection='default', doc_limit=10)` + +Execute uma consulta de Geração Aumentada por Recuperação (RAG) baseada em documentos. + +O RAG baseado em documentos usa incorporações vetoriais para encontrar trechos de documentos relevantes, +e então gera uma resposta usando um LLM, utilizando esses trechos como contexto. + +**Argumentos:** + +`query`: Consulta em linguagem natural +`user`: Identificador de usuário/espaço de chaves (padrão: "trustgraph") +`collection`: Identificador de coleção (padrão: "default") +`doc_limit`: Número máximo de trechos de documentos a serem recuperados (padrão: 10) + +**Retorna:** str: Resposta gerada incorporando o contexto do documento + +**Exemplo:** + +```python +flow = api.flow().id("default") +response = flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts)` + +Gere incorporações vetoriais para um ou mais textos. + +Converte textos em representações vetoriais densas adequadas para busca semântica e +comparação de similaridade. + +**Argumentos:** + +`texts`: Lista de textos de entrada a serem incorporados + +**Retorna:** list[list[list[float]]]: Incorporações vetoriais, um conjunto por texto de entrada + +**Exemplo:** + +```python +flow = api.flow().id("default") +vectors = flow.embeddings(["quantum computing"]) +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `generate_descriptor(self, sample, data_type, schema_name, options=None)` + +Gerar um descritor para mapeamento de dados estruturados para um esquema específico. + +**Argumentos:** + +`sample`: Amostra de dados a ser analisada (conteúdo de string) +`data_type`: Tipo de dados (csv, json, xml) +`schema_name`: Nome do esquema de destino para a geração do descritor +`options`: Parâmetros opcionais (por exemplo, delimitador para CSV) + +**Retorna:** dicionário com o descritor e metadados + +### `graph_embeddings_query(self, text, user, collection, limit=10)` + +Consultar entidades de grafo de conhecimento usando similaridade semântica. + +Encontra entidades no grafo de conhecimento cujas descrições são semanticamente +similares ao texto de entrada, usando incorporações vetoriais. + +**Argumentos:** + +`text`: Texto de consulta para pesquisa semântica +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção +`limit`: Número máximo de resultados (padrão: 10) + +**Retorna:** dicionário: Resultados da consulta com entidades similares + +**Exemplo:** + +```python +flow = api.flow().id("default") +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +# results contains {"entities": [{"entity": {...}, "score": 0.95}, ...]} +``` + +### `graph_rag(self, query, user='trustgraph', collection='default', entity_limit=50, triple_limit=30, max_subgraph_size=150, max_path_length=2)` + +Execute consulta de Geração Aumentada por Recuperação (RAG) baseada em grafo. + +O Graph RAG utiliza a estrutura do grafo de conhecimento para encontrar o contexto relevante, +percorrendo as relações entre entidades, e então gera uma resposta usando um LLM. + +**Argumentos:** + +`query`: Consulta em linguagem natural +`user`: Identificador de usuário/espaço de chaves (padrão: "trustgraph") +`collection`: Identificador de coleção (padrão: "default") +`entity_limit`: Número máximo de entidades a recuperar (padrão: 50) +`triple_limit`: Número máximo de triplas por entidade (padrão: 30) +`max_subgraph_size`: Número máximo total de triplas no subgrafo (padrão: 150) +`max_path_length`: Profundidade máxima de travessia (padrão: 2) + +**Retorna:** str: Resposta gerada incorporando o contexto do grafo + +**Exemplo:** + +```python +flow = api.flow().id("default") +response = flow.graph_rag( + query="Tell me about Marie Curie's discoveries", + user="trustgraph", + collection="scientists", + entity_limit=20, + max_path_length=3 +) +print(response) +``` + +### `load_document(self, document, id=None, metadata=None, user=None, collection=None)` + +Carregar um documento binário para processamento. + +Envia um documento (PDF, DOCX, imagens, etc.) para extração e +processamento através do pipeline de documentos do fluxo. + +**Argumentos:** + +`document`: Conteúdo do documento como bytes +`id`: Identificador de documento opcional (gerado automaticamente se for None) +`metadata`: Metadados opcionais (lista de Triplas ou objeto com método emit) +`user`: Identificador de usuário/espaço de chaves (opcional) +`collection`: Identificador de coleção (opcional) + +**Retorna:** dict: Resposta de processamento + +**Levanta:** + +`RuntimeError`: Se metadados forem fornecidos sem id + +**Exemplo:** + +```python +flow = api.flow().id("default") + +# Load a PDF document +with open("research.pdf", "rb") as f: + result = flow.load_document( + document=f.read(), + id="research-001", + user="trustgraph", + collection="papers" + ) +``` + +### `load_text(self, text, id=None, metadata=None, charset='utf-8', user=None, collection=None)` + +Carrega o conteúdo de texto para processamento. + +Carrega o conteúdo de texto para extração e processamento através do pipeline de texto do fluxo. + + +**Argumentos:** + +`text`: Conteúdo de texto como bytes +`id`: Identificador de documento opcional (gerado automaticamente se for None) +`metadata`: Metadados opcionais (lista de Triplas ou objeto com método emit) +`charset`: Codificação de caracteres (padrão: "utf-8") +`user`: Identificador de usuário/espaço de chaves (opcional) +`collection`: Identificador de coleção (opcional) + +**Retorna:** dict: Resposta de processamento + +**Levanta:** + +`RuntimeError`: Se metadados forem fornecidos sem id + +**Exemplo:** + +```python +flow = api.flow().id("default") + +# Load text content +text_content = b"This is the document content..." +result = flow.load_text( + text=text_content, + id="text-001", + charset="utf-8", + user="trustgraph", + collection="documents" +) +``` + +### `mcp_tool(self, name, parameters={})` + +Execute uma ferramenta de Protocolo de Contexto de Modelo (MCP). + +As ferramentas MCP fornecem funcionalidade extensível para agentes e fluxos de trabalho, +permitindo a integração com sistemas e serviços externos. + +**Argumentos:** + +`name`: Nome/identificador da ferramenta +`parameters`: Dicionário de parâmetros da ferramenta (padrão: {}) + +**Retorna:** str ou dict: Resultado da execução da ferramenta + +**Levanta:** + +`ProtocolException`: Se o formato da resposta for inválido + +**Exemplo:** + +```python +flow = api.flow().id("default") + +# Execute a tool +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `nlp_query(self, question, max_results=100)` + +Converter uma pergunta em linguagem natural em uma consulta GraphQL. + +**Argumentos:** + +`question`: Pergunta em linguagem natural +`max_results`: Número máximo de resultados a retornar (padrão: 100) + +**Retorna:** dicionário com graphql_query, variáveis, schemas detectados, confiança + +### `prompt(self, id, variables)` + +Executar um modelo de prompt com substituição de variáveis. + +Modelos de prompt permitem padrões de prompt reutilizáveis com variáveis dinâmicas. +de substituição, úteis para engenharia de prompt consistente. + +**Argumentos:** + +`id`: Identificador do modelo de prompt. +`variables`: Dicionário de mapeamentos de nomes de variáveis para valores. + +**Retorna:** str ou dict: Resultado do prompt renderizado (texto ou objeto estruturado). + +**Levanta:** + +`ProtocolException`: Se o formato da resposta for inválido. + +**Exemplo:** + +```python +flow = api.flow().id("default") + +# Text template +result = flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"} +) + +# Structured template +result = flow.prompt( + id="extract-entities", + variables={"text": "Marie Curie won Nobel Prizes"} +) +``` + +### `request(self, path, request)` + +Faça uma solicitação de serviço nesta instância de fluxo. + +**Argumentos:** + +`path`: Caminho do serviço (por exemplo, "service/text-completion") +`request`: Dicionário de carga útil da solicitação + +**Retorna:** dict: Resposta do serviço + +### `row_embeddings_query(self, text, schema_name, user='trustgraph', collection='default', index_name=None, limit=10)` + +Consulta dados de linha usando similaridade semântica em campos indexados. + +Encontra linhas cujos valores de campos indexados são semanticamente semelhantes ao +texto de entrada, usando incorporações vetoriais. Isso permite a correspondência aproximada/semântica +em dados estruturados. + +**Argumentos:** + +`text`: Texto de consulta para pesquisa semântica +`schema_name`: Nome do esquema para pesquisar +`user`: Identificador de usuário/espaço de chaves (padrão: "trustgraph") +`collection`: Identificador de coleção (padrão: "default") +`index_name`: Nome de índice opcional para filtrar a pesquisa para um índice específico +`limit`: Número máximo de resultados (padrão: 10) + +**Retorna:** dict: Resultados da consulta com correspondências contendo index_name, index_value, text e score + +**Exemplo:** + +```python +flow = api.flow().id("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query, user='trustgraph', collection='default', variables=None, operation_name=None)` + +Execute uma consulta GraphQL contra linhas estruturadas no grafo de conhecimento. + +Consulta dados estruturados usando a sintaxe GraphQL, permitindo consultas complexas +com filtragem, agregação e travessia de relacionamentos. + +**Argumentos:** + +`query`: String de consulta GraphQL +`user`: Identificador de usuário/espaço de chaves (padrão: "trustgraph") +`collection`: Identificador de coleção (padrão: "default") +`variables`: Dicionário opcional de variáveis de consulta +`operation_name`: Nome de operação opcional para documentos com várias operações + +**Retorna:** dict: Resposta GraphQL com os campos 'data', 'errors' e/ou 'extensions' + +**Levanta:** + +`ProtocolException`: Se ocorrer um erro de nível do sistema + +**Exemplo:** + +```python +flow = api.flow().id("default") + +# Simple query +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) + +# Query with variables +query = ''' +query GetScientist($name: String!) { + scientists(name: $name) { + name + nobelPrizes + } +} +''' +result = flow.rows_query( + query=query, + variables={"name": "Marie Curie"} +) +``` + +### `schema_selection(self, sample, options=None)` + +Selecione os esquemas correspondentes para uma amostra de dados usando análise de prompt. + +**Argumentos:** + +`sample`: Amostra de dados a ser analisada (conteúdo de string) +`options`: Parâmetros opcionais + +**Retorna:** dicionário com array schema_matches e metadados + +### `structured_query(self, question, user='trustgraph', collection='default')` + +Execute uma pergunta em linguagem natural contra dados estruturados. +Combina a conversão de consulta NLP e a execução GraphQL. + +**Argumentos:** + +`question`: Pergunta em linguagem natural +`user`: Identificador de keyspace do Cassandra (padrão: "trustgraph") +`collection`: Identificador da coleção de dados (padrão: "default") + +**Retorna:** dicionário com dados e erros opcionais + +### `text_completion(self, system, prompt)` + +Execute a conclusão de texto usando o LLM do fluxo. + +**Argumentos:** + +`system`: Prompt do sistema que define o comportamento do assistente +`prompt`: Prompt/pergunta do usuário + +**Retorna:** str: Texto de resposta gerado + +**Exemplo:** + +```python +flow = api.flow().id("default") +response = flow.text_completion( + system="You are a helpful assistant", + prompt="What is quantum computing?" +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=10000)` + +Consultar triplas de grafos de conhecimento usando correspondência de padrões. + +Procura triplas RDF que correspondam aos padrões de sujeito, predicado e/ou +objeto fornecidos. Parâmetros não especificados atuam como curingas. + +**Argumentos:** + +`s`: URI do sujeito (opcional, use None para curinga) +`p`: URI do predicado (opcional, use None para curinga) +`o`: URI do objeto ou Literal (opcional, use None para curinga) +`user`: Identificador de usuário/espaço de chaves (opcional) +`collection`: Identificador de coleção (opcional) +`limit`: Número máximo de resultados a retornar (padrão: 10000) + +**Retorna:** list[Triple]: Lista de objetos Triple correspondentes + +**Levanta:** + +`RuntimeError`: Se s ou p não forem um Uri, ou o não for um Uri/Literal + +**Exemplo:** + +```python +from trustgraph.knowledge import Uri, Literal + +flow = api.flow().id("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s=Uri("http://example.org/person/marie-curie"), + user="trustgraph", + collection="scientists" +) + +# Find all instances of a specific relationship +triples = flow.triples_query( + p=Uri("http://example.org/ontology/discovered"), + limit=100 +) +``` + + +-- + +## `AsyncFlow` + +```python +from trustgraph.api import AsyncFlow +``` + +Cliente de gerenciamento de fluxo assíncrono usando a API REST. + +Fornece operações de gerenciamento de fluxo baseadas em async/await, incluindo listagem, +início, parada de fluxos e gerenciamento de definições de classes de fluxo. Também fornece +acesso a serviços de escopo de fluxo, como agentes, RAG e consultas, por meio de +endpoints REST não baseados em streaming. + +Nota: Para suporte a streaming, use AsyncSocketClient em vez disso. + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicializa o cliente de fluxo assíncrono. + +**Argumentos:** + +`url`: URL base para a API TrustGraph +`timeout`: Tempo limite de solicitação em segundos +`token`: Token de autorização opcional para autenticação + +### `aclose(self) -> None` + +Fecha o cliente assíncrono e libera recursos. + +Nota: A limpeza é tratada automaticamente pelos gerenciadores de contexto de sessão aiohttp. +Este método é fornecido para consistência com outros clientes assíncronos. + +### `delete_class(self, class_name: str)` + +Exclui uma definição de classe de fluxo. + +Remove um modelo de classe de fluxo do sistema. Não afeta +instâncias de fluxo em execução. + +**Argumentos:** + +`class_name`: Nome da classe de fluxo a ser excluída + +**Exemplo:** + +```python +async_flow = await api.async_flow() + +# Delete a flow class +await async_flow.delete_class("old-flow-class") +``` + +### `get(self, id: str) -> Dict[str, Any]` + +Obter a definição do fluxo. + +Recupera a configuração completa do fluxo, incluindo seu nome de classe, +descrição e parâmetros. + +**Argumentos:** + +`id`: Identificador do fluxo + +**Retorna:** dict: Objeto de definição do fluxo + +**Exemplo:** + +```python +async_flow = await api.async_flow() + +# Get flow definition +flow_def = await async_flow.get("default") +print(f"Flow class: {flow_def.get('class-name')}") +print(f"Description: {flow_def.get('description')}") +``` + +### `get_class(self, class_name: str) -> Dict[str, Any]` + +Obter a definição da classe de fluxo. + +Recupera a definição do blueprint para uma classe de fluxo, incluindo seu +esquema de configuração e associações de serviço. + +**Argumentos:** + +`class_name`: Nome da classe de fluxo + +**Retorna:** dict: Objeto de definição da classe de fluxo + +**Exemplo:** + +```python +async_flow = await api.async_flow() + +# Get flow class definition +class_def = await async_flow.get_class("default") +print(f"Services: {class_def.get('services')}") +``` + +### `id(self, flow_id: str)` + +Obtenha uma instância de cliente de fluxo assíncrono. + +Retorna um cliente para interagir com os serviços de um fluxo específico +(agente, RAG, consultas, embeddings, etc.). + +**Argumentos:** + +`flow_id`: Identificador do fluxo + +**Retorna:** AsyncFlowInstance: Cliente para operações específicas do fluxo + +**Exemplo:** + +```python +async_flow = await api.async_flow() + +# Get flow instance +flow = async_flow.id("default") + +# Use flow services +result = await flow.graph_rag( + query="What is TrustGraph?", + user="trustgraph", + collection="default" +) +``` + +### `list(self) -> List[str]` + +Liste todos os identificadores de fluxo. + +Recupera os IDs de todos os fluxos atualmente implementados no sistema. + +**Retorna:** list[str]: Lista de identificadores de fluxo + +**Exemplo:** + +```python +async_flow = await api.async_flow() + +# List all flows +flows = await async_flow.list() +print(f"Available flows: {flows}") +``` + +### `list_classes(self) -> List[str]` + +Listar todos os nomes das classes de fluxo. + +Recupera os nomes de todas as classes de fluxo (modelos) disponíveis no sistema. + +**Retorna:** list[str]: Lista de nomes das classes de fluxo. + +**Exemplo:** + +```python +async_flow = await api.async_flow() + +# List available flow classes +classes = await async_flow.list_classes() +print(f"Available flow classes: {classes}") +``` + +### `put_class(self, class_name: str, definition: Dict[str, Any])` + +Criar ou atualizar uma definição de classe de fluxo. + +Armazena um modelo de classe de fluxo que pode ser usado para instanciar fluxos. + +**Argumentos:** + +`class_name`: Nome da classe de fluxo +`definition`: Objeto de definição da classe de fluxo + +**Exemplo:** + +```python +async_flow = await api.async_flow() + +# Create a custom flow class +class_def = { + "services": { + "agent": {"module": "agent", "config": {...}}, + "graph-rag": {"module": "graph-rag", "config": {...}} + } +} +await async_flow.put_class("custom-flow", class_def) +``` + +### `request(self, path: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +Faça uma requisição HTTP POST assíncrona para a API Gateway. + +Método interno para fazer requisições autenticadas para a API TrustGraph. + +**Argumentos:** + +`path`: Caminho do endpoint da API (relativo à URL base) +`request_data`: Dicionário de carga útil da requisição + +**Retorna:** dict: Objeto de resposta da API + +**Levanta:** + +`ProtocolException`: Se o status HTTP não for 200 ou a resposta não for um JSON válido +`ApplicationException`: Se a API retornar uma resposta de erro + +### `start(self, class_name: str, id: str, description: str, parameters: Dict | None = None)` + +Inicia uma nova instância de fluxo. + +Cria e inicia um fluxo a partir de uma definição de classe de fluxo com os +parâmetros especificados. + +**Argumentos:** + +`class_name`: Nome da classe de fluxo a ser instanciada +`id`: Identificador para a nova instância de fluxo +`description`: Descrição legível por humanos do fluxo +`parameters`: Parâmetros de configuração opcionais para o fluxo + +**Exemplo:** + +```python +async_flow = await api.async_flow() + +# Start a flow from a class +await async_flow.start( + class_name="default", + id="my-flow", + description="Custom flow instance", + parameters={"model": "claude-3-opus"} +) +``` + +### `stop(self, id: str)` + +Interromper um fluxo em execução. + +Interrompe e remove uma instância de fluxo, liberando seus recursos. + +**Argumentos:** + +`id`: Identificador do fluxo a ser interrompido + +**Exemplo:** + +```python +async_flow = await api.async_flow() + +# Stop a flow +await async_flow.stop("my-flow") +``` + + +-- + +## `AsyncFlowInstance` + +```python +from trustgraph.api import AsyncFlowInstance +``` + +Cliente de instância de fluxo assíncrono. + +Fornece acesso async/await a serviços com escopo de fluxo, incluindo agentes, +Consultas RAG, embeddings e consultas de grafo. Todas as operações retornam respostas completas (não em streaming). + + +Nota: Para suporte a streaming, use AsyncSocketFlowInstance. + +### Métodos + +### `__init__(self, flow: trustgraph.api.async_flow.AsyncFlow, flow_id: str)` + +Inicializa a instância de fluxo assíncrono. + +**Argumentos:** + +`flow`: Cliente AsyncFlow pai +`flow_id`: Identificador do fluxo + +### `agent(self, question: str, user: str, state: Dict | None = None, group: str | None = None, history: List | None = None, **kwargs: Any) -> Dict[str, Any]` + +Execute uma operação de agente (não em streaming). + +Executa um agente para responder a uma pergunta, com estado de conversa opcional e +histórico. Retorna a resposta completa após o agente ter terminado de +processar. + +Nota: Este método não suporta streaming. Para pensamentos e observações do agente em tempo real, use AsyncSocketFlowInstance.agent() em vez disso. + + +**Argumentos:** + +`question`: Pergunta ou instrução do usuário +`user`: Identificador do usuário +`state`: Dicionário de estado opcional para o contexto da conversa +`group`: Identificador de grupo opcional para o gerenciamento de sessões +`history`: Lista de histórico de conversa opcional +`**kwargs`: Parâmetros adicionais específicos do serviço + +**Retorna:** dict: Resposta completa do agente, incluindo a resposta e metadados + +**Exemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute agent +result = await flow.agent( + question="What is the capital of France?", + user="trustgraph" +) +print(f"Answer: {result.get('response')}") +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> str` + +Execute consulta RAG baseada em documentos (não em streaming). + +Realiza a Geração Aumentada por Recuperação usando incorporações de documentos. +Recupera trechos de documentos relevantes por meio de busca semântica e, em seguida, gera +uma resposta fundamentada nos documentos recuperados. Retorna a resposta completa. + +Nota: Este método não suporta streaming. Para respostas RAG em streaming, +use AsyncSocketFlowInstance.document_rag() em vez disso. + +**Argumentos:** + +`query`: Texto da consulta do usuário +`user`: Identificador do usuário +`collection`: Identificador da coleção contendo os documentos +`doc_limit`: Número máximo de trechos de documentos a serem recuperados (padrão: 10) +`**kwargs`: Parâmetros adicionais específicos do serviço + +**Retorna:** str: Resposta completa gerada com base nos dados do documento + +**Exemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query documents +response = await flow.document_rag( + query="What does the documentation say about authentication?", + user="trustgraph", + collection="docs", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts: list, **kwargs: Any)` + +Gere incorporações para textos de entrada. + +Converte textos em representações vetoriais numéricas usando o modelo de incorporação configurado do fluxo. Útil para pesquisa semântica e comparações de similaridade. + + + +**Argumentos:** + +`texts`: Lista de textos de entrada a serem incorporados +`**kwargs`: Parâmetros adicionais específicos do serviço + +**Retorna:** dict: Resposta contendo vetores de incorporação + +**Exemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate embeddings +result = await flow.embeddings(texts=["Sample text to embed"]) +vectors = result.get("vectors") +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any)` + +Consulta incorporações de grafos para busca semântica de entidades. + +Realiza uma busca semântica sobre as incorporações de entidades do grafo para encontrar entidades +mais relevantes para o texto de entrada. Retorna entidades classificadas por similaridade. + +**Argumentos:** + +`text`: Texto de consulta para a busca semântica +`user`: Identificador do usuário +`collection`: Identificador da coleção contendo as incorporações do grafo +`limit`: Número máximo de resultados a serem retornados (padrão: 10) +`**kwargs`: Parâmetros adicionais específicos do serviço + +**Retorna:** dict: Resposta contendo correspondências de entidades classificadas com pontuações de similaridade + +**Exemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find related entities +results = await flow.graph_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="tech-kb", + limit=5 +) + +for entity in results.get("entities", []): + print(f"{entity['name']}: {entity['score']}") +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> str` + +Execute consulta RAG baseada em grafo (não em streaming). + +Realiza a geração aumentada por recuperação usando dados de grafo de conhecimento. +Identifica entidades relevantes e seus relacionamentos, e então gera uma +resposta fundamentada na estrutura do grafo. Retorna a resposta completa. + +Nota: Este método não suporta streaming. Para respostas RAG em streaming, +use AsyncSocketFlowInstance.graph_rag() em vez disso. + +**Argumentos:** + +`query`: Texto da consulta do usuário +`user`: Identificador do usuário +`collection`: Identificador da coleção contendo o grafo de conhecimento +`max_subgraph_size`: Número máximo de triplas por subgrafo (padrão: 1000) +`max_subgraph_count`: Número máximo de subgrafos a serem recuperados (padrão: 5) +`max_entity_distance`: Distância máxima do grafo para expansão de entidades (padrão: 3) +`**kwargs`: Parâmetros adicionais específicos do serviço + +**Retorna:** str: Resposta completa gerada com base nos dados do grafo + +**Exemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query knowledge graph +response = await flow.graph_rag( + query="What are the relationships between these entities?", + user="trustgraph", + collection="medical-kb", + max_subgraph_count=3 +) +print(response) +``` + +### `request(self, service: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +Faça uma requisição para um serviço com escopo de fluxo. + +Método interno para chamar serviços dentro desta instância de fluxo. + +**Argumentos:** + +`service`: Nome do serviço (por exemplo, "agent", "graph-rag", "triples") +`request_data`: Payload da requisição do serviço + +**Retorna:** dict: Objeto de resposta do serviço + +**Lança:** + +`ProtocolException`: Se a requisição falhar ou a resposta for inválida +`ApplicationException`: Se o serviço retornar um erro + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any)` + +Consulta as incorporações de linhas para pesquisa semântica em dados estruturados. + +Realiza uma pesquisa semântica sobre as incorporações do índice de linhas para encontrar linhas cujos +valores de campo indexados são mais semelhantes ao texto de entrada. Permite +correspondência fuzzy/semântica em dados estruturados. + +**Argumentos:** + +`text`: Texto da consulta para pesquisa semântica +`schema_name`: Nome do esquema para pesquisar +`user`: Identificador do usuário (padrão: "trustgraph") +`collection`: Identificador da coleção (padrão: "default") +`index_name`: Nome de índice opcional para filtrar a pesquisa para um índice específico +`limit`: Número máximo de resultados a serem retornados (padrão: 10) +`**kwargs`: Parâmetros adicionais específicos do serviço + +**Retorna:** dict: Resposta contendo correspondências com index_name, index_value, text e score + +**Exemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Search for customers by name similarity +results = await flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +for match in results.get("matches", []): + print(f"{match['index_name']}: {match['index_value']} (score: {match['score']})") +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs: Any)` + +Execute uma consulta GraphQL em linhas armazenadas. + +Consulta linhas de dados estruturados usando a sintaxe GraphQL. Suporta consultas complexas +com variáveis e operações nomeadas. + +**Argumentos:** + +`query`: String da consulta GraphQL +`user`: Identificador do usuário +`collection`: Identificador da coleção contendo as linhas +`variables`: Variáveis de consulta GraphQL opcionais +`operation_name`: Nome da operação opcional para consultas com múltiplas operações +`**kwargs`: Parâmetros adicionais específicos do serviço + +**Retorna:** dict: Resposta GraphQL com dados e/ou erros + +**Exemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute GraphQL query +query = ''' + query GetUsers($status: String!) { + users(status: $status) { + id + name + email + } + } +''' + +result = await flow.rows_query( + query=query, + user="trustgraph", + collection="users", + variables={"status": "active"} +) + +for user in result.get("data", {}).get("users", []): + print(f"{user['name']}: {user['email']}") +``` + +### `text_completion(self, system: str, prompt: str, **kwargs: Any) -> str` + +Gerar conclusão de texto (não em fluxo). + +Gera uma resposta de texto a partir de um LLM, dado um prompt do sistema e um prompt do usuário. +Retorna o texto da resposta completo. + +Nota: Este método não suporta streaming. Para geração de texto em fluxo, +use AsyncSocketFlowInstance.text_completion() em vez disso. + +**Argumentos:** + +`system`: Prompt do sistema que define o comportamento do LLM. +`prompt`: Prompt ou pergunta do usuário. +`**kwargs`: Parâmetros adicionais específicos do serviço. + +**Retorna:** str: Resposta de texto gerada completa. + +**Exemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate text +response = await flow.text_completion( + system="You are a helpful assistant.", + prompt="Explain quantum computing in simple terms." +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs: Any)` + +Consulta triplas RDF usando correspondência de padrões. + +Procura triplas que correspondam aos padrões especificados de sujeito, predicado e/ou +objeto. Os padrões usam "None" como um caractere curinga para corresponder a qualquer valor. + +**Argumentos:** + +`s`: Padrão do sujeito (None para caractere curinga) +`p`: Padrão do predicado (None para caractere curinga) +`o`: Padrão do objeto (None para caractere curinga) +`user`: Identificador do usuário (None para todos os usuários) +`collection`: Identificador da coleção (None para todas as coleções) +`limit`: Número máximo de triplas a retornar (padrão: 100) +`**kwargs`: Parâmetros adicionais específicos do serviço + +**Retorna:** dict: Resposta contendo as triplas correspondentes + +**Exemplo:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find all triples with a specific predicate +results = await flow.triples_query( + p="knows", + user="trustgraph", + collection="social", + limit=50 +) + +for triple in results.get("triples", []): + print(f"{triple['s']} knows {triple['o']}") +``` + + +-- + +## `SocketClient` + +```python +from trustgraph.api import SocketClient +``` + +Cliente WebSocket síncrono para operações de streaming. + +Fornece uma interface síncrona para serviços TrustGraph baseados em WebSocket, +envolvendo a biblioteca de WebSockets assíncrona com geradores síncronos para facilitar o uso. +Suporta respostas de streaming de agentes, consultas RAG e preenchimentos de texto. + +Nota: Este é um wrapper síncrono em torno de operações de WebSocket assíncronas. Para +suporte assíncrono real, use AsyncSocketClient em vez disso. + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicializa o cliente WebSocket síncrono. + +**Argumentos:** + +`url`: URL base para a API TrustGraph (HTTP/HTTPS serão convertidos para WS/WSS) +`timeout`: Tempo limite do WebSocket em segundos +`token`: Token de autorização opcional para autenticação + +### `close(self) -> None` + +Fecha as conexões WebSocket. + +Nota: A limpeza é tratada automaticamente pelos gerenciadores de contexto em código assíncrono. + +### `flow(self, flow_id: str) -> 'SocketFlowInstance'` + +Obtém uma instância de fluxo para operações de streaming de WebSocket. + +**Argumentos:** + +`flow_id`: Identificador do fluxo + +**Retorna:** SocketFlowInstance: Instância de fluxo com métodos de streaming + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent(question="Hello", user="trustgraph", streaming=True): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `SocketFlowInstance` + +```python +from trustgraph.api import SocketFlowInstance +``` + +Fluxo de WebSocket síncrono para operações de streaming. + +Fornece a mesma interface que o FlowInstance REST, mas com suporte a streaming baseado em WebSocket +para respostas em tempo real. Todos os métodos suportam um parâmetro opcional +`streaming` para habilitar a entrega incremental de resultados. + +### Métodos + +### `__init__(self, client: trustgraph.api.socket_client.SocketClient, flow_id: str) -> None` + +Inicializa a instância do fluxo de socket. + +**Argumentos:** + +`client`: SocketClient pai +`flow_id`: Identificador do fluxo + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, streaming: bool = False, **kwargs: Any) -> Dict[str, Any] | Iterator[trustgraph.api.types.StreamingChunk]` + +Executa uma operação de agente com suporte a streaming. + +Os agentes podem realizar raciocínios de várias etapas com o uso de ferramentas. Este método sempre +retorna fragmentos de streaming (pensamentos, observações, respostas), mesmo quando +streaming=False, para mostrar o processo de raciocínio do agente. + +**Argumentos:** + +`question`: Pergunta ou instrução do usuário +`user`: Identificador do usuário +`state`: Dicionário de estado opcional para conversas com estado +`group`: Identificador de grupo opcional para contextos multiusuário +`history`: Histórico de conversas opcional como uma lista de dicionários de mensagens +`streaming`: Habilita o modo de streaming (padrão: Falso) +`**kwargs`: Parâmetros adicionais passados para o serviço do agente + +**Retorna:** Iterator[StreamingChunk]: Fluxo de pensamentos, observações e respostas do agente + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent reasoning +for chunk in flow.agent( + question="What is quantum computing?", + user="trustgraph", + streaming=True +): + if isinstance(chunk, AgentThought): + print(f"[Thinking] {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"[Observation] {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"[Answer] {chunk.content}") +``` + +### `agent_explain(self, question: str, user: str, collection: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, **kwargs: Any) -> Iterator[trustgraph.api.types.StreamingChunk | trustgraph.api.types.ProvenanceEvent]` + +Execute uma operação de agente com suporte para explicabilidade. + +Transmite tanto os fragmentos de conteúdo (AgentThought, AgentObservation, AgentAnswer) +quanto os eventos de rastreabilidade (ProvenanceEvent). Os eventos de rastreabilidade contêm URIs +que podem ser acessados usando o ExplainabilityClient para obter informações detalhadas +sobre o processo de raciocínio do agente. + +O rastreamento do agente consiste em: +Sessão: A pergunta inicial e os metadados da sessão +Iterações: Cada ciclo de pensamento/ação/observação +Conclusão: A resposta final + +**Argumentos:** + +`question`: Pergunta ou instrução do usuário +`user`: Identificador do usuário +`collection`: Identificador de coleção para armazenamento de rastreabilidade +`state`: Dicionário de estado opcional para conversas com estado +`group`: Identificador de grupo opcional para contextos multiusuário +`history`: Histórico de conversas opcional como uma lista de dicionários de mensagens +`**kwargs`: Parâmetros adicionais passados para o serviço do agente +`Yields`: +`Union[StreamingChunk, ProvenanceEvent]`: Fragmentos do agente e eventos de rastreabilidade + +**Exemplo:** + +```python +from trustgraph.api import Api, ExplainabilityClient, ProvenanceEvent +from trustgraph.api import AgentThought, AgentObservation, AgentAnswer + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +for item in flow.agent_explain( + question="What is the capital of France?", + user="trustgraph", + collection="default" +): + if isinstance(item, AgentThought): + print(f"[Thought] {item.content}") + elif isinstance(item, AgentObservation): + print(f"[Observation] {item.content}") + elif isinstance(item, AgentAnswer): + print(f"[Answer] {item.content}") + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.explain_id) + +# Fetch session trace after completion +if provenance_ids: + trace = explain_client.fetch_agent_trace( + provenance_ids[0], # Session URI is first + graph="urn:graph:retrieval", + user="trustgraph", + collection="default" + ) +``` + +### `document_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Consultar trechos de documentos usando similaridade semântica. + +**Argumentos:** + +`text`: Texto da consulta para busca semântica +`user`: Identificador do usuário/espaço de chaves +`collection`: Identificador da coleção +`limit`: Número máximo de resultados (padrão: 10) +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** dict: Resultados da consulta com os IDs dos trechos dos documentos correspondentes + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "...", "score": 0.95}, ...]} +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Execute uma consulta RAG baseada em documentos com streaming opcional. + +Utiliza incorporações vetoriais para encontrar trechos de documentos relevantes e, em seguida, gera +uma resposta usando um LLM. O modo de streaming entrega resultados incrementalmente. + +**Argumentos:** + +`query`: Consulta em linguagem natural +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção +`doc_limit`: Número máximo de trechos de documentos a serem recuperados (padrão: 10) +`streaming`: Habilitar o modo de streaming (padrão: Falso) +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** Union[str, Iterator[str]]: Resposta completa ou fluxo de trechos de texto + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming document RAG +for chunk in flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `document_rag_explain(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +Execute uma consulta RAG baseada em documentos com suporte para explicabilidade. + +Transmite tanto os fragmentos de conteúdo (RAGChunk) quanto os eventos de rastreabilidade (ProvenanceEvent). +Os eventos de rastreabilidade contêm URIs que podem ser recuperados usando o ExplainabilityClient +para obter informações detalhadas sobre como a resposta foi gerada. + +O rastreamento RAG do documento consiste em: +Pergunta: A consulta do usuário +Exploração: Fragmentos recuperados do armazenamento de documentos (chunk_count) +Síntese: A resposta gerada + +**Argumentos:** + +`query`: Consulta em linguagem natural +`user`: Identificador do usuário/espaço de chaves +`collection`: Identificador da coleção +`doc_limit`: Número máximo de fragmentos de documento a serem recuperados (padrão: 10) +`**kwargs`: Parâmetros adicionais passados para o serviço +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: Fragmentos de conteúdo e eventos de rastreabilidade + +**Exemplo:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +for item in flow.document_rag_explain( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +): + if isinstance(item, RAGChunk): + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + # Fetch entity details + entity = explain_client.fetch_entity( + item.explain_id, + graph=item.explain_graph, + user="trustgraph", + collection="research-papers" + ) + print(f"Event: {entity}", file=sys.stderr) +``` + +### `embeddings(self, texts: list, **kwargs: Any) -> Dict[str, Any]` + +Gerar incorporações vetoriais para um ou mais textos. + +**Argumentos:** + +`texts`: Lista de textos de entrada a serem incorporados +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** dict: Resposta contendo vetores (um conjunto por texto de entrada) + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.embeddings(["quantum computing"]) +vectors = result.get("vectors", []) +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Consultar entidades de grafo de conhecimento usando similaridade semântica. + +**Argumentos:** + +`text`: Texto da consulta para busca semântica +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção +`limit`: Número máximo de resultados (padrão: 10) +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** dict: Resultados da consulta com entidades similares + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Execute consulta RAG baseada em grafo com streaming opcional. + +Utiliza a estrutura do grafo de conhecimento para encontrar o contexto relevante e, em seguida, gera +uma resposta usando um LLM. O modo de streaming entrega os resultados incrementalmente. + +**Argumentos:** + +`query`: Consulta em linguagem natural +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção +`max_subgraph_size`: Número máximo total de triplas no subgrafo (padrão: 1000) +`max_subgraph_count`: Número máximo de subgrafos (padrão: 5) +`max_entity_distance`: Profundidade máxima de travessia (padrão: 3) +`streaming`: Habilitar o modo de streaming (padrão: Falso) +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** Union[str, Iterator[str]]: Resposta completa ou fluxo de fragmentos de texto + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming graph RAG +for chunk in flow.graph_rag( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `graph_rag_explain(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +Execute consulta RAG baseada em grafo com suporte para explicabilidade. + +Transmite tanto os fragmentos de conteúdo (RAGChunk) quanto os eventos de rastreabilidade (ProvenanceEvent). +Os eventos de rastreabilidade contêm URIs que podem ser recuperados usando ExplainabilityClient +para obter informações detalhadas sobre como a resposta foi gerada. + +**Argumentos:** + +`query`: Consulta em linguagem natural +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção +`max_subgraph_size`: Número máximo total de triplas no subgrafo (padrão: 1000) +`max_subgraph_count`: Número máximo de subgrafos (padrão: 5) +`max_entity_distance`: Profundidade máxima de travessia (padrão: 3) +`**kwargs`: Parâmetros adicionais passados para o serviço +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: Fragmentos de conteúdo e eventos de rastreabilidade + +**Exemplo:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +response_text = "" + +for item in flow.graph_rag_explain( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists" +): + if isinstance(item, RAGChunk): + response_text += item.content + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.provenance_id) + +# Fetch explainability details +for prov_id in provenance_ids: + entity = explain_client.fetch_entity( + prov_id, + graph="urn:graph:retrieval", + user="trustgraph", + collection="scientists" + ) + print(f"Entity: {entity}") +``` + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]` + +Execute uma ferramenta de Protocolo de Contexto de Modelo (MCP). + +**Argumentos:** + +`name`: Nome/identificador da ferramenta +`parameters`: Dicionário de parâmetros da ferramenta +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** dict: Resultado da execução da ferramenta + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Execute um modelo de prompt com streaming opcional. + +**Argumentos:** + +`id`: Identificador do modelo de prompt +`variables`: Dicionário de mapeamentos de nome de variável para valor +`streaming`: Habilitar o modo de streaming (padrão: Falso) +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** Union[str, Iterator[str]]: Resposta completa ou fluxo de fragmentos de texto + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming prompt execution +for chunk in flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"}, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Consulta dados de linhas usando similaridade semântica em campos indexados. + +Encontra linhas cujos valores de campos indexados são semanticamente similares ao +texto de entrada, usando embeddings vetoriais. Isso permite correspondência aproximada/semântica +em dados estruturados. + +**Argumentos:** + +`text`: Texto de consulta para busca semântica +`schema_name`: Nome do esquema para pesquisar +`user`: Identificador de usuário/espaço de chaves (padrão: "trustgraph") +`collection`: Identificador de coleção (padrão: "default") +`index_name`: Nome de índice opcional para filtrar a pesquisa para um índice específico +`limit`: Número máximo de resultados (padrão: 10) +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** dict: Resultados da consulta com correspondências contendo index_name, index_value, text e score + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict[str, Any] | None = None, operation_name: str | None = None, **kwargs: Any) -> Dict[str, Any]` + +Execute uma consulta GraphQL contra linhas estruturadas. + +**Argumentos:** + +`query`: String de consulta GraphQL +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção +`variables`: Dicionário opcional de variáveis de consulta +`operation_name`: Nome de operação opcional para documentos de múltiplas operações +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** dict: Resposta GraphQL com dados, erros e/ou extensões + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) +``` + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs) -> str | Iterator[str]` + +Execute a conclusão de texto com streaming opcional. + +**Argumentos:** + +`system`: Prompt do sistema que define o comportamento do assistente. +`prompt`: Prompt/pergunta do usuário. +`streaming`: Habilita o modo de streaming (padrão: Falso). +`**kwargs`: Parâmetros adicionais passados para o serviço. + +**Retorna:** Union[str, Iterator[str]]: Resposta completa ou fluxo de fragmentos de texto. + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Non-streaming +response = flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=False +) +print(response) + +# Streaming +for chunk in flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `triples_query(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, **kwargs: Any) -> List[Dict[str, Any]]` + +Consultar triplas de grafos de conhecimento usando correspondência de padrões. + +**Argumentos:** + +`s`: Filtro do sujeito - String URI, dicionário de termos ou None para curinga +`p`: Filtro do predicado - String URI, dicionário de termos ou None para curinga +`o`: Filtro do objeto - String URI/literal, dicionário de termos ou None para curinga +`g`: Filtro do grafo nomeado - String URI ou None para todos os grafos +`user`: Identificador de usuário/espaço de chaves (opcional) +`collection`: Identificador de coleção (opcional) +`limit`: Número máximo de resultados a retornar (padrão: 100) +`**kwargs`: Parâmetros adicionais passados para o serviço + +**Retorna:** List[Dict]: Lista de triplas correspondentes no formato de fio + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s="http://example.org/person/marie-curie", + user="trustgraph", + collection="scientists" +) + +# Query with named graph filter +triples = flow.triples_query( + s="urn:trustgraph:session:abc123", + g="urn:graph:retrieval", + user="trustgraph", + collection="default" +) +``` + +### `triples_query_stream(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, batch_size: int = 20, **kwargs: Any) -> Iterator[List[Dict[str, Any]]]` + +Consultar triplas de um grafo de conhecimento com lotes de streaming. + +Produz lotes de triplas à medida que chegam, reduzindo o tempo para o primeiro resultado +e a sobrecarga de memória para conjuntos de resultados grandes. + +**Argumentos:** + +`s`: Filtro de sujeito - String URI, dicionário de termos ou None para curinga +`p`: Filtro de predicado - String URI, dicionário de termos ou None para curinga +`o`: Filtro de objeto - String URI/literal, dicionário de termos ou None para curinga +`g`: Filtro de grafo nomeado - String URI ou None para todos os grafos +`user`: Identificador de usuário/espaço de chaves (opcional) +`collection`: Identificador de coleção (opcional) +`limit`: Número máximo de resultados a retornar (padrão: 100) +`batch_size`: Triplas por lote (padrão: 20) +`**kwargs`: Parâmetros adicionais passados para o serviço +`Yields`: +`List[Dict]`: Lotes de triplas em formato de fio + +**Exemplo:** + +```python +socket = api.socket() +flow = socket.flow("default") + +for batch in flow.triples_query_stream( + user="trustgraph", + collection="default" +): + for triple in batch: + print(triple["s"], triple["p"], triple["o"]) +``` + + +-- + +## `AsyncSocketClient` + +```python +from trustgraph.api import AsyncSocketClient +``` + +Cliente WebSocket assíncrono + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None)` + +Inicialize self. Consulte help(type(self)) para a assinatura correta. + +### `aclose(self)` + +Fechar conexão WebSocket + +### `flow(self, flow_id: str)` + +Obter instância de fluxo assíncrono para operações WebSocket + + +-- + +## `AsyncSocketFlowInstance` + +```python +from trustgraph.api import AsyncSocketFlowInstance +``` + +Fluxo assíncrono de WebSocket. + +### Métodos + +### `__init__(self, client: trustgraph.api.async_socket_client.AsyncSocketClient, flow_id: str)` + +Inicializa self. Consulte help(type(self)) para obter a assinatura correta. + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: list | None = None, streaming: bool = False, **kwargs) -> Dict[str, Any] | AsyncIterator` + +Agente com streaming opcional. + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs)` + +Documento RAG com streaming opcional. + +### `embeddings(self, texts: list, **kwargs)` + +Gera incorporações de texto. + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs)` + +Consulta incorporações de grafo para pesquisa semântica. + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs)` + +RAG de grafo com streaming opcional. + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs)` + +Executa a ferramenta MCP. + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs)` + +Executa o prompt com streaming opcional. + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs)` + +Consulta incorporações de linha para pesquisa semântica em dados estruturados. + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs)` + +Consulta GraphQL contra linhas estruturadas. + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs)` + +Conclusão de texto com streaming opcional. + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs)` + +Consulta de padrão triplo. + + +-- + +### `build_term(value: Any, term_type: str | None = None, datatype: str | None = None, language: str | None = None) -> Dict[str, Any] | None` + +Cria um dicionário Term no formato de fio a partir de um valor. + +Regras de detecção automática (quando term_type é None): + Já é um dicionário com a chave 't' -> retorna como está (já é um Term) + Começa com http://, https://, urn: -> IRI + Envolvido em <> (por exemplo, ) -> IRI (colchetes angulares removidos) + Qualquer outra coisa -> literal + +**Argumentos:** + +`value`: O valor do termo (string, dicionário ou None) +`term_type`: Um dos valores 'iri', 'literal' ou None para detecção automática +`datatype`: Tipo de dados para objetos literais (por exemplo, xsd:integer) +`language`: Etiqueta de idioma para objetos literais (por exemplo, en) + +**Retorna:** dict: Dicionário Term no formato de fio, ou None se o valor for None + + +-- + +## `BulkClient` + +```python +from trustgraph.api import BulkClient +``` + +Cliente para operações em lote síncronas para importação/exportação. + +Fornece transferência eficiente de dados em lote via WebSocket para grandes conjuntos de dados. +Envolve operações assíncronas do WebSocket com geradores síncronos para facilitar o uso. + +Nota: Para suporte assíncrono real, use AsyncBulkClient em vez disso. + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicializa o cliente de lote síncrono. + +**Argumentos:** + +`url`: URL base para a API TrustGraph (HTTP/HTTPS serão convertidos para WS/WSS) +`timeout`: Tempo limite do WebSocket em segundos +`token`: Token de autorização opcional para autenticação + +### `close(self) -> None` + +Fecha as conexões + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Exporta em lote os embeddings de documentos de um fluxo. + +Baixa eficientemente todos os embeddings de fragmentos de documentos via streaming WebSocket. + +**Argumentos:** + +`flow`: Identificador do fluxo +`**kwargs`: Parâmetros adicionais (reservados para uso futuro) + +**Retorna:** Iterator[Dict[str, Any]]: Fluxo de dicionários de embedding + +**Exemplo:** + +```python +bulk = api.bulk() + +# Export and process document embeddings +for embedding in bulk.export_document_embeddings(flow="default"): + chunk_id = embedding.get("chunk_id") + vector = embedding.get("embedding") + print(f"{chunk_id}: {len(vector)} dimensions") +``` + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Exportação em massa de contextos de entidades de um fluxo. + +Faz o download de todas as informações do contexto da entidade de forma eficiente via streaming WebSocket. + +**Argumentos:** + +`flow`: Identificador do fluxo +`**kwargs`: Parâmetros adicionais (reservados para uso futuro) + +**Retorna:** Iterator[Dict[str, Any]]: Fluxo de dicionários de contexto + +**Exemplo:** + +```python +bulk = api.bulk() + +# Export and process entity contexts +for context in bulk.export_entity_contexts(flow="default"): + entity = context.get("entity") + text = context.get("context") + print(f"{entity}: {text[:100]}...") +``` + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Exportação em massa de representações gráficas (embeddings) de um fluxo. + +Faz o download de todas as representações gráficas de entidades de forma eficiente via streaming WebSocket. + +**Argumentos:** + +`flow`: Identificador do fluxo +`**kwargs`: Parâmetros adicionais (reservados para uso futuro) + +**Retorna:** Iterator[Dict[str, Any]]: Fluxo de dicionários de representações. + +**Exemplo:** + +```python +bulk = api.bulk() + +# Export and process embeddings +for embedding in bulk.export_graph_embeddings(flow="default"): + entity = embedding.get("entity") + vector = embedding.get("embedding") + print(f"{entity}: {len(vector)} dimensions") +``` + +### `export_triples(self, flow: str, **kwargs: Any) -> Iterator[trustgraph.api.types.Triple]` + +Exportação em massa de triplas RDF de um fluxo. + +Faz o download de todas as triplas de forma eficiente via streaming WebSocket. + +**Argumentos:** + +`flow`: Identificador do fluxo +`**kwargs`: Parâmetros adicionais (reservados para uso futuro) + +**Retorna:** Iterator[Triple]: Fluxo de objetos Triple + +**Exemplo:** + +```python +bulk = api.bulk() + +# Export and process triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +### `import_document_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importação em massa de embeddings de documentos em um fluxo. + +Carrega eficientemente embeddings de fragmentos de documentos via streaming WebSocket +para uso em consultas RAG de documentos. + +**Argumentos:** + +`flow`: Identificador do fluxo +`embeddings`: Iterador que retorna dicionários de embedding +`**kwargs`: Parâmetros adicionais (reservados para uso futuro) + +**Exemplo:** + +```python +bulk = api.bulk() + +# Generate document embeddings to import +def doc_embedding_generator(): + yield {"chunk_id": "doc1/p0/c0", "embedding": [0.1, 0.2, ...]} + yield {"chunk_id": "doc1/p0/c1", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_document_embeddings( + flow="default", + embeddings=doc_embedding_generator() +) +``` + +### `import_entity_contexts(self, flow: str, contexts: Iterator[Dict[str, Any]], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +Importação em massa de contextos de entidades em um fluxo. + +Carrega eficientemente informações de contexto de entidade por meio de streaming WebSocket. +Os contextos de entidade fornecem contexto textual adicional sobre as entidades do grafo +para melhorar o desempenho do RAG. + +**Argumentos:** + +`flow`: Identificador do fluxo +`contexts`: Iterador que retorna dicionários de contexto +`metadata`: Dicionário de metadados com id, metadados, usuário, coleção +`batch_size`: Número de contextos por lote (padrão: 100) +`**kwargs`: Parâmetros adicionais (reservados para uso futuro) + +**Exemplo:** + +```python +bulk = api.bulk() + +# Generate entity contexts to import +def context_generator(): + yield {"entity": {"v": "entity1", "e": True}, "context": "Description..."} + yield {"entity": {"v": "entity2", "e": True}, "context": "Description..."} + # ... more contexts + +bulk.import_entity_contexts( + flow="default", + contexts=context_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + +### `import_graph_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importação em massa de representações gráficas em um fluxo. + +Carrega de forma eficiente as representações de entidades gráficas via streaming WebSocket. + +**Argumentos:** + +`flow`: Identificador do fluxo +`embeddings`: Iterador que retorna dicionários de representações +`**kwargs`: Parâmetros adicionais (reservados para uso futuro) + +**Exemplo:** + +```python +bulk = api.bulk() + +# Generate embeddings to import +def embedding_generator(): + yield {"entity": "entity1", "embedding": [0.1, 0.2, ...]} + yield {"entity": "entity2", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_graph_embeddings( + flow="default", + embeddings=embedding_generator() +) +``` + +### `import_rows(self, flow: str, rows: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importação em massa de linhas estruturadas em um fluxo. + +Carrega eficientemente linhas de dados estruturados via streaming WebSocket +para uso em consultas GraphQL. + +**Argumentos:** + +`flow`: Identificador do fluxo +`rows`: Iterador que retorna dicionários de linhas +`**kwargs`: Parâmetros adicionais (reservados para uso futuro) + +**Exemplo:** + +```python +bulk = api.bulk() + +# Generate rows to import +def row_generator(): + yield {"id": "row1", "name": "Row 1", "value": 100} + yield {"id": "row2", "name": "Row 2", "value": 200} + # ... more rows + +bulk.import_rows( + flow="default", + rows=row_generator() +) +``` + +### `import_triples(self, flow: str, triples: Iterator[trustgraph.api.types.Triple], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +Importação em massa de triplas RDF em um fluxo. + +Carrega eficientemente um grande número de triplas via streaming WebSocket. + +**Argumentos:** + +`flow`: Identificador do fluxo +`triples`: Iterador que retorna objetos Triple +`metadata`: Dicionário de metadados com id, metadados, usuário, coleção +`batch_size`: Número de triplas por lote (padrão 100) +`**kwargs`: Parâmetros adicionais (reservados para uso futuro) + +**Exemplo:** + +```python +from trustgraph.api import Triple + +bulk = api.bulk() + +# Generate triples to import +def triple_generator(): + yield Triple(s="subj1", p="pred", o="obj1") + yield Triple(s="subj2", p="pred", o="obj2") + # ... more triples + +# Import triples +bulk.import_triples( + flow="default", + triples=triple_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + + +-- + +## `AsyncBulkClient` + +```python +from trustgraph.api import AsyncBulkClient +``` + +Cliente para operações em lote assíncronas. + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + +### `aclose(self) -> None` + +Fechar conexões + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +Exportação em lote de incorporações de documentos via WebSocket. + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +Exportação em lote de contextos de entidades via WebSocket. + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +Exportação em lote de incorporações de grafos via WebSocket. + +### `export_triples(self, flow: str, **kwargs: Any) -> AsyncIterator[trustgraph.api.types.Triple]` + +Exportação em lote de triplas via WebSocket. + +### `import_document_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importação em lote de incorporações de documentos via WebSocket. + +### `import_entity_contexts(self, flow: str, contexts: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importação em lote de contextos de entidades via WebSocket. + +### `import_graph_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importação em lote de incorporações de grafos via WebSocket. + +### `import_rows(self, flow: str, rows: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Importação em lote de linhas via WebSocket. + +### `import_triples(self, flow: str, triples: AsyncIterator[trustgraph.api.types.Triple], **kwargs: Any) -> None` + +Importação em lote de triplas via WebSocket. + + +-- + +## `Metrics` + +```python +from trustgraph.api import Metrics +``` + +Cliente de métricas síncronas + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + +### `get(self) -> str` + +Obtenha as métricas do Prometheus como texto + + +-- + +## `AsyncMetrics` + +```python +from trustgraph.api import AsyncMetrics +``` + +Cliente de métricas assíncronas + +### Métodos + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + +### `aclose(self) -> None` + +Fechar conexões + +### `get(self) -> str` + +Obter métricas do Prometheus como texto + + +-- + +## `ExplainabilityClient` + +```python +from trustgraph.api import ExplainabilityClient +``` + +Cliente para buscar entidades de explicabilidade com tratamento de consistência eventual. + +Utiliza detecção de quiescência: buscar, esperar, buscar novamente, comparar. +Se os resultados forem os mesmos, os dados são estáveis. + +### Métodos + +### `__init__(self, flow_instance, retry_delay: float = 0.2, max_retries: int = 10)` + +Inicializa o cliente de explicabilidade. + +**Argumentos:** + +`flow_instance`: Uma instância de SocketFlowInstance para consultar triplas. +`retry_delay`: Atraso entre as tentativas (padrão: 0,2). +`max_retries`: Número máximo de tentativas (padrão: 10). + +### `detect_session_type(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> str` + +Detecta se uma sessão é do tipo GraphRAG ou Agent. + +**Argumentos:** + +`session_uri`: O URI da sessão/pergunta. +`graph`: Grafo nomeado. +`user`: Identificador de usuário/espaço de chaves. +`collection`: Identificador de coleção. + +**Retorna:** "graphrag" ou "agent". + +### `fetch_agent_trace(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Busca o rastreamento completo do Agent a partir de um URI de sessão. + +Segue a cadeia de rastreabilidade: Pergunta -> Análise(s) -> Conclusão. + +**Argumentos:** + +`session_uri`: O URI da sessão/pergunta do agente. +`graph`: Grafo nomeado (padrão: urn:graph:retrieval). +`user`: Identificador de usuário/espaço de chaves. +`collection`: Identificador de coleção. +`api`: Instância da API TrustGraph para acesso ao bibliotecário (opcional). +`max_content`: Comprimento máximo do conteúdo para a conclusão. + +**Retorna:** Dicionário com a pergunta, iterações (lista de Análises) e entidades de conclusão. + +### `fetch_docrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Busca o rastreamento completo do DocumentRAG a partir de um URI de pergunta. + +Segue a cadeia de rastreabilidade: + Pergunta -> Fundamentação -> Exploração -> Síntese. + +**Argumentos:** + +`question_uri`: O URI da entidade de pergunta. +`graph`: Grafo nomeado (padrão: urn:graph:retrieval). +`user`: Identificador de usuário/espaço de chaves. +`collection`: Identificador de coleção. +`api`: Instância da API TrustGraph para acesso ao bibliotecário (opcional). +`max_content`: Comprimento máximo do conteúdo para a síntese. + +**Retorna:** Dicionário com a pergunta, fundamentação, exploração e entidades de síntese. + +### `fetch_document_content(self, document_uri: str, api: Any, user: str | None = None, max_content: int = 10000) -> str` + +Busca o conteúdo do bibliotecário por URI de documento. + +**Argumentos:** + +`document_uri`: O URI do documento no bibliotecário. +`api`: Instância da API TrustGraph para acesso ao bibliotecário. +`user`: Identificador de usuário para o bibliotecário. +`max_content`: Comprimento máximo do conteúdo a ser retornado. + +**Retorna:** O conteúdo do documento como uma string. + +### `fetch_edge_selection(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.EdgeSelection | None` + +Busca uma entidade de seleção de arestas (usada pelo Focus). + +**Argumentos:** + +`uri`: O URI da seleção de arestas. +`graph`: Grafo nomeado a ser consultado. +`user`: Identificador de usuário/espaço de chaves. +`collection`: Identificador de coleção. + +**Retorna:** EdgeSelection ou None se não for encontrado. + +### `fetch_entity(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.ExplainEntity | None` + +Buscar uma entidade de explicabilidade por URI com tratamento de consistência eventual. + +Usa detecção de quiescência: +1. Buscar triplas para o URI +2. Se não houver resultados, tentar novamente +3. Se houver resultados, esperar e buscar novamente +4. Se os resultados forem os mesmos, os dados são estáveis - analisar e retornar +5. Se os resultados forem diferentes, os dados ainda estão sendo gravados - tentar novamente + +**Argumentos:** + +`uri`: O URI da entidade a ser buscada +`graph`: Grafo nomeado a ser consultado (por exemplo, "urn:graph:retrieval") +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção + +**Retorna:** Subclasse ExplainEntity ou None se não for encontrada + +### `fetch_focus_with_edges(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.Focus | None` + +Buscar uma entidade Focus e todas as suas seleções de arestas. + +**Argumentos:** + +`uri`: O URI da entidade Focus +`graph`: Grafo nomeado a ser consultado +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção + +**Retorna:** Focus com edge_selections preenchidos, ou None + +### `fetch_graphrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Buscar o rastreamento completo do GraphRAG a partir de um URI de pergunta. + +Segue a cadeia de rastreabilidade: Pergunta -> Grounding -> Exploração -> Focus -> Síntese + +**Argumentos:** + +`question_uri`: O URI da entidade de pergunta +`graph`: Grafo nomeado (padrão: urn:graph:retrieval) +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção +`api`: Instância da API TrustGraph para acesso de bibliotecário (opcional) +`max_content`: Comprimento máximo do conteúdo para síntese + +**Retorna:** Dicionário com as entidades de pergunta, grounding, exploração, focus e síntese + +### `list_sessions(self, graph: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 50) -> List[trustgraph.api.explainability.Question]` + +Listar todas as sessões de explicabilidade (perguntas) em uma coleção. + +**Argumentos:** + +`graph`: Grafo nomeado (padrão: urn:graph:retrieval) +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção +`limit`: Número máximo de sessões a serem retornadas + +**Retorna:** Lista de entidades de Pergunta ordenadas por timestamp (mais recentes primeiro) + +### `resolve_edge_labels(self, edge: Dict[str, str], user: str | None = None, collection: str | None = None) -> Tuple[str, str, str]` + +Resolver rótulos para todos os componentes de uma tripla de aresta. + +**Argumentos:** + +`edge`: Dicionário com chaves "s", "p" e "o" +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção + +**Retorna:** Tupla de (s_label, p_label, o_label) + +### `resolve_label(self, uri: str, user: str | None = None, collection: str | None = None) -> str` + +Resolver rdfs:label para um URI, com cache. + +**Argumentos:** + +`uri`: O URI para o qual obter o rótulo +`user`: Identificador de usuário/espaço de chaves +`collection`: Identificador de coleção + +**Retorna:** O rótulo se encontrado, caso contrário, o próprio URI + + +-- + +## `ExplainEntity` + +```python +from trustgraph.api import ExplainEntity +``` + +Classe base para entidades de explicabilidade. + +**Campos:** + +`uri`: +`entity_type`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '') -> None` + +Inicialize self. Consulte help(type(self)) para a assinatura correta. + + +-- + +## `Question` + +```python +from trustgraph.api import Question +``` + +Entidade de pergunta - a consulta do usuário que iniciou a sessão. + +**Campos:** + +`uri`: +`entity_type`: +`query`: +`timestamp`: +`question_type`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', query: str = '', timestamp: str = '', question_type: str = '') -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `Exploration` + +```python +from trustgraph.api import Exploration +``` + +Entidade de exploração - arestas/pedaços recuperados do repositório de conhecimento. + +**Campos:** + +`uri`: +`entity_type`: +`edge_count`: +`chunk_count`: +`entities`: typing.List[str] + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', edge_count: int = 0, chunk_count: int = 0, entities: List[str] = ) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `Focus` + +```python +from trustgraph.api import Focus +``` + +Entidade de foco - arestas selecionadas com raciocínio LLM (apenas GraphRAG). + +**Campos:** + +`uri`: +`entity_type`: +`selected_edge_uris`: typing.List[str] +`edge_selections`: typing.List[trustgraph.api.explainability.EdgeSelection] + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', selected_edge_uris: List[str] = , edge_selections: List[trustgraph.api.explainability.EdgeSelection] = ) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `Synthesis` + +```python +from trustgraph.api import Synthesis +``` + +Entidade de síntese - a resposta final. + +**Campos:** + +`uri`: +`entity_type`: +`document`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +Inicialize self. Consulte help(type(self)) para a assinatura correta. + + +-- + +## `Analysis` + +```python +from trustgraph.api import Analysis +``` + +Entidade de análise - um ciclo de pensar/agir/observar (apenas para o Agente). + +**Campos:** + +`uri`: +`entity_type`: +`action`: +`arguments`: +`thought`: +`observation`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', action: str = '', arguments: str = '', thought: str = '', observation: str = '') -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `Conclusion` + +```python +from trustgraph.api import Conclusion +``` + +Conclusão da entidade - resposta final (Agente apenas). + +**Campos:** + +`uri`: +`entity_type`: +`document`: + +### Métodos + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `EdgeSelection` + +```python +from trustgraph.api import EdgeSelection +``` + +Uma aresta selecionada com raciocínio da etapa GraphRAG Focus. + +**Campos:** + +`uri`: +`edge`: typing.Dict[str, str] | None +`reasoning`: + +### Métodos + +### `__init__(self, uri: str, edge: Dict[str, str] | None = None, reasoning: str = '') -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +### `wire_triples_to_tuples(wire_triples: List[Dict[str, Any]]) -> List[Tuple[str, str, Any]]` + +Converta triplas no formato de fio em tuplas (s, p, o). + + +-- + +### `extract_term_value(term: Dict[str, Any]) -> Any` + +Extraia o valor de um dicionário Term no formato de fio. + + +-- + +## `Triple` + +```python +from trustgraph.api import Triple +``` + +Tripla RDF que representa uma declaração de um grafo de conhecimento. + +**Campos:** + +`s`: +`p`: +`o`: + +### Métodos + +### `__init__(self, s: str, p: str, o: str) -> None` + +Inicializa self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `Uri` + +```python +from trustgraph.api import Uri +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +Crie um novo objeto string a partir do objeto fornecido. Se encoding ou +errors forem especificados, então o objeto deve expor um buffer de dados +que será decodificado usando a codificação e o manipulador de erros fornecidos. +Caso contrário, retorna o resultado de object.__str__() (se definido) +ou repr(object). +encoding tem como padrão 'utf-8'. +errors tem como padrão 'strict'. + +### Métodos + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `Literal` + +```python +from trustgraph.api import Literal +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +Crie um novo objeto string a partir do objeto fornecido. Se encoding ou +errors forem especificados, então o objeto deve expor um buffer de dados +que será decodificado usando a codificação e o manipulador de erros fornecidos. +Caso contrário, retorna o resultado de object.__str__() (se definido) +ou repr(object). +encoding tem como padrão 'utf-8'. +errors tem como padrão 'strict'. + +### Métodos + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `ConfigKey` + +```python +from trustgraph.api import ConfigKey +``` + +Identificador da chave de configuração. + +**Campos:** + +`type`: +`key`: + +### Métodos + +### `__init__(self, type: str, key: str) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `ConfigValue` + +```python +from trustgraph.api import ConfigValue +``` + +Par de chave-valor de configuração. + +**Campos:** + +`type`: +`key`: +`value`: + +### Métodos + +### `__init__(self, type: str, key: str, value: str) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `DocumentMetadata` + +```python +from trustgraph.api import DocumentMetadata +``` + +Metadados para um documento na biblioteca. + +**Atributos:** + +`parent_id: Parent document ID for child documents (empty for top`: level docs) + +**Campos:** + +`id`: +`time`: +`kind`: +`title`: +`comments`: +`metadata`: typing.List[trustgraph.api.types.Triple] +`user`: +`tags`: typing.List[str] +`parent_id`: +`document_type`: + +### Métodos + +### `__init__(self, id: str, time: datetime.datetime, kind: str, title: str, comments: str, metadata: List[trustgraph.api.types.Triple], user: str, tags: List[str], parent_id: str = '', document_type: str = 'source') -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `ProcessingMetadata` + +```python +from trustgraph.api import ProcessingMetadata +``` + +Metadados para um processo de documento ativo. + +**Campos:** + +`id`: +`document_id`: +`time`: +`flow`: +`user`: +`collection`: +`tags`: typing.List[str] + +### Métodos + +### `__init__(self, id: str, document_id: str, time: datetime.datetime, flow: str, user: str, collection: str, tags: List[str]) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `CollectionMetadata` + +```python +from trustgraph.api import CollectionMetadata +``` + +Metadados para uma coleção de dados. + +As coleções fornecem agrupamento lógico e isolamento para documentos e +dados de grafo de conhecimento. + +**Atributos:** + +`name: Human`: nome da coleção legível + +**Campos:** + +`user`: +`collection`: +`name`: +`description`: +`tags`: typing.List[str] + +### Métodos + +### `__init__(self, user: str, collection: str, name: str, description: str, tags: List[str]) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `StreamingChunk` + +```python +from trustgraph.api import StreamingChunk +``` + +Classe base para fragmentos de resposta de streaming. + +Usado para operações de streaming baseadas em WebSocket, onde as respostas são entregues +incrementalmente à medida que são geradas. + +**Campos:** + +`content`: +`end_of_message`: + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False) -> None` + +Inicializa self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `AgentThought` + +```python +from trustgraph.api import AgentThought +``` + +Trecho de raciocínio/processo de pensamento do agente. + +Representa o raciocínio interno ou as etapas de planejamento do agente durante a execução. +Esses trechos mostram como o agente está pensando sobre o problema. + +**Campos:** + +`content`: +`end_of_message`: +`chunk_type`: + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'thought') -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `AgentObservation` + +```python +from trustgraph.api import AgentObservation +``` + +Trecho de observação da execução da ferramenta do agente. + +Representa o resultado ou a observação da execução de uma ferramenta ou ação. +Esses trechos mostram o que o agente aprendeu ao usar ferramentas. + +**Campos:** + +`content`: +`end_of_message`: +`chunk_type`: + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'observation') -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `AgentAnswer` + +```python +from trustgraph.api import AgentAnswer +``` + +Trecho da resposta final do agente. + +Representa a resposta final do agente ao pedido do usuário após concluir +seu raciocínio e uso de ferramentas. + +**Atributos:** + +`chunk_type: Always "final`: answer" + +**Campos:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_dialog`: + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'final-answer', end_of_dialog: bool = False) -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `RAGChunk` + +```python +from trustgraph.api import RAGChunk +``` + +RAG (Geração Aumentada por Recuperação) em blocos de fluxo. + +Usado para transmitir respostas de RAG de grafos, RAG de documentos, preenchimento de texto, +e outros serviços generativos. + +**Campos:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_stream`: +`error`: typing.Dict[str, str] | None + +### Métodos + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'rag', end_of_stream: bool = False, error: Dict[str, str] | None = None) -> None` + +Inicializa self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `ProvenanceEvent` + +```python +from trustgraph.api import ProvenanceEvent +``` + +Evento de rastreabilidade para explicabilidade. + +Emitido durante as consultas GraphRAG quando o modo de explicabilidade está habilitado. +Cada evento representa um nó de rastreabilidade criado durante o processamento da consulta. + +**Campos:** + +`explain_id`: +`explain_graph`: +`event_type`: + +### Métodos + +### `__init__(self, explain_id: str, explain_graph: str = '', event_type: str = '') -> None` + +Inicialize self. Consulte help(type(self)) para obter a assinatura correta. + + +-- + +## `ProtocolException` + +```python +from trustgraph.api import ProtocolException +``` + +Disparado quando ocorrem erros no protocolo WebSocket. + + +-- + +## `TrustGraphException` + +```python +from trustgraph.api import TrustGraphException +``` + +Classe base para todos os erros do serviço TrustGraph. + + +-- + +## `AgentError` + +```python +from trustgraph.api import AgentError +``` + +Erro no serviço do agente + + +-- + +## `ConfigError` + +```python +from trustgraph.api import ConfigError +``` + +Erro no serviço de configuração. + + +-- + +## `DocumentRagError` + +```python +from trustgraph.api import DocumentRagError +``` + +Erro de recuperação de documentos RAG. + + +-- + +## `FlowError` + +```python +from trustgraph.api import FlowError +``` + +Erro de gerenciamento de fluxo + + +-- + +## `GatewayError` + +```python +from trustgraph.api import GatewayError +``` + +Erro no API Gateway + + +-- + +## `GraphRagError` + +```python +from trustgraph.api import GraphRagError +``` + +Erro de recuperação do Graph RAG. + + +-- + +## `LLMError` + +```python +from trustgraph.api import LLMError +``` + +Erro no serviço de LLM. + + +-- + +## `LoadError` + +```python +from trustgraph.api import LoadError +``` + +Erro ao carregar dados + + +-- + +## `LookupError` + +```python +from trustgraph.api import LookupError +``` + +Erro de pesquisa/busca + + +-- + +## `NLPQueryError` + +```python +from trustgraph.api import NLPQueryError +``` + +Erro no serviço de consulta de processamento de linguagem natural. + + +-- + +## `RowsQueryError` + +```python +from trustgraph.api import RowsQueryError +``` + +Erro no serviço de consulta de linhas. + + +-- + +## `RequestError` + +```python +from trustgraph.api import RequestError +``` + +Erro no processamento da requisição. + + +-- + +## `StructuredQueryError` + +```python +from trustgraph.api import StructuredQueryError +``` + +Erro no serviço de consulta estruturada. + + +-- + +## `UnexpectedError` + +```python +from trustgraph.api import UnexpectedError +``` + +Erro inesperado/desconhecido + + +-- + +## `ApplicationException` + +```python +from trustgraph.api import ApplicationException +``` + +Classe base para todos os erros do serviço TrustGraph. + + +-- + diff --git a/docs/python-api.sw.md b/docs/python-api.sw.md new file mode 100644 index 00000000..923b443d --- /dev/null +++ b/docs/python-api.sw.md @@ -0,0 +1,4071 @@ +# Marejeleo ya API ya Python ya TrustGraph + +## Ufungaji + +```bash +pip install trustgraph +``` + +## Kuanza Haraka + +Madarasa na aina zote zinaingizwa kutoka kwenye kifurushi cha `trustgraph.api`: + +```python +from trustgraph.api import Api, Triple, ConfigKey + +# Create API client +api = Api(url="http://localhost:8088/") + +# Get a flow instance +flow = api.flow().id("default") + +# Execute a graph RAG query +response = flow.graph_rag( + query="What are the main topics?", + user="trustgraph", + collection="default" +) +``` + +## Jina la Yaliyomo + +### Msingi + +[Api](#api) + +### Wateja wa Flow + +[Flow](#flow) +[FlowInstance](#flowinstance) +[AsyncFlow](#asyncflow) +[AsyncFlowInstance](#asyncflowinstance) + +### Wateja wa WebSocket + +[SocketClient](#socketclient) +[SocketFlowInstance](#socketflowinstance) +[AsyncSocketClient](#asyncsocketclient) +[AsyncSocketFlowInstance](#asyncsocketflowinstance) + +### Operesheni za Kiasi + +[BulkClient](#bulkclient) +[AsyncBulkClient](#asyncbulkclient) + +### Vipimo + +[Metrics](#metrics) +[AsyncMetrics](#asyncmetrics) + +### Aina za Data + +[Triple](#triple) +[ConfigKey](#configkey) +[ConfigValue](#configvalue) +[DocumentMetadata](#documentmetadata) +[ProcessingMetadata](#processingmetadata) +[CollectionMetadata](#collectionmetadata) +[StreamingChunk](#streamingchunk) +[AgentThought](#agentthought) +[AgentObservation](#agentobservation) +[AgentAnswer](#agentanswer) +[RAGChunk](#ragchunk) + +### Vizuizi + +[ProtocolException](#protocolexception) +[TrustGraphException](#trustgraphexception) +[AgentError](#agenterror) +[ConfigError](#configerror) +[DocumentRagError](#documentragerror) +[FlowError](#flowerror) +[GatewayError](#gatewayerror) +[GraphRagError](#graphragerror) +[LLMError](#llmerror) +[LoadError](#loaderror) +[LookupError](#lookuperror) +[NLPQueryError](#nlpqueryerror) +[RowsQueryError](#rowsqueryerror) +[RequestError](#requesterror) +[StructuredQueryError](#structuredqueryerror) +[UnexpectedError](#unexpectederror) +[ApplicationException](#applicationexception) + +-- + +## `Api` + +```python +from trustgraph.api import Api +``` + +Mteja mkuu wa API ya TrustGraph kwa operesheni za synchronous na asynchronous. + +Darasa hili hutoa ufikiaji kwa huduma zote za TrustGraph, pamoja na usimamizi wa mtiririko, +operesheni za grafu ya maarifa, usindikaji wa hati, maswali ya RAG, na zaidi. Inasaidia +mifumo ya mawasiliano ya msingi wa REST na WebSocket. + +Mteja unaweza kutumika kama meneja wa muktadha kwa usafi wa kiotomatiki wa rasilimali: + ```python + with Api(url="http://localhost:8088/") as api: + result = api.flow().id("default").graph_rag(query="test") + ``` + +### Mbinu + +### `__aenter__(self)` + +Ingia katika meneja wa muktadha wa asinkroni. + +### `__aexit__(self, *args)` + +Ondoka katika meneja wa muktadha wa asinkroni na ufungue miunganisho. + +### `__enter__(self)` + +Ingia katika meneja wa muktadha wa sinkroni. + +### `__exit__(self, *args)` + +Ondoka katika meneja wa muktadha wa sinkroni na ufungue miunganisho. + +### `__init__(self, url='http://localhost:8088/', timeout=60, token: str | None = None)` + +Anzisha mteja wa API ya TrustGraph. + +**Vigezo:** + +`url`: URL ya msingi kwa API ya TrustGraph (kiwango chachilia: "http://localhost:8088/"") +`timeout`: Muda wa kikao wa ombi katika sekunde (kiwango chachilia: 60) +`token`: Tokeni ya kuhudhuria ya hiari kwa uthibitishaji + +**Mfano:** + +```python +# Local development +api = Api() + +# Production with authentication +api = Api( + url="https://trustgraph.example.com/", + timeout=120, + token="your-api-token" +) +``` + +### `aclose(self)` + +Funga miunganisho yote ya mteja isiyo ya kawaida. + +Njia hii inafunga miunganisho ya WebSocket isiyo ya kawaida, operesheni kubwa, na miunganisho ya mtiririko. +Inaitwa kiotomatiki wakati wa kutoka katika meneja wa muktadha usio wa kawaida. + +**Mfano:** + +```python +api = Api() +async_socket = api.async_socket() +# ... use async_socket +await api.aclose() # Clean up connections + +# Or use async context manager (automatic cleanup) +async with Api() as api: + async_socket = api.async_socket() + # ... use async_socket +# Automatically closed +``` + +### `async_bulk(self)` + +Pata mteja wa operesheni za wingi zisizo za moja kwa moja. + +Hutoa operesheni za uagizaji/uangamizi za wingi kwa mtindo wa async/await kupitia WebSocket +kwa ajili ya usimamizi bora wa data kubwa. + +**Inarudisha:** AsyncBulkClient: Mteja wa operesheni za wingi zisizo za moja kwa moja. + +**Mfano:** + +```python +async_bulk = api.async_bulk() + +# Export triples asynchronously +async for triple in async_bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import with async generator +async def triple_gen(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +await async_bulk.import_triples( + flow="default", + triples=triple_gen() +) +``` + +### `async_flow(self)` + +Pata mteja wa mtiririko (flow) unaotumia REST na unaoweza kufanya kazi bila kusubiri. + +Hutoa ufikiaji wa operesheni za mtiririko kwa mtindo wa async/await. Hii inapendelewa +kwa programu na mifumo ya Python inayotumia async (FastAPI, aiohttp, n.k.). + +**Inarudisha:** AsyncFlow: Mteja wa mtiririko (flow) usiofanya kazi bila kusubiri. + +**Mfano:** + +```python +async_flow = api.async_flow() + +# List flows +flow_ids = await async_flow.list() + +# Execute operations +instance = async_flow.id("default") +result = await instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `async_metrics(self)` + +Pata mteja wa metriki zisizo za moja kwa moja. + +Hutoa ufikiaji wa mtindo wa async/await kwa metriki za Prometheus. + +**Inarudisha:** AsyncMetrics: Mteja wa metriki zisizo za moja kwa moja. + +**Mfano:** + +```python +async_metrics = api.async_metrics() +prometheus_text = await async_metrics.get() +print(prometheus_text) +``` + +### `async_socket(self)` + +Pata mteja wa WebSocket usio na utaratibu kwa operesheni za utiririshaji. + +Hutoa ufikiaji wa WebSocket wa aina ya async/await pamoja na usaidizi wa utiririshaji. +Hii ndiyo njia inayopendekezwa kwa utiririshaji usio na utaratibu katika Python. + +**Inarudisha:** AsyncSocketClient: Mteja wa WebSocket usio na utaratibu. + +**Mfano:** + +```python +async_socket = api.async_socket() +flow = async_socket.flow("default") + +# Stream agent responses +async for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + +### `bulk(self)` + +Pata mteja wa shughuli za wingi za moja kwa moja kwa ajili ya uagizaji/utoaji. + +Shughuli za wingi huruhusu uhamishaji wa ufanisi wa data kubwa kupitia muunganisho wa WebSocket, +ikiwa ni pamoja na vitu vitatu, maandamano, muktadha wa vitu, na vitu. + +**Inarudisha:** BulkClient: Mteja wa shughuli za wingi za moja kwa moja. + +**Mfano:** + +```python +bulk = api.bulk() + +# Export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import triples +def triple_generator(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +bulk.import_triples(flow="default", triples=triple_generator()) +``` + +### `close(self)` + +Funga miunganisho yote ya mteja ya wakati huo. + +Njia hii inafunga miunganisho ya WebSocket na miunganisho ya operesheni kubwa. +Inaitwa kiotomatiki wakati wa kutoka katika meneja wa muktadha. + +**Mfano:** + +```python +api = Api() +socket = api.socket() +# ... use socket +api.close() # Clean up connections + +# Or use context manager (automatic cleanup) +with Api() as api: + socket = api.socket() + # ... use socket +# Automatically closed +``` + +### `collection(self)` + +Pata mteja wa Collection kwa ajili ya kusimamia makusanyo ya data. + +Makusanyo huandaa hati na data ya mfumo wa maarifa katika +vikundi vya mantiki kwa ajili ya kutenganisha na udhibiti wa ufikiaji. + +**Inarudisha:** Collection: Mteja wa usimamizi wa Collection + +**Mfano:** + +```python +collection = api.collection() + +# List collections +colls = collection.list_collections(user="trustgraph") + +# Update collection metadata +collection.update_collection( + user="trustgraph", + collection="default", + name="Default Collection", + description="Main data collection" +) +``` + +### `config(self)` + +Pata mteja wa Config kwa ajili ya kusimamia mipangilio. + +**Inarudisha:** Config: Mteja wa usimamizi wa mipangilio. + +**Mfano:** + +```python +config = api.config() + +# Get configuration values +values = config.get([ConfigKey(type="llm", key="model")]) + +# Set configuration +config.put([ConfigValue(type="llm", key="model", value="gpt-4")]) +``` + +### `flow(self)` + +Pata programu (client) ya Flow kwa ajili ya kusimamia na kuingiliana na michakato. + +Michakato (Flows) ni vitengo vikuu vya utekelezaji katika TrustGraph, ikitoa ufikiaji kwa +huduma kama vile wakala, maswali ya RAG, maandamano, na usindikaji wa nyaraka. + +**Inarudisha:** Flow: Programu ya usimamizi wa Flow. + +**Mfano:** + +```python +flow_client = api.flow() + +# List available blueprints +blueprints = flow_client.list_blueprints() + +# Get a specific flow instance +flow_instance = flow_client.id("default") +response = flow_instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `knowledge(self)` + +Pata mteja wa Knowledge kwa ajili ya kusimamia msingi wa grafu ya maarifa. + +**Inarudisha:** Mteja wa usimamizi wa grafu ya maarifa: Knowledge + +**Mfano:** + +```python +knowledge = api.knowledge() + +# List available KG cores +cores = knowledge.list_kg_cores(user="trustgraph") + +# Load a KG core +knowledge.load_kg_core(id="core-123", user="trustgraph") +``` + +### `library(self)` + +Pata mteja wa Maktaba kwa usimamizi wa nyaraka. + +Maktaba hutoa uhifadhi wa nyaraka, usimamizi wa metadata, na +uratibu wa mtiririko wa kazi. + +**Inarudisha:** Library: Mteja wa usimamizi wa maktaba ya nyaraka. + +**Mfano:** + +```python +library = api.library() + +# Add a document +library.add_document( + document=b"Document content", + id="doc-123", + metadata=[], + user="trustgraph", + title="My Document", + comments="Test document" +) + +# List documents +docs = library.get_documents(user="trustgraph") +``` + +### `metrics(self)` + +Pata mteja wa metriki wa moja kwa moja kwa ajili ya ufuatiliaji. + +Hupata metriki zilizofunganishwa kwa muundo wa Prometheus kutoka kwa huduma ya TrustGraph +kwa ajili ya ufuatiliaji na uwezeshaji. + +**Inarudisha:** Metri: Mteja wa metriki wa moja kwa moja + +**Mfano:** + +```python +metrics = api.metrics() +prometheus_text = metrics.get() +print(prometheus_text) +``` + +### `request(self, path, request)` + +Fanya ombi la API ya REST ya kiwango cha chini. + +Njia hii hutumika hasa kwa matumizi ya ndani, lakini inaweza kutumika kwa ufikiaji wa moja kwa moja +wa API wakati inahitajika. + +**Vigezo:** + +`path`: Njia ya mwisho ya API (kulingana na URL ya msingi) +`request`: Takwimu ya ombi kama kamusi + +**Inarudisha:** dict: Kijisimu cha majibu + +**Inatirisha:** + +`ProtocolException`: Ikiwa hali ya majibu si 200 au majibu hayana umbizo la JSON +`ApplicationException`: Ikiwa majibu yana kosa + +**Mfano:** + +```python +response = api.request("flow", { + "operation": "list-flows" +}) +``` + +### `socket(self)` + +Pata mteja wa WebSocket wa aina ya moja kwa shughuli za utiririshaji. + +Miunganisho ya WebSocket hutoa utiifu wa data kwa majibu ya muda halisi +kutoka kwa wakala, maswali ya RAG, na kukamilisha maandishi. Njia hii inarudisha +kifungashio cha aina ya moja kilichozunguka itifaki ya WebSocket. + +**Inarudisha:** SocketClient: Mteja wa WebSocket wa aina ya moja. + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `Flow` + +```python +from trustgraph.api import Flow +``` + +Mteja wa usimamizi wa mtiririko kwa operesheni za muundo na mfano wa mtiririko. + +Darasa hili hutoa mbinu za kusimamia muundo wa mtiririko (vipengele) na +mifano ya mtiririko (mitiririko inayoendelea). Vipengele vinafafanua muundo na +vigezo vya mitiririko, wakati mifano inawakilisha mitiririko inayofanya kazi ambayo +inaweza kutekeleza huduma. + +### Mbinu + +### `__init__(self, api)` + +Anzisha mteja wa mtiririko. + +**Majadiliano:** + +`api`: Eneo la awali la Api kwa kutuma ombi. + +### `delete_blueprint(self, blueprint_name)` + +Futa muundo wa mtiririko. + +**Majadiliano:** + +`blueprint_name`: Jina la muundo kufutwa. + +**Mfano:** + +```python +api.flow().delete_blueprint("old-blueprint") +``` + +### `get(self, id)` + +Pata ufafanuzi wa mfano unaoendelea. + +**Vigezo:** + +`id`: Kitambulisho cha mfano. + +**Inarudisha:** dict: Ufafanuzi wa mfano. + +**Mfano:** + +```python +flow_def = api.flow().get("default") +print(flow_def) +``` + +### `get_blueprint(self, blueprint_name)` + +Pata ufafanuzi wa mpango (blueprint) kwa jina. + +**Vigezo:** + +`blueprint_name`: Jina la mpango (blueprint) ambao unataka kupata + +**Inarudisha:** dict: Ufafanuzi wa mpango (blueprint) kama kamusi. + +**Mfano:** + +```python +blueprint = api.flow().get_blueprint("default") +print(blueprint) # Blueprint configuration +``` + +### `id(self, id='default')` + +Pata FlowInstance ili kutekeleza shughuli kwenye mtiririko maalum. + +**Vigezo:** + +`id`: Kitambulisho cha mtiririko (cha kawaida: "default") + +**Inarudisha:** FlowInstance: Mtiririko wa huduma kwa shughuli. + +**Mfano:** + +```python +flow = api.flow().id("my-flow") +response = flow.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `list(self)` + +Orodha ya matukio yote yanayoendelea. + +**Inarudisha:** list[str]: Orodha ya kitambulisho cha matukio. + +**Mfano:** + +```python +flows = api.flow().list() +print(flows) # ['default', 'flow-1', 'flow-2', ...] +``` + +### `list_blueprints(self)` + +Orodha ya mipango yote ya mtiririko inayopatikana. + +**Inarudisha:** list[str]: Orodha ya majina ya mipango + +**Mfano:** + +```python +blueprints = api.flow().list_blueprints() +print(blueprints) # ['default', 'custom-flow', ...] +``` + +### `put_blueprint(self, blueprint_name, definition)` + +Kuunda au kusasisha mpango wa mtiririko. + +**Vigezo:** + +`blueprint_name`: Jina la mpango +`definition`: Kamusi ya ufafanuzi wa mpango + +**Mfano:** + +```python +definition = { + "services": ["text-completion", "graph-rag"], + "parameters": {"model": "gpt-4"} +} +api.flow().put_blueprint("my-blueprint", definition) +``` + +### `request(self, path=None, request=None)` + +Fanya ombi la API katika eneo maalum. + +**Vigezo:** + +`path`: Ongeza ya hiari kwa njia za mwisho za eneo. +`request`: Kamusi ya data ya ombi. + +**Inarudisha:** dict: Kitu kinachojibu. + +**Inayotokea:** + +`RuntimeError`: Ikiwa parameter ya ombi haijatolewa. + +### `start(self, blueprint_name, id, description, parameters=None)` + +Anza eneo jipya kutoka kwa mpango. + +**Vigezo:** + +`blueprint_name`: Jina la mpango ambao utaanzishwa. +`id`: Kitambulisho cha kipekee kwa eneo. +`description`: Maelezo ambayo yanaweza kueleweka. +`parameters`: Vigezo vya hiari. + +**Mfano:** + +```python +api.flow().start( + blueprint_name="default", + id="my-flow", + description="My custom flow", + parameters={"model": "gpt-4"} +) +``` + +### `stop(self, id)` + +Kusimamisha mfumo unaoendelea. + +**Vigezo:** + +`id`: Kitambulisho cha mfumo unaoendelea ili kusimamishwa. + +**Mfano:** + +```python +api.flow().stop("my-flow") +``` + + +-- + +## `FlowInstance` + +```python +from trustgraph.api import FlowInstance +``` + +Mteja wa mfumo (flow) kwa kutekeleza huduma kwenye mfumo maalum. + +Darasa hili hutoa ufikiaji kwa huduma zote za TrustGraph, pamoja na: +Kukamilisha maandishi na uwekaji wa data (embeddings) +Utendaji wa wakala (agent) pamoja na usimamizi wa hali (state) +Ufuatiliaji wa maswali (queries) ya RAG kwa grafu na nyaraka +Utendaji wa grafu ya maarifa (triples, vitu) +Kupakua na kuchakata nyaraka +Ubadilishaji wa lugha ya asili kuwa swali la GraphQL +Uchambuzi wa data iliyopangwa na utambuzi wa muundo (schema) +Utendaji wa zana ya MCP +Ubunifu wa kigezo cha swali (prompt templating) + +Huduma zinapatikana kupitia mfumo unaoendelea (flow instance) unaotambulika na kitambulisho (ID). + +### Mbinu (Methods) + +### `__init__(self, api, id)` + +Anzisha FlowInstance. + +**Majadilisho:** + +`api`: Mteja wa mfumo (flow) wa juu. +`id`: Kitambulisho cha mfumo unaoendelea (flow instance). + +### `agent(self, question, user='trustgraph', state=None, group=None, history=None)` + +Tekeleza utendaji wa wakala (agent) pamoja na uwezo wa kufikiri na kutumia zana. + +Wakala wanaweza kufanya utafakari wa hatua nyingi, kutumia zana, na kudumisha mazungumzo +hali katika mwingiliano. Hii ni toleo la moja kwa moja (synchronous) lisilo na utiririshaji (non-streaming). + +**Majadilisho:** + +`question`: Swali au maagizo ya mtumiaji. +`user`: Kitambulisho cha mtumiaji (default: "trustgraph") +`state`: Kamusi ya hali (state) ya hiari kwa mazungumzo yenye hali. +`group`: Kitambulisho cha kikundi cha hiari kwa muktadha wa watumiaji wengi. +`history`: Historia ya mazungumzo ya hiari kama orodha ya maneno ya kamusi. + +**Inarudisha:** string: Jibu la mwisho la wakala. + +**Mfano:** + +```python +flow = api.flow().id("default") + +# Simple question +answer = flow.agent( + question="What is the capital of France?", + user="trustgraph" +) + +# With conversation history +history = [ + {"role": "user", "content": "Hello"}, + {"role": "assistant", "content": "Hi! How can I help?"} +] +answer = flow.agent( + question="Tell me about Paris", + user="trustgraph", + history=history +) +``` + +### `detect_type(self, sample)` + +Gundua aina ya data ya sampuli ya data iliyohifadhiwa. + +**Vigezo:** + +`sample`: Sampuli ya data kuchanganua (yaliyomo katika maandishi) + +**Inarudisha:** kamusi yenye aina_iliyogunduliwa, uaminifu, na metadata ya hiari + +### `diagnose_data(self, sample, schema_name=None, options=None)` + +Fanya uchunguzi wa pamoja wa data: gundua aina na uundue maelezo. + +**Vigezo:** + +`sample`: Sampuli ya data kuchanganua (yaliyomo katika maandishi) +`schema_name`: Jina la schema ya lengo la hiari kwa uundaji wa maelezo +`options`: Vigezo vya hiari (k.m., kigawanyo kwa CSV) + +**Inarudisha:** kamusi yenye aina_iliyogunduliwa, uaminifu, maelezo, na metadata + +### `document_embeddings_query(self, text, user, collection, limit=10)` + +Tafuta vipande vya hati kwa kutumia utofauti wa maana. + +Inapata vipande vya hati ambavyo yaliyomo katika vipande hivyo yanafanana kwa maana na +maandishi ya ingizo, kwa kutumia uelekezo wa vector. + +**Vigezo:** + +`text`: Maandishi ya swali kwa utafutaji wa maana +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`limit`: Nambari ya juu ya matokeo (ya kawaida: 10) + +**Inarudisha:** kamusi: Matokeo ya swali yenye vipande vyenye kitambulisho cha kipande na alama + +**Mfano:** + +```python +flow = api.flow().id("default") +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "doc1/p0/c0", "score": 0.95}, ...]} +``` + +### `document_rag(self, query, user='trustgraph', collection='default', doc_limit=10)` + +Tekeleza swali la Uzalishaji Ulioboreshwa na Utafiti (RAG) linalotegemea nyaraka. + +RAG ya nyaraka hutumia ufashilia wa vector ili kupata vipande muhimu vya nyaraka, +kisha huunda jibu kwa kutumia LLM (Large Language Model) kwa kutumia vipande hivyo kama muktadha. + +**Vigezo:** + +`query`: Swali katika lugha ya asili +`user`: Kitambulisho cha mtumiaji/nafasi (cha kawaida: "trustgraph") +`collection`: Kitambulisho cha mkusanyiko (cha kawaida: "default") +`doc_limit`: Vipande vingi vya nyaraka ambavyo vitapatikana (cha kawaida: 10) + +**Inarudisha:** string: Jibu lililoundwa ambalo linajumuisha muktadha wa nyaraka + +**Mfano:** + +```python +flow = api.flow().id("default") +response = flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts)` + +Toa ufafanuzi wa vector kwa maandishi moja au zaidi. + +Hubadilisha maandishi kuwa uwakilishi wa vector mnono unaofaa kwa utafutaji wa maana +na kulinganisha sawa. + +**Vigezo:** + +`texts`: Orodha ya maandishi ya pembeni ambayo yanahitajika kufafanuliwa + +**Inarudisha:** list[list[list[float]]]: Ufafanuzi wa vector, seti moja kwa kila maandishi ya pembeni + +**Mfano:** + +```python +flow = api.flow().id("default") +vectors = flow.embeddings(["quantum computing"]) +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `generate_descriptor(self, sample, data_type, schema_name, options=None)` + +Tengeneza maelezo kwa ajili ya uhusiano wa data iliyopangwa na mpango maalum. + +**Vigezo:** + +`sample`: Sampuli ya data ya kuchambua (maudhui ya maandishi) +`data_type`: Aina ya data (csv, json, xml) +`schema_name`: Jina la mpango unaolengwa kwa ajili ya utengenezaji wa maelezo +`options`: Vigezo vya hiari (k.m., kigawanyo kwa CSV) + +**Inarudisha:** kamusi yenye maelezo na metadata + +### `graph_embeddings_query(self, text, user, collection, limit=10)` + +Tafuta vitu vya grafu ya maarifa kwa kutumia ufanano wa maana. + +Inatafuta vitu katika grafu ya maarifa ambavyo maelezo yake yanafanana +na maandishi yaingizwavyo, kwa kutumia uelekezo wa vector. + +**Vigezo:** + +`text`: Maandishi ya swali kwa ajili ya utafutaji wa maana +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`limit`: Nambari ya juu ya matokeo (ya kawaida: 10) + +**Inarudisha:** kamusi: Matokeo ya swali na vitu vinavyofanana + +**Mfano:** + +```python +flow = api.flow().id("default") +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +# results contains {"entities": [{"entity": {...}, "score": 0.95}, ...]} +``` + +### `graph_rag(self, query, user='trustgraph', collection='default', entity_limit=50, triple_limit=30, max_subgraph_size=150, max_path_length=2)` + +Tekeleza swali la Uzalishaji Ulioboreshwa na Utafutaji (RAG) unaotegemea grafu. + +RAG ya grafu hutumia muundo wa grafu ya maarifa ili kupata muktadha unaohusiana kwa +kutumia uhusiano wa vitu, kisha huunda jibu kwa kutumia LLM. + +**Vigezo:** + +`query`: Swali la lugha ya asili +`user`: Kitambulisho cha mtumiaji/nafasi (cha kawaida: "trustgraph") +`collection`: Kitambulisho cha mkusanyiko (cha kawaida: "default") +`entity_limit`: Vitu vingi zaidi ya kuchuja (cha kawaida: 50) +`triple_limit`: Triples nyingi zaidi kwa kila kitu (cha kawaida: 30) +`max_subgraph_size`: Triples jumla nyingi zaidi katika subgraph (cha kawaida: 150) +`max_path_length`: Kina cha juu zaidi cha utafutaji (cha kawaida: 2) + +**Inarudisha:** string: Jibu lililoundwa ambalo linajumuisha muktadha wa grafu + +**Mfano:** + +```python +flow = api.flow().id("default") +response = flow.graph_rag( + query="Tell me about Marie Curie's discoveries", + user="trustgraph", + collection="scientists", + entity_limit=20, + max_path_length=3 +) +print(response) +``` + +### `load_document(self, document, id=None, metadata=None, user=None, collection=None)` + +Pakia hati ya binary ili kuendelea na usindikaji. + +Hupakia hati (PDF, DOCX, picha, n.k.) ili kuchukua maelezo na +kuendelea na usindikaji kupitia mchakato wa hati. + +**Vigezo:** + +`document`: Yaliyomo katika hati kama bytes +`id`: Kitambulisho cha hati cha hiari (kinatengenezwa kiotomatiki ikiwa hakipo) +`metadata`: Meta-data ya hiari (orodha ya Triples au kitu na njia ya emit) +`user`: Kitambulisho cha mtumiaji/nafasi (cha hiari) +`collection`: Kitambulisho cha mkusanyiko (cha hiari) + +**Inarudisha:** dict: Jibu la usindikaji + +**Inatirisha:** + +`RuntimeError`: Ikiwa meta-data imetolewa bila kitambulisho + +**Mfano:** + +```python +flow = api.flow().id("default") + +# Load a PDF document +with open("research.pdf", "rb") as f: + result = flow.load_document( + document=f.read(), + id="research-001", + user="trustgraph", + collection="papers" + ) +``` + +### `load_text(self, text, id=None, metadata=None, charset='utf-8', user=None, collection=None)` + +Pakia maudhui ya maandishi kwa ajili ya uchakataji. + +Hupakia maudhui ya maandishi kwa ajili ya uondoaji na uchakataji kupitia njia ya maandishi ya mtiririko. + + +**Vigezo:** + +`text`: Maudhui ya maandishi kama bytes +`id`: Kitambulisho cha hati cha hiari (kinaundwa kiotomatiki ikiwa hakipo) +`metadata`: Meta data ya hiari (orodha ya Triples au kitu na njia ya emit) +`charset`: Ufuatiliaji wa herufi (kiasi: "utf-8") +`user`: Kitambulisho cha mtumiaji/nafasi (cha hiari) +`collection`: Kitambulisho cha mkusanyiko (cha hiari) + +**Inarudisha:** dict: Jibu la uchakataji + +**Inayotokea:** + +`RuntimeError`: Ikiwa meta data imetolewa bila kitambulisho + +**Mfano:** + +```python +flow = api.flow().id("default") + +# Load text content +text_content = b"This is the document content..." +result = flow.load_text( + text=text_content, + id="text-001", + charset="utf-8", + user="trustgraph", + collection="documents" +) +``` + +### `mcp_tool(self, name, parameters={})` + +Fanya kazi na zana ya Itifaki ya Mfumo (MCP). + +Zana za MCP hutoa utendakazi unaoweza kupanuliwa kwa wakala na michakato, +kuruhusu ujumuishaji na mifumo na huduma za nje. + +**Vigezo:** + +`name`: Jina/kitambulisho cha zana +`parameters`: Kamusi ya vigezo vya zana (ya kawaida: {}) + +**Inarudisha:** string au kamusi: Matokeo ya utekelezaji wa zana + +**Inatirisha:** + +`ProtocolException`: Ikiwa muundo wa majibu hauna uhakika + +**Mfano:** + +```python +flow = api.flow().id("default") + +# Execute a tool +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `nlp_query(self, question, max_results=100)` + +Badilisha swali la lugha ya asili kuwa ombi la GraphQL. + +**Vigezo:** + +`question`: Swali la lugha ya asili +`max_results`: Nambari ya juu ya matokeo yanayorudishwa (ya kawaida: 100) + +**Inarudisha:** kamusi yenye graphql_query, variables, detected_schemas, uaminifu + +### `prompt(self, id, variables)` + +Tekeleza kiolezo cha ombi kwa kubadilisha vigezo. + +Kiolezo cha ombi huruhusu muundo wa ombi unaoweza kutumika tena na kubadilisha vigezo, +muhimu kwa uhandisi wa ombi unaoendana. + +**Vigezo:** + +`id`: Kitambulisho cha kiolezo cha ombi +`variables`: Kamusi ya ulinganisho wa jina la kigezo hadi thamani + +**Inarudisha:** string au kamusi: Matokeo ya ombi yaliyobadilishwa (maandishi au kitu kilicho na muundo) + +**Inatirisha:** + +`ProtocolException`: Ikiwa muundo wa jibu sio sahihi + +**Mfano:** + +```python +flow = api.flow().id("default") + +# Text template +result = flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"} +) + +# Structured template +result = flow.prompt( + id="extract-entities", + variables={"text": "Marie Curie won Nobel Prizes"} +) +``` + +### `request(self, path, request)` + +Toa ombi la huduma katika toleo hili la mtiririko. + +**Vigezo:** + +`path`: Njia ya huduma (k.m., "service/text-completion") +`request`: Kamusi ya data ya ombi + +**Inarudisha:** dict: Jibu la huduma + +### `row_embeddings_query(self, text, schema_name, user='trustgraph', collection='default', index_name=None, limit=10)` + +Tafuta data ya mstari kwa kutumia ufanano wa maana kwenye sehemu zilizofichwa. + +Inatafuta mistari ambayo maadili ya sehemu zilizofichwa yanafanana kwa maana na +maandishi ya ingizo, kwa kutumia uelekezo wa vector. Hii inaruhusu utafutaji wa "fuzzy"/maana +kwenye data iliyopangwa. + +**Vigezo:** + +`text`: Maandishi ya swali kwa utafutaji wa maana +`schema_name`: Jina la mpango wa kutafuta ndani +`user`: Kitambulisho cha mtumiaji/nafasi (cha kawaida: "trustgraph") +`collection`: Kitambulisho cha mkusanyiko (cha kawaida: "default") +`index_name`: Jina la fahirisi la hiari ili kuchuja utafutaji kwa fahirisi maalum +`limit`: Idadi ya juu ya matokeo (cha kawaida: 10) + +**Inarudisha:** dict: Matokeo ya utafutaji ambayo yana mechi, na yana index_name, index_value, text, na score + +**Mfano:** + +```python +flow = api.flow().id("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query, user='trustgraph', collection='default', variables=None, operation_name=None)` + +Tekeleza swali la GraphQL dhidi ya safu zilizopangwa katika grafu ya maarifa. + +Maswali hutumia data iliyopangwa kwa lugha ya GraphQL, na kuruhusu maswali magumu +yenye kuchujwa, ukusanyaji, na uhusiano. + +**Vigezo:** + +`query`: Mnyororo wa swali la GraphQL +`user`: Kitambulisho cha mtumiaji/nafasi (cha kawaida: "trustgraph") +`collection`: Kitambulisho cha mkusanyiko (cha kawaida: "default") +`variables`: Kamusi ya vigezo vya swali ya hiari +`operation_name`: Jina la operesheni ya hiari kwa hati za operesheni nyingi + +**Inarudisha:** dict: Jibu la GraphQL na sehemu za 'data', 'errors', na/au 'extensions' + +**Inatirisha:** + +`ProtocolException`: Ikiwa hitilafu ya kiwango cha mfumo hutokea + +**Mfano:** + +```python +flow = api.flow().id("default") + +# Simple query +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) + +# Query with variables +query = ''' +query GetScientist($name: String!) { + scientists(name: $name) { + name + nobelPrizes + } +} +''' +result = flow.rows_query( + query=query, + variables={"name": "Marie Curie"} +) +``` + +### `schema_selection(self, sample, options=None)` + +Chagua schemas zinazolingana kwa sampuli ya data kwa kutumia uchambuzi wa swali. + +**Vigezo:** + +`sample`: Sampuli ya data ya kuchambua (maudhui ya maandishi) +`options`: Vigezo vya hiari + +**Inarudisha:** kamusi yenye safu ya schema_matches na metadata + +### `structured_query(self, question, user='trustgraph', collection='default')` + +Tekeleza swali la lugha ya asili dhidi ya data iliyopangwa. +Inachanganya ubadilishaji wa swali la NLP na utekelezaji wa GraphQL. + +**Vigezo:** + +`question`: Swali la lugha ya asili +`user`: Kitambulisho cha nafasi ya Cassandra (cha kawaida: "trustgraph") +`collection`: Kitambulisho cha mkusanyiko wa data (cha kawaida: "default") + +**Inarudisha:** kamusi yenye data na makosa yanayohitajika + +### `text_completion(self, system, prompt)` + +Tekeleza kukamilisha maandishi kwa kutumia LLM ya mtiririko. + +**Vigezo:** + +`system`: Swali la mfumo linalobainisha tabia ya msaidizi +`prompt`: Swali/swali la mtumiaji + +**Inarudisha:** maandishi: Jibu lililoundwa + +**Mfano:** + +```python +flow = api.flow().id("default") +response = flow.text_completion( + system="You are a helpful assistant", + prompt="What is quantum computing?" +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=10000)` + +Tafuta ujuzi wa grapu kwa kutumia utangamano. + +Inatafuta triplet za RDF zinazofanana na mada, tabia, na/au +mifumo ya kitu. Vigezo visivyotajwa hufanya kama vichwa vya habari. + +**Vigezo:** + +`s`: URI ya mada (hiari, tumia None kwa kichwa cha habari) +`p`: URI ya tabia (hiari, tumia None kwa kichwa cha habari) +`o`: URI ya kitu au Literal (hiari, tumia None kwa kichwa cha habari) +`user`: Kitambulisho cha mtumiaji/nafasi (hiari) +`collection`: Kitambulisho cha mkusanyiko (hiari) +`limit`: Matokeo ya juu ya kurejesha (ya kawaida: 10000) + +**Inarejea:** list[Triple]: Orodha ya vitu vinavyolingana vya Triple + +**Inatiruka:** + +`RuntimeError`: Ikiwa s au p si Uri, au o si Uri/Literal + +**Mfano:** + +```python +from trustgraph.knowledge import Uri, Literal + +flow = api.flow().id("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s=Uri("http://example.org/person/marie-curie"), + user="trustgraph", + collection="scientists" +) + +# Find all instances of a specific relationship +triples = flow.triples_query( + p=Uri("http://example.org/ontology/discovered"), + limit=100 +) +``` + + +-- + +## `AsyncFlow` + +```python +from trustgraph.api import AsyncFlow +``` + +Mteja wa usimamizi wa mtiririko usio na usawisi, unaotumia API ya REST. + +Hutoa operesheni za usimamizi wa mtiririko kulingana na async/await, ikiwa ni pamoja na kuorodhesha, +kuanzisha, kusimamisha mitiririko, na kusimamia ufafanuzi wa darasa la mtiririko. Pia hutoa +ufikiaji wa huduma za mtiririko kama vile wakala, RAG, na maswali kupitia sehemu za mwisho za REST ambazo hazitumii utiririshaji. + + +Kumbuka: Kwa usaidizi wa utiririshaji, tumia AsyncSocketClient badala yake. + +### Mbinu + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Anzisha mteja wa mtiririko usio na usawisi. + +**Majadiliano:** + +`url`: URL ya msingi ya API ya TrustGraph +`timeout`: Muda wa kuchelewa wa ombi kwa sekunde +`token`: Tokeni ya kuhifadhiwa ya hiari kwa uthibitishaji + +### `aclose(self) -> None` + +Funga mteja usio na usawisi na safisha rasilimali. + +Kumbuka: Usafishaji unashughulikiwa kiotomatiki na meneja wa muktadha wa kikao cha aiohttp. +Mbinu hii hutolewa kwa utangamano na wateja wengine wasio na usawisi. + +### `delete_class(self, class_name: str)` + +Futa ufafanuzi wa darasa la mtiririko. + +Huondoa mpango wa darasa la mtiririko kutoka kwenye mfumo. Haathiri +mifano ya mtiririko inayoruka. + +**Majadiliano:** + +`class_name`: Jina la darasa la mtiririko kufutwa + +**Mfano:** + +```python +async_flow = await api.async_flow() + +# Delete a flow class +await async_flow.delete_class("old-flow-class") +``` + +### `get(self, id: str) -> Dict[str, Any]` + +Pata ufafanuzi wa mtiririko. + +Hupata usanidi kamili wa mtiririko, pamoja na jina lake la darasa, +maelezo, na vigezo. + +**Vigezo:** + +`id`: Kitambulisho cha mtiririko + +**Inarudisha:** dict: Kitu cha ufafanuzi wa mtiririko + +**Mfano:** + +```python +async_flow = await api.async_flow() + +# Get flow definition +flow_def = await async_flow.get("default") +print(f"Flow class: {flow_def.get('class-name')}") +print(f"Description: {flow_def.get('description')}") +``` + +### `get_class(self, class_name: str) -> Dict[str, Any]` + +Pata ufafanuzi wa darasa la mtiririko. + +Inapata ufafanuzi wa mpango wa darasa la mtiririko, pamoja na +mpango wake wa usanidi na viunganisho vya huduma. + +**Vigezo:** + +`class_name`: Jina la darasa la mtiririko + +**Inarudisha:** dict: Kitu kinachowakilisha ufafanuzi wa darasa la mtiririko + +**Mfano:** + +```python +async_flow = await api.async_flow() + +# Get flow class definition +class_def = await async_flow.get_class("default") +print(f"Services: {class_def.get('services')}") +``` + +### `id(self, flow_id: str)` + +Pata mteja wa mtiririko wa async. + +Inarudisha mteja kwa ajili ya kuingiliana na huduma za mtiririko maalum +(wakala, RAG, maswali, ufumbuzi, n.k.). + +**Majadiliano:** + +`flow_id`: Kitambulisho cha mtiririko + +**Inarudisha:** AsyncFlowInstance: Mteja kwa operesheni maalum za mtiririko + +**Mfano:** + +```python +async_flow = await api.async_flow() + +# Get flow instance +flow = async_flow.id("default") + +# Use flow services +result = await flow.graph_rag( + query="What is TrustGraph?", + user="trustgraph", + collection="default" +) +``` + +### `list(self) -> List[str]` + +Orodha ya kitambulisho cha kila mtiririko. + +Inapata kitambulisho cha kila mtiririko unaoendeshwa kwa sasa katika mfumo. + +**Inarudisha:** list[str]: Orodha ya kitambulisho cha mtiririko + +**Mfano:** + +```python +async_flow = await api.async_flow() + +# List all flows +flows = await async_flow.list() +print(f"Available flows: {flows}") +``` + +### `list_classes(self) -> List[str]` + +Orodha ya majina yote ya darasa la mtiririko. + +Inapata majina ya madarasa yote ya mtiririko (mipango) yanayopatikana katika mfumo. + +**Inarudisha:** list[str]: Orodha ya majina ya darasa la mtiririko. + +**Mfano:** + +```python +async_flow = await api.async_flow() + +# List available flow classes +classes = await async_flow.list_classes() +print(f"Available flow classes: {classes}") +``` + +### `put_class(self, class_name: str, definition: Dict[str, Any])` + +Kuunda au kusasisha ufafanuzi wa darasa la mtiririko. + +Hifadhi mfumo wa darasa la mtiririko ambao unaweza kutumika kuunda mitiririko. + +**Vigezo:** + +`class_name`: Jina la darasa la mtiririko +`definition`: Kifaa cha ufafanuzi cha darasa la mtiririko + +**Mfano:** + +```python +async_flow = await api.async_flow() + +# Create a custom flow class +class_def = { + "services": { + "agent": {"module": "agent", "config": {...}}, + "graph-rag": {"module": "graph-rag", "config": {...}} + } +} +await async_flow.put_class("custom-flow", class_def) +``` + +### `request(self, path: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +Fanya ombi la HTTP POST lisilo na usumbufu kwa API ya Gateway. + +Njia ya ndani ya kutuma ombi lililo na uthibitisho kwa API ya TrustGraph. + +**Vigezo:** + +`path`: Njia ya mwisho ya API (kulinganisha na URL ya msingi) +`request_data`: Kamusi ya data inayotumwa kwenye ombi + +**Inarudisha:** dict: Kielelezo cha majibu kutoka kwa API + +**Inayotokea:** + +`ProtocolException`: Ikiwa hali ya HTTP si 200 au majibu hayana umbizo sahihi la JSON +`ApplicationException`: Ikiwa API inarudisha jibu la kosa + +### `start(self, class_name: str, id: str, description: str, parameters: Dict | None = None)` + +Anzisha mfumo mpya wa utekelezaji. + +Huunda na kuanzisha mfumo kutoka kwa ufafanuzi wa darasa la mfumo pamoja na +vigezo vilivyoelezwa. + +**Vigezo:** + +`class_name`: Jina la darasa la mfumo linalotumiwa +`id`: Kitambulisho cha mfumo mpya +`description`: Maelezo yanayoweza kusomwa na binadamu ya mfumo +`parameters`: Vigezo vya ziada vya usanidi vya mfumo + +**Mfano:** + +```python +async_flow = await api.async_flow() + +# Start a flow from a class +await async_flow.start( + class_name="default", + id="my-flow", + description="Custom flow instance", + parameters={"model": "claude-3-opus"} +) +``` + +### `stop(self, id: str)` + +Kusimamisha mtiririko unaoendelea. + +Inasimamisha na kuondoa mfano wa mtiririko, na kutoa rasilimali zake. + +**Vigezo:** + +`id`: Kitambulisho cha mtiririko ili kusimamishwa + +**Mfano:** + +```python +async_flow = await api.async_flow() + +# Stop a flow +await async_flow.stop("my-flow") +``` + + +-- + +## `AsyncFlowInstance` + +```python +from trustgraph.api import AsyncFlowInstance +``` + +Mteja wa mfumo wa kazi usiofanyika kwa wakati mmoja. + +Hutoa ufikiaji wa async/await kwa huduma za mfumo wa kazi, ikiwa ni pamoja na wakala, +Maswali ya RAG, maandamano, na maswali ya grafu. Operesheni zote hurudisha +majibu kamili (ya moja kwa moja). + +Kumbuka: Kwa usaidizi wa utiririshaji, tumia AsyncSocketFlowInstance. + +### Mbinu + +### `__init__(self, flow: trustgraph.api.async_flow.AsyncFlow, flow_id: str)` + +Anzisha mfumo wa kazi usiofanyika kwa wakati mmoja. + +**Majadiliano:** + +`flow`: Mteja wa AsyncFlow mkuu +`flow_id`: Kitambulisho cha mfumo wa kazi + +### `agent(self, question: str, user: str, state: Dict | None = None, group: str | None = None, history: List | None = None, **kwargs: Any) -> Dict[str, Any]` + +Fanya operesheni ya wakala (ya moja kwa moja). + +Huendesha wakala kujibu swali, pamoja na hali ya mazungumzo na +historia. Inarudisha jibu kamili baada ya wakala kumaliza +kuchakata. + +Kumbuka: Njia hii haitumii utiririshaji. Kwa mawazo na matokeo ya wakala +ya wakati halisi, tumia AsyncSocketFlowInstance.agent() badala yake. + +**Majadiliano:** + +`question`: Suali au maagizo ya mtumiaji +`user`: Kitambulisho cha mtumiaji +`state`: Kamusi ya hali ya hiari kwa muktadha wa mazungumzo +`group`: Kitambulisho cha kikundi cha hiari kwa usimamizi wa kikao +`history`: Orodha ya historia ya mazungumzo ya hiari +`**kwargs`: Vigezo vya ziada maalum kwa huduma + +**Inarudisha:** dict: Jibu kamili la wakala ikiwa ni pamoja na jibu na metadata + +**Mfano:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute agent +result = await flow.agent( + question="What is the capital of France?", + user="trustgraph" +) +print(f"Answer: {result.get('response')}") +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> str` + +Fanya swali la RAG (Retrieval-Augmented Generation) linalotegemea hati (si mtiririko). + +Hufanya Uundaji Ulioboreshwa kwa Upatanishaji kwa kutumia ufichuo wa hati. +Hupata vipande muhimu vya hati kupitia utafutaji wa maana, kisha huunda +jibu linalotegemea hati zilizopatikana. Inarudisha jibu kamili. + +Kumbuka: Njia hii haitumii mtiririko. Kwa majibu ya RAG yanayotumia mtiririko, +tumia AsyncSocketFlowInstance.document_rag() badala yake. + +**Vigezo:** + +`query`: Nakala ya swali la mtumiaji +`user`: Kitambulisho cha mtumiaji +`collection`: Kitambulisho cha mkusanyiko unao na hati +`doc_limit`: Nambari ya juu ya vipande vya hati ambavyo vinaweza kupatikana (kiwango chachilia: 10) +`**kwargs`: Vigezo vya ziada vinavyohusiana na huduma + +**Inarudisha:** str: Jibu kamili lililoundwa na linalotegemea data ya hati + +**Mfano:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query documents +response = await flow.document_rag( + query="What does the documentation say about authentication?", + user="trustgraph", + collection="docs", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts: list, **kwargs: Any)` + +Toa maelezo kwa maandishi ya pembejeo. + +Hubadilisha maandishi kuwa uwakilishi wa nambari za vector kwa kutumia +mfumo wa embedding uliopangwa wa mtiririko. Ni muhimu kwa utafutaji wa maana na +ulinganisho wa alama. + +**Vigezo:** + +`texts`: Orodha ya maandishi ya pembejeo ambayo yanahitajika kuwekwa maelezo. +`**kwargs`: Vigezo vya ziada maalum kwa huduma. + +**Inarudisha:** dict: Jibu lenye vector za maelezo. + +**Mfano:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate embeddings +result = await flow.embeddings(texts=["Sample text to embed"]) +vectors = result.get("vectors") +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any)` + +Tafuta ujumuishi wa grafu kwa ajili ya utafutaji wa vitu vya maana. + +Hufanya utafutaji wa maana kwenye ujumuishi wa vitu vya grafu ili kupata vitu +ambavyo ni muhimu zaidi kwa maandishi yaliyopo. Inarudisha vitu vilivyopangwa kwa umuhimu. + +**Vigezo:** + +`text`: Maandishi ya swali kwa utafutaji wa maana +`user`: Kitambulisho cha mtumiaji +`collection`: Kitambulisho cha mkusanyiko unao na ujumuishi wa grafu +`limit`: Nambari ya juu ya matokeo yanayorudishwa (ya kawaida: 10) +`**kwargs`: Vigezo vya ziada maalum kwa huduma + +**Inarudisha:** dict: Jibu linalo na vitu vinavyolingana vilivyopangwa pamoja na alama za umuhimu + +**Mfano:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find related entities +results = await flow.graph_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="tech-kb", + limit=5 +) + +for entity in results.get("entities", []): + print(f"{entity['name']}: {entity['score']}") +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> str` + +Tekeleza swali la RAG linalotegemea grafu (lisilo na utiririshaji). + +Hufanya Uundaji Ulioboreshwa na Upatanishaji kwa kutumia data ya grafu ya maarifa. +Hutambua vitu muhimu na uhusiano wao, kisha huunda +jibu ambalo limekithiri katika muundo wa grafu. Inarudisha jibu kamili. + +Kumbuka: Njia hii haitumii utiririshaji. Kwa majibu ya RAG yanayotumia utiririshaji, +tumia AsyncSocketFlowInstance.graph_rag() badala yake. + +**Vigezo:** + +`query`: Nakala ya swali la mtumiaji +`user`: Kitambulisho cha mtumiaji +`collection`: Kitambulisho cha mkusanyiko unao na grafu ya maarifa +`max_subgraph_size`: Nambari ya juu ya triplet kwa kila subgrafu (ya kawaida: 1000) +`max_subgraph_count`: Nambari ya juu ya subgrafu za kuchukuliwa (ya kawaida: 5) +`max_entity_distance`: Umbali wa juu wa grafu kwa upanuzi wa vitu (ya kawaida: 3) +`**kwargs`: Vigezo vya ziada vya huduma maalum + +**Inarudisha:** string: Jibu kamili lililoundwa ambalo limekithiri katika data ya grafu + +**Mfano:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query knowledge graph +response = await flow.graph_rag( + query="What are the relationships between these entities?", + user="trustgraph", + collection="medical-kb", + max_subgraph_count=3 +) +print(response) +``` + +### `request(self, service: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +Tafadhali omba huduma iliyo ndani ya eneo la mtiririko. + +Njia ya ndani ya kuita huduma ndani ya mfano huu wa mtiririko. + +**Vigezo:** + +`service`: Jina la huduma (k.m., "agent", "graph-rag", "triples") +`request_data`: Takwimu ya ombi la huduma + +**Inarudisha:** dict: Kielelezo cha jibu la huduma + +**Inatirisha:** + +`ProtocolException`: Ikiwa ombi halikubaliwi au jibu ni batili +`ApplicationException`: Ikiwa huduma inarudisha kosa + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any)` + +Tafuta ujumbe wa mistari ili kutafuta maana katika data iliyopangwa. + +Hufanya utafutaji wa maana kwenye ujumbe wa mistari ili kupata mistari ambayo +maadili ya sehemu iliyopangwa ni sawa zaidi na maandishi ya ingizo. Inaruhusu +utangamano/ufanisi wa maana katika data iliyopangwa. + +**Vigezo:** + +`text`: Maandishi ya swali kwa utafutaji wa maana +`schema_name`: Jina la mpango wa kutafuta ndani +`user`: Kitambulisho cha mtumiaji (kawaida: "trustgraph") +`collection`: Kitambulisho cha mkusanyiko (kawaida: "default") +`index_name`: Jina la faharasa la hiari ili kuchuja utafutaji kwa faharasa maalum +`limit`: Nambari ya juu ya matokeo ya kurejesha (kawaida: 10) +`**kwargs`: Vigezo vya ziada vya huduma + +**Inarudisha:** dict: Jibu linalo na mechi pamoja na index_name, index_value, text, na score + +**Mfano:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Search for customers by name similarity +results = await flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +for match in results.get("matches", []): + print(f"{match['index_name']}: {match['index_value']} (score: {match['score']})") +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs: Any)` + +Tekeleza swali la GraphQL kwenye mistari iliyohifadhiwa. + +Maswali hutumia mistari iliyo na muundo kwa kutumia sintaksia ya GraphQL. Inasaidia +maswali magumu yenye vigezo na operesheni zilizo na majina. + +**Vigezo:** + +`query`: Mnyororo wa swali la GraphQL +`user`: Kitambulisho cha mtumiaji +`collection`: Kitambulisho cha mkusanyiko unao na mistari +`variables`: Vigezo vya swali la GraphQL vya hiari +`operation_name`: Jina la operesheni la hiari kwa maswali mengi +`**kwargs`: Vigezo vya ziada vya mahitaji ya huduma + +**Inarudisha:** dict: Jibu la GraphQL lenye data na/au makosa + +**Mfano:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute GraphQL query +query = ''' + query GetUsers($status: String!) { + users(status: $status) { + id + name + email + } + } +''' + +result = await flow.rows_query( + query=query, + user="trustgraph", + collection="users", + variables={"status": "active"} +) + +for user in result.get("data", {}).get("users", []): + print(f"{user['name']}: {user['email']}") +``` + +### `text_completion(self, system: str, prompt: str, **kwargs: Any) -> str` + +Toa maandishi yaliyokamilika (hayajazalishwa kwa utiririshaji). + +Huunda jibu la maandishi kutoka kwa mfumo wa LLM (Large Language Model) kwa kutumia maagizo ya mfumo na maagizo ya mtumiaji. +Inarudisha maandishi kamili ya jibu. + +Kumbuka: Njia hii haitumii utiririshaji. Kwa utiririshaji wa maandishi, +tumia AsyncSocketFlowInstance.text_completion() badala yake. + +**Vigezo:** + +`system`: Maagizo ya mfumo ambayo yanaeleza tabia ya mfumo wa LLM. +`prompt`: Maagizo ya mtumiaji au swali. +`**kwargs`: Vigezo vya ziada ambavyo ni mahususi kwa huduma. + +**Inarudisha:** str: Jibu kamili la maandishi lililozalishwa. + +**Mfano:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate text +response = await flow.text_completion( + system="You are a helpful assistant.", + prompt="Explain quantum computing in simple terms." +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs: Any)` + +Tafuta maneno matatu ya RDF kwa kutumia utambuzi wa muundo. + +Inatafuta maneno matatu yanayolingana na mada, sifa, na/au +mifumo ya kitu. Mifumo hutumia "Hakuna" kama ishara ya kujielekeza ili kuangalia thamani yoyote. + +**Vigezo:** + +`s`: Mfumo wa mada (Hakuna kwa kujielekeza) +`p`: Mfumo wa sifa (Hakuna kwa kujielekeza) +`o`: Mfumo wa kitu (Hakuna kwa kujielekeza) +`user`: Kitambulisho cha mtumiaji (Hakuna kwa watumiaji wote) +`collection`: Kitambulisho cha mkusanyiko (Hakuna kwa mkusanyiko wote) +`limit`: Nambari ya juu ya maneno matatu ya kurejesha (ya kawaida: 100) +`**kwargs`: Vigezo vya ziada maalum kwa huduma + +**Inarejea:** dict: Jibu lenye maneno matatu yanayolingana + +**Mfano:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find all triples with a specific predicate +results = await flow.triples_query( + p="knows", + user="trustgraph", + collection="social", + limit=50 +) + +for triple in results.get("triples", []): + print(f"{triple['s']} knows {triple['o']}") +``` + + +-- + +## `SocketClient` + +```python +from trustgraph.api import SocketClient +``` + +Mteja wa WebSocket wa wakati mmoja kwa operesheni za utiririshaji. + +Hutoa kiolesura cha wakati mmoja kwa huduma za TrustGraph zinazotegemea WebSocket, +ikibadilisha maktabu ya websockets ya asinkroni na jenereta za wakati mmoja ili iwe rahisi kutumia. +Inasaidia majibu ya utiririshaji kutoka kwa wakala, maswali ya RAG, na kukamilisha maandishi. + +Kumbuka: Hii ni kifungashio cha wakati mmoja kilichoanzishwa kwenye operesheni za WebSocket za asinkroni. Kwa +usaidizi wa kweli wa asinkroni, tumia AsyncSocketClient badala yake. + +### Mbinu + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Anzisha mteja wa WebSocket wa wakati mmoja. + +**Majadiliano:** + +`url`: URL ya msingi kwa API ya TrustGraph (HTTP/HTTPS itabadilishwa kuwa WS/WSS) +`timeout`: Muda wa kimya wa WebSocket kwa sekunde +`token`: Tokeni ya kuhifadhia ya hiari kwa uthibitishaji + +### `close(self) -> None` + +Funga miunganisho ya WebSocket. + +Kumbuka: Usafi unashughulikiwa kiotomatiki na wasimamizi wa muktadha katika msimbo wa asinkroni. + +### `flow(self, flow_id: str) -> 'SocketFlowInstance'` + +Pata mfano wa mtiririko kwa operesheni za utiririshaji wa WebSocket. + +**Majadiliano:** + +`flow_id`: Kitambulisho cha mtiririko + +**Inarudisha:** SocketFlowInstance: Mfano wa mtiririko na mbinu za utiririshaji + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent(question="Hello", user="trustgraph", streaming=True): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `SocketFlowInstance` + +```python +from trustgraph.api import SocketFlowInstance +``` + +Mfumo wa mawasiliano ya WebSocket wa wakati mmoja kwa operesheni za utiririshaji. + +Hutoa kiolesura sawa na FlowInstance ya REST lakini na msaada wa utiririshaji wa WebSocket +kwa majibu ya wakati halisi. Mbinu zote zinaunga mkono parameter ya hiari +`streaming` ili kuwezesha utoaji wa matokeo kwa hatua. + +### Mbinu + +### `__init__(self, client: trustgraph.api.socket_client.SocketClient, flow_id: str) -> None` + +Anzisha mfumo wa utiririshaji wa soketi. + +**Majadiliano:** + +`client`: Soketi ya Msimamizi +`flow_id`: Kitambulisho cha mtiririko + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, streaming: bool = False, **kwargs: Any) -> Dict[str, Any] | Iterator[trustgraph.api.types.StreamingChunk]` + +Fanya operesheni ya wakala na msaada wa utiririshaji. + +Wakala wanaweza kufanya utaratibu wa hatua kadhaa kwa kutumia zana. Mbinu hii daima +hurudisha vipande vya utiririshaji (mawazo, uchunguzi, majibu) hata wakati +streaming=False, ili kuonyesha mchakato wa utafakari wa wakala. + +**Majadiliano:** + +`question`: Swali au maagizo ya mtumiaji +`user`: Kitambulisho cha mtumiaji +`state`: Kamusi ya hiari ya hali kwa mazungumzo ya hali +`group`: Kitambulisho cha hiari cha kikundi kwa muktadha wa watumiaji wengi +`history`: Historia ya hiari ya mazungumzo kama orodha ya maneno +`streaming`: Washa hali ya utiririshaji (kiasi: False) +`**kwargs`: Vigezo vya ziada vilivyopitishwa kwa huduma ya wakala + +**Hurejesha:** Iterator[StreamingChunk]: Mto wa mawazo, uchunguzi, na majibu ya wakala + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent reasoning +for chunk in flow.agent( + question="What is quantum computing?", + user="trustgraph", + streaming=True +): + if isinstance(chunk, AgentThought): + print(f"[Thinking] {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"[Observation] {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"[Answer] {chunk.content}") +``` + +### `agent_explain(self, question: str, user: str, collection: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, **kwargs: Any) -> Iterator[trustgraph.api.types.StreamingChunk | trustgraph.api.types.ProvenanceEvent]` + +Fanya operesheni ya wakala pamoja na ufuatiliaji wa uelewaji. + +Hutuma vipande vya maudhui (AgentThought, AgentObservation, AgentAnswer) +na matukio ya asili (ProvenanceEvent). Matukio ya asili yana anwani za mtandao (URIs) +ambazo zinaweza kupatikana kwa kutumia ExplainabilityClient ili kupata maelezo +kuhusu mchakato wa utafakari wa wakala. + +Ufuatiliaji wa wakala una vipengele vifuatavyo: +Kipindi: Swali la awali na metadata ya kipindi +Mzunguko: Kila mzunguko wa mawazo/tendo/uchunguzi +Hitimisho: Jibu la mwisho + +**Vigezo:** + +`question`: Swali au maagizo ya mtumiaji +`user`: Kitambulisho cha mtumiaji +`collection`: Kitambulisho cha mkusanyiko kwa uhifadhi wa asili +`state`: Kamusi ya hali inayobadilika (optional) kwa mazungumzo yanayoendelea +`group`: Kitambulisho cha kikundi (optional) kwa mazingira ya watumiaji wengi +`history`: Historia ya mazungumzo (optional) kama orodha ya maneno +`**kwargs`: Vigezo vya ziada ambavyo hutumwa kwa huduma ya wakala +`Yields`: +`Union[StreamingChunk, ProvenanceEvent]`: Vipande vya wakala na matukio ya asili + +**Mfano:** + +```python +from trustgraph.api import Api, ExplainabilityClient, ProvenanceEvent +from trustgraph.api import AgentThought, AgentObservation, AgentAnswer + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +for item in flow.agent_explain( + question="What is the capital of France?", + user="trustgraph", + collection="default" +): + if isinstance(item, AgentThought): + print(f"[Thought] {item.content}") + elif isinstance(item, AgentObservation): + print(f"[Observation] {item.content}") + elif isinstance(item, AgentAnswer): + print(f"[Answer] {item.content}") + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.explain_id) + +# Fetch session trace after completion +if provenance_ids: + trace = explain_client.fetch_agent_trace( + provenance_ids[0], # Session URI is first + graph="urn:graph:retrieval", + user="trustgraph", + collection="default" + ) +``` + +### `document_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Tafuta vipande vya hati kwa kutumia utambulisho wa maana. + +**Vigezo:** + +`text`: Nakala ya swali kwa utafutaji wa maana +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`limit`: Nambari ya juu ya matokeo (ya kawaida: 10) +`**kwargs`: Vigezo vya ziada vilivyopitishwa kwa huduma + +**Inarudisha:** dict: Matokeo ya swali na kitambulisho cha vipande vya hati vinavyolingana + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "...", "score": 0.95}, ...]} +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Fanya swali la RAG (Retrieval-Augmented Generation) linalotegemea hati, na uwezekano wa kutumia utiririshaji. + +Hutumia ufashiliaji wa vector ili kupata vipande muhimu vya hati, kisha huunda +jibu kwa kutumia LLM (Large Language Model). Njia ya utiririshaji huwasilisha matokeo hatua kwa hatua. + +**Vigezo:** + +`query`: Swali la lugha ya asili +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`doc_limit`: Idadi ya juu ya vipande vya hati ambavyo vinaweza kupatikana (kiwango chachilia: 10) +`streaming`: Washa hali ya utiririshaji (kiwango chachilia: False) +`**kwargs`: Vigezo vya ziada ambavyo hutumwa kwa huduma + +**Hurejesha:** Union[str, Iterator[str]]: Jibu kamili au mkondo wa vipande vya maandishi + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming document RAG +for chunk in flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `document_rag_explain(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +Fanya swali la RAG (Retrieval-Augmented Generation) linalotegemea hati na linalo na uwezo wa kueleza. + +Hutuma vipande vya maudhui (RAGChunk) na matukio ya asili (ProvenanceEvent). +Matukio ya asili yana anwani za mtandao (URIs) ambazo zinaweza kupatikana kwa kutumia ExplainabilityClient +ili kupata maelezo ya kina kuhusu jinsi jibu lilivyoundwa. + +Mfuatiliaji wa RAG wa hati una vipengele vifuatavyo: +Swali: Swali la mtumiaji +Uchunguzi: Vipande vilivyopatikana kutoka kwenye hifadhi ya hati (idadi ya vipande) +Muundo: Jibu lililoundwa + +**Vigezo:** + +`query`: Swali kwa lugha ya asili +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`doc_limit`: Vipande vingi vya hati ambavyo vinaweza kupatikana (kiwango chachilia: 10) +`**kwargs`: Vigezo vya ziada ambavyo vinatumiwa kwa huduma +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: Vipande vya maudhui na matukio ya asili + +**Mfano:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +for item in flow.document_rag_explain( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +): + if isinstance(item, RAGChunk): + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + # Fetch entity details + entity = explain_client.fetch_entity( + item.explain_id, + graph=item.explain_graph, + user="trustgraph", + collection="research-papers" + ) + print(f"Event: {entity}", file=sys.stderr) +``` + +### `embeddings(self, texts: list, **kwargs: Any) -> Dict[str, Any]` + +Toa ufafanuzi wa maandishi kwa ajili ya maandishi moja au zaidi. + +**Vigezo:** + +`texts`: Orodha ya maandishi ya pembeni ambayo yatatumika kuunda ufafanuzi. +`**kwargs`: Vigezo vya ziada ambavyo hutumwa kwa huduma. + +**Inarudisha:** dict: Jibu ambalo lina ufafanuzi (kundi moja kwa kila maandishi ya pembeni). + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.embeddings(["quantum computing"]) +vectors = result.get("vectors", []) +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Tafuta vitu vya grafu ya maarifa kwa kutumia utambulisho wa maana. + +**Vigezo:** + +`text`: Nakala ya swali kwa utafutaji wa maana +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`limit`: Nambari ya juu ya matokeo (ya kawaida: 10) +`**kwargs`: Vigezo vya ziada vilivyopitishwa kwa huduma + +**Inarudisha:** dict: Matokeo ya swali na vitu vinavyofanana + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Tekeleza swali la RAG linalotegemea grafu pamoja na utiririshaji wa hiari. + +Hutumia muundo wa grafu ya maarifa ili kupata muktadha unaohusika, kisha huunda +jibu kwa kutumia LLM. Njia ya utiririshaji huwasilisha matokeo hatua kwa hatua. + +**Vigezo:** + +`query`: Swali la lugha ya asili +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`max_subgraph_size`: Idadi ya juu ya triplet katika subgrafu (ya kawaida: 1000) +`max_subgraph_count`: Idadi ya juu ya subgrafu (ya kawaida: 5) +`max_entity_distance`: Kina cha juu cha utafutaji (ya kawaida: 3) +`streaming`: Washa hali ya utiririshaji (ya kawaida: False) +`**kwargs`: Vigezo vya ziada ambavyo hutumwa kwa huduma + +**Hurejesha:** Union[str, Iterator[str]]: Jibu kamili au mkondo wa vipande vya maandishi + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming graph RAG +for chunk in flow.graph_rag( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `graph_rag_explain(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +Tekeleza swali la RAG linalotegemea grafu pamoja na utumiaji wa uelewaji. + +Hutiririsha vipande vya maudhui (RAGChunk) na matukio ya asili (ProvenanceEvent). +Matukio ya asili yana URI ambazo zinaweza kupatikana kwa kutumia ExplainabilityClient +ili kupata maelezo ya kina kuhusu jinsi jibu lilivyoundwa. + +**Vigezo:** + +`query`: Swali la lugha ya asili +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`max_subgraph_size`: Idadi ya juu ya triplet katika subgrafu (ya kawaida: 1000) +`max_subgraph_count`: Idadi ya juu ya subgrafu (ya kawaida: 5) +`max_entity_distance`: Kina cha juu cha utafutaji (ya kawaida: 3) +`**kwargs`: Vigezo vya ziada ambavyo hutumwa kwa huduma +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: Vipande vya maudhui na matukio ya asili + +**Mfano:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +response_text = "" + +for item in flow.graph_rag_explain( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists" +): + if isinstance(item, RAGChunk): + response_text += item.content + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.provenance_id) + +# Fetch explainability details +for prov_id in provenance_ids: + entity = explain_client.fetch_entity( + prov_id, + graph="urn:graph:retrieval", + user="trustgraph", + collection="scientists" + ) + print(f"Entity: {entity}") +``` + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]` + +Fanya kazi ya zana ya Itifaki ya Mfumo (MCP). + +**Vigezo:** + +`name`: Jina/kitambulisho cha zana +`parameters`: Kamusi ya vigezo vya zana +`**kwargs`: Vigezo vya ziada vilivyopitishwa kwa huduma + +**Inarudisha:** dict: Matokeo ya utekelezaji wa zana + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Tekeleza mfumo wa kielelezo cha ombi pamoja na utiririshaji wa hiari. + +**Vigezo:** + +`id`: Kitambulisho cha kielelezo cha ombi +`variables`: Kamusi ya uhusiano kati ya jina la vigezo na maadili +`streaming`: Washa hali ya utiririshaji (kiwango chake: Feleke) +`**kwargs`: Vigezo vya ziada ambavyo hutumwa kwa huduma + +**Inarudisha:** Union[str, Iterator[str]]: Jibu kamili au mkondo wa vipande vya maandishi + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming prompt execution +for chunk in flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"}, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Tafuta data ya safu kwa kutumia utofauti wa maana kwenye sehemu zilizofichwa. + +Inatafuta safu ambazo maadili ya sehemu zilizofichwa zinafanana kwa maana na +maandishi ya ingizo, kwa kutumia uelekezo wa vector. Hii inaruhusu utafutaji wa "fuzzy"/maana +kwenye data iliyopangwa. + +**Vigezo:** + +`text`: Maandishi ya swali kwa utafutaji wa maana +`schema_name`: Jina la schema ili kutafuta ndani +`user`: Kitambulisho cha mtumiaji/keyspace (cha kawaida: "trustgraph") +`collection`: Kitambulisho cha mkusanyiko (cha kawaida: "default") +`index_name`: Jina la index la hiari ili kuchuja utafutaji kwa index maalum +`limit`: Nambari ya juu ya matokeo (cha kawaida: 10) +`**kwargs`: Vigezo vya ziada vilivyopitishwa kwa huduma + +**Inarudisha:** dict: Matokeo ya swali ambayo yana mechi zinazojumuisha index_name, index_value, text, na score + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict[str, Any] | None = None, operation_name: str | None = None, **kwargs: Any) -> Dict[str, Any]` + +Tekeleza swali la GraphQL dhidi ya mistari iliyopangwa. + +**Vigezo:** + +`query`: Mnyororo wa swali la GraphQL +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`variables`: Kamusi ya vigezo vya swali ya hiari +`operation_name`: Jina la operesheni ya hiari kwa hati za operesheni nyingi +`**kwargs`: Vigezo vya ziada vilivyopitishwa kwa huduma + +**Inarudisha:** dict: Jibu la GraphQL lenye data, makosa, na/au nyongeza + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) +``` + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs) -> str | Iterator[str]` + +Tekeleza kukamilisha maandishi kwa kutumia utiririshaji wa hiari. + +**Vigezo:** + +`system`: Maelezo ya mfumo ambayo yanaelezea tabia ya msaidizi. +`prompt`: Maelezo ya mtumiaji/swali. +`streaming`: Washa hali ya utiririshaji (kiwango chachilia: False). +`**kwargs`: Vigezo vya ziada ambavyo hutumwa kwa huduma. + +**Inarudisha:** Union[str, Iterator[str]]: Jibu kamili au mkondo wa vipande vya maandishi. + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Non-streaming +response = flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=False +) +print(response) + +# Streaming +for chunk in flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `triples_query(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, **kwargs: Any) -> List[Dict[str, Any]]` + +Tafuta tripli za grafu ya maarifa kwa kutumia utambuzi wa muundo. + +**Vigezo:** + +`s`: Kichujio cha somo - Msururu wa URI, kamusi ya neno, au None kwa kichujio cha kila kitu. +`p`: Kichujio cha tabia - Msururu wa URI, kamusi ya neno, au None kwa kichujio cha kila kitu. +`o`: Kichujio cha kitu - Msururu wa URI/lita, kamusi ya neno, au None kwa kichujio cha kila kitu. +`g`: Kichujio cha grafu iliyojulikana - Msururu wa URI au None kwa grafu zote. +`user`: Kitambulisho cha mtumiaji/nafasi (hiari). +`collection`: Kitambulisho cha mkusanyiko (hiari). +`limit`: Matokeo ya kiwango cha juu ya kurudishwa (kiwango chachilia: 100). +`**kwargs`: Vigezo vya ziada vilivyopitishwa kwa huduma. + +**Inarudisha:** Orodha[Dict]: Orodha ya tripli zinazolingana katika muundo wa msingi. + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s="http://example.org/person/marie-curie", + user="trustgraph", + collection="scientists" +) + +# Query with named graph filter +triples = flow.triples_query( + s="urn:trustgraph:session:abc123", + g="urn:graph:retrieval", + user="trustgraph", + collection="default" +) +``` + +### `triples_query_stream(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, batch_size: int = 20, **kwargs: Any) -> Iterator[List[Dict[str, Any]]]` + +Tafuta tripla za grafu ya maarifa kwa kutumia mikondo ya data. + +Hutoa mikondo ya tripla kadri zinavyofika, na hivyo kupunguza muda wa kupata matokeo ya kwanza +na matumizi ya kumbukumbu kwa matokeo makubwa. + +**Vigezo:** + +`s`: Kichujio cha mada - Msururu wa URI, kamusi ya neno, au None kwa kichujio cha wote. +`p`: Kichujio cha sifa - Msururu wa URI, kamusi ya neno, au None kwa kichujio cha wote. +`o`: Kichujio cha kitu - Msururu wa URI/lita, kamusi ya neno, au None kwa kichujio cha wote. +`g`: Kichujio cha grafu iliyojulikana - Msururu wa URI au None kwa grafu zote. +`user`: Kitambulisho cha mtumiaji/nafasi (hiari). +`collection`: Kitambulisho cha mkusanyiko (hiari). +`limit`: Matokeo mengi ya kurejesha (ya kawaida: 100). +`batch_size`: Tripla kwa kila kikundi (ya kawaida: 20). +`**kwargs`: Vigezo vya ziada vilivyopitishwa kwa huduma. +`Yields`: +`List[Dict]`: Mikundi ya tripla katika umbizo la mawasiliano. + +**Mfano:** + +```python +socket = api.socket() +flow = socket.flow("default") + +for batch in flow.triples_query_stream( + user="trustgraph", + collection="default" +): + for triple in batch: + print(triple["s"], triple["p"], triple["o"]) +``` + + +-- + +## `AsyncSocketClient` + +```python +from trustgraph.api import AsyncSocketClient +``` + +Mteja wa WebSocket asinkroni. + +### Mbinu + +### `__init__(self, url: str, timeout: int, token: str | None)` + +Anzisha `self`. Angalia `help(type(self))` kwa maelezo sahihi ya muundo. + +### `aclose(self)` + +Funga muunganisho wa WebSocket. + +### `flow(self, flow_id: str)` + +Pata mfumo wa kazi asinkroni kwa operesheni za WebSocket. + + +-- + +## `AsyncSocketFlowInstance` + +```python +from trustgraph.api import AsyncSocketFlowInstance +``` + +Mfumo wa mtiririko wa WebSocket usiohusisha wakati. + +### Mbinu + +### `__init__(self, client: trustgraph.api.async_socket_client.AsyncSocketClient, flow_id: str)` + +Anzisha `self`. Angalia `help(type(self))` kwa maelezo sahihi ya jinsi ya kutumia. + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: list | None = None, streaming: bool = False, **kwargs) -> Dict[str, Any] | AsyncIterator` + +Wakala na utiririshaji wa hiari. + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs)` + +Andika RAG (Retrieval-Augmented Generation) na utiririshaji wa hiari. + +### `embeddings(self, texts: list, **kwargs)` + +Tengeneza ufichishaji wa maandishi. + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs)` + +Tafuta ufichishaji wa grafu kwa utafutaji wa maana. + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs)` + +Grafu RAG na utiririshaji wa hiari. + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs)` + +Endesha zana ya MCP. + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs)` + +Endesha ombi na utiririshaji wa hiari. + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs)` + +Tafuta ufichishaji wa mistari kwa utafutaji wa maana kwenye data iliyopangwa. + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs)` + +Ombi la GraphQL dhidi ya mistari iliyopangwa. + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs)` + +Kukamilisha maandishi na utiririshaji wa hiari. + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs)` + +Uchunguzi wa muundo wa tatu. + + +-- + +### `build_term(value: Any, term_type: str | None = None, datatype: str | None = None, language: str | None = None) -> Dict[str, Any] | None` + +Jenga kamusi ya Term ya muundo kutoka kwa thamani. + +Kanuni za utambuzi wa kiotomatiki (wakati `term_type` ni `None`): + Tayari ni kamusi yenye ufunguo 't' -> irudishe kama ilivyo (tayari ni Term) + Inaanzia na http://, https://, urn: -> IRI + Imezungushwa ndani ya <> (e.g., ) -> IRI (brashi za pembe zimeondolewa) + Kila kitu kingine -> literal + +**Majadiliano:** + +`value`: Thamani ya Term (mfululizo, kamusi, au `None`) +`term_type`: Moja kati ya 'iri', 'literal', au `None` kwa utambuzi wa kiotomatiki +`datatype`: Aina ya data kwa vitu vya literal (e.g., xsd:integer) +`language`: Lango la lugha kwa vitu vya literal (e.g., en) + +**Inarudisha:** kamusi: Kamusi ya Term ya muundo, au `None` ikiwa thamani ni `None` + + +-- + +## `BulkClient` + +```python +from trustgraph.api import BulkClient +``` + +Mteja wa operesheni za wingi za wakati mmoja kwa uagizaji/utoaji. + +Hutoa uhamishaji wa data wa wingi unaofaa kupitia WebSocket kwa data kubwa. +Huweka operesheni za WebSocket za asinkroni na jenereta za wakati mmoja ili kupunguza ugumu. + +Kumbuka: Kwa usaidizi halisi wa asinkroni, tumia AsyncBulkClient badala yake. + +### Mbinu + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Anzisha mteja wa wingi wa wakati mmoja. + +**Majadilisho:** + +`url`: URL ya msingi kwa API ya TrustGraph (HTTP/HTTPS itabadilishwa kuwa WS/WSS) +`timeout`: Muda wa timeout wa WebSocket kwa sekunde +`token`: Tokeni ya kuhifadhiwa ya hiari kwa uthibitishaji + +### `close(self) -> None` + +Funga miunganisho + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Toa nakala za uainishaji kutoka kwa mtiririko. + +Inapakua kwa ufanisi uainishaji wote wa vipande vya nyaraka kupitia utiririshaji wa WebSocket. + +**Majadilisho:** + +`flow`: Kitambulisho cha mtiririko +`**kwargs`: Vigezo vya ziada (hifadhiwa kwa matumizi ya baadaye) + +**Inarudisha:** Iterator[Dict[str, Any]]: Msururu wa kamusi za uainishaji + +**Mfano:** + +```python +bulk = api.bulk() + +# Export and process document embeddings +for embedding in bulk.export_document_embeddings(flow="default"): + chunk_id = embedding.get("chunk_id") + vector = embedding.get("embedding") + print(f"{chunk_id}: {len(vector)} dimensions") +``` + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Uhamisho wa wingi wa muktadha wa vitu kutoka kwa mtiririko. + +Inapakua habari yote ya muktadha wa vitu kwa ufanisi kupitia utiririshaji wa WebSocket. + +**Vigezo:** + +`flow`: Kitambulisho cha mtiririko +`**kwargs`: Vigezo vya ziada (hifadhiwa kwa matumizi ya baadaye) + +**Inarudisha:** Iterator[Dict[str, Any]]: Msururu wa kamusi za muktadha + +**Mfano:** + +```python +bulk = api.bulk() + +# Export and process entity contexts +for context in bulk.export_entity_contexts(flow="default"): + entity = context.get("entity") + text = context.get("context") + print(f"{entity}: {text[:100]}...") +``` + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Uhamisho wa wingi wa maandamano ya grafu kutoka kwa mtiririko. + +Inapakua kwa ufanisi maandamano yote ya vitu vya grafu kupitia utiririshaji wa WebSocket. + +**Vigezo:** + +`flow`: Kitambulisho cha mtiririko +`**kwargs`: Vigezo vya ziada (hifadhiwa kwa matumizi ya baadaye) + +**Inarudisha:** Iterator[Dict[str, Any]]: Mto wa kamusi za maandamano + +**Mfano:** + +```python +bulk = api.bulk() + +# Export and process embeddings +for embedding in bulk.export_graph_embeddings(flow="default"): + entity = embedding.get("entity") + vector = embedding.get("embedding") + print(f"{entity}: {len(vector)} dimensions") +``` + +### `export_triples(self, flow: str, **kwargs: Any) -> Iterator[trustgraph.api.types.Triple]` + +Uhamisho wa wingi wa data ya RDF kutoka kwa mtiririko. + +Inapakua data yote kwa ufanisi kupitia utiririshaji wa WebSocket. + +**Vigezo:** + +`flow`: Kitambulisho cha mtiririko. +`**kwargs`: Vigezo vya ziada (hifadhiwa kwa matumizi ya baadaye). + +**Inarudisha:** Iterator[Triple]: Mto wa vitu vya Triple. + +**Mfano:** + +```python +bulk = api.bulk() + +# Export and process triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +### `import_document_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Kuleta kwa wingi maandishi ya kuingizwa katika mtiririko. + +Huainisha kwa ufanisi maandishi ya vipande vya maandishi kupitia utiririshaji wa WebSocket +kwa matumizi katika maswali ya RAG ya maandishi. + +**Vigezo:** + +`flow`: Kitambulisho cha mtiririko +`embeddings`: Mfumo unaotoa kamusi za kuingizwa +`**kwargs`: Vigezo vya ziada (hifadhiwa kwa matumizi ya baadaye) + +**Mfano:** + +```python +bulk = api.bulk() + +# Generate document embeddings to import +def doc_embedding_generator(): + yield {"chunk_id": "doc1/p0/c0", "embedding": [0.1, 0.2, ...]} + yield {"chunk_id": "doc1/p0/c1", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_document_embeddings( + flow="default", + embeddings=doc_embedding_generator() +) +``` + +### `import_entity_contexts(self, flow: str, contexts: Iterator[Dict[str, Any]], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +Kuleta kwa wingi maelezo ya vitu ndani ya mtiririko. + +Huwezesha kupakia taarifa za maelezo ya vitu kupitia utiririshaji wa WebSocket. +Maelezo ya vitu hutoa maelezo ya ziada ya maandishi kuhusu vitu vya chati +ili kuboresha utendaji wa RAG. + +**Vigezo:** + +`flow`: Kitambulisho cha mtiririko +`contexts`: Iteratili inayotoa kamusi za maelezo +`metadata`: Kamusi ya metadata yenye id, metadata, mtumiaji, mkusanyiko +`batch_size`: Idadi ya maelezo kwa kila kundi (ya kawaida 100) +`**kwargs`: Vigezo vya ziada (vimehifadhiwa kwa matumizi ya baadaye) + +**Mfano:** + +```python +bulk = api.bulk() + +# Generate entity contexts to import +def context_generator(): + yield {"entity": {"v": "entity1", "e": True}, "context": "Description..."} + yield {"entity": {"v": "entity2", "e": True}, "context": "Description..."} + # ... more contexts + +bulk.import_entity_contexts( + flow="default", + contexts=context_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + +### `import_graph_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Kuleta kwa wingi michoro ya pembejeo katika mtiririko. + +Huainisha kwa ufanisi pembejeo za michoro kupitia utiririshaji wa WebSocket. + +**Vigezo:** + +`flow`: Kitambulisho cha mtiririko +`embeddings`: Mfuatiliao unaotoa kamusi za pembejeo +`**kwargs`: Vigezo vya ziada (hifadhiwa kwa matumizi ya baadaye) + +**Mfano:** + +```python +bulk = api.bulk() + +# Generate embeddings to import +def embedding_generator(): + yield {"entity": "entity1", "embedding": [0.1, 0.2, ...]} + yield {"entity": "entity2", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_graph_embeddings( + flow="default", + embeddings=embedding_generator() +) +``` + +### `import_rows(self, flow: str, rows: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Kuingiza kwa wingi mistari iliyoandaliwa katika mtiririko. + +Inapakia data iliyoandaliwa kwa ufanisi kupitia utiririshaji wa WebSocket +kwa ajili ya matumizi katika maswali ya GraphQL. + +**Vigezo:** + +`flow`: Kitambulisho cha mtiririko +`rows`: Mfuatiliazo unaotoa kamusi za mistari +`**kwargs`: Vigezo vya ziada (hifadhiwa kwa matumizi ya baadaye) + +**Mfano:** + +```python +bulk = api.bulk() + +# Generate rows to import +def row_generator(): + yield {"id": "row1", "name": "Row 1", "value": 100} + yield {"id": "row2", "name": "Row 2", "value": 200} + # ... more rows + +bulk.import_rows( + flow="default", + rows=row_generator() +) +``` + +### `import_triples(self, flow: str, triples: Iterator[trustgraph.api.types.Triple], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +Uingizaji wa jumla wa triplet za RDF katika mtiririko. + +Huainisha triplet nyingi kwa ufanisi kupitia utiririshaji wa WebSocket. + +**Vigezo:** + +`flow`: Kitambulisho cha mtiririko +`triples`: Itereta inayotoa vitu vya Triple +`metadata`: Kamusi ya metadata yenye id, metadata, mtumiaji, mkusanyiko +`batch_size`: Idadi ya triplet kwa kila kundi (ya kawaida 100) +`**kwargs`: Vigezo vya ziada (vimehifadhiwa kwa matumizi ya baadaye) + +**Mfano:** + +```python +from trustgraph.api import Triple + +bulk = api.bulk() + +# Generate triples to import +def triple_generator(): + yield Triple(s="subj1", p="pred", o="obj1") + yield Triple(s="subj2", p="pred", o="obj2") + # ... more triples + +# Import triples +bulk.import_triples( + flow="default", + triples=triple_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + + +-- + +## `AsyncBulkClient` + +```python +from trustgraph.api import AsyncBulkClient +``` + +Mteja wa operesheni za wingi zisizo za wakati. + +### Mbinu + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Anzisha `self`. Angalia `help(type(self))` kwa maelezo sahihi ya muundo. + +### `aclose(self) -> None` + +Funga miunganisho. + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +Uhamisho wa wingi wa maandishi ya nyaraka kupitia WebSocket. + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +Uhamisho wa wingi wa muktadha wa vitu kupitia WebSocket. + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +Uhamisho wa wingi wa maandishi ya chati kupitia WebSocket. + +### `export_triples(self, flow: str, **kwargs: Any) -> AsyncIterator[trustgraph.api.types.Triple]` + +Uhamisho wa wingi wa triplet kupitia WebSocket. + +### `import_document_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Uingizaji wa wingi wa maandishi ya nyaraka kupitia WebSocket. + +### `import_entity_contexts(self, flow: str, contexts: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Uingizaji wa wingi wa muktadha wa vitu kupitia WebSocket. + +### `import_graph_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Uingizaji wa wingi wa maandishi ya chati kupitia WebSocket. + +### `import_rows(self, flow: str, rows: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +Uingizaji wa wingi wa mistari kupitia WebSocket. + +### `import_triples(self, flow: str, triples: AsyncIterator[trustgraph.api.types.Triple], **kwargs: Any) -> None` + +Uingizaji wa wingi wa triplet kupitia WebSocket. + + +-- + +## `Metrics` + +```python +from trustgraph.api import Metrics +``` + +Mteja wa metriki za wakati mmoja. + +### Mbinu + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Anzisha `self`. Angalia `help(type(self))` kwa maelezo sahihi ya muundo. + +### `get(self) -> str` + +Pata metriki za Prometheus kama maandishi. + + +-- + +## `AsyncMetrics` + +```python +from trustgraph.api import AsyncMetrics +``` + +Mteja wa metriki zisizo za wakati (asynchronous). + +### Mbinu (Methods) + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Anzisha (Initialize) `self`. Angalia `help(type(self))` kwa maelezo sahihi ya muundo. + +### `aclose(self) -> None` + +Funga miunganisho (Close connections). + +### `get(self) -> str` + +Pata metriki za Prometheus kama maandishi (Get Prometheus metrics as text). + + +-- + +## `ExplainabilityClient` + +```python +from trustgraph.api import ExplainabilityClient +``` + +Mteja wa kupata vitu vya uhalisia kwa utaratibu wa utangamano wa mwisho. + +Hutumia utambuzi wa utulivu: pata, subiri, pata tena, linganisha. +Ikiwa matokeo ni sawa, data ni thabiti. + +### Mbinu + +### `__init__(self, flow_instance, retry_delay: float = 0.2, max_retries: int = 10)` + +Anzisha mteja wa uhalisia. + +**Majadiliano:** + +`flow_instance`: Toleo la SocketFlowInstance kwa kuuliza vitatu. +`retry_delay`: Kuchelewesha kati ya majaribio katika sekunde (kiwango chote: 0.2). +`max_retries`: Jaribio la juu zaidi (kiwango chote: 10). + +### `detect_session_type(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> str` + +Thibitisha ikiwa kikao ni cha aina ya GraphRAG au Agent. + +**Vigezo:** + +`session_uri`: URI ya kipindi/swali +`graph`: Grafu iliyopewa jina +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko + +**Inarudisha:** "graphrag" au "agent" + +### `fetch_agent_trace(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Pata faili kamili ya "Agent" kuanzia URI ya kipindi. + +Fuata mnyororo wa asili: Swali -> Uchambuzi(s) -> Hitimisho + +**Vigezo:** + +`session_uri`: URI ya kipindi cha "agent"/swali +`graph`: Grafu iliyopewa jina (ya kawaida: urn:graph:retrieval) +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`api`: Ena ya TrustGraph API kwa ufikiaji wa "librarian" (hiari) +`max_content`: Urefu wa juu wa maudhui kwa hitimisho + +**Inarudi:** Kamusi yenye swali, mara (Orodha ya uchambuzi), na vitu vya hitimisho. + +### `fetch_docrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Kuchukua faili kamili ya "DocumentRAG" kuanzia URI ya swali. + +Kufuata mnyororo wa asili: + Swali -> Msingi -> Uchunguzi -> Muunganisho + +**Majadiliano:** + +`question_uri`: URI ya swali. +`graph`: Grafu iliyoitwa (ya kawaida: urn:graph:retrieval). +`user`: Kitambulisho cha mtumiaji/nafasi. +`collection`: Kitambulisho cha mkusanyiko. +`api`: Eneo la TrustGraph API kwa ufikiaji wa "librarian" (hiari). +`max_content`: Urefu wa juu wa yaliyomo kwa muunganisho. + +**Inarudi:** Kamusi yenye swali, msingi, uchunguzi, na vitu vya muunganisho. + +### `fetch_document_content(self, document_uri: str, api: Any, user: str | None = None, max_content: int = 10000) -> str` + +Kuchukua yaliyomo kutoka kwa "librarian" kwa URI ya hati. + +**Majadiliano:** + +`document_uri`: URI ya hati katika "librarian". +`api`: Eneo la TrustGraph API kwa ufikiaji wa "librarian". +`user`: Kitambulisho cha mtumiaji kwa "librarian". +`max_content`: Urefu wa juu wa yaliyomo yanayorudishwa. + +**Inarudi:** Yaliyomo ya hati kama mfululizo. + +### `fetch_edge_selection(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.EdgeSelection | None` + +Kuchukua kitambulisho cha uchaguzi wa "edge" (kinachotumika na Focus). + +**Majadiliano:** + +`uri`: URI ya uchaguzi wa "edge". +`graph`: Grafu iliyoitwa ya kuchunguza. +`user`: Kitambulisho cha mtumiaji/nafasi. +`collection`: Kitambulisho cha mkusanyiko. + +**Inarudi:** EdgeSelection au None ikiwa haipatikani. + +### `fetch_entity(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.ExplainEntity | None` + +Kuchukua na kueleza kitu (entity) kwa kutumia URI, na kusimamia utaratibu wa uthabiti. + +Hutumia utambuzi wa utulivu: +1. Kuchukua data (triples) kwa URI +2. Ikiwa hakuna matokeo, jaribu tena +3. Ikiwa kuna matokeo, subiri na chukua tena +4. Ikiwa matokeo ni sawa, data imetulia - changanua na urudishe +5. Ikiwa matokeo ni tofauti, data bado inaanzishwa - jaribu tena + +**Vigezo:** + +`uri`: URI ya kitu (entity) kinachohitajika +`graph`: Picha (graph) inayotumika kwa utafutaji (e.g., "urn:graph:retrieval") +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko + +**Inarudisha:** Kifaa cha aina ya ExplainEntity au None ikiwa haipatikani + +### `fetch_focus_with_edges(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.Focus | None` + +Kuchukua kitu (entity) cha "Focus" na uteuzi wake wote wa "edge". + +**Vigezo:** + +`uri`: URI ya kitu (entity) cha "Focus" +`graph`: Picha (graph) inayotumika kwa utafutaji +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko + +**Inarudisha:** "Focus" iliyo na "edge_selections" zilizojazwa, au None + +### `fetch_graphrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Kuchukua "GraphRAG" kamili kuanzia URI ya swali. + +Ifuatilia mnyororo wa asili: Swali -> Uthabiti -> Uchunguzi -> Focus -> Muhtasari + +**Vigezo:** + +`question_uri`: URI ya swali +`graph`: Picha (default: urn:graph:retrieval) +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`api`: Ena ya TrustGraph API kwa ufikiaji wa "librarian" (hiari) +`max_content`: Urefu wa juu wa yaliyomo kwa ajili ya muhtasari + +**Inarudisha:** Kamusi yenye vitu vya swali, msingi, uchunguzi, lengo, na muhtasari. + +### `list_sessions(self, graph: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 50) -> List[trustgraph.api.explainability.Question]` + +Orodha ya vipindi vyote vya kufafanua (maswali) katika mkusanyiko. + +**Majadiliano:** + +`graph`: Picha iliyopewa jina (ya kawaida: urn:graph:retrieval) +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko +`limit`: Nambari ya juu ya vipindi kurudishwa + +**Inarudisha:** Orodha ya vitu vya Swali vilivyopangwa kwa wakati (vya hivi karibuni kwanza) + +### `resolve_edge_labels(self, edge: Dict[str, str], user: str | None = None, collection: str | None = None) -> Tuple[str, str, str]` + +Tatua lebo kwa vipengele vyote vya triplet ya ukingo. + +**Majadiliano:** + +`edge`: Kamusi yenye funguo za "s", "p", na "o" +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko + +**Inarudisha:** Jozi ya (s_label, p_label, o_label) + +### `resolve_label(self, uri: str, user: str | None = None, collection: str | None = None) -> str` + +Tatua rdfs:label kwa URI, pamoja na kuhifadhi. + +**Majadiliano:** + +`uri`: URI ambayo lebo inapaswa kupatikana +`user`: Kitambulisho cha mtumiaji/nafasi +`collection`: Kitambulisho cha mkusanyiko + +**Inarudisha:** Lebo ikiwa imepatikana, vinginevyo URI yenyewe. + + +-- + +## `ExplainEntity` + +```python +from trustgraph.api import ExplainEntity +``` + +Darasa la msingi kwa vitu vya uelewaji. + +**Vipengele:** + +`uri`: +`entity_type`: + +### Mbinu + +### `__init__(self, uri: str, entity_type: str = '') -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi. + + +-- + +## `Question` + +```python +from trustgraph.api import Question +``` + +Swali la mtumiaji - swali la mtumiaji ambalo lilianzisha kipindi. + +**Vifaa:** + +`uri`: +`entity_type`: +`query`: +`timestamp`: +`question_type`: + +### Mbinu + +### `__init__(self, uri: str, entity_type: str = '', query: str = '', timestamp: str = '', question_type: str = '') -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi. + + +-- + +## `Exploration` + +```python +from trustgraph.api import Exploration +``` + +Kitengo cha utafiti - pembejeo/sehemu zilizopatikana kutoka kwenye hifadhi ya maarifa. + +**Vifaa:** + +`uri`: +`entity_type`: +`edge_count`: +`chunk_count`: +`entities`: typing.List[str] + +### Mbinu + +### `__init__(self, uri: str, entity_type: str = '', edge_count: int = 0, chunk_count: int = 0, entities: List[str] = ) -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `Focus` + +```python +from trustgraph.api import Focus +``` + +Mfumo wa msingi - pembe zilizochaguliwa pamoja na utaratibu wa akili wa LLM (GraphRAG pekee). + +**Sehemu:** + +`uri`: +`entity_type`: +`selected_edge_uris`: typing.List[str] +`edge_selections`: typing.List[trustgraph.api.explainability.EdgeSelection] + +### Mbinu + +### `__init__(self, uri: str, entity_type: str = '', selected_edge_uris: List[str] = , edge_selections: List[trustgraph.api.explainability.EdgeSelection] = ) -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `Synthesis` + +```python +from trustgraph.api import Synthesis +``` + +Kitengo cha muhtasari - jibu la mwisho. + +**Sehemu:** + +`uri`: +`entity_type`: +`document`: + +### Mbinu + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi. + + +-- + +## `Analysis` + +```python +from trustgraph.api import Analysis +``` + +Kitengo cha uchambuzi - mzunguko mmoja wa kufikiria/kutenda/kuchunguza (Kwa wakala pekee). + +**Vyunzo:** + +`uri`: +`entity_type`: +`action`: +`arguments`: +`thought`: +`observation`: + +### Mbinu + +### `__init__(self, uri: str, entity_type: str = '', action: str = '', arguments: str = '', thought: str = '', observation: str = '') -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `Conclusion` + +```python +from trustgraph.api import Conclusion +``` + +Hitimisho la kitengo - jibu la mwisho (Kwa wakala pekee). + +**Sehemu:** + +`uri`: +`entity_type`: +`document`: + +### Mbinu + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi. + + +-- + +## `EdgeSelection` + +```python +from trustgraph.api import EdgeSelection +``` + +Kichwa kilichochaguliwa pamoja na hoja kutoka hatua ya GraphRAG Focus. + +**Sehemu:** + +`uri`: +`edge`: typing.Dict[str, str] | None +`reasoning`: + +### Mbinu + +### `__init__(self, uri: str, edge: Dict[str, str] | None = None, reasoning: str = '') -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +### `wire_triples_to_tuples(wire_triples: List[Dict[str, Any]]) -> List[Tuple[str, str, Any]]` + +Badilisha triplet katika umbizo la waya kuwa tuples za (s, p, o). + + +-- + +### `extract_term_value(term: Dict[str, Any]) -> Any` + +Toa thamani kutoka kwenye kamusi ya Term katika umbizo la waya. + + +-- + +## `Triple` + +```python +from trustgraph.api import Triple +``` + +Mfumo wa data wa RDF unaoonyesha sentensi ya grafu ya maarifa. + +**Sehemu:** + +`s`: +`p`: +`o`: + +### Mbinu + +### `__init__(self, s: str, p: str, o: str) -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `Uri` + +```python +from trustgraph.api import Uri +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +Unda mnyororo mpya kutoka kwa kitu kilichopewa. Ikiwa encoding au +errors imebainishwa, basi kitu lazima kiwe na buffer ya data +ambayo itafichuliwa kwa kutumia encoding iliyopewa na kidhibiti cha makosa. +Vinginevyo, hurudia matokeo ya kitu.__str__() (ikiwa imefafanuliwa) +au repr(kitu). +encoding huwezeshwa kuwa 'utf-8'. +errors huwezeshwa kuwa 'strict'. + +### Mbinu + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `Literal` + +```python +from trustgraph.api import Literal +``` + +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +Unda mnyororo mpya kutoka kwa kitu kilichopewa. Ikiwa encoding au +errors imebainishwa, basi kitu lazima kiwe na buffer ya data +ambayo itafichuliwa kwa kutumia usimbaji (encoding) na kidhibiti cha makosa (error handler) uliobainishwa. +Vinginevyo, hurudia matokeo ya kitu.__str__() (ikiwa imefafanuliwa) +au repr(object). +usimbaji (encoding) huanguka kwa 'utf-8'. +makosa (errors) huanguka kwa 'strict'. + +### Mbinu + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `ConfigKey` + +```python +from trustgraph.api import ConfigKey +``` + +Kitambulisho cha ufunguo wa usanidi. + +**Sehemu:** + +`type`: +`key`: + +### Mbinu + +### `__init__(self, type: str, key: str) -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi. + + +-- + +## `ConfigValue` + +```python +from trustgraph.api import ConfigValue +``` + +Jozi ya ufunguo na thamani ya usanidi. + +**Sehemu:** + +`type`: +`key`: +`value`: + +### Mbinu + +### `__init__(self, type: str, key: str, value: str) -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi. + + +-- + +## `DocumentMetadata` + +```python +from trustgraph.api import DocumentMetadata +``` + +Meta data kwa hati katika maktaba. + +**Sifa:** + +`parent_id: Parent document ID for child documents (empty for top`: ngazi ya hati + +**Nafasi:** + +`id`: +`time`: +`kind`: +`title`: +`comments`: +`metadata`: typing.List[trustgraph.api.types.Triple] +`user`: +`tags`: typing.List[str] +`parent_id`: +`document_type`: + +### Mbinu + +### `__init__(self, id: str, time: datetime.datetime, kind: str, title: str, comments: str, metadata: List[trustgraph.api.types.Triple], user: str, tags: List[str], parent_id: str = '', document_type: str = 'source') -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `ProcessingMetadata` + +```python +from trustgraph.api import ProcessingMetadata +``` + +Meta data kwa kazi ya usindikaji hati inayofanya kazi. + +**Vyunzo:** + +`id`: +`document_id`: +`time`: +`flow`: +`user`: +`collection`: +`tags`: typing.List[str] + +### Mbinu + +### `__init__(self, id: str, document_id: str, time: datetime.datetime, flow: str, user: str, collection: str, tags: List[str]) -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `CollectionMetadata` + +```python +from trustgraph.api import CollectionMetadata +``` + +Meta data kwa mkusanyiko wa data. + +Mikusanyiko hutoa uainishaji na kutenganisha kwa mantiki kwa hati na +data ya mfumo wa maarifa. + +**Sifa:** + +`name: Human`: jina la mkusanyiko linalosoma + +**Nafasi:** + +`user`: +`collection`: +`name`: +`description`: +`tags`: typing.List[str] + +### Mbinu + +### `__init__(self, user: str, collection: str, name: str, description: str, tags: List[str]) -> None` + +Anzisha self. Angalia help(type(self)) kwa saini sahihi. + + +-- + +## `StreamingChunk` + +```python +from trustgraph.api import StreamingChunk +``` + +Darasa la msingi kwa ajili ya vipande vya majibu yanayotumwa. + +Hutumika kwa operesheni za utiririshaji zinazotegemea WebSocket ambapo majibu hutolewa +hatua kwa hatua yanapozalishwa. + +**Vipengele:** + +`content`: +`end_of_message`: + +### Njia + +### `__init__(self, content: str, end_of_message: bool = False) -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi. + + +-- + +## `AgentThought` + +```python +from trustgraph.api import AgentThought +``` + +Sehemu ya hoja au mchakato wa kufikiri wa wakala. + +Inawakilisha hoja au hatua za upangaji za ndani za wakala wakati wa utekelezaji. +Sehemu hizi zinaonyesha jinsi wakala anavyofikiri kuhusu tatizo. + +**Vifaa:** + +`content`: +`end_of_message`: +`chunk_type`: + +### Mbinu + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'thought') -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `AgentObservation` + +```python +from trustgraph.api import AgentObservation +``` + +Sehemu ya matokeo au uchunguzi wa matumizi ya zana. + +Inawakilisha matokeo au uchunguzi kutoka kwa matumizi ya zana au kitendo. +Sehemu hizi zinaonyesha kile ambacho wakala alijifunza kutokana na matumizi ya zana. + +**Vifaa:** + +`content`: +`end_of_message`: +`chunk_type`: + +### Mbinu + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'observation') -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `AgentAnswer` + +```python +from trustgraph.api import AgentAnswer +``` + +Sehemu ya jibu la mwisho la wakala. + +Inawakilisha jibu la mwisho la wakala kwa swali la mtumiaji baada ya kukamilisha +utaratibu wake na matumizi ya zana. + +**Sifa:** + +`chunk_type: Always "final`: jibu" + +**Nafasi:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_dialog`: + +### Mbinu + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'final-answer', end_of_dialog: bool = False) -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `RAGChunk` + +```python +from trustgraph.api import RAGChunk +``` + +Sehemu inayotumika kwa utiririshaji ya RAG (Uundaji Ulioboreshwa na Urekebishaji). + +Inatumika kwa utiririshaji wa majibu kutoka kwa RAG ya grafu, RAG ya hati, kukamilisha maandishi, +na huduma zingine za uundaji. + +**Vipengele:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_stream`: +`error`: typing.Dict[str, str] | None + +### Mbinu + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'rag', end_of_stream: bool = False, error: Dict[str, str] | None = None) -> None` + +Anzisha self. Angalia help(type(self)) kwa maelezo sahihi ya muundo. + + +-- + +## `ProvenanceEvent` + +```python +from trustgraph.api import ProvenanceEvent +``` + +Tukio la asili kwa ajili ya uelewaji. + +Hutolewa wakati wa maswali ya GraphRAG wakati hali ya uelewaji imeanzishwa. +Kila tukio linawakilisha nodi ya asili iliyoundwa wakati wa uchakataji wa swali. + +**Vifaa:** + +`explain_id`: +`explain_graph`: +`event_type`: + +### Mbinu + +### `__init__(self, explain_id: str, explain_graph: str = '', event_type: str = '') -> None` + +Anzisha self. Angalia help(type(self)) kwa ajili ya saini sahihi. + + +-- + +## `ProtocolException` + +```python +from trustgraph.api import ProtocolException +``` + +Inayotokea wakati wa hitilafu za itifaki ya WebSocket. + + +-- + +## `TrustGraphException` + +```python +from trustgraph.api import TrustGraphException +``` + +Darasa la msingi kwa makosa yote ya huduma ya TrustGraph. + + +-- + +## `AgentError` + +```python +from trustgraph.api import AgentError +``` + +Kosa la huduma ya wakala. + + +-- + +## `ConfigError` + +```python +from trustgraph.api import ConfigError +``` + +Kosa la huduma ya usanidi. + + +-- + +## `DocumentRagError` + +```python +from trustgraph.api import DocumentRagError +``` + +Kosa la upokeaji wa hati kutoka kwa mfumo. + + +-- + +## `FlowError` + +```python +from trustgraph.api import FlowError +``` + +Kosa la usimamizi wa mtiririko + + +-- + +## `GatewayError` + +```python +from trustgraph.api import GatewayError +``` + +Kosa la API Gateway + + +-- + +## `GraphRagError` + +```python +from trustgraph.api import GraphRagError +``` + +Kosa la urejesho la mfumo wa RAG. + + +-- + +## `LLMError` + +```python +from trustgraph.api import LLMError +``` + +Kosa la huduma ya LLM. + + +-- + +## `LoadError` + +```python +from trustgraph.api import LoadError +``` + +Kosa la kupakia data. + + +-- + +## `LookupError` + +```python +from trustgraph.api import LookupError +``` + +Kosa la utafutaji/tazama. + + +-- + +## `NLPQueryError` + +```python +from trustgraph.api import NLPQueryError +``` + +Kosa la huduma ya utafutaji kwa lugha. + + +-- + +## `RowsQueryError` + +```python +from trustgraph.api import RowsQueryError +``` + +Kosa la huduma ya utafutaji wa data. + + +-- + +## `RequestError` + +```python +from trustgraph.api import RequestError +``` + +Kosa katika usindikaji wa ombi. + + +-- + +## `StructuredQueryError` + +```python +from trustgraph.api import StructuredQueryError +``` + +Kosa la huduma ya maswali iliyopangwa. + + +-- + +## `UnexpectedError` + +```python +from trustgraph.api import UnexpectedError +``` + +Kosa lisilotarajiwa/lisilojulikana. + + +-- + +## `ApplicationException` + +```python +from trustgraph.api import ApplicationException +``` + +Darasa la msingi kwa makosa yote ya huduma ya TrustGraph. + + +-- + diff --git a/docs/python-api.tr.md b/docs/python-api.tr.md new file mode 100644 index 00000000..df37b744 --- /dev/null +++ b/docs/python-api.tr.md @@ -0,0 +1,4071 @@ +# TrustGraph Python API Referansı + +## Kurulum + +```bash +pip install trustgraph +``` + +## Hızlı Başlangıç + +Tüm sınıflar ve tipler, `trustgraph.api` paketinden içe aktarılmıştır: + +```python +from trustgraph.api import Api, Triple, ConfigKey + +# Create API client +api = Api(url="http://localhost:8088/") + +# Get a flow instance +flow = api.flow().id("default") + +# Execute a graph RAG query +response = flow.graph_rag( + query="What are the main topics?", + user="trustgraph", + collection="default" +) +``` + +## İçindekiler + +### Çekirdek + +[Api](#api) + +### Akış İstemcileri + +[Flow](#flow) +[FlowInstance](#flowinstance) +[AsyncFlow](#asyncflow) +[AsyncFlowInstance](#asyncflowinstance) + +### WebSocket İstemcileri + +[SocketClient](#socketclient) +[SocketFlowInstance](#socketflowinstance) +[AsyncSocketClient](#asyncsocketclient) +[AsyncSocketFlowInstance](#asyncsocketflowinstance) + +### Toplu İşlemler + +[BulkClient](#bulkclient) +[AsyncBulkClient](#asyncbulkclient) + +### Metrikler + +[Metrics](#metrics) +[AsyncMetrics](#asyncmetrics) + +### Veri Tipleri + +[Triple](#triple) +[ConfigKey](#configkey) +[ConfigValue](#configvalue) +[DocumentMetadata](#documentmetadata) +[ProcessingMetadata](#processingmetadata) +[CollectionMetadata](#collectionmetadata) +[StreamingChunk](#streamingchunk) +[AgentThought](#agentthought) +[AgentObservation](#agentobservation) +[AgentAnswer](#agentanswer) +[RAGChunk](#ragchunk) + +### İstisnalar + +[ProtocolException](#protocolexception) +[TrustGraphException](#trustgraphexception) +[AgentError](#agenterror) +[ConfigError](#configerror) +[DocumentRagError](#documentragerror) +[FlowError](#flowerror) +[GatewayError](#gatewayerror) +[GraphRagError](#graphragerror) +[LLMError](#llmerror) +[LoadError](#loaderror) +[LookupError](#lookuperror) +[NLPQueryError](#nlpqueryerror) +[RowsQueryError](#rowsqueryerror) +[RequestError](#requesterror) +[StructuredQueryError](#structuredqueryerror) +[UnexpectedError](#unexpectederror) +[ApplicationException](#applicationexception) + +-- + +## `Api` + +```python +from trustgraph.api import Api +``` + +Senkron ve asenkron işlemler için ana TrustGraph API istemcisi. + +Bu sınıf, akış yönetimi, +bilgi grafiği işlemleri, belge işleme, RAG sorguları ve daha fazlası dahil olmak üzere tüm TrustGraph hizmetlerine erişim sağlar. Hem REST tabanlı hem de WebSocket tabanlı iletişim modellerini destekler. + + +İstemci, otomatik kaynak temizliği için bir bağlam yöneticisi olarak kullanılabilir: + ```python + with Api(url="http://localhost:8088/") as api: + result = api.flow().id("default").graph_rag(query="test") + ``` + +### Yöntemler + +### `__aenter__(self)` + +Asenkron bağlam yöneticisine girin. + +### `__aexit__(self, *args)` + +Asenkron bağlam yöneticisinden çıkın ve bağlantıları kapatın. + +### `__enter__(self)` + +Senkron bağlam yöneticisine girin. + +### `__exit__(self, *args)` + +Senkron bağlam yöneticisinden çıkın ve bağlantıları kapatın. + +### `__init__(self, url='http://localhost:8088/', timeout=60, token: str | None = None)` + +TrustGraph API istemciyi başlatın. + +**Argümanlar:** + +`url`: TrustGraph API'si için temel URL (varsayılan: "http://localhost:8088/"") +`timeout`: İstek zaman aşımı süresi (saniye cinsinden) (varsayılan: 60) +`token`: İsteğe bağlı doğrulama için taşıyıcı belirteci + +**Örnek:** + +```python +# Local development +api = Api() + +# Production with authentication +api = Api( + url="https://trustgraph.example.com/", + timeout=120, + token="your-api-token" +) +``` + +### `aclose(self)` + +Tüm asenkron istemci bağlantılarını kapatın. + +Bu yöntem, asenkron WebSocket, toplu işlem ve akış bağlantılarını kapatır. +Bu, asenkron bir bağlam yöneticisinden çıkıldığında otomatik olarak çağrılır. + +**Örnek:** + +```python +api = Api() +async_socket = api.async_socket() +# ... use async_socket +await api.aclose() # Clean up connections + +# Or use async context manager (automatic cleanup) +async with Api() as api: + async_socket = api.async_socket() + # ... use async_socket +# Automatically closed +``` + +### `async_bulk(self)` + +Asenkron toplu işlemler istemcisi alın. + +WebSocket üzerinden asenkron/bekleme tarzı toplu içe/dışa aktarma işlemleri sağlar, +böylece büyük veri kümelerinin verimli bir şekilde işlenmesini sağlar. + +**Döndürür:** AsyncBulkClient: Asenkron toplu işlemler istemcisi + +**Örnek:** + +```python +async_bulk = api.async_bulk() + +# Export triples asynchronously +async for triple in async_bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import with async generator +async def triple_gen(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +await async_bulk.import_triples( + flow="default", + triples=triple_gen() +) +``` + +### `async_flow(self)` + +Asenkron, REST tabanlı bir akış istemcisi alın. + +Akış işlemlerine, async/await stili erişim sağlar. Bu, asenkron Python uygulamaları ve çerçeveleri (FastAPI, aiohttp, vb.) için tercih edilir. + + +**Döndürür:** AsyncFlow: Asenkron akış istemcisi + +**Örnek:** + +```python +async_flow = api.async_flow() + +# List flows +flow_ids = await async_flow.list() + +# Execute operations +instance = async_flow.id("default") +result = await instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `async_metrics(self)` + +Asenkron bir metrik istemcisi alın. + +Prometheus metriklerine, async/await tarzında erişim sağlar. + +**Döndürür:** AsyncMetrics: Asenkron metrik istemcisi + +**Örnek:** + +```python +async_metrics = api.async_metrics() +prometheus_text = await async_metrics.get() +print(prometheus_text) +``` + +### `async_socket(self)` + +Akış işlemleri için asenkron bir WebSocket istemcisi alın. + +Akış desteği ile asenkron/bekleme tarzı WebSocket erişimi sağlar. +Bu, Python'da asenkron akış için tercih edilen yöntemdir. + +**Döndürür:** AsyncSocketClient: Asenkron WebSocket istemcisi + +**Örnek:** + +```python +async_socket = api.async_socket() +flow = async_socket.flow("default") + +# Stream agent responses +async for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + +### `bulk(self)` + +İçe/dışa aktarım için senkron toplu işlemler istemcisi alın. + +Toplu işlemler, üçlüler, gömülü veriler, varlık bağlamları ve nesneler dahil olmak üzere büyük veri kümelerinin WebSocket bağlantıları aracılığıyla verimli bir şekilde aktarılmasını sağlar. + +**Döndürür:** BulkClient: Senkron toplu işlemler istemcisi + +**Örnek:** + + +```python +bulk = api.bulk() + +# Export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} {triple.p} {triple.o}") + +# Import triples +def triple_generator(): + yield Triple(s="subj", p="pred", o="obj") + # ... more triples + +bulk.import_triples(flow="default", triples=triple_generator()) +``` + +### `close(self)` + +Tüm senkronize istemci bağlantılarını kapatın. + +Bu yöntem, WebSocket ve toplu işlem bağlantılarını kapatır. +Bir bağlam yöneticisinden çıkılırken otomatik olarak çağrılır. + +**Örnek:** + +```python +api = Api() +socket = api.socket() +# ... use socket +api.close() # Clean up connections + +# Or use context manager (automatic cleanup) +with Api() as api: + socket = api.socket() + # ... use socket +# Automatically closed +``` + +### `collection(self)` + +Veri koleksiyonlarını yönetmek için bir Collection istemcisi alın. + +Koleksiyonlar, belgeleri ve bilgi grafiği verilerini, +izolasyon ve erişim kontrolü için mantıksal gruplara ayırır. + +**Döndürür:** Collection: Koleksiyon yönetimi istemcisi + +**Örnek:** + +```python +collection = api.collection() + +# List collections +colls = collection.list_collections(user="trustgraph") + +# Update collection metadata +collection.update_collection( + user="trustgraph", + collection="default", + name="Default Collection", + description="Main data collection" +) +``` + +### `config(self)` + +Yapılandırma ayarlarını yönetmek için bir Config istemcisi alın. + +**Döndürür:** Config: Yapılandırma yönetimi istemcisi + +**Örnek:** + +```python +config = api.config() + +# Get configuration values +values = config.get([ConfigKey(type="llm", key="model")]) + +# Set configuration +config.put([ConfigValue(type="llm", key="model", value="gpt-4")]) +``` + +### `flow(self)` + +Akışları yönetmek ve etkileşim kurmak için bir Flow istemcisi edinin. + +Akışlar, TrustGraph'ta birincil yürütme birimleridir ve ajanlar, RAG sorguları, gömme ve belge işleme gibi +hizmetlere erişim sağlar. + +**Döndürür:** Flow: Akış yönetimi istemcisi + +**Örnek:** + +```python +flow_client = api.flow() + +# List available blueprints +blueprints = flow_client.list_blueprints() + +# Get a specific flow instance +flow_instance = flow_client.id("default") +response = flow_instance.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `knowledge(self)` + +Bilgi grafiği çekirdeklerini yönetmek için bir Knowledge istemcisi edinin. + +**Döndürür:** Knowledge: Bilgi grafiği yönetimi istemcisi + +**Örnek:** + +```python +knowledge = api.knowledge() + +# List available KG cores +cores = knowledge.list_kg_cores(user="trustgraph") + +# Load a KG core +knowledge.load_kg_core(id="core-123", user="trustgraph") +``` + +### `library(self)` + +Belge yönetimi için bir Kütüphane istemcisi edinin. + +Bu kütüphane, belge depolama, meta veri yönetimi ve +iş akışı koordinasyonu sağlar. + +**Döndürür:** Library: Belge kütüphanesi yönetimi istemcisi + +**Örnek:** + +```python +library = api.library() + +# Add a document +library.add_document( + document=b"Document content", + id="doc-123", + metadata=[], + user="trustgraph", + title="My Document", + comments="Test document" +) + +# List documents +docs = library.get_documents(user="trustgraph") +``` + +### `metrics(self)` + +İzleme için senkron bir ölçüm istemcisi alın. + +İzleme ve gözlemlenebilirlik için TrustGraph hizmetinden Prometheus formatında ölçümleri alır. + +**Döndürür:** Ölçümler: Senkron ölçüm istemcisi + + +**Örnek:** + +```python +metrics = api.metrics() +prometheus_text = metrics.get() +print(prometheus_text) +``` + +### `request(self, path, request)` + +Düşük seviyeli bir REST API isteği yapın. + +Bu yöntem öncelikle dahili kullanım içindir, ancak gerektiğinde doğrudan +API erişimi için kullanılabilir. + +**Argümanlar:** + +`path`: API uç noktası yolu (temel URL'ye göre) +`request`: İstek yükü, bir sözlük olarak + +**Döndürür:** dict: Yanıt nesnesi + +**Hatalar:** + +`ProtocolException`: Yanıt durum kodu 200 değilse veya yanıt JSON değilse +`ApplicationException`: Yanıt bir hata içeriyorsa + +**Örnek:** + +```python +response = api.request("flow", { + "operation": "list-flows" +}) +``` + +### `socket(self)` + +Akış işlemleri için senkron bir WebSocket istemcisi alın. + +WebSocket bağlantıları, gerçek zamanlı yanıtlar için akış desteği sağlar +ajanlardan, RAG sorgularından ve metin tamamlama işlemlerinden. Bu yöntem, WebSocket protokolünün +senkron bir sarmalayıcısını döndürür. + +**Döndürür:** SocketClient: Senkron WebSocket istemcisi + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent( + question="Explain quantum computing", + user="trustgraph", + streaming=True +): + if hasattr(chunk, 'content'): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `Flow` + +```python +from trustgraph.api import Flow +``` + +Blueprint ve akış örneği işlemlerini gerçekleştirmek için kullanılan akış yönetimi istemcisi. + +Bu sınıf, akış blueprint'larını (şablonları) ve +akış örneklerini (çalışan akışları) yönetmek için yöntemler sağlar. Blueprint'ler, akışların yapısını ve +parametrelerini tanımlarken, örnekler, hizmetleri çalıştırabilen aktif akışları temsil eder. + + +### Yöntemler + +### `__init__(self, api)` + +Akış istemcisini başlat. + +**Argümanlar:** + +`api`: İstekler göndermek için kullanılan üst düzey Api örneği. + +### `delete_blueprint(self, blueprint_name)` + +Bir akış blueprint'ini sil. + +**Argümanlar:** + +`blueprint_name`: Silinecek blueprint'in adı. + +**Örnek:** + +```python +api.flow().delete_blueprint("old-blueprint") +``` + +### `get(self, id)` + +Çalışan bir akış örneğinin tanımını alın. + +**Argümanlar:** + +`id`: Akış örneği kimliği + +**Döndürür:** dict: Akış örneği tanımı + +**Örnek:** + +```python +flow_def = api.flow().get("default") +print(flow_def) +``` + +### `get_blueprint(self, blueprint_name)` + +Bir akış şema tanımını ada göre alın. + +**Argümanlar:** + +`blueprint_name`: Alınacak şemanın adı + +**Döndürür:** dict: Şema tanımı bir sözlük olarak + +**Örnek:** + +```python +blueprint = api.flow().get_blueprint("default") +print(blueprint) # Blueprint configuration +``` + +### `id(self, id='default')` + +Belirli bir akış üzerinde işlemler yürütmek için bir FlowInstance alın. + +**Argümanlar:** + +`id`: Akış tanımlayıcısı (varsayılan: "default") + +**Döndürür:** FlowInstance: Servis işlemleri için akış örneği + +**Örnek:** + +```python +flow = api.flow().id("my-flow") +response = flow.text_completion( + system="You are helpful", + prompt="Hello" +) +``` + +### `list(self)` + +Tüm aktif akış örneklerini listele. + +**Döndürür:** list[str]: Akış örnekleri kimliklerinin listesi + +**Örnek:** + +```python +flows = api.flow().list() +print(flows) # ['default', 'flow-1', 'flow-2', ...] +``` + +### `list_blueprints(self)` + +Mevcut tüm akış şemalarını listele. + +**Döndürür:** list[str]: Şema adlarının listesi + +**Örnek:** + +```python +blueprints = api.flow().list_blueprints() +print(blueprints) # ['default', 'custom-flow', ...] +``` + +### `put_blueprint(self, blueprint_name, definition)` + +Bir akış şemasını oluştur veya güncelle. + +**Argümanlar:** + +`blueprint_name`: Şema için isim +`definition`: Şema tanım sözlüğü + +**Örnek:** + +```python +definition = { + "services": ["text-completion", "graph-rag"], + "parameters": {"model": "gpt-4"} +} +api.flow().put_blueprint("my-blueprint", definition) +``` + +### `request(self, path=None, request=None)` + +Akış kapsamlı bir API isteği yapın. + +**Argümanlar:** + +`path`: Akış uç noktaları için isteğe bağlı yol soneki +`request`: İstek yükü sözlüğü + +**Döndürür:** dict: Yanıt nesnesi + +**Hatalar:** + +`RuntimeError`: İstek parametresi belirtilmediyse + +### `start(self, blueprint_name, id, description, parameters=None)` + +Bir şablondan yeni bir akış örneği başlatın. + +**Argümanlar:** + +`blueprint_name`: Oluşturulacak şablonun adı +`id`: Akış örneği için benzersiz tanımlayıcı +`description`: İnsan tarafından okunabilir açıklama +`parameters`: İsteğe bağlı parametreler sözlüğü + +**Örnek:** + +```python +api.flow().start( + blueprint_name="default", + id="my-flow", + description="My custom flow", + parameters={"model": "gpt-4"} +) +``` + +### `stop(self, id)` + +Çalışan bir akış örneğini durdurun. + +**Argümanlar:** + +`id`: Durdurulacak akış örneği kimliği + +**Örnek:** + +```python +api.flow().stop("my-flow") +``` + + +-- + +## `FlowInstance` + +```python +from trustgraph.api import FlowInstance +``` + +Belirli bir akış üzerinde hizmetleri çalıştırmak için kullanılan akış örneği istemcisi. + +Bu sınıf, aşağıdaki TrustGraph hizmetlerine erişim sağlar: +Metin tamamlama ve gömme +Durum yönetimi ile birlikte aracı işlemleri +Grafik ve belge RAG sorguları +Bilgi grafiği işlemleri (üçlüler, nesneler) +Belge yükleme ve işleme +Doğal dili GraphQL sorgusuna dönüştürme +Yapılandırılmış veri analizi ve şema algılama +MCP aracı yürütme +İstek şablonlama + +Hizmetler, ID ile tanımlanan çalışan bir akış örneği aracılığıyla erişilir. + +### Yöntemler + +### `__init__(self, api, id)` + +FlowInstance'ı başlat. + +**Argümanlar:** + +`api`: Üst akış istemcisi +`id`: Akış örneği tanımlayıcısı + +### `agent(self, question, user='trustgraph', state=None, group=None, history=None)` + +Akıl yürütme ve araç kullanma yetenekleriyle bir aracı işlemi yürüt. + +Aracıların çok adımlı akıl yürütme yapabilmesi, araçları kullanabilmesi ve etkileşimler arasında konuşma +durumunu koruyabilmesi mümkündür. Bu, senkron, akışsız bir versiyondur. + +**Argümanlar:** + +`question`: Kullanıcı sorusu veya talimatı +`user`: Kullanıcı tanımlayıcısı (varsayılan: "trustgraph") +`state`: Durumlu konuşmalar için isteğe bağlı durum sözlüğü +`group`: Çok kullanıcılı bağlamlar için isteğe bağlı grup tanımlayıcısı +`history`: İsteğe bağlı olarak mesaj sözlükleri listesi olarak konuşma geçmişi + +**Döndürür:** str: Aracının son cevabı + +**Örnek:** + +```python +flow = api.flow().id("default") + +# Simple question +answer = flow.agent( + question="What is the capital of France?", + user="trustgraph" +) + +# With conversation history +history = [ + {"role": "user", "content": "Hello"}, + {"role": "assistant", "content": "Hi! How can I help?"} +] +answer = flow.agent( + question="Tell me about Paris", + user="trustgraph", + history=history +) +``` + +### `detect_type(self, sample)` + +Yapılandırılmış bir veri örneğinin veri türünü tespit edin. + +**Argümanlar:** + +`sample`: Analiz edilecek veri örneği (metin içeriği) + +**Döndürür:** tespit_türü, güven ve isteğe bağlı meta verileri içeren bir sözlük. + +### `diagnose_data(self, sample, schema_name=None, options=None)` + +Birleşik veri tanılama işlemini gerçekleştirin: türü tespit edin ve tanımlayıcı oluşturun. + +**Argümanlar:** + +`sample`: Analiz edilecek veri örneği (metin içeriği) +`schema_name`: İsteğe bağlı, tanımlayıcı oluşturmak için hedef şema adı +`options`: İsteğe bağlı parametreler (örneğin, CSV için ayraç) + +**Döndürür:** tespit_türü, güven, tanımlayıcı ve meta verileri içeren bir sözlük. + +### `document_embeddings_query(self, text, user, collection, limit=10)` + +Anlamsal benzerlik kullanarak belge parçalarına sorgu yapın. + +Vektör gömüler kullanarak, içeriği giriş metnine anlamsal olarak benzeyen belge parçalarını bulur. + + +**Argümanlar:** + +`text`: Anlamsal arama için sorgu metni +`user`: Kullanıcı/keyspace tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`limit`: Maksimum sonuç sayısı (varsayılan: 10) + +**Döndürür:** dict: Parçaları içeren sonuçlar, chunk_id ve puan ile birlikte. + +**Örnek:** + +```python +flow = api.flow().id("default") +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "doc1/p0/c0", "score": 0.95}, ...]} +``` + +### `document_rag(self, query, user='trustgraph', collection='default', doc_limit=10)` + +Belge tabanlı Geliştirilmiş Bilgi Alma (RAG) sorgusunu çalıştırın. + +Belge RAG, ilgili belge parçalarını bulmak için vektör gömülerini kullanır, +ardından bu parçaları bağlam olarak kullanarak bir LLM ile bir yanıt oluşturur. + +**Argümanlar:** + +`query`: Doğal dil sorgusu +`user`: Kullanıcı/keyspace tanımlayıcısı (varsayılan: "trustgraph") +`collection`: Koleksiyon tanımlayıcısı (varsayılan: "default") +`doc_limit`: Alınacak maksimum belge parçası sayısı (varsayılan: 10) + +**Döndürür:** str: Belge bağlamını içeren oluşturulan yanıt + +**Örnek:** + +```python +flow = api.flow().id("default") +response = flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts)` + +Bir veya daha fazla metin için vektör gömme işlemleri gerçekleştirin. + +Metinleri, semantik +arama ve benzerlik karşılaştırması için uygun olan yoğun vektör gösterimlerine dönüştürür. + +**Argümanlar:** + +`texts`: Gömülecek giriş metinlerinin listesi + +**Döndürür:** list[list[list[float]]]: Vektör gömmeleri, her giriş metni için bir set. + +**Örnek:** + +```python +flow = api.flow().id("default") +vectors = flow.embeddings(["quantum computing"]) +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `generate_descriptor(self, sample, data_type, schema_name, options=None)` + +Belirli bir şemaya yapılandırılmış veri eşlemesi için bir tanımlayıcı oluşturun. + +**Argümanlar:** + +`sample`: Analiz edilecek veri örneği (metin içeriği) +`data_type`: Veri türü (csv, json, xml) +`schema_name`: Tanımlayıcı oluşturmak için hedef şema adı +`options`: İsteğe bağlı parametreler (örneğin, CSV için ayraç) + +**Döndürür:** tanımlayıcı ve meta verileri içeren sözlük + +### `graph_embeddings_query(self, text, user, collection, limit=10)` + +Anlamsal benzerlik kullanarak bilgi grafiği varlıklarını sorgulayın. + +Vektör gömüler kullanarak, giriş metnine anlamsal olarak +benzer açıklamaları olan bilgi grafiğindeki varlıkları bulur. + +**Argümanlar:** + +`text`: Anlamsal arama için sorgu metni +`user`: Kullanıcı/keyspace tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`limit`: Maksimum sonuç sayısı (varsayılan: 10) + +**Döndürür:** dict: Benzer varlıklarla birlikte sorgu sonuçları + +**Örnek:** + +```python +flow = api.flow().id("default") +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +# results contains {"entities": [{"entity": {...}, "score": 0.95}, ...]} +``` + +### `graph_rag(self, query, user='trustgraph', collection='default', entity_limit=50, triple_limit=30, max_subgraph_size=150, max_path_length=2)` + +Grafik tabanlı, Bilgiyle Zenginleştirilmiş Üretim (RAG) sorgusunu çalıştırın. + +Grafik RAG, ilgili bağlamı bulmak için bilgi grafiği yapısını kullanarak, varlık ilişkilerini +izleyerek ve ardından bir LLM kullanarak bir yanıt oluşturur. + +**Argümanlar:** + +`query`: Doğal dil sorgusu +`user`: Kullanıcı/veri kümesi tanımlayıcısı (varsayılan: "trustgraph") +`collection`: Koleksiyon tanımlayıcısı (varsayılan: "default") +`entity_limit`: Alınacak maksimum varlık sayısı (varsayılan: 50) +`triple_limit`: Her varlık için maksimum üçlü sayısı (varsayılan: 30) +`max_subgraph_size`: Alt grafik içindeki maksimum toplam üçlü sayısı (varsayılan: 150) +`max_path_length`: Maksimum gezinme derinliği (varsayılan: 2) + +**Döndürür:** str: Grafik bağlamını içeren oluşturulmuş yanıt + +**Örnek:** + +```python +flow = api.flow().id("default") +response = flow.graph_rag( + query="Tell me about Marie Curie's discoveries", + user="trustgraph", + collection="scientists", + entity_limit=20, + max_path_length=3 +) +print(response) +``` + +### `load_document(self, document, id=None, metadata=None, user=None, collection=None)` + +Bir belgeyi işleme için yükleyin. + +Bir belgeyi (PDF, DOCX, resimler, vb.) çıkarma ve +iş akışının belge işleme hattı aracılığıyla işlenmesi için yükleyin. + +**Argümanlar:** + +`document`: Belge içeriği (bayt olarak) +`id`: İsteğe bağlı belge tanımlayıcısı (None ise otomatik olarak oluşturulur) +`metadata`: İsteğe bağlı meta veri (Üçlüler listesi veya emit yöntemine sahip nesne) +`user`: Kullanıcı/veri alanı tanımlayıcısı (isteğe bağlı) +`collection`: Koleksiyon tanımlayıcısı (isteğe bağlı) + +**Döndürür:** dict: İşleme yanıtı + +**Hatalar:** + +`RuntimeError`: Meta veri sağlanırsa ancak kimlik belirtilmezse + +**Örnek:** + +```python +flow = api.flow().id("default") + +# Load a PDF document +with open("research.pdf", "rb") as f: + result = flow.load_document( + document=f.read(), + id="research-001", + user="trustgraph", + collection="papers" + ) +``` + +### `load_text(self, text, id=None, metadata=None, charset='utf-8', user=None, collection=None)` + +İşlenmek üzere metin içeriğini yükleyin. + +Metin içeriğini, akışın metin işleme hattı aracılığıyla çıkarma ve işleme için yükler. + + +**Argümanlar:** + +`text`: Metin içeriği (bayt olarak) +`id`: İsteğe bağlı belge tanımlayıcısı (None ise otomatik olarak oluşturulur) +`metadata`: İsteğe bağlı meta veri (Üçlüler listesi veya emit yöntemine sahip nesne) +`charset`: Karakter kodlaması (varsayılan: "utf-8") +`user`: Kullanıcı/keyspace tanımlayıcısı (isteğe bağlı) +`collection`: Koleksiyon tanımlayıcısı (isteğe bağlı) + +**Döndürür:** dict: İşleme yanıtı + +**Hatalar:** + +`RuntimeError`: Meta veri sağlanmış ancak id belirtilmemişse + +**Örnek:** + +```python +flow = api.flow().id("default") + +# Load text content +text_content = b"This is the document content..." +result = flow.load_text( + text=text_content, + id="text-001", + charset="utf-8", + user="trustgraph", + collection="documents" +) +``` + +### `mcp_tool(self, name, parameters={})` + +Bir Model Bağlam Protokolü (MCP) aracını çalıştırın. + +MCP araçları, ajanlar ve iş akışları için genişletilebilir işlevsellik sağlar, +ve harici sistemler ve hizmetlerle entegrasyon imkanı sunar. + +**Argümanlar:** + +`name`: Araç adı/tanımlayıcı +`parameters`: Araç parametreleri sözlüğü (varsayılan: {}) + +**Döndürür:** str veya dict: Aracın çalıştırma sonucu + +**Hatalar:** + +`ProtocolException`: Yanıt formatı geçersizse + +**Örnek:** + +```python +flow = api.flow().id("default") + +# Execute a tool +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `nlp_query(self, question, max_results=100)` + +Doğal bir dil sorusunu GraphQL sorgusuna dönüştürün. + +**Argümanlar:** + +`question`: Doğal dil sorusu +`max_results`: Döndürülecek maksimum sonuç sayısı (varsayılan: 100) + +**Döndürür:** graphql_query, variables, detected_schemas, confidence alanlarını içeren bir sözlük. + +### `prompt(self, id, variables)` + +Değişken yerleştirmesiyle bir istem şablonunu çalıştırın. + +İstek şablonları, dinamik değişkenlerle yeniden kullanılabilir istek kalıplarına olanak tanır ve tutarlı istek mühendisliği için kullanışlıdır. + + +**Argümanlar:** + +`id`: İstek şablonu tanımlayıcısı +`variables`: Değişken adı ile değer eşlemelerinin sözlüğü + +**Döndürür:** str veya dict: Oluşturulmuş istek sonucu (metin veya yapılandırılmış nesne) + +**Hatalar:** + +`ProtocolException`: Yanıt formatı geçersizse + +**Örnek:** + +```python +flow = api.flow().id("default") + +# Text template +result = flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"} +) + +# Structured template +result = flow.prompt( + id="extract-entities", + variables={"text": "Marie Curie won Nobel Prizes"} +) +``` + +### `request(self, path, request)` + +Bu işlem örneği üzerinden bir hizmet isteği oluşturun. + +**Parametreler:** + +`path`: Hizmet yolu (örneğin, "service/text-completion") +`request`: İstek yükü sözlüğü + +**Dönüş:** dict: Hizmet yanıtı + +### `row_embeddings_query(self, text, schema_name, user='trustgraph', collection='default', index_name=None, limit=10)` + +İndekslenmiş alanlar üzerinde semantik benzerlik kullanarak satır verilerini sorgulayın. + +İndeksli alan değerlerinin, vektör gömüler kullanılarak, giriş metnine anlamsal olarak benzer olduğu satırları bulur. Bu, yapılandırılmış veriler üzerinde bulanık/anlamsal eşleşme sağlar. + +**Argümanlar:** + + + +`text`: Anlamsal arama için sorgu metni +`schema_name`: İçinde arama yapılacak şema adı +`user`: Kullanıcı/veri tabanı tanımlayıcısı (varsayılan: "trustgraph") +`collection`: Koleksiyon tanımlayıcısı (varsayılan: "default") +`index_name`: Aramayı belirli bir indekse sınırlamak için isteğe bağlı indeks adı +`limit`: Maksimum sonuç sayısı (varsayılan: 10) + +**Döndürür:** dict: Eşleşmeleri içeren, index_name, index_value, text ve score alanlarını içeren sorgu sonuçları + +**Örnek:** + +```python +flow = api.flow().id("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query, user='trustgraph', collection='default', variables=None, operation_name=None)` + +Bilgi grafiğindeki yapılandırılmış satırlara karşı bir GraphQL sorgusu çalıştırın. + +GraphQL sözdizimini kullanarak yapılandırılmış verileri sorgular, bu sayede filtreleme, toplama ve ilişki taraması gibi karmaşık sorgular +mümkün hale gelir. + +**Parametreler:** + +`query`: GraphQL sorgu dizesi +`user`: Kullanıcı/veri alanı tanımlayıcısı (varsayılan: "trustgraph") +`collection`: Koleksiyon tanımlayıcısı (varsayılan: "default") +`variables`: İsteğe bağlı sorgu değişkenleri sözlüğü +`operation_name`: Çoklu işlem belgeleri için isteğe bağlı işlem adı + +**Döndürür:** dict: 'data', 'errors' ve/veya 'extensions' alanlarına sahip GraphQL yanıtı + +**Hatalar:** + +`ProtocolException`: Sistem düzeyinde bir hata oluşursa + +**Örnek:** + +```python +flow = api.flow().id("default") + +# Simple query +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) + +# Query with variables +query = ''' +query GetScientist($name: String!) { + scientists(name: $name) { + name + nobelPrizes + } +} +''' +result = flow.rows_query( + query=query, + variables={"name": "Marie Curie"} +) +``` + +### `schema_selection(self, sample, options=None)` + +Bir veri örneği için, istem analizi kullanarak eşleşen şemaları seçin. + +**Argümanlar:** + +`sample`: Analiz edilecek veri örneği (metin içeriği) +`options`: İsteğe bağlı parametreler + +**Döndürür:** schema_matches dizisi ve meta veriler içeren bir sözlük. + +### `structured_query(self, question, user='trustgraph', collection='default')` + +Yapılandırılmış verilere karşı doğal dil sorgusu yürütün. +NLP sorgu dönüşümü ve GraphQL yürütmeyi birleştirir. + +**Argümanlar:** + +`question`: Doğal dil sorgusu +`user`: Cassandra keyspace tanımlayıcısı (varsayılan: "trustgraph") +`collection`: Veri koleksiyonu tanımlayıcısı (varsayılan: "default") + +**Döndürür:** veri ve isteğe bağlı hataları içeren bir sözlük. + +### `text_completion(self, system, prompt)` + +İş akışının LLM'sini kullanarak metin tamamlama işlemini yürütün. + +**Argümanlar:** + +`system`: Yardımcının davranışını tanımlayan sistem istemi +`prompt`: Kullanıcı istemi/sorusu + +**Döndürür:** str: Oluşturulan yanıt metni + +**Örnek:** + +```python +flow = api.flow().id("default") +response = flow.text_completion( + system="You are a helpful assistant", + prompt="What is quantum computing?" +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=10000)` + +Desen eşleştirme kullanarak bilgi grafiği üçlülerini sorgulayın. + +Belirtilen konu, yüklem ve/veya +nesne desenlerine uyan RDF üçlülerini arar. Belirtilmemiş parametreler, joker karakter olarak işlev görür. + +**Argümanlar:** + +`s`: Konu URI'si (isteğe bağlı, joker karakter için None kullanın) +`p`: Yüklem URI'si (isteğe bağlı, joker karakter için None kullanın) +`o`: Nesne URI'si veya Literal (isteğe bağlı, joker karakter için None kullanın) +`user`: Kullanıcı/veri tabanı tanımlayıcısı (isteğe bağlı) +`collection`: Koleksiyon tanımlayıcısı (isteğe bağlı) +`limit`: Döndürülecek maksimum sonuç sayısı (varsayılan: 10000) + +**Döndürür:** list[Triple]: Eşleşen Triple nesnelerinin listesi + +**Hatalar:** + +`RuntimeError`: s veya p bir Uri değilse veya o bir Uri/Literal değilse + +**Örnek:** + +```python +from trustgraph.knowledge import Uri, Literal + +flow = api.flow().id("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s=Uri("http://example.org/person/marie-curie"), + user="trustgraph", + collection="scientists" +) + +# Find all instances of a specific relationship +triples = flow.triples_query( + p=Uri("http://example.org/ontology/discovered"), + limit=100 +) +``` + + +-- + +## `AsyncFlow` + +```python +from trustgraph.api import AsyncFlow +``` + +REST API'sini kullanan asenkron akış yönetimi istemcisi. + +Listeleme, +akışları başlatma, durdurma ve akış sınıf tanımlarını yönetme gibi, async/await tabanlı akış yönetimi işlemleri sağlar. Ayrıca, ajanlar, RAG ve sorgular gibi akış kapsamlı hizmetlere, akış olmayan REST uç noktaları aracılığıyla erişim sağlar. + +Not: Akış desteği için, AsyncSocketClient'ı kullanın. + +### Yöntemler + +### Yöntemler + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Asenkron akış istemciyi başlat. + +**Argümanlar:** + +`url`: TrustGraph API'si için temel URL +`timeout`: İstek zaman aşımı (saniye cinsinden) +`token`: Kimlik doğrulama için isteğe bağlı taşıyıcı belirteci + +### `aclose(self) -> None` + +Asenkron istemciyi kapatın ve kaynakları temizleyin. + +Not: Temizleme, aiohttp oturum bağlam yöneticileri tarafından otomatik olarak yapılır. +Bu yöntem, diğer asenkron istemcilerle tutarlılık sağlamak için sağlanmıştır. + +### `delete_class(self, class_name: str)` + +Bir akış sınıf tanımını silin. + +Sistemden bir akış sınıf şablonunu kaldırır. Çalışan akış örneklerini etkilemez. + + +**Argümanlar:** + +`class_name`: Silinecek akış sınıf adı + +**Örnek:** + +```python +async_flow = await api.async_flow() + +# Delete a flow class +await async_flow.delete_class("old-flow-class") +``` + +### `get(self, id: str) -> Dict[str, Any]` + +Akış tanımını al. + +Sınıf adı, +açıklaması ve parametreleri dahil olmak üzere eksiksiz akış yapılandırmasını alır. + +**Argümanlar:** + +`id`: Akış tanımlayıcısı + +**Döndürür:** dict: Akış tanımı nesnesi + +**Örnek:** + +```python +async_flow = await api.async_flow() + +# Get flow definition +flow_def = await async_flow.get("default") +print(f"Flow class: {flow_def.get('class-name')}") +print(f"Description: {flow_def.get('description')}") +``` + +### `get_class(self, class_name: str) -> Dict[str, Any]` + +Akış sınıfı tanımını alın. + +Bir akış sınıfının, yapılandırma şeması ve hizmet bağlamaları dahil olmak üzere, temel tasarım tanımını alır. + + +**Parametreler:** + +`class_name`: Akış sınıfı adı + +**Döndürür:** dict: Akış sınıfı tanım nesnesi + +**Örnek:** + +```python +async_flow = await api.async_flow() + +# Get flow class definition +class_def = await async_flow.get_class("default") +print(f"Services: {class_def.get('services')}") +``` + +### `id(self, flow_id: str)` + +Asenkron akış örneği istemciyi alın. + +Belirli bir akışın hizmetleriyle etkileşim kurmak için bir istemci döndürür +(ajan, RAG, sorgular, gömme vb.). + +**Argümanlar:** + +`flow_id`: Akış tanımlayıcısı + +**Döndürür:** AsyncFlowInstance: Akışa özel işlemler için istemci + +**Örnek:** + +```python +async_flow = await api.async_flow() + +# Get flow instance +flow = async_flow.id("default") + +# Use flow services +result = await flow.graph_rag( + query="What is TrustGraph?", + user="trustgraph", + collection="default" +) +``` + +### `list(self) -> List[str]` + +Tüm akış tanımlayıcılarını listele. + +Sistemde şu anda dağıtılmış olan tüm akışların kimliklerini alır. + +**Döndürür:** list[str]: Akış tanımlayıcılarının listesi + +**Örnek:** + +```python +async_flow = await api.async_flow() + +# List all flows +flows = await async_flow.list() +print(f"Available flows: {flows}") +``` + +### `list_classes(self) -> List[str]` + +Tüm akış sınıfı adlarını listele. + +Sistemdeki mevcut tüm akış sınıfı (şablon) adlarını alır. + +**Döndürür:** list[str]: Akış sınıfı adlarının listesi + +**Örnek:** + +```python +async_flow = await api.async_flow() + +# List available flow classes +classes = await async_flow.list_classes() +print(f"Available flow classes: {classes}") +``` + +### `put_class(self, class_name: str, definition: Dict[str, Any])` + +Bir akış sınıf tanımını oluşturun veya güncelleyin. + +Akışları örneklemek için kullanılabilecek bir akış sınıf şablonunu saklar. + +**Argümanlar:** + +`class_name`: Akış sınıf adı +`definition`: Akış sınıf tanımı nesnesi + +**Örnek:** + +```python +async_flow = await api.async_flow() + +# Create a custom flow class +class_def = { + "services": { + "agent": {"module": "agent", "config": {...}}, + "graph-rag": {"module": "graph-rag", "config": {...}} + } +} +await async_flow.put_class("custom-flow", class_def) +``` + +### `request(self, path: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +Gateway API'sine asenkron HTTP POST isteği gönderin. + +TrustGraph API'sine kimlik doğrulaması yapılmış istekler göndermek için kullanılan iç metot. + +**Argümanlar:** + +`path`: API uç noktası yolu (temel URL'ye göre) +`request_data`: İstek yükü sözlüğü + +**Döndürür:** dict: API'den gelen yanıt nesnesi + +**Hatalar:** + +`ProtocolException`: HTTP durum kodu 200 değilse veya yanıt geçerli bir JSON değilse +`ApplicationException`: API bir hata yanıtı döndürürse + +### `start(self, class_name: str, id: str, description: str, parameters: Dict | None = None)` + +Yeni bir akış örneği başlatın. + +Belirtilen parametrelerle, bir akış sınıf tanımından bir akış oluşturur ve başlatır. + + +**Argümanlar:** + +`class_name`: Oluşturulacak akış sınıfının adı +`id`: Yeni akış örneği için tanımlayıcı +`description`: Akışın insan tarafından okunabilir açıklaması +`parameters`: Akış için isteğe bağlı yapılandırma parametreleri + +**Örnek:** + +```python +async_flow = await api.async_flow() + +# Start a flow from a class +await async_flow.start( + class_name="default", + id="my-flow", + description="Custom flow instance", + parameters={"model": "claude-3-opus"} +) +``` + +### `stop(self, id: str)` + +Çalışan bir akışı durdur. + +Bir akış örneğini durdurur ve kaldırır, böylece kaynakları serbest bırakılır. + +**Argümanlar:** + +`id`: Durdurulacak akış tanımlayıcısı + +**Örnek:** + +```python +async_flow = await api.async_flow() + +# Stop a flow +await async_flow.stop("my-flow") +``` + + +-- + +## `AsyncFlowInstance` + +```python +from trustgraph.api import AsyncFlowInstance +``` + +Asenkron akış örneği istemcisi. + +Ajanlar, +RAG sorguları, gömülme işlemleri ve grafik sorguları dahil olmak üzere akış kapsamındaki hizmetlere asenkron/bekleme erişimi sağlar. Tüm işlemler, eksiksiz +yanıtları (akışsız) döndürür. + +Not: Akış desteği için, AsyncSocketFlowInstance'ı kullanın. + +### Yöntemler + +### `__init__(self, flow: trustgraph.api.async_flow.AsyncFlow, flow_id: str)` + +Asenkron akış örneğini başlatır. + +**Argümanlar:** + +`flow`: Üst düzey AsyncFlow istemcisi +`flow_id`: Akış tanımlayıcısı + +### `agent(self, question: str, user: str, state: Dict | None = None, group: str | None = None, history: List | None = None, **kwargs: Any) -> Dict[str, Any]` + +Bir ajan işlemini (akışsız) yürütür. + +Bir soruyu yanıtlamak için bir ajan çalıştırır, isteğe bağlı konuşma durumu ve +geçmişi ile. Ajan işleme işlemini tamamladıktan sonra eksiksiz yanıtı döndürür. + + +Not: Bu yöntem akışı desteklemez. Gerçek zamanlı ajan düşünceleri ve +gözlemler için, AsyncSocketFlowInstance.agent() yöntemini kullanın. + +**Argümanlar:** + +`question`: Kullanıcı sorusu veya talimatı +`user`: Kullanıcı tanımlayıcısı +`state`: İsteğe bağlı, konuşma bağlamı için durum sözlüğü +`group`: İsteğe bağlı, oturum yönetimi için grup tanımlayıcısı +`history`: İsteğe bağlı, konuşma geçmişi listesi +`**kwargs`: Ek, hizmete özgü parametreler + +**Döndürür:** dict: Cevap ve meta verileri içeren eksiksiz ajan yanıtı + +**Örnek:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute agent +result = await flow.agent( + question="What is the capital of France?", + user="trustgraph" +) +print(f"Answer: {result.get('response')}") +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> str` + +Belge tabanlı RAG sorgusunu (akışsız) çalıştırın. + +Belge gömüler kullanarak, bilgi artırılmış metin oluşturma işlemini gerçekleştirir. +Anlamsal arama yoluyla ilgili belge parçalarını alır ve ardından alınan belgelerle +ilişkili bir yanıt oluşturur. Tam yanıtı döndürür. + +Not: Bu yöntem akışı desteklemez. Akışlı RAG yanıtları için, +bunun yerine AsyncSocketFlowInstance.document_rag() yöntemini kullanın. + +**Argümanlar:** + +`query`: Kullanıcı sorgusu metni +`user`: Kullanıcı kimliği +`collection`: Belgeleri içeren koleksiyon kimliği +`doc_limit`: Alınacak maksimum belge parçası sayısı (varsayılan: 10) +`**kwargs`: Ek hizmete özgü parametreler + +**Döndürür:** str: Belge verilerine dayalı olarak oluşturulan tam yanıt + +**Örnek:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query documents +response = await flow.document_rag( + query="What does the documentation say about authentication?", + user="trustgraph", + collection="docs", + doc_limit=5 +) +print(response) +``` + +### `embeddings(self, texts: list, **kwargs: Any)` + +Girdi metinleri için gömme (embedding) oluşturur. + +Metinleri, akışın yapılandırılmış gömme modelini kullanarak sayısal vektör gösterimlerine dönüştürür. Anlamsal arama ve benzerlik +karşılaştırmaları için kullanışlıdır. + + +**Argümanlar:** + +`texts`: Gömülecek girdi metinlerinin listesi +`**kwargs`: Ek hizmete özgü parametreler + +**Döndürür:** dict: Gömme vektörlerini içeren yanıt + +**Örnek:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate embeddings +result = await flow.embeddings(texts=["Sample text to embed"]) +vectors = result.get("vectors") +print(f"Embedding dimension: {len(vectors[0][0])}") +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any)` + +Anlamsal varlık araması için grafik gömme verilerini sorgular. + +Varlıkların anlamsal olarak aranmasını, grafik varlık gömmeleri üzerinde gerçekleştirerek, giriş metnine en uygun varlıkları bulur. Benzerliğe göre sıralanmış varlıkları döndürür. + + +**Argümanlar:** + +`text`: Anlamsal arama için sorgu metni +`user`: Kullanıcı kimliği +`collection`: Grafik gömmelerini içeren koleksiyon kimliği +`limit`: Döndürülecek maksimum sonuç sayısı (varsayılan: 10) +`**kwargs`: Ek hizmete özel parametreler + +**Döndürür:** dict: Sıralanmış varlık eşleşmelerini ve benzerlik puanlarını içeren yanıt + +**Örnek:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find related entities +results = await flow.graph_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="tech-kb", + limit=5 +) + +for entity in results.get("entities", []): + print(f"{entity['name']}: {entity['score']}") +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> str` + +Grafik tabanlı RAG sorgusunu (akışsız) çalıştırın. + +Bilgi grafi veri kullanarak, bilgiyle zenginleştirilmiş metin üretimi gerçekleştirir. +İlgili varlıkları ve bunların ilişkilerini belirler, ardından grafiğin yapısına dayalı olarak bir +yanıt oluşturur. Tam yanıtı döndürür. + +Not: Bu yöntem akışı desteklemez. Akışlı RAG yanıtları için, bunun yerine AsyncSocketFlowInstance.graph_rag() kullanın. + + +**Argümanlar:** + +`query`: Kullanıcı sorgusu metni +`user`: Kullanıcı kimliği +`collection`: Bilgi grafiğini içeren koleksiyon kimliği +`max_subgraph_size`: Her alt grafik için maksimum üçlü sayısı (varsayılan: 1000) +`max_subgraph_count`: Alınacak maksimum alt grafik sayısı (varsayılan: 5) +`max_entity_distance`: Varlık genişletmesi için maksimum grafik mesafesi (varsayılan: 3) +`**kwargs`: Ek hizmete özgü parametreler + +**Döndürür:** str: Grafik verilerine dayalı olarak oluşturulan tam yanıt + +**Örnek:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Query knowledge graph +response = await flow.graph_rag( + query="What are the relationships between these entities?", + user="trustgraph", + collection="medical-kb", + max_subgraph_count=3 +) +print(response) +``` + +### `request(self, service: str, request_data: Dict[str, Any]) -> Dict[str, Any]` + +Bir akış kapsamındaki bir hizmete istek gönderin. + +Bu akış örneği içindeki hizmetleri çağırmak için kullanılan iç metot. + +**Argümanlar:** + +`service`: Hizmet adı (örneğin, "agent", "graph-rag", "triples") +`request_data`: Hizmet isteği yükü + +**Döndürür:** dict: Hizmet yanıt nesnesi + +**Hatalar:** + +`ProtocolException`: İstek başarısız olursa veya yanıt geçersizse +`ApplicationException`: Hizmet bir hata döndürürse + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any)` + +Yapılandırılmış veriler üzerinde semantik arama için satır gömme vektörlerini sorgular. + +Satır indeks gömme vektörleri üzerinde semantik arama gerçekleştirir ve giriş metnine en benzer indeksli alan değerlerine sahip satırları bulur. Yapılandırılmış veriler üzerinde bulanık/semantik eşleşme sağlar. + + +**Argümanlar:** + + +`text`: Semantik arama için sorgu metni +`schema_name`: Arama yapılacak şema adı +`user`: Kullanıcı kimliği (varsayılan: "trustgraph") +`collection`: Koleksiyon kimliği (varsayılan: "default") +`index_name`: Aramayı belirli bir indekse sınırlamak için isteğe bağlı indeks adı +`limit`: Döndürülecek maksimum sonuç sayısı (varsayılan: 10) +`**kwargs`: Ek hizmete özgü parametreler + +**Döndürür:** dict: index_name, index_value, text ve score ile eşleşmeleri içeren yanıt + +**Örnek:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Search for customers by name similarity +results = await flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +for match in results.get("matches", []): + print(f"{match['index_name']}: {match['index_value']} (score: {match['score']})") +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs: Any)` + +Saklanan satırları kullanarak bir GraphQL sorgusu çalıştırın. + +GraphQL sözdizimini kullanarak yapılandırılmış veri satırlarını sorgular. Değişkenler ve adlandırılmış işlemler içeren karmaşık +sorguları destekler. + +**Argümanlar:** + +`query`: GraphQL sorgu dizesi +`user`: Kullanıcı tanımlayıcısı +`collection`: Satırları içeren koleksiyon tanımlayıcısı +`variables`: İsteğe bağlı GraphQL sorgu değişkenleri +`operation_name`: Çoklu işlem sorguları için isteğe bağlı işlem adı +`**kwargs`: Ek hizmete özgü parametreler + +**Döndürür:** dict: Veri ve/veya hataları içeren GraphQL yanıtı + +**Örnek:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Execute GraphQL query +query = ''' + query GetUsers($status: String!) { + users(status: $status) { + id + name + email + } + } +''' + +result = await flow.rows_query( + query=query, + user="trustgraph", + collection="users", + variables={"status": "active"} +) + +for user in result.get("data", {}).get("users", []): + print(f"{user['name']}: {user['email']}") +``` + +### `text_completion(self, system: str, prompt: str, **kwargs: Any) -> str` + +Metin tamamlama oluşturun (akış olmadan). + +Bir sistem istemi ve kullanıcı istemi verildiğinde, bir LLM'den metin yanıtı oluşturur. +Tam yanıt metnini döndürür. + +Not: Bu yöntem akışı desteklemez. Akışlı metin oluşturma için, +bunun yerine AsyncSocketFlowInstance.text_completion() yöntemini kullanın. + +**Argümanlar:** + +`system`: LLM'nin davranışını tanımlayan sistem istemi +`prompt`: Kullanıcı istemi veya sorusu +`**kwargs`: Ek hizmete özgü parametreler + +**Döndürür:** str: Tam oluşturulmuş metin yanıtı + +**Örnek:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Generate text +response = await flow.text_completion( + system="You are a helpful assistant.", + prompt="Explain quantum computing in simple terms." +) +print(response) +``` + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs: Any)` + +Desen eşleştirme kullanarak RDF üçlülerini sorgulayın. + +Belirtilen konu, yüklem ve/veya +nesne desenlerine uyan üçlüleri arar. Desenler, herhangi bir değeri eşleştirmek için "None" değerini joker karakter olarak kullanır. + +**Argümanlar:** + +`s`: Konu deseni (joker karakter için "None") +`p`: Yüklem deseni (joker karakter için "None") +`o`: Nesne deseni (joker karakter için "None") +`user`: Kullanıcı kimliği (tüm kullanıcılar için "None") +`collection`: Koleksiyon kimliği (tüm koleksiyonlar için "None") +`limit`: Döndürülecek maksimum üçlü sayısı (varsayılan: 100) +`**kwargs`: Ek hizmete özgü parametreler + +**Döndürür:** dict: Eşleşen üçlüleri içeren yanıt + +**Örnek:** + +```python +async_flow = await api.async_flow() +flow = async_flow.id("default") + +# Find all triples with a specific predicate +results = await flow.triples_query( + p="knows", + user="trustgraph", + collection="social", + limit=50 +) + +for triple in results.get("triples", []): + print(f"{triple['s']} knows {triple['o']}") +``` + + +-- + +## `SocketClient` + +```python +from trustgraph.api import SocketClient +``` + +Akış işlemleri için senkron WebSocket istemcisi. + +WebSocket tabanlı TrustGraph hizmetlerine senkron bir arayüz sağlar, +kullanımı kolaylaştırmak için senkron oluşturucularla asenkron WebSocket kütüphanesini sarar. +Ajanlardan gelen akış yanıtlarını, RAG sorgularını ve metin tamamlama işlemlerini destekler. + +Not: Bu, asenkron WebSocket işlemlerinin etrafında oluşturulmuş bir senkron katmandır. +Gerçek asenkron destek için AsyncSocketClient'ı kullanın. + +### Yöntemler + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Senkron WebSocket istemcisini başlatın. + +**Argümanlar:** + +`url`: TrustGraph API'si için temel URL (HTTP/HTTPS, WS/WSS'ye dönüştürülecektir) +`timeout`: Saniyeler cinsinden WebSocket zaman aşımı +`token`: İsteğe bağlı kimlik doğrulama için taşıyıcı belirteci + +### `close(self) -> None` + +WebSocket bağlantılarını kapatın. + +Not: Temizleme, asenkron kodda bağlam yöneticileri tarafından otomatik olarak yapılır. + +### `flow(self, flow_id: str) -> 'SocketFlowInstance'` + +WebSocket akış işlemleri için bir akış örneği alın. + +**Argümanlar:** + +`flow_id`: Akış tanımlayıcısı + +**Döndürür:** SocketFlowInstance: Akış yöntemleri içeren akış örneği + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent responses +for chunk in flow.agent(question="Hello", user="trustgraph", streaming=True): + print(chunk.content, end='', flush=True) +``` + + +-- + +## `SocketFlowInstance` + +```python +from trustgraph.api import SocketFlowInstance +``` + +Akış işlemleri için senkron WebSocket akışı örneği. + +REST FlowInstance ile aynı arayüzü sağlar, ancak gerçek zamanlı yanıtlar için WebSocket tabanlı +akış desteği sunar. Tüm yöntemler, kademeli sonuç teslimini etkinleştirmek için isteğe bağlı +`streaming` parametresini destekler. + +### Yöntemler + +### `__init__(self, client: trustgraph.api.socket_client.SocketClient, flow_id: str) -> None` + +Soket akışı örneğini başlatır. + +**Argümanlar:** + +`client`: Üst SoketClient +`flow_id`: Akış tanımlayıcısı + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, streaming: bool = False, **kwargs: Any) -> Dict[str, Any] | Iterator[trustgraph.api.types.StreamingChunk]` + +Akış desteği ile bir ajan işlemi gerçekleştirin. + +Ajanlar, araç kullanımıyla çok aşamalı akıl yürütme yapabilir. Bu yöntem, streaming=False olsa bile, her zaman +akış parçaları (düşünceler, gözlemler, cevaplar) döndürür, böylece ajanın akıl yürütme süreci gösterilir. + + +**Argümanlar:** + +`question`: Kullanıcı sorusu veya talimatı +`user`: Kullanıcı kimliği +`state`: Durumlu konuşmalar için isteğe bağlı durum sözlüğü +`group`: Çok kullanıcılı bağlamlar için isteğe bağlı grup kimliği +`history`: İsteğe bağlı olarak mesaj sözlüklerinin listesi olarak konuşma geçmişi +`streaming`: Akış modunu etkinleştir (varsayılan: False) +`**kwargs`: Ajan hizmetine iletilen ek parametreler + +**Döndürür:** Iterator[StreamingChunk]: Ajanın düşüncelerinin, gözlemlerinin ve cevaplarının akışı + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Stream agent reasoning +for chunk in flow.agent( + question="What is quantum computing?", + user="trustgraph", + streaming=True +): + if isinstance(chunk, AgentThought): + print(f"[Thinking] {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"[Observation] {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"[Answer] {chunk.content}") +``` + +### `agent_explain(self, question: str, user: str, collection: str, state: Dict[str, Any] | None = None, group: str | None = None, history: List[Dict[str, Any]] | None = None, **kwargs: Any) -> Iterator[trustgraph.api.types.StreamingChunk | trustgraph.api.types.ProvenanceEvent]` + +Açıklanabilirlik desteğiyle bir ajan işlemini yürütün. + +Hem içerik parçalarını (AgentThought, AgentObservation, AgentAnswer) +ve kaynak olaylarını (ProvenanceEvent) akışa aktarır. Kaynak olayları, ayrıntılı bilgi +almak için ExplainabilityClient kullanılarak alınabilen URI'ler içerir +ve ajanın akıl yürütme süreci hakkında. + +Ajan izi şunlardan oluşur: +Oturum: Başlangıç sorusu ve oturum meta verileri +Yinelemeler: Her düşünce/eylem/gözlem döngüsü +Sonuç: Nihai cevap + +**Argümanlar:** + +`question`: Kullanıcı sorusu veya talimatı +`user`: Kullanıcı tanımlayıcısı +`collection`: Kaynak depolama için koleksiyon tanımlayıcısı +`state`: Durumlu konuşmalar için isteğe bağlı durum sözlüğü +`group`: Çoklu kullanıcı bağlamları için isteğe bağlı grup tanımlayıcısı +`history`: İsteğe bağlı olarak mesaj sözlüklerinin listesi olarak konuşma geçmişi +`**kwargs`: Ajan hizmetine iletilen ek parametreler +`Yields`: +`Union[StreamingChunk, ProvenanceEvent]`: Ajan parçaları ve kaynak olayları + +**Örnek:** + +```python +from trustgraph.api import Api, ExplainabilityClient, ProvenanceEvent +from trustgraph.api import AgentThought, AgentObservation, AgentAnswer + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +for item in flow.agent_explain( + question="What is the capital of France?", + user="trustgraph", + collection="default" +): + if isinstance(item, AgentThought): + print(f"[Thought] {item.content}") + elif isinstance(item, AgentObservation): + print(f"[Observation] {item.content}") + elif isinstance(item, AgentAnswer): + print(f"[Answer] {item.content}") + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.explain_id) + +# Fetch session trace after completion +if provenance_ids: + trace = explain_client.fetch_agent_trace( + provenance_ids[0], # Session URI is first + graph="urn:graph:retrieval", + user="trustgraph", + collection="default" + ) +``` + +### `document_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Anlamlı benzerlik kullanarak belge parçalarını sorgulayın. + +**Argümanlar:** + +`text`: Anlamlı arama için sorgu metni +`user`: Kullanıcı/veri kümesi tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`limit`: Maksimum sonuç sayısı (varsayılan: 10) +`**kwargs`: Hizmete iletilen ek parametreler + +**Dönüş:** dict: Eşleşen belge parçalarının chunk_id'leri ile birlikte sorgu sonuçları + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.document_embeddings_query( + text="machine learning algorithms", + user="trustgraph", + collection="research-papers", + limit=5 +) +# results contains {"chunks": [{"chunk_id": "...", "score": 0.95}, ...]} +``` + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +Belge tabanlı RAG sorgusunu, isteğe bağlı olarak akış modunda çalıştırın. + +İlgili belge parçalarını bulmak için vektör gömülmelerini kullanır, ardından bir LLM kullanarak +bir yanıt oluşturur. Akış modu, sonuçları kademeli olarak sunar. + +**Argümanlar:** + +`query`: Doğal dil sorgusu +`user`: Kullanıcı/veri kümesi tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`doc_limit`: Alınacak maksimum belge parçası sayısı (varsayılan: 10) +`streaming`: Akış modunu etkinleştir (varsayılan: False) +`**kwargs`: Hizmete iletilen ek parametreler + +**Döndürür:** Union[str, Iterator[str]]: Tam yanıt veya metin parçalarının akışı + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming document RAG +for chunk in flow.document_rag( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `document_rag_explain(self, query: str, user: str, collection: str, doc_limit: int = 10, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +Açıklanabilirlik desteğiyle belge tabanlı RAG sorgusunu çalıştırın. + +Hem içerik parçalarını (RAGChunk) hem de kaynak olaylarını (ProvenanceEvent) akışa aktarır. +Kaynak olayları, yanıtın nasıl oluşturulduğuna dair ayrıntılı bilgi almak için ExplainabilityClient kullanılarak alınabilen URI'ler içerir. + + +Belge RAG izi şunlardan oluşur: +Soru: Kullanıcının sorgusu +Keşif: Belge deposundan alınan parçalar (parça_sayısı) +Sentez: Oluşturulan yanıt + +**Argümanlar:** + +`query`: Doğal dil sorgusu +`user`: Kullanıcı/keyspace tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`doc_limit`: Alınacak maksimum belge parçası sayısı (varsayılan: 10) +`**kwargs`: Hizmete iletilen ek parametreler +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: İçerik parçaları ve kaynak olayları + +**Örnek:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +for item in flow.document_rag_explain( + query="Summarize the key findings", + user="trustgraph", + collection="research-papers", + doc_limit=5 +): + if isinstance(item, RAGChunk): + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + # Fetch entity details + entity = explain_client.fetch_entity( + item.explain_id, + graph=item.explain_graph, + user="trustgraph", + collection="research-papers" + ) + print(f"Event: {entity}", file=sys.stderr) +``` + +### `embeddings(self, texts: list, **kwargs: Any) -> Dict[str, Any]` + +Bir veya daha fazla metin için vektör gömme işlemleri gerçekleştirin. + +**Argümanlar:** + +`texts`: Gömülecek giriş metinlerinin listesi +`**kwargs`: Hizmete iletilen ek parametreler + +**Döndürür:** dict: Vektörleri içeren (her giriş metni için bir set) yanıt + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.embeddings(["quantum computing"]) +vectors = result.get("vectors", []) +``` + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +Anlamsal benzerlik kullanarak bilgi grafiği varlıklarını sorgulayın. + +**Argümanlar:** + +`text`: Anlamsal arama için sorgu metni +`user`: Kullanıcı/veri kümesi tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`limit`: Maksimum sonuç sayısı (varsayılan: 10) +`**kwargs`: Hizmete iletilen ek parametreler + +**Dönüş:** dict: Benzer varlıklarla birlikte sorgu sonuçları + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +results = flow.graph_embeddings_query( + text="physicist who discovered radioactivity", + user="trustgraph", + collection="scientists", + limit=5 +) +``` + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +İsteğe bağlı akışla, grafik tabanlı RAG sorgusunu çalıştırın. + +İlgili bağlamı bulmak için bilgi grafiği yapısını kullanır, ardından +bir LLM kullanarak bir yanıt oluşturur. Akış modu, sonuçları kademeli olarak sunar. + +**Argümanlar:** + +`query`: Doğal dil sorgusu +`user`: Kullanıcı/veri kümesi tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`max_subgraph_size`: Alt grafikteki maksimum toplam üçlü sayısı (varsayılan: 1000) +`max_subgraph_count`: Maksimum alt grafik sayısı (varsayılan: 5) +`max_entity_distance`: Maksimum gezinme derinliği (varsayılan: 3) +`streaming`: Akış modunu etkinleştir (varsayılan: False) +`**kwargs`: Hizmete iletilen ek parametreler + +**Döndürür:** Union[str, Iterator[str]]: Tam yanıt veya metin parçalarının akışı + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming graph RAG +for chunk in flow.graph_rag( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `graph_rag_explain(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, **kwargs: Any) -> Iterator[trustgraph.api.types.RAGChunk | trustgraph.api.types.ProvenanceEvent]` + +Açıklanabilirlik desteğiyle grafik tabanlı RAG sorgusunu çalıştırın. + +Hem içerik parçalarını (RAGChunk) hem de kaynak olaylarını (ProvenanceEvent) iletir. +Kaynak olayları, yanıtın nasıl oluşturulduğuna dair ayrıntılı bilgi almak için ExplainabilityClient kullanılarak alınabilen URI'ler içerir. + + +**Argümanlar:** + +`query`: Doğal dil sorgusu +`user`: Kullanıcı/keyspace tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`max_subgraph_size`: Alt grafik içindeki maksimum toplam üçlü sayısı (varsayılan: 1000) +`max_subgraph_count`: Maksimum alt grafik sayısı (varsayılan: 5) +`max_entity_distance`: Maksimum gezinme derinliği (varsayılan: 3) +`**kwargs`: Hizmete iletilen ek parametreler +`Yields`: +`Union[RAGChunk, ProvenanceEvent]`: İçerik parçaları ve kaynak olayları + +**Örnek:** + +```python +from trustgraph.api import Api, ExplainabilityClient, RAGChunk, ProvenanceEvent + +socket = api.socket() +flow = socket.flow("default") +explain_client = ExplainabilityClient(flow) + +provenance_ids = [] +response_text = "" + +for item in flow.graph_rag_explain( + query="Tell me about Marie Curie", + user="trustgraph", + collection="scientists" +): + if isinstance(item, RAGChunk): + response_text += item.content + print(item.content, end='', flush=True) + elif isinstance(item, ProvenanceEvent): + provenance_ids.append(item.provenance_id) + +# Fetch explainability details +for prov_id in provenance_ids: + entity = explain_client.fetch_entity( + prov_id, + graph="urn:graph:retrieval", + user="trustgraph", + collection="scientists" + ) + print(f"Entity: {entity}") +``` + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]` + +Bir Model Bağlam Protokolü (MCP) aracını çalıştırın. + +**Argümanlar:** + +`name`: Araç adı/tanımlayıcı +`parameters`: Araç parametreleri sözlüğü +`**kwargs`: Hizmete iletilen ek parametreler + +**Döndürür:** dict: Aracın çalıştırma sonucu + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +result = flow.mcp_tool( + name="search-web", + parameters={"query": "latest AI news", "limit": 5} +) +``` + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs: Any) -> str | Iterator[str]` + +İsteğe bağlı akışla bir istem şablonunu yürütün. + +**Argümanlar:** + +`id`: İstem şablonu tanımlayıcısı +`variables`: Değişken adı ile değer eşlemelerinin sözlüğü +`streaming`: Akış modunu etkinleştir (varsayılan: False) +`**kwargs`: Hizmete iletilen ek parametreler + +**Döndürür:** Union[str, Iterator[str]]: Tam yanıt veya metin parçacıklarının akışı + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Streaming prompt execution +for chunk in flow.prompt( + id="summarize-template", + variables={"topic": "quantum computing", "length": "brief"}, + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs: Any) -> Dict[str, Any]` + +İndekslenmiş alanlar üzerinde semantik benzerlik kullanarak sorgu satır verilerini alın. + +Giriş metnine semantik olarak benzer olan, indekslenmiş alan değerlerine sahip satırları bulur, vektör gömme teknikleri kullanılarak. Bu, yapılandırılmış veriler üzerinde bulanık/semantik eşleşme +sağlar. + + +**Argümanlar:** + +`text`: Anlamsal arama için sorgu metni +`schema_name`: İçinde arama yapılacak şema adı +`user`: Kullanıcı/veri tabanı tanımlayıcısı (varsayılan: "trustgraph") +`collection`: Koleksiyon tanımlayıcısı (varsayılan: "default") +`index_name`: Aramayı belirli bir indekse sınırlamak için isteğe bağlı indeks adı +`limit`: Maksimum sonuç sayısı (varsayılan: 10) +`**kwargs`: Hizmete iletilen ek parametreler + +**Döndürür:** dict: Eşleşmeleri içeren, index_name, index_value, text ve score alanlarını içeren sorgu sonuçları + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Search for customers by name similarity +results = flow.row_embeddings_query( + text="John Smith", + schema_name="customers", + user="trustgraph", + collection="sales", + limit=5 +) + +# Filter to specific index +results = flow.row_embeddings_query( + text="machine learning engineer", + schema_name="employees", + index_name="job_title", + limit=10 +) +``` + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict[str, Any] | None = None, operation_name: str | None = None, **kwargs: Any) -> Dict[str, Any]` + +Yapılandırılmış satırlara karşı bir GraphQL sorgusu çalıştırın. + +**Argümanlar:** + +`query`: GraphQL sorgu dizesi +`user`: Kullanıcı/keyspace tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`variables`: İsteğe bağlı sorgu değişkenleri sözlüğü +`operation_name`: Çoklu işlem belgeleri için isteğe bağlı işlem adı +`**kwargs`: Hizmete iletilen ek parametreler + +**Döndürür:** dict: Veri, hatalar ve/veya uzantılar içeren GraphQL yanıtı + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +query = ''' +{ + scientists(limit: 10) { + name + field + discoveries + } +} +''' +result = flow.rows_query( + query=query, + user="trustgraph", + collection="scientists" +) +``` + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs) -> str | Iterator[str]` + +İsteğe bağlı akışla metin tamamlama işlemini gerçekleştirin. + +**Argümanlar:** + +`system`: Asistanın davranışını tanımlayan sistem istemi +`prompt`: Kullanıcı istemi/sorusu +`streaming`: Akış modunu etkinleştir (varsayılan: False) +`**kwargs`: Hizmete iletilen ek parametreler + +**Dönüş:** Union[str, Iterator[str]]: Tamamlanmış yanıt veya metin parçalarının akışı + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Non-streaming +response = flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=False +) +print(response) + +# Streaming +for chunk in flow.text_completion( + system="You are helpful", + prompt="Explain quantum computing", + streaming=True +): + print(chunk, end='', flush=True) +``` + +### `triples_query(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, **kwargs: Any) -> List[Dict[str, Any]]` + +Desen eşleştirme kullanarak bilgi grafiği üçlülerini sorgulayın. + +**Argümanlar:** + +`s`: Konu filtresi - URI dizesi, Terim sözlüğü veya joker karakter için None +`p`: Özne filtresi - URI dizesi, Terim sözlüğü veya joker karakter için None +`o`: Nesne filtresi - URI/literal dizesi, Terim sözlüğü veya joker karakter için None +`g`: Adlandırılmış grafik filtresi - URI dizesi veya tüm grafikler için None +`user`: Kullanıcı/uzay kimlik tanımlayıcısı (isteğe bağlı) +`collection`: Koleksiyon kimlik tanımlayıcısı (isteğe bağlı) +`limit`: Döndürülecek maksimum sonuç sayısı (varsayılan: 100) +`**kwargs`: Hizmete geçirilecek ek parametreler + +**Döndürür:** List[Dict]: Tel formatındaki eşleşen üçlülerin listesi + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +# Find all triples about a specific subject +triples = flow.triples_query( + s="http://example.org/person/marie-curie", + user="trustgraph", + collection="scientists" +) + +# Query with named graph filter +triples = flow.triples_query( + s="urn:trustgraph:session:abc123", + g="urn:graph:retrieval", + user="trustgraph", + collection="default" +) +``` + +### `triples_query_stream(self, s: str | Dict[str, Any] | None = None, p: str | Dict[str, Any] | None = None, o: str | Dict[str, Any] | None = None, g: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 100, batch_size: int = 20, **kwargs: Any) -> Iterator[List[Dict[str, Any]]]` + +Akışlı toplu işlemlerle bilgi grafiği üçlülerini sorgulayın. + +Üçlüleri geldikleri gibi toplu olarak döndürür, böylece ilk sonuç alma süresini ve büyük sonuç kümeleri için bellek yükünü azaltır. + + +**Parametreler:** + +`s`: Konu filtresi - URI dizesi, Terim sözlüğü veya joker karakter için None +`p`: Özne filtresi - URI dizesi, Terim sözlüğü veya joker karakter için None +`o`: Nesne filtresi - URI/literal dizesi, Terim sözlüğü veya joker karakter için None +`g`: Adlandırılmış grafik filtresi - URI dizesi veya tüm grafikler için None +`user`: Kullanıcı/keyspace tanımlayıcısı (isteğe bağlı) +`collection`: Koleksiyon tanımlayıcısı (isteğe bağlı) +`limit`: Döndürülecek maksimum sonuç sayısı (varsayılan: 100) +`batch_size`: Toplu işlemdeki üçlü sayısı (varsayılan: 20) +`**kwargs`: Hizmete geçirilecek ek parametreler +`Yields`: +`List[Dict]`: Tel formatındaki üçlü topları + +**Örnek:** + +```python +socket = api.socket() +flow = socket.flow("default") + +for batch in flow.triples_query_stream( + user="trustgraph", + collection="default" +): + for triple in batch: + print(triple["s"], triple["p"], triple["o"]) +``` + + +-- + +## `AsyncSocketClient` + +```python +from trustgraph.api import AsyncSocketClient +``` + +Asenkron WebSocket istemcisi + +### Yöntemler + +### `__init__(self, url: str, timeout: int, token: str | None)` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + +### `aclose(self)` + +WebSocket bağlantısını kapat + +### `flow(self, flow_id: str)` + +WebSocket işlemleri için asenkron akış örneğini al + + +-- + +## `AsyncSocketFlowInstance` + +```python +from trustgraph.api import AsyncSocketFlowInstance +``` + +Asenkron WebSocket akışı örneği + +### Yöntemler + +### `__init__(self, client: trustgraph.api.async_socket_client.AsyncSocketClient, flow_id: str)` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + +### `agent(self, question: str, user: str, state: Dict[str, Any] | None = None, group: str | None = None, history: list | None = None, streaming: bool = False, **kwargs) -> Dict[str, Any] | AsyncIterator` + +İsteğe bağlı akışa sahip ajan + +### `document_rag(self, query: str, user: str, collection: str, doc_limit: int = 10, streaming: bool = False, **kwargs)` + +İsteğe bağlı akışa sahip RAG dokümanı + +### `embeddings(self, texts: list, **kwargs)` + +Metin gömülmelerini oluştur + +### `graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs)` + +Anlamsal arama için grafik gömülmelerini sorgula + +### `graph_rag(self, query: str, user: str, collection: str, max_subgraph_size: int = 1000, max_subgraph_count: int = 5, max_entity_distance: int = 3, streaming: bool = False, **kwargs)` + +İsteğe bağlı akışa sahip grafik RAG + +### `mcp_tool(self, name: str, parameters: Dict[str, Any], **kwargs)` + +MCP aracını çalıştır + +### `prompt(self, id: str, variables: Dict[str, str], streaming: bool = False, **kwargs)` + +İsteğe bağlı akışa sahip istemi çalıştır + +### `row_embeddings_query(self, text: str, schema_name: str, user: str = 'trustgraph', collection: str = 'default', index_name: str | None = None, limit: int = 10, **kwargs)` + +Yapılandırılmış veriler üzerinde anlamsal arama için satır gömülmelerini sorgula + +### `rows_query(self, query: str, user: str, collection: str, variables: Dict | None = None, operation_name: str | None = None, **kwargs)` + +Yapılandırılmış satırlara karşı GraphQL sorgusu + +### `text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs)` + +İsteğe bağlı akışa sahip metin tamamlama + +### `triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs)` + +Üçlü desen sorgusu + + +-- + +### `build_term(value: Any, term_type: str | None = None, datatype: str | None = None, language: str | None = None) -> Dict[str, Any] | None` + +Bir değerden tel formatlı Term sözlüğünü oluştur. + +Otomatik algılama kuralları (term_type None olduğunda): + Zaten 't' anahtarına sahip bir sözlük -> olduğu gibi döndür (zaten bir Term) + http://, https://, urn: ile başlıyorsa -> IRI + <> (örneğin, ) içinde ise -> IRI (köşeli parantezler kaldırılır) + Başka bir şey -> literal + +**Argümanlar:** + +`value`: Term değeri (string, sözlük veya None) +`term_type`: 'iri', 'literal' veya otomatik algılama için +`datatype`: Literal nesneler için veri türü (örneğin, xsd:integer) +`language`: Literal nesneler için dil etiketi (örneğin, en) + +**Döndürür:** sözlük: Tel formatlı Term sözlüğü veya değer None ise None + + +-- + +## `BulkClient` + +```python +from trustgraph.api import BulkClient +``` + +İçe/dışa aktarım için senkron toplu işlemler istemcisi. + +Büyük veri kümeleri için WebSocket üzerinden verimli toplu veri aktarımı sağlar. +Kullanım kolaylığı için asenkron WebSocket işlemlerini senkron oluşturucularla birleştirir. + +Not: Gerçek asenkron destek için, AsyncBulkClient'ı kullanın. + +### Yöntemler + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Senkron toplu istemciyi başlatır. + +**Argümanlar:** + +`url`: TrustGraph API'si için temel URL (HTTP/HTTPS, WS/WSS'ye dönüştürülecektir). +`timeout`: WebSocket zaman aşımı (saniye cinsinden). +`token`: İsteğe bağlı, kimlik doğrulama için taşıyıcı belirteci. + +### `close(self) -> None` + +Bağlantıları kapatır. + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Bir akıştan toplu belge gömme çıktılarını dışa aktarır. + +Tüm belge parçası gömmelerini WebSocket akışı üzerinden verimli bir şekilde indirir. + +**Argümanlar:** + +`flow`: Akış tanımlayıcısı. +`**kwargs`: Ek parametreler (gelecekteki kullanım için ayrılmıştır). + +**Döndürür:** Iterator[Dict[str, Any]]: Gömme sözlüklerinin akışı. + +**Örnek:** + +```python +bulk = api.bulk() + +# Export and process document embeddings +for embedding in bulk.export_document_embeddings(flow="default"): + chunk_id = embedding.get("chunk_id") + vector = embedding.get("embedding") + print(f"{chunk_id}: {len(vector)} dimensions") +``` + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Bir akıştan toplu olarak varlık bağlamlarını dışa aktarın. + +Tüm varlık bağlamı bilgilerini WebSocket akışı aracılığıyla verimli bir şekilde indirir. + +**Argümanlar:** + +`flow`: Akış tanımlayıcısı +`**kwargs`: Ek parametreler (gelecekteki kullanım için ayrılmıştır) + +**Döndürür:** Iterator[Dict[str, Any]]: Bağlam sözlüklerinin akışı + +**Örnek:** + +```python +bulk = api.bulk() + +# Export and process entity contexts +for context in bulk.export_entity_contexts(flow="default"): + entity = context.get("entity") + text = context.get("context") + print(f"{entity}: {text[:100]}...") +``` + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]` + +Bir akıştan toplu grafik gömme verilerini dışa aktarın. + +Tüm grafik varlık gömme verilerini WebSocket üzerinden verimli bir şekilde indirir. + +**Parametreler:** + +`flow`: Akış tanımlayıcısı +`**kwargs`: Ek parametreler (gelecekteki kullanım için ayrılmıştır) + +**Döndürür:** Iterator[Dict[str, Any]]: Gömme sözlüklerinin akışı + +**Örnek:** + +```python +bulk = api.bulk() + +# Export and process embeddings +for embedding in bulk.export_graph_embeddings(flow="default"): + entity = embedding.get("entity") + vector = embedding.get("embedding") + print(f"{entity}: {len(vector)} dimensions") +``` + +### `export_triples(self, flow: str, **kwargs: Any) -> Iterator[trustgraph.api.types.Triple]` + +Bir akıştan RDF üçlülerini toplu olarak dışa aktarın. + +Tüm üçlüleri WebSocket akışı aracılığıyla verimli bir şekilde indirir. + +**Argümanlar:** + +`flow`: Akış tanımlayıcısı +`**kwargs`: Ek parametreler (gelecekteki kullanım için ayrılmıştır) + +**Döndürür:** Iterator[Triple]: Triple nesnelerinin akışı + +**Örnek:** + +```python +bulk = api.bulk() + +# Export and process triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +### `import_document_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Bir akışa belge gömme verilerini toplu olarak aktarın. + +Belge parçası gömme verilerini, belge RAG sorgularında kullanılmak üzere, WebSocket akışı aracılığıyla verimli bir şekilde yükler. + + +**Argümanlar:** + +`flow`: Akış tanımlayıcısı +`embeddings`: Gömme sözlükleri üreten yineleyici +`**kwargs`: Ek parametreler (gelecekteki kullanım için ayrılmıştır) + +**Örnek:** + +```python +bulk = api.bulk() + +# Generate document embeddings to import +def doc_embedding_generator(): + yield {"chunk_id": "doc1/p0/c0", "embedding": [0.1, 0.2, ...]} + yield {"chunk_id": "doc1/p0/c1", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_document_embeddings( + flow="default", + embeddings=doc_embedding_generator() +) +``` + +### `import_entity_contexts(self, flow: str, contexts: Iterator[Dict[str, Any]], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +Bir akışa toplu olarak varlık bağlamlarını aktarın. + +Varlık bağlamı bilgilerini WebSocket akışı aracılığıyla verimli bir şekilde yükler. +Varlık bağlamları, grafik varlıkları hakkında ek metinsel bağlam sağlar +ve geliştirilmiş RAG performansı için kullanılır. + +**Argümanlar:** + +`flow`: Akış tanımlayıcısı +`contexts`: Bağlam sözlükleri üreten yineleyici +`metadata`: id, metadata, kullanıcı, koleksiyon içeren meta veri sözlüğü +`batch_size`: Toplu iş başına bağlam sayısı (varsayılan 100) +`**kwargs`: Ek parametreler (gelecekteki kullanım için ayrılmıştır) + +**Örnek:** + +```python +bulk = api.bulk() + +# Generate entity contexts to import +def context_generator(): + yield {"entity": {"v": "entity1", "e": True}, "context": "Description..."} + yield {"entity": {"v": "entity2", "e": True}, "context": "Description..."} + # ... more contexts + +bulk.import_entity_contexts( + flow="default", + contexts=context_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + +### `import_graph_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Bir akışa toplu olarak grafik gömme verilerini aktarın. + +Grafik varlık gömme verilerini WebSocket üzerinden verimli bir şekilde yükleyin. + +**Parametreler:** + +`flow`: Akış tanımlayıcısı +`embeddings`: Gömme sözlükleri üreten yineleyici +`**kwargs`: Ek parametreler (gelecekteki kullanım için ayrılmıştır) + +**Örnek:** + +```python +bulk = api.bulk() + +# Generate embeddings to import +def embedding_generator(): + yield {"entity": "entity1", "embedding": [0.1, 0.2, ...]} + yield {"entity": "entity2", "embedding": [0.3, 0.4, ...]} + # ... more embeddings + +bulk.import_graph_embeddings( + flow="default", + embeddings=embedding_generator() +) +``` + +### `import_rows(self, flow: str, rows: Iterator[Dict[str, Any]], **kwargs: Any) -> None` + +Bir akışa yapılandırılmış satırları toplu olarak aktarın. + +Yapılandırılmış veri satırlarını, GraphQL sorgularında kullanılmak üzere WebSocket akışı aracılığıyla verimli bir şekilde yükleyin. + + +**Argümanlar:** + +`flow`: Akış tanımlayıcısı +`rows`: Satır sözlükleri üreten yineleyici +`**kwargs`: Ek parametreler (gelecekteki kullanım için ayrılmıştır) + +**Örnek:** + +```python +bulk = api.bulk() + +# Generate rows to import +def row_generator(): + yield {"id": "row1", "name": "Row 1", "value": 100} + yield {"id": "row2", "name": "Row 2", "value": 200} + # ... more rows + +bulk.import_rows( + flow="default", + rows=row_generator() +) +``` + +### `import_triples(self, flow: str, triples: Iterator[trustgraph.api.types.Triple], metadata: Dict[str, Any] | None = None, batch_size: int = 100, **kwargs: Any) -> None` + +Bir akışa RDF üçlülerini toplu olarak aktarın. + +Büyük miktarlarda üçlü verisini WebSocket akışı aracılığıyla verimli bir şekilde yükler. + +**Parametreler:** + +`flow`: Akış tanımlayıcısı +`triples`: Triple nesneleri üreten yineleyici +`metadata`: id, metadata, kullanıcı, koleksiyon içeren meta veri sözlüğü +`batch_size`: Her topluluktaki üçlü sayısı (varsayılan 100) +`**kwargs`: Ek parametreler (gelecekteki kullanım için ayrılmıştır) + +**Örnek:** + +```python +from trustgraph.api import Triple + +bulk = api.bulk() + +# Generate triples to import +def triple_generator(): + yield Triple(s="subj1", p="pred", o="obj1") + yield Triple(s="subj2", p="pred", o="obj2") + # ... more triples + +# Import triples +bulk.import_triples( + flow="default", + triples=triple_generator(), + metadata={"id": "doc1", "metadata": [], "user": "user1", "collection": "default"} +) +``` + + +-- + +## `AsyncBulkClient` + +```python +from trustgraph.api import AsyncBulkClient +``` + +Asenkron toplu işlemler istemcisi + +### Yöntemler + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + +### `aclose(self) -> None` + +Bağlantıları kapat + +### `export_document_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +WebSocket üzerinden belge gömme verilerini toplu olarak dışa aktar + +### `export_entity_contexts(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +WebSocket üzerinden varlık bağlamlarını toplu olarak dışa aktar + +### `export_graph_embeddings(self, flow: str, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]` + +WebSocket üzerinden grafik gömme verilerini toplu olarak dışa aktar + +### `export_triples(self, flow: str, **kwargs: Any) -> AsyncIterator[trustgraph.api.types.Triple]` + +WebSocket üzerinden üçlüleri toplu olarak dışa aktar + +### `import_document_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +WebSocket üzerinden belge gömme verilerini toplu olarak içe aktar + +### `import_entity_contexts(self, flow: str, contexts: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +WebSocket üzerinden varlık bağlamlarını toplu olarak içe aktar + +### `import_graph_embeddings(self, flow: str, embeddings: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +WebSocket üzerinden grafik gömme verilerini toplu olarak içe aktar + +### `import_rows(self, flow: str, rows: AsyncIterator[Dict[str, Any]], **kwargs: Any) -> None` + +WebSocket üzerinden satırları toplu olarak içe aktar + +### `import_triples(self, flow: str, triples: AsyncIterator[trustgraph.api.types.Triple], **kwargs: Any) -> None` + +WebSocket üzerinden üçlüleri toplu olarak içe aktar + + +-- + +## `Metrics` + +```python +from trustgraph.api import Metrics +``` + +Senkron ölçüm istemcisi + +### Yöntemler + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + +### `get(self) -> str` + +Prometheus ölçümlerini metin olarak al + + +-- + +## `AsyncMetrics` + +```python +from trustgraph.api import AsyncMetrics +``` + +Asenkron metrik istemcisi + +### Yöntemler + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + +### `aclose(self) -> None` + +Bağlantıları kapat + +### `get(self) -> str` + +Prometheus metriklerini metin olarak al + + +-- + +## `ExplainabilityClient` + +```python +from trustgraph.api import ExplainabilityClient +``` + +Açıklanabilirlik varlıklarını, nihai tutarlılık işleme ile getirmek için kullanılan istemci. + +Aşağıdaki dinlenme algılama yöntemini kullanır: getirme, bekleme, tekrar getirme, karşılaştırma. +Sonuçlar aynıysa, veri kararlıdır. + +### Yöntemler + +### `__init__(self, flow_instance, retry_delay: float = 0.2, max_retries: int = 10)` + +Açıklanabilirlik istemcisini başlat. + +**Argümanlar:** + +`flow_instance`: Üçlüleri sorgulamak için bir SocketFlowInstance. +`retry_delay`: Tekrar denemeler arasındaki gecikme (varsayılan: 0.2). +`max_retries`: Maksimum tekrar deneme sayısı (varsayılan: 10). + +### `detect_session_type(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> str` + +Bir oturumun GraphRAG veya Agent türünde olup olmadığını tespit edin. + +**Argümanlar:** + +`session_uri`: Oturum/soru URI'si. +`graph`: Adlandırılmış grafik. +`user`: Kullanıcı/keyspace tanımlayıcısı. +`collection`: Koleksiyon tanımlayıcısı. + +**Döndürür:** "graphrag" veya "agent". + +### `fetch_agent_trace(self, session_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Bir oturum URI'sinden başlayarak, tamamlanmış Agent izini alın. + +Aşağıdaki köken zincirini izleyin: Soru -> Analiz(ler) -> Sonuç. + +**Argümanlar:** + +`session_uri`: Agent oturum/soru URI'si. +`graph`: Adlandırılmış grafik (varsayılan: urn:graph:retrieval). +`user`: Kullanıcı/keyspace tanımlayıcısı. +`collection`: Koleksiyon tanımlayıcısı. +`api`: Kütüphaneci erişimi için TrustGraph Api örneği (isteğe bağlı). +`max_content`: Sonuç için maksimum içerik uzunluğu. + +**Döndürür:** Soru, yinelemeler (Analiz listesi), sonuç varlıkları ile birlikte bir Sözlük. + +### `fetch_docrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Bir soru URI'sinden başlayarak, tamamlanmış DocumentRAG izini alın. + +Aşağıdaki köken zincirini izleyin: + Soru -> Yerleştirme -> Keşif -> Sentez. + +**Argümanlar:** + +`question_uri`: Soru varlık URI'si. +`graph`: Adlandırılmış grafik (varsayılan: urn:graph:retrieval). +`user`: Kullanıcı/keyspace tanımlayıcısı. +`collection`: Koleksiyon tanımlayıcısı. +`api`: Kütüphaneci erişimi için TrustGraph Api örneği (isteğe bağlı). +`max_content`: Sentez için maksimum içerik uzunluğu. + +**Döndürür:** Soru, yerleştirme, keşif, sentez varlıkları ile birlikte bir Sözlük. + +### `fetch_document_content(self, document_uri: str, api: Any, user: str | None = None, max_content: int = 10000) -> str` + +Bir belge URI'si tarafından kütüphaneciden içerik alın. + +**Argümanlar:** + +`document_uri`: Kütüphanecideki belge URI'si. +`api`: Kütüphaneci erişimi için TrustGraph Api örneği. +`user`: Kütüphaneci için kullanıcı tanımlayıcısı. +`max_content`: Döndürülecek maksimum içerik uzunluğu. + +**Döndürür:** Belge içeriğini bir dize olarak. + +### `fetch_edge_selection(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.EdgeSelection | None` + +Bir kenar seçimi varlığı alın (Focus tarafından kullanılır). + +**Argümanlar:** + +`uri`: Kenar seçimi URI'si. +`graph`: Sorgulanacak adlandırılmış grafik. +`user`: Kullanıcı/keyspace tanımlayıcısı. +`collection`: Koleksiyon tanımlayıcısı. + +**Döndürür:** EdgeSelection veya bulunamazsa None. + +### `fetch_entity(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.ExplainEntity | None` + +Bir URI'yi, olası tutarlılık yönetimi ile bir açıklanabilirlik varlığı olarak alın. + +Aşağıdaki durgunluk tespitini kullanır: +1. URI için üçlüleri alın +2. Sıfır sonuç varsa, tekrar deneyin +3. Sıfır olmayan sonuçlar varsa, bekleyin ve tekrar alın +4. Aynı sonuçlar varsa, veri kararlıdır - ayrıştırın ve döndürün +5. Farklı sonuçlar varsa, veri hala yazılıyor - tekrar deneyin + +**Argümanlar:** + +`uri`: Alınacak varlık URI'si +`graph`: Sorgulanacak adlandırılmış grafik (örneğin, "urn:graph:retrieval") +`user`: Kullanıcı/anahtar alanı tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı + +**Döndürür:** Açıklanabilir Varlık alt sınıfı veya bulunamazsa None + +### `fetch_focus_with_edges(self, uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None) -> trustgraph.api.explainability.Focus | None` + +Bir Focus varlığını ve tüm kenar seçimlerini alın. + +**Argümanlar:** + +`uri`: Focus varlık URI'si +`graph`: Sorgulanacak adlandırılmış grafik +`user`: Kullanıcı/anahtar alanı tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı + +**Döndürür:** Doldurulmuş kenar_seçimleri ile Focus veya bulunamazsa None + +### `fetch_graphrag_trace(self, question_uri: str, graph: str | None = None, user: str | None = None, collection: str | None = None, api: Any = None, max_content: int = 10000) -> Dict[str, Any]` + +Bir soru URI'sinden başlayarak, tamamlanmış GraphRAG izini alın. + +Aşağıdaki köken zincirini izler: Soru -> Yerleştirme -> Keşif -> Focus -> Sentez + +**Argümanlar:** + +`question_uri`: Soru varlık URI'si +`graph`: Adlandırılmış grafik (varsayılan: urn:graph:retrieval) +`user`: Kullanıcı/anahtar alanı tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`api`: Kütüphaneci erişimi için TrustGraph Api örneği (isteğe bağlı) +`max_content`: Sentez için maksimum içerik uzunluğu + +**Döndürür:** Soru, yerleştirme, keşif, focus, sentez varlıkları ile Sözlük + +### `list_sessions(self, graph: str | None = None, user: str | None = None, collection: str | None = None, limit: int = 50) -> List[trustgraph.api.explainability.Question]` + +Bir koleksiyondaki tüm açıklanabilirlik oturumlarını (soruları) listeleyin. + +**Argümanlar:** + +`graph`: Adlandırılmış grafik (varsayılan: urn:graph:retrieval) +`user`: Kullanıcı/anahtar alanı tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı +`limit`: Döndürülecek maksimum oturum sayısı + +**Döndürür:** Zaman damgasına göre sıralanmış (en yeni ilk) Soru varlıkları listesi + +### `resolve_edge_labels(self, edge: Dict[str, str], user: str | None = None, collection: str | None = None) -> Tuple[str, str, str]` + +Bir kenar üçlüsünün tüm bileşenleri için etiketleri çözün. + +**Argümanlar:** + +`edge`: "s", "p", "o" anahtarlarına sahip Sözlük +`user`: Kullanıcı/anahtar alanı tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı + +**Döndürür:** (s_etiketi, p_etiketi, o_etiketi) tuple'ı + +### `resolve_label(self, uri: str, user: str | None = None, collection: str | None = None) -> str` + +Bir URI için rdfs:label'i, önbellekleme ile çözün. + +**Argümanlar:** + +`uri`: Etiketi alınacak URI +`user`: Kullanıcı/anahtar alanı tanımlayıcısı +`collection`: Koleksiyon tanımlayıcısı + +**Döndürür:** Bulunursa etiketi, aksi takdirde URI'yi kendisi + + +-- + +## `ExplainEntity` + +```python +from trustgraph.api import ExplainEntity +``` + +Açıklanabilirlik varlıkları için temel sınıf. + +**Alanlar:** + +`uri`: +`entity_type`: + +### Yöntemler + +### `__init__(self, uri: str, entity_type: str = '') -> None` + +Kendini başlatır. Doğru imza için help(type(self))'e bakın. + + +-- + +## `Question` + +```python +from trustgraph.api import Question +``` + +Soru varlığı - oturumu başlatan kullanıcının sorgusu. + +**Alanlar:** + +`uri`: +`entity_type`: +`query`: +`timestamp`: +`question_type`: + +### Yöntemler + +### `__init__(self, uri: str, entity_type: str = '', query: str = '', timestamp: str = '', question_type: str = '') -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `Exploration` + +```python +from trustgraph.api import Exploration +``` + +Keşif varlığı - bilgi deposundan alınan kenarlar/parçalar. + +**Alanlar:** + +`uri`: +`entity_type`: +`edge_count`: +`chunk_count`: +`entities`: typing.List[str] + +### Yöntemler + +### `__init__(self, uri: str, entity_type: str = '', edge_count: int = 0, chunk_count: int = 0, entities: List[str] = ) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `Focus` + +```python +from trustgraph.api import Focus +``` + +Odak varlığı - LLM akıl yürütmesiyle seçilen kenarlar (yalnızca GraphRAG). + +**Alanlar:** + +`uri`: +`entity_type`: +`selected_edge_uris`: typing.List[str] +`edge_selections`: typing.List[trustgraph.api.explainability.EdgeSelection] + +### Yöntemler + +### `__init__(self, uri: str, entity_type: str = '', selected_edge_uris: List[str] = , edge_selections: List[trustgraph.api.explainability.EdgeSelection] = ) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `Synthesis` + +```python +from trustgraph.api import Synthesis +``` + +Sentez varlığı - nihai cevap. + +**Alanlar:** + +`uri`: +`entity_type`: +`document`: + +### Yöntemler + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `Analysis` + +```python +from trustgraph.api import Analysis +``` + +Analiz varlığı - bir düşünme/eylem/gözlem döngüsü (Sadece Ajan). + +**Alanlar:** + +`uri`: +`entity_type`: +`action`: +`arguments`: +`thought`: +`observation`: + +### Yöntemler + +### `__init__(self, uri: str, entity_type: str = '', action: str = '', arguments: str = '', thought: str = '', observation: str = '') -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `Conclusion` + +```python +from trustgraph.api import Conclusion +``` + +Sonuç varlığı - kesin cevap (Sadece Ajan). + +**Alanlar:** + +`uri`: +`entity_type`: +`document`: + +### Yöntemler + +### `__init__(self, uri: str, entity_type: str = '', document: str = '') -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `EdgeSelection` + +```python +from trustgraph.api import EdgeSelection +``` + +GraphRAG Odak adımı tarafından sağlanan bir mantıkla seçilen bir kenar. + +**Alanlar:** + +`uri`: +`edge`: typing.Dict[str, str] | None +`reasoning`: + +### Yöntemler + +### `__init__(self, uri: str, edge: Dict[str, str] | None = None, reasoning: str = '') -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +### `wire_triples_to_tuples(wire_triples: List[Dict[str, Any]]) -> List[Tuple[str, str, Any]]` + +Kablolu üçlüleri (s, p, o) demetlerine dönüştürün. + + +-- + +### `extract_term_value(term: Dict[str, Any]) -> Any` + +Bir kablolu Term sözlüğünden değer çıkarın. + + +-- + +## `Triple` + +```python +from trustgraph.api import Triple +``` + +Bilgi grafiği ifadesini temsil eden RDF üçlüsü. + +**Alanlar:** + +`s`: +`p`: +`o`: + +### Yöntemler + +### `__init__(self, s: str, p: str, o: str) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `Uri` + +```python +from trustgraph.api import Uri +``` + +str(nesne='') -> str +str(bayt_veya_tampon[, kodlama[, hatalar]]) -> str + +Verilen nesneden yeni bir dize nesnesi oluşturur. Eğer kodlama veya +hatalar belirtildiyse, nesne, belirtilen kodlama ve hata işleyicisi kullanılarak +çözümlenecek bir veri tamponu içermelidir. +Aksi takdirde, object.__str__()'nin sonucunu (eğer tanımlıysa) +veya repr(object)'in sonucunu döndürür. +kodlama varsayılan olarak 'utf-8' değerine sahiptir. +hatalar varsayılan olarak 'strict' değerine sahiptir. + +### Metotlar + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `Literal` + +```python +from trustgraph.api import Literal +``` + +str(nesne='') -> str +str(bayt_veya_tampon[, kodlama[, hatalar]]) -> str + +Verilen nesneden yeni bir dize nesnesi oluşturur. Eğer kodlama veya +hatalar belirtildiyse, nesne, belirtilen kodlama ve hata işleyici kullanılarak +çözümlenecek bir veri tamponu içermelidir. +Aksi takdirde, nesnenin object.__str__() (eğer tanımlıysa) +veya repr(nesne) sonucunu döndürür. +kodlama varsayılan olarak 'utf-8' değerine sahiptir. +hatalar varsayılan olarak 'strict' değerine sahiptir. + +### Yöntemler + +### `is_literal(self)` + +### `is_triple(self)` + +### `is_uri(self)` + + +-- + +## `ConfigKey` + +```python +from trustgraph.api import ConfigKey +``` + +Yapılandırma anahtar tanımlayıcısı. + +**Alanlar:** + +`type`: +`key`: + +### Yöntemler + +### `__init__(self, type: str, key: str) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `ConfigValue` + +```python +from trustgraph.api import ConfigValue +``` + +Yapılandırma anahtar-değer çifti. + +**Alanlar:** + +`type`: +`key`: +`value`: + +### Metotlar + +### `__init__(self, type: str, key: str, value: str) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `DocumentMetadata` + +```python +from trustgraph.api import DocumentMetadata +``` + +Kütüphanedeki bir belge için meta veri. + +**Özellikler:** + +`parent_id: Parent document ID for child documents (empty for top`: level docs) + +**Alanlar:** + +`id`: +`time`: +`kind`: +`title`: +`comments`: +`metadata`: typing.List[trustgraph.api.types.Triple] +`user`: +`tags`: typing.List[str] +`parent_id`: +`document_type`: + +### Yöntemler + +### `__init__(self, id: str, time: datetime.datetime, kind: str, title: str, comments: str, metadata: List[trustgraph.api.types.Triple], user: str, tags: List[str], parent_id: str = '', document_type: str = 'source') -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `ProcessingMetadata` + +```python +from trustgraph.api import ProcessingMetadata +``` + +Etkin bir belge işleme işi için meta veriler. + +**Alanlar:** + +`id`: +`document_id`: +`time`: +`flow`: +`user`: +`collection`: +`tags`: typing.List[str] + +### Yöntemler + +### `__init__(self, id: str, document_id: str, time: datetime.datetime, flow: str, user: str, collection: str, tags: List[str]) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `CollectionMetadata` + +```python +from trustgraph.api import CollectionMetadata +``` + +Bir veri koleksiyonu için meta veri. + +Koleksiyonlar, belgeler ve +bilgi grafiği verileri için mantıksal gruplama ve izolasyon sağlar. + +**Özellikler:** + +`name: Human`: okunabilir koleksiyon adı + +**Alanlar:** + +`user`: +`collection`: +`name`: +`description`: +`tags`: typing.List[str] + +### Yöntemler + +### `__init__(self, user: str, collection: str, name: str, description: str, tags: List[str]) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `StreamingChunk` + +```python +from trustgraph.api import StreamingChunk +``` + +Akış yanıtı parçacıkları için temel sınıf. + +Yanıtların üretildikleri gibi kademeli olarak iletildiği, WebSocket tabanlı akış işlemlerinde kullanılır. + + +**Alanlar:** + +`content`: +`end_of_message`: + +### Yöntemler + +### `__init__(self, content: str, end_of_message: bool = False) -> None` + +Kendini başlatır. Doğru imza için help(type(self))'e bakın. + + +-- + +## `AgentThought` + +```python +from trustgraph.api import AgentThought +``` + +Ajanın muhakeme/düşünce süreci parçası. + +Ajanın yürütme sırasında kullandığı iç muhakeme veya planlama adımlarını temsil eder. +Bu parçalar, ajanın problemi nasıl düşündüğünü gösterir. + +**Alanlar:** + +`content`: +`end_of_message`: +`chunk_type`: + +### Yöntemler + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'thought') -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `AgentObservation` + +```python +from trustgraph.api import AgentObservation +``` + +Ajan aracı yürütme gözlemi parçası. + +Bir aracın veya eylemin yürütülmesinden elde edilen sonucu veya gözlemi temsil eder. +Bu parçalar, ajanın araçları kullanmaktan ne öğrendiğini gösterir. + +**Alanlar:** + +`content`: +`end_of_message`: +`chunk_type`: + +### Yöntemler + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'observation') -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `AgentAnswer` + +```python +from trustgraph.api import AgentAnswer +``` + +Ajanın son yanıt parçası. + +Kullanıcının sorgusuna, akıl yürütme ve araç kullanımını tamamladıktan sonra, ajanın verdiği son yanıtı temsil eder. + + +**Özellikler:** + +`chunk_type: Always "final`: answer" + +**Alanlar:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_dialog`: + +### Yöntemler + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'final-answer', end_of_dialog: bool = False) -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `RAGChunk` + +```python +from trustgraph.api import RAGChunk +``` + +RAG (Retrieval-Augmented Generation) akışı parçası. + +Grafik RAG, belge RAG, metin tamamlama, +ve diğer üretken hizmetlerden gelen yanıtları akış için kullanılır. + +**Alanlar:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_stream`: +`error`: typing.Dict[str, str] | None + +### Yöntemler + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'rag', end_of_stream: bool = False, error: Dict[str, str] | None = None) -> None` + +Kendini başlatır. Doğru imza için help(type(self))'e bakın. + + +-- + +## `ProvenanceEvent` + +```python +from trustgraph.api import ProvenanceEvent +``` + +Açıklanabilirlik için köken olayları. + +Açıklanabilir mod etkinleştirildiğinde GraphRAG sorguları sırasında yayımlanır. +Her olay, sorgu işleme sırasında oluşturulan bir köken düğümünü temsil eder. + +**Alanlar:** + +`explain_id`: +`explain_graph`: +`event_type`: + +### Yöntemler + +### `__init__(self, explain_id: str, explain_graph: str = '', event_type: str = '') -> None` + +Kendini başlat. Doğru imza için help(type(self))'e bakın. + + +-- + +## `ProtocolException` + +```python +from trustgraph.api import ProtocolException +``` + +WebSocket protokolü hataları oluştuğunda tetiklenir. + + +-- + +## `TrustGraphException` + +```python +from trustgraph.api import TrustGraphException +``` + +Tüm TrustGraph hizmeti hataları için temel sınıf. + + +-- + +## `AgentError` + +```python +from trustgraph.api import AgentError +``` + +Ajan hizmeti hatası + + +-- + +## `ConfigError` + +```python +from trustgraph.api import ConfigError +``` + +Yapılandırma hizmeti hatası + + +-- + +## `DocumentRagError` + +```python +from trustgraph.api import DocumentRagError +``` + +Belge RAG (Retrieval-Augmented Generation) alma hatası + + +-- + +## `FlowError` + +```python +from trustgraph.api import FlowError +``` + +Akış yönetimi hatası + + +-- + +## `GatewayError` + +```python +from trustgraph.api import GatewayError +``` + +API Ağ Geçidi hatası + + +-- + +## `GraphRagError` + +```python +from trustgraph.api import GraphRagError +``` + +Grafik RAG geri alma hatası + + +-- + +## `LLMError` + +```python +from trustgraph.api import LLMError +``` + +LLM hizmeti hatası + + +-- + +## `LoadError` + +```python +from trustgraph.api import LoadError +``` + +Veri yükleme hatası + + +-- + +## `LookupError` + +```python +from trustgraph.api import LookupError +``` + +Arama/ara hata + + +-- + +## `NLPQueryError` + +```python +from trustgraph.api import NLPQueryError +``` + +NLP sorgu hizmeti hatası + + +-- + +## `RowsQueryError` + +```python +from trustgraph.api import RowsQueryError +``` + +Satır sorgu hizmeti hatası + + +-- + +## `RequestError` + +```python +from trustgraph.api import RequestError +``` + +İstek işleme hatası + + +-- + +## `StructuredQueryError` + +```python +from trustgraph.api import StructuredQueryError +``` + +Yapılandırılmış sorgu hizmeti hatası + + +-- + +## `UnexpectedError` + +```python +from trustgraph.api import UnexpectedError +``` + +Beklenmedik/bilinmeyen hata + + +-- + +## `ApplicationException` + +```python +from trustgraph.api import ApplicationException +``` + +Tüm TrustGraph hizmeti hataları için temel sınıf. + + +-- + diff --git a/docs/tech-specs/architecture-principles.zh-cn.md b/docs/tech-specs/architecture-principles.zh-cn.md index c115e1e1..8062853a 100644 --- a/docs/tech-specs/architecture-principles.zh-cn.md +++ b/docs/tech-specs/architecture-principles.zh-cn.md @@ -9,7 +9,7 @@ 奠定基础,"解锁"许多下游功能 支持节点到节点的关系 (SPO) 和节点到字面值关系 (RDF) -**实现**: +**实施**: 核心数据结构: `node → edge → {node | literal}` 在支持扩展的 SPO 操作的同时,保持与 RDF 标准的兼容性 @@ -21,7 +21,7 @@ 图技术选择必须优先考虑与 LLM 的兼容性,而不是其他考虑因素 能够实现利用结构化知识的自然语言处理工作流程 -**实现**: +**实施**: 设计 LLM 可以有效推理的图模式 针对常见的 LLM 交互模式进行优化 @@ -33,7 +33,7 @@ 避免复杂的中间查询生成步骤 提供图结构内部高效的语义搜索功能 -**实现**: +**实施**: `NLP Query → Graph Embeddings → Graph Nodes` 维护所有图实体的嵌入表示 支持用于查询解析的直接语义相似性匹配 @@ -43,26 +43,26 @@ **理由**: **理想**: 单进程提取,具有完整的状态可见性,可以实现完美的实体解析 -**现实**: 可伸缩性要求需要并行处理能力 +**现实**: 可扩展性要求需要并行处理能力 **折衷**: 设计用于在分布式进程中实现确定性实体标识 -**实现**: -开发机制,以在不同的知识提取器中生成一致且唯一的标识符 +**实施**: +开发机制,以生成在不同知识提取器中保持一致且唯一的标识符 在不同的进程中提到的相同实体必须解析为相同的标识符 承认约 20% 的边缘情况可能需要替代处理模型 -设计用于复杂实体解析场景的后备机制 +设计用于处理复杂实体解析场景的后备机制 ## 基础 5:事件驱动架构与发布-订阅 -**决策**: 实现 pub-sub 消息系统,用于系统协调 +**决策**: 实施 pub-sub 消息系统,用于系统协调 **理由**: 允许知识提取、存储和查询组件之间的松散耦合 支持实时更新和跨系统的通知 促进可扩展的分布式处理工作流程 -**实现**: -基于消息的系统组件协调 -事件流用于知识更新、提取完成和查询结果 +**实施**: +使用消息驱动的系统组件协调 +用于知识更新、提取完成和查询结果的事件流 ## 基础 6:可重入代理通信 **决策**: 支持用于基于代理的处理的可重入 pub-sub 操作 @@ -72,9 +72,9 @@ 支持复杂的多步骤知识处理管道 允许递归和迭代处理模式 -**实现**: +**实施**: pub-sub 系统必须安全地处理可重入调用 -代理协调机制,防止无限循环 +防止无限循环的代理协调机制 支持代理工作流程编排 ## 基础 7:列式数据存储集成 @@ -83,12 +83,12 @@ pub-sub 系统必须安全地处理可重入调用 **理由**: 能够对大型知识数据集执行高效的分析查询 支持商业智能和报告用例 -连接基于图的知识表示与传统的分析工作流程 +桥接基于图的知识表示与传统的分析工作流程 -**实现**: +**实施**: 查询转换层:图查询 → 列式查询 -混合存储策略,支持图操作和分析工作负载 -在这两种范例中,保持查询性能 +支持图操作和分析工作负载的混合存储策略 +在这两种范例中保持查询性能 -- @@ -96,11 +96,11 @@ pub-sub 系统必须安全地处理可重入调用 1. **灵活性至上**: SPO/RDF 模型提供最大的适应性 2. **LLM 优化**: 所有设计决策都考虑 LLM 交互要求 -3. **语义效率**: 直接的嵌入到节点映射,以实现最佳查询性能 +3. **语义效率**: 直接的嵌入到节点映射,以实现最佳的查询性能 4. **务实的扩展性**: 在完美准确性和实际的分布式处理之间取得平衡 5. **事件驱动协调**: pub-sub 实现松散耦合和可扩展性 6. **代理友好**: 支持复杂的多代理处理工作流程 -7. **分析兼容性**: 连接图和列式范例,实现全面的查询 +7. **分析兼容性**: 桥接图和列式范例,以实现全面的查询 这些基础构建了一个知识图谱架构,该架构在理论严谨性和实际可扩展性之间取得了平衡,并针对 LLM 集成和分布式处理进行了优化。 diff --git a/docs/tech-specs/extraction-provenance-subgraph.ar.md b/docs/tech-specs/extraction-provenance-subgraph.ar.md new file mode 100644 index 00000000..fd1e7708 --- /dev/null +++ b/docs/tech-specs/extraction-provenance-subgraph.ar.md @@ -0,0 +1,205 @@ +# أصل الاستخراج: نموذج الرسم البياني الفرعي + +## المشكلة + +حاليًا، يقوم تتبع أصل الاستخراج بإنشاء تجسيد كامل لكل ثلاثية مستخرجة: +معرف فريد `stmt_uri`، و `activity_uri`، وبيانات وصفية PROV-O مرتبطة +لكل حقيقة معرفية. يؤدي معالجة جزء واحد ينتج عنه 20 علاقة إلى إنتاج حوالي 220 ثلاثية لتتبع الأصل بالإضافة إلى +حوالي 20 ثلاثية معرفية - وهو عبء إضافي يقدر بحوالي 10:1. + + +هذا مكلف للغاية (من حيث التخزين والفهرسة والنقل) وغير دقيق من الناحية الدلالية. +تتم معالجة كل جزء بواسطة استدعاء واحد لنموذج اللغة الكبير (LLM) ينتج +جميع الثلاثيات الخاصة به في معاملة واحدة. +يخفي النموذج الحالي لكل ثلاثية ذلك من خلال خلق وهم بوجود 20 عملية استخراج +مستقلة. + +بالإضافة إلى ذلك، لا توجد أي معلومات عن مصدرين من أصل أربعة معالجات للاستخراج (kg-extract-ontology، +kg-extract-agent)، مما يترك فجوات في مسار التدقيق. + + +## الحل + +استبدال عملية التجسيد لكل ثلاثية بنموذج **رسم بياني فرعي**: سجل واحد للبيانات الوصفية لكل جزء مستخرج، ويتم مشاركته عبر جميع الثلاثيات الناتجة عن هذا الجزء. + + + +### تغيير في المصطلحات + +| القديم | الجديد | +|-----|-----| +| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | +| `statement_uri()` | `subgraph_uri()` | +| `tg:reifies` (1:1، تطابق) | `tg:contains` (1:كثير، احتواء) | + +### الهيكل المستهدف + +يجب أن تضاف جميع الثلاثيات المتعلقة بأصل البيانات إلى الرسم البياني المسمى `urn:graph:source`. + +``` +# Subgraph contains each extracted triple (RDF-star quoted triples) + tg:contains <> . + tg:contains <> . + tg:contains <> . + +# Derivation from source chunk + prov:wasDerivedFrom . + prov:wasGeneratedBy . + +# Activity: one per chunk extraction + rdf:type prov:Activity . + rdfs:label "{component_name} extraction" . + prov:used . + prov:wasAssociatedWith . + prov:startedAtTime "2026-03-13T10:00:00Z" . + tg:componentVersion "0.25.0" . + tg:llmModel "gpt-4" . # if available + tg:ontology . # if available + +# Agent: stable per component + rdf:type prov:Agent . + rdfs:label "{component_name}" . +``` + +### مقارنة الحجم + +لكل جزء ينتج عنه N من الثلاثيات المستخرجة: + +| | القديم (لكل ثلاثية) | الجديد (الرسم البياني الفرعي) | +|---|---|---| +| `tg:contains` / `tg:reifies` | N | N | +| ثلاثيات النشاط | ~9 × N | ~9 | +| ثلاثيات الوكيل | 2 × N | 2 | +| بيانات التعريف/الرسم البياني الفرعي | 2 × N | 2 | +| **إجمالي ثلاثيات التتبع** | **~13N** | **N + 13** | +| **مثال (N=20)** | **~260** | **33** | + +## النطاق + +### المعالجات التي سيتم تحديثها (التتبع الحالي، لكل ثلاثية) + +**kg-extract-definitions** +(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) + +حاليًا، تستدعي `statement_uri()` + `triple_provenance_triples()` داخل +حلقة التعريف لكل عنصر. + +التغييرات: +نقل إنشاء `subgraph_uri()` و `activity_uri()` قبل الحلقة +جمع ثلاثيات `tg:contains` داخل الحلقة +إخراج كتلة النشاط/الوكيل/الاشتقاق المشتركة مرة واحدة بعد الحلقة + +**kg-extract-relationships** +(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`) + +نفس النمط مثل التعريفات. نفس التغييرات. + +### المعالجات التي يجب إضافتها للتتبع (مفقودة حاليًا) + +**kg-extract-ontology** +(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) + +حاليًا، يقوم بإخراج ثلاثيات بدون مصدر. أضف مصدر الرسم البياني الفرعي. +باستخدام نفس النمط: رسم بياني فرعي واحد لكل جزء، `tg:contains` لكل +ثلاثية مستخرجة. + +**kg-extract-agent** +(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) + +حاليًا، يقوم بإخراج ثلاثيات بدون مصدر. أضف مصدر الرسم البياني الفرعي +باستخدام نفس النمط. + +### تغييرات في مكتبة المصادر المشتركة + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +استبدل `triple_provenance_triples()` بـ `subgraph_provenance_triples()` +تقبل الدالة الجديدة قائمة بالثلاثيات المستخرجة بدلاً من ثلاثية واحدة. +تقوم بإنشاء `tg:contains` واحد لكل ثلاثية، كتلة نشاط/وكيل مشتركة. +قم بإزالة `triple_provenance_triples()` القديم. + +**`trustgraph-base/trustgraph/provenance/uris.py`** + +استبدل `statement_uri()` بـ `subgraph_uri()` + +**`trustgraph-base/trustgraph/provenance/namespaces.py`** + +استبدل `TG_REIFIES` بـ `TG_CONTAINS` + +### ليس ضمن النطاق + +**kg-extract-topics**: معالج بنمط قديم، ولا يتم استخدامه حاليًا في + العمليات القياسية. +**kg-extract-rows**: ينتج صفوفًا وليست ثلاثيات، ومن مصدر مختلف. + نموذج. +**تتبع المصدر في وقت الاستعلام** (`urn:graph:retrieval`): مسألة منفصلة، + تستخدم بالفعل نمطًا مختلفًا (سؤال/استكشاف/تركيز/توليف). +**أصل المستند/الصفحة/الجزء** (فك تشفير PDF، تقسيم النص): تستخدم بالفعل. + `derived_entity_triples()` وهو خاص بكل كيان، وليس لكل ثلاثية - لا. + مشكلة التكرار. + +## ملاحظات حول التنفيذ + +### إعادة هيكلة حلقة المعالج + +قبل (لكل ثلاثية، في العلاقات): +```python +for rel in rels: + # ... build relationship_triple ... + stmt_uri = statement_uri() + prov_triples = triple_provenance_triples( + stmt_uri=stmt_uri, + extracted_triple=relationship_triple, + ... + ) + triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +بعد (رسم بياني فرعي): +```python +sg_uri = subgraph_uri() + +for rel in rels: + # ... build relationship_triple ... + extracted_triples.append(relationship_triple) + +prov_triples = subgraph_provenance_triples( + subgraph_uri=sg_uri, + extracted_triples=extracted_triples, + chunk_uri=chunk_uri, + component_name=default_ident, + component_version=COMPONENT_VERSION, + llm_model=llm_model, + ontology_uri=ontology_uri, +) +triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +### التوقيع المساعد الجديد + +```python +def subgraph_provenance_triples( + subgraph_uri: str, + extracted_triples: List[Triple], + chunk_uri: str, + component_name: str, + component_version: str, + llm_model: Optional[str] = None, + ontology_uri: Optional[str] = None, + timestamp: Optional[str] = None, +) -> List[Triple]: + """ + Build provenance triples for a subgraph of extracted knowledge. + + Creates: + - tg:contains link for each extracted triple (RDF-star quoted) + - One prov:wasDerivedFrom link to source chunk + - One activity with agent metadata + """ +``` + +### تغيير جذري + +هذا تغيير جذري في نموذج التتبع. لم يتم +تم إصدارها، لذا لا توجد حاجة إلى ترحيل. الكود القديم `tg:reifies` / +يمكن إزالة كود `statement_uri` تمامًا. diff --git a/docs/tech-specs/extraction-provenance-subgraph.he.md b/docs/tech-specs/extraction-provenance-subgraph.he.md new file mode 100644 index 00000000..d1878243 --- /dev/null +++ b/docs/tech-specs/extraction-provenance-subgraph.he.md @@ -0,0 +1,205 @@ +# מקור החילוץ: מודל תת-גרף + +## בעיה + +מעקב מקורות מידע בזמן החילוץ מייצר כיום מימוש מלא לכל טריפל +שחולץ: `stmt_uri` ייחודי, `activity_uri` ו-מטא-דאטה של PROV-O עבור כל +עובדה ידע בודדת. עיבוד של חלק אחד שמייצר 20 קשרים מייצר כ-220 +טריפלי מעקב מקורות מידע בנוסף ל-כ-20 טריפלי ידע - תקורה של בערך 10:1. + + +זה יקר (אחסון, אינדקס, העברה) וגם לא מדויק מבחינה סמנטית. כל חלק +מעובד על ידי קריאה אחת של מודל שפה גדול (LLM) שמייצר את כל +הטריפלים שלו בעסקה אחת. המודל הנוכחי של טריפל בודד מטשטש את זה +על ידי יצירת האשליה של 20 אירועי חילוץ עצמאיים. + + +בנוסף, לשני מתוך ארבעה מעבדי החילוץ (kg-extract-ontology, +kg-extract-agent) אין מעקב מקורות מידע כלל, מה שמשאיר פערים +במסלול הביקורת. + +## פתרון + +החליפו את הפירוט של כל שלישייה במודל תת-גרף: רשומת מוצא אחת לכל חילוץ, המשותפת לכל השלישיות שנוצרו מחלק זה. + + +### שינוי מונחים + + +| ישן | חדש | +|-----|-----| +| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | +| `statement_uri()` | `subgraph_uri()` | +| `tg:reifies` (1:1, זהות) | `tg:contains` (1:רבים, הכלה) | + +### מבנה מטרה + +כל השלישיות של המוצא נכנסות לגרף המקוּם בשם `urn:graph:source`. + +``` +# Subgraph contains each extracted triple (RDF-star quoted triples) + tg:contains <> . + tg:contains <> . + tg:contains <> . + +# Derivation from source chunk + prov:wasDerivedFrom . + prov:wasGeneratedBy . + +# Activity: one per chunk extraction + rdf:type prov:Activity . + rdfs:label "{component_name} extraction" . + prov:used . + prov:wasAssociatedWith . + prov:startedAtTime "2026-03-13T10:00:00Z" . + tg:componentVersion "0.25.0" . + tg:llmModel "gpt-4" . # if available + tg:ontology . # if available + +# Agent: stable per component + rdf:type prov:Agent . + rdfs:label "{component_name}" . +``` + +### השוואת נפחים + +עבור קטע המייצר N משולשים חילוצים: + +| | ישן (למשולש) | חדש (תת-גרף) | +|---|---|---| +| `tg:contains` / `tg:reifies` | N | N | +| משולשי פעילות | ~9 x N | ~9 | +| משולשי סוכנים | 2 x N | 2 | +| מטא-נתונים של הצהרה/תת-גרף | 2 x N | 2 | +| **סה"כ משולשי מקור** | **~13N** | **N + 13** | +| **דוגמה (N=20)** | **~260** | **33** | + +## היקף + +### מעבדים לעדכון (מקור קיים, לכל משולש) + +**kg-extract-definitions** +(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) + +כיום קורא ל-`statement_uri()` + `triple_provenance_triples()` בתוך +הלולאה לכל הגדרה. + +שינויים: +העברת יצירת `subgraph_uri()` ו-`activity_uri()` לפני הלולאה +איסוף משולשי `tg:contains` בתוך הלולאה +פליטת בלוק פעילות/סוכן/הסקה משותף פעם אחת לאחר הלולאה + +**kg-extract-relationships** +(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`) + +דפוס זהה כמו הגדרות. שינויים זהים. + +### מעבדים להוספת מקור (חסרים כרגע) + +**kg-extract-ontology** +(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) + +כיום פולט משולשים ללא מקור. הוספת מקור תת-גרף +באמצעות הדפוס הזהה: תת-גרף אחד לכל קטע, `tg:contains` עבור כל +משולש חילוץ. + +**kg-extract-agent** +(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) + +כיום פולט משולשים ללא מקור. הוספת מקור תת-גרף +באמצעות הדפוס הזהה. + +### שינויים בספריית המקור המשותפת + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +החלפת `triple_provenance_triples()` עם `subgraph_provenance_triples()` +פונקציה חדשה מקבלת רשימה של משולשים חילוצים במקום משולש בודד +מייצרת `tg:contains` אחד לכל משולש, בלוק פעילות/סוכן משותף +הסרת `triple_provenance_triples()` הישן + +**`trustgraph-base/trustgraph/provenance/uris.py`** + +החלפת `statement_uri()` עם `subgraph_uri()` + +**`trustgraph-base/trustgraph/provenance/namespaces.py`** + +החלפת `TG_REIFIES` עם `TG_CONTAINS` + +### לא בתחום + +**kg-extract-topics**: מעבד מסוג ישן, לא בשימוש כרגע ב + זרימות סטנדרטיות +**kg-extract-rows**: מייצר שורות ולא משולשים, מודל מקור + שונה +**מקור בזמן שאילתה** (`urn:graph:retrieval`): נושא נפרד, + כבר משתמש בדפוס שונה (שאילתה/חקירה/מיקוד/סינתזה) +**מקור של מסמך/עמוד/קטע** (מקודד PDF, מפצל): כבר משתמש + ב-`derived_entity_triples()` שהוא לכל ישות, ולא לכל משולש — אין + בעיית יתירות + +## הערות יישום + +### שינוי מבנה הלולאה של המעבד + +לפני (לכל משולש, ביחסים): +```python +for rel in rels: + # ... build relationship_triple ... + stmt_uri = statement_uri() + prov_triples = triple_provenance_triples( + stmt_uri=stmt_uri, + extracted_triple=relationship_triple, + ... + ) + triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +אחרי (תת-גרף): +```python +sg_uri = subgraph_uri() + +for rel in rels: + # ... build relationship_triple ... + extracted_triples.append(relationship_triple) + +prov_triples = subgraph_provenance_triples( + subgraph_uri=sg_uri, + extracted_triples=extracted_triples, + chunk_uri=chunk_uri, + component_name=default_ident, + component_version=COMPONENT_VERSION, + llm_model=llm_model, + ontology_uri=ontology_uri, +) +triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +### חתימה חדשה של עוזר + +```python +def subgraph_provenance_triples( + subgraph_uri: str, + extracted_triples: List[Triple], + chunk_uri: str, + component_name: str, + component_version: str, + llm_model: Optional[str] = None, + ontology_uri: Optional[str] = None, + timestamp: Optional[str] = None, +) -> List[Triple]: + """ + Build provenance triples for a subgraph of extracted knowledge. + + Creates: + - tg:contains link for each extracted triple (RDF-star quoted) + - One prov:wasDerivedFrom link to source chunk + - One activity with agent metadata + """ +``` + +### שינוי משמעותי + +זוהי שינוי משמעותי במודל המקור. המקור טרם פורסם, ולכן אין צורך בביצוע שדרוג. ניתן להסיר את קוד ⟦CODE_0⟧ / +`tg:reifies` הישן לחלוטין. +קוד `statement_uri` ניתן להסרה לחלוטין. diff --git a/docs/tech-specs/extraction-provenance-subgraph.hi.md b/docs/tech-specs/extraction-provenance-subgraph.hi.md new file mode 100644 index 00000000..547f5d1e --- /dev/null +++ b/docs/tech-specs/extraction-provenance-subgraph.hi.md @@ -0,0 +1,205 @@ +# निष्कर्षण का स्रोत: सबग्राफ मॉडल + +## समस्या + +निष्कर्षण के समय का वर्तमान स्रोत जानकारी एक पूर्ण पुन: निरूपण प्रति उत्पन्न करता है +निष्कर्षित त्रिगुट: प्रत्येक ज्ञान तथ्य के लिए एक अद्वितीय `stmt_uri`, `activity_uri`, और संबंधित +PROV-O मेटाडेटा। एक ऐसे खंड को संसाधित करना जो 20 संबंधों का उत्पादन करता है, उसमें लगभग 220 स्रोत जानकारी त्रिगुट होते हैं, इसके अतिरिक्त +लगभग 20 ज्ञान त्रिगुट - लगभग 10:1 का ओवरहेड। + + +यह महंगा है (भंडारण, अनुक्रमण, प्रसारण) और अर्थपूर्ण रूप से +गलत है। प्रत्येक खंड को एक एकल LLM कॉल द्वारा संसाधित किया जाता है जो सभी त्रिगुटों को एक लेनदेन में उत्पन्न करता है। +वर्तमान प्रति-त्रिगुट मॉडल 20 स्वतंत्र निष्कर्षण +घटनाओं का भ्रम पैदा करके इसे अस्पष्ट करता है। + + +इसके अतिरिक्त, चार निष्कर्षण प्रोसेसरों में से दो (kg-extract-ontology, +kg-extract-agent) में कोई स्रोत जानकारी नहीं है, जिससे ऑडिट +में अंतराल पैदा होते हैं। + +## समाधान + +प्रति-त्रिगुट पुन: निरूपण को एक **सबग्राफ मॉडल** से बदलें: एक स्रोत जानकारी +रिकॉर्ड प्रति खंड निष्कर्षण, उस खंड से उत्पन्न सभी त्रिगुटों में साझा किया जाता है। + + +### शब्दावली परिवर्तन + +| पुराना | नया | +|-----|-----| +| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | +| `statement_uri()` | `subgraph_uri()` | +| `tg:reifies` (1:1, पहचान) | `tg:contains` (1:कई, समावेशन) | + +### लक्षित संरचना + +सभी स्रोत जानकारी त्रिगुट `urn:graph:source` नामित ग्राफ में जाते हैं। + +``` +# Subgraph contains each extracted triple (RDF-star quoted triples) + tg:contains <> . + tg:contains <> . + tg:contains <> . + +# Derivation from source chunk + prov:wasDerivedFrom . + prov:wasGeneratedBy . + +# Activity: one per chunk extraction + rdf:type prov:Activity . + rdfs:label "{component_name} extraction" . + prov:used . + prov:wasAssociatedWith . + prov:startedAtTime "2026-03-13T10:00:00Z" . + tg:componentVersion "0.25.0" . + tg:llmModel "gpt-4" . # if available + tg:ontology . # if available + +# Agent: stable per component + rdf:type prov:Agent . + rdfs:label "{component_name}" . +``` + +### मात्रा की तुलना + +एक ऐसे खंड के लिए जो N निकाले गए त्रिगुण उत्पन्न करता है: + +| | पुराना (प्रति-त्रिगुण) | नया (उप-ग्राफ) | +|---|---|---| +| `tg:contains` / `tg:reifies` | N | N | +| गतिविधि त्रिगुण | ~9 x N | ~9 | +| एजेंट त्रिगुण | 2 x N | 2 | +| कथन/उप-ग्राफ मेटाडेटा | 2 x N | 2 | +| **कुल प्रामाणिकता त्रिगुण** | **~13N** | **N + 13** | +| **उदाहरण (N=20)** | **~260** | **33** | + +## दायरा + +### अपडेट करने के लिए प्रोसेसर (मौजूदा प्रामाणिकता, प्रति-त्रिगुण) + +**kg-extract-definitions** +(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) + +वर्तमान में, यह `statement_uri()` + `triple_provenance_triples()` को परिभाषा के प्रत्येक लूप के अंदर कॉल करता है। + + +परिवर्तन: +लूप से पहले `subgraph_uri()` और `activity_uri()` का निर्माण करें। +लूप के अंदर `tg:contains` त्रिकों को एकत्र करें। +लूप के बाद एक बार साझा गतिविधि/एजेंट/व्युत्पत्ति ब्लॉक उत्सर्जित करें। + +**kg-extract-relationships** +(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`) + +परिभाषाओं के समान पैटर्न। समान परिवर्तन। + +### उत्पत्ति जोड़ने के लिए प्रोसेसर (वर्तमान में गायब) + +**kg-extract-ontology** +(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) + +वर्तमान में, यह बिना किसी स्रोत जानकारी के त्रिक उत्पन्न करता है। उपग्राफ स्रोत जानकारी जोड़ें। +उसी पैटर्न का उपयोग करके: प्रत्येक खंड के लिए एक उपग्राफ, प्रत्येक के लिए `tg:contains`। +निकाले गए त्रिगुट। + +**kg-extract-agent** +(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) + +वर्तमान में, यह बिना किसी स्रोत जानकारी के त्रिक (triples) उत्पन्न करता है। समान पैटर्न का उपयोग करके सबग्राफ (subgraph) स्रोत जानकारी जोड़ें। + + +### साझा उत्पत्ति लाइब्रेरी में परिवर्तन + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +`triple_provenance_triples()` को `subgraph_provenance_triples()` से बदलें +नया फ़ंक्शन एक एकल के बजाय निकाले गए त्रिपुलों की सूची को स्वीकार करता है +प्रत्येक ट्रिपल के लिए एक `tg:contains` उत्पन्न करता है, साझा गतिविधि/एजेंट ब्लॉक +पुराने `triple_provenance_triples()` को हटा दें + +**`trustgraph-base/trustgraph/provenance/uris.py`** + +`statement_uri()` को `subgraph_uri()` से बदलें। + +**`trustgraph-base/trustgraph/provenance/namespaces.py`** + +`TG_REIFIES` को `TG_CONTAINS` से बदलें। + +### दायरे में नहीं + +**kg-extract-topics**: पुराना-शैली का प्रोसेसर, वर्तमान में उपयोग में नहीं है। + मानक प्रक्रियाओं में। +**kg-extract-rows**: पंक्तियाँ उत्पन्न करता है, ट्रिपल नहीं, अलग उत्पत्ति मॉडल। + मॉडल। +**क्वेरी-टाइम प्रोवेनेंस** (`urn:graph:retrieval`): एक अलग चिंता का विषय, + पहले से ही एक अलग पैटर्न का उपयोग करता है (प्रश्न/अन्वेषण/फोकस/संश्लेषण)। +**दस्तावेज़/पृष्ठ/खंड प्रोवेनेंस** (पीडीएफ डिकोडर, चंकर): पहले से ही उपयोग करता है + `derived_entity_triples()` जो प्रति-एंटिटी है, प्रति-ट्रिपल नहीं - कोई + अनावश्यकता समस्या नहीं। + +## कार्यान्वयन संबंधी टिप्पणियाँ + +### प्रोसेसर लूप का पुनर्गठन + +पहले (प्रत्येक त्रिक के लिए, संबंधों में): +```python +for rel in rels: + # ... build relationship_triple ... + stmt_uri = statement_uri() + prov_triples = triple_provenance_triples( + stmt_uri=stmt_uri, + extracted_triple=relationship_triple, + ... + ) + triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +(उपग्राफ के बाद): +```python +sg_uri = subgraph_uri() + +for rel in rels: + # ... build relationship_triple ... + extracted_triples.append(relationship_triple) + +prov_triples = subgraph_provenance_triples( + subgraph_uri=sg_uri, + extracted_triples=extracted_triples, + chunk_uri=chunk_uri, + component_name=default_ident, + component_version=COMPONENT_VERSION, + llm_model=llm_model, + ontology_uri=ontology_uri, +) +triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +### नया सहायक हस्ताक्षर + +```python +def subgraph_provenance_triples( + subgraph_uri: str, + extracted_triples: List[Triple], + chunk_uri: str, + component_name: str, + component_version: str, + llm_model: Optional[str] = None, + ontology_uri: Optional[str] = None, + timestamp: Optional[str] = None, +) -> List[Triple]: + """ + Build provenance triples for a subgraph of extracted knowledge. + + Creates: + - tg:contains link for each extracted triple (RDF-star quoted) + - One prov:wasDerivedFrom link to source chunk + - One activity with agent metadata + """ +``` + +### महत्वपूर्ण परिवर्तन + +यह उत्पत्ति मॉडल में एक महत्वपूर्ण बदलाव है। उत्पत्ति (प्रोवेनेंस) का +जारी किया गया है, इसलिए माइग्रेशन की आवश्यकता नहीं है। पुराना `tg:reifies` / +`statement_uri` कोड पूरी तरह से हटाया जा सकता है। diff --git a/docs/tech-specs/extraction-provenance-subgraph.pt.md b/docs/tech-specs/extraction-provenance-subgraph.pt.md new file mode 100644 index 00000000..bab9d315 --- /dev/null +++ b/docs/tech-specs/extraction-provenance-subgraph.pt.md @@ -0,0 +1,205 @@ +# Proveniência de Extração: Modelo de Subgrafo + +## Problema + +A proveniência em tempo de extração atualmente gera uma reificação completa para cada +tripla extraída: um `stmt_uri`, `activity_uri` e metadados PROV-O associados para cada +fato de conhecimento. O processamento de um bloco que gera 20 relacionamentos produz aproximadamente 220 triplas de proveniência, além de +aproximadamente 20 triplas de conhecimento — uma sobrecarga de aproximadamente 10:1. + + +Isso é caro (armazenamento, indexação, transmissão) e semanticamente +impreciso. Cada bloco é processado por uma única chamada de LLM que produz +todas as suas triplas em uma única transação. O modelo atual, baseado em tripla, +obscure isso, criando a ilusão de 20 eventos de extração independentes. + + +Além disso, dois dos quatro processadores de extração (kg-extract-ontology, +kg-extract-agent) não possuem proveniência, deixando lacunas no registro de auditoria. + + +## Solução + +Substituir a reificação por tripla por um **modelo de subgrafo**: um registro de proveniência +por extração de bloco, compartilhado entre todas as triplas produzidas a partir desse +bloco. + +### Mudança de Terminologia + +| Antigo | Novo | +|-----|-----| +| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | +| `statement_uri()` | `subgraph_uri()` | +| `tg:reifies` (1:1, identidade) | `tg:contains` (1:muitos, contenção) | + +### Estrutura Alvo + +Todas as triplas de proveniência devem ser inseridas no grafo nomeado `urn:graph:source`. + +``` +# Subgraph contains each extracted triple (RDF-star quoted triples) + tg:contains <> . + tg:contains <> . + tg:contains <> . + +# Derivation from source chunk + prov:wasDerivedFrom . + prov:wasGeneratedBy . + +# Activity: one per chunk extraction + rdf:type prov:Activity . + rdfs:label "{component_name} extraction" . + prov:used . + prov:wasAssociatedWith . + prov:startedAtTime "2026-03-13T10:00:00Z" . + tg:componentVersion "0.25.0" . + tg:llmModel "gpt-4" . # if available + tg:ontology . # if available + +# Agent: stable per component + rdf:type prov:Agent . + rdfs:label "{component_name}" . +``` + +### Comparação de Volume + +Para um conjunto de dados que produz N triplas extraídas: + +| | Antigo (por tripla) | Novo (subgrafo) | +|---|---|---| +| `tg:contains` / `tg:reifies` | N | N | +| Triplas de atividade | ~9 x N | ~9 | +| Triplas de agente | 2 x N | 2 | +| Metadados de declaração/subgrafo | 2 x N | 2 | +| **Total de triplas de rastreabilidade** | **~13N** | **N + 13** | +| **Exemplo (N=20)** | **~260** | **33** | + +## Escopo + +### Processadores a serem Atualizados (rastreabilidade existente, por tripla) + +**kg-extract-definitions** +(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) + +Atualmente, chama `statement_uri()` + `triple_provenance_triples()` dentro +do loop por definição. + +Alterações: +Mover a criação de `subgraph_uri()` e `activity_uri()` antes do loop +Coletar triplas `tg:contains` dentro do loop +Emitir bloco compartilhado de atividade/agente/derivação uma vez após o loop + +**kg-extract-relationships** +(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`) + +Mesmo padrão que definições. As mesmas alterações. + +### Processadores a serem Adicionados para Rastreabilidade (atualmente ausente) + +**kg-extract-ontology** +(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) + +Atualmente, emite triplas sem rastreabilidade. Adicionar rastreabilidade de subgrafo +usando o mesmo padrão: um subgrafo por conjunto de dados, `tg:contains` para cada +tripla extraída. + +**kg-extract-agent** +(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) + +Atualmente, emite triplas sem rastreabilidade. Adicionar rastreabilidade de subgrafo +usando o mesmo padrão. + +### Alterações na Biblioteca Compartilhada de Rastreabilidade + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +Substituir `triple_provenance_triples()` por `subgraph_provenance_triples()` +Nova função aceita uma lista de triplas extraídas em vez de uma única +Gera um `tg:contains` por tripla, bloco compartilhado de atividade/agente +Remover `triple_provenance_triples()` antigo + +**`trustgraph-base/trustgraph/provenance/uris.py`** + +Substituir `statement_uri()` por `subgraph_uri()` + +**`trustgraph-base/trustgraph/provenance/namespaces.py`** + +Substituir `TG_REIFIES` por `TG_CONTAINS` + +### Não no Escopo + +**kg-extract-topics**: processador de estilo antigo, não usado atualmente em + fluxos padrão +**kg-extract-rows**: produz linhas, não triplas, modelo de rastreabilidade + diferente +**Rastreabilidade em tempo de consulta** (`urn:graph:retrieval`): questão separada, + já usa um padrão diferente (pergunta/exploração/foco/síntese) +**Rastreabilidade de documento/página/conjunto de dados** (decodificador PDF, divisor): já usa + `derived_entity_triples()` que é por entidade, não por tripla — não há + problema de redundância + +## Notas de Implementação + +### Reestruturação do Loop do Processador + +Antes (por tripla, em relacionamentos): +```python +for rel in rels: + # ... build relationship_triple ... + stmt_uri = statement_uri() + prov_triples = triple_provenance_triples( + stmt_uri=stmt_uri, + extracted_triple=relationship_triple, + ... + ) + triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +Após (subgrafo): +```python +sg_uri = subgraph_uri() + +for rel in rels: + # ... build relationship_triple ... + extracted_triples.append(relationship_triple) + +prov_triples = subgraph_provenance_triples( + subgraph_uri=sg_uri, + extracted_triples=extracted_triples, + chunk_uri=chunk_uri, + component_name=default_ident, + component_version=COMPONENT_VERSION, + llm_model=llm_model, + ontology_uri=ontology_uri, +) +triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +### Nova Assinatura de Auxílio + +```python +def subgraph_provenance_triples( + subgraph_uri: str, + extracted_triples: List[Triple], + chunk_uri: str, + component_name: str, + component_version: str, + llm_model: Optional[str] = None, + ontology_uri: Optional[str] = None, + timestamp: Optional[str] = None, +) -> List[Triple]: + """ + Build provenance triples for a subgraph of extracted knowledge. + + Creates: + - tg:contains link for each extracted triple (RDF-star quoted) + - One prov:wasDerivedFrom link to source chunk + - One activity with agent metadata + """ +``` + +### Mudança Significativa + +Esta é uma mudança significativa no modelo de rastreabilidade. A rastreabilidade não +foi lançada, portanto, nenhuma migração é necessária. O código antigo `tg:reifies` / +`statement_uri` pode ser removido completamente. diff --git a/docs/tech-specs/extraction-provenance-subgraph.ru.md b/docs/tech-specs/extraction-provenance-subgraph.ru.md new file mode 100644 index 00000000..787b952d --- /dev/null +++ b/docs/tech-specs/extraction-provenance-subgraph.ru.md @@ -0,0 +1,205 @@ +# Происхождение извлечения: Модель подграфа + +## Проблема + +В настоящее время механизм отслеживания происхождения, работающий во время извлечения, создает полную реификацию для каждого +извлеченного тройства: уникальный `stmt_uri`, `activity_uri` и связанные +метаданные PROV-O для каждого отдельного факта знаний. Обработка одного блока +данных, который дает 20 отношений, приводит к появлению примерно 220 тройств отслеживания происхождения в дополнение к +примерно 20 тройствам знаний — это примерно 10:1 избыточности. + +Это дорого (хранение, индексация, передача) и семантически +неточно. Каждый блок обрабатывается одним вызовом LLM, который создает +все свои тройства за одну транзакцию. Текущая модель, основанная на тройствах, +искажает это, создавая иллюзию 20 независимых событий извлечения. + + +Кроме того, два из четырех процессоров извлечения (kg-extract-ontology, +kg-extract-agent) вообще не имеют информации об отслеживании происхождения, что оставляет пробелы в журнале аудита. + + +## Решение + +Заменить реификацию на уровне тройств на **модель подграфа**: одна запись отслеживания происхождения для каждого блока извлечения, +используемая для всех тройств, созданных из этого блока. + + +### Изменение терминологии + +| Старое | Новое | +|-----|-----| +| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | +| `statement_uri()` | `subgraph_uri()` | +| `tg:reifies` (1:1, идентичность) | `tg:contains` (1:много, содержательность) | + +### Целевая структура + +Все тройства отслеживания происхождения должны быть помещены в именованный граф `urn:graph:source`. + +``` +# Subgraph contains each extracted triple (RDF-star quoted triples) + tg:contains <> . + tg:contains <> . + tg:contains <> . + +# Derivation from source chunk + prov:wasDerivedFrom . + prov:wasGeneratedBy . + +# Activity: one per chunk extraction + rdf:type prov:Activity . + rdfs:label "{component_name} extraction" . + prov:used . + prov:wasAssociatedWith . + prov:startedAtTime "2026-03-13T10:00:00Z" . + tg:componentVersion "0.25.0" . + tg:llmModel "gpt-4" . # if available + tg:ontology . # if available + +# Agent: stable per component + rdf:type prov:Agent . + rdfs:label "{component_name}" . +``` + +### Сравнение объемов + +Для блока, генерирующего N извлеченных троек: + +| | Старый (на тройку) | Новый (подграф) | +|---|---|---| +| `tg:contains` / `tg:reifies` | N | N | +| Тройки активности | ~9 x N | ~9 | +| Тройки агентов | 2 x N | 2 | +| Метаданные утверждения/подграфа | 2 x N | 2 | +| **Всего троек происхождения** | **~13N** | **N + 13** | +| **Пример (N=20)** | **~260** | **33** | + +## Область применения + +### Модули для обновления (существующее происхождение, на тройку) + +**kg-extract-definitions** +(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) + +В настоящее время вызывает `statement_uri()` + `triple_provenance_triples()` внутри +цикла для каждой сущности. + +Изменения: +Переместить создание `subgraph_uri()` и `activity_uri()` перед циклом +Собирать тройки `tg:contains` внутри цикла +Выводить общий блок активности/агента/происхождения один раз после цикла + +**kg-extract-relationships** +(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`) + +Та же схема, что и для сущностей. Те же изменения. + +### Модули для добавления информации о происхождении (в настоящее время отсутствуют) + +**kg-extract-ontology** +(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) + +В настоящее время генерируются тройки без указания источника. Добавить информацию об источнике подграфа, +используя ту же схему: один подграф для каждого фрагмента, `tg:contains` для каждой +извлеченной тройки. + +**kg-extract-agent** +(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) + +В настоящее время генерируются тройки без указания источника. Добавить информацию об источнике подграфа, +используя ту же схему. + +### Изменения в общей библиотеке отслеживания происхождения данных + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +Заменить `triple_provenance_triples()` на `subgraph_provenance_triples()` +Новая функция принимает список извлеченных троек вместо одной +Генерирует один `tg:contains` для каждой тройки, общий блок активности/агента +Удалить старый `triple_provenance_triples()` + +**`trustgraph-base/trustgraph/provenance/uris.py`** + +Заменить `statement_uri()` на `subgraph_uri()` + +**`trustgraph-base/trustgraph/provenance/namespaces.py`** + +Заменить `TG_REIFIES` на `TG_CONTAINS` + +### Не входит в область действия + +**kg-extract-topics**: устаревший процессор, в настоящее время не используется в + стандартных процессах. +**kg-extract-rows**: генерирует строки, а не тройки, имеет другую модель + происхождения. +**Происхождение во время запроса** (`urn:graph:retrieval`): отдельная задача, + уже использует другую схему (вопрос/исследование/фокус/синтез). +**Происхождение документа/страницы/фрагмента** (декодер PDF, разбиение на фрагменты): уже использует + `derived_entity_triples()`, который применяется к каждой сущности, а не к каждой тройке — нет + проблемы избыточности. + +## Замечания по реализации + +### Реструктуризация цикла процессора + +До (для каждой тройки, в отношениях): +```python +for rel in rels: + # ... build relationship_triple ... + stmt_uri = statement_uri() + prov_triples = triple_provenance_triples( + stmt_uri=stmt_uri, + extracted_triple=relationship_triple, + ... + ) + triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +После (подграфа): +```python +sg_uri = subgraph_uri() + +for rel in rels: + # ... build relationship_triple ... + extracted_triples.append(relationship_triple) + +prov_triples = subgraph_provenance_triples( + subgraph_uri=sg_uri, + extracted_triples=extracted_triples, + chunk_uri=chunk_uri, + component_name=default_ident, + component_version=COMPONENT_VERSION, + llm_model=llm_model, + ontology_uri=ontology_uri, +) +triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +### Новая вспомогательная подпись + +```python +def subgraph_provenance_triples( + subgraph_uri: str, + extracted_triples: List[Triple], + chunk_uri: str, + component_name: str, + component_version: str, + llm_model: Optional[str] = None, + ontology_uri: Optional[str] = None, + timestamp: Optional[str] = None, +) -> List[Triple]: + """ + Build provenance triples for a subgraph of extracted knowledge. + + Creates: + - tg:contains link for each extracted triple (RDF-star quoted) + - One prov:wasDerivedFrom link to source chunk + - One activity with agent metadata + """ +``` + +### Существенное изменение + +Это существенное изменение модели отслеживания происхождения. Отслеживание происхождения еще не было выпущено, поэтому миграция не требуется. Старый код ⟦CODE_0⟧ / +`tg:reifies` можно удалить безвозвратно. +Код `statement_uri` можно удалить полностью. diff --git a/docs/tech-specs/extraction-provenance-subgraph.sw.md b/docs/tech-specs/extraction-provenance-subgraph.sw.md new file mode 100644 index 00000000..2abf3c65 --- /dev/null +++ b/docs/tech-specs/extraction-provenance-subgraph.sw.md @@ -0,0 +1,205 @@ +# Asili ya Utoaji: Mfumo wa Subgraph + +## Tatizo + +Hivi sasa, utoaji wa wakati wa uondoaji huunda uelekezaji kamili kwa kila +triple iliyoundwa: `stmt_uri`, `activity_uri`, na metadata inayohusiana +ya PROV-O kwa kila ukweli wa maarifa. Kushughulikia sehemu moja +ambayo hutoa uhusiano wa 20 hutoa triples ~220 za utoaji pamoja na +triples ~20 za maarifa - mzigo wa takriban 10:1. + +Hii ni ghali (uhifadhi, uwekaji wa indexi, usambazaji) na pia si sahihi +kimaana. Kila sehemu hushughulikiwa na simu moja ya LLM ambayo hutoa +triples zake zote katika mshono mmoja. Mfumo wa sasa wa kila triple +huficha hili kwa kuunda udanganyifu wa matukio 20 ya uondoaji +huru. + +Zaidi ya hayo, vichakavu viwili vya nne vya uondoaji (kg-extract-ontology, +kg-extract-agent) havina utoaji wowote, na hivyo kuacha pengo katika +njia ya ukaguzi. + +## Suluhisho + +Badilisha uelekezaji wa kila triple na **mfumo wa subgraph**: rekodi moja +ya utoaji kwa kila uondoaji wa sehemu, inayoshirikiwa na triples zote +zilizozalishwa kutoka sehemu hiyo. + +### Mabadiliko ya Dhana + +| Zamani | Mpya | +|-----|-----| +| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | +| `statement_uri()` | `subgraph_uri()` | +| `tg:reifies` (1:1, utambulisho) | `tg:contains` (1:wengi, uwezeshaji) | + +### Muundo Unaolengwa + +Triples zote za utoaji huwekwa katika grafu iliyoitwa `urn:graph:source`. + +``` +# Subgraph contains each extracted triple (RDF-star quoted triples) + tg:contains <> . + tg:contains <> . + tg:contains <> . + +# Derivation from source chunk + prov:wasDerivedFrom . + prov:wasGeneratedBy . + +# Activity: one per chunk extraction + rdf:type prov:Activity . + rdfs:label "{component_name} extraction" . + prov:used . + prov:wasAssociatedWith . + prov:startedAtTime "2026-03-13T10:00:00Z" . + tg:componentVersion "0.25.0" . + tg:llmModel "gpt-4" . # if available + tg:ontology . # if available + +# Agent: stable per component + rdf:type prov:Agent . + rdfs:label "{component_name}" . +``` + +### Kulinganisha Kiasi + +Kwa kila sehemu inayozalisha triples tatu zilizochukuliwa: + +| | Zamani (kwa kila triple) | Mpya (subgraph) | +|---|---|---| +| `tg:contains` / `tg:reifies` | N | N | +| Triples za shughuli | ~9 x N | ~9 | +| Triples za wakala | 2 x N | 2 | +| Metadata ya taarifa/subgraph | 2 x N | 2 | +| **Triples tatu za jumla za asili** | **~13N** | **N + 13** | +| **Mfano (N=20)** | **~260** | **33** | + +## Upeo + +### Wasindikaji ambao Watasasishwa (asili iliyopo, kwa kila triple) + +**kg-extract-definitions** +(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) + +Hivi sasa huita `statement_uri()` + `triple_provenance_triples()` ndani +ya loop ya kila ufafanuzi. + +Mabadiliko: +Hamisha `subgraph_uri()` na `activity_uri()` kabla ya loop +Kusanya triples za `tg:contains` ndani ya loop +Toa kundi la shughuli/wakala/uzalishaji mara moja baada ya loop + +**kg-extract-relationships** +(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`) + +Mfano sawa na ufafanuzi. Mabadiliko sawa. + +### Wasindikaji ambao Watasasishwa ili Kuongeza Asili (sasa hayapo) + +**kg-extract-ontology** +(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) + +Hivi sasa hutoa triples bila asili. Ongeza asili ya subgraph +kwa kutumia mfano sawa: subgraph moja kwa kila sehemu, `tg:contains` kwa kila +triple iliyochukuliwa. + +**kg-extract-agent** +(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) + +Hivi sasa hutoa triples bila asili. Ongeza asili ya subgraph +kwa kutumia mfano sawa. + +### Mabadiliko ya Maktaba ya Asili iliyoshirikiwa + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +Badilisha `triple_provenance_triples()` na `subgraph_provenance_triples()` +Kazi mpya inakubali orodha ya triples zilizochukuliwa badala ya moja +Inazalisha `tg:contains` moja kwa kila triple, kundi la shughuli/wakala lililoshirikiwa +Ondoa `triple_provenance_triples()` ya zamani + +**`trustgraph-base/trustgraph/provenance/uris.py`** + +Badilisha `statement_uri()` na `subgraph_uri()` + +**`trustgraph-base/trustgraph/provenance/namespaces.py`** + +Badilisha `TG_REIFIES` na `TG_CONTAINS` + +### Hayajajumuishwa katika Upeo + +**kg-extract-topics**: wasindikaji wa mtindo wa zamani, hawatumiki kwa sasa katika + mtiririko wa kawaida +**kg-extract-rows**: hutoa mistari si triples, mfumo tofauti wa + asili +**Asili ya wakati wa swali** (`urn:graph:retrieval`): suala tofauti, + tayari hutumia mfumo tofauti (swali/uchunguzi/lengo/muhtasari) +**Asili ya hati/ukurasa/sehemu** (dekoda ya PDF, kichunguzi): tayari hutumia + `derived_entity_triples()` ambayo ni kwa kila kitu, si kwa kila triple — hakuna + suala la ziada + +## Maelezo ya Utendaji + +### Upangaji Upya wa Loop ya Msindikaji + +Kabla (kwa kila triple, katika uhusiano): +```python +for rel in rels: + # ... build relationship_triple ... + stmt_uri = statement_uri() + prov_triples = triple_provenance_triples( + stmt_uri=stmt_uri, + extracted_triple=relationship_triple, + ... + ) + triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +Baada ya (mfumo mdogo): +```python +sg_uri = subgraph_uri() + +for rel in rels: + # ... build relationship_triple ... + extracted_triples.append(relationship_triple) + +prov_triples = subgraph_provenance_triples( + subgraph_uri=sg_uri, + extracted_triples=extracted_triples, + chunk_uri=chunk_uri, + component_name=default_ident, + component_version=COMPONENT_VERSION, + llm_model=llm_model, + ontology_uri=ontology_uri, +) +triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +### Saini Mpya ya Msaidizi + +```python +def subgraph_provenance_triples( + subgraph_uri: str, + extracted_triples: List[Triple], + chunk_uri: str, + component_name: str, + component_version: str, + llm_model: Optional[str] = None, + ontology_uri: Optional[str] = None, + timestamp: Optional[str] = None, +) -> List[Triple]: + """ + Build provenance triples for a subgraph of extracted knowledge. + + Creates: + - tg:contains link for each extracted triple (RDF-star quoted) + - One prov:wasDerivedFrom link to source chunk + - One activity with agent metadata + """ +``` + +### Mabadiliko Makubwa + +Hii ni mabadiliko makubwa kwa mfumo wa asili ya data. Asili ya data haijatolewa, kwa hivyo hakuna uhamishaji unaohitajika. Msimbo wa zamani wa ⟦CODE_0⟧ / +`tg:reifies` unaweza kuondolewa kabisa. +Msimbo `statement_uri` unaweza kufutwa kabisa. diff --git a/docs/tech-specs/extraction-provenance-subgraph.tr.md b/docs/tech-specs/extraction-provenance-subgraph.tr.md new file mode 100644 index 00000000..58fd85df --- /dev/null +++ b/docs/tech-specs/extraction-provenance-subgraph.tr.md @@ -0,0 +1,205 @@ +# Çıkarma Kaynağı: Alt Grafik Modeli + +## Sorun + +Çıkarma zamanı köken bilgisi şu anda her +çıkarılan üçlü için tam bir somutlaştırma oluşturur: benzersiz bir `stmt_uri`, `activity_uri` ve ilgili +PROV-O meta verileri, her bir bilgi parçası için. Bir parça işlenirken +ve bu parça 20 ilişki üretiyorsa, yaklaşık 220 köken bilgisi üçlüsü, bunun üzerine +yaklaşık 20 bilgi üçlüsü bulunur; bu da yaklaşık 10:1'lik bir ek yük demektir. + +Bu hem pahalıdır (depolama, indeksleme, iletim) hem de anlamsal olarak +yanlıştır. Her bir parça, tek bir LLM çağrısı ile işlenir ve bu çağrı, +tüm üçlemelerini tek bir işlemde üretir. Mevcut üçleme bazlı model, +20 bağımsız çıkarma olayının yanılsamasını yaratarak bunu gizler. + + +Ayrıca, dört çıkarma işlemcisinden ikisi (kg-extract-ontology, +kg-extract-agent), hiçbir kaynak bilgisini içermemektedir, bu da denetim +izinde boşluklara neden olmaktadır. + +## Çözüm + +Her üçlü için yapılan somutlaştırmayı, **bir alt grafik modeli** ile değiştirin: her bir parça çıkarımı için bir köken kaydı, bu parçadan üretilen tüm üçlüler arasında paylaşılan. + + + +### Terminoloji Değişikliği + +| Eski | Yeni | +|-----|-----| +| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | +| `statement_uri()` | `subgraph_uri()` | +| `tg:reifies` (1:1, eşlik) | `tg:contains` (1:çok, içerik) | + +### Hedef Yapı + +Tüm köken bilgisi üçlüleri, `urn:graph:source` adlı grafikte yer alır. + +``` +# Subgraph contains each extracted triple (RDF-star quoted triples) + tg:contains <> . + tg:contains <> . + tg:contains <> . + +# Derivation from source chunk + prov:wasDerivedFrom . + prov:wasGeneratedBy . + +# Activity: one per chunk extraction + rdf:type prov:Activity . + rdfs:label "{component_name} extraction" . + prov:used . + prov:wasAssociatedWith . + prov:startedAtTime "2026-03-13T10:00:00Z" . + tg:componentVersion "0.25.0" . + tg:llmModel "gpt-4" . # if available + tg:ontology . # if available + +# Agent: stable per component + rdf:type prov:Agent . + rdfs:label "{component_name}" . +``` + +### Hacim Karşılaştırması + +N sayıda çıkarılan üçlü üreten bir parça için: + +| | Eski (üçlü başına) | Yeni (alt grafik) | +|---|---|---| +| `tg:contains` / `tg:reifies` | N | N | +| Aktivite üçlüleri | ~9 x N | ~9 | +| Ajan üçlüleri | 2 x N | 2 | +| İfade/alt grafik meta verileri | 2 x N | 2 | +| **Toplam kaynak üçlüleri** | **~13N** | **N + 13** | +| **Örnek (N=20)** | **~260** | **33** | + +## Kapsam + +### Güncellenecek İşlemciler (mevcut kaynak, üçlü başına) + +**kg-extract-definitions** +(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) + +Şu anda her bir tanım döngüsü içinde `statement_uri()` + `triple_provenance_triples()`'i çağırıyor. + + +Değişiklikler: +`subgraph_uri()` ve `activity_uri()` oluşturmayı döngüden önce taşıyın +`tg:contains` üçlülerini döngü içinde toplayın +Paylaşılan aktivite/ajan/türetme bloğunu döngüden sonra bir kez yayınlayın + +**kg-extract-relationships** +(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`) + +Tanımlarla aynı desen. Aynı değişiklikler. + +### Kaynak Eklenmesi Gereken İşlemciler (şu anda eksik) + +**kg-extract-ontology** +(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) + +Şu anda, herhangi bir kaynak bilgisi olmadan üçlüler oluşturuluyor. Alt grafik kaynak bilgisini ekleyin. +Aynı kalıbı kullanarak: her parça için bir alt grafik, her çıkarılan üçlü için `tg:contains`. + + +**kg-extract-agent** +(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) + +Şu anda, herhangi bir kaynak bilgisi olmadan üçlüler oluşturuluyor. Alt grafik kaynak bilgisini aynı kalıbı kullanarak ekleyin. + + +### Paylaşılan Kaynak Bilgisi Kütüphanesi Değişiklikleri + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +`triple_provenance_triples()`'ı `subgraph_provenance_triples()` ile değiştirin. +Yeni fonksiyon, tek bir üçlü yerine çıkarılan üçlülerin bir listesini kabul ediyor. +Her üçlü için bir `tg:contains` oluşturuyor, paylaşılan etkinlik/ajan bloğu. +Eski `triple_provenance_triples()`'ı kaldırın. + +**`trustgraph-base/trustgraph/provenance/uris.py`** + +`statement_uri()`'ı `subgraph_uri()` ile değiştirin. + +**`trustgraph-base/trustgraph/provenance/namespaces.py`** + +`TG_REIFIES`'ı `TG_CONTAINS` ile değiştirin. + +### Kapsam Dışında + +**kg-extract-topics**: eski tip işlemci, şu anda standart akışlarda kullanılmıyor. + **kg-extract-rows**: satırlar üretiyor, üçlüler değil, farklı bir köken modeline sahip. +**Çalışma zamanı köken bilgisi** (⟦CODE_0⟧): ayrı bir konu. + model +**Çalışma zamanı veri kaynağı bilgisi** (`urn:graph:retrieval`): ayrı bir konu, + zaten farklı bir kalıp kullanıyor (soru/keşif/odaklanma/sentez). +**Belge/sayfa/parça kaynağı** (PDF çözücü, parçalayıcı): zaten kullanılıyor. + `derived_entity_triples()` ki bu, her bir varlık için, her bir üçlü için değil; yani bir sorun yok. + gereksiz veri sorunu yok. + +## Uygulama Notları + +### İşlemci Döngüsü Yeniden Yapılandırması + +Önce (her üçlü için, ilişkilerde): +```python +for rel in rels: + # ... build relationship_triple ... + stmt_uri = statement_uri() + prov_triples = triple_provenance_triples( + stmt_uri=stmt_uri, + extracted_triple=relationship_triple, + ... + ) + triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +(Alt grafik): +```python +sg_uri = subgraph_uri() + +for rel in rels: + # ... build relationship_triple ... + extracted_triples.append(relationship_triple) + +prov_triples = subgraph_provenance_triples( + subgraph_uri=sg_uri, + extracted_triples=extracted_triples, + chunk_uri=chunk_uri, + component_name=default_ident, + component_version=COMPONENT_VERSION, + llm_model=llm_model, + ontology_uri=ontology_uri, +) +triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +### Yeni Yardımcı İmza + +```python +def subgraph_provenance_triples( + subgraph_uri: str, + extracted_triples: List[Triple], + chunk_uri: str, + component_name: str, + component_version: str, + llm_model: Optional[str] = None, + ontology_uri: Optional[str] = None, + timestamp: Optional[str] = None, +) -> List[Triple]: + """ + Build provenance triples for a subgraph of extracted knowledge. + + Creates: + - tg:contains link for each extracted triple (RDF-star quoted) + - One prov:wasDerivedFrom link to source chunk + - One activity with agent metadata + """ +``` + +### Önemli Değişiklik + +Bu, köken modeli için önemli bir değişikliktir. Köken henüz yayınlanmadığı için, herhangi bir geçiş işlemine gerek yoktur. Eski ⟦CODE_0⟧ / +`tg:reifies` kodu tamamen kaldırılabilir. +`statement_uri` kodu tamamen kaldırılabilir. diff --git a/docs/tech-specs/extraction-provenance-subgraph.zh-cn.md b/docs/tech-specs/extraction-provenance-subgraph.zh-cn.md new file mode 100644 index 00000000..1ca33eba --- /dev/null +++ b/docs/tech-specs/extraction-provenance-subgraph.zh-cn.md @@ -0,0 +1,205 @@ +# 提取来源:子图模型 + +## 问题 + +提取时 provenance 目前为每个提取的三元组生成完整的重构:一个唯一的 ⟦CODE_0⟧、⟦CODE_1⟧,以及与每个知识事实相关的 PROV-O 元数据。处理一个块 +提取时 provenance 目前为每个提取的三元组生成完整的重构:一个唯一的 `stmt_uri`、`activity_uri`,以及与每个知识事实相关的 PROV-O 元数据。处理一个块 +提取时 provenance 目前为每个提取的三元组生成完整的重构:一个唯一的 ⟦CODE_0⟧、⟦CODE_1⟧,以及与每个知识事实相关的 PROV-O 元数据。处理一个块 +这会产生 20 个关系,并在其基础上产生约 220 个溯源三元组,而知识三元组约为 20 个,这导致了大约 10:1 的开销。 + + +这既成本高昂(存储、索引、传输),又在语义上 +不准确。每个片段都由单个 LLM 调用处理,该调用在一个事务中生成 +所有其三元组。当前的每个三元组模型 +通过制造 20 个独立提取 +事件的假象来掩盖这一点。 + +此外,四个提取处理器中的两个(kg-extract-ontology、 +kg-extract-agent)完全没有来源信息,这在审计 +跟踪中留下了空白。 + +## 解决方案 + +将每个三元组的显式化替换为**子图模型**:每个数据块提取一个溯源记录,该记录在从该数据块生成的所有三元组中共享。 + + + +### 术语变更 + +| 旧术语 | 新术语 | +|-----|-----| +| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | +| `statement_uri()` | `subgraph_uri()` | +| `tg:reifies` (1:1, 相同) | `tg:contains` (1:多, 包含) | + +### 目标结构 + +所有溯源三元组都放入名为 `urn:graph:source` 的命名图中。 + +``` +# Subgraph contains each extracted triple (RDF-star quoted triples) + tg:contains <> . + tg:contains <> . + tg:contains <> . + +# Derivation from source chunk + prov:wasDerivedFrom . + prov:wasGeneratedBy . + +# Activity: one per chunk extraction + rdf:type prov:Activity . + rdfs:label "{component_name} extraction" . + prov:used . + prov:wasAssociatedWith . + prov:startedAtTime "2026-03-13T10:00:00Z" . + tg:componentVersion "0.25.0" . + tg:llmModel "gpt-4" . # if available + tg:ontology . # if available + +# Agent: stable per component + rdf:type prov:Agent . + rdfs:label "{component_name}" . +``` + +### 比较数据量 + +对于一个产生 N 个提取三元组的模块: + +| | 旧方式(每个三元组) | 新方式(子图) | +|---|---|---| +| `tg:contains` / `tg:reifies` | N | N | +| 活动三元组 | ~9 x N | ~9 | +| 代理三元组 | 2 x N | 2 | +| 语句/子图元数据 | 2 x N | 2 | +| **总的溯源三元组** | **~13N** | **N + 13** | +| **示例(N=20)** | **~260** | **33** | + +## 范围 + +### 需要更新的处理器(现有溯源,每个三元组) + +**kg-extract-definitions** +(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) + +目前,它在每个定义的循环内部调用 `statement_uri()` + `triple_provenance_triples()`。 + + +更改: +将 `subgraph_uri()` 和 `activity_uri()` 的创建移到循环之前。 +在循环内部收集 `tg:contains` 三元组。 +循环结束后,一次性输出共享的活动/主体/推导块。 + +**kg-extract-relationships** +(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`) + +模式与定义相同。 更改也相同。 + +### 需要添加的处理器,用于添加来源信息(目前缺失) + +**kg-extract-ontology** +(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) + +目前会生成不带来源信息的三元组。添加子图来源信息。 +使用相同的模式:每个块一个子图,对于每个提取的三元组使用 `tg:contains`。 + + +**kg-extract-agent** +(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) + +目前会生成不带来源信息的三元组。添加子图来源信息。 +使用相同的模式。 + +### 共享来源库的更改 + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +将 `triple_provenance_triples()` 替换为 `subgraph_provenance_triples()` +新函数接受一个提取的三元组列表,而不是单个三元组。 +为每个三元组生成一个 `tg:contains`,共享活动/代理块。 +移除旧的 `triple_provenance_triples()` + +**`trustgraph-base/trustgraph/provenance/uris.py`** + +将 `statement_uri()` 替换为 `subgraph_uri()` + +**`trustgraph-base/trustgraph/provenance/namespaces.py`** + +将 `TG_REIFIES` 替换为 `TG_CONTAINS` + +### 不在范围之内 + +**kg-extract-topics**: 较旧的处理器,目前未在标准流程中使用。 + **kg-extract-rows**: 生成的是行,而不是三元组,具有不同的数据来源模型。 +**查询时的数据来源** (⟦CODE_0⟧): 独立的关注点。 + 模型 +**查询时的数据来源信息** (`urn:graph:retrieval`):独立的关注点, + 已经使用了不同的模式(提问/探索/聚焦/综合)。 +**文档/页面/块的来源**(PDF解码器,分块器):已经使用了。 + `derived_entity_triples()`,这对于每个实体而言,而不是每个三元组而言,因此没有 + 重复的问题。 + +## 实现说明 + +### 处理器循环重构 + +之前(每个三元组,在关系中): +```python +for rel in rels: + # ... build relationship_triple ... + stmt_uri = statement_uri() + prov_triples = triple_provenance_triples( + stmt_uri=stmt_uri, + extracted_triple=relationship_triple, + ... + ) + triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +在 (子图) 之后: +```python +sg_uri = subgraph_uri() + +for rel in rels: + # ... build relationship_triple ... + extracted_triples.append(relationship_triple) + +prov_triples = subgraph_provenance_triples( + subgraph_uri=sg_uri, + extracted_triples=extracted_triples, + chunk_uri=chunk_uri, + component_name=default_ident, + component_version=COMPONENT_VERSION, + llm_model=llm_model, + ontology_uri=ontology_uri, +) +triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +### 新的辅助签名 + +```python +def subgraph_provenance_triples( + subgraph_uri: str, + extracted_triples: List[Triple], + chunk_uri: str, + component_name: str, + component_version: str, + llm_model: Optional[str] = None, + ontology_uri: Optional[str] = None, + timestamp: Optional[str] = None, +) -> List[Triple]: + """ + Build provenance triples for a subgraph of extracted knowledge. + + Creates: + - tg:contains link for each extracted triple (RDF-star quoted) + - One prov:wasDerivedFrom link to source chunk + - One activity with agent metadata + """ +``` + +### 破坏性变更 + +这是一个对溯源模型的重大更改。 +溯源功能尚未发布,因此无需迁移。旧的 `tg:reifies` / `tg:reifies` 代码可以直接删除。 +`statement_uri` 代码可以直接删除。 diff --git a/docs/tech-specs/extraction-time-provenance.ar.md b/docs/tech-specs/extraction-time-provenance.ar.md new file mode 100644 index 00000000..7d066108 --- /dev/null +++ b/docs/tech-specs/extraction-time-provenance.ar.md @@ -0,0 +1,619 @@ +# أصل البيانات في وقت الاستخراج: الطبقة المصدر + +## نظرة عامة + +يوثق هذا المستند ملاحظات حول أصل البيانات في وقت الاستخراج لأعمال المواصفات المستقبلية. يسجل أصل البيانات في وقت الاستخراج "الطبقة المصدر" - من أين أتت البيانات في الأصل، وكيف تم استخراجها وتحويلها. + +هذا يختلف عن أصل البيانات في وقت الاستعلام (انظر `query-time-provenance.md`) الذي يسجل استنتاجات الوكيل. + +## بيان المشكلة + +### التنفيذ الحالي + +يعمل أصل البيانات حاليًا على النحو التالي: +يتم تخزين بيانات وصف المستند كـ RDF triples في الرسم البياني المعرفي. +يربط معرف المستند البيانات الوصفية بالمستند، بحيث يظهر المستند كعقدة في الرسم البياني. +عند استخراج الحواف (العلاقات/الحقائق) من المستندات، تربط علاقة `subjectOf` الحافة المستخرجة بالمستند المصدر. + +### المشاكل في النهج الحالي + +1. **تحميل البيانات الوصفية المتكرر:** يتم تجميع بيانات وصف المستند وتحميلها بشكل متكرر مع كل مجموعة من الـ triples المستخرجة من هذا المستند. هذا مضيعة ويزيد من التكرار - نفس البيانات الوصفية تنتقل كحمولة مع كل مخرج استخراج. + +2. **أصل بيانات سطحي:** تربط العلاقة `subjectOf` الحالية الحقائق مباشرة بالمستند ذي المستوى الأعلى فقط. لا توجد رؤية لسلسلة التحويل - أي الصفحة التي جاءت منها الحقيقة، أو الجزء، أو طريقة الاستخراج المستخدمة. + +### الحالة المرغوبة + +1. **تحميل البيانات الوصفية مرة واحدة:** يجب تحميل بيانات وصف المستند مرة واحدة وإرفاقها بعقدة المستند ذات المستوى الأعلى، وليس تكرارها مع كل مجموعة من الـ triples. + +2. **رسم بياني كامل لأصل البيانات:** التقاط سلسلة التحويل الكاملة من المستند المصدر عبر جميع القطع الأثرية الوسيطة وصولاً إلى الحقائق المستخرجة. على سبيل المثال، تحويل مستند PDF: + + ``` + PDF file (source document with metadata) + → Page 1 (decoded text) + → Chunk 1 + → Extracted edge/fact (via subjectOf) + → Extracted edge/fact + → Chunk 2 + → Extracted edge/fact + → Page 2 + → Chunk 3 + → ... + ``` + +3. **التخزين الموحد:** يتم تخزين الرسم البياني للأصل (provenance DAG) في نفس الرسم البياني للمعرفة كما يتم تخزين المعرفة المستخرجة. يتيح ذلك الاستعلام عن الأصل بنفس الطريقة التي يتم بها الاستعلام عن المعرفة - من خلال تتبع الحواف صعودًا في السلسلة من أي حقيقة إلى موقع مصدرها الدقيق. + +4. **معرفات مستقرة:** لكل قطعة أثرية وسيطة (صفحة، جزء) معرف مستقر كعقدة في الرسم البياني. + +5. **الربط بين الأب والطفل:** يتم ربط المستندات المشتقة بآبائها وصولاً إلى المستند المصدر الرئيسي باستخدام أنواع علاقات متسقة. + +6. **تخصيص الحقائق بدقة:** تشير العلاقة `subjectOf` في الحواف المستخرجة إلى الأصل الفوري (الجزء)، وليس المستند الرئيسي. يتم استعادة الأصل الكامل من خلال التنقل عبر الرسم البياني للأصل. + +## حالات الاستخدام + +### UC1: تحديد مصدر المعلومات في استجابات GraphRAG + +**السيناريو:** يقوم المستخدم بتشغيل استعلام GraphRAG ويتلقى استجابة من الوكيل. + +**التدفق:** +1. يرسل المستخدم استعلامًا إلى وكيل GraphRAG. +2. يسترجع الوكيل الحقائق ذات الصلة من الرسم البياني للمعرفة لصياغة استجابة. +3. وفقًا لمواصفات الأصل في وقت الاستعلام، يقوم الوكيل بالإبلاغ عن الحقائق التي ساهمت في الاستجابة. +4. يربط كل حقيقة بمصدره (الجزء) عبر الرسم البياني للأصل. +5. ترتبط الأجزاء بالصفحات، وترتبط الصفحات بمستندات المصدر. + +**النتيجة في تجربة المستخدم:** يعرض الواجهة استجابة نموذج اللغة الكبير (LLM) جنبًا إلى جنب مع تحديد مصدر المعلومات. يمكن للمستخدم: +رؤية الحقائق التي دعمت الاستجابة. +النزول من الحقائق إلى الأجزاء إلى الصفحات إلى المستندات. +مراجعة المستندات المصدر الأصلية للتحقق من صحة الادعاءات. +فهم بالضبط من أين في المستند (في أي صفحة، في أي قسم) نشأت الحقيقة. + +**القيمة:** يمكن للمستخدمين التحقق من صحة الاستجابات التي تم إنشاؤها بواسطة الذكاء الاصطناعي مقابل المصادر الأولية، مما يعزز الثقة ويمكن المستخدمين من التحقق من الحقائق. + +### UC2: تصحيح جودة الاستخراج + +تبدو حقيقة خاطئة. تتبعها من خلال الجزء إلى الصفحة إلى المستند لمعرفة النص الأصلي. هل كان استخراجًا سيئًا، أم أن المصدر نفسه كان خاطئًا؟ + +### UC3: إعادة استخراج تدريجي + +يتم تحديث مستند المصدر. ما هي الأجزاء/الحقائق التي تم اشتقاقها منه؟ قم بإبطالها وإعادة إنشائها فقط لتلك الأجزاء، بدلاً من إعادة معالجة كل شيء. + +### UC4: حذف البيانات / الحق في النسيان + +يجب إزالة مستند المصدر (بسبب اللائحة العامة لحماية البيانات، أو لأسباب قانونية، إلخ). تتبع الرسم البياني للأصل للعثور على جميع الحقائق المشتقة وإزالتها. + +### UC5: حل النزاعات + +تتناقض حقائق مع بعضها البعض. تتبع كلتا الحالتين إلى مصادرها لفهم السبب واتخاذ قرار بشأن أي منهما يجب الوثوق به (المصدر الأكثر موثوقية، أو الأحدث، إلخ). + +### UC6: وزن سلطة المصدر + +بعض المصادر أكثر موثوقية من غيرها. يمكن ترجيح الحقائق أو تصفيتها بناءً على سلطة/جودة مستندات الأصل. + +### UC7: مقارنة مسار الاستخراج + +قارن المخرجات من طرق/إصدارات استخراج مختلفة. أي أداة استخراج أنتجت حقائق أفضل من نفس المصدر؟ + +## نقاط التكامل + +### أمين المكتبة + +يوفر مكون أمين المكتبة بالفعل تخزين المستندات بمعرفات مستندات فريدة. يتكامل نظام التتبع مع هذه البنية التحتية الحالية. + +#### القدرات الحالية (تم تنفيذها بالفعل) + +**ربط المستندات من الأب إلى الابن:** +`parent_id` الحقل في `DocumentMetadata` - يربط المستند الابن بالمستند الأب +`document_type` الحقل - القيم: `"source"` (أصلي) أو `"extracted"` (مشتق) +واجهة برمجة تطبيقات `add-child-document` - لإنشاء مستند ابن بمعرف `document_type = "extracted"` تلقائيًا +واجهة برمجة تطبيقات `list-children` - لاسترداد جميع المستندات الابناء لمستند أب معين +الحذف المتتالي - يؤدي إزالة مستند الأب تلقائيًا إلى حذف جميع مستندات الأبناء + +**تحديد المستند:** +معرفات المستندات محددة من قبل العميل (وليس تم إنشاؤها تلقائيًا) +المستندات مفهرسة باستخدام `(user, document_id)` المركب في Cassandra +يتم إنشاء معرفات الكائنات (UUIDs) داخليًا لتخزين الكائنات الثنائية + +**دعم البيانات الوصفية:** +`metadata: list[Triple]` الحقل - ثلاثيات RDF للبيانات الوصفية المنظمة +`title`، `comments`، `tags` - بيانات وصفية أساسية للمستند +`time` - الطابع الزمني، `kind` - نوع MIME + +**هيكل التخزين:** +يتم تخزين البيانات الوصفية في Cassandra (مساحة مفاتيح `librarian`، جدول `document`) +يتم تخزين المحتوى في تخزين الكائنات الثنائية MinIO/S3 (دلو `library`) +تسليم محتوى ذكي: يتم تضمين المستندات الأقل من 2 ميجابايت، ويتم بث المستندات الأكبر حجمًا + +#### الملفات الرئيسية + +`trustgraph-flow/trustgraph/librarian/librarian.py` - العمليات الأساسية لأمين المكتبة +`trustgraph-flow/trustgraph/librarian/service.py` - معالج الخدمة، تحميل المستند +`trustgraph-flow/trustgraph/tables/library.py` - تخزين جدول Cassandra +`trustgraph-base/trustgraph/schema/services/library.py` - تعريفات المخططات + +#### الثغرات التي يجب معالجتها + +يحتوي أمين المكتبة على اللبنات الأساسية ولكن حاليًا: +1. الربط من الأب إلى الابن ذو مستوى واحد فقط - لا توجد أدوات مساعدة لتصفح الرسوم البيانية متعددة المستويات +2. لا يوجد مفردات قياسية لأنواع العلاقات (مثل `derivedFrom`، `extractedFrom`) +3. بيانات التتبع الوصفية (طريقة الاستخراج، والثقة، وموضع الجزء) غير موحدة +4. لا توجد واجهة برمجة تطبيقات للاستعلام للتنقل عبر سلسلة التتبع الكاملة من حقيقة إلى المصدر + +## تصميم التدفق الشامل + +يتبع كل معالج في خط الأنابيب نمطًا متسقًا: +استقبال معرف المستند من البنية التحتية +جلب المحتوى من أمين المكتبة +إنتاج القطع الأثرية الفرعية +لكل قطعة أثرية فرعية: حفظ في أمين المكتبة، وإصدار حافة إلى الرسم البياني، وتمرير المعرف إلى البنية التحتية + +### تدفقات المعالجة + +هناك تدفقان اعتمادًا على نوع المستند: + +#### تدفق مستند PDF + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID to PDF extractor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ PDF Extractor (per page) │ +│ 1. Fetch PDF content from librarian using document ID │ +│ 2. Extract pages as text │ +│ 3. For each page: │ +│ a. Save page as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send page document ID to chunker │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch page content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = page) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + Post-chunker optimization: messages carry both + chunk ID (for provenance) and content (to avoid + librarian round-trip). Chunks are small (2-4KB). + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor (per chunk) │ +│ 1. Receive chunk ID + content directly (no librarian fetch needed) │ +│ 2. Extract facts/triples and embeddings from chunk content │ +│ 3. For each triple: │ +│ a. Emit triple to knowledge graph │ +│ b. Emit reified edge linking triple → chunk ID (edge pointing │ +│ to edge - first use of reification support) │ +│ 4. For each embedding: │ +│ a. Emit embedding with its entity ID │ +│ b. Link entity ID → chunk ID in knowledge graph │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +#### تدفق مستندات النص + +تتجاوز مستندات النص أداة استخراج ملفات PDF وتنتقل مباشرةً إلى وحدة التقسيم: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID directly to chunker (skip PDF extractor) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch text content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor │ +│ (same as PDF flow) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +الرسم البياني الموجه الناتج أقصر بمستوى واحد: + +``` +PDF: Document → Pages → Chunks → Triples/Embeddings +Text: Document → Chunks → Triples/Embeddings +``` + +التصميم يتكيف مع كل من المصدر والصفحة لأن وحدة التقسيم تعالج مدخلاتها بشكل عام - فهي تستخدم أي معرف مستند تتلقاه كمعرف رئيسي، بغض النظر عما إذا كان ذلك مستند مصدر أم صفحة. + +### مخطط البيانات الوصفية (PROV-O) + +تستخدم البيانات الوصفية المتعلقة بالأصل علم الوجود W3C PROV-O. يوفر هذا مفردات قياسية ويمكن أن يمكّن التوقيع/المصادقة المستقبلية لنتائج الاستخراج. + +#### المفاهيم الأساسية في PROV-O + +| نوع PROV-O | استخدام TrustGraph | +|-------------|------------------| +| `prov:Entity` | مستند، صفحة، جزء، ثلاثي، تضمين | +| `prov:Activity` | حالات عمليات الاستخراج | +| `prov:Agent` | مكونات TG (مثل أداة استخراج PDF، ووحدة التقسيم، إلخ) مع الإصدارات | + +#### علاقات PROV-O + +| الرابط | المعنى | مثال | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | كيان مشتق من كيان آخر | الصفحة مشتقة من المستند | +| `prov:wasGeneratedBy` | كيان تم إنشاؤه بواسطة نشاط | الصفحة تم إنشاؤها بواسطة نشاط استخراج PDF | +| `prov:used` | نشاط استخدم كيانًا كمدخل | نشاط استخراج PDF استخدم المستند | +| `prov:wasAssociatedWith` | نشاط تم تنفيذه بواسطة وكيل | نشاط استخراج PDF مرتبط بـ tg:PDFExtractor | + +#### البيانات الوصفية في كل مستوى + +**المستند المصدر (يتم إصداره بواسطة Librarian):** +``` +doc:123 a prov:Entity . +doc:123 dc:title "Research Paper" . +doc:123 dc:source . +doc:123 dc:date "2024-01-15" . +doc:123 dc:creator "Author Name" . +doc:123 tg:pageCount 42 . +doc:123 tg:mimeType "application/pdf" . +``` + +**الصفحة (تم إنشاؤها بواسطة مُستخرج PDF):** +``` +page:123-1 a prov:Entity . +page:123-1 prov:wasDerivedFrom doc:123 . +page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 . +page:123-1 tg:pageNumber 1 . + +activity:pdf-extract-456 a prov:Activity . +activity:pdf-extract-456 prov:used doc:123 . +activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor . +activity:pdf-extract-456 tg:componentVersion "1.2.3" . +activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . +``` + +**الجزء (يتم إصداره بواسطة وحدة التجميع):** +``` +chunk:123-1-1 a prov:Entity . +chunk:123-1-1 prov:wasDerivedFrom page:123-1 . +chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 . +chunk:123-1-1 tg:chunkIndex 1 . +chunk:123-1-1 tg:charOffset 0 . +chunk:123-1-1 tg:charLength 2048 . + +activity:chunk-789 a prov:Activity . +activity:chunk-789 prov:used page:123-1 . +activity:chunk-789 prov:wasAssociatedWith tg:Chunker . +activity:chunk-789 tg:componentVersion "1.0.0" . +activity:chunk-789 tg:chunkSize 2048 . +activity:chunk-789 tg:chunkOverlap 200 . +``` + +**ثلاثي (تم إصداره بواسطة مُستخلص المعرفة):** +``` +# The extracted triple (edge) +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph containing the extracted triples +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 prov:wasGeneratedBy activity:extract-999 . + +activity:extract-999 a prov:Activity . +activity:extract-999 prov:used chunk:123-1-1 . +activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor . +activity:extract-999 tg:componentVersion "2.1.0" . +activity:extract-999 tg:llmModel "claude-3" . +activity:extract-999 tg:ontology . +``` + +**التضمين (يتم تخزينه في مخزن المتجهات، وليس في مخزن الثلاثيات):** + +يتم تخزين التضمينات في مخزن المتجهات مع البيانات الوصفية، وليس كـ RDF triples. يحتوي كل سجل تضمين على: + +| الحقل | الوصف | مثال | +|-------|-------------|---------| +| vector | متجه التضمين | [0.123, -0.456, ...] | +| entity | عنوان URI للعقدة التي يمثلها التضمين | `entity:JohnSmith` | +| chunk_id | الجزء المصدر (الأصل) | `chunk:123-1-1` | +| model | نموذج التضمين المستخدم | `text-embedding-ada-002` | +| component_version | إصدار مُحسِّن التضمين (TG embedder) | `1.0.0` | + +يربط الحقل `entity` التضمين بالرسم البياني المعرفي (عنوان URI للعقدة). يوفر الحقل `chunk_id` معلومات عن الأصل إلى الجزء المصدر، مما يتيح التنقل صعودًا في الرسم البياني الموجه (DAG) إلى المستند الأصلي. + +#### امتدادات مساحة اسم TrustGraph + +محددات مخصصة ضمن مساحة الاسم `tg:` لبيانات وصفية خاصة بالاستخراج: + +| المحدد | النطاق | الوصف | +|-----------|--------|-------------| +| `tg:contains` | Subgraph | يشير إلى ثلاثية موجودة في هذا الرسوم البيانية الفرعية للاستخراج | +| `tg:pageCount` | Document | العدد الإجمالي لصفحات المستند المصدر | +| `tg:mimeType` | Document | نوع MIME للمستند المصدر | +| `tg:pageNumber` | Page | رقم الصفحة في المستند المصدر | +| `tg:chunkIndex` | Chunk | فهرس الجزء داخل الأصل | +| `tg:charOffset` | Chunk | الإزاحة الحرفية في النص الأصل | +| `tg:charLength` | Chunk | طول الجزء بالأحرف | +| `tg:chunkSize` | Activity | حجم الجزء المُكوَّن | +| `tg:chunkOverlap` | Activity | التداخل المُكوَّن بين الأجزاء | +| `tg:componentVersion` | Activity | إصدار مكون TG | +| `tg:llmModel` | Activity | نموذج LLM المستخدم للاستخراج | +| `tg:ontology` | Activity | عنوان URI للأنطولوجيا المستخدم لتوجيه الاستخراج | +| `tg:embeddingModel` | Activity | النموذج المستخدم للتضمينات | +| `tg:sourceText` | Statement | النص الدقيق الذي تم استخراج ثلاثية منه | +| `tg:sourceCharOffset` | Statement | الإزاحة الحرفية داخل الجزء حيث يبدأ النص المصدر | +| `tg:sourceCharLength` | Statement | طول النص المصدر بالأحرف | + +#### تهيئة المفردات (لكل مجموعة) + +الرسم البياني المعرفي محايد للأنطولوجيا ويبدأ فارغًا. عند كتابة بيانات سلالة PROV-O إلى مجموعة لأول مرة، يجب تهيئة المفردات باستخدام تسميات RDF لجميع الفئات والمحددات. يضمن ذلك عرضًا قابلاً للقراءة بواسطة الإنسان في الاستعلامات وواجهة المستخدم. + +**فئات PROV-O:** +``` +prov:Entity rdfs:label "Entity" . +prov:Activity rdfs:label "Activity" . +prov:Agent rdfs:label "Agent" . +``` + +**المُتَعَدِّيات (Predicates) الخاصة بـ PROV-O:** +``` +prov:wasDerivedFrom rdfs:label "was derived from" . +prov:wasGeneratedBy rdfs:label "was generated by" . +prov:used rdfs:label "used" . +prov:wasAssociatedWith rdfs:label "was associated with" . +prov:startedAtTime rdfs:label "started at" . +``` + +**عبارات TrustGraph:** +``` +tg:contains rdfs:label "contains" . +tg:pageCount rdfs:label "page count" . +tg:mimeType rdfs:label "MIME type" . +tg:pageNumber rdfs:label "page number" . +tg:chunkIndex rdfs:label "chunk index" . +tg:charOffset rdfs:label "character offset" . +tg:charLength rdfs:label "character length" . +tg:chunkSize rdfs:label "chunk size" . +tg:chunkOverlap rdfs:label "chunk overlap" . +tg:componentVersion rdfs:label "component version" . +tg:llmModel rdfs:label "LLM model" . +tg:ontology rdfs:label "ontology" . +tg:embeddingModel rdfs:label "embedding model" . +tg:sourceText rdfs:label "source text" . +tg:sourceCharOffset rdfs:label "source character offset" . +tg:sourceCharLength rdfs:label "source character length" . +``` + +**ملاحظة حول التنفيذ:** يجب أن يكون هذا الإطار اللغوي ذاتي الإعادة - آمنًا للتشغيل عدة مرات دون إنشاء تكرارات. يمكن تشغيله في معالجة المستند الأول في المجموعة، أو كخطوة منفصلة لتهيئة المجموعة. + +#### أصل الجزء الفرعي (طموح) + +للحصول على معلومات تفصيلية حول الأصل، سيكون من المفيد تسجيل المكان الدقيق داخل جزء معين حيث تم استخراج الثلاثي. هذا يسمح بـ: + +تسليط الضوء على النص المصدر الدقيق في واجهة المستخدم. +التحقق من دقة الاستخراج مقابل المصدر. +تصحيح جودة الاستخراج على مستوى الجملة. + +**مثال مع تتبع الموضع:** +``` +# The extracted triple +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph with sub-chunk provenance +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +subgraph:001 tg:sourceCharOffset 1547 . +subgraph:001 tg:sourceCharLength 46 . +``` + +**مثال مع نطاق نص (بديل):** +``` +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceRange "1547-1593" . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +``` + +**اعتبارات التنفيذ:** + +قد لا توفر استخراج البيانات باستخدام نماذج اللغة الكبيرة (LLM) بشكل طبيعي مواقع الأحرف. +يمكن توجيه نموذج اللغة الكبيرة لإرجاع الجملة/العبارة المصدرية بالإضافة إلى الثلاثيات المستخرجة. +بدلاً من ذلك، يمكن إجراء معالجة لاحقة لمطابقة الكيانات المستخرجة بشكل تقريبي مع النص المصدر. +يوجد مقايضة بين تعقيد الاستخراج ودقة تتبع المصدر. +قد يكون من الأسهل تحقيق ذلك باستخدام طرق الاستخراج المنظمة بدلاً من استخراج البيانات المجردة باستخدام نماذج اللغة الكبيرة. + +هذا الأمر مصنف على أنه طموح - يجب تنفيذ تتبع المصدر على مستوى المقطع أولاً، مع تتبع المقطع الفرعي كتحسين مستقبلي إذا كان ذلك ممكنًا. + +### نموذج التخزين المزدوج + +يتم بناء رسم بياني لتتبع المصدر بشكل تدريجي أثناء تدفق المستندات عبر مسار العمل: + +| التخزين | ما يتم تخزينه | الغرض | +|-------|---------------|---------| +| أمين المكتبة | محتوى المستند + روابط الأبناء | استرجاع المحتوى، حذف متسلسل | +| الرسم البياني للمعرفة | حواف الأبناء، وبيانات وصفية | استعلامات تتبع المصدر، إسناد الحقائق | + +تحتفظ كلا التخزينين بنفس هيكل الرسم البياني. يحتوي أمين المكتبة على المحتوى، بينما يحتوي الرسم البياني على العلاقات ويمكنه تمكين استعلامات التصفح. + +### المبادئ الأساسية للتصميم + +1. **معرف المستند كوحدة تدفق** - تمرر المعالجات المعرفات، وليس المحتوى. يتم استرداد المحتوى من أمين المكتبة عند الحاجة. + +2. **الإرسال مرة واحدة من المصدر** - يتم كتابة البيانات الوصفية في الرسم البياني مرة واحدة عند بدء المعالجة، وليس بشكل متكرر في المراحل اللاحقة. + +3. **نمط معالج متسق** - يتبع كل معالج نفس النمط: الاستقبال/الاسترداد/الإنتاج/الحفظ/الإرسال/التوجيه. + +4. **بناء تدريجي للرسم البياني** - يضيف كل معالج مستواه إلى الرسم البياني. يتم بناء سلسلة تتبع المصدر الكاملة بشكل تدريجي. + +5. **تحسين ما بعد التقطيع** - بعد التقطيع، تحمل الرسائل كلاً من المعرف والمحتوى. تكون القطع صغيرة (2-4 كيلوبايت)، لذلك يؤدي تضمين المحتوى إلى تجنب عمليات الذهاب والإياب غير الضرورية إلى أمين المكتبة مع الحفاظ على تتبع المصدر عبر المعرف. + +## مهام التنفيذ + +### تغييرات أمين المكتبة + +#### الحالة الحالية + +يبدأ معالجة المستند عن طريق إرسال معرف المستند إلى المعالج الأول. +لا يوجد اتصال بمخزن الثلاثيات - يتم تجميع البيانات الوصفية مع مخرجات الاستخراج. +`add-child-document` ينشئ روابط الأبناء من مستوى واحد. +`list-children` يُرجع فقط الأبناء المباشرين. + +#### التغييرات المطلوبة + +**1. واجهة جديدة: اتصال بمخزن الثلاثيات** + +يحتاج أمين المكتبة إلى إرسال حواف بيانات وصفية للمستند مباشرة إلى الرسم البياني للمعرفة عند بدء المعالجة. +إضافة عميل/ناشر مخزن الثلاثيات إلى خدمة أمين المكتبة. +عند بدء المعالجة: إرسال بيانات وصفية للمستند الجذر كحواف في الرسم البياني (مرة واحدة). + +**2. مفردات أنواع المستندات** + +توحيد قيم `document_type` لأبناء المستند: +`source` - المستند الذي تم تحميله أصلاً. +`page` - صفحة مستخرجة من المصدر (PDF، إلخ). +`chunk` - جزء نصي مشتق من الصفحة أو المصدر. + +#### ملخص تغييرات الواجهة + +| الواجهة | التغيير | +|-----------|--------| +| مخزن الثلاثيات | اتصال صادر جديد - إرسال حواف بيانات وصفية للمستند | +| بدء المعالجة | إرسال البيانات الوصفية إلى الرسم البياني قبل توجيه معرف المستند | + +### تغييرات مستخرج PDF + +#### الحالة الحالية + +يتلقى محتوى المستند (أو يتدفق المستندات الكبيرة). +يستخرج النص من صفحات PDF. +يوجه محتوى الصفحة إلى وحدة التقطيع. +لا يوجد تفاعل مع أمين المكتبة أو مخزن الثلاثيات. + +#### التغييرات المطلوبة + +**1. واجهة جديدة: عميل أمين المكتبة** + +يحتاج مستخرج PDF إلى حفظ كل صفحة كمستند تابع في أمين المكتبة. +إضافة عميل أمين المكتبة إلى خدمة مستخرج PDF. +لكل صفحة: استدعاء `add-child-document` مع parent = معرف المستند الجذر. + +**2. واجهة جديدة: اتصال بمخزن الثلاثيات** + +يحتاج مستخرج PDF إلى إرسال حواف الأبناء إلى الرسم البياني للمعرفة. +إضافة عميل/ناشر مخزن الثلاثيات. +لكل صفحة: إرسال حافة تربط مستند الصفحة بالمستند الأصل. + +**3. تغيير تنسيق الإخراج** + +بدلًا من إرسال محتوى الصفحة مباشرةً، أرسل مُعرّف مستند الصفحة. +سيقوم المقطع (Chunker) بجلب المحتوى من أمين المكتبة (librarian) باستخدام المعرّف. + +#### ملخص التغييرات في الواجهة + +| الواجهة | التغيير | +|-----------|--------| +| أمين المكتبة (Librarian) | واجهة تصدير جديدة - حفظ المستندات الفرعية | +| قاعدة البيانات الثلاثية (Triple store) | واجهة تصدير جديدة - إرسال علاقات الأبناء والبنات | +| رسالة الإخراج | تغيير من المحتوى إلى مُعرّف المستند | + +### تغييرات المقطع (Chunker) + +#### الحالة الحالية + +يستقبل محتوى الصفحة/النص +يقسم إلى أجزاء (chunks) +يرسل محتوى الجزء إلى المعالجات اللاحقة +لا يوجد تفاعل مع أمين المكتبة أو قاعدة البيانات الثلاثية + +#### التغييرات المطلوبة + +**1. تغيير طريقة معالجة الإدخال** + +استقبل مُعرّف المستند بدلًا من المحتوى، وجلبه من أمين المكتبة. +أضف عميل أمين المكتبة إلى خدمة المقطع. +جلب محتوى الصفحة باستخدام مُعرّف المستند. + +**2. واجهة جديدة: عميل أمين المكتبة (للكتابة)** + +احفظ كل جزء كمستند فرعي في أمين المكتبة. +لكل جزء: استدعِ `add-child-document` مع `parent = page document ID` + +**3. واجهة جديدة: اتصال بقاعدة البيانات الثلاثية** + +أرسل علاقات الأبناء والبنات إلى الرسم البياني المعرفي. +أضف عميل/ناشر قاعدة البيانات الثلاثية. +لكل جزء: أرسل علاقة تربط مستند الجزء بمستند الصفحة. + +**4. تغيير تنسيق الإخراج** + +أرسل كلاً من مُعرّف مستند الجزء ومحتوى الجزء (تحسين لاحق للمقطع). +تستقبل المعالجات اللاحقة المعرّف لأغراض التتبع + المحتوى للعمل به. + +#### ملخص التغييرات في الواجهة + +| الواجهة | التغيير | +|-----------|--------| +| رسالة الإدخال | تغيير من المحتوى إلى مُعرّف المستند | +| أمين المكتبة (Librarian) | واجهة تصدير جديدة (قراءة وكتابة) - جلب المحتوى، حفظ المستندات الفرعية | +| قاعدة البيانات الثلاثية (Triple store) | واجهة تصدير جديدة - إرسال علاقات الأبناء والبنات | +| رسالة الإخراج | تغيير من المحتوى فقط إلى المعرّف + المحتوى | + +### تغييرات مُستخرج المعرفة (Knowledge Extractor) + +#### الحالة الحالية + +يستقبل محتوى الجزء +يستخرج الثلاثيات والتضمينات +يرسل إلى قاعدة البيانات الثلاثية ومخزن التضمينات +`subjectOf` تشير العلاقة إلى المستند ذي المستوى الأعلى (وليس الجزء) + +#### التغييرات المطلوبة + +**1. تغيير طريقة معالجة الإدخال** + +استقبل مُعرّف مستند الجزء بالإضافة إلى المحتوى. +استخدم مُعرّف الجزء لأغراض الربط (المحتوى مدرج بالفعل كتحسين). + +**2. تحديث أثر الثلاثيات** + +اربط الثلاثيات المستخرجة بالجزء (وليس المستند ذي المستوى الأعلى). +استخدم التجريد لإنشاء حافة تشير إلى الحافة +`subjectOf` العلاقة: ثلاثية → مُعرّف مستند الجزء +الاستخدام الأول للدعم الحالي للتجريد + +**3. تحديث أثر التضمينات** + +اربط معرفات كيانات التضمين بالجزء. +أرسل حافة: معرف كيان التضمين → مُعرّف مستند الجزء + +#### ملخص التغييرات في الواجهة + +| الواجهة | التغيير | +|-----------|--------| +| رسالة الإدخال | توقع مُعرّف الجزء + المحتوى (وليس المحتوى فقط) | +| قاعدة البيانات الثلاثية | استخدم التجريد لأثر الثلاثية → الجزء | +| أثر التضمين | اربط معرف الكيان → معرف الجزء | + +## المراجع + +أثر وقت الاستعلام: `docs/tech-specs/query-time-provenance.md` +معيار PROV-O لنمذجة الأثر +البيانات الوصفية المصدر الحالية في الرسم البياني المعرفي (تحتاج إلى تدقيق) diff --git a/docs/tech-specs/extraction-time-provenance.es.md b/docs/tech-specs/extraction-time-provenance.es.md new file mode 100644 index 00000000..e6721819 --- /dev/null +++ b/docs/tech-specs/extraction-time-provenance.es.md @@ -0,0 +1,619 @@ +# Proveniencia en Tiempo de Extracción: Capa de Origen + +## Resumen + +Este documento captura notas sobre la proveniencia en tiempo de extracción para futuros trabajos de especificación. La proveniencia en tiempo de extracción registra la "capa de origen": de dónde provienen los datos originalmente, cómo se extrajeron y transformaron. + +Esto es diferente de la proveniencia en tiempo de consulta (ver `query-time-provenance.md`), que registra el razonamiento del agente. + +## Declaración del Problema + +### Implementación Actual + +Actualmente, la proveniencia funciona de la siguiente manera: +Los metadatos del documento se almacenan como triples RDF en el grafo de conocimiento. +Un ID de documento vincula los metadatos al documento, de modo que el documento aparece como un nodo en el grafo. +Cuando se extraen aristas (relaciones/hechos) de los documentos, una relación `subjectOf` vincula la arista extraída con el documento de origen. + +### Problemas con el Enfoque Actual + +1. **Carga repetitiva de metadatos:** Los metadatos del documento se empaquetan y cargan repetidamente con cada lote de triples extraídos de ese documento. Esto es un desperdicio y redundante: los mismos metadatos viajan como carga con cada salida de extracción. + +2. **Proveniencia superficial:** La relación `subjectOf` actual solo vincula los hechos directamente con el documento de nivel superior. No hay visibilidad de la cadena de transformación: qué página proporcionó el hecho, qué fragmento, qué método de extracción se utilizó. + +### Estado Deseado + +1. **Cargar metadatos una vez:** Los metadatos del documento deben cargarse una vez y adjuntarse al nodo del documento de nivel superior, no repetirse con cada lote de triples. + +2. **DAG de proveniencia rica:** Capturar toda la cadena de transformación desde el documento de origen a través de todos los artefactos intermedios hasta los hechos extraídos. Por ejemplo, una transformación de un documento PDF: + + ``` + PDF file (source document with metadata) + → Page 1 (decoded text) + → Chunk 1 + → Extracted edge/fact (via subjectOf) + → Extracted edge/fact + → Chunk 2 + → Extracted edge/fact + → Page 2 + → Chunk 3 + → ... + ``` + +3. **Almacenamiento unificado:** El grafo de procedencia se almacena en el mismo grafo de conocimiento que el conocimiento extraído. Esto permite consultar la procedencia de la misma manera que se consulta el conocimiento: siguiendo los enlaces hacia atrás a lo largo de la cadena desde cualquier hecho hasta su ubicación de origen exacta. + +4. **Identificadores estables:** Cada artefacto intermedio (página, fragmento) tiene un identificador estable como un nodo en el grafo. + +5. **Enlace padre-hijo:** Los documentos derivados se vinculan a sus padres hasta el documento fuente de nivel superior, utilizando tipos de relación consistentes. + +6. **Atribución precisa de hechos:** La relación `subjectOf` en los bordes extraídos apunta al padre inmediato (fragmento), no al documento de nivel superior. La procedencia completa se recupera recorriendo el DAG. + +## Casos de uso + +### UC1: Atribución de la fuente en las respuestas de GraphRAG + +**Escenario:** Un usuario ejecuta una consulta de GraphRAG y recibe una respuesta del agente. + +**Flujo:** +1. El usuario envía una consulta al agente de GraphRAG. +2. El agente recupera hechos relevantes del grafo de conocimiento para formular una respuesta. +3. De acuerdo con la especificación de procedencia en tiempo de consulta, el agente informa qué hechos contribuyeron a la respuesta. +4. Cada hecho se vincula a su fragmento de origen a través del grafo de procedencia. +5. Los fragmentos se vinculan a páginas, las páginas se vinculan a documentos fuente. + +**Resultado de la experiencia de usuario:** La interfaz muestra la respuesta del LLM junto con la atribución de la fuente. El usuario puede: +Ver qué hechos respaldaron la respuesta. +Profundizar desde hechos → fragmentos → páginas → documentos. +Examinar los documentos fuente originales para verificar las afirmaciones. +Comprender exactamente dónde en un documento (en qué página, en qué sección) se originó un hecho. + +**Valor:** Los usuarios pueden verificar las respuestas generadas por la IA con fuentes primarias, lo que genera confianza y permite la verificación de hechos. + +### UC2: Depuración de la calidad de la extracción + +Un hecho parece incorrecto. Rastrear hacia atrás a través del fragmento → página → documento para ver el texto original. ¿Fue una mala extracción, o la fuente en sí misma estaba equivocada? + +### UC3: Reextracción incremental + +El documento fuente se actualiza. ¿Qué fragmentos/hechos se derivaron de él? Invalidar y regenerar solo esos, en lugar de volver a procesar todo. + +### UC4: Eliminación de datos / Derecho al olvido + +Se debe eliminar un documento fuente (GDPR, legal, etc.). Recorrer el DAG para encontrar y eliminar todos los hechos derivados. + +### UC5: Resolución de conflictos + +Dos hechos se contradicen. Rastrear ambos hasta sus fuentes para comprender por qué y decidir a cuál confiar (fuente más autorizada, más reciente, etc.). + +### UC6: Ponderación de la autoridad de la fuente + +Algunas fuentes son más autorizadas que otras. Los hechos se pueden ponderar o filtrar según la autoridad/calidad de sus documentos de origen. + +### UC7: Comparación de la canalización de extracción + +Comparar los resultados de diferentes métodos/versiones de extracción. ¿Qué extractor produjo mejores hechos del mismo documento fuente? + +## Puntos de integración + +### Bibliotecario + +El componente de bibliotecario ya proporciona almacenamiento de documentos con identificadores de documentos únicos. El sistema de procedencia se integra con esta infraestructura existente. + +#### Capacidades existentes (ya implementadas) + +**Vinculación de documentos padre-hijo:** +Campo `parent_id` en `DocumentMetadata`: vincula el documento hijo al documento padre. +Campo `document_type`: valores: `"source"` (original) o `"extracted"` (derivado). +API `add-child-document`: crea un documento hijo con `document_type = "extracted"` automático. +API `list-children`: recupera todos los hijos de un documento padre. +Eliminación en cascada: eliminar un padre elimina automáticamente todos los documentos hijo. + +**Identificación de documentos:** +Los identificadores de documentos son especificados por el cliente (no generados automáticamente). +Documentos indexados por una clave compuesta `(user, document_id)` en Cassandra. +Identificadores de objetos (UUID) generados internamente para el almacenamiento de blobs. + +**Soporte de metadatos:** +Campo `metadata: list[Triple]`: triples RDF para metadatos estructurados. +`title`, `comments`, `tags`: metadatos básicos del documento. +`time`: marca de tiempo, `kind`: tipo MIME. + +**Arquitectura de almacenamiento:** +Los metadatos se almacenan en Cassandra (espacio de claves `librarian`, tabla `document`). +El contenido se almacena en MinIO/S3 blob storage (cubeta `library`). +Entrega inteligente de contenido: documentos < 2 MB incrustados, documentos más grandes transmitidos por flujo. + +#### Archivos clave + +`trustgraph-flow/trustgraph/librarian/librarian.py`: operaciones principales del bibliotecario. +`trustgraph-flow/trustgraph/librarian/service.py`: procesador de servicios, carga de documentos. +`trustgraph-flow/trustgraph/tables/library.py`: almacén de tablas de Cassandra. +`trustgraph-base/trustgraph/schema/services/library.py`: definiciones de esquema. + +#### Aspectos a abordar + +El bibliotecario tiene los componentes básicos, pero actualmente: +1. La vinculación padre-hijo es de un solo nivel: no hay ayudantes de recorrido de DAG multinivel. +2. No hay un vocabulario estándar de tipos de relación (por ejemplo, `derivedFrom`, `extractedFrom`). +3. Los metadatos de procedencia (método de extracción, confianza, posición de fragmento) no están estandarizados. +4. No hay una API de consulta para recorrer toda la cadena de procedencia desde un hecho hasta la fuente. + +## Diseño de flujo de extremo a extremo + +Cada procesador en la canalización sigue un patrón consistente: +Recibe el ID del documento del componente anterior. +Recupera el contenido del bibliotecario. +Produce artefactos secundarios. +Para cada hijo: guarda en el bibliotecario, emite un borde al gráfico, reenvía el ID al componente posterior. + +### Flujos de procesamiento + +Existen dos flujos dependiendo del tipo de documento: + +#### Flujo de documento PDF + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID to PDF extractor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ PDF Extractor (per page) │ +│ 1. Fetch PDF content from librarian using document ID │ +│ 2. Extract pages as text │ +│ 3. For each page: │ +│ a. Save page as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send page document ID to chunker │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch page content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = page) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + Post-chunker optimization: messages carry both + chunk ID (for provenance) and content (to avoid + librarian round-trip). Chunks are small (2-4KB). + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor (per chunk) │ +│ 1. Receive chunk ID + content directly (no librarian fetch needed) │ +│ 2. Extract facts/triples and embeddings from chunk content │ +│ 3. For each triple: │ +│ a. Emit triple to knowledge graph │ +│ b. Emit reified edge linking triple → chunk ID (edge pointing │ +│ to edge - first use of reification support) │ +│ 4. For each embedding: │ +│ a. Emit embedding with its entity ID │ +│ b. Link entity ID → chunk ID in knowledge graph │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +#### Flujo de documentos de texto + +Los documentos de texto omiten el extractor de PDF y van directamente al fragmentador: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID directly to chunker (skip PDF extractor) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch text content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor │ +│ (same as PDF flow) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +El DAG resultante es un nivel más corto: + +``` +PDF: Document → Pages → Chunks → Triples/Embeddings +Text: Document → Chunks → Triples/Embeddings +``` + +El diseño se adapta a ambos porque el componente de segmentación trata su entrada de forma genérica; utiliza cualquier ID de documento que reciba como elemento padre, independientemente de si se trata de un documento fuente o de una página. + +### Esquema de metadatos (PROV-O) + +Los metadatos de procedencia utilizan la ontología W3C PROV-O. Esto proporciona un vocabulario estándar y permite la futura firma/autenticación de los resultados de la extracción. + +#### Conceptos principales de PROV-O + +| Tipo PROV-O | Uso en TrustGraph | +|-------------|------------------| +| `prov:Entity` | Documento, Página, Segmento, Triple, Incrustación | +| `prov:Activity` | Instancias de operaciones de extracción | +| `prov:Agent` | Componentes de TG (extractor de PDF, segmentador, etc.) con versiones | + +#### Relaciones PROV-O + +| Predicado | Significado | Ejemplo | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | Entidad derivada de otra entidad | Página wasDerivedFrom Documento | +| `prov:wasGeneratedBy` | Entidad generada por una actividad | Página wasGeneratedBy PDFExtractionActivity | +| `prov:used` | Actividad que utiliza una entidad como entrada | PDFExtractionActivity used Documento | +| `prov:wasAssociatedWith` | Actividad realizada por un agente | PDFExtractionActivity wasAssociatedWith tg:PDFExtractor | + +#### Metadatos en cada nivel + +**Documento fuente (emitido por Librarian):** +``` +doc:123 a prov:Entity . +doc:123 dc:title "Research Paper" . +doc:123 dc:source . +doc:123 dc:date "2024-01-15" . +doc:123 dc:creator "Author Name" . +doc:123 tg:pageCount 42 . +doc:123 tg:mimeType "application/pdf" . +``` + +**Página (emitida por el extractor de PDF):** +``` +page:123-1 a prov:Entity . +page:123-1 prov:wasDerivedFrom doc:123 . +page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 . +page:123-1 tg:pageNumber 1 . + +activity:pdf-extract-456 a prov:Activity . +activity:pdf-extract-456 prov:used doc:123 . +activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor . +activity:pdf-extract-456 tg:componentVersion "1.2.3" . +activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . +``` + +**Fragmento (emitido por el procesador de fragmentos):** +``` +chunk:123-1-1 a prov:Entity . +chunk:123-1-1 prov:wasDerivedFrom page:123-1 . +chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 . +chunk:123-1-1 tg:chunkIndex 1 . +chunk:123-1-1 tg:charOffset 0 . +chunk:123-1-1 tg:charLength 2048 . + +activity:chunk-789 a prov:Activity . +activity:chunk-789 prov:used page:123-1 . +activity:chunk-789 prov:wasAssociatedWith tg:Chunker . +activity:chunk-789 tg:componentVersion "1.0.0" . +activity:chunk-789 tg:chunkSize 2048 . +activity:chunk-789 tg:chunkOverlap 200 . +``` + +**Triple (emitido por el Extractor de Conocimiento):** +``` +# The extracted triple (edge) +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph containing the extracted triples +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 prov:wasGeneratedBy activity:extract-999 . + +activity:extract-999 a prov:Activity . +activity:extract-999 prov:used chunk:123-1-1 . +activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor . +activity:extract-999 tg:componentVersion "2.1.0" . +activity:extract-999 tg:llmModel "claude-3" . +activity:extract-999 tg:ontology . +``` + +**Incrustación (almacenada en un almacén de vectores, no en un almacén de triples):** + +Las incrustaciones se almacenan en el almacén de vectores con metadatos, no como triples RDF. Cada registro de incrustación contiene: + +| Campo | Descripción | Ejemplo | +|-------|-------------|---------| +| vector | El vector de incrustación | [0.123, -0.456, ...] | +| entity | URI del nodo que representa la incrustación | `entity:JohnSmith` | +| chunk_id | Fragmento de origen (procedencia) | `chunk:123-1-1` | +| model | Modelo de incrustación utilizado | `text-embedding-ada-002` | +| component_version | Versión del incrustador de TG | `1.0.0` | + +El campo `entity` vincula la incrustación al grafo de conocimiento (URI del nodo). El campo `chunk_id` proporciona la procedencia de vuelta al fragmento de origen, lo que permite el recorrido ascendente del DAG hasta el documento original. + +#### Extensiones del Espacio de Nombres de TrustGraph + +Predicados personalizados dentro del espacio de nombres `tg:` para metadatos específicos de la extracción: + +| Predicado | Dominio | Descripción | +|-----------|--------|-------------| +| `tg:contains` | Subgrafo | Indica un triple contenido en este subgrafo de extracción | +| `tg:pageCount` | Documento | Número total de páginas en el documento de origen | +| `tg:mimeType` | Documento | Tipo MIME del documento de origen | +| `tg:pageNumber` | Página | Número de página en el documento de origen | +| `tg:chunkIndex` | Fragmento | Índice del fragmento dentro del fragmento principal | +| `tg:charOffset` | Fragmento | Desplazamiento de caracteres en el texto principal | +| `tg:charLength` | Fragmento | Longitud del fragmento en caracteres | +| `tg:chunkSize` | Actividad | Tamaño de fragmento configurado | +| `tg:chunkOverlap` | Actividad | Solapamiento configurado entre fragmentos | +| `tg:componentVersion` | Actividad | Versión del componente de TG | +| `tg:llmModel` | Actividad | LLM utilizado para la extracción | +| `tg:ontology` | Actividad | URI de la ontología utilizada para guiar la extracción | +| `tg:embeddingModel` | Actividad | Modelo utilizado para las incrustaciones | +| `tg:sourceText` | Declaración | Texto exacto del cual se extrajo un triple | +| `tg:sourceCharOffset` | Declaración | Desplazamiento de caracteres dentro del fragmento donde comienza el texto de origen | +| `tg:sourceCharLength` | Declaración | Longitud del texto de origen en caracteres | + +#### Inicialización del Vocabulario (Por Colección) + +El grafo de conocimiento es neutral con respecto a la ontología y se inicializa vacío. Cuando se escriben datos de procedencia PROV-O en una colección por primera vez, el vocabulario debe inicializarse con etiquetas RDF para todas las clases y predicados. Esto garantiza una visualización legible por humanos en las consultas y la interfaz de usuario. + +**Clases PROV-O:** +``` +prov:Entity rdfs:label "Entity" . +prov:Activity rdfs:label "Activity" . +prov:Agent rdfs:label "Agent" . +``` + +**Predicados PROV-O:** +``` +prov:wasDerivedFrom rdfs:label "was derived from" . +prov:wasGeneratedBy rdfs:label "was generated by" . +prov:used rdfs:label "used" . +prov:wasAssociatedWith rdfs:label "was associated with" . +prov:startedAtTime rdfs:label "started at" . +``` + +**Predicados de TrustGraph:** +``` +tg:contains rdfs:label "contains" . +tg:pageCount rdfs:label "page count" . +tg:mimeType rdfs:label "MIME type" . +tg:pageNumber rdfs:label "page number" . +tg:chunkIndex rdfs:label "chunk index" . +tg:charOffset rdfs:label "character offset" . +tg:charLength rdfs:label "character length" . +tg:chunkSize rdfs:label "chunk size" . +tg:chunkOverlap rdfs:label "chunk overlap" . +tg:componentVersion rdfs:label "component version" . +tg:llmModel rdfs:label "LLM model" . +tg:ontology rdfs:label "ontology" . +tg:embeddingModel rdfs:label "embedding model" . +tg:sourceText rdfs:label "source text" . +tg:sourceCharOffset rdfs:label "source character offset" . +tg:sourceCharLength rdfs:label "source character length" . +``` + +**Nota de implementación:** Este vocabulario de inicio debe ser idempotente, es decir, seguro de ejecutar varias veces sin crear duplicados. Podría activarse durante el procesamiento inicial de un documento en una colección, o como un paso separado de inicialización de la colección. + +#### Origen de los Sub-Fragmentos (Aspiracional) + +Para un seguimiento de origen más detallado, sería valioso registrar exactamente dónde dentro de un fragmento se extrajo una tripleta. Esto permite: + +Resaltar el texto fuente exacto en la interfaz de usuario. +Verificar la precisión de la extracción en comparación con la fuente. +Depurar la calidad de la extracción a nivel de oración. + +**Ejemplo con seguimiento de posición:** +``` +# The extracted triple +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph with sub-chunk provenance +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +subgraph:001 tg:sourceCharOffset 1547 . +subgraph:001 tg:sourceCharLength 46 . +``` + +**Ejemplo con rango de texto (alternativa):** +``` +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceRange "1547-1593" . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +``` + +**Consideraciones de implementación:** + +La extracción basada en LLM puede no proporcionar naturalmente las posiciones de los caracteres. +Se podría solicitar al LLM que devuelva la oración/frase original junto con las triples extraídas. +Alternativamente, se puede realizar un procesamiento posterior para hacer coincidir de forma difusa las entidades extraídas con el texto fuente. +Compromiso entre la complejidad de la extracción y la granularidad de la procedencia. +Puede ser más fácil de lograr con métodos de extracción estructurados que con la extracción de LLM de formato libre. + +Esto se considera una meta a largo plazo; primero se debe implementar la procedencia a nivel de fragmento, y el seguimiento de subfragmentos puede ser una mejora futura si es factible. + +### Modelo de almacenamiento dual + +El DAG de procedencia se construye progresivamente a medida que los documentos fluyen a través de la canalización: + +| Almacén | ¿Qué se almacena | Propósito | +|-------|---------------|---------| +| Bibliotecario | Contenido del documento + enlaces padre-hijo | Recuperación de contenido, eliminación en cascada | +| Gráfico de conocimiento | Bordes padre-hijo + metadatos | Consultas de procedencia, atribución de hechos | + +Ambos almacenes mantienen la misma estructura DAG. El bibliotecario almacena el contenido; el gráfico almacena las relaciones y permite las consultas de recorrido. + +### Principios de diseño clave + +1. **El ID del documento como unidad de flujo**: Los procesadores pasan ID, no contenido. El contenido se recupera del bibliotecario cuando es necesario. + +2. **Emitir una vez en la fuente**: Los metadatos se escriben en el gráfico una vez al inicio del procesamiento, no se repiten en procesos posteriores. + +3. **Patrón de procesador consistente**: Cada procesador sigue el mismo patrón de recepción/recuperación/producción/guardado/emisión/reenvío. + +4. **Construcción progresiva del DAG**: Cada procesador agrega su nivel al DAG. La cadena completa de procedencia se construye de forma incremental. + +5. **Optimización posterior al fragmentador**: Después de la fragmentación, los mensajes contienen tanto el ID como el contenido. Los fragmentos son pequeños (2-4 KB), por lo que incluir el contenido evita viajes de ida y vuelta innecesarios al bibliotecario, al tiempo que preserva la procedencia a través del ID. + +## Tareas de implementación + +### Cambios en el bibliotecario + +#### Estado actual + +Inicia el procesamiento de documentos enviando el ID del documento al primer procesador. +No tiene conexión con el almacén de triples; los metadatos se incluyen en los resultados de la extracción. +`add-child-document` crea enlaces padre-hijo de un solo nivel. +`list-children` devuelve solo los hijos inmediatos. + +#### Cambios requeridos + +**1. Nueva interfaz: Conexión al almacén de triples** + +El bibliotecario debe emitir directamente los bordes de metadatos del documento al gráfico de conocimiento al iniciar el procesamiento. +Agregar un cliente/publicador del almacén de triples al servicio del bibliotecario. +Al iniciar el procesamiento: emitir los metadatos del documento raíz como bordes del gráfico (una vez). + +**2. Vocabulario de tipos de documentos** + +Estandarizar los valores de `document_type` para los documentos hijo: +`source` - documento original cargado. +`page` - página extraída de la fuente (PDF, etc.). +`chunk` - fragmento de texto derivado de la página o la fuente. + +#### Resumen de cambios de interfaz + +| Interfaz | Cambio | +|-----------|--------| +| Almacén de triples | Nueva conexión de salida: emitir bordes de metadatos del documento | +| Inicio del procesamiento | Emitir metadatos al gráfico antes de reenviar el ID del documento | + +### Cambios en el extractor de PDF + +#### Estado actual + +Recibe el contenido del documento (o transmite documentos grandes). +Extrae texto de las páginas PDF. +Envía el contenido de la página al fragmentador. +No interactúa con el bibliotecario ni con el almacén de triples. + +#### Cambios requeridos + +**1. Nueva interfaz: Cliente del bibliotecario** + +El extractor de PDF debe guardar cada página como un documento hijo en el bibliotecario. +Agregar un cliente del bibliotecario al servicio del extractor de PDF. +Para cada página: llamar a `add-child-document` con padre = ID del documento raíz. + +**2. Nueva interfaz: Conexión al almacén de triples** + +El extractor de PDF debe emitir bordes padre-hijo al gráfico de conocimiento. +Agregar un cliente/publicador del almacén de triples. +Para cada página: emitir un borde que vincule el documento de la página con el documento padre. + +**3. Cambiar el formato de salida** + +En lugar de reenviar el contenido de la página directamente, reenvíe el ID del documento de la página. +El componente "Chunker" recuperará el contenido del "librarian" utilizando el ID. + +#### Resumen de Cambios en la Interfaz + +| Interfaz | Cambio | +|-----------|--------| +| Librarian | Nueva salida: guardar documentos hijos | +| Triple store | Nueva salida: emitir aristas padre-hijo | +| Mensaje de salida | Cambio de contenido a ID de documento | + +### Cambios en el Componente "Chunker" + +#### Estado Actual + +Recibe contenido de página/texto +Lo divide en fragmentos +Reenvía el contenido del fragmento a los procesadores posteriores +No interactúa con el "librarian" ni con el "triple store" + +#### Cambios Requeridos + +**1. Cambiar el manejo de la entrada** + +Recibir el ID del documento en lugar del contenido, y recuperarlo del "librarian". +Agregar un cliente de "librarian" al servicio "chunker" +Recuperar el contenido de la página utilizando el ID del documento + +**2. Nueva interfaz: Cliente de "Librarian" (escritura)** + +Guardar cada fragmento como un documento hijo en el "librarian". +Para cada fragmento: llamar a `add-child-document` con parent = ID del documento de la página + +**3. Nueva interfaz: Conexión con el "Triple store"** + +Emitir aristas padre-hijo al grafo de conocimiento. +Agregar un cliente/publicador de "triple store" +Para cada fragmento: emitir una arista que vincule el documento del fragmento con el documento de la página + +**4. Cambiar el formato de salida** + +Reenviar tanto el ID del documento del fragmento como el contenido del fragmento (optimización posterior al componente "chunker"). +Los procesadores posteriores reciben el ID para la trazabilidad y el contenido para trabajar con él + +#### Resumen de Cambios en la Interfaz + +| Interfaz | Cambio | +|-----------|--------| +| Mensaje de entrada | Cambio de contenido a ID de documento | +| Librarian | Nueva salida (lectura + escritura) - recuperar contenido, guardar documentos hijos | +| Triple store | Nueva salida - emitir aristas padre-hijo | +| Mensaje de salida | Cambio de contenido-único a ID + contenido | + +### Cambios en el Extractor de Conocimiento + +#### Estado Actual + +Recibe contenido del fragmento +Extrae triples y embeddings +Los emite al "triple store" y al almacén de "embeddings" +La relación `subjectOf` apunta al documento de nivel superior (no al fragmento) + +#### Cambios Requeridos + +**1. Cambiar el manejo de la entrada** + +Recibir el ID del fragmento junto con el contenido. +Utilizar el ID del fragmento para la vinculación de trazabilidad (el contenido ya está incluido según la optimización) + +**2. Actualizar la trazabilidad de los triples** + +Vincular los triples extraídos al fragmento (no al documento de nivel superior). +Utilizar la reificación para crear una arista que apunte a la arista +Relación `subjectOf`: triple → ID del documento del fragmento +Primer uso del soporte de reificación existente + +**3. Actualizar la trazabilidad de los "embeddings"** + +Vincular los ID de las entidades de "embedding" al fragmento. +Emitir una arista: ID de la entidad de "embedding" → ID del documento del fragmento + +#### Resumen de Cambios en la Interfaz + +| Interfaz | Cambio | +|-----------|--------| +| Mensaje de entrada | Se espera el ID del fragmento + contenido (no solo contenido) | +| Triple store | Utilizar la reificación para la trazabilidad de triple → fragmento | +| Trazabilidad de "embeddings" | Vincular ID de entidad → ID de fragmento | + +## Referencias + +Trazabilidad en tiempo de consulta: `docs/tech-specs/query-time-provenance.md` +Estándar PROV-O para el modelado de trazabilidad +Metadatos de origen existentes en el grafo de conocimiento (necesitan auditoría) diff --git a/docs/tech-specs/extraction-time-provenance.he.md b/docs/tech-specs/extraction-time-provenance.he.md new file mode 100644 index 00000000..16937d51 --- /dev/null +++ b/docs/tech-specs/extraction-time-provenance.he.md @@ -0,0 +1,619 @@ +# מקור המידע בזמן החילוץ: שכבת המקור + +## סקירה כללית + +מסמך זה מתעד הערות על מקור המידע בזמן החילוץ לצורך עבודה עתידית על מפרטים. מקור המידע בזמן החילוץ מתעד את "שכבת המקור" - מאיפה הנתונים הגיעו במקור, וכיצד הם חולצו ועובדו. + +זה נפרד ממקור המידע בזמן השאילתה (ראה `query-time-provenance.md`) אשר מתעד את הנימוקים של המערכת. + +## הצהרת בעיה + +### יישום נוכחי + +כיום, מקור המידע פועל באופן הבא: +מטא-נתונים של מסמכים מאוחסנים כמשולשים RDF בגרף הידע. +מזהה מסמך מקשר בין מטא-נתונים למסמך, כך שהמסמך מופיע כצומת בגרף. +כאשר קשרים (יחסים/עובדות) מחולצים ממסמכים, קשר `subjectOf` מקשר את הקשר המחולץ בחזרה למסמך המקור. + +### בעיות בגישה הנוכחית + +1. **טעינת מטא-נתונים חוזרת:** מטא-נתונים של מסמכים מקובצים ונטענים שוב ושוב עם כל אצווה של משולשים המחולצים ממסמך זה. זה בזבוז ומיותר - אותם מטא-נתונים מועברים כחלק מהפלט בכל חילוץ. + +2. **מקור מידע שטחי:** הקשר `subjectOf` הנוכחי מקשר רק עובדות ישירות למסמך הראשי. אין נראות לגבי שרשרת השינויים - מאיזו עמוד הגיעה העובדה, מאיזה חלק, באיזו שיטת חילוץ נעשה שימוש. + +### מצב רצוי + +1. **טעינת מטא-נתונים פעם אחת:** מטא-נתונים של מסמכים צריכים להיטען פעם אחת ולהיות מחוברים לצומת המסמך הראשי, ולא לחזור על עצמם עם כל אצווה של משולשים. + +2. **גרף מקור מידע עשיר:** לתפוס את שרשרת השינויים המלאה ממסמך המקור דרך כל הארטיפקטים הביניים ועד לעובדות המחולצות. לדוגמה, טרנספורמציה של מסמך PDF: + + ``` + PDF file (source document with metadata) + → Page 1 (decoded text) + → Chunk 1 + → Extracted edge/fact (via subjectOf) + → Extracted edge/fact + → Chunk 2 + → Extracted edge/fact + → Page 2 + → Chunk 3 + → ... + ``` + +3. **אחסון מאוחד:** גרף המוצא (provenance DAG) מאוחסן באותו גרף ידע כמו הידע שחולץ. זה מאפשר שאילתת מוצא באותה צורה כמו שאילתת ידע - מעקב אחר קשרים לאחור בשרשרת מכל עובדה למיקום המקור המדויק שלה. + +4. **מזהים יציבים:** לכל ארטיפקט ביניים (עמוד, מקטע) יש מזהה יציב כצומת בגרף. + +5. **קישור הורה-ילד:** מסמכים נגזרים מקושרים להוריהם עד למסמך המקור העליון באמצעות סוגי קשרים עקביים. + +6. **הקצאת עובדות מדויקת:** הקשר `subjectOf` בקשרים שחולצו מצביע על ההורה המיידי (מקטע), ולא על מסמך המקור העליון. ניתן לשחזר את כל המוצא על ידי מעבר ב-DAG. + +## תרחישי שימוש + +### UC1: הקצאת מקור בתגובות GraphRAG + +**תרחיש:** משתמש מריץ שאילתה של GraphRAG ומקבל תגובה מהסוכן. + +**תהליך:** +1. משתמש מגיש שאילתה לסוכן GraphRAG. +2. הסוכן שולף עובדות רלוונטיות מגרף הידע כדי לנסח תגובה. +3. בהתאם למפרט המוצא בזמן השאילתה, הסוכן מדווח אילו עובדות תרמו לתגובה. +4. כל עובדה מקושרת למקטע המקור שלה באמצעות גרף המוצא. +5. מקטעים מקושרים לעמודים, עמודים מקושרים למסמכי מקור. + +**תוצאה עבור המשתמש:** הממשק מציג את תגובת מודל השפה הגדול (LLM) יחד עם הקצאת מקור. המשתמש יכול: +לראות אילו עובדות תמכו בתגובה. +לעבור ממקטעים → עמודים → מסמכים. +לעיין במסמכי המקור המקוריים כדי לאמת טענות. +להבין בדיוק מאיפה במסמך (איזה עמוד, איזה חלק) עובדה מסוימת הגיעה. + +**ערך:** משתמשים יכולים לאמת תגובות שנוצרו על ידי AI מול מקורות ראשוניים, ובכך לבנות אמון ולאפשר בדיקת עובדות. + +### UC2: ניפוי באגים של איכות חילוץ + +עובדה נראית שגויה. ניתן לעקוב אחורה דרך מקטע → עמוד → מסמך כדי לראות את הטקסט המקורי. האם זו הייתה שגיאת חילוץ, או שהמקור עצמו היה שגוי? + +### UC3: חילוץ חוזר מצטבר + +מסמך מקור מתעדכן. אילו מקטעים/עובדות נגזרו ממנו? לבטל ולחדש רק את אלה, ולא לעבד הכל מחדש. + +### UC4: מחיקת נתונים / הזכות להיות נשכח + +יש להסיר מסמך מקור (GDPR, סיבות משפטיות וכו'). יש לעבור ב-DAG כדי למצוא ולהסיר את כל העובדות הנגזרות. + +### UC5: פתרון קונפליקטים + +שתי עובדות סותרות אחת את השנייה. ניתן לעקוב אחורה לשני המקורות שלהן כדי להבין מדוע ולהחליט איזו עובדה לתת לה עדיפות (מקור סמכותי יותר, עדכני יותר וכו'). + +### UC6: שקלול סמכות מקור + +למקורות מסוימים יש סמכות רבה יותר מאחרים. ניתן לשקלל או לסנן עובדות בהתאם לסמכות/איכות מסמכי המקור שלהן. + +### UC7: השוואת צינורות חילוץ + +השוואת תוצאות משיטות/גרסאות חילוץ שונות. איזה מחלץ הפיק עובדות טובות יותר מאותו מקור? + +## נקודות אינטגרציה + +### ספרן + +רכיב הספרן כבר מספק אחסון מסמכים עם מזהי מסמכים ייחודיים. מערכת המקור משתלבת בתשתית הקיימת. + +#### יכולות קיימות (שיושמו כבר) + +**קישור מסמכים הורה-ילד:** +`parent_id` שדה ב-`DocumentMetadata` - מקשר מסמך ילד למסמך הורה +`document_type` שדה - ערכים: `"source"` (מקור) או `"extracted"` (נגזר) +`add-child-document` API - יוצר מסמך ילד עם `document_type = "extracted"` אוטומטי +`list-children` API - שולף את כל ילדי מסמך הורה +מחיקה מדורגת - הסרת מסמך הורה מוחקת אוטומטית את כל מסמכי הילד + +**זיהוי מסמכים:** +מזהי מסמכים מוגדרים על ידי הלקוח (לא נוצרים אוטומטית) +מסמכים מאוחסנים לפי מפתח מורכב `(user, document_id)` ב-Cassandra +מזהי אובייקטים (UUIDs) נוצרים באופן פנימי עבור אחסון בלובים + +**תמיכה במטא-נתונים:** +`metadata: list[Triple]` שדה - משולשים RDF עבור מטא-נתונים מובנים +`title`, `comments`, `tags` - מטא-נתונים בסיסיים של מסמך +`time` - חותמת זמן, `kind` - סוג MIME + +**ארכיטקטורת אחסון:** +מטא-נתונים מאוחסנים ב-Cassandra (מרחב מפתחות `librarian`, טבלה `document`) +תוכן מאוחסן ב-MinIO/S3 blob storage (דלי `library`) +העברת תוכן חכמה: מסמכים קטנים מ-2MB משובצים, מסמכים גדולים יותר מועברים + +#### קבצים מרכזיים + +`trustgraph-flow/trustgraph/librarian/librarian.py` - פעולות ליבה של הספרן +`trustgraph-flow/trustgraph/librarian/service.py` - מעבד שירות, טעינת מסמכים +`trustgraph-flow/trustgraph/tables/library.py` - חנות טבלאות Cassandra +`trustgraph-base/trustgraph/schema/services/library.py` - הגדרות סכימה + +#### פערים לטיפול + +ל-ספרן יש את אבני הבניין, אך כרגע: +1. קישור הורה-ילד הוא בעומק של רמה אחת - אין עזרי מעבר DAG מרובי רמות +2. אין אוצר מילים סטנדרטי לסוגי יחסים (לדוגמה, `derivedFrom`, `extractedFrom`) +3. מטא-נתונים של מקור (שיטת חילוץ, רמת אמון, מיקום מקטע) אינם סטנדרטיים +4. אין API שאילתה למעבר על שרשרת המקור המלאה מעובדה חזרה למקור + +## תכנון זרימת עבודה מקצה לקצה + +כל מעבד בצינור עוקב אחר דפוס עקבי: +מקבל מזהה מסמך מהשורה העליונה +שולף תוכן מהספרן +מייצר ארטיפקטים ילדים +עבור כל ילד: שומר בספרן, פולט קצה לגרף, מעביר מזהה לשורה התחתונה + +### זרימות עיבוד + +ישנן שתי זרימות בהתאם לסוג המסמך: + +#### זרימת מסמכי PDF + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID to PDF extractor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ PDF Extractor (per page) │ +│ 1. Fetch PDF content from librarian using document ID │ +│ 2. Extract pages as text │ +│ 3. For each page: │ +│ a. Save page as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send page document ID to chunker │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch page content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = page) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + Post-chunker optimization: messages carry both + chunk ID (for provenance) and content (to avoid + librarian round-trip). Chunks are small (2-4KB). + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor (per chunk) │ +│ 1. Receive chunk ID + content directly (no librarian fetch needed) │ +│ 2. Extract facts/triples and embeddings from chunk content │ +│ 3. For each triple: │ +│ a. Emit triple to knowledge graph │ +│ b. Emit reified edge linking triple → chunk ID (edge pointing │ +│ to edge - first use of reification support) │ +│ 4. For each embedding: │ +│ a. Emit embedding with its entity ID │ +│ b. Link entity ID → chunk ID in knowledge graph │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +#### זרימת מסמכי טקסט + +מסמכי טקסט עוקפים את מודל החילוץ של PDF ועוברים ישירות למקטע: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID directly to chunker (skip PDF extractor) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch text content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor │ +│ (same as PDF flow) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +הגרף המכוון (DAG) המתקבל הוא ברמה אחת קצרה יותר: + +``` +PDF: Document → Pages → Chunks → Triples/Embeddings +Text: Document → Chunks → Triples/Embeddings +``` + +העיצוב מתאים לשני המקרים מכיוון שהמקטע (chunker) מטפל בקלט שלו באופן כללי - הוא משתמש בכל מזהה מסמך שהוא מקבל כאב, ללא קשר לשאלה האם מדובר במסמך מקור או בעמוד. + +### סכימת מטא-נתונים (PROV-O) + +מטא-נתונים של מקור (Provenance) משתמשים באונטולוגיה W3C PROV-O. זה מספק אוצר מילים סטנדרטי ומאפשר חתימה/אימות עתידי של תוצרי חילוץ. + +#### מושגים מרכזיים ב-PROV-O + +| סוג PROV-O | שימוש ב-TrustGraph | +|-------------|------------------| +| `prov:Entity` | מסמך, עמוד, מקטע, טריפל, הטמעה | +| `prov:Activity` | מופעים של פעולות חילוץ | +| `prov:Agent` | רכיבי TG (תוכנת חילוץ PDF, מקטע, וכו') עם גרסאות | + +#### קשרים ב-PROV-O + +| פרידיקט | משמעות | דוגמה | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | ישות שמקורה בישות אחרת | עמוד היה-מבוסס-על מסמך | +| `prov:wasGeneratedBy` | ישות שנוצרה על ידי פעילות | עמוד נוצר-על-ידי פעולת חילוץ PDF | +| `prov:used` | פעילות השתמשה בישות כקלט | פעולת חילוץ PDF השתמשה במסמך | +| `prov:wasAssociatedWith` | פעילות בוצעה על ידי סוכן | פעולת חילוץ PDF הייתה-קשורה ל-tg:PDFExtractor | + +#### מטא-נתונים בכל רמה + +**מסמך מקור (נפלט על ידי הספרן):** +``` +doc:123 a prov:Entity . +doc:123 dc:title "Research Paper" . +doc:123 dc:source . +doc:123 dc:date "2024-01-15" . +doc:123 dc:creator "Author Name" . +doc:123 tg:pageCount 42 . +doc:123 tg:mimeType "application/pdf" . +``` + +**עמוד (נפלט על ידי מופשט PDF):** +``` +page:123-1 a prov:Entity . +page:123-1 prov:wasDerivedFrom doc:123 . +page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 . +page:123-1 tg:pageNumber 1 . + +activity:pdf-extract-456 a prov:Activity . +activity:pdf-extract-456 prov:used doc:123 . +activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor . +activity:pdf-extract-456 tg:componentVersion "1.2.3" . +activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . +``` + +**חלק (נפלט על ידי מודול החלוקה):** +``` +chunk:123-1-1 a prov:Entity . +chunk:123-1-1 prov:wasDerivedFrom page:123-1 . +chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 . +chunk:123-1-1 tg:chunkIndex 1 . +chunk:123-1-1 tg:charOffset 0 . +chunk:123-1-1 tg:charLength 2048 . + +activity:chunk-789 a prov:Activity . +activity:chunk-789 prov:used page:123-1 . +activity:chunk-789 prov:wasAssociatedWith tg:Chunker . +activity:chunk-789 tg:componentVersion "1.0.0" . +activity:chunk-789 tg:chunkSize 2048 . +activity:chunk-789 tg:chunkOverlap 200 . +``` + +**משולש (נפלט על ידי מפיק ידע):** +``` +# The extracted triple (edge) +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph containing the extracted triples +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 prov:wasGeneratedBy activity:extract-999 . + +activity:extract-999 a prov:Activity . +activity:extract-999 prov:used chunk:123-1-1 . +activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor . +activity:extract-999 tg:componentVersion "2.1.0" . +activity:extract-999 tg:llmModel "claude-3" . +activity:extract-999 tg:ontology . +``` + +**הטמעה (מאוחסנת במאגר וקטורים, ולא במאגר משולשות):** + +הטמעות מאוחסנות במאגר הווקטורים עם מטא-נתונים, ולא כמשולשות RDF. כל רשומה של הטמעה מכילה: + +| שדה | תיאור | דוגמה | +|-------|-------------|---------| +| וקטור | וקטור ההטמעה | [0.123, -0.456, ...] | +| ישות | מזהה צומת שההטמעה מייצגת | `entity:JohnSmith` | +| מזהה_קטע | קטע מקור (מקור) | `chunk:123-1-1` | +| מודל | מודל הטמעה ששימש | `text-embedding-ada-002` | +| גרסת_רכיב | גרסת הטמעת TG | `1.0.0` | + +השדה `entity` מקשר את ההטמעה לגרף הידע (מזהה צומת). השדה `chunk_id` מספק מידע על המקור חזרה לקטע המקור, ומאפשר מעבר במבנה ה-DAG אל המסמך המקורי. + +#### הרחבות מרחב השמות של TrustGraph + +פרדיקטים מותאמים אישית תחת מרחב השמות `tg:` עבור מטא-נתונים ספציפיים לחילוץ: + +| פרדיקט | תחום | תיאור | +|-----------|--------|-------------| +| `tg:contains` | תת-גרף | מצביע על משולש הכלול בתת-גרף החילוץ הזה | +| `tg:pageCount` | מסמך | מספר כולל של עמודים במסמך המקור | +| `tg:mimeType` | מסמך | סוג MIME של המסמך המקור | +| `tg:pageNumber` | עמוד | מספר עמוד במסמך המקור | +| `tg:chunkIndex` | קטע | אינדקס של קטע בתוך הורה | +| `tg:charOffset` | קטע | התאמה אופסט בטקסט הורה | +| `tg:charLength` | קטע | אורך הקטע בתווים | +| `tg:chunkSize` | פעילות | גודל קטע מוגדר | +| `tg:chunkOverlap` | פעילות | חפיפה מוגדרת בין קטעים | +| `tg:componentVersion` | פעילות | גרסת רכיב TG | +| `tg:llmModel` | פעילות | מודל LLM ששימש לחילוץ | +| `tg:ontology` | פעילות | אונטולוגיה ששימשה להכוונת החילוץ | +| `tg:embeddingModel` | פעילות | מודל ששימש להטמעות | +| `tg:sourceText` | הצהרה | הטקסט המדויק ממנו חולצה משולשת | +| `tg:sourceCharOffset` | הצהרה | התאמה אופסט בתוך קטע שבו מתחיל הטקסט המקור | +| `tg:sourceCharLength` | הצהרה | אורך הטקסט המקור בתווים | + +#### אתחול אוצר מילים (לכל אוסף) + +גרף הידע הוא ניטרלי אוטולוגי ומתחיל ריק. בעת כתיבת נתוני provenance של PROV-O לאוסף בפעם הראשונה, יש לאתחל את אוצר המילים עם תגיות RDF עבור כל מחלקות ופרדיקטים. זה מבטיח תצוגה קריאה על ידי בני אדם בשאילתות ובממשק המשתמש. + +**מחלקות PROV-O:** +``` +prov:Entity rdfs:label "Entity" . +prov:Activity rdfs:label "Activity" . +prov:Agent rdfs:label "Agent" . +``` + +**נשואים של PROV-O:** +``` +prov:wasDerivedFrom rdfs:label "was derived from" . +prov:wasGeneratedBy rdfs:label "was generated by" . +prov:used rdfs:label "used" . +prov:wasAssociatedWith rdfs:label "was associated with" . +prov:startedAtTime rdfs:label "started at" . +``` + +**משפטי TrustGraph:** +``` +tg:contains rdfs:label "contains" . +tg:pageCount rdfs:label "page count" . +tg:mimeType rdfs:label "MIME type" . +tg:pageNumber rdfs:label "page number" . +tg:chunkIndex rdfs:label "chunk index" . +tg:charOffset rdfs:label "character offset" . +tg:charLength rdfs:label "character length" . +tg:chunkSize rdfs:label "chunk size" . +tg:chunkOverlap rdfs:label "chunk overlap" . +tg:componentVersion rdfs:label "component version" . +tg:llmModel rdfs:label "LLM model" . +tg:ontology rdfs:label "ontology" . +tg:embeddingModel rdfs:label "embedding model" . +tg:sourceText rdfs:label "source text" . +tg:sourceCharOffset rdfs:label "source character offset" . +tg:sourceCharLength rdfs:label "source character length" . +``` + +**הערה בנושא יישום:** אוצר המילים הזה צריך להיות בעל תכונה של אידמפוטנטיות - בטוח להפעיל אותו מספר פעמים מבלי ליצור כפילויות. ניתן להפעיל אותו בפעם הראשונה בעיבוד מסמך באוסף, או כשלב נפרד של אתחול אוסף. + +#### מקור של חלקים קטנים (שאפתני) + +לצורך מעקב מקור מדויק יותר, יהיה שימושי לתעד בדיוק מאיפה בתוך חלק קטן נשלפה טריפלט. זה מאפשר: + +הדגשת הטקסט המדויק ממנו נשלף הטריפלט בממשק המשתמש +אימות דיוק החילוץ מול המקור +ניפוי באגים באיכות החילוץ ברמת המשפט + +**דוגמה עם מעקב מיקום:** +``` +# The extracted triple +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph with sub-chunk provenance +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +subgraph:001 tg:sourceCharOffset 1547 . +subgraph:001 tg:sourceCharLength 46 . +``` + +**דוגמה עם טווח טקסט (חלופה):** +``` +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceRange "1547-1593" . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +``` + +**שיקולי יישום:** + +חילוץ מבוסס מודל שפה גדול (LLM) עשוי שלא לספק באופן טבעי מיקומי תווים. +ניתן לבקש מה-LLM להחזיר את המשפט/הביטוי המקורי יחד עם הטריפלים החילוצים. +לחלופין, ניתן לבצע עיבוד לאחר החילוץ כדי להתאים את הישויות החילוצות בחזרה לטקסט המקור. +איזון בין מורכבות החילוץ ובין רמת הפירוט של מקור המידע. +ייתכן שיהיה קל יותר להשיג זאת באמצעות שיטות חילוץ מובנות מאשר חילוץ חופשי מבוסס LLM. + +זה מסומן כשאיפה - יש ליישם תחילה את מקור המידע ברמת החלקים, כאשר מעקב אחר תת-חלקים הוא שיפור עתידי אם אפשרי. + +### מודל אחסון כפול + +גרף מקור המידע נבנה בהדרגה ככל שהמסמכים עוברים דרך הצינור: + +| אחסון | מה מאוחסן | מטרה | +|-------|---------------|---------| +| ספרן (Librarian) | תוכן מסמך + קישורים הורה-ילד | אחזור תוכן, מחיקה מדורגת | +| גרף ידע (Knowledge Graph) | קצוות הורה-ילד + מטא-נתונים | שאילתות מקור מידע, ייחוס עובדות | + +שני האחסונים שומרים על מבנה גרף זהה. הספרן שומר על התוכן; הגרף שומר על קשרים ומאפשר שאילתות מעבר. + +### עקרונות עיצוב מרכזיים + +1. **מזהה מסמך כיחידת זרימה** - מעבדים מעבירים מזהים, לא תוכן. התוכן נשאב מהספרן בעת הצורך. + +2. **פליטה חד-פעמית במקור** - מטא-נתונים נכתבים לגרף פעם אחת בתחילת העיבוד, ולא חוזרים על עצמם במעלה הצינור. + +3. **תבנית מעבד עקבית** - כל מעבד פועל לפי אותה תבנית של קבלה/שאילתא/יצירה/שמירה/פליטה/העברה. + +4. **בניית גרף הדרגתית** - כל מעבד מוסיף את השכבה שלו לגרף. שרשרת מקור המידע השלמה נבנית בהדרגה. + +5. **אופטימיזציה לאחר חלוקה לחלקים** - לאחר חלוקה לחלקים, הודעות נושאות גם מזהה וגם תוכן. החלקים קטנים (2-4KB), כך שכלול התוכן מונע מעברים מיותרים לספרן תוך שמירה על מקור המידע באמצעות המזהה. + +## משימות יישום + +### שינויים בספרן + +#### מצב נוכחי + +מתחיל עיבוד מסמכים על ידי שליחת מזהה מסמך למעבד הראשון. +אין חיבור למאגר טריפלים - מטא-נתונים נכללים בפלט החילוץ. +`add-child-document` יוצר קישורים הורה-ילד ברמה אחת. +`list-children` מחזיר רק ילדים מיידיים. + +#### שינויים נדרשים + +**1. ממשק חדש: חיבור למאגר טריפלים** + +הספרן צריך לפלוט קצוות מטא-נתונים של מסמכים ישירות לגרף הידע בעת התחלת העיבוד. +הוספת לקוח/מפרסם של מאגר טריפלים לשירות הספרן. +בעת התחלת עיבוד: פליטת מטא-נתונים של מסמך השורש כקצוות גרף (פעם אחת). + +**2. אוצר מילים של סוגי מסמכים** + +סטנדרטיזציה של ערכים `document_type` עבור מסמכי ילד: +`source` - מסמך שהועלה במקור. +`page` - עמוד שחולץ מהמקור (PDF, וכו'). +`chunk` - חלק טקסט שמקורו בעמוד או במקור. + +#### סיכום שינויים בממשק + +| ממשק | שינוי | +|-----------|--------| +| מאגר טריפלים | חיבור יוצא חד - פליטת קצוות מטא-נתונים של מסמכים | +| התחלת עיבוד | פליטת מטא-נתונים לגרף לפני העברת מזהה מסמך | + +### שינויים בחולץ PDF + +#### מצב נוכחי + +מקבל תוכן מסמך (או זורם מסמכים גדולים). +מחלץ טקסט מעמודי PDF. +מעביר תוכן עמוד לחולץ חלקים. +אין אינטראקציה עם הספרן או מאגר הטריפלים. + +#### שינויים נדרשים + +**1. ממשק חדש: לקוח ספרן** + +חולץ PDF צריך לשמור כל עמוד כמסמך ילד בספרן. +הוספת לקוח ספרן לשירות חולץ PDF. +עבור כל עמוד: קריאה ל-`add-child-document` עם מזהה הורה = מזהה מסמך השורש. + +**2. ממשק חדש: חיבור למאגר טריפלים** + +חולץ PDF צריך לפלוט קצוות הורה-ילד לגרף הידע. +הוספת לקוח/מפרסם של מאגר טריפלים. +עבור כל עמוד: פליטת קצה המקשר עמוד מסמך למסמך הורה. + +**3. שינוי פורמט פלט** +פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא). +במקום להעביר ישירות את תוכן העמוד, יש להעביר את מזהה המסמך של העמוד. +ה-Chunker ישלוף את התוכן מה-librarian באמצעות המזהה. + +#### סיכום שינויים בממשק + +| ממשק | שינוי | +|-----------|--------| +| Librarian | יציאה חדשה - שמירת מסמכים ילדים | +| Triple store | יציאה חדשה - פליטת קשרים הורה-ילד | +| הודעת פלט | שינוי מתוכן למזהה מסמך | + +### שינויים ב-Chunker + +#### מצב נוכחי + +מקבל תוכן עמוד/טקסט +מחלק לחלקים +מעביר את תוכן החלק למעבדים downstream +אין אינטראקציה עם ה-librarian או ה-triple store + +#### שינויים נדרשים + +**1. שינוי טיפול בקלט** + +לקבל מזהה מסמך במקום תוכן, לשלוף מה-librarian. +להוסיף לקוח librarian לשירות ה-chunker +לשלוף תוכן עמוד באמצעות מזהה מסמך + +**2. ממשק חדש: לקוח Librarian (כתיבה)** + +לשמור כל חלק כמסמך ילד ב-librarian. +עבור כל חלק: לקרוא לפונקציה `add-child-document` עם parent = מזהה מסמך העמוד + +**3. ממשק חדש: חיבור ל-Triple store** + +לפלוט קשרים הורה-ילד לגרף הידע. +להוסיף לקוח/מפרסם triple store +עבור כל חלק: לפלוט קשר המקשר בין מסמך החלק למסמך העמוד + +**4. שינוי פורמט פלט** + +להעביר גם את מזהה מסמך החלק וגם את תוכן החלק (אופטימיזציה לאחר ה-chunker). +מעבדים downstream מקבלים מזהה לצורך מעקב מקור + תוכן לעבודה איתו + +#### סיכום שינויים בממשק + +| ממשק | שינוי | +|-----------|--------| +| הודעת קלט | שינוי מתוכן למזהה מסמך | +| Librarian | יציאה חדשה (קריאה + כתיבה) - שליפת תוכן, שמירת מסמכים ילדים | +| Triple store | יציאה חדשה - פליטת קשרים הורה-ילד | +| הודעת פלט | שינוי מתוכן בלבד ל-ID + תוכן | + +### שינויים ב-Knowledge Extractor + +#### מצב נוכחי + +מקבל תוכן חלק +מחלץ טריפל ו-embeddings +פולט ל-triple store ול-embedding store +`subjectOf` הקשר מצביע למסמך ברמה העליונה (ולא לחלק) + +#### שינויים נדרשים + +**1. שינוי טיפול בקלט** + +לקבל מזהה מסמך חלק יחד עם התוכן. +להשתמש במזהה החלק לצורך קישור מעקב מקור (תוכן כלול כבר בהתאם לאופטימיזציה) + +**2. עדכון מעקב טריפל** + +לקשר טריפל מחולץ לחלק (ולא למסמך ברמה העליונה). +להשתמש ב-reification ליצירת קשר המצביע לקשר +`subjectOf` הקשר: טריפל → מזהה מסמך חלק +שימוש ראשון בתמיכה קיימת ב-reification + +**3. עדכון מעקב embedding** + +לקשר מזהי ישויות embedding לחלק. +לפלוט קשר: מזהה ישות embedding → מזהה מסמך חלק + +#### סיכום שינויים בממשק + +| ממשק | שינוי | +|-----------|--------| +| הודעת קלט | מצפים למזהה חלק + תוכן (ולא רק תוכן) | +| Triple store | להשתמש ב-reification למעקב טריפל → חלק | +| מעקב embedding | לקשר מזהה ישות → מזהה חלק | + +## הפניות + +מעקב בזמן שאילתה: `docs/tech-specs/query-time-provenance.md` +תקן PROV-O למודל מעקב מקור +מטא-נתונים קיימים ממקור בגרף הידע (דורש ביקורת) diff --git a/docs/tech-specs/extraction-time-provenance.hi.md b/docs/tech-specs/extraction-time-provenance.hi.md new file mode 100644 index 00000000..7b1ddbe9 --- /dev/null +++ b/docs/tech-specs/extraction-time-provenance.hi.md @@ -0,0 +1,619 @@ +# निष्कर्षण-समय का प्रमाण: स्रोत परत + +## अवलोकन + +यह दस्तावेज़ भविष्य के विनिर्देशन कार्य के लिए निष्कर्षण-समय के प्रमाण पर नोट्स एकत्र करता है। निष्कर्षण-समय का प्रमाण "स्रोत परत" को रिकॉर्ड करता है - डेटा मूल रूप से कहाँ से आया, इसे कैसे निकाला और रूपांतरित किया गया। + +यह क्वेरी-समय के प्रमाण (देखें `query-time-provenance.md`) से अलग है, जो एजेंट तर्क को रिकॉर्ड करता है। + +## समस्या विवरण + +### वर्तमान कार्यान्वयन + +वर्तमान में, प्रमाण इस प्रकार काम करता है: +दस्तावेज़ मेटाडेटा को ज्ञान ग्राफ में RDF ट्रिपल के रूप में संग्रहीत किया जाता है +एक दस्तावेज़ आईडी मेटाडेटा को दस्तावेज़ से जोड़ती है, इसलिए दस्तावेज़ ग्राफ में एक नोड के रूप में दिखाई देता है +जब दस्तावेज़ों से किनारे (संबंध/तथ्य) निकाले जाते हैं, तो एक `subjectOf` संबंध निकाले गए किनारे को स्रोत दस्तावेज़ से जोड़ता है + +### वर्तमान दृष्टिकोण की समस्याएं + +1. **दोहरा मेटाडेटा लोडिंग:** दस्तावेज़ मेटाडेटा को प्रत्येक दस्तावेज़ से निकाले गए ट्रिपल बैच के साथ बार-बार बंडल किया जाता है और लोड किया जाता है। यह अनावश्यक और दोहराव वाला है - समान मेटाडेटा प्रत्येक निष्कर्षण आउटपुट के साथ पेलोड के रूप में यात्रा करता है। + +2. **उथला प्रमाण:** वर्तमान `subjectOf` संबंध केवल तथ्यों को सीधे शीर्ष-स्तरीय दस्तावेज़ से जोड़ता है। परिवर्तन श्रृंखला में कोई दृश्यता नहीं है - तथ्य किस पृष्ठ से आया, किस भाग से, किस निष्कर्षण विधि का उपयोग किया गया था। + +### वांछित स्थिति + +1. **मेटाडेटा को एक बार लोड करें:** दस्तावेज़ मेटाडेटा को एक बार लोड किया जाना चाहिए और शीर्ष-स्तरीय दस्तावेज़ नोड से जोड़ा जाना चाहिए, न कि प्रत्येक ट्रिपल बैच के साथ दोहराया जाना चाहिए। + +2. **समृद्ध प्रमाण DAG:** स्रोत दस्तावेज़ से सभी मध्यवर्ती कलाकृतियों से लेकर निकाले गए तथ्यों तक, संपूर्ण परिवर्तन श्रृंखला को कैप्चर करें। उदाहरण के लिए, एक PDF दस्तावेज़ रूपांतरण: + + ``` + PDF file (source document with metadata) + → Page 1 (decoded text) + → Chunk 1 + → Extracted edge/fact (via subjectOf) + → Extracted edge/fact + → Chunk 2 + → Extracted edge/fact + → Page 2 + → Chunk 3 + → ... + ``` + +3. **एकीकृत भंडारण:** उत्पत्ति (provenance) DAG को उसी ज्ञान ग्राफ में संग्रहीत किया जाता है जैसे कि निकाले गए ज्ञान को। यह उत्पत्ति को ज्ञान की तरह ही क्वेरी करने की अनुमति देता है - किसी भी तथ्य से लेकर उसके सटीक स्रोत स्थान तक, श्रृंखला में किनारों का पालन करके। + +4. **स्थिर आईडी:** प्रत्येक मध्यवर्ती कलाकृति (पेज, चंक) का ग्राफ में एक नोड के रूप में एक स्थिर आईडी होता है। + +5. **पैरेंट-चाइल्ड लिंकिंग:** व्युत्पन्न दस्तावेज़ों को सुसंगत संबंध प्रकारों का उपयोग करके शीर्ष-स्तरीय स्रोत दस्तावेज़ तक उनके माता-पिता से जोड़ा जाता है। + +6. **सटीक तथ्यattribution:** निकाले गए किनारों पर `subjectOf` संबंध तत्काल माता-पिता (चंक) की ओर इशारा करता है, न कि शीर्ष-स्तरीय दस्तावेज़ की ओर। पूर्ण उत्पत्ति को DAG के माध्यम से ऊपर की ओर ट्रैवर्स करके पुनर्प्राप्त किया जाता है। + +## उपयोग के मामले + +### UC1: GraphRAG प्रतिक्रियाओं में स्रोत attribution + +**परिदृश्य:** एक उपयोगकर्ता GraphRAG क्वेरी चलाता है और एजेंट से एक प्रतिक्रिया प्राप्त करता है। + +**प्रवाह:** +1. उपयोगकर्ता GraphRAG एजेंट को एक क्वेरी सबमिट करता है +2. एजेंट प्रतिक्रिया तैयार करने के लिए ज्ञान ग्राफ से प्रासंगिक तथ्यों को पुनर्प्राप्त करता है +3. क्वेरी-टाइम provenance विनिर्देश के अनुसार, एजेंट उन तथ्यों की रिपोर्ट करता है जिन्होंने प्रतिक्रिया में योगदान दिया +4. प्रत्येक तथ्य provenance DAG के माध्यम से अपने स्रोत चंक से जुड़ा होता है +5. चंक पृष्ठों से जुड़ते हैं, पृष्ठ स्रोत दस्तावेज़ों से जुड़ते हैं + +**उपयोगकर्ता अनुभव परिणाम:** इंटरफ़ेस LLM प्रतिक्रिया के साथ स्रोत attribution प्रदर्शित करता है। उपयोगकर्ता: +प्रतिक्रिया का समर्थन करने वाले तथ्यों को देख सकते हैं +तथ्यों → चंक → पृष्ठ → दस्तावेज़ से ड्रिल डाउन कर सकते हैं +दावों को सत्यापित करने के लिए मूल स्रोत दस्तावेज़ों की समीक्षा कर सकते हैं +यह समझ सकते हैं कि एक तथ्य दस्तावेज़ में कहाँ से (किस पृष्ठ, किस अनुभाग से) उत्पन्न हुआ था + +**मूल्य:** उपयोगकर्ता AI-जनित प्रतिक्रियाओं को प्राथमिक स्रोतों के विरुद्ध सत्यापित कर सकते हैं, जिससे विश्वास बढ़ता है और तथ्य-जांच सक्षम होती है। + +### UC2: निष्कर्षण गुणवत्ता का डिबगिंग + +एक तथ्य गलत दिखता है। मूल पाठ देखने के लिए चंक → पृष्ठ → दस्तावेज़ के माध्यम से वापस ट्रेस करें। क्या यह एक खराब निष्कर्षण था, या क्या स्रोत स्वयं गलत था? + +### UC3: वृद्धिशील पुन: निष्कर्षण + +स्रोत दस्तावेज़ अपडेट किया गया है। किन चंक/तथ्यों को इससे व्युत्पन्न किया गया था? केवल उन चंक/तथ्यों को अमान्य करें और पुन: उत्पन्न करें, न कि सब कुछ को पुन: संसाधित करें। + +### UC4: डेटा हटाना / भुलाए जाने का अधिकार + +एक स्रोत दस्तावेज़ को हटाया जाना चाहिए (GDPR, कानूनी, आदि)। सभी व्युत्पन्न तथ्यों को खोजने और हटाने के लिए DAG को पार करें। + +### UC5: संघर्ष समाधान + +दो तथ्य एक-दूसरे का खंडन करते हैं। कारण को समझने और यह तय करने के लिए कि किस पर भरोसा करना है (अधिक आधिकारिक स्रोत, अधिक हालिया, आदि), दोनों को उनके स्रोतों तक वापस ट्रेस करें। + +### UC6: स्रोत प्राधिकरण भार + +कुछ स्रोत दूसरों की तुलना में अधिक आधिकारिक होते हैं। तथ्यों को उनके मूल दस्तावेज़ों के प्राधिकरण/गुणवत्ता के आधार पर भारित या फ़िल्टर किया जा सकता है। + +### UC7: निष्कर्षण पाइपलाइन तुलना + +विभिन्न निष्कर्षण विधियों/संस्करणों से आउटपुट की तुलना करें। किस निष्कर्षण ने समान स्रोत से बेहतर तथ्य उत्पन्न किए? + +## एकीकरण बिंदु + +### लाइब्रेरियन + +लाइब्रेरियन घटक पहले से ही अद्वितीय दस्तावेज़ आईडी के साथ दस्तावेज़ भंडारण प्रदान करता है। प्रोवेनेंस सिस्टम इस मौजूदा बुनियादी ढांचे के साथ एकीकृत होता है। + +#### मौजूदा क्षमताएं (पहले से लागू) + +**पैरेंट-चाइल्ड दस्तावेज़ लिंकिंग:** +`parent_id` फ़ील्ड `DocumentMetadata` में - चाइल्ड को पैरेंट दस्तावेज़ से जोड़ता है +`document_type` फ़ील्ड - मान: `"source"` (मूल) या `"extracted"` (व्युत्पन्न) +`add-child-document` एपीआई - स्वचालित `document_type = "extracted"` के साथ चाइल्ड दस्तावेज़ बनाता है +`list-children` एपीआई - एक पैरेंट दस्तावेज़ के सभी चाइल्ड को पुनः प्राप्त करता है +कैस्केड डिलीशन - एक पैरेंट को हटाने से स्वचालित रूप से सभी चाइल्ड दस्तावेज़ हटा दिए जाते हैं + +**दस्तावेज़ पहचान:** +दस्तावेज़ आईडी क्लाइंट द्वारा निर्दिष्ट हैं (स्वचालित रूप से उत्पन्न नहीं) +दस्तावेज़ों को कैसेंड्रा में समग्र `(user, document_id)` द्वारा कुंजीबद्ध किया जाता है +ऑब्जेक्ट आईडी (UUID) आंतरिक रूप से ब्लब स्टोरेज के लिए उत्पन्न होते हैं + +**मेटाडेटा समर्थन:** +`metadata: list[Triple]` फ़ील्ड - संरचित मेटाडेटा के लिए आरडीएफ ट्रिपल +`title`, `comments`, `tags` - बुनियादी दस्तावेज़ मेटाडेटा +`time` - टाइमस्टैम्प, `kind` - एमआईएमई प्रकार + +**भंडारण आर्किटेक्चर:** +मेटाडेटा कैसेंड्रा में संग्रहीत है (`librarian` कीस्पेस, `document` टेबल) +सामग्री MinIO/S3 ब्लब स्टोरेज में संग्रहीत है (`library` बकेट) +स्मार्ट सामग्री वितरण: 2MB से कम दस्तावेज़ एम्बेडेड हैं, बड़े दस्तावेज़ स्ट्रीम किए जाते हैं + +#### मुख्य फाइलें + +`trustgraph-flow/trustgraph/librarian/librarian.py` - मुख्य लाइब्रेरियन ऑपरेशन +`trustgraph-flow/trustgraph/librarian/service.py` - सर्विस प्रोसेसर, दस्तावेज़ लोडिंग +`trustgraph-flow/trustgraph/tables/library.py` - कैसेंड्रा टेबल स्टोर +`trustgraph-base/trustgraph/schema/services/library.py` - स्कीमा परिभाषाएं + +#### संबोधित करने योग्य कमियां + +लाइब्रेरियन में बिल्डिंग ब्लॉक्स हैं लेकिन वर्तमान में: +1. पैरेंट-चाइल्ड लिंकिंग एक स्तर गहरा है - मल्टी-लेवल डीएजी ट्रैवर्सल हेल्पर नहीं हैं +2. कोई मानक संबंध प्रकार शब्दावली नहीं (जैसे, `derivedFrom`, `extractedFrom`) +3. प्रोवेनेंस मेटाडेटा (निष्कर्षण विधि, आत्मविश्वास, चंक स्थिति) मानकीकृत नहीं है +4. तथ्य से स्रोत तक संपूर्ण प्रोवेनेंस श्रृंखला को पार करने के लिए कोई क्वेरी एपीआई नहीं है + +## एंड-टू-एंड फ्लो डिज़ाइन + +पाइपलाइन में प्रत्येक प्रोसेसर एक सुसंगत पैटर्न का पालन करता है: +अपस्ट्रीम से दस्तावेज़ आईडी प्राप्त करें +लाइब्रेरियन से सामग्री प्राप्त करें +चाइल्ड आर्टिफैक्ट उत्पन्न करें +प्रत्येक चाइल्ड के लिए: लाइब्रेरियन में सहेजें, ग्राफ में एज उत्सर्जित करें, आईडी को डाउनस्ट्रीम पर अग्रेषित करें + +### प्रोसेसिंग फ्लो + +दस्तावेज़ के प्रकार के आधार पर दो फ्लो हैं: + +#### पीडीएफ दस्तावेज़ फ्लो + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID to PDF extractor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ PDF Extractor (per page) │ +│ 1. Fetch PDF content from librarian using document ID │ +│ 2. Extract pages as text │ +│ 3. For each page: │ +│ a. Save page as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send page document ID to chunker │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch page content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = page) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + Post-chunker optimization: messages carry both + chunk ID (for provenance) and content (to avoid + librarian round-trip). Chunks are small (2-4KB). + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor (per chunk) │ +│ 1. Receive chunk ID + content directly (no librarian fetch needed) │ +│ 2. Extract facts/triples and embeddings from chunk content │ +│ 3. For each triple: │ +│ a. Emit triple to knowledge graph │ +│ b. Emit reified edge linking triple → chunk ID (edge pointing │ +│ to edge - first use of reification support) │ +│ 4. For each embedding: │ +│ a. Emit embedding with its entity ID │ +│ b. Link entity ID → chunk ID in knowledge graph │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +#### पाठ दस्तावेज़ प्रवाह + +पाठ दस्तावेज़ पीडीएफ एक्सट्रैक्टर को छोड़ देते हैं और सीधे चंकर पर जाते हैं: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID directly to chunker (skip PDF extractor) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch text content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor │ +│ (same as PDF flow) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +परिणामी निर्देशित एसाइक्लिक ग्राफ (DAG) एक स्तर छोटा होता है: + +``` +PDF: Document → Pages → Chunks → Triples/Embeddings +Text: Document → Chunks → Triples/Embeddings +``` + +डिज़ाइन दोनों को समायोजित करता है क्योंकि चंकर अपने इनपुट को सामान्य रूप से संसाधित करता है - यह जो भी दस्तावेज़ आईडी प्राप्त करता है, उसे पैरेंट के रूप में उपयोग करता है, चाहे वह स्रोत दस्तावेज़ हो या पृष्ठ। + +### मेटाडेटा स्कीमा (PROV-O) + +प्रामाणिकता मेटाडेटा W3C PROV-O ऑन्टोलॉजी का उपयोग करता है। यह एक मानक शब्दावली प्रदान करता है और निष्कर्षण आउटपुट के भविष्य के हस्ताक्षर/प्रमाणीकरण को सक्षम बनाता है। + +#### PROV-O मुख्य अवधारणाएँ + +| PROV-O प्रकार | ट्रस्टग्राफ उपयोग | +|-------------|------------------| +| `prov:Entity` | दस्तावेज़, पृष्ठ, चंक, ट्रिपल, एम्बेडिंग | +| `prov:Activity` | निष्कर्षण कार्यों के उदाहरण | +| `prov:Agent` | टीजी घटक (पीडीएफ एक्सट्रैक्टर, चंकर, आदि) संस्करणों के साथ | + +#### PROV-O संबंध + +| विधेय | अर्थ | उदाहरण | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | एक इकाई से व्युत्पन्न अन्य इकाई | पृष्ठ दस्तावेज़ से व्युत्पन्न था | +| `prov:wasGeneratedBy` | एक गतिविधि द्वारा उत्पन्न इकाई | पृष्ठ पीडीएफ निष्कर्षण गतिविधि द्वारा उत्पन्न किया गया था | +| `prov:used` | गतिविधि ने एक इकाई को इनपुट के रूप में उपयोग किया | पीडीएफ निष्कर्षण गतिविधि ने दस्तावेज़ का उपयोग किया | +| `prov:wasAssociatedWith` | एक एजेंट द्वारा की गई गतिविधि | पीडीएफ निष्कर्षण गतिविधि tg:पीडीएफएक्सट्रैक्टर से जुड़ी थी | + +#### प्रत्येक स्तर पर मेटाडेटा + +**स्रोत दस्तावेज़ (लाइब्रेरियन द्वारा उत्सर्जित):** +``` +doc:123 a prov:Entity . +doc:123 dc:title "Research Paper" . +doc:123 dc:source . +doc:123 dc:date "2024-01-15" . +doc:123 dc:creator "Author Name" . +doc:123 tg:pageCount 42 . +doc:123 tg:mimeType "application/pdf" . +``` + +**पृष्ठ (पीडीएफ एक्सट्रैक्टर द्वारा उत्सर्जित):** +``` +page:123-1 a prov:Entity . +page:123-1 prov:wasDerivedFrom doc:123 . +page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 . +page:123-1 tg:pageNumber 1 . + +activity:pdf-extract-456 a prov:Activity . +activity:pdf-extract-456 prov:used doc:123 . +activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor . +activity:pdf-extract-456 tg:componentVersion "1.2.3" . +activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . +``` + +**खंड (चंकर द्वारा उत्सर्जित):** +``` +chunk:123-1-1 a prov:Entity . +chunk:123-1-1 prov:wasDerivedFrom page:123-1 . +chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 . +chunk:123-1-1 tg:chunkIndex 1 . +chunk:123-1-1 tg:charOffset 0 . +chunk:123-1-1 tg:charLength 2048 . + +activity:chunk-789 a prov:Activity . +activity:chunk-789 prov:used page:123-1 . +activity:chunk-789 prov:wasAssociatedWith tg:Chunker . +activity:chunk-789 tg:componentVersion "1.0.0" . +activity:chunk-789 tg:chunkSize 2048 . +activity:chunk-789 tg:chunkOverlap 200 . +``` + +**ट्रिपल (नॉलेज एक्सट्रैक्टर द्वारा उत्सर्जित):** +``` +# The extracted triple (edge) +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph containing the extracted triples +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 prov:wasGeneratedBy activity:extract-999 . + +activity:extract-999 a prov:Activity . +activity:extract-999 prov:used chunk:123-1-1 . +activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor . +activity:extract-999 tg:componentVersion "2.1.0" . +activity:extract-999 tg:llmModel "claude-3" . +activity:extract-999 tg:ontology . +``` + +**एम्बेडिंग (वेक्टर स्टोर में संग्रहीत, ट्रिपल स्टोर में नहीं):** + +एम्बेडिंग को मेटाडेटा के साथ वेक्टर स्टोर में संग्रहीत किया जाता है, न कि आरडीएफ ट्रिपल के रूप में। प्रत्येक एम्बेडिंग रिकॉर्ड में निम्नलिखित शामिल हैं: + +| फ़ील्ड | विवरण | उदाहरण | +|-------|-------------|---------| +| वेक्टर | एम्बेडिंग वेक्टर | [0.123, -0.456, ...] | +| एंटिटी | नोड यूआरआई जिसे एम्बेडिंग दर्शाता है | `entity:JohnSmith` | +| चंक_आईडी | स्रोत चंक (उत्पत्ति) | `chunk:123-1-1` | +| मॉडल | उपयोग किया गया एम्बेडिंग मॉडल | `text-embedding-ada-002` | +| कंपोनेंट_वर्जन | टीजी एम्बेडर संस्करण | `1.0.0` | + +`entity` फ़ील्ड एम्बेडिंग को नॉलेज ग्राफ (नोड यूआरआई) से जोड़ता है। `chunk_id` फ़ील्ड स्रोत चंक तक उत्पत्ति जानकारी प्रदान करता है, जिससे मूल दस्तावेज़ तक डीएजी (DAG) के माध्यम से ट्रैवर्स करना संभव हो जाता है। + +#### ट्रस्टग्राफ नेमस्पेस एक्सटेंशन + +निष्कर्षण-विशिष्ट मेटाडेटा के लिए `tg:` नेमस्पेस के अंतर्गत कस्टम प्रेडिकेट: + +| प्रेडिकेट | डोमेन | विवरण | +|-----------|--------|-------------| +| `tg:contains` | सबग्राफ | इस निष्कर्षण सबग्राफ में निहित ट्रिपल की ओर इंगित करता है | +| `tg:pageCount` | दस्तावेज़ | स्रोत दस्तावेज़ में पृष्ठों की कुल संख्या | +| `tg:mimeType` | दस्तावेज़ | स्रोत दस्तावेज़ का एमआईएमई (MIME) प्रकार | +| `tg:pageNumber` | पृष्ठ | स्रोत दस्तावेज़ में पृष्ठ संख्या | +| `tg:chunkIndex` | चंक | मूल में चंक का इंडेक्स | +| `tg:charOffset` | चंक | मूल पाठ में कैरेक्टर ऑफसेट | +| `tg:charLength` | चंक | कैरेक्टर में चंक की लंबाई | +| `tg:chunkSize` | गतिविधि | कॉन्फ़िगर किया गया चंक आकार | +| `tg:chunkOverlap` | गतिविधि | चंक के बीच कॉन्फ़िगर किया गया ओवरलैप | +| `tg:componentVersion` | गतिविधि | टीजी घटक का संस्करण | +| `tg:llmModel` | गतिविधि | निष्कर्षण के लिए उपयोग किया गया एलएलएम (LLM) | +| `tg:ontology` | गतिविधि | निष्कर्षण का मार्गदर्शन करने के लिए उपयोग किया गया ऑन्टोलॉजी यूआरआई | +| `tg:embeddingModel` | गतिविधि | एम्बेडिंग के लिए उपयोग किया गया मॉडल | +| `tg:sourceText` | स्टेटमेंट | ट्रिपल से निकाले गए सटीक पाठ | +| `tg:sourceCharOffset` | स्टेटमेंट | चंक के भीतर स्रोत पाठ की शुरुआत का कैरेक्टर ऑफसेट | +| `tg:sourceCharLength` | स्टेटमेंट | कैरेक्टर में स्रोत पाठ की लंबाई | + +#### शब्दावली बूटस्ट्रैप (प्रत्येक संग्रह के लिए) + +नॉलेज ग्राफ ऑन्टोलॉजी-तटस्थ है और खाली अवस्था में शुरू होता है। पहली बार किसी संग्रह में पीआरओवी-ओ (PROV-O) उत्पत्ति डेटा लिखते समय, सभी क्लास और प्रेडिकेट के लिए आरडीएफ लेबल के साथ शब्दावली को बूटस्ट्रैप किया जाना चाहिए। यह प्रश्नों और यूआई (UI) में मानव-पठनीय प्रदर्शन सुनिश्चित करता है। + +**पीआरओवी-ओ क्लास:** +``` +prov:Entity rdfs:label "Entity" . +prov:Activity rdfs:label "Activity" . +prov:Agent rdfs:label "Agent" . +``` + +**प्रोव-ओ विधेय:** +``` +prov:wasDerivedFrom rdfs:label "was derived from" . +prov:wasGeneratedBy rdfs:label "was generated by" . +prov:used rdfs:label "used" . +prov:wasAssociatedWith rdfs:label "was associated with" . +prov:startedAtTime rdfs:label "started at" . +``` + +**ट्रस्टग्राफ प्रेडिकेट्स:** +``` +tg:contains rdfs:label "contains" . +tg:pageCount rdfs:label "page count" . +tg:mimeType rdfs:label "MIME type" . +tg:pageNumber rdfs:label "page number" . +tg:chunkIndex rdfs:label "chunk index" . +tg:charOffset rdfs:label "character offset" . +tg:charLength rdfs:label "character length" . +tg:chunkSize rdfs:label "chunk size" . +tg:chunkOverlap rdfs:label "chunk overlap" . +tg:componentVersion rdfs:label "component version" . +tg:llmModel rdfs:label "LLM model" . +tg:ontology rdfs:label "ontology" . +tg:embeddingModel rdfs:label "embedding model" . +tg:sourceText rdfs:label "source text" . +tg:sourceCharOffset rdfs:label "source character offset" . +tg:sourceCharLength rdfs:label "source character length" . +``` + +**कार्यान्वयन नोट:** यह शब्दावली बूटस्ट्रैप आइडेंम्पोटेंट होना चाहिए - बिना डुप्लिकेट बनाए कई बार चलाने के लिए सुरक्षित। इसे किसी संग्रह में पहली बार दस्तावेज़ प्रसंस्करण के दौरान या एक अलग संग्रह आरंभीकरण चरण के रूप में ट्रिगर किया जा सकता है। + +#### उप-खंड उत्पत्ति (आदर्श) + +अधिक बारीक उत्पत्ति के लिए, यह महत्वपूर्ण होगा कि एक त्रिक को एक खंड के भीतर से ठीक कहाँ से निकाला गया था, इसका रिकॉर्ड रखा जाए। यह निम्नलिखित को सक्षम करता है: + +यूआई में सटीक स्रोत पाठ को हाइलाइट करना +स्रोत के विरुद्ध निष्कर्षण सटीकता को सत्यापित करना +वाक्य स्तर पर निष्कर्षण गुणवत्ता को डीबग करना + +**स्थिति ट्रैकिंग के साथ उदाहरण:** +``` +# The extracted triple +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph with sub-chunk provenance +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +subgraph:001 tg:sourceCharOffset 1547 . +subgraph:001 tg:sourceCharLength 46 . +``` + +**उदाहरण पाठ सीमा के साथ (वैकल्पिक):** +``` +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceRange "1547-1593" . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +``` + +**कार्यान्वयन संबंधी विचार:** + +एलएलएम-आधारित निष्कर्षण स्वाभाविक रूप से वर्ण स्थिति प्रदान नहीं कर सकता है। +एलएलएम को निकाले गए त्रिगुटों के साथ स्रोत वाक्य/वाक्यांश वापस करने के लिए प्रेरित किया जा सकता है। +वैकल्पिक रूप से, निकाले गए संस्थाओं को स्रोत पाठ से "फजी-मैच" करके पोस्ट-प्रोसेस करें। +निष्कर्षण की जटिलता और उत्पत्ति की सूक्ष्मता के बीच एक समझौता। +यह संरचित निष्कर्षण विधियों की तुलना में मुफ्त-रूप एलएलएम निष्कर्षण से प्राप्त करना आसान हो सकता है। + +यह एक महत्वाकांक्षी लक्ष्य के रूप में चिह्नित है - मूल रूप से, बुनियादी चंक-स्तरीय उत्पत्ति को पहले लागू किया जाना चाहिए, और यदि संभव हो तो, उप-चंक ट्रैकिंग को भविष्य में एक संवर्द्धन के रूप में लागू किया जा सकता है। + +### दोहरी भंडारण मॉडल + +उत्पत्ति डीएजी (DAG) को क्रमिक रूप से बनाया जाता है क्योंकि दस्तावेज़ पाइपलाइन के माध्यम से प्रवाहित होते हैं: + +| स्टोर | क्या संग्रहीत है | उद्देश्य | +|-------|---------------|---------| +| लाइब्रेरियन | दस्तावेज़ सामग्री + माता-पिता-बच्चे लिंक | सामग्री पुनर्प्राप्ति, कैस्केड विलोपन | +| ज्ञान ग्राफ | माता-पिता-बच्चे किनारे + मेटाडेटा | उत्पत्ति प्रश्न, तथ्य का श्रेय | + +दोनों स्टोर समान डीएजी संरचना बनाए रखते हैं। लाइब्रेरियन सामग्री रखता है; ग्राफ संबंधों को रखता है और ट्रैवर्सल प्रश्नों को सक्षम करता है। + +### प्रमुख डिज़ाइन सिद्धांत + +1. **दस्तावेज़ आईडी प्रवाह की इकाई के रूप में** - प्रोसेसर आईडी, सामग्री नहीं, पास करते हैं। जब आवश्यक हो तो सामग्री लाइब्रेरियन से प्राप्त की जाती है। + +2. **स्रोत पर एक बार उत्सर्जित करें** - प्रसंस्करण शुरू होने पर मेटाडेटा को ग्राफ में एक बार लिखा जाता है, न कि बाद में दोहराया जाता है। + +3. **संगत प्रोसेसर पैटर्न** - प्रत्येक प्रोसेसर एक ही प्राप्त/प्राप्त/उत्पादित/सहेजें/उत्सर्जित/फॉरवर्ड पैटर्न का पालन करता है। + +4. **प्रगतिशील डीएजी निर्माण** - प्रत्येक प्रोसेसर अपने स्तर को डीएजी में जोड़ता है। पूर्ण उत्पत्ति श्रृंखला क्रमिक रूप से बनाई जाती है। + +5. **चंक-प्रोसेसर के बाद अनुकूलन** - चंकिंग के बाद, संदेशों में आईडी और सामग्री दोनों होते हैं। चंक छोटे होते हैं (2-4KB), इसलिए सामग्री को शामिल करने से अनावश्यक लाइब्रेरियन राउंड-ट्रिप से बचा जा सकता है, जबकि आईडी के माध्यम से उत्पत्ति को संरक्षित किया जा सकता है। + +## कार्यान्वयन कार्य + +### लाइब्रेरियन परिवर्तन + +#### वर्तमान स्थिति + +दस्तावेज़ प्रसंस्करण शुरू करता है दस्तावेज़ आईडी को पहले प्रोसेसर को भेजकर। +ट्रिपल स्टोर से कोई कनेक्शन नहीं - मेटाडेटा निष्कर्षण आउटपुट के साथ बंडल किया गया है। +`add-child-document` एक-स्तरीय माता-पिता-बच्चे लिंक बनाता है। +`list-children` केवल तत्काल बच्चों को वापस करता है। + +#### आवश्यक परिवर्तन + +**1. नया इंटरफ़ेस: ट्रिपल स्टोर कनेक्शन** + +लाइब्रेरियन को प्रसंस्करण शुरू करते समय दस्तावेज़ मेटाडेटा किनारों को सीधे ज्ञान ग्राफ में उत्सर्जित करने की आवश्यकता है। +लाइब्रेरियन सेवा में ट्रिपल स्टोर क्लाइंट/प्रकाशक जोड़ें। +प्रसंस्करण शुरू होने पर: रूट दस्तावेज़ मेटाडेटा को ग्राफ किनारों के रूप में उत्सर्जित करें (एक बार)। + +**2. दस्तावेज़ प्रकार शब्दावली** + +चाइल्ड दस्तावेज़ों के लिए `document_type` मानों का मानकीकरण करें: +`source` - मूल अपलोड किया गया दस्तावेज़। +`page` - स्रोत से निकाला गया पृष्ठ (पीडीएफ, आदि)। +`chunk` - पृष्ठ या स्रोत से प्राप्त पाठ चंक। + +#### इंटरफ़ेस परिवर्तन सारांश + +| इंटरफ़ेस | परिवर्तन | +|-----------|--------| +| ट्रिपल स्टोर | नया आउटबाउंड कनेक्शन - दस्तावेज़ मेटाडेटा किनारों को उत्सर्जित करें | +| प्रसंस्करण प्रारंभ | ग्राफ पर मेटाडेटा उत्सर्जित करें प्रसंस्करण को अग्रेषित करने से पहले | + +### पीडीएफ एक्सट्रैक्टर परिवर्तन + +#### वर्तमान स्थिति + +दस्तावेज़ सामग्री प्राप्त करता है (या बड़े दस्तावेज़ों को स्ट्रीम करता है)। +पीडीएफ पृष्ठों से पाठ निकालता है। +पृष्ठ सामग्री को चंकर को अग्रेषित करता है। +लाइब्रेरियन या ट्रिपल स्टोर के साथ कोई इंटरैक्शन नहीं। + +#### आवश्यक परिवर्तन + +**1. नया इंटरफ़ेस: लाइब्रेरियन क्लाइंट** + +पीडीएफ एक्सट्रैक्टर को प्रत्येक पृष्ठ को लाइब्रेरियन में एक चाइल्ड दस्तावेज़ के रूप में सहेजना होगा। +पीडीएफ एक्सट्रैक्टर सेवा में लाइब्रेरियन क्लाइंट जोड़ें। +प्रत्येक पृष्ठ के लिए: `add-child-document` को रूट दस्तावेज़ आईडी के साथ कॉल करें। + +**2. नया इंटरफ़ेस: ट्रिपल स्टोर कनेक्शन** + +पीडीएफ एक्सट्रैक्टर को ज्ञान ग्राफ में माता-पिता-बच्चे किनारे उत्सर्जित करने की आवश्यकता है। +ट्रिपल स्टोर क्लाइंट/प्रकाशक जोड़ें। +प्रत्येक पृष्ठ के लिए: पृष्ठ दस्तावेज़ को माता-पिता दस्तावेज़ से जोड़ने वाले किनारे को उत्सर्जित करें। + +**3. आउटपुट प्रारूप बदलें** + +सीधे पृष्ठ सामग्री अग्रेषित करने के बजाय, पृष्ठ दस्तावेज़ आईडी अग्रेषित करें। +चंकर लाइब्रेरियन का उपयोग करके आईडी के साथ सामग्री प्राप्त करेगा + +#### इंटरफ़ेस परिवर्तनों का सारांश + +| इंटरफ़ेस | परिवर्तन | +|-----------|--------| +| लाइब्रेरियन | नया आउटबाउंड - चाइल्ड दस्तावेज़ सहेजें | +| ट्रिपल स्टोर | नया आउटबाउंड - पैरेंट-चाइल्ड किनारे उत्सर्जित करें | +| आउटपुट संदेश | सामग्री से दस्तावेज़ आईडी में परिवर्तन | + +### चंकर परिवर्तन + +#### वर्तमान स्थिति + +पृष्ठ/पाठ सामग्री प्राप्त करता है +टुकड़ों में विभाजित करता है +डाउनस्ट्रीम प्रोसेसर को टुकड़े सामग्री अग्रेषित करता है +लाइब्रेरियन या ट्रिपल स्टोर के साथ कोई इंटरैक्शन नहीं + +#### आवश्यक परिवर्तन + +**1. इनपुट हैंडलिंग बदलें** + +सामग्री के बजाय दस्तावेज़ आईडी प्राप्त करें, लाइब्रेरियन से प्राप्त करें। +चंकर सेवा में लाइब्रेरियन क्लाइंट जोड़ें +दस्तावेज़ आईडी का उपयोग करके पृष्ठ सामग्री प्राप्त करें + +**2. नया इंटरफ़ेस: लाइब्रेरियन क्लाइंट (लिखना)** + +प्रत्येक टुकड़े को लाइब्रेरियन में एक चाइल्ड दस्तावेज़ के रूप में सहेजें। +प्रत्येक टुकड़े के लिए: `add-child-document` को पैरेंट = पृष्ठ दस्तावेज़ आईडी के साथ कॉल करें + +**3. नया इंटरफ़ेस: ट्रिपल स्टोर कनेक्शन** + +नॉलेज ग्राफ में पैरेंट-चाइल्ड किनारे उत्सर्जित करें। +ट्रिपल स्टोर क्लाइंट/प्रकाशक जोड़ें +प्रत्येक टुकड़े के लिए: टुकड़े दस्तावेज़ को पृष्ठ दस्तावेज़ से जोड़ने वाला किनारा उत्सर्जित करें + +**4. आउटपुट प्रारूप बदलें** + +टुकड़े दस्तावेज़ आईडी और टुकड़े सामग्री दोनों अग्रेषित करें (टुकड़े-टुकड़े अनुकूलन के बाद)। +डाउनस्ट्रीम प्रोसेसर उत्पत्ति के लिए आईडी और काम करने के लिए सामग्री प्राप्त करते हैं + +#### इंटरफ़ेस परिवर्तनों का सारांश + +| इंटरफ़ेस | परिवर्तन | +|-----------|--------| +| इनपुट संदेश | सामग्री से दस्तावेज़ आईडी में परिवर्तन | +| लाइब्रेरियन | नया आउटबाउंड (पढ़ना + लिखना) - सामग्री प्राप्त करें, चाइल्ड दस्तावेज़ सहेजें | +| ट्रिपल स्टोर | नया आउटबाउंड - पैरेंट-चाइल्ड किनारे उत्सर्जित करें | +| आउटपुट संदेश | सामग्री-केवल से आईडी + सामग्री में परिवर्तन | + +### नॉलेज एक्सट्रैक्टर परिवर्तन + +#### वर्तमान स्थिति + +टुकड़े सामग्री प्राप्त करता है +ट्रिपल और एम्बेडिंग निकालता है +ट्रिपल स्टोर और एम्बेडिंग स्टोर में उत्सर्जित करता है +`subjectOf` संबंध शीर्ष-स्तरीय दस्तावेज़ (टुकड़े नहीं) की ओर इशारा करता है + +#### आवश्यक परिवर्तन + +**1. इनपुट हैंडलिंग बदलें** + +टुकड़े दस्तावेज़ आईडी के साथ-साथ सामग्री प्राप्त करें। +उत्पत्ति लिंकिंग के लिए टुकड़े आईडी का उपयोग करें (सामग्री पहले से ही अनुकूलन के अनुसार शामिल है) + +**2. ट्रिपल उत्पत्ति को अपडेट करें** + +निकाले गए ट्रिपल को टुकड़े (शीर्ष-स्तरीय दस्तावेज़ नहीं) से लिंक करें। +किनारे को इंगित करने वाले किनारे को बनाने के लिए पुन: उपयोग करें +`subjectOf` संबंध: ट्रिपल → टुकड़े दस्तावेज़ आईडी +मौजूदा पुन: उपयोग समर्थन का पहला उपयोग + +**3. एम्बेडिंग उत्पत्ति को अपडेट करें** + +एम्बेडिंग इकाई आईडी को टुकड़े से लिंक करें। +किनारा उत्सर्जित करें: एम्बेडिंग इकाई आईडी → टुकड़े दस्तावेज़ आईडी + +#### इंटरफ़ेस परिवर्तनों का सारांश + +| इंटरफ़ेस | परिवर्तन | +|-----------|--------| +| इनपुट संदेश | टुकड़े आईडी + सामग्री की अपेक्षा करें (केवल सामग्री नहीं) | +| ट्रिपल स्टोर | ट्रिपल → टुकड़े उत्पत्ति के लिए पुन: उपयोग का उपयोग करें | +| एम्बेडिंग उत्पत्ति | इकाई आईडी → टुकड़े आईडी से लिंक करें | + +## संदर्भ + +क्वेरी-टाइम उत्पत्ति: `docs/tech-specs/query-time-provenance.md` +उत्पत्ति मॉडलिंग के लिए PROV-O मानक +नॉलेज ग्राफ में मौजूदा स्रोत मेटाडेटा (ऑडिट की आवश्यकता है) diff --git a/docs/tech-specs/extraction-time-provenance.pt.md b/docs/tech-specs/extraction-time-provenance.pt.md new file mode 100644 index 00000000..e5c9b10c --- /dev/null +++ b/docs/tech-specs/extraction-time-provenance.pt.md @@ -0,0 +1,619 @@ +# Proveniência no Momento da Extração: Camada de Origem + +## Visão Geral + +Este documento registra notas sobre a proveniência no momento da extração para trabalhos de especificação futuros. A proveniência no momento da extração registra a "camada de origem" - de onde os dados vieram originalmente, como foram extraídos e transformados. + +Isso é diferente da proveniência no momento da consulta (veja `query-time-provenance.md`), que registra o raciocínio do agente. + +## Declaração do Problema + +### Implementação Atual + +Atualmente, a proveniência funciona da seguinte forma: +Metadados do documento são armazenados como triplas RDF no grafo de conhecimento. +Um ID de documento associa metadados ao documento, de modo que o documento aparece como um nó no grafo. +Quando arestas (relacionamentos/fatos) são extraídas de documentos, um relacionamento `subjectOf` vincula a aresta extraída ao documento de origem. + +### Problemas com a Abordagem Atual + +1. **Carregamento repetitivo de metadados:** Os metadados do documento são agrupados e carregados repetidamente com cada lote de triplas extraídas daquele documento. Isso é um desperdício e redundante - os mesmos metadados viajam como carga com cada saída de extração. + +2. **Proveniência superficial:** O relacionamento `subjectOf` atual vincula apenas os fatos diretamente ao documento de nível superior. Não há visibilidade da cadeia de transformação - qual página o fato veio, qual trecho, qual método de extração foi usado. + +### Estado Desejado + +1. **Carregar metadados uma vez:** Os metadados do documento devem ser carregados uma vez e anexados ao nó do documento de nível superior, não repetidos com cada lote de triplas. + +2. **DAG de proveniência rica:** Capture toda a cadeia de transformação desde o documento de origem, passando por todos os artefatos intermediários, até os fatos extraídos. Por exemplo, uma transformação de documento PDF: + + ``` + PDF file (source document with metadata) + → Page 1 (decoded text) + → Chunk 1 + → Extracted edge/fact (via subjectOf) + → Extracted edge/fact + → Chunk 2 + → Extracted edge/fact + → Page 2 + → Chunk 3 + → ... + ``` + +3. **Armazenamento unificado:** O grafo de proveniência é armazenado no mesmo grafo de conhecimento que o conhecimento extraído. Isso permite que a proveniência seja consultada da mesma forma que o conhecimento - seguindo as arestas de volta à cadeia de qualquer fato para sua localização de origem exata. + +4. **IDs estáveis:** Cada artefato intermediário (página, trecho) possui um ID estável como um nó no grafo. + +5. **Vinculação pai-filho:** Documentos derivados são vinculados aos seus pais até o documento de origem de nível superior, usando tipos de relacionamento consistentes. + +6. **Atribuição precisa de fatos:** O relacionamento `subjectOf` nas arestas extraídas aponta para o pai imediato (trecho), não para o documento de nível superior. A proveniência completa é recuperada percorrendo o DAG. + +## Casos de Uso + +### UC1: Atribuição de Fonte em Respostas GraphRAG + +**Cenário:** Um usuário executa uma consulta GraphRAG e recebe uma resposta do agente. + +**Fluxo:** +1. O usuário envia uma consulta para o agente GraphRAG. +2. O agente recupera fatos relevantes do grafo de conhecimento para formular uma resposta. +3. De acordo com a especificação de proveniência em tempo de consulta, o agente informa quais fatos contribuíram para a resposta. +4. Cada fato vincula-se ao seu trecho de origem através do grafo de proveniência. +5. Trechos vinculam-se a páginas, páginas vinculam-se a documentos de origem. + +**Resultado da Experiência do Usuário:** A interface exibe a resposta do LLM juntamente com a atribuição da fonte. O usuário pode: +Ver quais fatos apoiaram a resposta. +Acessar informações detalhadas de fatos → trechos → páginas → documentos. +Examinar os documentos de origem para verificar as alegações. +Entender exatamente onde em um documento (qual página, qual seção) um fato se originou. + +**Valor:** Os usuários podem verificar as respostas geradas por IA em relação às fontes primárias, construindo confiança e permitindo a verificação de fatos. + +### UC2: Depuração da Qualidade da Extração + +Um fato parece incorreto. Rastreie de volta através do trecho → página → documento para ver o texto original. Foi uma extração ruim ou a fonte em si estava incorreta? + +### UC3: Reextração Incremental + +O documento de origem é atualizado. Quais trechos/fatos foram derivados dele? Invalide e regenere apenas esses, em vez de reprocessar tudo. + +### UC4: Exclusão de Dados / Direito ao Esquecimento + +Um documento de origem deve ser removido (GDPR, legal, etc.). Percorra o DAG para encontrar e remover todos os fatos derivados. + +### UC5: Resolução de Conflitos + +Dois fatos se contradizem. Rastreie ambos de volta às suas fontes para entender por que e decidir qual confiar (fonte mais autoritária, mais recente, etc.). + +### UC6: Ponderação da Autoridade da Fonte + +Algumas fontes são mais autoritárias do que outras. Os fatos podem ser ponderados ou filtrados com base na autoridade/qualidade de seus documentos de origem. + +### UC7: Comparação de Pipelines de Extração + +Compare os resultados de diferentes métodos/versões de extração. Qual extrator produziu melhores fatos da mesma fonte? + +## Pontos de Integração + +### Bibliotecário + +O componente bibliotecário já fornece armazenamento de documentos com IDs de documento exclusivos. O sistema de rastreabilidade se integra com essa infraestrutura existente. + +#### Capacidades Existentes (já implementadas) + +**Vinculação de Documentos Pai-Filho:** +Campo `parent_id` em `DocumentMetadata` - vincula o documento filho ao documento pai +Campo `document_type` - valores: `"source"` (original) ou `"extracted"` (derivado) +API `add-child-document` - cria um documento filho com `document_type = "extracted"` automático +API `list-children` - recupera todos os filhos de um documento pai +Exclusão em cascata - a remoção de um pai exclui automaticamente todos os documentos filhos + +**Identificação de Documentos:** +Os IDs de documento são especificados pelo cliente (não gerados automaticamente) +Documentos indexados por `(user, document_id)` composto no Cassandra +IDs de objeto (UUIDs) gerados internamente para armazenamento de blobs + +**Suporte a Metadados:** +Campo `metadata: list[Triple]` - triplas RDF para metadados estruturados +`title`, `comments`, `tags` - metadados básicos do documento +`time` - carimbo de data/hora, `kind` - tipo MIME + +**Arquitetura de Armazenamento:** +Metadados armazenados no Cassandra (espaço de chaves `librarian`, tabela `document`) +Conteúdo armazenado no armazenamento de blobs MinIO/S3 (bucket `library`) +Entrega inteligente de conteúdo: documentos < 2MB incorporados, documentos maiores transmitidos + +#### Arquivos Chave + +`trustgraph-flow/trustgraph/librarian/librarian.py` - Operações principais do bibliotecário +`trustgraph-flow/trustgraph/librarian/service.py` - Processador de serviço, carregamento de documento +`trustgraph-flow/trustgraph/tables/library.py` - Armazenamento de tabela Cassandra +`trustgraph-base/trustgraph/schema/services/library.py` - Definições de esquema + +#### Lacunas a Serem Abordadas + +O bibliotecário tem os blocos de construção, mas atualmente: +1. A vinculação pai-filho é de um único nível - não há auxiliares de travessia de DAG de vários níveis +2. Não há vocabulário padrão de tipo de relacionamento (por exemplo, `derivedFrom`, `extractedFrom`) +3. Metadados de rastreabilidade (método de extração, confiança, posição do fragmento) não estão padronizados +4. Não há API de consulta para percorrer toda a cadeia de rastreabilidade de um fato até a fonte + +## Design de Fluxo de Extremo a Extremo + +Cada processador no pipeline segue um padrão consistente: +Recebe o ID do documento do upstream +Recupera o conteúdo do bibliotecário +Produz artefatos filhos +Para cada filho: salva no bibliotecário, emite uma aresta para o grafo, encaminha o ID para o downstream + +### Fluxos de Processamento + +Existem dois fluxos dependendo do tipo de documento: + +#### Fluxo de Documento PDF + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID to PDF extractor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ PDF Extractor (per page) │ +│ 1. Fetch PDF content from librarian using document ID │ +│ 2. Extract pages as text │ +│ 3. For each page: │ +│ a. Save page as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send page document ID to chunker │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch page content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = page) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + Post-chunker optimization: messages carry both + chunk ID (for provenance) and content (to avoid + librarian round-trip). Chunks are small (2-4KB). + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor (per chunk) │ +│ 1. Receive chunk ID + content directly (no librarian fetch needed) │ +│ 2. Extract facts/triples and embeddings from chunk content │ +│ 3. For each triple: │ +│ a. Emit triple to knowledge graph │ +│ b. Emit reified edge linking triple → chunk ID (edge pointing │ +│ to edge - first use of reification support) │ +│ 4. For each embedding: │ +│ a. Emit embedding with its entity ID │ +│ b. Link entity ID → chunk ID in knowledge graph │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +#### Fluxo de Documentos de Texto + +Documentos de texto ignoram o extrator de PDF e vão diretamente para o processador de fragmentos: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID directly to chunker (skip PDF extractor) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch text content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor │ +│ (same as PDF flow) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +O grafo acíclico dirigido (DAG) resultante é um nível mais curto: + +``` +PDF: Document → Pages → Chunks → Triples/Embeddings +Text: Document → Chunks → Triples/Embeddings +``` + +O design acomoda ambos porque o processador divide o conteúdo de forma genérica - ele usa qualquer ID de documento que recebe como pai, independentemente de ser um documento de origem ou uma página. + +### Esquema de Metadados (PROV-O) + +Os metadados de procedência utilizam a ontologia W3C PROV-O. Isso fornece um vocabulário padrão e permite a futura assinatura/autenticação dos resultados da extração. + +#### Conceitos Principais do PROV-O + +| Tipo PROV-O | Uso no TrustGraph | +|-------------|------------------| +| `prov:Entity` | Documento, Página, Trecho, Tripla, Incorporação | +| `prov:Activity` | Instâncias de operações de extração | +| `prov:Agent` | Componentes do TG (extrator de PDF, processador, etc.) com versões | + +#### Relacionamentos do PROV-O + +| Predicado | Significado | Exemplo | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | Entidade derivada de outra entidade | Página foiDerivadaDe Documento | +| `prov:wasGeneratedBy` | Entidade gerada por uma atividade | Página foiGeradaPor AtividadeDeExtraçãoDePDF | +| `prov:used` | Atividade que usou uma entidade como entrada | AtividadeDeExtraçãoDePDF usou Documento | +| `prov:wasAssociatedWith` | Atividade realizada por um agente | AtividadeDeExtraçãoDePDF foiAssociadaA tg:ExtratorDePDF | + +#### Metadados em Cada Nível + +**Documento de Origem (emitido pelo Librarian):** +``` +doc:123 a prov:Entity . +doc:123 dc:title "Research Paper" . +doc:123 dc:source . +doc:123 dc:date "2024-01-15" . +doc:123 dc:creator "Author Name" . +doc:123 tg:pageCount 42 . +doc:123 tg:mimeType "application/pdf" . +``` + +**Página (emitida pelo Extrator de PDF):** +``` +page:123-1 a prov:Entity . +page:123-1 prov:wasDerivedFrom doc:123 . +page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 . +page:123-1 tg:pageNumber 1 . + +activity:pdf-extract-456 a prov:Activity . +activity:pdf-extract-456 prov:used doc:123 . +activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor . +activity:pdf-extract-456 tg:componentVersion "1.2.3" . +activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . +``` + +**Bloco (emitido pelo Chunker):** +``` +chunk:123-1-1 a prov:Entity . +chunk:123-1-1 prov:wasDerivedFrom page:123-1 . +chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 . +chunk:123-1-1 tg:chunkIndex 1 . +chunk:123-1-1 tg:charOffset 0 . +chunk:123-1-1 tg:charLength 2048 . + +activity:chunk-789 a prov:Activity . +activity:chunk-789 prov:used page:123-1 . +activity:chunk-789 prov:wasAssociatedWith tg:Chunker . +activity:chunk-789 tg:componentVersion "1.0.0" . +activity:chunk-789 tg:chunkSize 2048 . +activity:chunk-789 tg:chunkOverlap 200 . +``` + +**Tripla (emitida pelo Extrator de Conhecimento):** +``` +# The extracted triple (edge) +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph containing the extracted triples +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 prov:wasGeneratedBy activity:extract-999 . + +activity:extract-999 a prov:Activity . +activity:extract-999 prov:used chunk:123-1-1 . +activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor . +activity:extract-999 tg:componentVersion "2.1.0" . +activity:extract-999 tg:llmModel "claude-3" . +activity:extract-999 tg:ontology . +``` + +**Incorporação (armazenada em um armazenamento vetorial, não em um armazenamento triplo):** + +As incorporações são armazenadas no armazenamento vetorial com metadados, e não como triplos RDF. Cada registro de incorporação contém: + +| Campo | Descrição | Exemplo | +|-------|-------------|---------| +| vetor | O vetor de incorporação | [0.123, -0.456, ...] | +| entidade | URI do nó que a incorporação representa | `entity:JohnSmith` | +| chunk_id | Fragmento de origem (proveniência) | `chunk:123-1-1` | +| modelo | Modelo de incorporação usado | `text-embedding-ada-002` | +| component_version | Versão do incorporador TG | `1.0.0` | + +O campo `entity` vincula a incorporação ao grafo de conhecimento (URI do nó). O campo `chunk_id` fornece a proveniência de volta ao fragmento de origem, permitindo a navegação ascendente no DAG até o documento original. + +#### Extensões do Namespace TrustGraph + +Predicados personalizados sob o namespace `tg:` para metadados específicos de extração: + +| Predicado | Domínio | Descrição | +|-----------|--------|-------------| +| `tg:contains` | Subgrafo | Aponta para um triplo contido neste subgrafo de extração | +| `tg:pageCount` | Documento | Número total de páginas no documento de origem | +| `tg:mimeType` | Documento | Tipo MIME do documento de origem | +| `tg:pageNumber` | Página | Número da página no documento de origem | +| `tg:chunkIndex` | Fragmento | Índice do fragmento dentro do fragmento pai | +| `tg:charOffset` | Fragmento | Deslocamento de caractere no texto pai | +| `tg:charLength` | Fragmento | Comprimento do fragmento em caracteres | +| `tg:chunkSize` | Atividade | Tamanho do fragmento configurado | +| `tg:chunkOverlap` | Atividade | Sobreposição configurada entre fragmentos | +| `tg:componentVersion` | Atividade | Versão do componente TG | +| `tg:llmModel` | Atividade | LLM usado para extração | +| `tg:ontology` | Atividade | URI da ontologia usada para guiar a extração | +| `tg:embeddingModel` | Atividade | Modelo usado para incorporações | +| `tg:sourceText` | Declaração | Texto exato do qual um triplo foi extraído | +| `tg:sourceCharOffset` | Declaração | Deslocamento de caractere dentro do fragmento onde o texto de origem começa | +| `tg:sourceCharLength` | Declaração | Comprimento do texto de origem em caracteres | + +#### Inicialização do Vocabulário (Por Coleção) + +O grafo de conhecimento é neutro em relação à ontologia e é inicializado como vazio. Ao gravar dados de proveniência PROV-O em uma coleção pela primeira vez, o vocabulário deve ser inicializado com rótulos RDF para todas as classes e predicados. Isso garante a exibição legível por humanos em consultas e na interface do usuário. + +**Classes PROV-O:** +``` +prov:Entity rdfs:label "Entity" . +prov:Activity rdfs:label "Activity" . +prov:Agent rdfs:label "Agent" . +``` + +**Predicados PROV-O:** +``` +prov:wasDerivedFrom rdfs:label "was derived from" . +prov:wasGeneratedBy rdfs:label "was generated by" . +prov:used rdfs:label "used" . +prov:wasAssociatedWith rdfs:label "was associated with" . +prov:startedAtTime rdfs:label "started at" . +``` + +**Predicados TrustGraph:** +``` +tg:contains rdfs:label "contains" . +tg:pageCount rdfs:label "page count" . +tg:mimeType rdfs:label "MIME type" . +tg:pageNumber rdfs:label "page number" . +tg:chunkIndex rdfs:label "chunk index" . +tg:charOffset rdfs:label "character offset" . +tg:charLength rdfs:label "character length" . +tg:chunkSize rdfs:label "chunk size" . +tg:chunkOverlap rdfs:label "chunk overlap" . +tg:componentVersion rdfs:label "component version" . +tg:llmModel rdfs:label "LLM model" . +tg:ontology rdfs:label "ontology" . +tg:embeddingModel rdfs:label "embedding model" . +tg:sourceText rdfs:label "source text" . +tg:sourceCharOffset rdfs:label "source character offset" . +tg:sourceCharLength rdfs:label "source character length" . +``` + +**Observação sobre a implementação:** Este processo de inicialização do vocabulário deve ser idempotente - seguro para executar várias vezes sem criar duplicatas. Pode ser acionado no processamento do primeiro documento em uma coleção, ou como uma etapa separada de inicialização da coleção. + +#### Proveniência de Sub-Fragmentos (Alvo) + +Para uma rastreabilidade mais detalhada, seria valioso registrar exatamente onde, dentro de um fragmento, uma tripla foi extraída. Isso permite: + +Destacar o texto de origem exato na interface do usuário +Verificar a precisão da extração em relação à fonte +Depurar a qualidade da extração no nível da frase + +**Exemplo com rastreamento de posição:** +``` +# The extracted triple +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph with sub-chunk provenance +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +subgraph:001 tg:sourceCharOffset 1547 . +subgraph:001 tg:sourceCharLength 46 . +``` + +**Exemplo com intervalo de texto (alternativa):** +``` +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceRange "1547-1593" . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +``` + +**Considerações de implementação:** + +A extração baseada em LLM pode não fornecer naturalmente as posições dos caracteres. +Poderia solicitar ao LLM que retornasse a frase/frase de origem junto com as triplas extraídas. +Alternativamente, pós-processe para fazer uma correspondência aproximada das entidades extraídas com o texto de origem. +Compromisso entre a complexidade da extração e a granularidade da procedência. +Pode ser mais fácil de alcançar com métodos de extração estruturados do que com a extração de LLM de formato livre. + +Isso está marcado como uma meta a longo prazo - a procedência no nível do bloco deve ser implementada primeiro, com o rastreamento de subblocos como um aprimoramento futuro, se viável. + +### Modelo de Armazenamento Duplo + +O grafo de procedência é construído progressivamente à medida que os documentos fluem pelo pipeline: + +| Armazenamento | O que é armazenado | Propósito | +|-------|---------------|---------| +| Bibliotecário | Conteúdo do documento + links pai-filho | Recuperação de conteúdo, exclusão em cascata | +| Grafo de Conhecimento | Arestas pai-filho + metadados | Consultas de procedência, atribuição de fatos | + +Ambos os armazenamentos mantêm a mesma estrutura de grafo. O bibliotecário armazena o conteúdo; o grafo armazena os relacionamentos e permite consultas de travessia. + +### Princípios de Design Chave + +1. **ID do documento como a unidade de fluxo** - Os processadores passam IDs, não o conteúdo. O conteúdo é buscado do bibliotecário quando necessário. + +2. **Emitir uma vez na origem** - Os metadados são gravados no grafo uma vez quando o processamento começa, e não repetidos downstream. + +3. **Padrão de processador consistente** - Cada processador segue o mesmo padrão de receber/buscar/produzir/salvar/emitir/transmitir. + +4. **Construção progressiva do grafo** - Cada processador adiciona seu nível ao grafo. A cadeia completa de procedência é construída incrementalmente. + +5. **Otimização pós-fragmentação** - Após a fragmentação, as mensagens carregam tanto o ID quanto o conteúdo. Os fragmentos são pequenos (2-4 KB), portanto, incluir o conteúdo evita viagens de ida e volta desnecessárias ao bibliotecário, preservando a procedência por meio do ID. + +## Tarefas de Implementação + +### Alterações no Bibliotecário + +#### Estado Atual + +Inicia o processamento do documento enviando o ID do documento para o primeiro processador. +Não possui conexão com o armazenamento de triplas - os metadados são agrupados com as saídas de extração. +`add-child-document` cria links pai-filho de um nível. +`list-children` retorna apenas os filhos imediatos. + +#### Alterações Necessárias + +**1. Nova interface: Conexão com o armazenamento de triplas** + +O bibliotecário precisa emitir as bordas de metadados do documento diretamente para o grafo de conhecimento ao iniciar o processamento. +Adicione um cliente/publicador de armazenamento de triplas ao serviço do bibliotecário. +Na inicialização do processamento: emita os metadados do documento raiz como bordas do grafo (uma vez). + +**2. Vocabulário de tipo de documento** + +Padronize os valores de `document_type` para documentos filhos: +`source` - documento original carregado. +`page` - página extraída da fonte (PDF, etc.). +`chunk` - fragmento de texto derivado da página ou da fonte. + +#### Resumo das Alterações na Interface + +| Interface | Alteração | +|-----------|--------| +| Armazenamento de triplas | Nova conexão de saída - emita bordas de metadados do documento | +| Início do processamento | Emita metadados para o grafo antes de encaminhar o ID do documento | + +### Alterações no Extrator de PDF + +#### Estado Atual + +Recebe o conteúdo do documento (ou transmite documentos grandes). +Extrai texto das páginas PDF. +Transmite o conteúdo da página para o fragmentador. +Não interage com o bibliotecário ou o armazenamento de triplas. + +#### Alterações Necessárias + +**1. Nova interface: Cliente do bibliotecário** + +O extrator de PDF precisa salvar cada página como um documento filho no bibliotecário. +Adicione um cliente do bibliotecário ao serviço do extrator de PDF. +Para cada página: chame `add-child-document` com pai = ID do documento raiz. + +**2. Nova interface: Conexão com o armazenamento de triplas** + +O extrator de PDF precisa emitir bordas pai-filho para o grafo de conhecimento. +Adicione um cliente/publicador de armazenamento de triplas. +Para cada página: emita uma borda que vincule o documento da página ao documento pai. + +**3. Alterar o formato de saída** + +Em vez de encaminhar o conteúdo da página diretamente, encaminhe o ID do documento da página. +O Chunker buscará o conteúdo do "librarian" usando o ID. + +#### Resumo das Alterações na Interface + +| Interface | Mudança | +|-----------|--------| +| Librarian | Nova saída - salvar documentos filhos | +| Triple store | Nova saída - emitir arestas pai-filho | +| Mensagem de saída | Mudança de conteúdo para ID do documento | + +### Mudanças no Chunker + +#### Estado Atual + +Recebe conteúdo da página/texto +Divide em partes (chunks) +Encaminha o conteúdo da parte para processadores subsequentes +Sem interação com o "librarian" ou o "triple store" + +#### Mudanças Necessárias + +**1. Alterar o tratamento da entrada** + +Receber o ID do documento em vez do conteúdo, buscar do "librarian". +Adicionar cliente do "librarian" ao serviço do Chunker +Buscar o conteúdo da página usando o ID do documento + +**2. Nova interface: Cliente do "Librarian" (escrita)** + +Salvar cada parte como um documento filho no "librarian". +Para cada parte: chamar `add-child-document` com parent = ID do documento da página + +**3. Nova interface: Conexão com o "Triple store"** + +Emitir arestas pai-filho para o grafo de conhecimento. +Adicionar cliente/publicador do "triple store" +Para cada parte: emitir aresta ligando o documento da parte ao documento da página + +**4. Alterar o formato de saída** + +Encaminhar tanto o ID do documento da parte quanto o conteúdo da parte (otimização pós-chunker). +Os processadores subsequentes recebem o ID para rastreabilidade + o conteúdo para trabalhar + +#### Resumo das Alterações na Interface + +| Interface | Mudança | +|-----------|--------| +| Mensagem de entrada | Mudança de conteúdo para ID do documento | +| Librarian | Nova saída (leitura + escrita) - buscar conteúdo, salvar documentos filhos | +| Triple store | Nova saída - emitir arestas pai-filho | +| Mensagem de saída | Mudança de conteúdo-apenas para ID + conteúdo | + +### Mudanças no Extrator de Conhecimento + +#### Estado Atual + +Recebe conteúdo da parte +Extrai triplas e embeddings +Emite para o "triple store" e o "embedding store" +A relação `subjectOf` aponta para o documento de nível superior (não para a parte) + +#### Mudanças Necessárias + +**1. Alterar o tratamento da entrada** + +Receber o ID do documento da parte junto com o conteúdo. +Usar o ID da parte para rastreabilidade (o conteúdo já está incluído por otimização) + +**2. Atualizar a rastreabilidade das triplas** + +Ligar as triplas extraídas à parte (não ao documento de nível superior). +Usar a reificação para criar uma aresta apontando para a aresta +Relação `subjectOf`: tripla → ID do documento da parte +Primeiro uso do suporte de reificação existente + +**3. Atualizar a rastreabilidade dos embeddings** + +Ligar os IDs das entidades de embedding à parte. +Emitir aresta: ID da entidade de embedding → ID do documento da parte + +#### Resumo das Alterações na Interface + +| Interface | Mudança | +|-----------|--------| +| Mensagem de entrada | Esperar ID da parte + conteúdo (não apenas conteúdo) | +| Triple store | Usar reificação para rastreabilidade de tripla → parte | +| Rastreabilidade de embedding | Ligar ID da entidade → ID da parte | + +## Referências + +Rastreabilidade em tempo de consulta: `docs/tech-specs/query-time-provenance.md` +Padrão PROV-O para modelagem de rastreabilidade +Metadados de origem existentes no grafo de conhecimento (precisa de auditoria) diff --git a/docs/tech-specs/extraction-time-provenance.ru.md b/docs/tech-specs/extraction-time-provenance.ru.md new file mode 100644 index 00000000..cdd896ce --- /dev/null +++ b/docs/tech-specs/extraction-time-provenance.ru.md @@ -0,0 +1,619 @@ +# Происхождение данных во время извлечения: Исходный слой + +## Обзор + +Этот документ содержит заметки о происхождении данных во время извлечения для будущих работ по спецификации. Происхождение данных во время извлечения фиксирует "исходный слой" - откуда данные были получены изначально, как они были извлечены и преобразованы. + +Это отличается от происхождения данных во время запроса (см. `query-time-provenance.md`), которое фиксирует логику работы агента. + +## Описание проблемы + +### Текущая реализация + +В настоящее время происхождение данных работает следующим образом: +Метаданные документа хранятся в виде RDF-триплетов в графе знаний. +Идентификатор документа связывает метаданные с документом, поэтому документ отображается как узел в графе. +Когда связи (отношения/факты) извлекаются из документов, связь `subjectOf` связывает извлеченную связь с исходным документом. + +### Проблемы текущего подхода + +1. **Повторная загрузка метаданных:** Метаданные документа группируются и загружаются повторно при каждой партии триплетов, извлеченных из этого документа. Это неэффективно и избыточно - одни и те же метаданные передаются как "груз" с каждым результатом извлечения. + +2. **Поверхностное происхождение данных:** Текущая связь `subjectOf` связывает факты только с верхним уровнем документа. Нет информации о цепочке преобразований - с какой страницы был получен факт, из какого фрагмента, какой метод извлечения был использован. + +### Желаемое состояние + +1. **Загрузка метаданных один раз:** Метаданные документа должны быть загружены один раз и привязаны к узлу верхнего уровня документа, а не повторяться с каждой партией триплетов. + +2. **Разветвленная структура данных о происхождении:** Захватите полную цепочку преобразований от исходного документа через все промежуточные артефакты до извлеченных фактов. Например, преобразование PDF-документа: + + ``` + PDF file (source document with metadata) + → Page 1 (decoded text) + → Chunk 1 + → Extracted edge/fact (via subjectOf) + → Extracted edge/fact + → Chunk 2 + → Extracted edge/fact + → Page 2 + → Chunk 3 + → ... + ``` + +3. **Унифицированное хранилище:** Граф происхождения хранится в той же базе знаний, что и извлеченные знания. Это позволяет запрашивать происхождение так же, как и знания, прослеживая связи обратно по цепочке от любого факта к его точному источнику. + +4. **Стабильные идентификаторы:** Каждый промежуточный артефакт (страница, фрагмент) имеет стабильный идентификатор в виде узла в графе. + +5. **Связь родитель-потомок:** Производные документы связаны с их родительскими документами до самого верхнего уровня, используя согласованные типы отношений. + +6. **Точное определение источника факта:** Отношение `subjectOf` на извлеченных связях указывает на непосредственный родительский элемент (фрагмент), а не на верхний документ. Полное происхождение восстанавливается путем прохода по графу. + +## Случаи использования + +### UC1: Определение источника в ответах GraphRAG + +**Сценарий:** Пользователь выполняет запрос GraphRAG и получает ответ от агента. + +**Процесс:** +1. Пользователь отправляет запрос агенту GraphRAG. +2. Агент извлекает соответствующие факты из базы знаний для формирования ответа. +3. В соответствии со спецификацией происхождения во время запроса, агент сообщает, какие факты внесли вклад в ответ. +4. Каждый факт связан с его исходным фрагментом через граф происхождения. +5. Фрагменты связаны со страницами, страницы связаны с исходными документами. + +**Результат для пользователя:** Интерфейс отображает ответ LLM вместе с указанием источника. Пользователь может: +Увидеть, какие факты подтверждают ответ. +Переходить от фактов к фрагментам, страницам и документам. +Просматривать исходные документы для проверки утверждений. +Понимать, откуда в документе (на какой странице, в каком разделе) произошел факт. + +**Преимущество:** Пользователи могут проверять ответы, сгенерированные ИИ, по сравнению с первичными источниками, что повышает доверие и позволяет проводить проверку фактов. + +### UC2: Отладка качества извлечения + +Факт кажется неверным. Проследите обратно через фрагмент, страницу и документ, чтобы увидеть исходный текст. Это была ошибка извлечения, или исходный документ был неверным? + +### UC3: Инкрементное повторное извлечение + +Исходный документ обновлен. Какие фрагменты/факты были получены из него? Отмените и перезапустите только эти, а не перерабатывайте все. + +### UC4: Удаление данных / Право на забвение + +Исходный документ должен быть удален (GDPR, юридические требования и т.д.). Найдите и удалите все производные факты, пройдя по графу. + +### UC5: Разрешение конфликтов + +Два факта противоречат друг другу. Проследите оба обратно к их источникам, чтобы понять, почему, и решить, кому доверять (более авторитетному источнику, более свежему и т.д.). + +### UC6: Взвешивание авторитетности источника + +Некоторые источники более авторитетны, чем другие. Факты могут быть взвешены или отфильтрованы на основе авторитетности/качества исходных документов. + +### UC7: Сравнение конвейеров извлечения + +Сравните результаты, полученные с использованием различных методов/версий извлечения. Какой экстрактор выдал лучшие факты из одного и того же источника? + +## Точки интеграции + +### Библиотекарь + +Компонент "библиотекарь" уже предоставляет хранение документов с уникальными идентификаторами документов. Система отслеживания происхождения интегрируется с существующей инфраструктурой. + +#### Существующие возможности (уже реализовано) + +**Связывание документов "родитель-потомок":** +Поле `parent_id` в `DocumentMetadata` - связывает дочерний документ с родительским документом. +Поле `document_type` - значения: `"source"` (оригинальный) или `"extracted"` (производный). +API `add-child-document` - создает дочерний документ с автоматическим `document_type = "extracted"`. +API `list-children` - извлекает все дочерние документы родительского документа. +Каскадное удаление - удаление родительского документа автоматически удаляет все дочерние документы. + +**Идентификация документов:** +Идентификаторы документов задаются клиентом (не генерируются автоматически). +Документы индексируются по составному ключу `(user, document_id)` в Cassandra. +Объектные идентификаторы (UUID) генерируются внутренне для хранения двоичных данных. + +**Поддержка метаданных:** +Поле `metadata: list[Triple]` - тройки RDF для структурированных метаданных. +`title`, `comments`, `tags` - основные метаданные документа. +`time` - метка времени, `kind` - MIME-тип. + +**Архитектура хранения:** +Метаданные хранятся в Cassandra (пространство ключей `librarian`, таблица `document`). +Содержимое хранится в хранилище двоичных данных MinIO/S3 (контейнер `library`). +Интеллектуальная доставка контента: документы размером менее 2 МБ встраиваются, более крупные документы передаются потоком. + +#### Основные файлы + +`trustgraph-flow/trustgraph/librarian/librarian.py` - Основные операции "библиотекаря". +`trustgraph-flow/trustgraph/librarian/service.py` - Сервисный процессор, загрузка документов. +`trustgraph-flow/trustgraph/tables/library.py` - Хранилище таблиц Cassandra. +`trustgraph-base/trustgraph/schema/services/library.py` - Определения схемы. + +#### Необходимые улучшения + +"Библиотекарь" имеет необходимые компоненты, но в настоящее время: +1. Связывание "родитель-потомок" ограничено одним уровнем - отсутствуют вспомогательные функции для обхода многоуровневых графов. +2. Отсутствует стандартная терминология для типов отношений (например, `derivedFrom`, `extractedFrom`). +3. Метаданные происхождения (метод извлечения, уверенность, позиция фрагмента) не стандартизированы. +4. Отсутствует API запросов для прослеживания полной цепочки происхождения от факта до исходного источника. + +## Проектирование сквозного потока + +Каждый процессор в конвейере следует последовательной схеме: +Получает идентификатор документа от предыдущего этапа. +Извлекает содержимое из "библиотекаря". +Создает дочерние артефакты. +Для каждого дочернего элемента: сохраняет в "библиотекаре", создает связь в графе и передает идентификатор на следующий этап. + +### Потоки обработки + +Существуют два потока в зависимости от типа документа: + +#### Поток обработки документов PDF + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID to PDF extractor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ PDF Extractor (per page) │ +│ 1. Fetch PDF content from librarian using document ID │ +│ 2. Extract pages as text │ +│ 3. For each page: │ +│ a. Save page as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send page document ID to chunker │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch page content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = page) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + Post-chunker optimization: messages carry both + chunk ID (for provenance) and content (to avoid + librarian round-trip). Chunks are small (2-4KB). + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor (per chunk) │ +│ 1. Receive chunk ID + content directly (no librarian fetch needed) │ +│ 2. Extract facts/triples and embeddings from chunk content │ +│ 3. For each triple: │ +│ a. Emit triple to knowledge graph │ +│ b. Emit reified edge linking triple → chunk ID (edge pointing │ +│ to edge - first use of reification support) │ +│ 4. For each embedding: │ +│ a. Emit embedding with its entity ID │ +│ b. Link entity ID → chunk ID in knowledge graph │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +#### Поток текстовых документов + +Текстовые документы пропускают этап извлечения из PDF и сразу поступают в компоновщик: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID directly to chunker (skip PDF extractor) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch text content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor │ +│ (same as PDF flow) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +Полученный ориентированный ациклический граф (DAG) имеет на один уровень меньше: + +``` +PDF: Document → Pages → Chunks → Triples/Embeddings +Text: Document → Chunks → Triples/Embeddings +``` + +Дизайн учитывает оба варианта, поскольку компонент, разделяющий текст на части, обрабатывает входные данные универсально - он использует любой идентификатор документа, который он получает, в качестве родительского, независимо от того, является ли это исходным документом или страницей. + +### Схема метаданных (PROV-O) + +Метаданные происхождения используют онтологию W3C PROV-O. Это обеспечивает стандартный словарь и позволяет в будущем осуществлять подпись/аутентификацию результатов извлечения. + +#### Основные концепции PROV-O + +| Тип PROV-O | Использование в TrustGraph | +|-------------|------------------| +| `prov:Entity` | Документ, страница, фрагмент, тройка, вложение | +| `prov:Activity` | Экземпляры операций извлечения | +| `prov:Agent` | Компоненты TG (извлечение PDF, компонент, разделяющий текст на части и т.д.) с версиями | + +#### Отношения PROV-O + +| Предикат | Значение | Пример | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | Сущность, полученная из другой сущности | Страница была получена из документа | +| `prov:wasGeneratedBy` | Сущность, сгенерированная действием | Страница была сгенерирована действием извлечения PDF | +| `prov:used` | Действие, использующее сущность в качестве входных данных | Действие извлечения PDF использовало документ | +| `prov:wasAssociatedWith` | Действие, выполненное агентом | Действие извлечения PDF было связано с tg:PDFExtractor | + +#### Метаданные на каждом уровне + +**Исходный документ (генерируется Librarian):** +``` +doc:123 a prov:Entity . +doc:123 dc:title "Research Paper" . +doc:123 dc:source . +doc:123 dc:date "2024-01-15" . +doc:123 dc:creator "Author Name" . +doc:123 tg:pageCount 42 . +doc:123 tg:mimeType "application/pdf" . +``` + +**Страница (сгенерирована извлечением из PDF):** +``` +page:123-1 a prov:Entity . +page:123-1 prov:wasDerivedFrom doc:123 . +page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 . +page:123-1 tg:pageNumber 1 . + +activity:pdf-extract-456 a prov:Activity . +activity:pdf-extract-456 prov:used doc:123 . +activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor . +activity:pdf-extract-456 tg:componentVersion "1.2.3" . +activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . +``` + +**Раздел (выдан разделителем):** +``` +chunk:123-1-1 a prov:Entity . +chunk:123-1-1 prov:wasDerivedFrom page:123-1 . +chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 . +chunk:123-1-1 tg:chunkIndex 1 . +chunk:123-1-1 tg:charOffset 0 . +chunk:123-1-1 tg:charLength 2048 . + +activity:chunk-789 a prov:Activity . +activity:chunk-789 prov:used page:123-1 . +activity:chunk-789 prov:wasAssociatedWith tg:Chunker . +activity:chunk-789 tg:componentVersion "1.0.0" . +activity:chunk-789 tg:chunkSize 2048 . +activity:chunk-789 tg:chunkOverlap 200 . +``` + +**Жирный шрифт (вывод Knowledge Extractor):** +``` +# The extracted triple (edge) +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph containing the extracted triples +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 prov:wasGeneratedBy activity:extract-999 . + +activity:extract-999 a prov:Activity . +activity:extract-999 prov:used chunk:123-1-1 . +activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor . +activity:extract-999 tg:componentVersion "2.1.0" . +activity:extract-999 tg:llmModel "claude-3" . +activity:extract-999 tg:ontology . +``` + +**Встраивание (хранится в векторной базе данных, а не в тройной базе данных):** + +Встраивания хранятся в векторной базе данных вместе с метаданными, а не в виде RDF-троек. Каждая запись встраивания содержит: + +| Поле | Описание | Пример | +|-------|-------------|---------| +| vector | Вектор встраивания | [0.123, -0.456, ...] | +| entity | URI узла, который представляет встраивание | `entity:JohnSmith` | +| chunk_id | Исходный фрагмент (происхождение) | `chunk:123-1-1` | +| model | Используемая модель встраивания | `text-embedding-ada-002` | +| component_version | Версия компонента TG | `1.0.0` | + +Поле `entity` связывает встраивание с графом знаний (URI узла). Поле `chunk_id` предоставляет информацию о происхождении, указывающую на исходный фрагмент, что позволяет проследить путь до исходного документа. + +#### Расширения пространства имен TrustGraph + +Пользовательские предикаты в пространстве имен `tg:` для метаданных, специфичных для извлечения: + +| Предикат | Область | Описание | +|-----------|--------|-------------| +| `tg:contains` | Подграф | Указывает на тройку, содержащуюся в этом подграфе извлечения | +| `tg:pageCount` | Документ | Общее количество страниц в исходном документе | +| `tg:mimeType` | Документ | MIME-тип исходного документа | +| `tg:pageNumber` | Страница | Номер страницы в исходном документе | +| `tg:chunkIndex` | Фрагмент | Индекс фрагмента внутри родительского фрагмента | +| `tg:charOffset` | Фрагмент | Смещение символов в родительском тексте | +| `tg:charLength` | Фрагмент | Длина фрагмента в символах | +| `tg:chunkSize` | Действие | Настроенный размер фрагмента | +| `tg:chunkOverlap` | Действие | Настроенное перекрытие между фрагментами | +| `tg:componentVersion` | Действие | Версия компонента TG | +| `tg:llmModel` | Действие | LLM, используемый для извлечения | +| `tg:ontology` | Действие | URI онтологии, используемой для управления извлечением | +| `tg:embeddingModel` | Действие | Модель, используемая для встраиваний | +| `tg:sourceText` | Утверждение | Точный текст, из которого была извлечена тройка | +| `tg:sourceCharOffset` | Утверждение | Смещение символов внутри фрагмента, где начинается исходный текст | +| `tg:sourceCharLength` | Утверждение | Длина исходного текста в символах | + +#### Начальная загрузка словаря (для каждой коллекции) + +Граф знаний является онтологически нейтральным и изначально пуст. При первом добавлении данных о происхождении PROV-O в коллекцию словарь должен быть инициализирован с помощью RDF-меток для всех классов и предикатов. Это обеспечивает удобочитаемое отображение в запросах и пользовательском интерфейсе. + +**Классы PROV-O:** +``` +prov:Entity rdfs:label "Entity" . +prov:Activity rdfs:label "Activity" . +prov:Agent rdfs:label "Agent" . +``` + +**Предикаты PROV-O:** +``` +prov:wasDerivedFrom rdfs:label "was derived from" . +prov:wasGeneratedBy rdfs:label "was generated by" . +prov:used rdfs:label "used" . +prov:wasAssociatedWith rdfs:label "was associated with" . +prov:startedAtTime rdfs:label "started at" . +``` + +**Предикаты TrustGraph:** +``` +tg:contains rdfs:label "contains" . +tg:pageCount rdfs:label "page count" . +tg:mimeType rdfs:label "MIME type" . +tg:pageNumber rdfs:label "page number" . +tg:chunkIndex rdfs:label "chunk index" . +tg:charOffset rdfs:label "character offset" . +tg:charLength rdfs:label "character length" . +tg:chunkSize rdfs:label "chunk size" . +tg:chunkOverlap rdfs:label "chunk overlap" . +tg:componentVersion rdfs:label "component version" . +tg:llmModel rdfs:label "LLM model" . +tg:ontology rdfs:label "ontology" . +tg:embeddingModel rdfs:label "embedding model" . +tg:sourceText rdfs:label "source text" . +tg:sourceCharOffset rdfs:label "source character offset" . +tg:sourceCharLength rdfs:label "source character length" . +``` + +**Примечания по реализации:** Этот механизм начальной загрузки словаря должен быть идемпотентным, то есть его можно безопасно запускать несколько раз без создания дубликатов. Его можно запускать при первой обработке документа в коллекции или как отдельный этап инициализации коллекции. + +#### Происхождение подраздела (желательно) + +Для более детальной информации о происхождении полезно записывать, из какой именно части фрагмента была извлечена тройка. Это позволяет: + +Выделять точный исходный текст в пользовательском интерфейсе +Проверять точность извлечения по отношению к исходному тексту +Отлаживать качество извлечения на уровне предложений + +**Пример с отслеживанием позиции:** +``` +# The extracted triple +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph with sub-chunk provenance +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +subgraph:001 tg:sourceCharOffset 1547 . +subgraph:001 tg:sourceCharLength 46 . +``` + +**Пример с выделением текста (альтернативный):** +``` +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceRange "1547-1593" . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +``` + +**Соображения по реализации:** + +Извлечение на основе LLM может не всегда предоставлять информацию о позициях символов. +Можно запросить LLM, чтобы он возвращал исходное предложение/фразу вместе с извлеченными тройками. +Альтернативно, можно выполнить постобработку для сопоставления извлеченных сущностей с исходным текстом. +Компромисс между сложностью извлечения и детализацией происхождения. +Может быть проще реализовать с использованием структурированных методов извлечения, чем с использованием LLM для извлечения в свободной форме. + +Это обозначено как перспективное направление - сначала следует реализовать базовое отслеживание происхождения на уровне фрагментов, а отслеживание подфрагментов следует рассматривать как улучшение в будущем, если это будет возможно. + +### Двухуровневая модель хранения + +Граф происхождения строится постепенно по мере прохождения документов через конвейер: + +| Хранилище | Что хранится | Назначение | +|-------|---------------|---------| +| Библиотекарь | Содержимое документа + ссылки "родитель-потомок" | Извлечение содержимого, каскадное удаление | +| Граф знаний | Ребра "родитель-потомок" + метаданные | Запросы происхождения, атрибуция фактов | + +Оба хранилища поддерживают одну и ту же структуру графа. Библиотекарь хранит содержимое, а граф хранит отношения и обеспечивает возможности запросов для обхода. + +### Основные принципы проектирования + +1. **Идентификатор документа как единица потока данных** - Процессоры передают идентификаторы, а не содержимое. Содержимое извлекается из библиотеки, когда это необходимо. + +2. **Отправка данных только в исходной точке** - Метаданные записываются в граф только один раз при начале обработки, а не повторяются далее по цепочке. + +3. **Единый шаблон для процессоров** - Каждый процессор следует одному и тому же шаблону: прием/извлечение/создание/сохранение/отправка/передача. + +4. **Постепенное построение графа** - Каждый процессор добавляет свой уровень в граф. Полная цепочка происхождения строится постепенно. + +5. **Оптимизация после разбиения на фрагменты** - После разбиения на фрагменты сообщения содержат как идентификатор, так и содержимое. Фрагменты небольшие (2-4 КБ), поэтому включение содержимого позволяет избежать ненужных обращений к библиотеке, сохраняя при этом происхождение с помощью идентификатора. + +## Задачи реализации + +### Изменения в библиотеке + +#### Текущее состояние + +Инициирует обработку документа, отправляя идентификатор документа первому процессору. +Нет подключения к хранилищу тройных данных - метаданные добавляются к результатам извлечения. +`add-child-document` создает одноуровневые ссылки "родитель-потомок". +`list-children` возвращает только непосредственные потомки. + +#### Необходимые изменения + +**1. Новый интерфейс: Подключение к хранилищу тройных данных** + +Библиотекарь должен напрямую отправлять ребра метаданных документа в граф знаний при начале обработки. +Добавить клиент/публикатор хранилища тройных данных в сервис библиотеки. +При инициации обработки: отправлять метаданные корневого документа в виде ребер графа (один раз). + +**2. Словарь типов документов** + +Стандартизировать значения `document_type` для дочерних документов: +`source` - исходный загруженный документ. +`page` - страница, извлеченная из источника (PDF и т.д.). +`chunk` - текстовый фрагмент, полученный из страницы или источника. + +#### Краткое описание изменений интерфейса + +| Интерфейс | Изменение | +|-----------|--------| +| Хранилище тройных данных | Новый исходящий канал - отправка ребер метаданных документа | +| Инициация обработки | Отправка метаданных в граф перед передачей идентификатора документа | + +### Изменения в извлечении данных из PDF + +#### Текущее состояние + +Получает содержимое документа (или потоковую передачу больших документов). +Извлекает текст из страниц PDF. +Передает содержимое страницы в компоновщик. +Не взаимодействует с библиотекой или хранилищем тройных данных. + +#### Необходимые изменения + +**1. Новый интерфейс: Клиент библиотеки** + +Извлечение данных из PDF должно сохранять каждую страницу как дочерний документ в библиотеке. +Добавить клиент библиотеки в сервис извлечения данных из PDF. +Для каждой страницы: вызвать `add-child-document` с parent = идентификатор корневого документа. + +**2. Новый интерфейс: Подключение к хранилищу тройных данных** + +Извлечение данных из PDF должно отправлять ребра "родитель-потомок" в граф знаний. +Добавить клиент/публикатор хранилища тройных данных. +Для каждой страницы: отправлять ребро, связывающее документ страницы с родительским документом. + +**3. Изменить формат вывода** + +Вместо прямой передачи содержимого страницы, передавайте идентификатор документа страницы. +Chunker будет извлекать содержимое из хранилища, используя идентификатор. + +#### Краткое описание изменений интерфейса + +| Интерфейс | Изменение | +|-----------|--------| +| Хранилище | Новый исходящий поток - сохранение дочерних документов | +| Тройной магазин | Новый исходящий поток - генерация связей родитель-потомок | +| Сообщение вывода | Изменение с содержимого на идентификатор документа | + +### Изменения Chunker + +#### Текущее состояние + +Получает содержимое страницы/текста +Разбивает на фрагменты +Передает содержимое фрагмента обработчикам на последующих этапах +Не взаимодействует с хранилищем или тройным магазином + +#### Необходимые изменения + +**1. Изменение обработки входных данных** + +Вместо содержимого получайте идентификатор документа, извлекайте из хранилища. +Добавьте клиент хранилища в сервис Chunker +Извлекайте содержимое страницы, используя идентификатор документа + +**2. Новый интерфейс: Клиент хранилища (запись)** + +Сохраняйте каждый фрагмент как дочерний документ в хранилище. +Для каждого фрагмента: вызывайте `add-child-document` с parent = идентификатор документа страницы + +**3. Новый интерфейс: Подключение к тройному магазину** + +Генерируйте связи родитель-потомок для графа знаний. +Добавьте клиент/публикатор тройного магазина +Для каждого фрагмента: генерируйте связь, связывающую документ фрагмента с документом страницы + +**4. Изменение формата вывода** + +Передавайте как идентификатор документа фрагмента, так и содержимое фрагмента (оптимизация после обработки фрагмента). +Обработчики на последующих этапах получают идентификатор для отслеживания происхождения + содержимое для работы + +#### Краткое описание изменений интерфейса + +| Интерфейс | Изменение | +|-----------|--------| +| Сообщение ввода | Изменение с содержимого на идентификатор документа | +| Хранилище | Новый исходящий поток (чтение + запись) - извлечение содержимого, сохранение дочерних документов | +| Тройной магазин | Новый исходящий поток - генерация связей родитель-потомок | +| Сообщение вывода | Изменение с содержимого только на идентификатор + содержимое | + +### Изменения Knowledge Extractor + +#### Текущее состояние + +Получает содержимое фрагмента +Извлекает тройки и вложения +Передает в тройной магазин и хранилище вложений +`subjectOf` отношение указывает на верхний уровень документа (а не на фрагмент) + +#### Необходимые изменения + +**1. Изменение обработки входных данных** + +Получайте идентификатор фрагмента вместе с содержимым. +Используйте идентификатор фрагмента для отслеживания происхождения (содержимое уже включено в соответствии с оптимизацией) + +**2. Обновление отслеживания происхождения тройками** + +Связывайте извлеченные тройки с фрагментом (а не с верхним уровнем документа). +Используйте реификацию для создания связи, указывающей на связь +`subjectOf` отношение: тройка → идентификатор документа фрагмента +Первое использование существующей поддержки реификации + +**3. Обновление отслеживания происхождения вложениями** + +Связывайте идентификаторы сущностей вложений с фрагментом. +Генерируйте связь: идентификатор сущности вложения → идентификатор документа фрагмента + +#### Краткое описание изменений интерфейса + +| Интерфейс | Изменение | +|-----------|--------| +| Сообщение ввода | Ожидается идентификатор фрагмента + содержимое (а не только содержимое) | +| Тройной магазин | Используйте реификацию для отслеживания происхождения тройки → фрагмент | +| Отслеживание происхождения вложениями | Свяжите идентификатор сущности → идентификатор фрагмента | + +## Ссылки + +Отслеживание происхождения во время запроса: `docs/tech-specs/query-time-provenance.md` +Стандарт PROV-O для моделирования происхождения +Существующие метаданные источника в графе знаний (требуется аудит) diff --git a/docs/tech-specs/extraction-time-provenance.sw.md b/docs/tech-specs/extraction-time-provenance.sw.md new file mode 100644 index 00000000..a52613ff --- /dev/null +++ b/docs/tech-specs/extraction-time-provenance.sw.md @@ -0,0 +1,619 @@ +# Asili ya Data Wakati wa Utoaji: Safu ya Chanzo + +## Muhtasari + +Hati hii ina rekodi za maelezo kuhusu asili ya data wakati wa utoaji kwa ajili ya kazi ya maelezo ya baadaye. Asili ya data wakati wa utoaji inarejelea "safu ya chanzo" - ambako data ilitoka awali, jinsi ilivyochukuliwa na kubadilishwa. + +Hii ni tofauti na asili ya data wakati wa kuulizia (angalia `query-time-provenance.md`) ambayo inarejelea utaratibu wa akili wa mhusika. + +## Tatizo + +### Utendaji wa Sasa + +Hivi sasa, asili ya data inafanya kazi kama ifuatavyo: +Meta-data ya hati huhifadhiwa kama triple za RDF katika grafu ya maarifa. +Kitambulisho cha hati huunganisha meta-data na hati, hivyo hati inaonekana kama node katika grafu. +Wakati uhusiano (maelezo/ukweli) unachukuliwa kutoka kwa hati, uhusiano wa `subjectOf` huunganisha uhusiano uliochukuliwa na hati ya chanzo. + +### Matatizo ya Mbinu ya Sasa + +1. **Upakiaji wa meta-data unaorudia:** Meta-data ya hati huunganishwa na kupakiwa mara kwa mara na kila kundi la triple zilizochukuliwa kutoka kwa hati hiyo. Hii ni matumizi ya rasilimali na kurudia - meta-data sawa husafiri kama mizigo na kila pato la utoaji. + +2. **Asili ya data ya juu:** Uhusiano wa `subjectOf` wa sasa huunganisha tu ukweli moja kwa moja na hati ya juu. Hakuna uonevu katika mnyororo wa mabadiliko - ukweli huo ulichukuliwa kutoka kwa ukurasa gani, sehemu gani, mbinu gani ya utoaji iliyotumika. + +### Hali Inayotakikana + +1. **Pakia meta-data mara moja:** Meta-data ya hati inapaswa kupakiwa mara moja na kuunganishwa na node ya juu ya hati, sio kurudiwa na kila kundi la triple. + +2. **Grafu ya asili ya data iliyo na maelezo:** Rekodi mnyororo kamili wa mabadiliko kutoka kwa hati ya chanzo hadi kwa vitu vyote vya kati hadi kwa ukweli uliopatikana. Kwa mfano, mabadiliko ya hati ya PDF: + + ``` + PDF file (source document with metadata) + → Page 1 (decoded text) + → Chunk 1 + → Extracted edge/fact (via subjectOf) + → Extracted edge/fact + → Chunk 2 + → Extracted edge/fact + → Page 2 + → Chunk 3 + → ... + ``` + +3. **Hifadhi iliyounganishwa:** Mfumo wa uhusiano wa asili (provenance DAG) huhifadhiwa katika mfumo sawa wa maarifa kama maarifa yaliyopatikana. Hii inaruhusu uhusiano wa asili kuchunguzwa kwa njia ile ile kama maarifa - kufuata miundo kurudi nyuma kutoka kwa ukweli wowote hadi mahali pake halisi. + +4. **Kitambulisho cha kudumu:** Kila kitu (artifact) cha kati (ukurasa, sehemu) kina kitambulisho cha kudumu kama node katika mfumo. + +5. **Uunganisho wa mzazi-mtoto:** Hati zilizoundwa zinaunganishwa na wazazi wao hadi kwenye hati ya asili ya juu kwa kutumia aina za uhusiano sawa. + +6. **Uhusiano sahihi wa ukweli:** Uhusiano wa `subjectOf` kwenye miundo iliyopatikana unaelekeza kwenye mzazi wa karibu (sehemu), sio kwenye hati ya juu. Uhusiano wa asili kamili hupatikana kwa kutembea juu ya DAG. + +## Matumizi + +### UC1: Uhusiano wa Chanzo katika Majibu ya GraphRAG + +**Hali:** Mtumiaji hufanya swali la GraphRAG na kupokea jibu kutoka kwa programu (agent). + +**Mchakato:** +1. Mtumiaji huwasilisha swali kwa programu ya GraphRAG. +2. Programu inapata ukweli unaohusiana kutoka kwa mfumo wa maarifa ili kuunda jibu. +3. Kulingana na vipimo vya uhusiano wa asili wakati wa swali, programu huripoti ukweli ambao ulichangia jibu. +4. Kila ukweli unaunganishwa na sehemu yake ya asili kupitia mfumo wa uhusiano wa asili. +5. Sehemu zinaunganishwa na kurasa, kurasa zinaunganishwa na hati za asili. + +**Matokeo ya Uzoefu wa Mtumiaji (UX):** Kiolesura huonyesha jibu la LLM pamoja na uhusiano wa chanzo. Mtumiaji anaweza: +Kuona ukweli ambao uliunga mkono jibu. +Kuchunguza kutoka kwa ukweli → sehemu → kurasa → hati. +Kusoma hati za asili ili kuthibitisha madai. +Kuelewa hasa wapi katika hati (ukurasa gani, sehemu gani) ukweli ulitoka. + +**Faida:** Watumiaji wanaweza kuthibitisha majibu yaliyozalishwa na AI dhidi ya vyanzo vya msingi, kuunda uaminifu na kuwezesha ukaguzi wa ukweli. + +### UC2: Kurekebisha Ubora wa Upatikanaji + +Ukweli unaonekana kuwa mbaya. Tembelea kurudi nyuma kupitia sehemu → ukurasa → hati ili kuona maandishi ya asili. Je, ilikuwa upatikanaji mbaya, au chanzo kilikuwa kibaya? + +### UC3: Upatikanaji wa Kurekebishwa + +Hati ya asili inasasishwa. Ni sehemu/ukweli gani uliotokana nayo? Ghairi na uundue tena tu zile, badala ya kuchakata kila kitu. + +### UC4: Ufutilishaji wa Data / Haki ya Kusahau + +Hati ya asili lazima iondolewe (GDPR, kisheria, n.k.). Tembelea DAG ili kupata na kuondoa ukweli wote uliotokana. + +### UC5: Suluhisho la Mzozo + +Ushawishi mbili unapingana. Tembelea zote kurudi kwenye vyanzo vyao ili kuelewa kwa nini na uamue ni ipi ya kuamini (chanzo cha mamlaka zaidi, cha hivi karibuni, n.k.). + +### UC6: Uzito wa Uamuzi wa Chanzo + +Vyanzo vingine ni vya mamlaka kuliko vingine. Ushawishi unaweza kupimwa au kuchujwa kulingana na uamuzi/ubora wa hati zao za asili. + +### UC7: Ulinganisho wa Mfumo wa Upatikanaji + +Linganisha matokeo kutoka kwa mbinu/matoleo tofauti ya upatikanaji. Mfumo wa upatikanaji upi uliunda ukweli bora kutoka kwa chanzo kimoja? + +## Maeneo ya Uunganisho + +### Msimamizi wa Maktaba + +Kifaa cha msimamizi wa maktaba hutoa tayari uhifadhi wa hati na kitambulisho cha kipekee cha hati. Mfumo wa asili unajumuishwa na miundombinu hii iliyopo. + +#### Uwezo Ulioopo (tayari umetekelezwa) + +**Uunganisho wa Hati ya Mzazi-Mtoto:** +`parent_id` field katika `DocumentMetadata` - huunganisha hati ya mtoto na hati ya mzazi +`document_type` field - maadili: `"source"` (asili) au `"extracted"` (iliyotokana) +`add-child-document` API - huunda hati ya mtoto na `document_type = "extracted"` moja kwa moja +`list-children` API - hurudisha hati zote za watoto za hati ya mzazi +Ufutilishaji wa mfuatano - kuondoa hati ya mzazi huondoa moja kwa moja hati zote za watoto + +**Kitambulisho cha Hati:** +Kitambulisho cha hati huamuliwa na mteja (hayajaumbwa kiotomatiki) +Hati zimepangwa kwa `(user, document_id)` iliyounganishwa katika Cassandra +Kitambulisho cha kitu (UUIDs) huundwa ndani kwa uhifadhi wa blob + +**Usaidizi wa MetaData:** +`metadata: list[Triple]` field - triples za RDF kwa metaData iliyopangwa +`title`, `comments`, `tags` - metaData ya msingi ya hati +`time` - wakati, `kind` - aina ya MIME + +**Muundo wa Uhifadhi:** +MetaData huhifadhiwa katika Cassandra (`librarian` keyspace, `document` meza) +Yaliyomo huhifadhiwa katika uhifadhi wa blob wa MinIO/S3 (`library` ndoo) +Uwasilishaji mahiri wa yaliyomo: hati < 2MB zimejumuishwa, hati kubwa zaidi hutiririshwa + +#### Faili Muhimu + +`trustgraph-flow/trustgraph/librarian/librarian.py` - Operesheni muhimu za msimamizi wa maktaba +`trustgraph-flow/trustgraph/librarian/service.py` - Mchakato wa huduma, upakaji hati +`trustgraph-flow/trustgraph/tables/library.py` - Duka la meza ya Cassandra +`trustgraph-base/trustgraph/schema/services/library.py` - Ufafanuzi wa mpango + +#### Mapungufu Yanayohitaji Kusuluhishwa + +Msimamizi wa maktaba una vipengele muhimu lakini kwa sasa: +1. Uunganisho wa mzazi-mtoto ni safu moja tu - hakuna msaada wa utambuzi wa DAG wa ngazi nyingi +2. Hakuna hesabu ya kawaida ya aina ya uhusiano (e.g., `derivedFrom`, `extractedFrom`) +3. MetaData ya asili (mbinu ya uondoaji, uaminifu, nafasi ya kipande) hayajaainishwa +4. Hakuna API ya kuuliza ili kutambua mnyororo kamili wa asili kutoka kwa ukweli hadi chanzo + +## Muundo wa Mtiririko wa Utoaji hadi Utoaji + +Kila mchakato katika mstari huu unafuata mfumo unaoendana: +Kupokea kitambulisho cha hati kutoka kwa chanzo +Kuchukua yaliyomo kutoka kwa msimamizi wa maktaba +Kutoa vifaa vya watoto +Kwa kila mtoto: kuhifadhi kwenye msimamizi wa maktaba, kutuma upau kwenye grafu, kusonga kitambulisho mbele + +### Mitiririko ya Uendeshaji + +Kuna mitiririko miwili kulingana na aina ya hati: + +#### Mtiririko wa Hati ya PDF + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID to PDF extractor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ PDF Extractor (per page) │ +│ 1. Fetch PDF content from librarian using document ID │ +│ 2. Extract pages as text │ +│ 3. For each page: │ +│ a. Save page as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send page document ID to chunker │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch page content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = page) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + Post-chunker optimization: messages carry both + chunk ID (for provenance) and content (to avoid + librarian round-trip). Chunks are small (2-4KB). + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor (per chunk) │ +│ 1. Receive chunk ID + content directly (no librarian fetch needed) │ +│ 2. Extract facts/triples and embeddings from chunk content │ +│ 3. For each triple: │ +│ a. Emit triple to knowledge graph │ +│ b. Emit reified edge linking triple → chunk ID (edge pointing │ +│ to edge - first use of reification support) │ +│ 4. For each embedding: │ +│ a. Emit embedding with its entity ID │ +│ b. Link entity ID → chunk ID in knowledge graph │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +#### Mtiririko wa Nyaraka za Nakshata + +Nyaraka za nakshata huenda moja kwa moja kwenye sehemu ya "chunker" na hazitumii programu ya kutenganisha faili za PDF: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID directly to chunker (skip PDF extractor) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch text content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor │ +│ (same as PDF flow) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +DAG iliyotokea ni ya kiwango kimoja chini: + +``` +PDF: Document → Pages → Chunks → Triples/Embeddings +Text: Document → Chunks → Triples/Embeddings +``` + +Ubunifu unaoendana na matumizi ya aina zote, kwa sababu mfumo wa kugawanya (chunker) hutumia data yake ya pembejeo kwa njia ya jumla - hutumia kitambulisho chochote cha hati kinachopokelewa kama mzazi, bila kujali kama hiyo ni hati ya asili au ukurasa. + +### Mpango wa Meta-data (PROV-O) + +Meta-data ya asili hutumia ontolojia ya W3C PROV-O. Hii hutoa msamiati wa kawaida na inawezesha usaini/uthibitishaji wa matokeo ya utoaji katika siku zijazo. + +### Dhana Zikuu za PROV-O + +| Aina ya PROV-O | Matumizi katika TrustGraph | +|-------------|------------------| +| `prov:Entity` | Hati, Ukurasa, Sehemu, Triple, Uingizwaji | +| `prov:Activity` | Mifano ya operesheni za utoaji | +| `prov:Agent` | Vipengele vya TG (mfumo wa utoaji wa PDF, mfumo wa kugawanya, n.k.) pamoja na matoleo | + +### Mahusiano ya PROV-O + +| Kifurushi | Maana | Mfano | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | Kitu kinachotokana na kitu kingine | Ukurasa ulikuwa umetokana na Hati | +| `prov:wasGeneratedBy` | Kitu kilichoundwa na shughuli | Ukurasa ulikuwa umelindwa na Shughuli ya Utoaji wa PDF | +| `prov:used` | Shughuli ilitumia kitu kama pembejeo | Shughuli ya Utoaji wa PDF ilitumia Hati | +| `prov:wasAssociatedWith` | Shughuli ilifanywa na wakala | Shughuli ya Utoaji wa PDF ilihusishwa na tg:PDFExtractor | + +### Meta-data katika Kila Ngazi + +**Hati ya Asili (inatoolewa na Librarian):** +``` +doc:123 a prov:Entity . +doc:123 dc:title "Research Paper" . +doc:123 dc:source . +doc:123 dc:date "2024-01-15" . +doc:123 dc:creator "Author Name" . +doc:123 tg:pageCount 42 . +doc:123 tg:mimeType "application/pdf" . +``` + +**Ukurasa (uliochukuliwa na programu ya kuchambua faili za PDF):** +``` +page:123-1 a prov:Entity . +page:123-1 prov:wasDerivedFrom doc:123 . +page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 . +page:123-1 tg:pageNumber 1 . + +activity:pdf-extract-456 a prov:Activity . +activity:pdf-extract-456 prov:used doc:123 . +activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor . +activity:pdf-extract-456 tg:componentVersion "1.2.3" . +activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . +``` + +**Sehemu (imetolewa na Chunker):** +``` +chunk:123-1-1 a prov:Entity . +chunk:123-1-1 prov:wasDerivedFrom page:123-1 . +chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 . +chunk:123-1-1 tg:chunkIndex 1 . +chunk:123-1-1 tg:charOffset 0 . +chunk:123-1-1 tg:charLength 2048 . + +activity:chunk-789 a prov:Activity . +activity:chunk-789 prov:used page:123-1 . +activity:chunk-789 prov:wasAssociatedWith tg:Chunker . +activity:chunk-789 tg:componentVersion "1.0.0" . +activity:chunk-789 tg:chunkSize 2048 . +activity:chunk-789 tg:chunkOverlap 200 . +``` + +**Tatu (imetolewa na Mvumbuzi wa Maarifa):** +``` +# The extracted triple (edge) +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph containing the extracted triples +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 prov:wasGeneratedBy activity:extract-999 . + +activity:extract-999 a prov:Activity . +activity:extract-999 prov:used chunk:123-1-1 . +activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor . +activity:extract-999 tg:componentVersion "2.1.0" . +activity:extract-999 tg:llmModel "claude-3" . +activity:extract-999 tg:ontology . +``` + +**Uingizwaji (hifadhiwa katika hifadhi ya vekta, sio hifadhi ya triple):** + +Uingizwaji huhifadhiwa katika hifadhi ya vekta pamoja na metadata, sio kama triple za RDF. Kila rekodi ya uingizwaji ina: + +| Nguvu | Maelezo | Mfano | +|-------|-------------|---------| +| vekta | Vektali ya uingizwaji | [0.123, -0.456, ...] | +| kitu | URI ya node ambayo uingizwaji unawakilisha | `entity:JohnSmith` | +| kitambulisho_cha_sehemu | Sehemu ya asili (asili) | `chunk:123-1-1` | +| mfumo | Mfumo wa uingizwaji uliotumika | `text-embedding-ada-002` | +| toleo_la_komponenti | Toleo la programu ya uingizwaji | `1.0.0` | + +Nguvu ya `entity` huunganisha uingizwaji na grafu ya maarifa (URI ya node). Nguvu ya `chunk_id` hutoa asili kurudi kwa sehemu ya asili, na kuwezesha ufuatiliaji hadi kwenye hati asili. + +#### Miondoko ya Jina ya TrustGraph + +Maneno maalum chini ya nafasi ya `tg:` kwa metadata maalum ya uondoaji: + +| Neno | Doman | Maelezo | +|-----------|--------|-------------| +| `tg:contains` | Subgraph | Inaashiria triple iliyo ndani ya subgraph hii ya uondoaji | +| `tg:pageCount` | Hati | Idadi jumla ya kurasa katika hati ya asili | +| `tg:mimeType` | Hati | Aina ya MIME ya hati ya asili | +| `tg:pageNumber` | Ukurasa | Namba ya ukurasa katika hati ya asili | +| `tg:chunkIndex` | Sehemu | Index ya sehemu ndani ya sehemu ya wazazi | +| `tg:charOffset` | Sehemu | Marekebisho ya herufi katika maandishi ya wazazi | +| `tg:charLength` | Sehemu | Urefu wa sehemu katika herufi | +| `tg:chunkSize` | Shughuli | Ukubwa uliopangwa wa sehemu | +| `tg:chunkOverlap` | Shughuli | Ulinganishi kati ya sehemu | +| `tg:componentVersion` | Shughuli | Toleo la komponenti ya TG | +| `tg:llmModel` | Shughuli | LLM iliyotumika kwa uondoaji | +| `tg:ontology` | Shughuli | Ontology iliyotumika kuongoza uondoaji | +| `tg:embeddingModel` | Shughuli | Mfumo uliotumika kwa uingizwaji | +| `tg:sourceText` | Tamko | Nakala kamili kutoka ambayo triple iliondolewa | +| `tg:sourceCharOffset` | Tamko | Marekebisho ya herufi ndani ya sehemu ambapo nakala ya asili huanza | +| `tg:sourceCharLength` | Tamko | Urefu wa nakala ya asili katika herufi | + +#### Uanzishaji wa Dhana (Kwa Mkusanyiko Kila Kila) + +Grafu ya maarifa ni ya aina ya ontology na inaanzishwa kuwa tupu. Wakati wa kuandika data ya asili ya PROV-O kwa mkusanyiko kwa mara ya kwanza, dhana lazima ianzishwe na lebo za RDF kwa madarasa na maneno yote. Hii inahakikisha onyesho linalosoma kwa binadamu katika maswali na UI. + +**Madarasa ya PROV-O:** +``` +prov:Entity rdfs:label "Entity" . +prov:Activity rdfs:label "Activity" . +prov:Agent rdfs:label "Agent" . +``` + +**Predikati za PROV-O:** +``` +prov:wasDerivedFrom rdfs:label "was derived from" . +prov:wasGeneratedBy rdfs:label "was generated by" . +prov:used rdfs:label "used" . +prov:wasAssociatedWith rdfs:label "was associated with" . +prov:startedAtTime rdfs:label "started at" . +``` + +**Predikatendi za TrustGraph:** +``` +tg:contains rdfs:label "contains" . +tg:pageCount rdfs:label "page count" . +tg:mimeType rdfs:label "MIME type" . +tg:pageNumber rdfs:label "page number" . +tg:chunkIndex rdfs:label "chunk index" . +tg:charOffset rdfs:label "character offset" . +tg:charLength rdfs:label "character length" . +tg:chunkSize rdfs:label "chunk size" . +tg:chunkOverlap rdfs:label "chunk overlap" . +tg:componentVersion rdfs:label "component version" . +tg:llmModel rdfs:label "LLM model" . +tg:ontology rdfs:label "ontology" . +tg:embeddingModel rdfs:label "embedding model" . +tg:sourceText rdfs:label "source text" . +tg:sourceCharOffset rdfs:label "source character offset" . +tg:sourceCharLength rdfs:label "source character length" . +``` + +**Kumbukumbu kuhusu utekelezaji:** Kamusi hii ya kuanzia inapaswa kuwa ya aina ambayo inaweza kuendeshwa mara nyingi bila kuunda nakala. Inaweza kuanzishwa wakati wa usindikaji wa hati ya kwanza katika mkusanyiko, au kama hatua tofauti ya uanzishaji wa mkusanyiko. + +#### Asili ya Sehemu Ndogo (Lengo) + +Kwa asili ya kina zaidi, itakuwa muhimu kurekodi hasa katika sehemu gani ya kipande ambapo triple ilitokana. Hii inaruhusu: + +Kuonyesha maandishi ya asili hasa katika kiolesura (UI) +Kuthibitisha usahihi wa uondoaji dhidi ya asili +Kuchunguza ubora wa uondoaji katika kiwango cha sentensi + +**Mfano na ufuatiliaji wa nafasi:** +``` +# The extracted triple +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph with sub-chunk provenance +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +subgraph:001 tg:sourceCharOffset 1547 . +subgraph:001 tg:sourceCharLength 46 . +``` + +**Mfano na sehemu ya maandishi (badala):** +``` +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceRange "1547-1593" . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +``` + +**Mazingatio ya utekelezaji:** + +Utaratibu wa kutolea maelezo unaotegemea modeli ya lugha (LLM) huenda usitoe nafasi za herufi kwa kawaida. +Inaweza kuwezekana kuomba LLM irudishe sentensi/maneno ya asili pamoja na vitu vilivyotolewa. +Badala yake, inaweza kufanywa urekebishaji wa ziada ili kulinganisha vitu vilivyotolewa na maandishi ya asili. +Kuna mtego kati ya utata wa utoleaji wa maelezo na kiwango cha uhakikisho. +Inaweza kuwa rahisi kufanikisha kwa kutumia mbinu zilizopangwa kuliko utoleaji wa maelezo wa aina huru unaotegemea LLM. + +Hii imewekwa kama lengo la baadaye - uhakikisho wa kimsingi wa kiwango cha sehemu unapaswa kutekelezwa kwanza, na kufuatilia kwa sehemu ndogo kama uboreshaji wa baadaye ikiwa inawezekana. + +### Mfumo wa Uhifadhi Mkubwa + +Mfumo wa uhakikisho unajengwa hatua kwa hatua wakati hati zinapopitia katika mchakato: + +| Hifadhi | Kile kinachohifadhiwa | Madhumuni | +|-------|---------------|---------| +| Msimamizi | Yaliyomo ya hati + viungo vya mzazi-mtoto | Kupata yaliyomo, kufuta kwa mfuatano | +| Grafu ya Maarifa | Miunganisho ya mzazi-mtoto + metadata | Maswali ya uhakikisho, utambuzi wa ukweli | + +Hifadhi zote mbili zinahifadhi muundo sawa wa DAG. Msimamizi huhifadhi yaliyomo; grafu huhifadhi uhusiano na inaruhusu maswali ya utaftaji. + +### Kanuni Muhimu za Ubunifu + +1. **Kitambulisho cha hati kama kitengo cha mchakato** - Wasindikaji hupitisha vitambulisho, sio yaliyomo. Yaliyomo hupatikana kutoka kwa msimamizi wakati inahitajika. + +2. **Tolea mara moja katika chanzo** - Metadata imeandikwa kwenye grafu mara moja wakati wa mchakato unaanza, sio kurudiwa baadaye. + +3. **Mfumo sawa wa wasindikaji** - Kila wasindikaji hufuata muundo sawa wa kupokea/kupata/kutoa/kuokoa/kutoa/kusonga. + +4. **Ujenzi wa hatua kwa hatua wa DAG** - Kila wasindikaji huongeza kiwango chake kwenye DAG. Mnyororo kamili wa uhakikisho unajengwa hatua kwa hatua. + +5. **Uboreshaji baada ya kugawanyika** - Baada ya kugawanyika, ujumbe unaambatana na kitambulisho na yaliyomo. Sehemu ndogo (2-4KB), kwa hivyo kuingiza yaliyomo inazuia safari zisizo za lazima za msimamizi wakati inahifadhi uhakikisho kupitia kitambulisho. + +## Majukumu ya Utekelezaji + +### Marekebisho ya Msimamizi + +#### Hali ya Sasa + +Inaanzisha mchakato wa hati kwa kutuma kitambulisho cha hati kwa wasindikaji wa kwanza. +Hakuna muunganisho na duka la vitriple - metadata huunganishwa na matokeo ya utoleaji. +`add-child-document` huunda viungo vya mzazi-mtoto vya kiwango kimoja. +`list-children` hurudisha watoto wa karibu tu. + +#### Marekebisho Yanayohitajika + +**1. Kiolesura kipya: Muunganisho wa duka la vitriple** + +Msimamizi anahitaji kutoa kingo za metadata ya hati moja kwa moja kwenye grafu ya maarifa wakati wa kuanzisha mchakato. +Ongeza mteja/mpublisher wa duka la vitriple kwenye huduma ya msimamizi. +Wakati wa kuanzisha mchakato: toa metadata ya hati ya mizizi kama kingo za grafu (mara moja). + +**2. Hesabu ya aina ya hati** + +Sanidi maadili ya `document_type` kwa watoto wa hati: +`source` - hati iliyopakiwa asili. +`page` - ukurasa uliotolewa kutoka chanzo (PDF, n.k.). +`chunk` - sehemu ya maandishi iliyotokana na ukurasa au chanzo. + +#### Muhtasari wa Marekebisho ya Kiolesura + +| Kiolesura | Marekebisho | +|-----------|--------| +| Duka la vitriple | Muunganisho mpya wa kutoka nje - toa kingo za metadata ya hati | +| Kuanzisha mchakato | Toa metadata kwenye grafu kabla ya kusonga kitambulisho cha hati | + +### Marekebisho ya Mtoa Hati ya PDF + +#### Hali ya Sasa + +Hupokea yaliyomo ya hati (au mitiririko ya hati kubwa). +Hutolea maandishi kutoka kwa kurasa za PDF. +Hupeleka yaliyomo ya ukurasa kwa mtoa sehemu. +Hakuna mwingiliano na msimamizi au duka la vitriple. + +#### Marekebisho Yanayohitajika + +**1. Kiolesura kipya: Mteja wa msimamizi** + +Mtoa hati ya PDF anahitaji kuhifadhi kila ukurasa kama hati ya mtoto katika msimamizi. +Ongeza mteja wa msimamizi kwenye huduma ya mtoa hati ya PDF. +Kwa kila ukurasa: piga `add-child-document` na mzazi = kitambulisho cha hati ya mizizi. + +**2. Kiolesura kipya: Muunganisho wa duka la vitriple** + +Mtoa hati ya PDF anahitaji kutoa kingo za mzazi-mtoto kwenye grafu ya maarifa. +Ongeza mteja/mpublisher wa duka la vitriple. +Kwa kila ukurasa: toa kingo inayounganisha hati ya ukurasa na hati ya mzazi. + +**3. Badilisha muundo wa matokeo** + +Badala ya kusambaza yaliyomo ya ukurasa moja kwa moja, sambaza kitambulisho cha hati ya ukurasa. +Chunker itapata yaliyomo kutoka kwa 'librarian' kwa kutumia kitambulisho. + +#### Muhtasari wa Mabadiliko ya Kiolesura + +| Kiolesura | Mabadiliko | +|-----------|--------| +| Librarian | Mabadiliko mapya ya kutoka - hifadhi hati za watoto | +| Hifadhi tatu | Mabadiliko mapya ya kutoka - toka miunganisho ya mzazi-mtoto | +| Ujumbe wa pato | Mabadiliko kutoka yaliyomo hadi kitambulisho cha hati | + +### Mabadiliko ya Chunker + +#### Hali ya Sasa + +Yanapokea yaliyomo ya ukurasa/maandishi +Yanagawanyika katika sehemu ndogo +Yanatuma yaliyomo ya sehemu ndogo kwa wasindikaji wa baadaye +Hakuna mwingiliano na 'librarian' au hifadhi tatu + +#### Mabadiliko Yanayohitajika + +**1. Badilisha utunzaji wa ingizo** + +Pokea kitambulisho cha hati badala ya yaliyomo, pata kutoka kwa 'librarian'. +Ongeza mteja wa 'librarian' kwenye huduma ya chunker +Pata yaliyomo ya ukurasa kwa kutumia kitambulisho cha hati + +**2. Kiolesura kipya: Mteja wa 'Librarian' (kuandika)** + +Hifadhi kila sehemu ndogo kama hati ya mtoto katika 'librarian'. +Kwa kila sehemu ndogo: piga simu `add-child-document` na mzazi = kitambulisho cha hati ya ukurasa + +**3. Kiolesura kipya: Muunganisho wa hifadhi tatu** + +Toa miunganisho ya mzazi-mtoto kwa grafu ya maarifa. +Ongeza mteja/mpublisher wa hifadhi tatu +Kwa kila sehemu ndogo: toa muunganiko unaounganisha hati ya sehemu ndogo na hati ya ukurasa + +**4. Badilisha muundo wa pato** + +Sambaza kitambulisho cha hati ya sehemu ndogo na yaliyomo ya sehemu ndogo (uboreshaji wa baada ya chunker). +Wasindikaji wa baadaye hupokea kitambulisho kwa ajili ya asili + yaliyomo ili kufanya kazi nayo + +#### Muhtasari wa Mabadiliko ya Kiolesura + +| Kiolesura | Mabadiliko | +|-----------|--------| +| Ujumbe wa ingizo | Mabadiliko kutoka yaliyomo hadi kitambulisho cha hati | +| Librarian | Mabadiliko mapya ya kutoka (kusoma + kuandika) - pata yaliyomo, hifadhi hati za watoto | +| Hifadhi tatu | Mabadiliko mapya ya kutoka - toa miunganisho ya mzazi-mtoto | +| Ujumbe wa pato | Mabadiliko kutoka yaliyomo-tu hadi kitambulisho + yaliyomo | + +### Mabadiliko ya Mvumbuzi wa Maarifa + +#### Hali ya Sasa + +Yanapokea yaliyomo ya sehemu ndogo +Yanatoa triples na embeddings +Yanatoa kwa hifadhi ya triples na hifadhi ya embeddings +`subjectOf` uhusiano unaelekeza kwenye hati ya juu (si sehemu ndogo) + +#### Mabadiliko Yanayohitajika + +**1. Badilisha utunzaji wa ingizo** + +Pokea kitambulisho cha hati ya sehemu ndogo pamoja na yaliyomo. +Tumia kitambulisho cha sehemu ndogo kwa ulinganisho (yaliyomo tayari yamejumuishwa kwa uboreshaji) + +**2. Sasisha asili ya triples** + +Unganisha triples zilizotolewa na sehemu ndogo (si hati ya juu). +Tumia reification ili kuunda muunganiko unaoelekeza kwenye muunganiko +`subjectOf` uhusiano: triple → kitambulisho cha hati ya sehemu ndogo +Matumizi ya kwanza ya msaada uliopo wa reification + +**3. Sasisha asili ya embeddings** + +Unganisha kitambulisho cha entiti ya embedding na sehemu ndogo. +Toa muunganiko: kitambulisho cha entiti ya embedding → kitambulisho cha hati ya sehemu ndogo + +#### Muhtasari wa Mabadiliko ya Kiolesura + +| Kiolesura | Mabadiliko | +|-----------|--------| +| Ujumbe wa ingizo | Inatarajia kitambulisho cha sehemu ndogo + yaliyomo (si yaliyomo tu) | +| Hifadhi tatu | Tumia reification kwa asili ya triple → sehemu | +| Asili ya embedding | Unganisha kitambulisho cha entiti → kitambulisho cha sehemu | + +## Marejeleo + +Asili ya wakati wa swali: `docs/tech-specs/query-time-provenance.md` +Kiwango cha PROV-O kwa uundaji wa asili +Meta-data ya chanzo iliyopo katika grafu ya maarifa (inahitaji ukaguzi) diff --git a/docs/tech-specs/extraction-time-provenance.tr.md b/docs/tech-specs/extraction-time-provenance.tr.md new file mode 100644 index 00000000..b27473eb --- /dev/null +++ b/docs/tech-specs/extraction-time-provenance.tr.md @@ -0,0 +1,619 @@ +# Çıkarma Zamanı Köken Bilgisi: Kaynak Katmanı + +## Genel Bakış + +Bu belge, gelecekteki özelliklendirme çalışmaları için çıkarma zamanı köken bilgisi üzerine notları içermektedir. Çıkarma zamanı köken bilgisi kayıtları, verilerin başlangıçta nereden geldiğini, nasıl çıkarıldığını ve dönüştürüldüğünü gösteren "kaynak katmanını" kaydeder. + +Bu, ajan muhakemesini kaydeden sorgu zamanı köken bilgisinden (bkz. `query-time-provenance.md`) farklıdır. + +## Problem Tanımı + +### Mevcut Uygulama + +Şu anda köken bilgisi aşağıdaki şekilde çalışmaktadır: +Belge meta verileri, bilgi grafiğinde RDF üçlüleri olarak saklanır. +Bir belge kimliği, meta verileri belgeyle ilişkilendirir, böylece belge grafikte bir düğüm olarak görünür. +Belgelerden kenarlar (ilişkiler/gerçekler) çıkarıldığında, çıkarılan kenarı kaynak belgeye bağlayan bir `subjectOf` ilişkisi bulunur. + +### Mevcut Yaklaşımla İlgili Sorunlar + +1. **Tekrarlayan meta veri yüklemesi:** Belge meta verileri, o belgeden çıkarılan her üçlü grubuyla birlikte tekrar tekrar paketlenir ve yüklenir. Bu, israf ve gereksizdir - aynı meta veriler her çıkarma çıktısıyla birlikte yük taşımacılığı yapar. + +2. **Yüzeysel köken bilgisi:** Mevcut `subjectOf` ilişkisi yalnızca gerçekleri doğrudan en üst düzey belgeyle ilişkilendirir. Dönüşüm zinciri hakkında hiçbir görünürlük yoktur - gerçek hangi sayfadan geldi, hangi parçadan, hangi çıkarma yöntemi kullanıldı. + +### İstediğimiz Durum + +1. **Meta verileri yalnızca bir kez yükleyin:** Belge meta verileri, her üçlü grubuyla tekrarlanmak yerine, yalnızca bir kez yüklenmeli ve en üst düzey belge düğümüne eklenmelidir. + +2. **Zengin köken bilgisi DAG'ı:** Kaynak belgeden başlayarak tüm ara öğeler aracılığıyla çıkarılan gerçeklere kadar olan tüm dönüşüm zincirini yakalayın. Örneğin, bir PDF belgesi dönüşümü: + + ``` + PDF file (source document with metadata) + → Page 1 (decoded text) + → Chunk 1 + → Extracted edge/fact (via subjectOf) + → Extracted edge/fact + → Chunk 2 + → Extracted edge/fact + → Page 2 + → Chunk 3 + → ... + ``` + +3. **Birleşik depolama:** Kaynak bilgisi DAG'ı, çıkarılan bilgiyle aynı bilgi grafiğinde saklanır. Bu, kaynak bilgisinin, herhangi bir gerçeğin tam kaynak konumuna doğru zincir boyunca geri izlenerek, bilgi gibi aynı şekilde sorgulanabilmesini sağlar. + +4. **Sabit Kimlikler:** Her ara öğe (sayfa, parça) grafikte bir düğüm olarak sabit bir kimliğe sahiptir. + +5. **Ebeveyn-çocuk bağlantısı:** Türetilmiş belgeler, tutarlı ilişki türleri kullanılarak, en üst düzey kaynak belgeye kadar ebeveynlerine bağlanır. + +6. **Hassas gerçek ataması:** Çıkarılan kenarlardaki `subjectOf` ilişkisi, doğrudan ebeveyne (parçaya), en üst düzey belgeye değil, işaret eder. Tam kaynak bilgisi, DAG boyunca yukarı doğru gezilerek elde edilir. + +## Kullanım Senaryoları + +### KS1: GraphRAG Yanıtlarında Kaynak Ataması + +**Senaryo:** Bir kullanıcı bir GraphRAG sorgusu çalıştırır ve ajandan bir yanıt alır. + +**Süreç:** +1. Kullanıcı, GraphRAG ajanıyla bir sorgu gönderir. +2. Ajan, bir yanıt oluşturmak için ilgili gerçekleri bilgi grafiğinden alır. +3. Sorgu zamanı kaynak bilgisi spesifikasyonuna göre, ajan yanıtı oluşturan gerçekleri bildirir. +4. Her gerçek, kaynak bilgisi DAG'ı aracılığıyla kaynak parçasına bağlanır. +5. Parçalar, sayfalara bağlanır, sayfalar kaynak belgelere bağlanır. + +**Kullanıcı Deneyimi Sonucu:** Arayüz, LLM yanıtını kaynak atamasıyla birlikte gösterir. Kullanıcı şunları yapabilir: +Yanıtı destekleyen gerçekleri görebilir. +Gerçeklerden → parçalara → sayfalara → belgelere kadar ayrıntılara inebilir. +İddiaları doğrulamak için orijinal kaynak belgelerine göz atabilir. +Bir gerçekin tam olarak bir belgenin (hangi sayfa, hangi bölüm) neresinden geldiğini anlayabilir. + +**Değer:** Kullanıcılar, yapay zeka tarafından oluşturulan yanıtlara birincil kaynaklara göre doğrulama yaparak güven oluşturabilir ve doğrulama yapabilir. + +### KS2: Çıkarma Kalitesinin Hata Ayıklaması + +Bir gerçek yanlış görünüyor. Orijinal metni görmek için parça → sayfa → belge yoluyla geriye doğru izleyin. Bu kötü bir çıkarma mıydı, yoksa kaynak mı yanlıştı? + +### KS3: Artımlı Yeniden Çıkarma + +Kaynak belge güncellendi. Bu belgeden hangi parçalar/gerçekler türetildi? Sadece bunları geçersiz kılın ve yeniden oluşturun, her şeyi yeniden işlemek yerine. + +### KS4: Veri Silme / Bilinme Hakkı + +Bir kaynak belge kaldırılmalıdır (GDPR, yasal, vb.). Türetilmiş tüm gerçekleri bulmak ve kaldırmak için DAG'ı izleyin. + +### KS5: Çatışma Çözümü + +İki gerçek birbiriyle çelişiyor. Nedenini anlamak ve hangisine güveneceğe karar vermek için her ikisini de kaynaklarına kadar izleyin (daha yetkili kaynak, daha yeni, vb.). + +### KS6: Kaynak Yetki Ağırlığı + +Bazı kaynaklar diğerlerinden daha yetkilidir. Gerçekler, kaynak belgelerinin yetki/kalitesine göre ağırlıklandırılabilir veya filtrelenebilir. + +### KS7: Çıkarma Boru Hattı Karşılaştırması + +Farklı çıkarma yöntemlerinin/sürümlerinin çıktılarını karşılaştırın. Aynı kaynaktan daha iyi gerçekler üreten hangi çıkarıcıydı? + +## Entegrasyon Noktaları + +### Kütüphaneci + +Kütüphaneci bileşeni, zaten benzersiz belge kimlikleriyle belge depolama imkanı sunmaktadır. Kaynak sistemi, bu mevcut altyapıyla entegre olmaktadır. + +#### Mevcut Yetenekler (zaten uygulanan) + +**Ebeveyn-Çocuk Belge Bağlantısı:** +`parent_id` alanı - `DocumentMetadata` içinde - çocuk belgeyi ebeveyn belgeye bağlar +`document_type` alanı - değerler: `"source"` (orijinal) veya `"extracted"` (türetilmiş) +`add-child-document` API'si - otomatik `document_type = "extracted"` ile çocuk belge oluşturur +`list-children` API'si - bir ebeveyn belgenin tüm çocuklarını alır +Zincirleme silme - bir ebeveynin silinmesi, otomatik olarak tüm çocuk belgelerin silinmesine neden olur + +**Belge Tanımlama:** +Belge kimlikleri, istemci tarafından belirtilir (otomatik olarak oluşturulmaz) +Belgeler, Cassandra'da bileşik `(user, document_id)` ile indekslenir +Nesne kimlikleri (UUID'ler), blob depolama için dahili olarak oluşturulur + +**Meta Veri Desteği:** +`metadata: list[Triple]` alanı - yapılandırılmış meta veriler için RDF üçlüleri +`title`, `comments`, `tags` - temel belge meta verileri +`time` - zaman damgası, `kind` - MIME türü + +**Depolama Mimarisi:** +Meta veriler, Cassandra'da saklanır (`librarian` anahtar alanı, `document` tablo) +İçerik, MinIO/S3 blob depolamasında saklanır (`library` bucket) +Akıllı içerik dağıtımı: 2 MB'den küçük belgeler yerleştirilir, daha büyük belgeler akışla iletilir + +#### Önemli Dosyalar + +`trustgraph-flow/trustgraph/librarian/librarian.py` - Temel kütüphaneci işlemleri +`trustgraph-flow/trustgraph/librarian/service.py` - Hizmet işlemcisi, belge yükleme +`trustgraph-flow/trustgraph/tables/library.py` - Cassandra tablo deposu +`trustgraph-base/trustgraph/schema/services/library.py` - Şema tanımları + +#### Giderilmesi Gereken Eksiklikler + +Kütüphaneci, temel yapı taşlarına sahip olmasına rağmen şu anda: +1. Ebeveyn-çocuk bağlantısı tek düzeylidir - çok düzeyli DAG (Yönlendirilmiş Döngüsel Grafik) gezinme yardımcıları yoktur +2. Standart bir ilişki türü sözlüğü yoktur (örneğin, `derivedFrom`, `extractedFrom`) +3. Kaynak meta verileri (çıkarma yöntemi, güven, parça konumu) standartlaştırılmamıştır +4. Bir gerçeğe geri dönen kaynaklara kadar tüm kaynak zincirini izlemek için bir sorgu API'si yoktur + +## Uçtan Uca Akış Tasarımı + +Boru hattındaki her işlemci, tutarlı bir kalıbı izler: +Yukarı akıştan belge kimliğini alır +Kütüphaneciden içeriği alır +Çocuk öğeler oluşturur +Her çocuk için: kütüphaneciye kaydeder, grafiğe bir kenar yollar, kimliği aşağı akışa iletir + +### İşlem Akışları + +Belge türüne bağlı olarak iki akış vardır: + +#### PDF Belge Akışı + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID to PDF extractor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ PDF Extractor (per page) │ +│ 1. Fetch PDF content from librarian using document ID │ +│ 2. Extract pages as text │ +│ 3. For each page: │ +│ a. Save page as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send page document ID to chunker │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch page content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = page) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + Post-chunker optimization: messages carry both + chunk ID (for provenance) and content (to avoid + librarian round-trip). Chunks are small (2-4KB). + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor (per chunk) │ +│ 1. Receive chunk ID + content directly (no librarian fetch needed) │ +│ 2. Extract facts/triples and embeddings from chunk content │ +│ 3. For each triple: │ +│ a. Emit triple to knowledge graph │ +│ b. Emit reified edge linking triple → chunk ID (edge pointing │ +│ to edge - first use of reification support) │ +│ 4. For each embedding: │ +│ a. Emit embedding with its entity ID │ +│ b. Link entity ID → chunk ID in knowledge graph │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +#### Metin Belgesi Akışı + +Metin belgeleri, PDF ayıklayıcıyı atlayarak doğrudan parçalayıcıya (chunker) gider: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID directly to chunker (skip PDF extractor) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch text content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor │ +│ (same as PDF flow) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +Elde edilen DAG, bir seviye daha kısadır: + +``` +PDF: Document → Pages → Chunks → Triples/Embeddings +Text: Document → Chunks → Triples/Embeddings +``` + +Tasarım, her iki durumu da destekler çünkü parçalayıcı (chunker), girdisini genel olarak işler; aldığı belge kimliği, kaynak belge mi yoksa bir sayfa mı olduğunu dikkate almadan, bunu üst belge olarak kullanır. + +### Metaveri Şeması (PROV-O) + +Kaynak metaverileri, W3C PROV-O ontolojisini kullanır. Bu, standart bir sözlük sağlar ve çıkarılan verilerin gelecekteki imzalanmasını/doğrulanmasını mümkün kılar. + +#### PROV-O Temel Kavramları + +| PROV-O Tipi | TrustGraph Kullanımı | +|-------------|------------------| +| `prov:Entity` | Belge, Sayfa, Parça, Üçlü, Gömme | +| `prov:Activity` | Çıkarma işlemlerinin örnekleri | +| `prov:Agent` | TG bileşenleri (PDF ayıklayıcı, parçalayıcı, vb.) ve versiyonları | + +#### PROV-O İlişkileri + +| Özne | Anlamı | Örnek | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | Başka bir varlıktan türetilen varlık | Sayfa, Belgeden Türetildi | +| `prov:wasGeneratedBy` | Bir etkinlik tarafından oluşturulan varlık | Sayfa, PDFÇıkarmaEtkinliği Tarafından Oluşturuldu | +| `prov:used` | Bir etkinliğin bir varlığı girdi olarak kullandığı | PDFÇıkarmaEtkinliği, Belgeyi Kullandı | +| `prov:wasAssociatedWith` | Bir etkinliğin bir ajan tarafından gerçekleştirildiği | PDFÇıkarmaEtkinliği, tg:PDFÇıkarıcı ile İlişkiliydi | + +#### Her Seviyedeki Metaveriler + +**Kaynak Belge (Librarian tarafından oluşturulan):** +``` +doc:123 a prov:Entity . +doc:123 dc:title "Research Paper" . +doc:123 dc:source . +doc:123 dc:date "2024-01-15" . +doc:123 dc:creator "Author Name" . +doc:123 tg:pageCount 42 . +doc:123 tg:mimeType "application/pdf" . +``` + +**Sayfa (PDF Çıkarıcı tarafından oluşturulmuştur):** +``` +page:123-1 a prov:Entity . +page:123-1 prov:wasDerivedFrom doc:123 . +page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 . +page:123-1 tg:pageNumber 1 . + +activity:pdf-extract-456 a prov:Activity . +activity:pdf-extract-456 prov:used doc:123 . +activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor . +activity:pdf-extract-456 tg:componentVersion "1.2.3" . +activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . +``` + +**Parça (Chunker tarafından üretilen):** +``` +chunk:123-1-1 a prov:Entity . +chunk:123-1-1 prov:wasDerivedFrom page:123-1 . +chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 . +chunk:123-1-1 tg:chunkIndex 1 . +chunk:123-1-1 tg:charOffset 0 . +chunk:123-1-1 tg:charLength 2048 . + +activity:chunk-789 a prov:Activity . +activity:chunk-789 prov:used page:123-1 . +activity:chunk-789 prov:wasAssociatedWith tg:Chunker . +activity:chunk-789 tg:componentVersion "1.0.0" . +activity:chunk-789 tg:chunkSize 2048 . +activity:chunk-789 tg:chunkOverlap 200 . +``` + +**Üçlü (Knowledge Extractor tarafından üretildi):** +``` +# The extracted triple (edge) +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph containing the extracted triples +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 prov:wasGeneratedBy activity:extract-999 . + +activity:extract-999 a prov:Activity . +activity:extract-999 prov:used chunk:123-1-1 . +activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor . +activity:extract-999 tg:componentVersion "2.1.0" . +activity:extract-999 tg:llmModel "claude-3" . +activity:extract-999 tg:ontology . +``` + +**Gömme (vektör deposunda saklanır, üçlü depolamada değil):** + +Gömme verileri, RDF üçlüleri olarak değil, meta verilerle birlikte vektör deposunda saklanır. Her gömme kaydı şunları içerir: + +| Alan | Açıklama | Örnek | +|-------|-------------|---------| +| vektör | Gömme vektörü | [0.123, -0.456, ...] | +| varlık | Gömmenin temsil ettiği düğüm URI'si | `entity:JohnSmith` | +| chunk_id | Kaynak parça (kaynak) | `chunk:123-1-1` | +| model | Kullanılan gömme modeli | `text-embedding-ada-002` | +| component_version | TG gömme sürümü | `1.0.0` | + +`entity` alanı, gömmeyi bilgi grafiğine (düğüm URI'si) bağlar. `chunk_id` alanı, orijinal belgeye kadar DAG üzerinde izlemeyi sağlayarak, kaynak parçaya ilişkin bilgileri sağlar. + +#### TrustGraph İsim Alanı Genişletmeleri + +Çıkarma ile ilgili meta veriler için `tg:` isim alanı altındaki özel önekler: + +| Önek | Alan | Açıklama | +|-----------|--------|-------------| +| `tg:contains` | Alt Grafik | Bu çıkarma alt grafiğindeki bir üçlüye işaret eder | +| `tg:pageCount` | Belge | Kaynak belgedeki toplam sayfa sayısı | +| `tg:mimeType` | Belge | Kaynak belgenin MIME türü | +| `tg:pageNumber` | Sayfa | Kaynak belgedeki sayfa numarası | +| `tg:chunkIndex` | Parça | Ebeveyn içindeki parçanın indeksi | +| `tg:charOffset` | Parça | Ebeveyn metnindeki karakter ofseti | +| `tg:charLength` | Parça | Parçanın karakter cinsinden uzunluğu | +| `tg:chunkSize` | Etkinlik | Yapılandırılmış parça boyutu | +| `tg:chunkOverlap` | Etkinlik | Parçalar arasındaki yapılandırılmış örtüşme | +| `tg:componentVersion` | Etkinlik | TG bileşeninin sürümü | +| `tg:llmModel` | Etkinlik | Çıkarma için kullanılan LLM | +| `tg:ontology` | Etkinlik | Çıkarma için kullanılan ontoloji URI'si | +| `tg:embeddingModel` | Etkinlik | Gömme için kullanılan model | +| `tg:sourceText` | İfade | Bir üçlünün çıkarıldığı tam metin | +| `tg:sourceCharOffset` | İfade | Kaynak metnin başladığı parça içindeki karakter ofseti | +| `tg:sourceCharLength` | İfade | Kaynak metnin karakter cinsinden uzunluğu | + +#### Sözlük Başlatma (Her Koleksiyon İçin) + +Bilgi grafiği, ontolojiye bağımlı olmayan ve başlangıçta boş olan bir yapıdır. Bir koleksiyona PROV-O kaynak verilerini ilk kez yazarken, tüm sınıflar ve önekler için RDF etiketleriyle sözlük başlatılmalıdır. Bu, sorgularda ve kullanıcı arayüzünde okunabilir bir görüntüleme sağlar. + +**PROV-O Sınıfları:** +``` +prov:Entity rdfs:label "Entity" . +prov:Activity rdfs:label "Activity" . +prov:Agent rdfs:label "Agent" . +``` + +**PROV-O Yüklemleri:** +``` +prov:wasDerivedFrom rdfs:label "was derived from" . +prov:wasGeneratedBy rdfs:label "was generated by" . +prov:used rdfs:label "used" . +prov:wasAssociatedWith rdfs:label "was associated with" . +prov:startedAtTime rdfs:label "started at" . +``` + +**TrustGraph Önermeleri:** +``` +tg:contains rdfs:label "contains" . +tg:pageCount rdfs:label "page count" . +tg:mimeType rdfs:label "MIME type" . +tg:pageNumber rdfs:label "page number" . +tg:chunkIndex rdfs:label "chunk index" . +tg:charOffset rdfs:label "character offset" . +tg:charLength rdfs:label "character length" . +tg:chunkSize rdfs:label "chunk size" . +tg:chunkOverlap rdfs:label "chunk overlap" . +tg:componentVersion rdfs:label "component version" . +tg:llmModel rdfs:label "LLM model" . +tg:ontology rdfs:label "ontology" . +tg:embeddingModel rdfs:label "embedding model" . +tg:sourceText rdfs:label "source text" . +tg:sourceCharOffset rdfs:label "source character offset" . +tg:sourceCharLength rdfs:label "source character length" . +``` + +**Uygulama notu:** Bu sözlük başlatma işleminin idempotent olması gerekir - yani, çoğaltmalar oluşturmadan birden çok kez çalıştırılabilir. Bu işlem, bir koleksiyondaki ilk belge işleme sırasında veya ayrı bir koleksiyon başlatma adımı olarak tetiklenebilir. + +#### Alt Parça Kaynağı (İdeal) + +Daha ayrıntılı bir kaynak bilgisi için, bir üçlemenin bir parça içinde tam olarak nereden çıkarıldığı kaydedilmesi değerli olacaktır. Bu, şunları sağlar: + +Kullanıcı arayüzünde (UI) tam kaynak metninin vurgulanması +Çıkarma doğruluğunun kaynağa göre doğrulanması +Çıkarma kalitesinin cümle düzeyinde hata ayıklanması + +**Konum takibi ile örnek:** +``` +# The extracted triple +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph with sub-chunk provenance +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +subgraph:001 tg:sourceCharOffset 1547 . +subgraph:001 tg:sourceCharLength 46 . +``` + +**Metin aralığı içeren örnek (alternatif):** +``` +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceRange "1547-1593" . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +``` + +**Uygulama hususları:** + +LLM tabanlı çıkarma, doğal olarak karakter konumlarını sağlamayabilir. +LLM'den çıkarılan üçlülerin yanı sıra kaynak cümleyi/ifadeyi de döndürmesi istenebilir. +Alternatif olarak, çıkarılan varlıkları kaynak metne geri eşleştirmek için bir işlem sonrası adımı uygulanabilir. +Çıkarma karmaşıklığı ile kaynak doğruluğu arasındaki denge. +Yapılandırılmış çıkarma yöntemleriyle serbest biçimli LLM çıkarma yöntemlerinden daha kolay uygulanabilir olabilir. + +Bu, iddialı bir hedef olarak işaretlenmiştir - temel parça düzeyindeki kaynak bilgisi öncelikle uygulanmalı, alt parça takibi ise uygulanabilirse gelecekteki bir iyileştirme olarak düşünülmelidir. + +### Çift Depolama Modeli + +Kaynak bilgisi DAG'ı, belgeler boru hattından geçerken kademeli olarak oluşturulur: + +| Depo | Neler Saklanır | Amaç | +|-------|---------------|---------| +| Kütüphaneci | Belge içeriği + ebeveyn-çocuk bağlantıları | İçerik alma, kaskad silme | +| Bilgi Grafiği | Ebeveyn-çocuk kenarları + meta veri | Kaynak bilgisi sorguları, gerçek ataması | + +Her iki depo da aynı DAG yapısını korur. Kütüphaneci içeriği saklar; grafik ilişkileri saklar ve gezinme sorgularını sağlar. + +### Temel Tasarım Prensipleri + +1. **Belge Kimliği akış birimi olarak** - İşleyiciler içeriği değil, kimlikleri iletir. İçerik gerektiğinde kütüphaneciden alınır. + +2. **Kaynakta bir kez yayınla** - Meta veri, işleme başladığında grafiğe bir kez yazılır, aşağı akışta tekrarlanmaz. + +3. **Tutarlı işlemci kalıbı** - Her işlemci aynı alım/alma/üretme/kaydetme/yayınlama/ileri gönderme kalıbını izler. + +4. **Kademeli DAG oluşturma** - Her işlemci DAG'a kendi seviyesini ekler. Tam kaynak bilgisi zinciri kademeli olarak oluşturulur. + +5. **Parça sonrasındaki optimizasyon** - Parçalama işleminden sonra, mesajlar hem kimliği hem de içeriği taşır. Parçalar küçüktür (2-4KB), bu nedenle içeriği dahil etmek, kütüphaneciye yapılan gereksiz geri dönüşleri önlerken kimlik yoluyla kaynak bilgisini korur. + +## Uygulama Görevleri + +### Kütüphaneci Değişiklikleri + +#### Mevcut Durum + +Belge işleme işlemini başlatarak belge kimliğini ilk işlemciye gönderir. +Üçlü depoyla bağlantı yok - meta veri, çıkarma çıktılarıyla birlikte paketlenir. +`add-child-document` tek seviyeli ebeveyn-çocuk bağlantıları oluşturur. +`list-children` yalnızca hemen alt öğeleri döndürür. + +#### Gerekli Değişiklikler + +**1. Yeni arayüz: Üçlü depo bağlantısı** + +Kütüphaneci, işleme başlatıldığında belge meta veri kenarlarını doğrudan bilgi grafiğine yayınlamalıdır. +Kütüphaneci hizmetine üçlü depo istemci/yayınlayıcısı ekleyin. +İşleme başlatıldığında: kök belge meta verilerini grafik kenarları olarak (tek seferlik) yayınlayın. + +**2. Belge türü sözlüğü** + +Alt belgeler için `document_type` değerlerini standartlaştırın: +`source` - orijinal olarak yüklenen belge +`page` - kaynaktan (PDF, vb.) çıkarılan sayfa +`chunk` - sayfadan veya kaynaktan türetilen metin parçası + +#### Arayüz Değişiklikleri Özeti + +| Arayüz | Değişiklik | +|-----------|--------| +| Üçlü depo | Yeni dışa dönük bağlantı - belge meta veri kenarlarını yayınlayın | +| İşleme başlatma | Meta veriyi grafiğe yayınlayın, belge kimliğini iletmeden önce | + +### PDF Çıkarma Değişiklikleri + +#### Mevcut Durum + +Belge içeriğini alır (veya büyük belgeleri akış halinde alır) +PDF sayfalarından metin çıkarır +Sayfa içeriğini parçalayıcıya iletir +Kütüphaneci veya üçlü depo ile etkileşimde bulunmaz + +#### Gerekli Değişiklikler + +**1. Yeni arayüz: Kütüphaneci istemcisi** + +PDF çıkarıcı, her sayfayı kütüphanecide bir alt belge olarak kaydetmelidir. +PDF çıkarıcı hizmetine kütüphaneci istemcisi ekleyin +Her sayfa için: ebeveyn = kök belge kimliği ile `add-child-document`'yi çağırın + +**2. Yeni arayüz: Üçlü depo bağlantısı** + +PDF çıkarıcı, ebeveyn-çocuk kenarlarını bilgi grafiğine yayınlamalıdır. +Üçlü depo istemci/yayınlayıcısı ekleyin +Her sayfa için: sayfa belgesini ebeveyn belgeyle ilişkilendiren bir kenar yayınlayın + +**3. Çıktı biçimini değiştirin** + +Sayfa içeriğini doğrudan iletmek yerine, sayfa belge kimliğini iletin. +Chunker, içeriği kütüphaneden kimliği kullanarak alacaktır. + +#### Arayüz Değişiklikleri Özeti + +| Arayüz | Değişiklik | +|-----------|--------| +| Kütüphane | Yeni dışa aktarma - alt belgeleri kaydet | +| Üçlü depolama | Yeni dışa aktarma - ebeveyn-çocuk kenarlarını yayınla | +| Çıkış mesajı | İçerikten belge kimliğine geçiş | + +### Chunker Değişiklikleri + +#### Mevcut Durum + +Sayfa/metin içeriğini alır +Parçalara böler +Parça içeriğini sonraki işleme birimlerine iletir +Kütüphane veya üçlü depolamayla etkileşimde bulunmaz + +#### Gerekli Değişiklikler + +**1. Giriş işleme şeklini değiştirin** + +İçerik yerine belge kimliğini alın, kütüphaneden alın. +Chunker hizmetine kütüphane istemcisini ekleyin +Belge kimliğini kullanarak sayfa içeriğini alın + +**2. Yeni arayüz: Kütüphane istemcisi (yazma)** + +Her parçayı kütüphanede bir alt belge olarak kaydedin. +Her parça için: ebeveyn = sayfa belge kimliği ile `add-child-document`'ı çağırın + +**3. Yeni arayüz: Üçlü depolama bağlantısı** + +Ebeveyn-çocuk kenarlarını bilgi grafiğine yayınlayın. +Üçlü depolama istemcisini/yayınlayıcısını ekleyin +Her parça için: parça belgesini sayfa belgesine bağlayan kenarı yayınlayın + +**4. Çıkış biçimini değiştirin** + +Hem parça belge kimliğini hem de parça içeriğini iletin (parça işleminden sonraki optimizasyon). +Sonraki işleme birimleri, köken bilgisi için kimliği ve çalışmak için içeriği alır + +#### Arayüz Değişiklikleri Özeti + +| Arayüz | Değişiklik | +|-----------|--------| +| Giriş mesajı | İçerikten belge kimliğine geçiş | +| Kütüphane | Yeni dışa aktarma (okuma + yazma) - içeriği alın, alt belgeleri kaydedin | +| Üçlü depolama | Yeni dışa aktarma - ebeveyn-çocuk kenarlarını yayınla | +| Çıkış mesajı | İçerikten kimliğe + içeriğe geçiş | + +### Bilgi Çıkarıcı Değişiklikleri + +#### Mevcut Durum + +Parça içeriğini alır +Üçlüleri ve gömme değerlerini çıkarır +Üçlü depolamaya ve gömme depolamaya yayınlar +`subjectOf` ilişkisi, en üst düzey belgeye (parçaya değil) işaret eder + +#### Gerekli Değişiklikler + +**1. Giriş işleme şeklini değiştirin** + +Parça belge kimliğini içeriğin yanında alın. +Köken bağlama için parça kimliğini kullanın (içerik zaten optimizasyon kapsamında dahil edilmiştir) + +**2. Üçlü kökeni güncelleyin** + +Çıkarılan üçlüleri parçaya (en üst düzey belgeye değil) bağlayın. +Kenara işaret eden bir kenar oluşturmak için yeniden tanımlama kullanın +`subjectOf` ilişkisi: üçlü → parça belge kimliği +Mevcut yeniden tanımlama desteğinin ilk kullanımı + +**3. Gömme kökenini güncelleyin** + +Gömme varlık kimliklerini parçaya bağlayın. +Kenar yayınlayın: gömme varlık kimliği → parça belge kimliği + +#### Arayüz Değişiklikleri Özeti + +| Arayüz | Değişiklik | +|-----------|--------| +| Giriş mesajı | Parça kimliğini + içeriği bekleyin (sadece içeriği değil) | +| Üçlü depolama | Üçlü → parça kökeni için yeniden tanımlamayı kullanın | +| Gömme kökeni | Varlık kimliğini → parça kimliğine bağlayın | + +## Referanslar + +Sorgu zamanı kökeni: `docs/tech-specs/query-time-provenance.md` +Köken modellemesi için PROV-O standardı +Bilgi grafiğindeki mevcut kaynak meta verileri (denetlenmesi gerekir) diff --git a/docs/tech-specs/extraction-time-provenance.zh-cn.md b/docs/tech-specs/extraction-time-provenance.zh-cn.md new file mode 100644 index 00000000..6399f279 --- /dev/null +++ b/docs/tech-specs/extraction-time-provenance.zh-cn.md @@ -0,0 +1,619 @@ +# 提取时的数据来源:源层 + +## 概述 + +本文档记录了关于提取时数据来源的笔记,用于未来的规范工作。提取时的数据来源记录了数据的“源层”,即数据最初来自哪里,以及它是如何提取和转换的。 + +这与查询时的数据来源(参见 `query-time-provenance.md`)不同,后者记录的是代理推理过程。 + +## 问题陈述 + +### 当前实现 + +目前,数据来源的工作方式如下: +文档元数据以 RDF 三元组的形式存储在知识图谱中。 +文档 ID 将元数据与文档关联起来,因此文档在图中显示为节点。 +当从文档中提取出边(关系/事实)时,一个 `subjectOf` 关系将提取出的边链接回原始文档。 + +### 当前方法的缺点 + +1. **重复加载元数据:** 文档元数据会被打包并重复加载,每次从该文档中提取一批三元组时都会重复。这既浪费又冗余,相同的元数据会作为“货物”随每次提取输出一起传输。 + +2. **浅层数据来源:** 当前的 `subjectOf` 关系仅将事实直接链接到顶级文档。无法了解转换链,例如,该事实来自哪个页面,哪个块,使用了哪种提取方法。 + +### 期望状态 + +1. **一次加载元数据:** 文档元数据应该只加载一次,并附加到顶级文档节点,而不是重复包含在每个三元组批次中。 + +2. **丰富的数据来源 DAG:** 捕获从原始文档到所有中间工件,再到提取出的事实的完整转换链。例如,一个 PDF 文档的转换过程: + + ``` + PDF file (source document with metadata) + → Page 1 (decoded text) + → Chunk 1 + → Extracted edge/fact (via subjectOf) + → Extracted edge/fact + → Chunk 2 + → Extracted edge/fact + → Page 2 + → Chunk 3 + → ... + ``` + +3. **统一存储:** 提取的知识及其来源信息(provenance)都存储在同一个知识图谱中。这使得对来源信息的查询方式与对知识的查询方式相同,即可以从任何事实出发,沿着链条追溯到其确切的来源位置。 + +4. **稳定的ID:** 每个中间产物(页面、段落)都具有一个稳定的ID,该ID在图中表示为一个节点。 + +5. **父子链接:** 从派生文档到其父文档,一直链接到顶层源文档,使用一致的关系类型。 + +6. **精确的事实归属:** 提取的边上的 `subjectOf` 关系指向直接的父节点(段落),而不是顶层文档。可以通过遍历DAG来恢复完整的来源信息。 + +## 用例 + +### UC1:GraphRAG响应中的来源归属 + +**场景:** 用户运行GraphRAG查询,并从代理接收到响应。 + +**流程:** +1. 用户向GraphRAG代理提交查询。 +2. 代理从知识图谱中检索相关的事实,以构建响应。 +3. 根据查询时期的来源信息规范,代理报告哪些事实对响应做出了贡献。 +4. 每个事实通过来源信息DAG链接到其源段落。 +5. 段落链接到页面,页面链接到源文档。 + +**用户体验结果:** 界面会显示LLM响应以及来源归属信息。用户可以: +查看哪些事实支持了响应。 +从事实 → 段落 → 页面 → 文档进行深入了解。 +浏览原始的源文档以验证声明。 +准确了解事实的来源(哪个页面,哪个部分)。 + +**价值:** 用户可以根据原始来源验证AI生成的响应,从而建立信任并实现事实核查。 + +### UC2:调试提取质量 + +某个事实看起来不正确。追溯到段落 → 页面 → 文档,查看原始文本。是提取出现问题,还是原始来源本身就是错误的? + +### UC3:增量重提取 + +源文档已更新。哪些段落/事实是从它派生的?仅使这些段落/事实失效并重新生成,而不是重新处理所有内容。 + +### UC4:数据删除/被遗忘的权利 + +必须删除一个源文档(GDPR、法律等)。遍历DAG以查找并删除所有派生的事实。 + +### UC5:冲突解决 + +两个事实相互矛盾。追溯到它们的来源,以了解原因并决定应该信任哪个(更权威的来源、更新的来源等)。 + +### UC6:来源权威性加权 + +某些来源比其他来源更具权威性。可以根据其原始文档的权威性/质量对事实进行加权或过滤。 + +### UC7:提取管道比较 + +比较来自不同提取方法/版本的输出。哪个提取器从相同的来源生成了更好的事实? + +## 集成点 + +### Librarian + +librarian组件已经提供了文档存储,并具有唯一的文档ID。来源信息系统与此现有的基础设施集成。 + +#### 现有功能(已实现) + +**父子文档链接:** +`parent_id` 字段在 `DocumentMetadata` 中 - 将子文档链接到父文档。 +`document_type` 字段 - 值:`"source"`(原始)或 `"extracted"`(派生)。 +`add-child-document` API - 创建具有自动 `document_type = "extracted"` 的子文档。 +`list-children` API - 检索父文档的所有子文档。 +级联删除 - 删除父文档会自动删除所有子文档。 + +**文档识别:** +文档ID由客户端指定(不是自动生成)。 +文档按复合 `(user, document_id)` 在Cassandra中键入。 +对象ID(UUID)在内部生成,用于blob存储。 + +**元数据支持:** +`metadata: list[Triple]` 字段 - RDF三元组用于结构化元数据。 +`title`、`comments`、`tags` - 基本文档元数据。 +`time` - 时间戳,`kind` - MIME类型。 + +**存储架构:** +元数据存储在Cassandra中(`librarian` 键空间,`document` 表)。 +内容存储在MinIO/S3 blob存储中(`library` 存储桶)。 +智能内容交付:小于 2MB 的文档嵌入,较大的文档流式传输。 + +#### 关键文件 + +`trustgraph-flow/trustgraph/librarian/librarian.py` - 核心 librarian 操作。 +`trustgraph-flow/trustgraph/librarian/service.py` - 服务处理器,文档加载。 +`trustgraph-flow/trustgraph/tables/library.py` - Cassandra 表存储。 +`trustgraph-base/trustgraph/schema/services/library.py` - 模式定义。 + +#### 需要解决的问题 + +librarian 具有构建块,但目前: +1. 父子链接仅限于一级深度 - 没有多级DAG遍历辅助功能。 +2. 没有标准的关系类型词汇表(例如,`derivedFrom`、`extractedFrom`)。 +3. 来源信息元数据(提取方法、置信度、段落位置)尚未标准化。 +4. 没有查询API来遍历从事实到源的全程来源信息链。 + +## 端到端流程设计 + +管道中的每个处理器都遵循一致的模式: +从上游接收文档ID。 +从librarian中获取内容。 +生成子产物。 +对于每个子产物:保存到librarian,向图发出边,将ID转发到下游。 + +### 处理流程 + +有两个流程,具体取决于文档类型: + +#### PDF文档流程 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID to PDF extractor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ PDF Extractor (per page) │ +│ 1. Fetch PDF content from librarian using document ID │ +│ 2. Extract pages as text │ +│ 3. For each page: │ +│ a. Save page as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send page document ID to chunker │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch page content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = page) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + Post-chunker optimization: messages carry both + chunk ID (for provenance) and content (to avoid + librarian round-trip). Chunks are small (2-4KB). + ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor (per chunk) │ +│ 1. Receive chunk ID + content directly (no librarian fetch needed) │ +│ 2. Extract facts/triples and embeddings from chunk content │ +│ 3. For each triple: │ +│ a. Emit triple to knowledge graph │ +│ b. Emit reified edge linking triple → chunk ID (edge pointing │ +│ to edge - first use of reification support) │ +│ 4. For each embedding: │ +│ a. Emit embedding with its entity ID │ +│ b. Link entity ID → chunk ID in knowledge graph │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +#### 文本文档流程 + +文本文档会跳过 PDF 提取器,直接进入分块处理: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Librarian (initiate processing) │ +│ 1. Emit root document metadata to knowledge graph (once) │ +│ 2. Send root document ID directly to chunker (skip PDF extractor) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Chunker (per chunk) │ +│ 1. Fetch text content from librarian using document ID │ +│ 2. Split text into chunks │ +│ 3. For each chunk: │ +│ a. Save chunk as child document in librarian (parent = root doc) │ +│ b. Emit parent-child edge to knowledge graph │ +│ c. Send chunk document ID + chunk content to next processor │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Knowledge Extractor │ +│ (same as PDF flow) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +结果生成的有向无环图(DAG)的层数减少了一层: + +``` +PDF: Document → Pages → Chunks → Triples/Embeddings +Text: Document → Chunks → Triples/Embeddings +``` + +该设计同时适用于这两种情况,因为分块器以通用方式处理其输入 - 它使用接收到的任何文档 ID 作为父级,无论该 ID 是源文档还是页面。 + +### 元数据模式 (PROV-O) + +溯源元数据使用 W3C PROV-O 本体。这提供了一个标准词汇表,并为未来提取输出的签名/身份验证提供了支持。 + +#### PROV-O 核心概念 + +| PROV-O 类型 | TrustGraph 用法 | +|-------------|------------------| +| `prov:Entity` | 文档、页面、块、三元组、嵌入 | +| `prov:Activity` | 提取操作的实例 | +| `prov:Agent` | TG 组件(PDF 提取器、分块器等)及其版本 | + +#### PROV-O 关系 + +| 谓词 | 含义 | 示例 | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | 一个实体源自另一个实体 | 页面 wasDerivedFrom 文档 | +| `prov:wasGeneratedBy` | 一个实体由一个活动生成 | 页面 wasGeneratedBy PDFExtractionActivity | +| `prov:used` | 一个活动使用一个实体作为输入 | PDFExtractionActivity used Document | +| `prov:wasAssociatedWith` | 一个活动由一个代理执行 | PDFExtractionActivity wasAssociatedWith tg:PDFExtractor | + +#### 每个级别的元数据 + +**源文档(由 Librarian 产生):** +``` +doc:123 a prov:Entity . +doc:123 dc:title "Research Paper" . +doc:123 dc:source . +doc:123 dc:date "2024-01-15" . +doc:123 dc:creator "Author Name" . +doc:123 tg:pageCount 42 . +doc:123 tg:mimeType "application/pdf" . +``` + +**页面 (由 PDF 提取器生成):** +``` +page:123-1 a prov:Entity . +page:123-1 prov:wasDerivedFrom doc:123 . +page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 . +page:123-1 tg:pageNumber 1 . + +activity:pdf-extract-456 a prov:Activity . +activity:pdf-extract-456 prov:used doc:123 . +activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor . +activity:pdf-extract-456 tg:componentVersion "1.2.3" . +activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . +``` + +**块 (由分块器发出):** +``` +chunk:123-1-1 a prov:Entity . +chunk:123-1-1 prov:wasDerivedFrom page:123-1 . +chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 . +chunk:123-1-1 tg:chunkIndex 1 . +chunk:123-1-1 tg:charOffset 0 . +chunk:123-1-1 tg:charLength 2048 . + +activity:chunk-789 a prov:Activity . +activity:chunk-789 prov:used page:123-1 . +activity:chunk-789 prov:wasAssociatedWith tg:Chunker . +activity:chunk-789 tg:componentVersion "1.0.0" . +activity:chunk-789 tg:chunkSize 2048 . +activity:chunk-789 tg:chunkOverlap 200 . +``` + +**强调 (由知识提取器发出):** +``` +# The extracted triple (edge) +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph containing the extracted triples +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 prov:wasGeneratedBy activity:extract-999 . + +activity:extract-999 a prov:Activity . +activity:extract-999 prov:used chunk:123-1-1 . +activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor . +activity:extract-999 tg:componentVersion "2.1.0" . +activity:extract-999 tg:llmModel "claude-3" . +activity:extract-999 tg:ontology . +``` + +**嵌入 (存储在向量存储中,而不是三元组存储中):** + +嵌入存储在向量存储中,包含元数据,而不是作为 RDF 三元组。每个嵌入记录包含: + +| 字段 | 描述 | 示例 | +|-------|-------------|---------| +| vector | 嵌入向量 | [0.123, -0.456, ...] | +| entity | 嵌入所代表的节点 URI | `entity:JohnSmith` | +| chunk_id | 源块 (来源) | `chunk:123-1-1` | +| model | 使用的嵌入模型 | `text-embedding-ada-002` | +| component_version | TG 嵌入器版本 | `1.0.0` | + +`entity` 字段将嵌入链接到知识图谱 (节点 URI)。 `chunk_id` 字段提供回溯到源块的来源信息,从而可以向上遍历 DAG,到达原始文档。 + +#### TrustGraph 命名空间扩展 + +在 `tg:` 命名空间下,定义了用于提取特定元数据的自定义谓词: + +| 谓词 | 域 | 描述 | +|-----------|--------|-------------| +| `tg:contains` | Subgraph | 指向此提取子图中包含的三元组 | +| `tg:pageCount` | Document | 源文档中的总页数 | +| `tg:mimeType` | Document | 源文档的 MIME 类型 | +| `tg:pageNumber` | Page | 源文档中的页码 | +| `tg:chunkIndex` | Chunk | 父级中的块索引 | +| `tg:charOffset` | Chunk | 父级文本中的字符偏移量 | +| `tg:charLength` | Chunk | 块的字符长度 | +| `tg:chunkSize` | Activity | 配置的块大小 | +| `tg:chunkOverlap` | Activity | 配置的块之间的重叠 | +| `tg:componentVersion` | Activity | TG 组件的版本 | +| `tg:llmModel` | Activity | 用于提取的 LLM | +| `tg:ontology` | Activity | 用于指导提取的本体 URI | +| `tg:embeddingModel` | Activity | 用于嵌入的模型 | +| `tg:sourceText` | Statement | 从提取的三元组的精确文本 | +| `tg:sourceCharOffset` | Statement | 源文本在块中的字符偏移量 | +| `tg:sourceCharLength` | Statement | 源文本的字符长度 | + +#### 词汇引导 (每个集合) + +知识图谱是本体无关的,并且初始化为空。 当首次将 PROV-O provenance 数据写入集合时,必须使用 RDF 标签引导所有类和谓词的词汇。 这可确保在查询和 UI 中提供人类可读的显示。 + +**PROV-O 类:** +``` +prov:Entity rdfs:label "Entity" . +prov:Activity rdfs:label "Activity" . +prov:Agent rdfs:label "Agent" . +``` + +**PROV-O谓词:** +``` +prov:wasDerivedFrom rdfs:label "was derived from" . +prov:wasGeneratedBy rdfs:label "was generated by" . +prov:used rdfs:label "used" . +prov:wasAssociatedWith rdfs:label "was associated with" . +prov:startedAtTime rdfs:label "started at" . +``` + +**TrustGraph谓词:** +``` +tg:contains rdfs:label "contains" . +tg:pageCount rdfs:label "page count" . +tg:mimeType rdfs:label "MIME type" . +tg:pageNumber rdfs:label "page number" . +tg:chunkIndex rdfs:label "chunk index" . +tg:charOffset rdfs:label "character offset" . +tg:charLength rdfs:label "character length" . +tg:chunkSize rdfs:label "chunk size" . +tg:chunkOverlap rdfs:label "chunk overlap" . +tg:componentVersion rdfs:label "component version" . +tg:llmModel rdfs:label "LLM model" . +tg:ontology rdfs:label "ontology" . +tg:embeddingModel rdfs:label "embedding model" . +tg:sourceText rdfs:label "source text" . +tg:sourceCharOffset rdfs:label "source character offset" . +tg:sourceCharLength rdfs:label "source character length" . +``` + +**实施说明:** 这个词汇库初始化应该具有幂等性,即可以多次运行而不会创建重复项。 它可以触发在集合中的第一个文档处理过程中,或者作为单独的集合初始化步骤。 + +#### 子块来源信息(期望) + +为了获得更细粒度的来源信息,记录三元组是从块中的哪个位置提取出来的将非常有用。 这可以实现: + +在用户界面中突出显示确切的原始文本 +验证提取的准确性与原始文本 +在句子级别调试提取质量 + +**带有位置跟踪的示例:** +``` +# The extracted triple +entity:JohnSmith rel:worksAt entity:AcmeCorp . + +# Subgraph with sub-chunk provenance +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +subgraph:001 tg:sourceCharOffset 1547 . +subgraph:001 tg:sourceCharLength 46 . +``` + +**带有文本范围的示例(备选方案):** +``` +subgraph:001 tg:contains <> . +subgraph:001 prov:wasDerivedFrom chunk:123-1-1 . +subgraph:001 tg:sourceRange "1547-1593" . +subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . +``` + +**实现注意事项:** + +基于 LLM 的提取可能无法自然地提供字符位置。 +可以提示 LLM 在提取的三元组旁边返回原始句子/短语。 +或者,可以进行后处理,将提取的实体模糊匹配回原始文本。 +提取复杂度和溯源粒度之间的权衡。 +使用结构化提取方法可能更容易实现,而不是使用自由形式的 LLM 提取。 + +这被标记为期望目标 - 首先应实现基本的块级溯源,如果可行,子块跟踪可以作为未来的增强功能。 + +### 双重存储模型 + +溯源 DAG 是随着文档在流水线中流动而逐步构建的: + +| 存储 | 存储内容 | 目的 | +|-------|---------------|---------| +| Librarian | 文档内容 + 父子链接 | 内容检索、级联删除 | +| Knowledge Graph | 父子边 + 元数据 | 溯源查询、事实归属 | + +两个存储都维护相同的 DAG 结构。 Librarian 存储内容;Graph 存储关系,并支持遍历查询。 + +### 关键设计原则 + +1. **文档 ID 作为流动的单位** - 处理程序传递 ID,而不是内容。 需要时从 Librarian 检索内容。 + +2. **在源头一次发出** - 元数据在处理开始时写入到 Graph 中,而不是在下游重复。 + +3. **一致的处理程序模式** - 每个处理程序都遵循相同的接收/检索/生成/保存/发出/转发模式。 + +4. **渐进的 DAG 构建** - 每个处理程序添加其级别到 DAG 中。 完整的溯源链是逐步构建的。 + +5. **分块后优化** - 在分块之后,消息同时携带 ID 和内容。 块很小(2-4KB),因此包含内容可以避免不必要的 Librarian 往返,同时通过 ID 保持溯源。 + +## 实现任务 + +### Librarian 更改 + +#### 当前状态 + +通过将文档 ID 发送到第一个处理程序来启动文档处理。 +没有连接到三元存储 - 元数据与提取输出一起打包。 +`add-child-document` 创建一级父子链接。 +`list-children` 仅返回直接子节点。 + +#### 需要的更改 + +**1. 新接口:三元存储连接** + +Librarian 需要直接将文档元数据边发射到知识图谱,以在启动处理时进行操作。 +向 Librarian 服务添加三元存储客户端/发布器。 +在处理启动时:以图谱边的方式(一次)发射根文档元数据。 + +**2. 文档类型词汇表** + +标准化子文档的 `document_type` 值: +`source` - 原始上传的文档。 +`page` - 从源头提取的页面(PDF 等)。 +`chunk` - 从页面或源头派生的文本块。 + +#### 接口更改摘要 + +| 接口 | 更改 | +|-----------|--------| +| 三元存储 | 新的出站连接 - 发射文档元数据边 | +| 处理启动 | 在转发文档 ID 之前,向图谱发射元数据 | + +### PDF 提取器更改 + +#### 当前状态 + +接收文档内容(或流式传输大型文档)。 +从 PDF 页面提取文本。 +将页面内容转发到分块器。 +没有与 Librarian 或三元存储交互。 + +#### 需要的更改 + +**1. 新接口:Librarian 客户端** + +PDF 提取器需要将每个页面作为子文档保存到 Librarian 中。 +向 PDF 提取器服务添加 Librarian 客户端。 +对于每个页面:使用父文档 ID 调用 `add-child-document`。 + +**2. 新接口:三元存储连接** + +PDF 提取器需要将父子边发射到知识图谱。 +添加三元存储客户端/发布器。 +对于每个页面:发射一个链接页面文档到父文档的边。 + +**3. 更改输出格式** + +而是直接转发页面内容,而是转发页面文档 ID。 +Chunker 将使用 ID 从 librarian 获取内容 + +#### 接口变更摘要 + +| 接口 | 变更 | +|-----------|--------| +| Librarian | 新的输出 - 保存子文档 | +| Triple store | 新的输出 - 发射父子边 | +| 输出消息 | 从内容更改为文档 ID | + +### Chunker 变更 + +#### 当前状态 + +接收页面/文本内容 +分割成块 +将块内容转发到下游处理器 +不与 librarian 或 triple store 交互 + +#### 必需的变更 + +**1. 更改输入处理** + +接收文档 ID 而不是内容,从 librarian 获取。 +向 chunker 服务添加 librarian 客户端 +使用文档 ID 获取页面内容 + +**2. 新接口:Librarian 客户端(写入)** + +将每个块保存为 librarian 中的子文档。 +对于每个块:使用 parent = 页面文档 ID 调用 `add-child-document` + +**3. 新接口:Triple store 连接** + +向知识图谱发射父子边。 +添加 triple store 客户端/发布器 +对于每个块:发射链接块文档到页面文档的边 + +**4. 更改输出格式** + +同时转发块文档 ID 和块内容(块处理后的优化)。 +下游处理器接收 ID 用于溯源 + 用于处理的内容 + +#### 接口变更摘要 + +| 接口 | 变更 | +|-----------|--------| +| 输入消息 | 从内容更改为文档 ID | +| Librarian | 新的输出(读取 + 写入)- 获取内容,保存子文档 | +| Triple store | 新的输出 - 发射父子边 | +| 输出消息 | 从仅包含内容更改为 ID + 内容 | + +### Knowledge Extractor 变更 + +#### 当前状态 + +接收块内容 +提取三元组和嵌入 +发送到 triple store 和 embedding store +`subjectOf` 关系指向顶级文档(不是块) + +#### 必需的变更 + +**1. 更改输入处理** + +接收块文档 ID 以及内容。 +使用块 ID 用于溯源链接(内容已包含在优化中) + +**2. 更新三元组溯源** + +将提取的三元组链接到块(而不是顶级文档)。 +使用重构来创建指向边的边 +`subjectOf` 关系:三元组 → 块文档 ID +首次使用现有的重构支持 + +**3. 更新嵌入溯源** + +将嵌入实体 ID 链接到块。 +发射边:嵌入实体 ID → 块文档 ID + +#### 接口变更摘要 + +| 接口 | 变更 | +|-----------|--------| +| 输入消息 | 期望块 ID + 内容(不是仅包含内容) | +| Triple store | 使用重构进行三元组 → 块溯源 | +| 嵌入溯源 | 将实体 ID 链接到块 ID | + +## 引用 + +查询时溯源:`docs/tech-specs/query-time-provenance.md` +PROV-O 标准用于溯源建模 +知识图谱中现有的源元数据(需要审计) diff --git a/docs/tech-specs/flow-class-definition.ar.md b/docs/tech-specs/flow-class-definition.ar.md new file mode 100644 index 00000000..df048c86 --- /dev/null +++ b/docs/tech-specs/flow-class-definition.ar.md @@ -0,0 +1,277 @@ +# مواصفات تعريف مخطط التدفق + +## نظرة عامة + +يحدد مخطط التدفق قالبًا كاملاً لنمط تدفق البيانات في نظام TrustGraph. عند تنفيذه، فإنه ينشئ شبكة مترابطة من المعالجات التي تتعامل مع استيعاب البيانات ومعالجتها وتخزينها والاستعلام عنها كنظام موحد. + +## الهيكل + +يتكون تعريف مخطط التدفق من خمسة أقسام رئيسية: + +### 1. قسم الفئة +يحدد معالجات الخدمات المشتركة التي يتم إنشاؤها مرة واحدة لكل مخطط تدفق. تتعامل هذه المعالجات مع الطلبات من جميع مثيلات التدفق لهذه الفئة. + +```json +"class": { + "service-name:{class}": { + "request": "queue-pattern:{class}", + "response": "queue-pattern:{class}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**الخصائص:** +مشتركة عبر جميع مثيلات التدفق من نفس الفئة. +عادةً ما تكون خدمات مكلفة أو غير تعتمد على الحالة (نماذج لغوية كبيرة، نماذج تضمين). +استخدم متغير القالب `{class}` لتسمية قائمة الانتظار. +يمكن أن تكون الإعدادات قيمًا ثابتة أو مُعَلمة باستخدام صيغة `{parameter-name}`. +أمثلة: `embeddings:{class}`، `text-completion:{class}`، `graph-rag:{class}`. + +### 2. قسم التدفق +يحدد المعالجات الخاصة بالتدفق والتي يتم إنشاؤها لكل مثيل تدفق فردي. يحصل كل تدفق على مجموعة معزولة خاصة به من هذه المعالجات. + +```json +"flow": { + "processor-name:{id}": { + "input": "queue-pattern:{id}", + "output": "queue-pattern:{id}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**الخصائص:** +نسخة فريدة لكل تدفق. +التعامل مع البيانات والحالة الخاصة بالتدفق. +استخدام متغير القالب `{id}` لأسماء قوائم الانتظار. +يمكن أن تكون الإعدادات قيمًا ثابتة أو مُعَلمة باستخدام صيغة `{parameter-name}`. +أمثلة: `chunker:{id}`، `pdf-decoder:{id}`، `kg-extract-relationships:{id}`. + +### القسم 3: الواجهات +يحدد نقاط الدخول وعقود التفاعل للتدفق. تشكل هذه الواجهة البرمجية (API) للأنظمة الخارجية وتواصل المكونات الداخلية. + +يمكن أن تتخذ الواجهات شكلين: + +**نمط الإرسال والإهمال** (قائمة انتظار واحدة): +```json +"interfaces": { + "document-load": "persistent://tg/flow/document-load:{id}", + "triples-store": "persistent://tg/flow/triples-store:{id}" +} +``` + +**نمط الطلب/الاستجابة** (كائن يحتوي على حقول الطلب/الاستجابة): +```json +"interfaces": { + "embeddings": { + "request": "non-persistent://tg/request/embeddings:{class}", + "response": "non-persistent://tg/response/embeddings:{class}" + } +} +``` + +**أنواع الواجهات:** +**نقاط الدخول:** الأماكن التي تقوم الأنظمة الخارجية بإدخال البيانات (`document-load`، `agent`) +**واجهات الخدمات:** أنماط الطلب/الاستجابة للخدمات (`embeddings`، `text-completion`) +**واجهات البيانات:** نقاط اتصال تدفق البيانات من نوع "أرسل وانتهى" (`triples-store`، `entity-contexts-load`) + +### القسم الرابع: معلمات +يربط أسماء المعلمات الخاصة بالتدفق بتعريفات المعلمات المخزنة مركزيًا: + +```json +"parameters": { + "model": "llm-model", + "temp": "temperature", + "chunk": "chunk-size" +} +``` + +**الخصائص:** +المفاتيح هي أسماء المعلمات المستخدمة في إعدادات المعالج (مثل: `{model}`) +القيم تشير إلى تعريفات المعلمات المخزنة في schema/config +يتيح إعادة استخدام تعريفات المعلمات الشائعة عبر التدفقات. +يقلل من تكرار مخططات المعلمات. + +### 5. البيانات الوصفية +معلومات إضافية حول مخطط التدفق: + +```json +"description": "Human-readable description", +"tags": ["capability-1", "capability-2"] +``` + +## متغيرات القالب + +### متغيرات النظام + +#### {id} +يتم استبدالها بمعرّف مثيل التدفق الفريد. +تقوم بإنشاء موارد معزولة لكل تدفق. +مثال: `flow-123`، `customer-A-flow` + +#### {class} +يتم استبدالها باسم مخطط التدفق. +تقوم بإنشاء موارد مشتركة عبر التدفقات من نفس الفئة. +مثال: `standard-rag`، `enterprise-rag` + +### متغيرات المعلمات + +#### {parameter-name} +معلمات مخصصة يتم تعريفها في وقت بدء التدفق. +تتطابق أسماء المعلمات مع المفاتيح الموجودة في قسم `parameters` الخاص بالتدفق. +تُستخدم في إعدادات المعالج لتخصيص السلوك. +أمثلة: `{model}`، `{temp}`، `{chunk}` +يتم استبدالها بالقيم المقدمة عند بدء التدفق. +يتم التحقق من صحتها مقابل تعريفات المعلمات المخزنة مركزيًا. + +## إعدادات المعالج + +توفر الإعدادات قيم التكوين للمعالجات في وقت الإنشاء. يمكن أن تكون: + +### إعدادات ثابتة +قيم مباشرة لا تتغير: +```json +"settings": { + "model": "gemma3:12b", + "temperature": 0.7, + "max_retries": 3 +} +``` + +### الإعدادات ذات المعلمات +القيم التي تستخدم معلمات يتم توفيرها عند بدء تشغيل التدفق: +```json +"settings": { + "model": "{model}", + "temperature": "{temp}", + "endpoint": "https://{region}.api.example.com" +} +``` + +تتوافق أسماء المعلمات في الإعدادات مع المفاتيح في قسم `parameters` الخاص بالتدفق. + +### أمثلة للإعدادات + +**معالج نماذج اللغة الكبيرة مع المعلمات:** +```json +// In parameters section: +"parameters": { + "model": "llm-model", + "temp": "temperature", + "tokens": "max-tokens", + "key": "openai-api-key" +} + +// In processor definition: +"text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "settings": { + "model": "{model}", + "temperature": "{temp}", + "max_tokens": "{tokens}", + "api_key": "{key}" + } +} +``` + +**تقسيم النص بإعدادات ثابتة ومعلمات:** +```json +// In parameters section: +"parameters": { + "chunk": "chunk-size" +} + +// In processor definition: +"chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "settings": { + "chunk_size": "{chunk}", + "chunk_overlap": 100, + "encoding": "utf-8" + } +} +``` + +## أنماط قائمة الانتظار (بالمسر) + +تستخدم مخططات التدفق Apache Pulsar للرسائل. تتبع أسماء قوائم الانتظار تنسيق بالمسر: +``` +://// +``` + +### المكونات: +**الاستمرارية**: `persistent` أو `non-persistent` (وضع استمرارية Pulsar) +**المستأجر**: `tg` لتعريفات مخطط التدفق المقدمة من TrustGraph +**مساحة الاسم**: تشير إلى نمط الرسائل + `flow`: خدمات الإرسال والاستقبال + `request`: الجزء الطلب من خدمات الطلب/الاستجابة + `response`: الجزء الاستجابة من خدمات الطلب/الاستجابة +**الموضوع**: اسم قائمة الانتظار/الموضوع المحدد مع متغيرات القالب + +### قوائم الانتظار الدائمة +النمط: `persistent://tg/flow/:{id}` +تستخدم لخدمات الإرسال والاستقبال وتدفق البيانات المتينة +تظل البيانات في تخزين Pulsar عبر عمليات إعادة التشغيل +مثال: `persistent://tg/flow/chunk-load:{id}` + +### قوائم الانتظار غير الدائمة +النمط: `non-persistent://tg/request/:{class}` أو `non-persistent://tg/response/:{class}` +تستخدم لأنماط الرسائل الطلب/الاستجابة +مؤقتة، ولا يتم حفظها على القرص بواسطة Pulsar +زمن انتقال أقل، ومناسبة للاتصالات على غرار RPC +مثال: `non-persistent://tg/request/embeddings:{class}` + +## بنية تدفق البيانات + +ينشئ مخطط التدفق تدفق بيانات موحد حيث: + +1. **مسار معالجة المستندات**: يبدأ من الاستيعاب ويمر بالتحويل إلى التخزين +2. **خدمات الاستعلام**: معالجات مدمجة تستعلم عن نفس مخازن البيانات والخدمات +3. **الخدمات المشتركة**: معالجات مركزية يمكن لجميع التدفقات استخدامها +4. **كتابة التخزين**: تحفظ البيانات المعالجة في المخازن المناسبة + +تعمل جميع المعالجات (سواء `{id}` و `{class}`) معًا كرسوم بيانية لتدفق بيانات متماسك، وليس كأنظمة منفصلة. + +## مثال على إنشاء التدفق + +المعطيات: +معرف مثيل التدفق: `customer-A-flow` +مخطط التدفق: `standard-rag` +تعيينات معلمات التدفق: + `"model": "llm-model"` + `"temp": "temperature"` + `"chunk": "chunk-size"` +المعلمات المقدمة من المستخدم: + `model`: `gpt-4` + `temp`: `0.5` + `chunk`: `512` + +التوسعات القالبية: +`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow` +`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag` +`"model": "{model}"` → `"model": "gpt-4"` +`"temperature": "{temp}"` → `"temperature": "0.5"` +`"chunk_size": "{chunk}"` → `"chunk_size": "512"` + +هذا ينشئ: +مسار معالجة مستندات معزول لـ `customer-A-flow` +خدمة تضمين مشتركة لجميع تدفقات `standard-rag` +تدفق بيانات كامل من استيعاب المستندات إلى الاستعلام +المعالجات مُكوَّنة بقيم المعلمات المقدمة + +## المزايا + +1. **كفاءة الموارد**: يتم مشاركة الخدمات المكلفة عبر التدفقات +2. **عزل التدفق**: يحتوي كل تدفق على مسار معالجة بيانات خاص به +3. **قابلية التوسع**: يمكن إنشاء مثيلات متعددة من نفس القالب +4. **النمطية**: فصل واضح بين المكونات المشتركة والمكونات الخاصة بالتدفق +5. **بنية موحدة**: الاستعلام والمعالجة جزء من تدفق البيانات نفسه \ No newline at end of file diff --git a/docs/tech-specs/flow-class-definition.es.md b/docs/tech-specs/flow-class-definition.es.md new file mode 100644 index 00000000..5c77a230 --- /dev/null +++ b/docs/tech-specs/flow-class-definition.es.md @@ -0,0 +1,277 @@ +# Especificación de la Definición del Esquema de Flujo + +## Resumen + +Un esquema de flujo define una plantilla de patrón de flujo de datos completo en el sistema TrustGraph. Cuando se instancia, crea una red interconectada de procesadores que manejan la ingesta de datos, el procesamiento, el almacenamiento y la consulta como un sistema unificado. + +## Estructura + +Una definición de esquema de flujo consta de cinco secciones principales: + +### 1. Sección de Clase +Define procesadores de servicios compartidos que se instancian una vez por esquema de flujo. Estos procesadores manejan las solicitudes de todas las instancias de flujo de esta clase. + +```json +"class": { + "service-name:{class}": { + "request": "queue-pattern:{class}", + "response": "queue-pattern:{class}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Características:** +Compartidas entre todas las instancias de flujo de la misma clase. +Típicamente servicios costosos o sin estado (modelos de lenguaje grandes, modelos de embedding). +Utilice la variable de plantilla `{class}` para el nombre de la cola. +Los ajustes pueden ser valores fijos o parametrizados con la sintaxis `{parameter-name}`. +Ejemplos: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}`. + +### 2. Sección de Flujo +Define los procesadores específicos del flujo que se instancian para cada instancia de flujo individual. Cada flujo obtiene su propio conjunto aislado de estos procesadores. + +```json +"flow": { + "processor-name:{id}": { + "input": "queue-pattern:{id}", + "output": "queue-pattern:{id}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Características:** +Instancia única por flujo +Maneja datos y estado específicos del flujo +Utilice la variable de plantilla `{id}` para el nombre de la cola +Los ajustes pueden ser valores fijos o parametrizados con la sintaxis `{parameter-name}` +Ejemplos: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}` + +### 3. Sección de Interfaces +Define los puntos de entrada y los contratos de interacción para el flujo. Estos forman la superficie de la API para sistemas externos y comunicación entre componentes internos. + +Las interfaces pueden adoptar dos formas: + +**Patrón de "Enviar y Olvidar"** (cola única): +```json +"interfaces": { + "document-load": "persistent://tg/flow/document-load:{id}", + "triples-store": "persistent://tg/flow/triples-store:{id}" +} +``` + +**Patrón de solicitud/respuesta** (objeto con campos de solicitud/respuesta): +```json +"interfaces": { + "embeddings": { + "request": "non-persistent://tg/request/embeddings:{class}", + "response": "non-persistent://tg/response/embeddings:{class}" + } +} +``` + +**Tipos de Interfaces:** +**Puntos de Entrada**: Lugares donde los sistemas externos inyectan datos (`document-load`, `agent`) +**Interfaces de Servicio**: Patrones de solicitud/respuesta para servicios (`embeddings`, `text-completion`) +**Interfaces de Datos**: Puntos de conexión de flujo de datos "dispara y olvida" (`triples-store`, `entity-contexts-load`) + +### 4. Sección de Parámetros +Mapea los nombres de parámetros específicos del flujo a definiciones de parámetros almacenadas centralmente: + +```json +"parameters": { + "model": "llm-model", + "temp": "temperature", + "chunk": "chunk-size" +} +``` + +**Características:** +Las claves son nombres de parámetros utilizados en la configuración del procesador (por ejemplo, `{model}`) +Los valores hacen referencia a definiciones de parámetros almacenadas en schema/config +Permite la reutilización de definiciones de parámetros comunes en diferentes flujos +Reduce la duplicación de esquemas de parámetros + +### 5. Metadatos +Información adicional sobre el plano del flujo: + +```json +"description": "Human-readable description", +"tags": ["capability-1", "capability-2"] +``` + +## Variables de Plantilla + +### Variables del Sistema + +#### {id} +Reemplazado con el identificador único de la instancia del flujo. +Crea recursos aislados para cada flujo. +Ejemplo: `flow-123`, `customer-A-flow` + +#### {class} +Reemplazado con el nombre de la plantilla del flujo. +Crea recursos compartidos entre flujos de la misma clase. +Ejemplo: `standard-rag`, `enterprise-rag` + +### Variables de Parámetro + +#### {parameter-name} +Parámetros personalizados definidos en el momento de la ejecución del flujo. +Los nombres de los parámetros coinciden con las claves en la sección `parameters` del flujo. +Se utilizan en la configuración de los procesadores para personalizar el comportamiento. +Ejemplos: `{model}`, `{temp}`, `{chunk}` +Reemplazado con los valores proporcionados al iniciar el flujo. +Validados contra definiciones de parámetros almacenadas centralmente. + +## Configuración de Procesadores + +La configuración proporciona valores de configuración a los procesadores en el momento de la creación. Pueden ser: + +### Configuración Fija +Valores directos que no cambian: +```json +"settings": { + "model": "gemma3:12b", + "temperature": 0.7, + "max_retries": 3 +} +``` + +### Configuración parametrizada +Valores que utilizan parámetros proporcionados al iniciar el flujo: +```json +"settings": { + "model": "{model}", + "temperature": "{temp}", + "endpoint": "https://{region}.api.example.com" +} +``` + +Los nombres de los parámetros en la configuración corresponden a las claves en la sección `parameters` del flujo. + +### Ejemplos de configuración + +**Procesador LLM con parámetros:** +```json +// In parameters section: +"parameters": { + "model": "llm-model", + "temp": "temperature", + "tokens": "max-tokens", + "key": "openai-api-key" +} + +// In processor definition: +"text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "settings": { + "model": "{model}", + "temperature": "{temp}", + "max_tokens": "{tokens}", + "api_key": "{key}" + } +} +``` + +**Chunker con Configuraciones Fijas y Parametrizadas:** +```json +// In parameters section: +"parameters": { + "chunk": "chunk-size" +} + +// In processor definition: +"chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "settings": { + "chunk_size": "{chunk}", + "chunk_overlap": 100, + "encoding": "utf-8" + } +} +``` + +## Patrones de Colas (Pulsar) + +Los planos de flujo utilizan Apache Pulsar para el envío de mensajes. Los nombres de las colas siguen el formato de Pulsar: +``` +://// +``` + +### Componentes: +**persistencia**: `persistent` or `non-persistent` (Modo de persistencia de Pulsar) +**inquilino**: `tg` para definiciones de planos de flujo proporcionados por TrustGraph +**espacio de nombres**: Indica el patrón de mensajería + `flow`: Servicios de envío y olvido + `request`: Parte de solicitud de servicios de solicitud/respuesta + `response`: Parte de respuesta de servicios de solicitud/respuesta +**tema**: El nombre específico de la cola/tema con variables de plantilla + +### Colas Persistentes +Patrón: `persistent://tg/flow/:{id}` +Utilizado para servicios de envío y olvido y flujo de datos duradero +Los datos persisten en el almacenamiento de Pulsar a través de reinicios +Ejemplo: `persistent://tg/flow/chunk-load:{id}` + +### Colas No Persistentes +Patrón: `non-persistent://tg/request/:{class}` or `non-persistent://tg/response/:{class}` +Utilizado para patrones de mensajería de solicitud/respuesta +Efímero, no se persiste en disco por Pulsar +Menor latencia, adecuado para comunicación estilo RPC +Ejemplo: `non-persistent://tg/request/embeddings:{class}` + +## Arquitectura del Flujo de Datos + +El plano de flujo crea un flujo de datos unificado donde: + +1. **Pipeline de Procesamiento de Documentos**: Fluye desde la ingesta hasta la transformación y el almacenamiento +2. **Servicios de Consulta**: Procesadores integrados que consultan las mismas bases de datos y servicios +3. **Servicios Compartidos**: Procesadores centralizados que todos los flujos pueden utilizar +4. **Escritores de Almacenamiento**: Persisten los datos procesados en los almacenes apropiados + +Todos los procesadores (tanto `{id}` como `{class}`) trabajan juntos como un gráfico de flujo de datos cohesivo, no como sistemas separados. + +## Ejemplo de Instanciación de Flujo + +Dado: +ID de instancia de flujo: `customer-A-flow` +Plano de flujo: `standard-rag` +Mapeos de parámetros de flujo: + `"model": "llm-model"` + `"temp": "temperature"` + `"chunk": "chunk-size"` +Parámetros proporcionados por el usuario: + `model`: `gpt-4` + `temp`: `0.5` + `chunk`: `512` + +Expansiones de plantilla: +`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow` +`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag` +`"model": "{model}"` → `"model": "gpt-4"` +`"temperature": "{temp}"` → `"temperature": "0.5"` +`"chunk_size": "{chunk}"` → `"chunk_size": "512"` + +Esto crea: +Pipeline de procesamiento de documentos aislado para `customer-A-flow` +Servicio de incrustación compartido para todos los flujos `standard-rag` +Flujo de datos completo desde la ingesta de documentos hasta la consulta +Procesadores configurados con los valores de parámetro proporcionados + +## Beneficios + +1. **Eficiencia de Recursos**: Los servicios costosos se comparten entre los flujos +2. **Aislamiento de Flujos**: Cada flujo tiene su propio pipeline de procesamiento de datos +3. **Escalabilidad**: Se pueden instanciar múltiples flujos desde la misma plantilla +4. **Modularidad**: Clara separación entre componentes compartidos y específicos del flujo +5. **Arquitectura Unificada**: La consulta y el procesamiento son parte del mismo flujo de datos \ No newline at end of file diff --git a/docs/tech-specs/flow-class-definition.he.md b/docs/tech-specs/flow-class-definition.he.md new file mode 100644 index 00000000..2ba61e83 --- /dev/null +++ b/docs/tech-specs/flow-class-definition.he.md @@ -0,0 +1,277 @@ +# הגדרת מפרט תוכנית זרימה + +## סקירה כללית + +תוכנית זרימה מגדירה תבנית מלאה של דפוסי זרימת נתונים במערכת TrustGraph. כאשר היא מופעלת, היא יוצרת רשת מקושרת של מעבדים המטפלים בקליטת נתונים, עיבוד, אחסון ושליפה כחלק ממערכת מאוחדת. + +## מבנה + +הגדרת תוכנית זרימה מורכבת מחמש קטעים עיקריים: + +### 1. קטע מחלקה +מגדיר מעבדי שירות משותפים המופעלים פעם אחת לכל תוכנית זרימה. מעבדים אלה מטפלים בבקשות מכל מופעי הזרימה של מחלקה זו. + +```json +"class": { + "service-name:{class}": { + "request": "queue-pattern:{class}", + "response": "queue-pattern:{class}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**מאפיינים:** +משותפים לכל מופעי זרימה מאותו סוג. +בדרך כלל שירותים יקרים או חסרי מצב (מודלים של שפה גדולים, מודלים להטמעה). +השתמשו במשתנה תבנית `{class}` עבור שמות תורים. +הגדרות יכולות להיות ערכים קבועים או פרמטריות באמצעות תחביר `{parameter-name}`. +דוגמאות: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}` + +### 2. סעיף זרימה +מגדיר מעבדים ספציפיים לזרימה, אשר מופעלים עבור כל מופע זרימה בודד. לכל זרימה יש סט נפרד משלה של מעבדים אלה. + +```json +"flow": { + "processor-name:{id}": { + "input": "queue-pattern:{id}", + "output": "queue-pattern:{id}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**מאפיינים:** +מופע ייחודי לכל זרימה +טיפול בנתונים ובמצב ספציפיים לזרימה +שימוש במשתנה תבנית `{id}` עבור שמות תורים +הגדרות יכולות להיות ערכים קבועים או פרמטריות באמצעות תחביר `{parameter-name}` +דוגמאות: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}` + +### 3. סעיף ממשקים +מגדיר את נקודות הכניסה ואת חוזי האינטראקציה עבור הזרימה. אלה מהווים את ממשק ה-API עבור מערכות חיצוניות ותקשורת בין רכיבים פנימיים. + +ממשקים יכולים לקבל שתי צורות: + +**תבנית "שלח ושכח"** (תור יחיד): +```json +"interfaces": { + "document-load": "persistent://tg/flow/document-load:{id}", + "triples-store": "persistent://tg/flow/triples-store:{id}" +} +``` + +**תבנית בקשה/תגובה** (אובייקט עם שדות בקשה/תגובה): +```json +"interfaces": { + "embeddings": { + "request": "non-persistent://tg/request/embeddings:{class}", + "response": "non-persistent://tg/response/embeddings:{class}" + } +} +``` + +**סוגי ממשקים:** +**נקודות כניסה:** נקודות שבהן מערכות חיצוניות מזריקות נתונים (`document-load`, `agent`) +**ממשקי שירות:** תבניות בקשה/תגובה עבור שירותים (`embeddings`, `text-completion`) +**ממשקי נתונים:** נקודות חיבור לזרימת נתונים מסוג "שלח וסגור" (`triples-store`, `entity-contexts-load`) + +### 4. סעיף פרמטרים +ממפה שמות פרמטרים ספציפיים לזרימה להגדרות פרמטרים המאוחסנות באופן מרכזי: + +```json +"parameters": { + "model": "llm-model", + "temp": "temperature", + "chunk": "chunk-size" +} +``` + +**מאפיינים:** +המפתחות הם שמות הפרמטרים המשמשים בהגדרות המעבד (לדוגמה, `{model}`) +הערכים מפנים להגדרות הפרמטרים המאוחסנות ב-schema/config +מאפשר שימוש חוזר בהגדרות פרמטרים נפוצות בין זרימות +מפחית כפילויות של סכימות פרמטרים + +### 5. מטא-נתונים +מידע נוסף על תוכנית הזרימה: + +```json +"description": "Human-readable description", +"tags": ["capability-1", "capability-2"] +``` + +## משתנים בתבנית + +### משתנים של המערכת + +#### {id} +מוחלף במזהה הייחודי של מופע ה-flow +יוצר משאבים מבודדים עבור כל flow +דוגמה: `flow-123`, `customer-A-flow` + +#### {class} +מוחלף בשם התבנית של ה-flow +יוצר משאבים משותפים בין flows של אותה תבנית +דוגמה: `standard-rag`, `enterprise-rag` + +### משתנים של פרמטרים + +#### {parameter-name} +פרמטרים מותאמים אישית המוגדרים בזמן הפעלת ה-flow +שמות הפרמטרים תואמים למפתחות במקטע `parameters` של ה-flow +משמש בהגדרות של מעבדים כדי להתאים אישית את ההתנהגות +דוגמאות: `{model}`, `{temp}`, `{chunk}` +מוחלף בערכים המסופקים בעת הפעלת ה-flow +מאומתים מול הגדרות פרמטרים המאוחסנות באופן מרכזי + +## הגדרות מעבד + +הגדרות מספקות ערכי תצורה למעבדים בזמן יצירתם. ניתן להגדיר אותן כ: + +### הגדרות קבועות +ערכים ישירים שאינם משתנים: +```json +"settings": { + "model": "gemma3:12b", + "temperature": 0.7, + "max_retries": 3 +} +``` + +### הגדרות מותאמות אישית +ערכים המשתמשים בפרמטרים המסופקים בעת הפעלת ה-flow: +```json +"settings": { + "model": "{model}", + "temperature": "{temp}", + "endpoint": "https://{region}.api.example.com" +} +``` + +שמות הפרמטרים בהגדרות תואמים למפתחות במקטע `parameters` של ה-flow. + +### דוגמאות להגדרות + +**מעבד LLM עם פרמטרים:** +```json +// In parameters section: +"parameters": { + "model": "llm-model", + "temp": "temperature", + "tokens": "max-tokens", + "key": "openai-api-key" +} + +// In processor definition: +"text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "settings": { + "model": "{model}", + "temperature": "{temp}", + "max_tokens": "{tokens}", + "api_key": "{key}" + } +} +``` + +**חלוקה למקטעים עם הגדרות קבועות וניתנות לשינוי:** +```json +// In parameters section: +"parameters": { + "chunk": "chunk-size" +} + +// In processor definition: +"chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "settings": { + "chunk_size": "{chunk}", + "chunk_overlap": 100, + "encoding": "utf-8" + } +} +``` + +## תבניות תורים (פולסר) + +תבניות זרימה משתמשות ב-Apache Pulsar עבור העברת הודעות. שמות התורים עוקבים אחר הפורמט של פולסר: +``` +://// +``` + +### רכיבים: +**persistence**: `persistent` או `non-persistent` (מצב אחסון של Pulsar) +**tenant**: `tg` עבור הגדרות תבניות זרימה המסופקות על ידי TrustGraph +**namespace**: מציין את דפוס העברת ההודעות + `flow`: שירותים מסוג "שלח וגע" (fire-and-forget) + `request`: החלק של הבקשה בשירותי בקשה/תגובה (request/response) + `response`: החלק של התגובה בשירותי בקשה/תגובה (request/response) +**topic**: שם התור/נושא הספציפי עם משתני תבנית + +### תורים קבועים (Persistent Queues) +דפוס: `persistent://tg/flow/:{id}` +משמש עבור שירותים מסוג "שלח וגע" וזרימת נתונים עמידה +הנתונים נשמרים באחסון של Pulsar בין הפעלות מחדש +דוגמה: `persistent://tg/flow/chunk-load:{id}` + +### תורים לא קבועים (Non-Persistent Queues) +דפוס: `non-persistent://tg/request/:{class}` או `non-persistent://tg/response/:{class}` +משמש עבור דפוסי העברת הודעות מסוג בקשה/תגובה +זמני, אינו נשמר בדיסק על ידי Pulsar +השהיה נמוכה יותר, מתאים לתקשורת בסגנון RPC +דוגמה: `non-persistent://tg/request/embeddings:{class}` + +## ארכיטקטורת זרימת נתונים + +תבנית זרימת הנתונים יוצרת זרימה מאוחדת שבה: + +1. **צינור עיבוד מסמכים**: זרימה מאיסוף דרך טרנספורמציה לאחסון +2. **שירותי שאילתות**: מעבדים משולבים השואלים את אותם מאגרי נתונים ושירותים +3. **שירותים משותפים**: מעבדים מרכזיים שכל הזרימות יכולות להשתמש בהם +4. **כותבי אחסון**: שומרים נתונים מעובדים לאחסונים המתאימים + +כל המעבדים (גם `{id}` וגם `{class}`) עובדים יחד כגרף זרימת נתונים מגובש, ולא כמערכות נפרדות. + +## דוגמה להפעלה של זרימה + +בהינתן: +מזהה מופע של זרימה: `customer-A-flow` +תבנית זרימה: `standard-rag` +מיפוי פרמטרים של זרימה: + `"model": "llm-model"` + `"temp": "temperature"` + `"chunk": "chunk-size"` +פרמטרים שסופקו על ידי המשתמש: + `model`: `gpt-4` + `temp`: `0.5` + `chunk`: `512` + +הרחבות תבניות: +`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow` +`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag` +`"model": "{model}"` → `"model": "gpt-4"` +`"temperature": "{temp}"` → `"temperature": "0.5"` +`"chunk_size": "{chunk}"` → `"chunk_size": "512"` + +זה יוצר: +צינור עיבוד מסמכים נפרד עבור `customer-A-flow` +שירות הטמעה משותף עבור כל זרימות `standard-rag` +זרימת נתונים שלמה מאיסוף מסמכים דרך שאילתות +מעבדים מוגדרים עם ערכי הפרמטרים שסופקו + +## יתרונות + +1. **יעילות משאבים**: שירותים יקרים משותפים בין זרימות +2. **בידוד זרימות**: לכל זרימה יש את צינור עיבוד הנתונים שלה +3. **מדרגיות**: ניתן להפעיל מספר זרימות מאותה תבנית +4. **מודולריות**: הפרדה ברורה בין רכיבים משותפים ורכיבים ספציפיים לזרימה +5. **ארכיטקטורה מאוחדת**: שאילתות ועיבוד הם חלק מאותה זרימת נתונים \ No newline at end of file diff --git a/docs/tech-specs/flow-class-definition.hi.md b/docs/tech-specs/flow-class-definition.hi.md new file mode 100644 index 00000000..efd9db77 --- /dev/null +++ b/docs/tech-specs/flow-class-definition.hi.md @@ -0,0 +1,277 @@ +# फ्लो ब्लूप्रिंट परिभाषा विनिर्देश + +## अवलोकन + +एक फ्लो ब्लूप्रिंट ट्रस्टग्राफ सिस्टम में एक पूर्ण डेटाफ्लो पैटर्न टेम्पलेट को परिभाषित करता है। जब इसे कार्यान्वित किया जाता है, तो यह प्रोसेसर का एक अंतर्संबंधित नेटवर्क बनाता है जो डेटा इनपुट, प्रसंस्करण, भंडारण और क्वेरी को एक एकीकृत प्रणाली के रूप में संभालता है। + +## संरचना + +एक फ्लो ब्लूप्रिंट परिभाषा में पाँच मुख्य अनुभाग होते हैं: + +### 1. क्लास अनुभाग +यह साझा सेवा प्रोसेसर को परिभाषित करता है जिन्हें प्रत्येक फ्लो ब्लूप्रिंट के लिए एक बार इंस्टेंट किया जाता है। ये प्रोसेसर इस क्लास के सभी फ्लो उदाहरणों से अनुरोधों को संभालते हैं। + +```json +"class": { + "service-name:{class}": { + "request": "queue-pattern:{class}", + "response": "queue-pattern:{class}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**विशेषताएं:** +समान वर्ग के सभी फ्लो उदाहरणों में साझा किया जाता है। +आमतौर पर महंगी या स्टेटलेस सेवाएं (एलएलएम, एम्बेडिंग मॉडल)। +कतार नामकरण के लिए `{class}` टेम्पलेट वेरिएबल का उपयोग करें। +सेटिंग्स निश्चित मान हो सकती हैं या `{parameter-name}` सिंटैक्स के साथ पैरामीटराइज़ की जा सकती हैं। +उदाहरण: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}` + +### 2. फ्लो सेक्शन +फ्लो-विशिष्ट प्रोसेसर को परिभाषित करता है जिन्हें प्रत्येक व्यक्तिगत फ्लो उदाहरण के लिए इंस्टेंट किया जाता है। प्रत्येक फ्लो को इन प्रोसेसर का अपना अलग सेट मिलता है। + +```json +"flow": { + "processor-name:{id}": { + "input": "queue-pattern:{id}", + "output": "queue-pattern:{id}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**विशेषताएं:** +प्रत्येक प्रवाह के लिए अद्वितीय उदाहरण। +प्रवाह-विशिष्ट डेटा और स्थिति को संभालें। +कतार नामकरण के लिए `{id}` टेम्पलेट चर का उपयोग करें। +सेटिंग्स या तो निश्चित मान हो सकती हैं या `{parameter-name}` सिंटैक्स के साथ पैरामीटराइज़ की जा सकती हैं। +उदाहरण: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}` + +### 3. इंटरफेस अनुभाग +यह प्रवाह के लिए प्रवेश बिंदुओं और इंटरैक्शन अनुबंधों को परिभाषित करता है। ये बाहरी प्रणालियों और आंतरिक घटक संचार के लिए एपीआई सतह बनाते हैं। + +इंटरफेस दो रूप ले सकते हैं: + +**फायर-एंड-फॉरगेट पैटर्न** (एक कतार): +```json +"interfaces": { + "document-load": "persistent://tg/flow/document-load:{id}", + "triples-store": "persistent://tg/flow/triples-store:{id}" +} +``` + +**अनुरोध/प्रतिक्रिया पैटर्न** (अनुरोध/प्रतिक्रिया फ़ील्ड वाले ऑब्जेक्ट): +```json +"interfaces": { + "embeddings": { + "request": "non-persistent://tg/request/embeddings:{class}", + "response": "non-persistent://tg/response/embeddings:{class}" + } +} +``` + +**इंटरफेस के प्रकार:** +**एंट्री पॉइंट:** वे स्थान जहाँ बाहरी सिस्टम डेटा इंजेक्ट करते हैं (`document-load`, `agent`) +**सर्विस इंटरफेस:** सेवाओं के लिए अनुरोध/प्रतिक्रिया पैटर्न (`embeddings`, `text-completion`) +**डेटा इंटरफेस:** फायर-एंड-फॉरगेट डेटा प्रवाह कनेक्शन बिंदु (`triples-store`, `entity-contexts-load`) + +### 4. पैरामीटर अनुभाग +यह प्रवाह-विशिष्ट पैरामीटर नामों को केंद्रीय रूप से संग्रहीत पैरामीटर परिभाषाओं से जोड़ता है: + +```json +"parameters": { + "model": "llm-model", + "temp": "temperature", + "chunk": "chunk-size" +} +``` + +**विशेषताएं:** +कुंजियाँ प्रोसेसर सेटिंग्स में उपयोग किए जाने वाले पैरामीटर नामों को संदर्भित करती हैं (उदाहरण के लिए, `{model}`) +मान स्कीमा/कॉन्फ़िगरेशन में संग्रहीत पैरामीटर परिभाषाओं को संदर्भित करते हैं। +यह सामान्य पैरामीटर परिभाषाओं को विभिन्न फ्लो में पुन: उपयोग करने की अनुमति देता है। +पैरामीटर स्कीमा की डुप्लिकेसी को कम करता है। + +### 5. मेटाडेटा +फ्लो ब्लूप्रिंट के बारे में अतिरिक्त जानकारी: + +```json +"description": "Human-readable description", +"tags": ["capability-1", "capability-2"] +``` + +## टेम्पलेट वेरिएबल + +### सिस्टम वेरिएबल + +#### {id} +यह अद्वितीय फ्लो इंस्टेंस पहचानकर्ता से प्रतिस्थापित किया जाता है। +यह प्रत्येक फ्लो के लिए अलग-अलग संसाधन बनाता है। +उदाहरण: `flow-123`, `customer-A-flow` + +#### {class} +यह फ्लो ब्लूप्रिंट नाम से प्रतिस्थापित किया जाता है। +यह समान क्लास के फ्लो में साझा संसाधनों का निर्माण करता है। +उदाहरण: `standard-rag`, `enterprise-rag` + +### पैरामीटर वेरिएबल + +#### {पैरामीटर-नाम} +फ्लो लॉन्च करते समय परिभाषित कस्टम पैरामीटर। +पैरामीटर नाम फ्लो के `parameters` अनुभाग में कुंजियों से मेल खाते हैं। +प्रोसेसर सेटिंग्स में व्यवहार को अनुकूलित करने के लिए उपयोग किया जाता है। +उदाहरण: `{model}`, `{temp}`, `{chunk}` +फ्लो लॉन्च करते समय प्रदान किए गए मानों से प्रतिस्थापित किया जाता है। +केंद्रीय रूप से संग्रहीत पैरामीटर परिभाषाओं के विरुद्ध मान्य किया जाता है। + +## प्रोसेसर सेटिंग्स + +सेटिंग्स, इंस्टैंशिएशन के समय प्रोसेसरों को कॉन्फ़िगरेशन मान प्रदान करती हैं। वे निम्न हो सकते हैं: + +### फिक्स्ड सेटिंग्स +सीधे मान जो नहीं बदलते: +```json +"settings": { + "model": "gemma3:12b", + "temperature": 0.7, + "max_retries": 3 +} +``` + +### पैरामीटराइज़्ड सेटिंग्स +वे मान जो प्रवाह शुरू करते समय प्रदान किए गए पैरामीटर का उपयोग करते हैं: +```json +"settings": { + "model": "{model}", + "temperature": "{temp}", + "endpoint": "https://{region}.api.example.com" +} +``` + +सेटिंग्स में पैरामीटर नाम, प्रवाह के `parameters` अनुभाग में कुंजियों से मेल खाते हैं। + +### सेटिंग्स के उदाहरण + +**पैरामीटर के साथ एलएलएम प्रोसेसर:** +```json +// In parameters section: +"parameters": { + "model": "llm-model", + "temp": "temperature", + "tokens": "max-tokens", + "key": "openai-api-key" +} + +// In processor definition: +"text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "settings": { + "model": "{model}", + "temperature": "{temp}", + "max_tokens": "{tokens}", + "api_key": "{key}" + } +} +``` + +**निश्चित और पैरामीटराइज़्ड सेटिंग्स के साथ चंकर:** +```json +// In parameters section: +"parameters": { + "chunk": "chunk-size" +} + +// In processor definition: +"chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "settings": { + "chunk_size": "{chunk}", + "chunk_overlap": 100, + "encoding": "utf-8" + } +} +``` + +## क्यू पैटर्न (पल्सर) + +फ्लो ब्लूप्रिंट्स संदेश भेजने के लिए अपाचे पल्सर का उपयोग करते हैं। क्यू नामों का प्रारूप पल्सर प्रारूप का अनुसरण करता है: +``` +://// +``` + +### घटक: +**स्थायित्व**: `persistent` या `non-persistent` (पल्सर स्थायित्व मोड) +**किरायेदार**: ट्रस्टग्राफ द्वारा प्रदान किए गए प्रवाह ब्लूप्रिंट परिभाषाओं के लिए `tg` +**नामस्थान**: यह संदेश पैटर्न को इंगित करता है + `flow`: फायर-एंड-फॉरगेट सेवाएं + `request`: अनुरोध/प्रतिक्रिया सेवाओं का अनुरोध भाग + `response`: अनुरोध/प्रतिक्रिया सेवाओं का प्रतिक्रिया भाग +**विषय**: टेम्पलेट चर के साथ विशिष्ट कतार/विषय नाम + +### स्थायी कतारें +पैटर्न: `persistent://tg/flow/:{id}` +फायर-एंड-फॉरगेट सेवाओं और टिकाऊ डेटा प्रवाह के लिए उपयोग किया जाता है +डेटा पल्सर स्टोरेज में पुनरारंभों में बना रहता है +उदाहरण: `persistent://tg/flow/chunk-load:{id}` + +### गैर-स्थायी कतारें +पैटर्न: `non-persistent://tg/request/:{class}` या `non-persistent://tg/response/:{class}` +अनुरोध/प्रतिक्रिया संदेश पैटर्न के लिए उपयोग किया जाता है +अस्थिर, पल्सर द्वारा डिस्क पर संग्रहीत नहीं है +कम विलंबता, RPC-शैली संचार के लिए उपयुक्त +उदाहरण: `non-persistent://tg/request/embeddings:{class}` + +## डेटाफ्लो आर्किटेक्चर + +प्रवाह ब्लूप्रिंट एक एकीकृत डेटाफ्लो बनाता है जहां: + +1. **दस्तावेज़ प्रसंस्करण पाइपलाइन**: अंतर्ग्रहण से लेकर परिवर्तन और भंडारण तक का प्रवाह +2. **क्वेरी सेवाएं**: एकीकृत प्रोसेसर जो समान डेटा स्टोर और सेवाओं को क्वेरी करते हैं +3. **साझा सेवाएं**: केंद्रीय प्रोसेसर जिनका उपयोग सभी प्रवाह कर सकते हैं +4. **भंडारण लेखक**: संसाधित डेटा को उपयुक्त स्टोर में सहेजें + +सभी प्रोसेसर (दोनों `{id}` और `{class}`) एक सुसंगत डेटाफ्लो ग्राफ के रूप में एक साथ काम करते हैं, अलग-अलग सिस्टम के रूप में नहीं। + +## उदाहरण प्रवाह कार्यान्वयन + +दिया गया: +प्रवाह उदाहरण आईडी: `customer-A-flow` +प्रवाह ब्लूप्रिंट: `standard-rag` +प्रवाह पैरामीटर मैपिंग: + `"model": "llm-model"` + `"temp": "temperature"` + `"chunk": "chunk-size"` +उपयोगकर्ता-प्रदत्त पैरामीटर: + `model`: `gpt-4` + `temp`: `0.5` + `chunk`: `512` + +टेम्पलेट विस्तार: +`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow` +`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag` +`"model": "{model}"` → `"model": "gpt-4"` +`"temperature": "{temp}"` → `"temperature": "0.5"` +`"chunk_size": "{chunk}"` → `"chunk_size": "512"` + +यह बनाता है: +`customer-A-flow` के लिए अलग दस्तावेज़ प्रसंस्करण पाइपलाइन +सभी `standard-rag` प्रवाह के लिए साझा एम्बेडिंग सेवा +दस्तावेज़ अंतर्ग्रहण से लेकर क्वेरी तक का पूर्ण डेटाफ्लो +प्रोसेसर प्रदान किए गए पैरामीटर मानों के साथ कॉन्फ़िगर किए गए + +## लाभ + +1. **संसाधन दक्षता**: महंगी सेवाओं को प्रवाह में साझा किया जाता है +2. **प्रवाह अलगाव**: प्रत्येक प्रवाह का अपना डेटा प्रसंस्करण पाइपलाइन होता है +3. **मापनीयता**: एक ही टेम्पलेट से कई प्रवाहों को कार्यान्वित किया जा सकता है +4. **मॉड्यूलरिटी**: साझा और प्रवाह-विशिष्ट घटकों के बीच स्पष्ट अलगाव +5. **एकीकृत आर्किटेक्चर**: क्वेरी और प्रसंस्करण एक ही डेटाफ्लो का हिस्सा हैं \ No newline at end of file diff --git a/docs/tech-specs/flow-class-definition.pt.md b/docs/tech-specs/flow-class-definition.pt.md new file mode 100644 index 00000000..6efb4c38 --- /dev/null +++ b/docs/tech-specs/flow-class-definition.pt.md @@ -0,0 +1,277 @@ +# Especificação da Definição do Modelo de Fluxo + +## Visão Geral + +Um modelo de fluxo define um modelo de padrão de fluxo de dados completo no sistema TrustGraph. Quando instanciado, ele cria uma rede interconectada de processadores que lidam com a ingestão, o processamento, o armazenamento e a consulta de dados como um sistema unificado. + +## Estrutura + +Uma definição de modelo de fluxo consiste em cinco seções principais: + +### 1. Seção de Classe +Define processadores de serviço compartilhados que são instanciados uma vez por modelo de fluxo. Esses processadores lidam com solicitações de todas as instâncias de fluxo desta classe. + +```json +"class": { + "service-name:{class}": { + "request": "queue-pattern:{class}", + "response": "queue-pattern:{class}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Características:** +Compartilhadas entre todas as instâncias de fluxo da mesma classe. +Normalmente, serviços caros ou sem estado (LLMs, modelos de embedding). +Use a variável de modelo `{class}` para o nome da fila. +As configurações podem ser valores fixos ou parametrizadas com a sintaxe `{parameter-name}`. +Exemplos: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}`. + +### 2. Seção de Fluxo +Define processadores específicos do fluxo que são instanciados para cada instância de fluxo individual. Cada fluxo recebe seu próprio conjunto isolado desses processadores. + +```json +"flow": { + "processor-name:{id}": { + "input": "queue-pattern:{id}", + "output": "queue-pattern:{id}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Características:** +Instância única por fluxo +Gerenciar dados e estado específicos do fluxo +Usar variável de modelo `{id}` para nomeação de filas +As configurações podem ser valores fixos ou parametrizados com a sintaxe `{parameter-name}` +Exemplos: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}` + +### 3. Seção de Interfaces +Define os pontos de entrada e os contratos de interação para o fluxo. Estes formam a superfície da API para sistemas externos e comunicação entre componentes internos. + +As interfaces podem assumir duas formas: + +**Padrão Fire-and-Forget** (uma única fila): +```json +"interfaces": { + "document-load": "persistent://tg/flow/document-load:{id}", + "triples-store": "persistent://tg/flow/triples-store:{id}" +} +``` + +**Padrão de Requisição/Resposta** (objeto com campos de requisição/resposta): +```json +"interfaces": { + "embeddings": { + "request": "non-persistent://tg/request/embeddings:{class}", + "response": "non-persistent://tg/response/embeddings:{class}" + } +} +``` + +**Tipos de Interfaces:** +**Pontos de Entrada**: Onde sistemas externos injetam dados (`document-load`, `agent`) +**Interfaces de Serviço**: Padrões de solicitação/resposta para serviços (`embeddings`, `text-completion`) +**Interfaces de Dados**: Pontos de conexão de fluxo de dados do tipo "enviar e esquecer" (`triples-store`, `entity-contexts-load`) + +### 4. Seção de Parâmetros +Mapeia nomes de parâmetros específicos do fluxo para definições de parâmetros armazenadas centralmente: + +```json +"parameters": { + "model": "llm-model", + "temp": "temperature", + "chunk": "chunk-size" +} +``` + +**Características:** +As chaves são nomes de parâmetros usados nas configurações do processador (por exemplo, `{model}`) +Os valores referenciam as definições de parâmetros armazenadas em schema/config +Permite a reutilização de definições de parâmetros comuns em diferentes fluxos +Reduz a duplicação de esquemas de parâmetros + +### 5. Metadados +Informações adicionais sobre o blueprint do fluxo: + +```json +"description": "Human-readable description", +"tags": ["capability-1", "capability-2"] +``` + +## Variáveis de Modelo + +### Variáveis do Sistema + +#### {id} +Substituído pelo identificador de instância de fluxo único. +Cria recursos isolados para cada fluxo. +Exemplo: `flow-123`, `customer-A-flow` + +#### {class} +Substituído pelo nome do blueprint do fluxo. +Cria recursos compartilhados entre fluxos da mesma classe. +Exemplo: `standard-rag`, `enterprise-rag` + +### Variáveis de Parâmetro + +#### {parameter-name} +Parâmetros personalizados definidos no momento da execução do fluxo. +Os nomes dos parâmetros correspondem às chaves na seção `parameters` do fluxo. +Usados em configurações do processador para personalizar o comportamento. +Exemplos: `{model}`, `{temp}`, `{chunk}` +Substituído pelos valores fornecidos ao iniciar o fluxo. +Validado em relação às definições de parâmetros armazenadas centralmente. + +## Configurações do Processador + +As configurações fornecem valores de configuração aos processadores no momento da instanciação. Elas podem ser: + +### Configurações Fixas +Valores diretos que não mudam: +```json +"settings": { + "model": "gemma3:12b", + "temperature": 0.7, + "max_retries": 3 +} +``` + +### Configurações Parametrizadas +Valores que utilizam parâmetros fornecidos no lançamento do fluxo: +```json +"settings": { + "model": "{model}", + "temperature": "{temp}", + "endpoint": "https://{region}.api.example.com" +} +``` + +Os nomes dos parâmetros nas configurações correspondem às chaves na seção `parameters` do fluxo. + +### Exemplos de Configurações + +**Processador LLM com Parâmetros:** +```json +// In parameters section: +"parameters": { + "model": "llm-model", + "temp": "temperature", + "tokens": "max-tokens", + "key": "openai-api-key" +} + +// In processor definition: +"text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "settings": { + "model": "{model}", + "temperature": "{temp}", + "max_tokens": "{tokens}", + "api_key": "{key}" + } +} +``` + +**Chunker com Configurações Fixas e Parametrizadas:** +```json +// In parameters section: +"parameters": { + "chunk": "chunk-size" +} + +// In processor definition: +"chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "settings": { + "chunk_size": "{chunk}", + "chunk_overlap": 100, + "encoding": "utf-8" + } +} +``` + +## Padrões de Filas (Pulsar) + +Os modelos de fluxo utilizam o Apache Pulsar para mensagens. Os nomes das filas seguem o formato do Pulsar: +``` +://// +``` + +### Componentes: +**persistência**: `persistent` ou `non-persistent` (modo de persistência do Pulsar) +**inquilino**: `tg` para definições de blueprint de fluxo fornecidas pelo TrustGraph +**namespace**: Indica o padrão de mensagens + `flow`: Serviços de envio e esquecimento + `request`: Parte de solicitação de serviços de solicitação/resposta + `response`: Parte de resposta de serviços de solicitação/resposta +**tópico**: O nome específico da fila/tópico com variáveis de modelo + +### Filas Persistentes +Padrão: `persistent://tg/flow/:{id}` +Usado para serviços de envio e esquecimento e fluxo de dados durável +Os dados persistem no armazenamento do Pulsar durante as reinicializações +Exemplo: `persistent://tg/flow/chunk-load:{id}` + +### Filas Não Persistentes +Padrão: `non-persistent://tg/request/:{class}` ou `non-persistent://tg/response/:{class}` +Usado para padrões de mensagens de solicitação/resposta +Efêmeras, não persistidas em disco pelo Pulsar +Menor latência, adequado para comunicação no estilo RPC +Exemplo: `non-persistent://tg/request/embeddings:{class}` + +## Arquitetura do Fluxo de Dados + +O blueprint do fluxo cria um fluxo de dados unificado onde: + +1. **Pipeline de Processamento de Documentos**: Fluxo da ingestão ao processamento e armazenamento +2. **Serviços de Consulta**: Processadores integrados que consultam os mesmos armazenamentos de dados e serviços +3. **Serviços Compartilhados**: Processadores centralizados que todos os fluxos podem utilizar +4. **Escritores de Armazenamento**: Persistem os dados processados em armazenamentos apropriados + +Todos os processadores (tanto `{id}` quanto `{class}`) trabalham juntos como um grafo de fluxo de dados coeso, e não como sistemas separados. + +## Exemplo de Instanciação de Fluxo + +Dado: +ID da Instância do Fluxo: `customer-A-flow` +Blueprint do Fluxo: `standard-rag` +Mapeamentos de parâmetros do fluxo: + `"model": "llm-model"` + `"temp": "temperature"` + `"chunk": "chunk-size"` +Parâmetros fornecidos pelo usuário: + `model`: `gpt-4` + `temp`: `0.5` + `chunk`: `512` + +Expansões de modelo: +`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow` +`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag` +`"model": "{model}"` → `"model": "gpt-4"` +`"temperature": "{temp}"` → `"temperature": "0.5"` +`"chunk_size": "{chunk}"` → `"chunk_size": "512"` + +Isso cria: +Pipeline de processamento de documentos isolado para `customer-A-flow` +Serviço de incorporação compartilhado para todos os fluxos `standard-rag` +Fluxo de dados completo da ingestão de documentos à consulta +Processadores configurados com os valores de parâmetro fornecidos + +## Benefícios + +1. **Eficiência de Recursos**: Serviços caros são compartilhados entre os fluxos +2. **Isolamento de Fluxo**: Cada fluxo tem seu próprio pipeline de processamento de dados +3. **Escalabilidade**: É possível instanciar vários fluxos do mesmo modelo +4. **Modularidade**: Separação clara entre componentes compartilhados e específicos do fluxo +5. **Arquitetura Unificada**: Consulta e processamento fazem parte do mesmo fluxo de dados \ No newline at end of file diff --git a/docs/tech-specs/flow-class-definition.ru.md b/docs/tech-specs/flow-class-definition.ru.md new file mode 100644 index 00000000..815cf556 --- /dev/null +++ b/docs/tech-specs/flow-class-definition.ru.md @@ -0,0 +1,277 @@ +# Спецификация определения шаблона потока + +## Обзор + +Шаблон потока определяет полный шаблон структуры потока данных в системе TrustGraph. При инстанцировании он создает взаимосвязанную сеть процессоров, которые обрабатывают прием данных, обработку, хранение и запросы как единую систему. + +## Структура + +Определение шаблона потока состоит из пяти основных разделов: + +### 1. Раздел классов +Определяет общие сервисные процессоры, которые инстанцируются один раз для каждого шаблона потока. Эти процессоры обрабатывают запросы от всех экземпляров потока этого класса. + +```json +"class": { + "service-name:{class}": { + "request": "queue-pattern:{class}", + "response": "queue-pattern:{class}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Характеристики:** +Общие для всех экземпляров потока одного класса. +Обычно это дорогие или безсостояниевые сервисы (LLM, модели эмбеддингов). +Используйте переменную шаблона `{class}` для именования очереди. +Настройки могут быть фиксированными значениями или параметризованы с использованием синтаксиса `{parameter-name}`. +Примеры: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}`. + +### 2. Раздел потока +Определяет процессоры, специфичные для потока, которые создаются для каждого отдельного экземпляра потока. Каждый поток получает свой собственный изолированный набор этих процессоров. + +```json +"flow": { + "processor-name:{id}": { + "input": "queue-pattern:{id}", + "output": "queue-pattern:{id}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Характеристики:** +Уникальный экземпляр для каждого потока. +Обработка данных и состояния, специфичных для потока. +Использование переменной шаблона `{id}` для именования очереди. +Настройки могут быть фиксированными значениями или параметризованы с использованием синтаксиса `{parameter-name}`. +Примеры: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}`. + +### Раздел "Интерфейсы" +Определяет точки входа и контракты взаимодействия для потока. Они формируют API для внешних систем и взаимодействия между внутренними компонентами. + +Интерфейсы могут иметь две формы: + +**Модель "Отправь и забудь"** (одна очередь): +```json +"interfaces": { + "document-load": "persistent://tg/flow/document-load:{id}", + "triples-store": "persistent://tg/flow/triples-store:{id}" +} +``` + +**Шаблон "Запрос/Ответ"** (объект с полями запроса/ответа): +```json +"interfaces": { + "embeddings": { + "request": "non-persistent://tg/request/embeddings:{class}", + "response": "non-persistent://tg/response/embeddings:{class}" + } +} +``` + +**Типы интерфейсов:** +**Точки входа:** Места, куда внешние системы вводят данные (`document-load`, `agent`) +**Интерфейсы сервисов:** Схемы запросов/ответов для сервисов (`embeddings`, `text-completion`) +**Интерфейсы данных:** Точки подключения для потоковой передачи данных (`triples-store`, `entity-contexts-load`) + +### 4. Раздел параметров +Отображает имена параметров, специфичные для потока, на централизованно хранящиеся определения параметров: + +```json +"parameters": { + "model": "llm-model", + "temp": "temperature", + "chunk": "chunk-size" +} +``` + +**Характеристики:** +Ключи являются именами параметров, используемыми в настройках процессора (например, `{model}`) +Значения ссылаются на определения параметров, хранящиеся в schema/config +Обеспечивает повторное использование общих определений параметров в различных потоках. +Уменьшает дублирование схем параметров. + +### 5. Метаданные +Дополнительная информация о шаблоне потока: + +```json +"description": "Human-readable description", +"tags": ["capability-1", "capability-2"] +``` + +## Переменные шаблона + +### Системные переменные + +#### {id} +Заменяется уникальным идентификатором экземпляра потока. +Создает изолированные ресурсы для каждого потока. +Пример: `flow-123`, `customer-A-flow` + +#### {class} +Заменяется именем шаблона потока. +Создает общие ресурсы для потоков одного и того же класса. +Пример: `standard-rag`, `enterprise-rag` + +### Переменные параметров + +#### {parameter-name} +Пользовательские параметры, определенные во время запуска потока. +Имена параметров соответствуют ключам в разделе `parameters` потока. +Используются в настройках процессоров для настройки поведения. +Примеры: `{model}`, `{temp}`, `{chunk}` +Заменяются значениями, предоставленными при запуске потока. +Проверяются на соответствие централизованным определениям параметров. + +## Настройки процессоров + +Настройки предоставляют значения конфигурации процессорам во время их создания. Они могут быть: + +### Фиксированные настройки +Прямые значения, которые не изменяются: +```json +"settings": { + "model": "gemma3:12b", + "temperature": 0.7, + "max_retries": 3 +} +``` + +### Параметрические настройки +Значения, использующие параметры, предоставленные при запуске потока: +```json +"settings": { + "model": "{model}", + "temperature": "{temp}", + "endpoint": "https://{region}.api.example.com" +} +``` + +Имена параметров в настройках соответствуют ключам в разделе `parameters` потока. + +### Примеры настроек + +**Обработчик LLM с параметрами:** +```json +// In parameters section: +"parameters": { + "model": "llm-model", + "temp": "temperature", + "tokens": "max-tokens", + "key": "openai-api-key" +} + +// In processor definition: +"text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "settings": { + "model": "{model}", + "temperature": "{temp}", + "max_tokens": "{tokens}", + "api_key": "{key}" + } +} +``` + +**Разбиение на части с фиксированными и параметризованными настройками:** +```json +// In parameters section: +"parameters": { + "chunk": "chunk-size" +} + +// In processor definition: +"chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "settings": { + "chunk_size": "{chunk}", + "chunk_overlap": 100, + "encoding": "utf-8" + } +} +``` + +## Паттерны очередей (Pulsar) + +Схемы потоков используют Apache Pulsar для обмена сообщениями. Имена очередей соответствуют формату Pulsar: +``` +://// +``` + +### Компоненты: +**постоянство**: `persistent` или `non-persistent` (режим постоянства Pulsar) +**арендатор**: `tg` для определений шаблонов потоков, предоставляемых TrustGraph +**пространство имен**: Указывает шаблон обмена сообщениями + `flow`: Сервисы "отправь и забудь" + `request`: Запрос в сервисах "запрос/ответ" + `response`: Ответ в сервисах "запрос/ответ" +**тема**: Конкретное имя очереди/темы с переменными шаблона + +### Постоянные очереди +Шаблон: `persistent://tg/flow/:{id}` +Используется для сервисов "отправь и забудь" и потоков данных с гарантированной доставкой +Данные сохраняются в хранилище Pulsar после перезагрузок +Пример: `persistent://tg/flow/chunk-load:{id}` + +### Непостоянные очереди +Шаблон: `non-persistent://tg/request/:{class}` или `non-persistent://tg/response/:{class}` +Используется для шаблонов обмена сообщениями "запрос/ответ" +Непостоянные, не сохраняются на диск Pulsar +Меньшая задержка, подходит для коммуникации в стиле RPC +Пример: `non-persistent://tg/request/embeddings:{class}` + +## Архитектура потока данных + +Шаблон потока данных создает унифицированный поток, где: + +1. **Конвейер обработки документов**: Поток от получения данных до преобразования и хранения +2. **Сервисы запросов**: Интегрированные процессоры, которые запрашивают одни и те же хранилища данных и сервисы +3. **Общие сервисы**: Централизованные процессоры, которые могут использоваться всеми потоками +4. **Модули записи данных**: Сохраняют обработанные данные в соответствующие хранилища + +Все процессоры (как `{id}`, так и `{class}`) работают вместе как единый граф потока данных, а не как отдельные системы. + +## Пример инстанцирования потока + +Дано: +Идентификатор экземпляра потока: `customer-A-flow` +Шаблон потока: `standard-rag` +Отображения параметров потока: + `"model": "llm-model"` + `"temp": "temperature"` + `"chunk": "chunk-size"` +Параметры, предоставленные пользователем: + `model`: `gpt-4` + `temp`: `0.5` + `chunk`: `512` + +Расширение шаблонов: +`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow` +`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag` +`"model": "{model}"` → `"model": "gpt-4"` +`"temperature": "{temp}"` → `"temperature": "0.5"` +`"chunk_size": "{chunk}"` → `"chunk_size": "512"` + +Это создает: +Изолированный конвейер обработки документов для `customer-A-flow` +Общий сервис внедрения для всех потоков `standard-rag` +Полный поток данных от получения документов до запросов +Процессоры, настроенные с предоставленными значениями параметров + +## Преимущества + +1. **Эффективность использования ресурсов**: Дорогие сервисы используются совместно несколькими потоками +2. **Изоляция потоков**: Каждый поток имеет свой собственный конвейер обработки данных +3. **Масштабируемость**: Можно создавать несколько экземпляров потоков из одного шаблона +4. **Модульность**: Четкое разделение между общими и специфичными для потока компонентами +5. **Унифицированная архитектура**: Запросы и обработка являются частью одного потока данных \ No newline at end of file diff --git a/docs/tech-specs/flow-class-definition.sw.md b/docs/tech-specs/flow-class-definition.sw.md new file mode 100644 index 00000000..66d63ab2 --- /dev/null +++ b/docs/tech-specs/flow-class-definition.sw.md @@ -0,0 +1,277 @@ +# Maelezo ya Ufafanuzi wa Mfumo wa Mtiririko + +## Muhtasari + +Mfumo wa mtiririko unafafanua kiolezo kamili cha mtiririko wa data katika mfumo wa TrustGraph. Unapoongezwa, huunda mtandao unaounganishwa wa vichakata ambavyo hushughulikia uingizaji wa data, uchakataji, uhifadhi, na kuulizia kama mfumo mmoja. + +## Muundo + +Ufafanuzi wa mfumo wa mtiririko una sehemu tano kuu: + +### 1. Sehemu ya Darasa +Inafafanua vichakata vya huduma ambavyo huanzishwa mara moja kwa kila mfumo wa mtiririko. Vichakata hivi hushughulikia ombi kutoka kwa visasisho vyote vya mfumo wa mtiririko vya darasa hili. + +```json +"class": { + "service-name:{class}": { + "request": "queue-pattern:{class}", + "response": "queue-pattern:{class}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Sifa:** +Zinashirikiwa katika visasisho vyote vya aina moja. +Hutoa huduma za kawaida au zisizo na hali (LLMs, modeli za uingizaji). +Tumia jina la kigezo cha `{class}` kwa ajili ya kujina kwa folyo. +Mipangilio inaweza kuwa maadili thabiti au kupangwa kwa kutumia sintaksia ya `{parameter-name}`. +Mifano: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}` + +### 2. Sehemu ya Folyo +Inafafanua vichakataji maalum ya folyo ambavyo huanzishwa kwa kila visa maalum la folyo. Kila folyo hupata seti yake mwenyewe ya vichakataji hivi. + +```json +"flow": { + "processor-name:{id}": { + "input": "queue-pattern:{id}", + "output": "queue-pattern:{id}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Sifa:** +Mfano pekee kwa kila mtiririko. +Hushughulikia data na hali maalum ya mtiririko. +Tumia kigezo cha `{id}` kwa ajili ya kujina kwa folyo. +Mipangilio inaweza kuwa maadili thabiti au kupangishwa kwa kutumia sintaksia ya `{parameter-name}`. +Mifano: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}`. + +### 3. Sehemu ya Vifaa +Inaelezea pointi za kuingilia na mikataba ya mwingiliano kwa mtiririko. Haya huunda safu ya API kwa mifumo ya nje na mawasiliano ya vipengele vya ndani. + +Vifaa vinaweza kuwa na aina mbili: + +**Mfumo wa "Tuma na Usahau"** (folyo moja): +```json +"interfaces": { + "document-load": "persistent://tg/flow/document-load:{id}", + "triples-store": "persistent://tg/flow/triples-store:{id}" +} +``` + +**Muundo wa Ombi/Jibu** (kitu chenye sehemu za ombi/jibu): +```json +"interfaces": { + "embeddings": { + "request": "non-persistent://tg/request/embeddings:{class}", + "response": "non-persistent://tg/response/embeddings:{class}" + } +} +``` + +**Aina za Mfumo:** +**Vituo vya Kuingia**: Maeneo ambapo mifumo ya nje huingiza data (`document-load`, `agent`) +**Mifumo ya Huduma**: Mfumo wa ombi/jibu kwa huduma (`embeddings`, `text-completion`) +**Mifumo ya Data**: Vituo vya muunganisho wa mtiririko wa data (`triples-store`, `entity-contexts-load`) + +### 4. Sehemu ya Vigezo +Huunganisha majina ya vigezo maalum ya mtiririko na ufafanuzi wa vigezo unaohifadhiwa katika eneo moja: + +```json +"parameters": { + "model": "llm-model", + "temp": "temperature", + "chunk": "chunk-size" +} +``` + +**Sifa:** +Nenosiri ni majina ya vigezo yanayotumika katika mipangilio ya kichakata (k.m., `{model}`) +Maelezo yanaashiria ufafanuzi wa vigezo uliohifadhiwa katika schema/config +Inaruhusu matumizi ya mara kwa mara ya ufafanuzi wa kawaida wa vigezo katika michakato. +Hupunguza marudio ya schemas za vigezo. + +### 5. Meta Data +Taarifa za ziada kuhusu mpango wa mtiririko: + +```json +"description": "Human-readable description", +"tags": ["capability-1", "capability-2"] +``` + +## Vigezo vya Kiolele + +### Vigezo vya Mfumo + +#### {id} +Huibwa na kitambulisho kipekee cha kila mfumo. +Huunda rasilimali zilizotengwa kwa kila mfumo. +Mifano: `flow-123`, `customer-A-flow` + +#### {class} +Huibwa na jina la mpango wa mfumo. +Huunda rasilimali zilizoshirikiwa katika mifumo ya aina moja. +Mifano: `standard-rag`, `enterprise-rag` + +### Vigezo vya Parameta + +#### {parameter-name} +Parameta maalum zilizobainishwa wakati wa kuanzisha mfumo. +Majina ya parameta yanalingana na funguo katika sehemu ya `parameters` ya mfumo. +Hutumiwa katika mipangilio ya kichakuzi ili kuboresha tabia. +Mifano: `{model}`, `{temp}`, `{chunk}` +Huibwa na maadili yaliyotolewa wakati wa kuanzisha mfumo. +Yanathibitishwa kulingana na ufafanuzi wa parameta uliohifadhiwa katika mfumo. + +## Mpangilio wa Kichakuzi + +Mpangilio hutoa maadili ya usanidi kwa vichakuzi wakati wa uundaji. Inaweza kuwa: + +### Mpangilio Thabiti +Maadili ya moja kwa moja ambayo hayubadiliki: +```json +"settings": { + "model": "gemma3:12b", + "temperature": 0.7, + "max_retries": 3 +} +``` + +### Mipangilio Iliyobadilishwa +Maelezo ambayo hutumia vigezo vilivyotolewa wakati wa kuanzisha mtiririko: +```json +"settings": { + "model": "{model}", + "temperature": "{temp}", + "endpoint": "https://{region}.api.example.com" +} +``` + +Majina ya vigezo katika mipangilio yanalingana na funguo katika sehemu ya `parameters` ya mtiririko. + +### Mifano ya Mipangilio + +**Mchakato wa LLM na Vigezo:** +```json +// In parameters section: +"parameters": { + "model": "llm-model", + "temp": "temperature", + "tokens": "max-tokens", + "key": "openai-api-key" +} + +// In processor definition: +"text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "settings": { + "model": "{model}", + "temperature": "{temp}", + "max_tokens": "{tokens}", + "api_key": "{key}" + } +} +``` + +**Kifurushi cha Mpangilio wa Kurekebisha na Unaoweza Kubadilishwa:** +```json +// In parameters section: +"parameters": { + "chunk": "chunk-size" +} + +// In processor definition: +"chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "settings": { + "chunk_size": "{chunk}", + "chunk_overlap": 100, + "encoding": "utf-8" + } +} +``` + +## Mifumo ya Kinyororo (Pulsar) + +Mfumo wa mtiririko hutumia Apache Pulsar kwa ujumbe. Majina ya nyororo yanafuata muundo wa Pulsar: +``` +://// +``` + +### Vipengele: +**uthibitisho**: `persistent` au `non-persistent` (Njia ya uthibitisho ya Pulsar) +**mwendeshaji**: `tg` kwa maelezo ya muundo wa mtiririko yanayotolewa na TrustGraph +**nafasi**: Inaonyesha muundo wa ujumbe + `flow`: Huduma za "tumia na usahau" + `request`: Sehemu ya ombi ya huduma za ombi/jibu + `response`: Sehemu ya jibu ya huduma za ombi/jibu +**mada**: Jina maalum la folyo/mada na vigezo vya kiolezo + +### Folyozilizohifadhiwa +Muundo: `persistent://tg/flow/:{id}` +Inatumika kwa huduma za "tumia na usahau" na mtiririko wa data endelevu +Data inabaki katika hifadhi ya Pulsar wakati wa kuanzishwa upya +Mfano: `persistent://tg/flow/chunk-load:{id}` + +### Folyozilizohifadhiwa +Muundo: `non-persistent://tg/request/:{class}` au `non-persistent://tg/response/:{class}` +Inatumika kwa muundo wa ujumbe wa ombi/jibu +Inapotea, haihifadhiwa kwenye diski na Pulsar +Latensi ndogo, inafaa kwa mawasiliano ya aina ya RPC +Mfano: `non-persistent://tg/request/embeddings:{class}` + +## Usanifu wa Mtiririko wa Data + +Muundo wa mtiririko huunda mtiririko wa data unaounganishwa ambapo: + +1. **Mchakato wa Kusindika Nyaraka**: Mtiririko kutoka kwa kupokea hadi kubadilisha hadi kuhifadhi +2. **Huduma za Uchunguzi**: Wasindikaji waliojumuishwa ambao huchunguza hifadhi na huduma sawa za data +3. **Huduma Zilizoshirikiwa**: Wasindikaji wa kati ambao mtiririko wote unaweza kutumia +4. **Waandikaji wa Hifadhi**: Kuhifadhi data iliyosindikwa kwenye hifadhi husika + +Wasindikaji wote (wote `{id}` na `{class}`) hufanya kazi pamoja kama grafu moja ya mtiririko wa data, sio mifumo tofauti. + +## Uanzishaji wa Mfano wa Mtiririko + +Imepewa: +Kitambulisho cha Mfano wa Mtiririko: `customer-A-flow` +Muundo wa Mtiririko: `standard-rag` +Ramani za vigezo vya mtiririko: + `"model": "llm-model"` + `"temp": "temperature"` + `"chunk": "chunk-size"` +Vigezo vilivyotolewa na mtumiaji: + `model`: `gpt-4` + `temp`: `0.5` + `chunk`: `512` + +Upanuzi wa kiolezo: +`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow` +`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag` +`"model": "{model}"` → `"model": "gpt-4"` +`"temperature": "{temp}"` → `"temperature": "0.5"` +`"chunk_size": "{chunk}"` → `"chunk_size": "512"` + +Hii huunda: +Mchakato wa kusindika nyaraka uliotengwa kwa `customer-A-flow` +Huduma ya pamoja ya uingizaji kwa mtiririko wote wa `standard-rag` +Mtiririko kamili kutoka kwa kupokea nyaraka hadi uchunguzi +Wasindikaji walioelekezwa na maadili ya vigezo vilivyotolewa + +## Faida + +1. **Ufanisi wa Rasilimali**: Huduma ghali hushirikiwa katika mitiririko +2. **Kutengwa kwa Mtiririko**: Kila mtiririko una mchakato wake wa kusindika data +3. **Uwezo wa Kupanuka**: Inaweza kuanzisha mitiririko mingi kutoka kwa kiolezo kimoja +4. **Uunganishaji**: Tofauti wazi kati ya vipengele vilivyoshirikiwa na vilivyohusiana na mtiririko +5. **Usanifu Uliounganishwa**: Uchunguzi na usindikaji ni sehemu ya mtiririko mmoja wa data \ No newline at end of file diff --git a/docs/tech-specs/flow-class-definition.tr.md b/docs/tech-specs/flow-class-definition.tr.md new file mode 100644 index 00000000..c13222ae --- /dev/null +++ b/docs/tech-specs/flow-class-definition.tr.md @@ -0,0 +1,277 @@ +# Akış Şeması Tanım Özellikleri + +## Genel Bakış + +Bir akış şeması, TrustGraph sisteminde eksiksiz bir veri akışı kalıbı şablonunu tanımlar. Örneklenildiğinde, verilerin alınması, işlenmesi, depolanması ve sorgulanması işlemlerini tek bir sistem olarak ele alan, birbirine bağlı bir işlemci ağı oluşturur. + +## Yapı + +Bir akış şeması tanımı, beş ana bölümden oluşur: + +### 1. Sınıf Bölümü +Her akış şeması için yalnızca bir kez örneklendirilen, paylaşılan hizmet işlemcilerini tanımlar. Bu işlemciler, bu sınıfın tüm akış örneklerinden gelen istekleri işler. + +```json +"class": { + "service-name:{class}": { + "request": "queue-pattern:{class}", + "response": "queue-pattern:{class}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Özellikler:** +Aynı sınıftaki tüm akış örnekleri arasında paylaşılır. +Genellikle maliyetli veya durumsuz hizmetlerdir (LLM'ler, gömme modelleri). +Kuyruk adlandırması için `{class}` şablon değişkenini kullanın. +Ayarlar, sabit değerler olabilir veya `{parameter-name}` sözdizimi ile parametrelendirilebilir. +Örnekler: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}` + +### 2. Akış Bölümü +Her bir bireysel akış örneği için örneklenen, akışa özgü işlemcileri tanımlar. Her akışın kendi izole edilmiş işlemci kümesi vardır. + +```json +"flow": { + "processor-name:{id}": { + "input": "queue-pattern:{id}", + "output": "queue-pattern:{id}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**Özellikler:** +Her akış için benzersiz bir örnek +Akışa özgü verileri ve durumu yönetir +Kuyruğu adlandırmak için `{id}` şablon değişkenini kullanın +Ayarlar, sabit değerler olabilir veya `{parameter-name}` sözdizimi ile parametrelendirilebilir +Örnekler: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}` + +### 3. Arayüzler Bölümü +Akış için giriş noktalarını ve etkileşim sözleşmelerini tanımlar. Bunlar, harici sistemler ve dahili bileşen iletişimi için API yüzeyini oluşturur. + +Arayüzler iki formda olabilir: + +**Ateşle ve Unut (Fire-and-Forget) Modeli** (tek kuyruk): +```json +"interfaces": { + "document-load": "persistent://tg/flow/document-load:{id}", + "triples-store": "persistent://tg/flow/triples-store:{id}" +} +``` + +**İstek/Yanıt Modeli** (istek/yanıt alanlarına sahip nesne): +```json +"interfaces": { + "embeddings": { + "request": "non-persistent://tg/request/embeddings:{class}", + "response": "non-persistent://tg/response/embeddings:{class}" + } +} +``` + +**Arayüz Türleri:** +**Giriş Noktaları:** Dış sistemlerin veri enjekte ettiği yerler (`document-load`, `agent`) +**Servis Arayüzleri:** Servisler için istek/yanıt kalıpları (`embeddings`, `text-completion`) +**Veri Arayüzleri:** Ateşle-ve-unut veri akışı bağlantı noktaları (`triples-store`, `entity-contexts-load`) + +### 4. Parametreler Bölümü +Akışa özgü parametre adlarını, merkezi olarak saklanan parametre tanımlarına eşler: + +```json +"parameters": { + "model": "llm-model", + "temp": "temperature", + "chunk": "chunk-size" +} +``` + +**Özellikler:** +Anahtarlar, işlemci ayarlarında kullanılan parametre adlarıdır (örneğin, `{model}`). +Değerler, şema/yapılandırmada saklanan parametre tanımlarına referans verir. +Akışlar arasında ortak parametre tanımlarının yeniden kullanılmasını sağlar. +Parametre şemalarının çoğaltılmasını azaltır. + +### 5. Meta Veriler +Akış şeması hakkında ek bilgiler: + +```json +"description": "Human-readable description", +"tags": ["capability-1", "capability-2"] +``` + +## Şablon Değişkenleri + +### Sistem Değişkenleri + +#### {id} +Her akış örneği için benzersiz tanımlayıcı ile değiştirilir. +Her akış için izole kaynaklar oluşturur. +Örnek: `flow-123`, `customer-A-flow` + +#### {class} +Akış şablonu adıyla değiştirilir. +Aynı sınıftaki akışlar arasında paylaşılan kaynaklar oluşturur. +Örnek: `standard-rag`, `enterprise-rag` + +### Parametre Değişkenleri + +#### {parametre-adı} +Akış başlatma zamanında tanımlanan özel parametrelerdir. +Parametre adları, akışın `parameters` bölümündeki anahtarlarla eşleşir. +İşlemci ayarlarında davranışı özelleştirmek için kullanılır. +Örnekler: `{model}`, `{temp}`, `{chunk}` +Akışı başlattığınızda sağlanan değerlerle değiştirilir. +Merkezi olarak saklanan parametre tanımlarına göre doğrulanır. + +## İşlemci Ayarları + +Ayarlar, işlemcilerin başlatma zamanındaki yapılandırma değerlerini sağlar. Bunlar şunlar olabilir: + +### Sabit Ayarlar +Değişmeyen doğrudan değerler: +```json +"settings": { + "model": "gemma3:12b", + "temperature": 0.7, + "max_retries": 3 +} +``` + +### Parametreleştirilmiş Ayarlar +Akış başlatılırken sağlanan parametreleri kullanan değerler: +```json +"settings": { + "model": "{model}", + "temperature": "{temp}", + "endpoint": "https://{region}.api.example.com" +} +``` + +Ayarlardaki parametre adları, akışın `parameters` bölümündeki anahtarlara karşılık gelir. + +### Ayar Örnekleri + +**Parametrelerle LLM İşlemcisi:** +```json +// In parameters section: +"parameters": { + "model": "llm-model", + "temp": "temperature", + "tokens": "max-tokens", + "key": "openai-api-key" +} + +// In processor definition: +"text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "settings": { + "model": "{model}", + "temperature": "{temp}", + "max_tokens": "{tokens}", + "api_key": "{key}" + } +} +``` + +**Sabit ve Parametreize Ayarlara Sahip Parçalayıcı:** +```json +// In parameters section: +"parameters": { + "chunk": "chunk-size" +} + +// In processor definition: +"chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "settings": { + "chunk_size": "{chunk}", + "chunk_overlap": 100, + "encoding": "utf-8" + } +} +``` + +## Kuyruk Desenleri (Pulsar) + +Akış şemaları, mesajlaşma için Apache Pulsar'ı kullanır. Kuyruk adları, Pulsar formatını izler: +``` +://// +``` + +### Bileşenler: +**kalıcılık**: `persistent` veya `non-persistent` (Pulsar kalıcılık modu) +**kiracı**: TrustGraph tarafından sağlanan akış tanım şablonları için `tg` +**isim alanı**: Mesajlaşma desenini belirtir + `flow`: Ateşle ve unut hizmetleri + `request`: İstek/yanıt hizmetlerinin istek kısmı + `response`: İstek/yanıt hizmetlerinin yanıt kısmı +**konu**: Şablon değişkenleriyle belirli kuyruk/konu adı + +### Kalıcı Kuyruklar +Desen: `persistent://tg/flow/:{id}` +Ateşle ve unut hizmetleri ve dayanıklı veri akışı için kullanılır +Veri, yeniden başlatmalarda Pulsar depolama alanında kalıcıdır +Örnek: `persistent://tg/flow/chunk-load:{id}` + +### Kalıcı Olmayan Kuyruklar +Desen: `non-persistent://tg/request/:{class}` veya `non-persistent://tg/response/:{class}` +İstek/yanıt mesajlaşma desenleri için kullanılır +Pulsar tarafından diske kalıcı hale getirilmez, geçicidir +Daha düşük gecikme süresi, RPC tarzı iletişim için uygundur +Örnek: `non-persistent://tg/request/embeddings:{class}` + +## Veri Akışı Mimarisi + +Akış tanımı, aşağıdaki gibi birleşik bir veri akışı oluşturur: + +1. **Belge İşleme Hattı**: Alımdan dönüşüme ve depolamaya kadar olan akış +2. **Sorgu Hizmetleri**: Aynı veri depolarını ve hizmetlerini sorgulayan entegre işlemciler +3. **Paylaşımlı Hizmetler**: Tüm akışların kullanabileceği merkezi işlemciler +4. **Depolama Yazıcıları**: İşlenmiş verileri uygun depolama alanlarına kaydeder + +Tüm işlemciler (hem `{id}` hem de `{class}`), ayrı sistemler olarak değil, uyumlu bir veri akışı grafiği olarak birlikte çalışır. + +## Örnek Akış Oluşturma + +Verilenler: +Akış Örneği Kimliği: `customer-A-flow` +Akış Tanımı: `standard-rag` +Akış parametre eşlemeleri: + `"model": "llm-model"` + `"temp": "temperature"` + `"chunk": "chunk-size"` +Kullanıcı tarafından sağlanan parametreler: + `model`: `gpt-4` + `temp`: `0.5` + `chunk`: `512` + +Şablon genişletmeleri: +`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow` +`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag` +`"model": "{model}"` → `"model": "gpt-4"` +`"temperature": "{temp}"` → `"temperature": "0.5"` +`"chunk_size": "{chunk}"` → `"chunk_size": "512"` + +Bu, aşağıdaki öğeleri oluşturur: +`customer-A-flow` için izole edilmiş belge işleme hattı +Tüm `standard-rag` akışları için paylaşımlı gömme hizmeti +Belge alımından sorgulamaya kadar olan eksiksiz veri akışı +İşlemciler, sağlanan parametre değerleriyle yapılandırılmıştır + +## Avantajlar + +1. **Kaynak Verimliliği**: Pahalı hizmetler, akışlar arasında paylaşılır +2. **Akış İzolasyonu**: Her akışın kendi veri işleme hattı vardır +3. **Ölçeklenebilirlik**: Aynı şablondan birden fazla akış oluşturulabilir +4. **Modülerlik**: Paylaşılan ve akışa özgü bileşenler arasında net bir ayrım +5. **Bütünleşik Mimari**: Sorgu ve işleme, aynı veri akışının bir parçasıdır \ No newline at end of file diff --git a/docs/tech-specs/flow-class-definition.zh-cn.md b/docs/tech-specs/flow-class-definition.zh-cn.md new file mode 100644 index 00000000..dea29c18 --- /dev/null +++ b/docs/tech-specs/flow-class-definition.zh-cn.md @@ -0,0 +1,277 @@ +# 流程蓝图定义规范 + +## 概述 + +流程蓝图在 TrustGraph 系统中定义了一个完整的数据流模式模板。当实例化时,它会创建一个相互连接的处理单元网络,该网络处理数据摄取、处理、存储和查询,作为一个统一的系统。 + +## 结构 + +流程蓝图定义由五个主要部分组成: + +### 1. 类部分 +定义共享服务处理器,这些处理器每个流程蓝图实例化一次。这些处理器处理来自此类的所有流程实例的请求。 + +```json +"class": { + "service-name:{class}": { + "request": "queue-pattern:{class}", + "response": "queue-pattern:{class}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**特性:** +在同一类别的所有流程实例中共享。 +通常是昂贵或无状态的服务(例如:大型语言模型、嵌入模型)。 +使用 `{class}` 模板变量进行队列命名。 +设置可以是固定值,也可以使用 `{parameter-name}` 语法进行参数化。 +示例:`embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}` + +### 2. 流程部分 +定义与流程相关的处理器,这些处理器为每个独立的流程实例进行实例化。 每个流程都拥有自己的一组隔离的处理器。 + +```json +"flow": { + "processor-name:{id}": { + "input": "queue-pattern:{id}", + "output": "queue-pattern:{id}", + "settings": { + "setting-name": "fixed-value", + "parameterized-setting": "{parameter-name}" + } + } +} +``` + +**特性:** +每个流程只有一个实例。 +处理流程特定的数据和状态。 +使用 `{id}` 模板变量进行队列命名。 +设置可以是固定值,也可以使用 `{parameter-name}` 语法进行参数化。 +示例:`chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}` + +### 3. 接口部分 +定义流程的入口点和交互协议。 这些构成了外部系统和内部组件通信的 API 表面。 + +接口可以有两种形式: + +**即发即弃模式**(单个队列): +```json +"interfaces": { + "document-load": "persistent://tg/flow/document-load:{id}", + "triples-store": "persistent://tg/flow/triples-store:{id}" +} +``` + +**请求/响应模式** (包含请求/响应字段的对象): +```json +"interfaces": { + "embeddings": { + "request": "non-persistent://tg/request/embeddings:{class}", + "response": "non-persistent://tg/response/embeddings:{class}" + } +} +``` + +**接口类型:** +**入口点:** 外部系统注入数据的入口点 (`document-load`, `agent`) +**服务接口:** 服务请求/响应模式 (`embeddings`, `text-completion`) +**数据接口:** 触发/完成式数据流连接点 (`triples-store`, `entity-contexts-load`) + +### 4. 参数部分 +将流程特定的参数名称映射到集中存储的参数定义: + +```json +"parameters": { + "model": "llm-model", + "temp": "temperature", + "chunk": "chunk-size" +} +``` + +**特性:** +键是处理器设置中使用的参数名称(例如,`{model}`) +值引用存储在 schema/config 中的参数定义 +允许在流程之间重用常见的参数定义 +减少参数模式的重复 + +### 5. 元数据 +关于流程蓝图的附加信息: + +```json +"description": "Human-readable description", +"tags": ["capability-1", "capability-2"] +``` + +## 模板变量 + +### 系统变量 + +#### {id} +被替换为唯一的流程实例标识符 +为每个流程创建隔离的资源 +示例:`flow-123`, `customer-A-flow` + +#### {class} +被替换为流程蓝图名称 +为相同类别的流程创建共享资源 +示例:`standard-rag`, `enterprise-rag` + +### 参数变量 + +#### {parameter-name} +在流程启动时定义的自定义参数 +参数名称与流程的 `parameters` 部分中的键匹配 +用于在处理器设置中自定义行为 +示例:`{model}`, `{temp}`, `{chunk}` +被替换为启动流程时提供的值 +验证通过与集中存储的参数定义进行比较 + +## 处理器设置 + +设置在实例化时向处理器提供配置值。 它们可以是: + +### 静态设置 +直接值,不会改变: +```json +"settings": { + "model": "gemma3:12b", + "temperature": 0.7, + "max_retries": 3 +} +``` + +### 参数化设置 +使用在流程启动时提供的参数的值: +```json +"settings": { + "model": "{model}", + "temperature": "{temp}", + "endpoint": "https://{region}.api.example.com" +} +``` + +参数名称在设置中对应于流程的 `parameters` 部分中的键。 + +### 设置示例 + +**带有参数的 LLM 处理器:** +```json +// In parameters section: +"parameters": { + "model": "llm-model", + "temp": "temperature", + "tokens": "max-tokens", + "key": "openai-api-key" +} + +// In processor definition: +"text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "settings": { + "model": "{model}", + "temperature": "{temp}", + "max_tokens": "{tokens}", + "api_key": "{key}" + } +} +``` + +**具有固定和参数化设置的分块器:** +```json +// In parameters section: +"parameters": { + "chunk": "chunk-size" +} + +// In processor definition: +"chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "settings": { + "chunk_size": "{chunk}", + "chunk_overlap": 100, + "encoding": "utf-8" + } +} +``` + +## 队列模式 (Pulsar) + +流程蓝图使用 Apache Pulsar 进行消息传递。队列名称遵循 Pulsar 格式: +``` +://// +``` + +### 组件: +**持久性**: `persistent` 或 `non-persistent` (Pulsar 持久性模式) +**租户**: `tg` 用于 TrustGraph 提供的流程蓝图定义 +**命名空间**: 表示消息模式 + `flow`: 适用于“发送即忘”服务 + `request`: 适用于请求/响应服务的请求部分 + `response`: 适用于请求/响应服务的响应部分 +**主题**: 具有模板变量的特定队列/主题名称 + +### 持久队列 +模式: `persistent://tg/flow/:{id}` +用于“发送即忘”服务和持久数据流 +数据在 Pulsar 存储中持久化,即使在重启后也保留 +示例: `persistent://tg/flow/chunk-load:{id}` + +### 非持久队列 +模式: `non-persistent://tg/request/:{class}` 或 `non-persistent://tg/response/:{class}` +用于请求/响应消息模式 +瞬态的,不由 Pulsar 持久化到磁盘 +延迟较低,适用于 RPC 风格的通信 +示例: `non-persistent://tg/request/embeddings:{class}` + +## 数据流架构 + +流程蓝图创建统一的数据流,其中: + +1. **文档处理管道**: 从摄取到转换再到存储的流程 +2. **查询服务**: 集成的处理器,查询相同的存储和服务 +3. **共享服务**: 所有流程都可以使用的集中式处理器 +4. **存储写入器**: 将处理后的数据持久化到适当的存储中 + +所有处理器(包括 `{id}` 和 `{class}`)协同工作,形成一个连贯的数据流图,而不是作为独立的系统。 + +## 流程实例化示例 + +假设: +流程实例 ID: `customer-A-flow` +流程蓝图: `standard-rag` +流程参数映射: + `"model": "llm-model"` + `"temp": "temperature"` + `"chunk": "chunk-size"` +用户提供的参数: + `model`: `gpt-4` + `temp`: `0.5` + `chunk`: `512` + +模板扩展: +`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow` +`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag` +`"model": "{model}"` → `"model": "gpt-4"` +`"temperature": "{temp}"` → `"temperature": "0.5"` +`"chunk_size": "{chunk}"` → `"chunk_size": "512"` + +这会创建: +用于 `customer-A-flow` 的隔离文档处理管道 +用于所有 `standard-rag` 流程的共享嵌入服务 +从文档摄取到查询的完整数据流 +使用提供的参数值配置的处理器 + +## 优点 + +1. **资源效率**: 昂贵的服务在流程之间共享 +2. **流程隔离**: 每个流程都有自己的数据处理管道 +3. **可扩展性**: 可以从相同的模板实例化多个流程 +4. **模块化**: 共享组件和流程特定组件之间有明确的分离 +5. **统一架构**: 查询和处理是相同的数据流的一部分 \ No newline at end of file diff --git a/docs/tech-specs/flow-configurable-parameters.ar.md b/docs/tech-specs/flow-configurable-parameters.ar.md new file mode 100644 index 00000000..98da3e71 --- /dev/null +++ b/docs/tech-specs/flow-configurable-parameters.ar.md @@ -0,0 +1,485 @@ +# المواصفات الفنية لـ "خطة سير العمل" (Flow Blueprint) للمعلمات القابلة للتكوين + +## نظرة عامة + +تصف هذه المواصفة تنفيذ المعلمات القابلة للتكوين لـ "خطط سير العمل" في TrustGraph. تتيح المعلمات للمستخدمين تخصيص معلمات المعالج في وقت بدء تشغيل سير العمل من خلال توفير قيم تحل محل العناصر النائبة للمعلمات في تعريف "خطة سير العمل". + +تعمل المعلمات من خلال استبدال متغيرات القالب في معلمات المعالج، على غرار كيفية عمل المتغيرات `{id}` و `{class}`، ولكن مع قيم مقدمة من المستخدم. + +يدعم التكامل أربعة حالات استخدام رئيسية: + +1. **اختيار النموذج**: السماح للمستخدمين باختيار نماذج LLM مختلفة (مثل `gemma3:8b`، `gpt-4`، `claude-3`) للمعالجات. +2. **تكوين الموارد**: تعديل معلمات المعالج مثل أحجام الدُفعات، وأحجام الدُفعات، وحدود التزامن. +3. **الضبط الدقيق للسلوك**: تعديل سلوك المعالج من خلال معلمات مثل درجة الحرارة، والحد الأقصى للرموز، أو عتبات الاسترجاع. +4. **معلمات خاصة بالبيئة**: تكوين نقاط النهاية، ومفاتيح API، أو عناوين URL خاصة بالمنطقة لكل عملية نشر. + +## الأهداف + +**تكوين المعالج الديناميكي**: تمكين تكوين معلمات المعالج في وقت التشغيل من خلال استبدال المعلمات. +**التحقق من صحة المعلمات**: توفير التحقق من النوع والتحقق من صحة المعلمات في وقت بدء تشغيل سير العمل. +**القيم الافتراضية**: دعم القيم الافتراضية المعقولة مع السماح بالتجاوزات للمستخدمين المتقدمين. +**استبدال القوالب**: استبدال العناصر النائبة للمعلمات في معلمات المعالج بسلاسة. +**التكامل مع واجهة المستخدم**: تمكين إدخال المعلمات من خلال كل من واجهات برمجة التطبيقات وواجهات المستخدم. +**الأمان من النوع**: التأكد من أن أنواع المعلمات تتطابق مع أنواع معلمات المعالج المتوقعة. +**التوثيق**: مخططات معلمات ذاتية التوثيق داخل تعريفات "خطط سير العمل". +**التوافق مع الإصدارات السابقة**: الحفاظ على التوافق مع "خطط سير العمل" الحالية التي لا تستخدم المعلمات. + +## الخلفية + +تدعم "خطط سير العمل" في TrustGraph الآن معلمات المعالج التي يمكن أن تحتوي إما على قيم ثابتة أو عناصر نائبة للمعلمات. هذا يخلق فرصة للتخصيص في وقت التشغيل. + +تدعم معلمات المعالج الحالية: +القيم الثابتة: `"model": "gemma3:12b"` +العناصر النائبة للمعلمات: `"model": "gemma3:{model-size}"` + +تحدد هذه المواصفة كيفية: +الإعلان عن المعلمات في تعريفات "خطط سير العمل". +التحقق من صحة المعلمات عند بدء تشغيل سير العمل. +استبدال المعلمات في معلمات المعالج. +الكشف عنها من خلال واجهات برمجة التطبيقات وواجهات المستخدم. + +من خلال الاستفادة من معلمات معلمات المعالج، يمكن لـ TrustGraph: +تقليل تكرار "خطط سير العمل" باستخدام المعلمات للتغيرات. +تمكين المستخدمين من ضبط سلوك المعالج دون تعديل التعريفات. +دعم التكوينات الخاصة بالبيئة من خلال قيم المعلمات. +الحفاظ على الأمان من النوع من خلال التحقق من صحة مخططات المعلمات. + +## التصميم الفني + +### البنية + +يتطلب نظام المعلمات القابلة للتكوين المكونات الفنية التالية: + +1. **تعريف مخطط المعلمات** + تعريفات المعلمات المستندة إلى JSON Schema داخل بيانات تعريف "خطة سير العمل". + تعريفات الأنواع بما في ذلك أنواع السلاسل والأرقام والمنطق والقوائم وأنواع الكائنات. + قواعد التحقق من الصحة بما في ذلك القيم الدنيا/القصوى، والأنماط، والحقول المطلوبة. + + الوحدة: trustgraph-flow/trustgraph/flow/definition.py + +2. **محرك حل المعلمات** + التحقق من صحة المعلمات في وقت التشغيل مقابل المخطط. + تطبيق القيم الافتراضية للمعلمات غير المحددة. + حقن المعلمات في سياق تنفيذ سير العمل. + التحويل والتحويل من النوع حسب الحاجة. + + الوحدة: trustgraph-flow/trustgraph/flow/parameter_resolver.py + +3. **تكامل مخزن المعلمات** + استرداد تعريفات المعلمات من نظام المخطط/التكوين. + التخزين المؤقت لتعريفات المعلمات المستخدمة بشكل متكرر. + التحقق من الصحة مقابل المخططات المخزنة مركزيًا. + + الوحدة: trustgraph-flow/trustgraph/flow/parameter_store.py + +4. **امتدادات مشغل سير العمل** + امتدادات واجهة برمجة التطبيقات لقبول قيم المعلمات أثناء بدء تشغيل سير العمل. + دقة تعيين المعلمات (أسماء سير العمل إلى أسماء التعريف). + معالجة الأخطاء لمجموعات المعلمات غير الصالحة. + + الوحدة: trustgraph-flow/trustgraph/flow/launcher.py + +5. **نماذج واجهة المستخدم للمعلمات** + إنشاء نماذج ديناميكية من بيانات تعريف معلمات سير العمل. + عرض المعلمات بترتيب باستخدام `order`. + تسميات وصفية للمعلمات باستخدام `description`. + التحقق من صحة الإدخال مقابل تعريفات أنواع المعلمات. + إعدادات مسبقة وقوالب للمعلمات. + + الوحدة: trustgraph-ui/components/flow-parameters/ + +### نماذج البيانات + +#### تعريفات المعلمات (مخزنة في المخطط/التكوين) + +يتم تخزين تعريفات المعلمات مركزيًا في نظام المخطط والتكوين مع النوع "parameter-type": + +```json +{ + "llm-model": { + "type": "string", + "description": "LLM model to use", + "default": "gpt-4", + "enum": [ + { + "id": "gpt-4", + "description": "OpenAI GPT-4 (Most Capable)" + }, + { + "id": "gpt-3.5-turbo", + "description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)" + }, + { + "id": "claude-3", + "description": "Anthropic Claude 3 (Thoughtful & Safe)" + }, + { + "id": "gemma3:8b", + "description": "Google Gemma 3 8B (Open Source)" + } + ], + "required": false + }, + "model-size": { + "type": "string", + "description": "Model size variant", + "default": "8b", + "enum": ["2b", "8b", "12b", "70b"], + "required": false + }, + "temperature": { + "type": "number", + "description": "Model temperature for generation", + "default": 0.7, + "minimum": 0.0, + "maximum": 2.0, + "required": false + }, + "chunk-size": { + "type": "integer", + "description": "Document chunk size", + "default": 512, + "minimum": 128, + "maximum": 2048, + "required": false + } +} +``` + +#### مخطط سير العمل مع مراجع المعلمات + +تحدد مخططات سير العمل بيانات وصفية للمعلمات مع مراجع للأنواع والأوصاف والترتيب: + +```json +{ + "flow_class": "document-analysis", + "parameters": { + "llm-model": { + "type": "llm-model", + "description": "Primary LLM model for text completion", + "order": 1 + }, + "llm-rag-model": { + "type": "llm-model", + "description": "LLM model for RAG operations", + "order": 2, + "advanced": true, + "controlled-by": "llm-model" + }, + "llm-temperature": { + "type": "temperature", + "description": "Generation temperature for creativity control", + "order": 3, + "advanced": true + }, + "chunk-size": { + "type": "chunk-size", + "description": "Document chunk size for processing", + "order": 4, + "advanced": true + }, + "chunk-overlap": { + "type": "integer", + "description": "Overlap between document chunks", + "order": 5, + "advanced": true, + "controlled-by": "chunk-size" + } + }, + "class": { + "text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "parameters": { + "model": "{llm-model}", + "temperature": "{llm-temperature}" + } + }, + "rag-completion:{class}": { + "request": "non-persistent://tg/request/rag-completion:{class}", + "response": "non-persistent://tg/response/rag-completion:{class}", + "parameters": { + "model": "{llm-rag-model}", + "temperature": "{llm-temperature}" + } + } + }, + "flow": { + "chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "parameters": { + "chunk_size": "{chunk-size}", + "chunk_overlap": "{chunk-overlap}" + } + } + } +} +``` + +القسم `parameters` يربط أسماء المعلمات الخاصة بالتدفق (المفاتيح) بكائنات بيانات تعريف المعلمات التي تحتوي على: +`type`: مرجع إلى تعريف المعلمة المحدد مركزيًا (مثل "llm-model") +`description`: وصف يمكن قراءته بواسطة الإنسان للعرض في واجهة المستخدم +`order`: ترتيب العرض لنماذج المعلمات (تظهر الأرقام الأقل أولاً) +`advanced` (اختياري): علامة منطقية تشير إلى ما إذا كانت هذه معلمة متقدمة (افتراضي: خطأ). عند تعيينها على "صحيح"، قد تخفي واجهة المستخدم هذه المعلمة افتراضيًا أو تضعها في قسم "متقدم" +`controlled-by` (اختياري): اسم معلمة أخرى تتحكم في قيمة هذه المعلمة عند التواجد في الوضع البسيط. عند تحديدها، ترث هذه المعلمة قيمتها من المعلمة المتحكمة ما لم يتم تجاوزها بشكل صريح + +تسمح هذه الطريقة بما يلي: +تعريفات أنواع معلمات قابلة لإعادة الاستخدام عبر قوالب تدفق متعددة +إدارة مركزية لأنواع المعلمات والتحقق من صحتها +أوصاف وترتيب المعلمات الخاصة بالتدفق +تجربة واجهة مستخدم محسنة مع نماذج معلمات وصفية +التحقق من صحة المعلمات بشكل متسق عبر التدفقات +إضافة سهلة لأنواع معلمات قياسية جديدة +واجهة مستخدم مبسطة مع فصل الوضع الأساسي/المتقدم +وراثة قيمة المعلمة للإعدادات ذات الصلة + +#### طلب بدء تشغيل التدفق + +تقبل واجهة برمجة تطبيقات بدء تشغيل التدفق المعلمات باستخدام أسماء المعلمات الخاصة بالتدفق: + +```json +{ + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "llm-model": "claude-3", + "llm-temperature": 0.5, + "chunk-size": 1024 + } +} +``` + +ملاحظة: في هذا المثال، `llm-rag-model` غير مقدمة بشكل صريح ولكنها سترث القيمة "claude-3" من `llm-model` بسبب علاقتها مع `controlled-by`. وبالمثل، يمكن أن ترث `chunk-overlap` قيمة محسوبة بناءً على `chunk-size`. + +سيقوم النظام بما يلي: +1. استخراج بيانات تعريف المعلمات من تعريف مخطط التدفق +2. مطابقة أسماء معلمات التدفق مع تعريفات أنواعها (على سبيل المثال، `llm-model` → نوع `llm-model`) +3. حل علاقات "يتم التحكم بها" (على سبيل المثال، ترث `llm-rag-model` من `llm-model`) +4. التحقق من صحة القيم المقدمة من المستخدم والقيم الموروثة مقابل تعريفات أنواع المعلمات +5. استبدال القيم التي تم حلها في معلمات المعالج أثناء إنشاء التدفق + +### تفاصيل التنفيذ + +#### عملية حل المعلمات + +عندما يتم بدء تدفق، يقوم النظام بتنفيذ الخطوات التالية لحل المعلمات: + +1. **تحميل مخطط التدفق**: تحميل تعريف مخطط التدفق واستخراج بيانات تعريف المعلمات +2. **استخراج البيانات الوصفية**: استخراج `type`، `description`، `order`، `advanced`، و `controlled-by` لكل معلمة معرفة في قسم `parameters` الخاص بمخطط التدفق +3. **البحث عن تعريف النوع**: لكل معلمة في مخطط التدفق: + استرجاع تعريف نوع المعلمة من متجر المخطط/التكوين باستخدام حقل `type` + يتم تخزين تعريفات الأنواع مع النوع "parameter-type" في نظام التكوين + يحتوي كل تعريف نوع على مخطط المعلمة والقيمة الافتراضية وقواعد التحقق من الصحة +4. **حل القيمة الافتراضية**: + لكل معلمة معرفة في مخطط التدفق: + التحقق مما إذا كان المستخدم قد قدم قيمة لهذه المعلمة + إذا لم يتم تقديم قيمة من قبل المستخدم، استخدم القيمة `default` من تعريف نوع المعلمة + إنشاء خريطة معلمات كاملة تحتوي على كل من القيم المقدمة من قبل المستخدم والقيم الافتراضية +5. **حل إرث المعلمات** (علاقات "يتم التحكم بها"): + للمعلمات التي تحتوي على حقل `controlled-by`، تحقق مما إذا تم توفير قيمة بشكل صريح + إذا لم يتم توفير قيمة صريحة، فقم بوراثة القيمة من المعلمة المسيطرة + إذا كانت المعلمة المسيطرة أيضًا لا تحتوي على قيمة، فاستخدم القيمة الافتراضية من تعريف النوع + التحقق من عدم وجود تبعيات دائرية في علاقات `controlled-by` +6. **التحقق من الصحة**: التحقق من صحة مجموعة المعلمات الكاملة (القيم المقدمة من قبل المستخدم والقيم الافتراضية والقيم الموروثة) مقابل تعريفات الأنواع +7. **التخزين**: تخزين مجموعة المعلمات التي تم حلها بالكامل مع مثيل التدفق لأغراض التدقيق +8. **الاستبدال القالب**: استبدال عناصر نائب المعلمات في معلمات المعالج بالقيم التي تم حلها +9. **إنشاء المعالجات**: إنشاء معالجات بمعلمات مستبدلة + +**ملاحظات تنفيذ مهمة:** +يجب على خدمة التدفق دمج المعلمات المقدمة من قبل المستخدم مع القيم الافتراضية من تعريفات أنواع المعلمات +يجب تخزين مجموعة المعلمات الكاملة (بما في ذلك القيم الافتراضية المطبقة) مع التدفق لأغراض التتبع +يحدث حل المعلمات في وقت بدء التدفق، وليس في وقت إنشاء المعالج +يجب أن يؤدي عدم وجود معلمات مطلوبة بدون قيم افتراضية إلى فشل بدء التدفق مع رسالة خطأ واضحة + +#### إرث المعلمات مع "يتم التحكم بها" + +يتيح الحقل `controlled-by` وراثة قيمة المعلمة، وهو مفيد بشكل خاص لتبسيط واجهات المستخدم مع الحفاظ على المرونة: + +**سيناريو مثال:** +تتحكم المعلمة `llm-model` في نموذج LLM الأساسي +تحتوي المعلمة `llm-rag-model` على `"controlled-by": "llm-model"` +في الوضع البسيط، يؤدي تعيين `llm-model` إلى "gpt-4" تلقائيًا إلى تعيين `llm-rag-model` إلى "gpt-4" أيضًا +في الوضع المتقدم، يمكن للمستخدمين تجاوز `llm-rag-model` بقيمة مختلفة + +**قواعد الحل:** +1. إذا كانت المعلمة تحتوي على قيمة مقدمة بشكل صريح، فاستخدم تلك القيمة +2. إذا لم تكن هناك قيمة صريحة وتم تعيين `controlled-by`، فاستخدم قيمة المعلمة المسيطرة +3. إذا كانت المعلمة المسيطرة لا تحتوي على قيمة، فارجع إلى القيمة الافتراضية من تعريف النوع +4. تؤدي التبعيات الدائرية في علاقات `controlled-by` إلى خطأ في التحقق من الصحة + +**سلوك واجهة المستخدم:** +في الوضع الأساسي/البسيط: قد تكون المعلمات التي تحتوي على `controlled-by` مخفية أو معروضة كقراءة فقط مع القيمة الموروثة +في الوضع المتقدم: يتم عرض جميع المعلمات ويمكن تكوينها بشكل فردي +عندما تتغير المعلمة المسيطرة، يتم تحديث المعلمات التابعة تلقائيًا ما لم يتم تجاوزها بشكل صريح + +#### تكامل Pulsar + +1. **عملية بدء التدفق** + يجب أن تقبل عملية بدء التدفق في Pulsar حقل `parameters` يحتوي على خريطة لقيم المعلمات + يجب تحديث مخطط طلب بدء التدفق في Pulsar لتضمين الحقل الاختياري `parameters` + مثال للطلب: + ```json + { + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +2. **عملية الحصول على التدفق** + يجب تحديث مخطط بولسر لـ "استجابة الحصول على التدفق" ليشمل الحقل `parameters`. + يتيح ذلك للعملاء استرداد قيم المعلمات التي تم استخدامها عند بدء التدفق. + مثال على الاستجابة: + ```json + { + "flow_id": "customer-A-flow", + "flow_class": "document-analysis", + "status": "running", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +#### تنفيذ خدمة التدفق + +تتطلب خدمة تكوين التدفق (`trustgraph-flow/trustgraph/config/service/flow.py`) التحسينات التالية: + +1. **وظيفة حل المعلمات** + ```python + async def resolve_parameters(self, flow_class, user_params): + """ + Resolve parameters by merging user-provided values with defaults. + + Args: + flow_class: The flow blueprint definition dict + user_params: User-provided parameters dict + + Returns: + Complete parameter dict with user values and defaults merged + """ + ``` + + يجب أن تقوم هذه الدالة بما يلي: + استخراج بيانات تعريف المعلمات من قسم `parameters` في مخطط سير العمل. + لكل معلمة، استرداد تعريف النوع الخاص بها من مستودع التكوين. + تطبيق القيم الافتراضية لأي معلمات لم يتم توفيرها من قبل المستخدم. + التعامل مع علاقات الوراثة `controlled-by`. + إرجاع المجموعة الكاملة للمعلمات. + +2. **الطريقة المعدلة `handle_start_flow`** + استدعاء `resolve_parameters` بعد تحميل مخطط سير العمل. + استخدام المجموعة الكاملة للمعلمات التي تم حلها للاستبدال في القوالب. + تخزين المجموعة الكاملة للمعلمات (وليس فقط المعلمات التي قدمها المستخدم) مع سير العمل. + التحقق من أن جميع المعلمات المطلوبة لها قيم. + +3. **استرداد أنواع المعلمات** + يتم تخزين تعريفات أنواع المعلمات في التكوين بنوع "parameter-type". + يحتوي كل تعريف نوع على مخطط وقيمة افتراضية وقواعد تحقق. + تخزين أنواع المعلمات المستخدمة بشكل متكرر في ذاكرة التخزين المؤقت لتقليل عمليات البحث في التكوين. + +#### تكامل نظام التكوين + +3. **تخزين كائنات سير العمل** + عندما تتم إضافة سير عمل إلى نظام التكوين بواسطة مكون سير العمل في مدير التكوين، يجب أن تتضمن كائن سير العمل قيم المعلمات التي تم حلها. + يحتاج مدير التكوين إلى تخزين كل من المعلمات التي قدمها المستخدم في الأصل والقيم التي تم حلها (مع تطبيق القيم الافتراضية). + يجب أن تتضمن كائنات سير العمل في نظام التكوين: + `parameters`: القيم النهائية للمعلمات التي تم حلها والتي تم استخدامها لسير العمل. + +#### تكامل واجهة سطر الأوامر + +4. **أوامر واجهة سطر الأوامر الخاصة بالمكتبة** + تحتاج أوامر واجهة سطر الأوامر التي تبدأ سير العمل إلى دعم المعلمات: + قبول قيم المعلمات عبر علامات سطر الأوامر أو ملفات التكوين. + التحقق من صحة المعلمات مقابل تعريفات مخطط سير العمل قبل الإرسال. + دعم إدخال ملف المعلمات (JSON/YAML) لمجموعات المعلمات المعقدة. + + تحتاج أوامر واجهة سطر الأوامر التي تعرض سير العمل إلى عرض معلومات المعلمات: + عرض قيم المعلمات المستخدمة عند بدء سير العمل. + عرض المعلمات المتاحة لمخطط سير عمل. + عرض مخططات التحقق من صحة المعلمات والقيم الافتراضية. + +#### تكامل الفئة الأساسية للمعالج + +5. **دعم ParameterSpec** + تحتاج الفئات الأساسية للمعالج إلى دعم استبدال المعلمات من خلال آلية ParametersSpec الحالية. + يجب تحسين فئة ParametersSpec (الموجودة في نفس الوحدة النمطية مثل ConsumerSpec و ProducerSpec) إذا لزم الأمر لدعم استبدال القوالب للمعلمات. + يجب أن تكون المعالجات قادرة على استدعاء ParametersSpec لتكوين معامها باستخدام قيم المعلمات التي تم حلها في وقت بدء سير العمل. + يجب أن تقوم تنفيذ ParametersSpec بما يلي: + قبول تكوينات المعلمات التي تحتوي على عناصر نائبة للمعلمات (مثل `{model}`، `{temperature}`). + دعم استبدال المعلمات في وقت التشغيل عند إنشاء المعالج. + التحقق من أن القيم المستبدلة تتطابق مع الأنواع والقيود المتوقعة. + توفير معالجة الأخطاء للإشارات المفقودة أو غير الصالحة للمعلمات. + +#### قواعد الاستبدال + +تستخدم المعلمات التنسيق `{parameter-name}` في معلمات المعالج. +تتطابق أسماء المعلمات في المعلمات مع المفاتيح في قسم `parameters` في سير العمل. +يحدث الاستبدال جنبًا إلى جنب مع استبدال `{id}` و `{class}`. +تؤدي الإشارات غير الصالحة للمعلمات إلى أخطاء في وقت بدء التشغيل. +يحدث التحقق من النوع بناءً على تعريف المعلمة المخزن مركزيًا. +**هام**: يتم تخزين جميع قيم المعلمات وإرسالها كسلاسل. + يتم تحويل الأرقام إلى سلاسل (على سبيل المثال، `0.7` تصبح `"0.7"`). + يتم تحويل القيم المنطقية إلى سلاسل صغيرة (على سبيل المثال، `true` تصبح `"true"`). + هذا مطلوب بواسطة مخطط Pulsar الذي يحدد `parameters = Map(String())`. + +مثال على الحل: +``` +Flow parameter mapping: "model": "llm-model" +Processor parameter: "model": "{model}" +User provides: "model": "gemma3:8b" +Final parameter: "model": "gemma3:8b" + +Example with type conversion: +Parameter type default: 0.7 (number) +Stored in flow: "0.7" (string) +Substituted in processor: "0.7" (string) +``` + +## استراتيجية الاختبار + +اختبارات الوحدة للتحقق من صحة مخططات المعلمات. +اختبارات التكامل لاستبدال المعلمات في معلمات المعالج. +اختبارات شاملة لإطلاق العمليات التدفقية بقيم معلمات مختلفة. +اختبارات واجهة المستخدم لإنشاء النموذج والتحقق من صحة المعلمات. +اختبارات الأداء للعمليات التدفقية التي تحتوي على العديد من المعلمات. +حالات حافة: معلمات مفقودة، وأنواع غير صالحة، وإشارات غير معرفة للمعلمات. + +## خطة الترحيل + +1. يجب أن يستمر النظام في دعم مخططات العمليات التدفقية التي لا تحتوي على معلمات. + معلنة. +2. يجب أن يستمر النظام في دعم العمليات التدفقية التي لا يتم فيها تحديد أي معلمات: + هذا يعمل للعمليات التدفقية التي لا تحتوي على معلمات، وللعمليات التدفقية التي تحتوي على معلمات + (لديها قيم افتراضية). + +## أسئلة مفتوحة + +س: هل يجب أن تدعم المعلمات كائنات متداخلة معقدة أم يجب الالتزام بأنواع بسيطة؟ +ج: سيتم ترميز قيم المعلمات كسلاسل نصية، لذلك من المحتمل أن نلتزم بالسلاسل النصية. + + +س: هل يجب السماح بوضع عناصر نائب للمعلمات في أسماء قوائم الانتظار أم فقط في + المعلمات؟ +ج: فقط في المعلمات لإزالة عمليات الحقن والحالات الحافة الغريبة. + +س: كيف نتعامل مع التعارضات بين أسماء المعلمات والمتغيرات النظامية مثل + `id` و `class`؟ +ج: من غير المسموح بتحديد المعرف (id) والفئة (class) عند إطلاق عملية تدفقية. + +س: هل يجب أن ندعم المعلمات المحسوبة (المشتقة من معلمات أخرى)؟ +ج: مجرد استبدال السلاسل النصية لإزالة عمليات الحقن والحالات الحافة الغريبة. + +## المراجع + +مواصفات مخطط JSON: https://json-schema.org/ +مواصفات تعريف مخطط العمليات التدفقية: docs/tech-specs/flow-class-definition.md diff --git a/docs/tech-specs/flow-configurable-parameters.es.md b/docs/tech-specs/flow-configurable-parameters.es.md new file mode 100644 index 00000000..f48bdd47 --- /dev/null +++ b/docs/tech-specs/flow-configurable-parameters.es.md @@ -0,0 +1,485 @@ +# Especificación Técnica de Parámetros Configurables para Flow Blueprint + +## Resumen + +Esta especificación describe la implementación de parámetros configurables para flow blueprints en TrustGraph. Los parámetros permiten a los usuarios personalizar los parámetros del procesador en el momento de la ejecución del flujo, proporcionando valores que reemplazan los marcadores de posición de parámetros en la definición del flow blueprint. + +Los parámetros funcionan a través de la sustitución de variables de plantilla en los parámetros del procesador, de manera similar a cómo funcionan las variables `{id}` y `{class}`, pero con valores proporcionados por el usuario. + +La integración admite cuatro casos de uso principales: + +1. **Selección de Modelo**: Permitir a los usuarios elegir diferentes modelos LLM (por ejemplo, `gemma3:8b`, `gpt-4`, `claude-3`) para los procesadores. +2. **Configuración de Recursos**: Ajustar los parámetros del procesador, como los tamaños de lote, los tamaños de lote y los límites de concurrencia. +3. **Ajuste del Comportamiento**: Modificar el comportamiento del procesador a través de parámetros como la temperatura, el número máximo de tokens o los umbrales de recuperación. +4. **Parámetros Específicos del Entorno**: Configurar puntos finales, claves de API o URL específicas de la región para cada implementación. + +## Objetivos + +**Configuración Dinámica del Procesador**: Permitir la configuración en tiempo de ejecución de los parámetros del procesador a través de la sustitución de parámetros. +**Validación de Parámetros**: Proporcionar verificación de tipos y validación para los parámetros en el momento de la ejecución del flujo. +**Valores Predeterminados**: Admitir valores predeterminados sensatos, al tiempo que se permite la sobrescritura para usuarios avanzados. +**Sustitución de Plantillas**: Reemplazar sin problemas los marcadores de posición de parámetros en los parámetros del procesador. +**Integración de la Interfaz de Usuario**: Permitir la entrada de parámetros a través de interfaces de API y de interfaz de usuario. +**Seguridad de Tipos**: Asegurar que los tipos de parámetros coincidan con los tipos de parámetros del procesador esperados. +**Documentación**: Esquemas de parámetros auto-documentados dentro de las definiciones de flow blueprint. +**Compatibilidad con Versiones Anteriores**: Mantener la compatibilidad con los flow blueprints existentes que no utilizan parámetros. + +## Antecedentes + +Los flow blueprints en TrustGraph ahora admiten parámetros de procesador que pueden contener valores fijos o marcadores de posición de parámetros. Esto crea una oportunidad para la personalización en tiempo de ejecución. + +Los parámetros de procesador actuales admiten: +Valores fijos: `"model": "gemma3:12b"` +Marcadores de posición de parámetros: `"model": "gemma3:{model-size}"` + +Esta especificación define cómo se: +Declaran en las definiciones de flow blueprint. +Validan cuando se ejecutan los flujos. +Sustituyen en los parámetros del procesador. +Exponen a través de las API y la interfaz de usuario. + +Al aprovechar los parámetros de procesador parametrizados, TrustGraph puede: +Reducir la duplicación de flow blueprints mediante el uso de parámetros para las variaciones. +Permitir a los usuarios ajustar el comportamiento del procesador sin modificar las definiciones. +Admitir configuraciones específicas del entorno a través de los valores de los parámetros. +Mantener la seguridad de tipos a través de la validación del esquema de parámetros. + +## Diseño Técnico + +### Arquitectura + +El sistema de parámetros configurables requiere los siguientes componentes técnicos: + +1. **Definición del Esquema de Parámetros** + Definiciones de parámetros basadas en JSON Schema dentro de los metadatos del flow blueprint. + Definiciones de tipos que incluyen cadenas, números, booleanos, enumeraciones y tipos de objetos. + Reglas de validación que incluyen valores mínimos/máximos, patrones y campos obligatorios. + + Módulo: trustgraph-flow/trustgraph/flow/definition.py + +2. **Motor de Resolución de Parámetros** + Validación de parámetros en tiempo de ejecución contra el esquema. + Aplicación de valores predeterminados para los parámetros no especificados. + Inyección de parámetros en el contexto de ejecución del flujo. + Coerción y conversión de tipos según sea necesario. + + Módulo: trustgraph-flow/trustgraph/flow/parameter_resolver.py + +3. **Integración del Almacén de Parámetros** + Recuperación de definiciones de parámetros del almacén de esquemas/configuración. + Almacenamiento en caché de definiciones de parámetros utilizadas con frecuencia. + Validación contra esquemas almacenados centralmente. + + Módulo: trustgraph-flow/trustgraph/flow/parameter_store.py + +4. **Extensiones del Lanzador de Flujos** + Extensiones de API para aceptar valores de parámetros durante el lanzamiento del flujo. + Resolución de mapeo de parámetros (nombres de flujo a nombres de definición). + Manejo de errores para combinaciones de parámetros no válidas. + + Módulo: trustgraph-flow/trustgraph/flow/launcher.py + +5. **Formularios de Parámetros de la Interfaz de Usuario** + Generación dinámica de formularios a partir de los metadatos de los parámetros del flujo. + Visualización ordenada de parámetros utilizando el campo `order`. + Etiquetas descriptivas de parámetros utilizando el campo `description`. + Validación de entrada contra las definiciones de tipo de parámetro. + Preajustes y plantillas de parámetros. + + Módulo: trustgraph-ui/components/flow-parameters/ + +### Modelos de Datos + +#### Definiciones de Parámetros (Almacenadas en Esquema/Configuración) + +Las definiciones de parámetros se almacenan centralmente en el sistema de esquemas y configuración con el tipo "parameter-type": + +```json +{ + "llm-model": { + "type": "string", + "description": "LLM model to use", + "default": "gpt-4", + "enum": [ + { + "id": "gpt-4", + "description": "OpenAI GPT-4 (Most Capable)" + }, + { + "id": "gpt-3.5-turbo", + "description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)" + }, + { + "id": "claude-3", + "description": "Anthropic Claude 3 (Thoughtful & Safe)" + }, + { + "id": "gemma3:8b", + "description": "Google Gemma 3 8B (Open Source)" + } + ], + "required": false + }, + "model-size": { + "type": "string", + "description": "Model size variant", + "default": "8b", + "enum": ["2b", "8b", "12b", "70b"], + "required": false + }, + "temperature": { + "type": "number", + "description": "Model temperature for generation", + "default": 0.7, + "minimum": 0.0, + "maximum": 2.0, + "required": false + }, + "chunk-size": { + "type": "integer", + "description": "Document chunk size", + "default": 512, + "minimum": 128, + "maximum": 2048, + "required": false + } +} +``` + +#### Diagrama de flujo con referencias de parámetros + +Los diagramas de flujo definen los metadatos de los parámetros con referencias de tipo, descripciones y orden: + +```json +{ + "flow_class": "document-analysis", + "parameters": { + "llm-model": { + "type": "llm-model", + "description": "Primary LLM model for text completion", + "order": 1 + }, + "llm-rag-model": { + "type": "llm-model", + "description": "LLM model for RAG operations", + "order": 2, + "advanced": true, + "controlled-by": "llm-model" + }, + "llm-temperature": { + "type": "temperature", + "description": "Generation temperature for creativity control", + "order": 3, + "advanced": true + }, + "chunk-size": { + "type": "chunk-size", + "description": "Document chunk size for processing", + "order": 4, + "advanced": true + }, + "chunk-overlap": { + "type": "integer", + "description": "Overlap between document chunks", + "order": 5, + "advanced": true, + "controlled-by": "chunk-size" + } + }, + "class": { + "text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "parameters": { + "model": "{llm-model}", + "temperature": "{llm-temperature}" + } + }, + "rag-completion:{class}": { + "request": "non-persistent://tg/request/rag-completion:{class}", + "response": "non-persistent://tg/response/rag-completion:{class}", + "parameters": { + "model": "{llm-rag-model}", + "temperature": "{llm-temperature}" + } + } + }, + "flow": { + "chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "parameters": { + "chunk_size": "{chunk-size}", + "chunk_overlap": "{chunk-overlap}" + } + } + } +} +``` + +La sección `parameters` mapea los nombres de parámetros específicos del flujo (claves) a objetos de metadatos de parámetros que contienen: +`type`: Referencia a la definición de parámetro definida centralmente (por ejemplo, "llm-model") +`description`: Descripción legible por humanos para su visualización en la interfaz de usuario +`order`: Orden de visualización para los formularios de parámetros (los números más bajos aparecen primero) +`advanced` (opcional): Bandera booleana que indica si este es un parámetro avanzado (por defecto: falso). Cuando se establece en verdadero, la interfaz de usuario puede ocultar este parámetro de forma predeterminada o colocarlo en una sección "Avanzado" +`controlled-by` (opcional): Nombre de otro parámetro que controla el valor de este parámetro cuando está en modo simple. Cuando se especifica, este parámetro hereda su valor del parámetro de control, a menos que se anule explícitamente + +Este enfoque permite: +Definiciones de tipos de parámetros reutilizables en múltiples plantillas de flujo +Gestión y validación centralizadas de tipos de parámetros +Descripciones y orden de parámetros específicos del flujo +Experiencia de interfaz de usuario mejorada con formularios de parámetros descriptivos +Validación de parámetros consistente en todos los flujos +Adición fácil de nuevos tipos de parámetros estándar +Interfaz de usuario simplificada con separación de modo básico/avanzado +Herencia de valores de parámetros para configuraciones relacionadas + +#### Solicitud de inicio de flujo + +La API de inicio de flujo acepta parámetros utilizando los nombres de parámetros del flujo: + +```json +{ + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "llm-model": "claude-3", + "llm-temperature": 0.5, + "chunk-size": 1024 + } +} +``` + +Nota: En este ejemplo, `llm-rag-model` no se proporciona explícitamente, pero heredará el valor "claude-3" de `llm-model` debido a su relación `controlled-by`. De manera similar, `chunk-overlap` podría heredar un valor calculado basado en `chunk-size`. + +El sistema realizará lo siguiente: +1. Extraer metadatos de parámetros de la definición de la plantilla de flujo. +2. Mapear los nombres de los parámetros del flujo a sus definiciones de tipo (por ejemplo, `llm-model` → tipo `llm-model`). +3. Resolver las relaciones de control (por ejemplo, `llm-rag-model` hereda de `llm-model`). +4. Validar los valores proporcionados por el usuario y los valores heredados en función de las definiciones de tipo de los parámetros. +5. Sustituir los valores resueltos en los parámetros del procesador durante la instanciación del flujo. + +### Detalles de implementación + +#### Proceso de resolución de parámetros + +Cuando se inicia un flujo, el sistema realiza los siguientes pasos de resolución de parámetros: + +1. **Carga de la plantilla del flujo**: Cargar la definición de la plantilla del flujo y extraer los metadatos de los parámetros. +2. **Extracción de metadatos**: Extraer `type`, `description`, `order`, `advanced` y `controlled-by` para cada parámetro definido en la sección `parameters` de la plantilla del flujo. +3. **Búsqueda de la definición de tipo**: Para cada parámetro en la plantilla del flujo: + Recuperar la definición de tipo del parámetro del almacén de esquema/configuración utilizando el campo `type`. + Las definiciones de tipo se almacenan con el tipo "parameter-type" en el sistema de configuración. + Cada definición de tipo contiene el esquema del parámetro, el valor predeterminado y las reglas de validación. +4. **Resolución del valor predeterminado**: + Para cada parámetro definido en la plantilla del flujo: + Comprobar si el usuario ha proporcionado un valor para este parámetro. + Si no se proporciona ningún valor del usuario, utilizar el valor `default` de la definición de tipo del parámetro. + Crear un mapa de parámetros completo que contenga tanto los valores proporcionados por el usuario como los valores predeterminados. +5. **Resolución de la herencia de parámetros** (relaciones de control): + Para los parámetros con el campo `controlled-by`, comprobar si se ha proporcionado un valor explícito. + Si no se proporciona ningún valor explícito, heredar el valor del parámetro de control. + Si el parámetro de control también no tiene valor, utilizar el valor predeterminado de la definición de tipo. + Validar que no existan dependencias circulares en las relaciones `controlled-by`. +6. **Validación**: Validar el conjunto completo de parámetros (proporcionados por el usuario, predeterminados y heredados) en función de las definiciones de tipo. +7. **Almacenamiento**: Almacenar el conjunto completo de parámetros resueltos con la instancia del flujo para su trazabilidad. +8. **Sustitución de plantillas**: Reemplazar los marcadores de posición de parámetros en los parámetros del procesador con los valores resueltos. +9. **Instanciación del procesador**: Crear procesadores con los parámetros sustituidos. + +**Notas importantes de implementación**: +El servicio de flujo DEBE combinar los parámetros proporcionados por el usuario con los valores predeterminados de las definiciones de tipo de parámetros. +El conjunto completo de parámetros (incluidos los valores predeterminados aplicados) DEBE almacenarse con el flujo para su trazabilidad. +La resolución de parámetros se realiza al inicio del flujo, no en el momento de la instanciación del procesador. +Los parámetros obligatorios sin valores predeterminados DEBEN provocar que el inicio del flujo falle con un mensaje de error claro. + +#### Herencia de parámetros con control + +El campo `controlled-by` permite la herencia de valores de parámetros, lo que es especialmente útil para simplificar las interfaces de usuario al tiempo que se mantiene la flexibilidad: + +**Escenario de ejemplo**: +El parámetro `llm-model` controla el modelo LLM primario. +El parámetro `llm-rag-model` tiene el valor `"controlled-by": "llm-model"`. +En el modo simple, establecer `llm-model` en "gpt-4" establece automáticamente `llm-rag-model` en "gpt-4" también. +En el modo avanzado, los usuarios pueden anular `llm-rag-model` con un valor diferente. + +**Reglas de resolución**: +1. Si un parámetro tiene un valor proporcionado explícitamente, utilizar ese valor. +2. Si no hay ningún valor explícito y `controlled-by` está establecido, utilizar el valor del parámetro de control. +3. Si el parámetro de control no tiene valor, recurrir al valor predeterminado de la definición de tipo. +4. Las dependencias circulares en las relaciones `controlled-by` dan como resultado un error de validación. + +**Comportamiento de la interfaz de usuario**: +En el modo básico/simple: Los parámetros con `controlled-by` pueden estar ocultos o mostrarse como de solo lectura con el valor heredado. +En el modo avanzado: Se muestran todos los parámetros y se pueden configurar individualmente. +Cuando cambia un parámetro de control, los parámetros dependientes se actualizan automáticamente, a menos que se anulen explícitamente. + +#### Integración de Pulsar + +1. **Operación de inicio de flujo** + La operación de inicio de flujo de Pulsar debe aceptar un campo `parameters` que contenga un mapa de valores de parámetros. + El esquema de Pulsar para la solicitud de inicio de flujo debe actualizarse para incluir el campo opcional `parameters`. + Ejemplo de solicitud: + ```json + { + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +2. **Operación Get-Flow** + El esquema de Pulsar para la respuesta de get-flow debe actualizarse para incluir el campo `parameters` + Esto permite a los clientes recuperar los valores de los parámetros que se utilizaron cuando se inició el flujo. + Ejemplo de respuesta: + ```json + { + "flow_id": "customer-A-flow", + "flow_class": "document-analysis", + "status": "running", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +#### Implementación del Servicio de Flujo + +El servicio de configuración de flujo (`trustgraph-flow/trustgraph/config/service/flow.py`) requiere las siguientes mejoras: + +1. **Función de Resolución de Parámetros** + ```python + async def resolve_parameters(self, flow_class, user_params): + """ + Resolve parameters by merging user-provided values with defaults. + + Args: + flow_class: The flow blueprint definition dict + user_params: User-provided parameters dict + + Returns: + Complete parameter dict with user values and defaults merged + """ + ``` + + Esta función debe: + Extraer los metadatos de los parámetros de la sección `parameters` del plano de flujo. + Para cada parámetro, obtener la definición de tipo de la tienda de configuración. + Aplicar los valores predeterminados para cualquier parámetro que no sea proporcionado por el usuario. + Manejar las relaciones de herencia de `controlled-by`. + Devolver el conjunto de parámetros completo. + +2. **Método `handle_start_flow` Modificado** + Llamar a `resolve_parameters` después de cargar el plano de flujo. + Utilizar el conjunto de parámetros resuelto completo para la sustitución de plantillas. + Almacenar el conjunto de parámetros completo (no solo los proporcionados por el usuario) con el flujo. + Validar que todos los parámetros requeridos tengan valores. + +3. **Obtención del Tipo de Parámetro** + Las definiciones de tipo de parámetro se almacenan en la configuración con el tipo "parameter-type". + Cada definición de tipo contiene un esquema, un valor predeterminado y reglas de validación. + Almacenar en caché los tipos de parámetro utilizados con frecuencia para reducir las búsquedas en la configuración. + +#### Integración del Sistema de Configuración + +3. **Almacenamiento de Objetos de Flujo** + Cuando un flujo se agrega al sistema de configuración por el componente de flujo en el administrador de configuración, el objeto de flujo debe incluir los valores de parámetros resueltos. + El administrador de configuración debe almacenar tanto los parámetros originales proporcionados por el usuario como los valores resueltos (con los valores predeterminados aplicados). + Los objetos de flujo en el sistema de configuración deben incluir: + `parameters`: Los valores de parámetros resueltos finales utilizados para el flujo. + +#### Integración de la CLI + +4. **Comandos de la CLI de la Biblioteca** + Los comandos de la CLI que inician flujos necesitan soporte de parámetros: + Aceptar valores de parámetros a través de indicadores de línea de comandos o archivos de configuración. + Validar los parámetros contra las definiciones del plano de flujo antes de la presentación. + Soporte para la entrada de archivos de parámetros (JSON/YAML) para conjuntos de parámetros complejos. + + Los comandos de la CLI que muestran flujos deben mostrar información de parámetros: + Mostrar los valores de parámetros utilizados cuando se inició el flujo. + Mostrar los parámetros disponibles para un plano de flujo. + Mostrar los esquemas y valores predeterminados de validación de parámetros. + +#### Integración de la Clase Base del Procesador + +5. **Soporte de ParameterSpec** + Las clases base del procesador deben admitir la sustitución de parámetros a través del mecanismo ParametersSpec existente. + La clase ParametersSpec (ubicada en el mismo módulo que ConsumerSpec y ProducerSpec) debe mejorarse si es necesario para admitir la sustitución de plantillas de parámetros. + Los procesadores deben poder invocar ParametersSpec para configurar sus parámetros con los valores de parámetros resueltos en el momento del lanzamiento del flujo. + La implementación de ParametersSpec debe: + Aceptar configuraciones de parámetros que contengan marcadores de posición de parámetros (por ejemplo, `{model}`, `{temperature}`). + Admitir la sustitución de parámetros en tiempo de ejecución cuando se instancia el procesador. + Validar que los valores sustituidos coincidan con los tipos y restricciones esperados. + Proporcionar manejo de errores para referencias de parámetros faltantes o no válidos. + +#### Reglas de Sustitución + +Los parámetros utilizan el formato `{parameter-name}` en los parámetros del procesador. +Los nombres de los parámetros en los parámetros coinciden con las claves en la sección `parameters` del flujo. +La sustitución se produce junto con la sustitución de `{id}` y `{class}`. +Las referencias de parámetros no válidas dan como resultado errores en el momento del lanzamiento. +La validación de tipos se basa en la definición de parámetro almacenada de forma centralizada. +**IMPORTANTE**: Todos los valores de parámetros se almacenan y transmiten como cadenas. + Los números se convierten a cadenas (por ejemplo, `0.7` se convierte en `"0.7"`). + Los booleanos se convierten a cadenas en minúsculas (por ejemplo, `true` se convierte en `"true"`). + Esto es requerido por el esquema de Pulsar que define `parameters = Map(String())`. + +Ejemplo de resolución: +``` +Flow parameter mapping: "model": "llm-model" +Processor parameter: "model": "{model}" +User provides: "model": "gemma3:8b" +Final parameter: "model": "gemma3:8b" + +Example with type conversion: +Parameter type default: 0.7 (number) +Stored in flow: "0.7" (string) +Substituted in processor: "0.7" (string) +``` + +## Estrategia de Pruebas + +Pruebas unitarias para la validación del esquema de parámetros. +Pruebas de integración para la sustitución de parámetros en los parámetros del procesador. +Pruebas de extremo a extremo para el lanzamiento de flujos con diferentes valores de parámetros. +Pruebas de la interfaz de usuario para la generación y validación de formularios de parámetros. +Pruebas de rendimiento para flujos con muchos parámetros. +Casos extremos: parámetros faltantes, tipos no válidos, referencias de parámetros no definidos. + +## Plan de Migración + +1. El sistema debe seguir soportando planos de flujo sin parámetros + declarados. +2. El sistema debe seguir soportando flujos sin parámetros especificados: + Esto funciona para flujos sin parámetros y para flujos con parámetros + (que tienen valores predeterminados). + +## Preguntas Abiertas + +P: ¿Deben los parámetros soportar objetos anidados complejos o limitarse a tipos simples? +R: Los valores de los parámetros se codificarán como cadenas, por lo que probablemente + queremos limitarnos a cadenas. + +P: ¿Se deben permitir los marcadores de posición de parámetros en los nombres de las colas o solo en + los parámetros? +R: Solo en los parámetros para evitar inyecciones extrañas y casos límite. + +P: ¿Cómo manejar los conflictos entre los nombres de los parámetros y las variables del sistema como + `id` y `class`? +R: No es válido especificar "id" y "class" al iniciar un flujo. + +P: ¿Debemos soportar parámetros calculados (derivados de otros parámetros)? +R: Solo la sustitución de cadenas para evitar inyecciones extrañas y casos límite. + +## Referencias + +Especificación de JSON Schema: https://json-schema.org/ +Especificación de la Definición del Plano de Flujo: docs/tech-specs/flow-class-definition.md diff --git a/docs/tech-specs/flow-configurable-parameters.he.md b/docs/tech-specs/flow-configurable-parameters.he.md new file mode 100644 index 00000000..c324efa9 --- /dev/null +++ b/docs/tech-specs/flow-configurable-parameters.he.md @@ -0,0 +1,485 @@ +# מפרט טכני של פרמטרים הניתנים להגדרה עבור תבניות זרימה + +## סקירה כללית + +מפרט זה מתאר את יישום הפרמטרים הניתנים להגדרה עבור תבניות זרימה ב-TrustGraph. פרמטרים מאפשרים למשתמשים להתאים אישית את פרמטרי המעבד בזמן הפעלת הזרימה על ידי מתן ערכים המחליפים את מקומות הפרמטרים בהגדרת תבנית הזרימה. + +פרמטרים פועלים באמצעות החלפת משתנים בתבניות בפרמטרי המעבד, בדומה לאופן שבו משתנים `{id}` ו-`{class}` פועלים, אך עם ערכים שמסופקים על ידי המשתמש. + +האינטגרציה תומכת בארבעה תרחישי שימוש עיקריים: + +1. **בחירת מודל**: לאפשר למשתמשים לבחור מודלים שונים של LLM (לדוגמה, `gemma3:8b`, `gpt-4`, `claude-3`) עבור מעבדים. +2. **תצורת משאבים**: התאמת פרמטרי מעבד כגון גודל חבילות, גודל אצווה ומגבלות מקביליות. +3. **כוונון התנהגות**: שינוי התנהגות המעבד באמצעות פרמטרים כגון טמפרטורה, מקסימום טוקנים או ספי תאחזור. +4. **פרמטרים ספציפיים לסביבה**: הגדרת נקודות קצה, מפתחות API או כתובות URL ספציפיות לאזור עבור כל פריסה. + +## מטרות + +**תצורת מעבד דינמית**: לאפשר תצורת זמן ריצה של פרמטרי מעבד באמצעות החלפת פרמטרים. +**אימות פרמטרים**: לספק בדיקת סוג ואימות עבור פרמטרים בזמן הפעלת הזרימה. +**ערכי ברירת מחדל**: לתמוך בערכי ברירת מחדל הגיוניים תוך מתן אפשרות לשנות אותם עבור משתמשים מתקדמים. +**החלפת תבניות**: להחליף בצורה חלקה את מקומות הפרמטרים בפרמטרי המעבד. +**אינטגרציה עם ממשק משתמש**: לאפשר הזנת פרמטרים באמצעות ממשקי API וממשקי משתמש. +**בטיחות סוגים**: להבטיח שטיפוסי הפרמטרים תואמים לטיפוסי פרמטרי המעבד הצפויים. +**תיעוד**: סכימות פרמטרים המתועדות באופן עצמי בתוך הגדרות תבניות הזרימה. +**תאימות לאחור**: לשמור על תאימות לתבניות זרימה קיימות שאינן משתמשות בפרמטרים. + +## רקע + +תבניות זרימה ב-TrustGraph תומכות כעת בפרמטרי מעבד שניתן להכיל ערכים קבועים או מקומות שמירת פרמטרים. זה יוצר הזדמנות להתאמה אישית בזמן ריצה. + +פרמטרי מעבד קיימים תומכים ב: +ערכים קבועים: `"model": "gemma3:12b"` +מקומות שמירת פרמטרים: `"model": "gemma3:{model-size}"` + +מפרט זה מגדיר כיצד פרמטרים: +מוצהרים בהגדרות תבניות זרימה +מאומתים כאשר זרימות מופעלות +מוכנסים לפרמטרי מעבד +נחשפים באמצעות ממשקי API וממשקי משתמש + +על ידי שימוש בפרמטרי מעבד מוגדרים, TrustGraph יכולה: +להפחית שכפול של תבניות זרימה על ידי שימוש בפרמטרים עבור וריאציות +לאפשר למשתמשים לכוונן את התנהגות המעבד מבלי לשנות הגדרות +לתמוך בתצורות ספציפיות לסביבה באמצעות ערכי פרמטרים +לשמור על בטיחות סוגים באמצעות אימות סכימת פרמטרים + +## עיצוב טכני + +### ארכיטקטורה + +מערכת הפרמטרים הניתנים להגדרה דורשת את הרכיבים הטכניים הבאים: + +1. **הגדרת סכימת פרמטרים** + הגדרות פרמטרים מבוססות סכימת JSON בתוך מטא-נתונים של תבניות זרימה + הגדרות סוגים כולל מחרוזות, מספרים, בוליאנים, enum ואובייקטים + כללי אימות כולל ערכים מינימליים/מקסימליים, תבניות ושדות חובה + + מודול: trustgraph-flow/trustgraph/flow/definition.py + +2. **מנוע פתרון פרמטרים** + אימות פרמטרים בזמן ריצה מול סכימה + יישום ערכי ברירת מחדל עבור פרמטרים לא מוגדרים + הכנסת פרמטרים להקשר ביצוע הזרימה + המרה והסבה של סוגים לפי הצורך + + מודול: trustgraph-flow/trustgraph/flow/parameter_resolver.py + +3. **אינטגרציה עם מאגר פרמטרים** + אחזור הגדרות פרמטרים ממערכת סכימות/תצורה + שמירת פרמטרי הגדרה בשימוש תכוף + אימות מול סכימות המאוחסנות באופן מרכזי + + מודול: trustgraph-flow/trustgraph/flow/parameter_store.py + +4. **הרחבות משגר זרימה** + הרחבות API לקבלת ערכי פרמטרים במהלך הפעלת זרימה + רזולוציית מיפוי פרמטרים (שמות זרימה לשמות הגדרה) + טיפול בשגיאות עבור שילובים לא חוקיים של פרמטרים + + מודול: trustgraph-flow/trustgraph/flow/launcher.py + +5. **טפסי פרמטרים של ממשק משתמש** + יצירת טפסים דינמיים ממטא-נתוני פרמטרים של זרימה + תצוגה מסודרת של פרמטרים באמצעות שדה `order` + תגיות תיאוריות של פרמטרים באמצעות שדה `description` + אימות קלט מול הגדרות סוג פרמטרים + ערכות מקדימות ותבניות פרמטרים + + מודול: trustgraph-ui/components/flow-parameters/ + +### מודלים של נתונים + +#### הגדרות פרמטרים (מאוחסנות בסכימה/תצורה) + +הגדרות פרמטרים מאוחסנות באופן מרכזי במערכת הסכימות והתצורה עם סוג "parameter-type": +פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא). +```json +{ + "llm-model": { + "type": "string", + "description": "LLM model to use", + "default": "gpt-4", + "enum": [ + { + "id": "gpt-4", + "description": "OpenAI GPT-4 (Most Capable)" + }, + { + "id": "gpt-3.5-turbo", + "description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)" + }, + { + "id": "claude-3", + "description": "Anthropic Claude 3 (Thoughtful & Safe)" + }, + { + "id": "gemma3:8b", + "description": "Google Gemma 3 8B (Open Source)" + } + ], + "required": false + }, + "model-size": { + "type": "string", + "description": "Model size variant", + "default": "8b", + "enum": ["2b", "8b", "12b", "70b"], + "required": false + }, + "temperature": { + "type": "number", + "description": "Model temperature for generation", + "default": 0.7, + "minimum": 0.0, + "maximum": 2.0, + "required": false + }, + "chunk-size": { + "type": "integer", + "description": "Document chunk size", + "default": 512, + "minimum": 128, + "maximum": 2048, + "required": false + } +} +``` + +#### תרשים זרימה עם הפניות לפרמטרים + +תרשימי זרימה מגדירים מטא-נתונים של פרמטרים עם הפניות לסוג, תיאורים וסדר: + +```json +{ + "flow_class": "document-analysis", + "parameters": { + "llm-model": { + "type": "llm-model", + "description": "Primary LLM model for text completion", + "order": 1 + }, + "llm-rag-model": { + "type": "llm-model", + "description": "LLM model for RAG operations", + "order": 2, + "advanced": true, + "controlled-by": "llm-model" + }, + "llm-temperature": { + "type": "temperature", + "description": "Generation temperature for creativity control", + "order": 3, + "advanced": true + }, + "chunk-size": { + "type": "chunk-size", + "description": "Document chunk size for processing", + "order": 4, + "advanced": true + }, + "chunk-overlap": { + "type": "integer", + "description": "Overlap between document chunks", + "order": 5, + "advanced": true, + "controlled-by": "chunk-size" + } + }, + "class": { + "text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "parameters": { + "model": "{llm-model}", + "temperature": "{llm-temperature}" + } + }, + "rag-completion:{class}": { + "request": "non-persistent://tg/request/rag-completion:{class}", + "response": "non-persistent://tg/response/rag-completion:{class}", + "parameters": { + "model": "{llm-rag-model}", + "temperature": "{llm-temperature}" + } + } + }, + "flow": { + "chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "parameters": { + "chunk_size": "{chunk-size}", + "chunk_overlap": "{chunk-overlap}" + } + } + } +} +``` + +הסעיף `parameters` ממפה שמות פרמטרים ספציפיים לזרימה (מפתחות) לאובייקטי מטא-נתונים של פרמטרים המכילים: +`type`: הפניה להגדרה מרכזית של פרמטר (לדוגמה, "llm-model") +`description`: תיאור קריא לבני אדם לצורך הצגה בממשק המשתמש +`order`: סדר הצגה של טפסי פרמטרים (מספרים נמוכים יותר מופיעים ראשונים) +`advanced` (אופציונלי): דגל בוליאני המציין אם זהו פרמטר מתקדם (ברירת מחדל: false). כאשר מוגדר כ-true, הממשק המשתמש עשוי להסתיר את הפרמטר הזה כברירת מחדל או למקם אותו בסעיף "מתקדם" +`controlled-by` (אופציונלי): שם של פרמטר אחר השולט בערך של הפרמטר הזה במצב פשוט. כאשר מצוין, פרמטר זה יורש את הערך שלו מהפרמטר השולט, אלא אם כן הוא מוגדר במפורש אחרת + +גישה זו מאפשרת: +הגדרות סוג פרמטרים שניתן לעשות בהן שימוש חוזר במספר תבניות זרימה +ניהול ובדיקת תוקף מרכזיים של סוגי פרמטרים +תיאורים וסדר הצגה ספציפיים לזרימה של פרמטרים +חוויית ממשק משתמש משופרת עם טפסי פרמטרים תיאוריים +בדיקת תוקף עקבית של פרמטרים בכל הזרימות +הוספה קלה של סוגי פרמטרים סטנדרטיים חדשים +ממשק משתמש מפושט עם הפרדה בין מצב בסיסי/מתקדם +ירושת ערכי פרמטרים עבור הגדרות קשורות + +#### בקשת הפעלת זרימה + +ממשק ה-API להפעלת זרימה מקבל פרמטרים באמצעות שמות הפרמטרים של הזרימה: + +```json +{ + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "llm-model": "claude-3", + "llm-temperature": 0.5, + "chunk-size": 1024 + } +} +``` + +הערה: בדוגמה זו, `llm-rag-model` אינו מסופק באופן מפורש, אך הוא יירש את הערך "claude-3" מ-`llm-model` בשל הקשר `controlled-by` שלו. באופן דומה, `chunk-overlap` יכול לרשת ערך מחושב המבוסס על `chunk-size`. + +המערכת תבצע את הפעולות הבאות: +1. חילוץ מטא-נתונים של פרמטרים מהגדרת תבנית זרימה +2. מיפוי שמות פרמטרים של זרימה להגדרות הסוג שלהם (לדוגמה, `llm-model` → סוג `llm-model`) +3. פתרון קשרים "שולט ב" (controlled-by) (לדוגמה, `llm-rag-model` יורש מ-`llm-model`) +4. אימות ערכים שסופקו על ידי המשתמש וערכים שירשו בהתאם להגדרות הסוג של הפרמטרים +5. החלפת ערכים שפתורים לתוך פרמטרים של מעבדים במהלך יצירת זרימה + +### פרטי יישום + +#### תהליך פתרון פרמטרים + +כאשר זרימה מתחילה, המערכת מבצעת את שלבי פתרון הפרמטרים הבאים: + +1. **טעינת תבנית זרימה**: טעינת הגדרת תבנית זרימה וחילוץ מטא-נתונים של פרמטרים +2. **חילוץ מטא-נתונים**: חילוץ `type`, `description`, `order`, `advanced` ו-`controlled-by` עבור כל פרמטר המוגדר בתבנית הזרימה בסעיף `parameters` +3. **חיפוש הגדרת סוג**: עבור כל פרמטר בתבנית הזרימה: + אחזור הגדרת הסוג של הפרמטר ממחסן הסכימה/התצורה באמצעות השדה `type` + הגדרות הסוג מאוחסנות עם הסוג "parameter-type" במערכת התצורה + כל הגדרת סוג מכילה את הסכימה של הפרמטר, ערך ברירת מחדל וכללי אימות +4. **פתרון ערך ברירת מחדל**: + עבור כל פרמטר המוגדר בתבנית הזרימה: + בדיקה האם המשתמש סיפק ערך עבור פרמטר זה + אם לא סופק ערך על ידי המשתמש, השתמש בערך `default` מהגדרת סוג הפרמטר + יצירת מפת פרמטרים שלמה המכילה הן ערכים שסופקו על ידי המשתמש והן ערכי ברירת מחדל +5. **פתרון ירושה של פרמטרים** (קשרים "שולט ב"): + עבור פרמטרים עם שדה `controlled-by`, בדוק האם סופק ערך באופן מפורש + אם לא סופק ערך מפורש, יורשים את הערך מהפרמטר השולט + אם גם לפרמטר השולט אין ערך, משתמשים בברירת המחדל מהגדרת הסוג + אימות שאין תלות מעגלית בקשרי `controlled-by` +6. **אימות**: אימות קבוצת הפרמטרים השלמה (ערכים שסופקו על ידי המשתמש, ברירות מחדל וערכים שירשו) בהתאם להגדרות הסוג +7. **אחסון**: אחסון קבוצת הפרמטרים השלמה שפתורה עם מופע הזרימה לצורך ביקורת +8. **החלפת תבניות**: החלפת מקומות שמורות של פרמטרים בפרמטרים של מעבדים עם ערכים שפתורים +9. **יצירת מעבדים**: יצירת מעבדים עם פרמטרים שהוחלפו + +**הערות חשובות ליישום:** +שירות הזרימה חייב למזג פרמטרים שסופקו על ידי המשתמש עם ברירות מחדל מהגדרות סוג הפרמטרים +קבוצת הפרמטרים השלמה (כולל ברירות המחדל המיושמות) חייבת להיות מאוחסנת עם הזרימה לצורך מעקב +פתרון פרמטרים מתרחש בזמן התחלת הזרימה, ולא בזמן יצירת המעבד +פרמטרים חסרים שנדרשים ללא ברירות מחדל חייבים לגרום לכישלון התחלת הזרימה עם הודעת שגיאה ברורה + +#### ירושת פרמטרים עם "שולט ב" + +השדה `controlled-by` מאפשר ירושת ערכי פרמטרים, שימושי במיוחד לפשט ממשקי משתמש תוך שמירה על גמישות: + +**תרחיש לדוגמה**: +פרמטר `llm-model` שולט במודל LLM הראשי +פרמטר `llm-rag-model` מכיל `"controlled-by": "llm-model"` +במצב פשוט, הגדרת `llm-model` ל-"gpt-4" מגדירה אוטומטית גם את `llm-rag-model` ל-"gpt-4" +במצב מתקדם, משתמשים יכולים לדרוס את `llm-rag-model` עם ערך שונה + +**כללי פתרון**: +1. אם לפרמטר יש ערך שסופק באופן מפורש, השתמש בערך זה +2. אם אין ערך מפורש ו-`controlled-by` מוגדר, השתמש בערך של הפרמטר השולט +3. אם לפרמטר השולט אין ערך, חזור לברירת המחדל מהגדרת הסוג +4. תלות מעגלית בקשרי `controlled-by` גורמת לשגיאת אימות + +**התנהגות ממשק משתמש**: +במצב בסיסי/פשוט: פרמטרים עם `controlled-by` עשויים להיות מוסתרים או מוצגים כקריאה בלבד עם ערך שירש +במצב מתקדם: מוצגים כל הפרמטרים וניתן להגדיר אותם באופן אינדיבידואלי +כאשר פרמטר שולט משתנה, פרמטרים תלויים מתעדכנים אוטומטית אלא אם כן הם נדחפים באופן מפורש + +#### אינטגרציה עם Pulsar + +1. **פעולת התחלת זרימה** + פעולת התחלת הזרימה של Pulsar צריכה לקבל שדה `parameters` המכיל מפה של ערכי פרמטרים + הסכימה של בקשת התחלת הזרימה של Pulsar חייבת להיות מעודכנת כדי לכלול את השדה האופציונלי `parameters` + דוגמת בקשה: + ```json + { + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +2. **פעולת Get-Flow** + הסכימה של Pulsar עבור תגובת ה-get-flow חייבת להיות מעודכנת כדי לכלול את השדה `parameters` + זה מאפשר ללקוחות לשלוף את ערכי הפרמטרים ששימשו כאשר ה-flow הופעל + דוגמה לתגובה: + ```json + { + "flow_id": "customer-A-flow", + "flow_class": "document-analysis", + "status": "running", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +#### יישום שירות זרימה + +שירות תצורת הזרימה (`trustgraph-flow/trustgraph/config/service/flow.py`) דורש את השיפורים הבאים: + +1. **פונקציית פתרון פרמטרים** + ```python + async def resolve_parameters(self, flow_class, user_params): + """ + Resolve parameters by merging user-provided values with defaults. + + Args: + flow_class: The flow blueprint definition dict + user_params: User-provided parameters dict + + Returns: + Complete parameter dict with user values and defaults merged + """ + ``` + + פונקציה זו צריכה: + לחלץ מטא-נתונים של פרמטרים מתוך סעיף `parameters` של תוכנית העבודה (blueprint). + עבור כל פרמטר, לשלוף את הגדרת הסוג שלו ממאגר התצורה. + להחיל ערכי ברירת מחדל עבור כל פרמטרים שאינם מסופקים על ידי המשתמש. + לטפל ביחסי ירושה `controlled-by`. + להחזיר את קבוצת הפרמטרים השלמה. + +2. **שיטה `handle_start_flow` שעברה שינוי** + לקרוא ל-`resolve_parameters` לאחר טעינת תוכנית העבודה. + להשתמש בקבוצת הפרמטרים המפורטת והפתורה עבור החלפת תבניות. + לשמור את קבוצת הפרמטרים השלמה (ולא רק את אלה שסופקו על ידי המשתמש) יחד עם תוכנית העבודה. + לוודא שכל הפרמטרים הנדרשים מכילים ערכים. + +3. **שליפת סוגי פרמטרים** + הגדרות סוגי פרמטרים מאוחסנות בתצורה עם הסוג "parameter-type". + כל הגדרת סוג מכילה סכימה, ערך ברירת מחדל וכללי אימות. + לשמור סוגי פרמטרים בשימוש נפוץ במטמון כדי להפחית את מספר הפניות לתצורה. + +#### שילוב עם מערכת התצורה + +3. **אחסון אובייקטי זרימה** + כאשר אובייקט זרימה מתווסף למערכת התצורה על ידי רכיב הזרימה בניהול התצורה, אובייקט הזרימה חייב לכלול את ערכי הפרמטרים הפתורים. + מנהל התצורה צריך לאחסן גם את הפרמטרים שסופקו על ידי המשתמש וגם את הערכים הפתורים (עם יישום ברירת המחדל). + אובייקטי זרימה במערכת התצורה צריכים לכלול: + `parameters`: ערכי הפרמטרים הפתורים הסופיים המשמשים עבור הזרימה. + +#### שילוב עם ממשק שורת הפקודה (CLI) + +4. **פקודות CLI של הספריה** + פקודות CLI המתחילות זרימות צריכות לתמוך בפרמטרים: + לקבל ערכי פרמטרים באמצעות דגלי שורת הפקודה או קבצי תצורה. + לאמת פרמטרים מול הגדרות תוכנית העבודה לפני שליחה. + לתמוך בקלט של קובץ פרמטרים (JSON/YAML) עבור קבוצות פרמטרים מורכבות. + + פקודות CLI המציגות זרימות צריכות להציג מידע על פרמטרים: + להציג את ערכי הפרמטרים ששימשו בעת התחלת הזרימה. + להציג את הפרמטרים הזמינים עבור תוכנית עבודה של זרימה. + להציג סכימות אימות של פרמטרים וערכי ברירת מחדל. + +#### שילוב עם מחלקת בסיס של מעבד (Processor) + +5. **תמיכה ב-ParameterSpec** + מחלקות בסיס של מעבדים צריכות לתמוך בהחלפת פרמטרים באמצעות מנגנון ה-ParametersSpec הקיים. + המחלקה ParametersSpec (הנמצאת באותו מודול כמו ConsumerSpec ו-ProducerSpec) צריכה להיות משופרת במידת הצורך כדי לתמוך בהחלפת תבניות של פרמטרים. + מעבדים צריכים להיות מסוגלים להשתמש ב-ParametersSpec כדי להגדיר את הפרמטרים שלהם עם ערכי פרמטרים שפתורים בזמן הפעלת הזרימה. + יישום ה-ParametersSpec צריך: + לקבל תצורות פרמטרים המכילות מקומות שמורות של פרמטרים (לדוגמה, `{model}`, `{temperature}`). + לתמוך בהחלפת פרמטרים בזמן ריצה בעת יצירת המעבד. + לוודא שערכים שהוחלפו תואמים לסוגים ולמגבלות הצפויים. + לספק טיפול בשגיאות עבור הפניות חסרות או לא חוקיות של פרמטרים. + +#### כללי החלפה + +פרמטרים משתמשים בפורמט `{parameter-name}` בפרמטרים של מעבד. +שמות הפרמטרים בפרמטרים תואמים למפתחות בסעיף `parameters` של תוכנית העבודה. +החלפה מתרחשת יחד עם החלפת `{id}` ו-`{class}`. +הפניות לא חוקיות של פרמטרים גורמות לשגיאות בזמן ההפעלה. +אימות סוג מתרחש בהתבסס על הגדרת הפרמטר המאוחסנת במרכז. +**חשוב**: כל ערכי הפרמטרים מאוחסנים ומועברים כרצף תווים. + מספרים מומרים לרצף תווים (לדוגמה, `0.7` הופך ל-`"0.7"`). + ערכים בוליאניים מומרים לרצף תווים קטן (לדוגמה, `true` הופך ל-`"true"`). + זה נדרש על ידי הסכימה של Pulsar, אשר מגדירה `parameters = Map(String())`. + +דוגמה לפענוח: +``` +Flow parameter mapping: "model": "llm-model" +Processor parameter: "model": "{model}" +User provides: "model": "gemma3:8b" +Final parameter: "model": "gemma3:8b" + +Example with type conversion: +Parameter type default: 0.7 (number) +Stored in flow: "0.7" (string) +Substituted in processor: "0.7" (string) +``` + +## אסטרטגיית בדיקות + +בדיקות יחידה לאימות סכימת הפרמטרים +בדיקות אינטגרציה להחלפת פרמטרים בפרמטרים של המעבד +בדיקות מקצה לקצה להפעלת זרימות עם ערכי פרמטרים שונים +בדיקות ממשק משתמש ליצירה ואימות של טופס פרמטרים +בדיקות ביצועים עבור זרימות עם פרמטרים רבים +מקרים קצה: פרמטרים חסרים, סוגים לא חוקיים, הפניות לפרמטרים לא מוגדרים + +## תוכנית מעבר + +1. המערכת צריכה להמשיך לתמוך בתבניות זרימה ללא פרמטרים + מוצהרים. +2. המערכת צריכה להמשיך לתמוך בזרימות ללא פרמטרים מוגדרים: + זה עובד עבור זרימות ללא פרמטרים, וזרימות עם פרמטרים + (שיש להם ערכי ברירת מחדל). + +## שאלות פתוחות + +ש: האם הפרמטרים צריכים לתמוך באובייקטים מקוננים מורכבים או להישאר בסוגים פשוטים? +ת: ערכי הפרמטרים יועברו כרצף תווים, סביר להניח שנרצה + להישאר ברצפים תווים. + +ש: האם מותר להשתמש במחזיקי פרמטרים בשמות תורים או רק ב + פרמטרים? +ת: רק בפרמטרים כדי למנוע הזרקות ותופעות לוואי. + +ש: כיצד לטפל בקונפליקטים בין שמות פרמטרים למשתנים של המערכת כמו + `id` ו- `class`? +ת: לא חוקי לציין id ו-class בעת הפעלת זרימה. + +ש: האם אנו תומכים בפרמטרים מחושבים (נגזרים מפרמטרים אחרים)? +ת: רק החלפת רצפי תווים כדי למנוע הזרקות ותופעות לוואי. + +## הפניות + +מפרט JSON Schema: https://json-schema.org/ +מפרט הגדרת תבנית זרימה: docs/tech-specs/flow-class-definition.md diff --git a/docs/tech-specs/flow-configurable-parameters.hi.md b/docs/tech-specs/flow-configurable-parameters.hi.md new file mode 100644 index 00000000..300687d7 --- /dev/null +++ b/docs/tech-specs/flow-configurable-parameters.hi.md @@ -0,0 +1,485 @@ +# फ्लो ब्लूप्रिंट कॉन्फ़िगर करने योग्य पैरामीटर तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ में कॉन्फ़िगर करने योग्य पैरामीटर के कार्यान्वयन का वर्णन करता है। पैरामीटर उपयोगकर्ताओं को फ्लो लॉन्च समय पर प्रोसेसर पैरामीटर को अनुकूलित करने की अनुमति देते हैं, जो फ्लो ब्लूप्रिंट परिभाषा में पैरामीटर प्लेसहोल्डर को बदलने वाले मान प्रदान करते हैं। + +पैरामीटर प्रोसेसर पैरामीटर में टेम्पलेट वेरिएबल प्रतिस्थापन के माध्यम से काम करते हैं, जो `{id}` और `{class}` वेरिएबल्स के काम करने के तरीके के समान है, लेकिन उपयोगकर्ता-प्रदत्त मानों के साथ। + +एकीकरण चार प्राथमिक उपयोग मामलों का समर्थन करता है: + +1. **मॉडल चयन**: उपयोगकर्ताओं को प्रोसेसर के लिए विभिन्न एलएलएम मॉडल (जैसे, `gemma3:8b`, `gpt-4`, `claude-3`) चुनने की अनुमति देना +2. **संसाधन कॉन्फ़िगरेशन**: प्रोसेसर पैरामीटर जैसे कि चंक आकार, बैच आकार और समवर्ती सीमा को समायोजित करना +3. **व्यवहार ट्यूनिंग**: तापमान, अधिकतम-टोकन या पुनर्प्राप्ति थ्रेसहोल्ड जैसे पैरामीटर के माध्यम से प्रोसेसर व्यवहार को संशोधित करना +4. **पर्यावरण-विशिष्ट पैरामीटर**: प्रत्येक परिनियोजन के लिए समापन बिंदु, एपीआई कुंजियाँ या क्षेत्र-विशिष्ट यूआरएल को कॉन्फ़िगर करना + +## लक्ष्य + +**डायनामिक प्रोसेसर कॉन्फ़िगरेशन**: पैरामीटर प्रतिस्थापन के माध्यम से प्रोसेसर पैरामीटर के रनटाइम कॉन्फ़िगरेशन को सक्षम करना +**पैरामीटर सत्यापन**: फ्लो लॉन्च समय पर पैरामीटर के लिए टाइप चेकिंग और सत्यापन प्रदान करना +**डिफ़ॉल्ट मान**: समझदार डिफ़ॉल्ट का समर्थन करना जबकि उन्नत उपयोगकर्ताओं के लिए ओवरराइड की अनुमति देना +**टेम्पलेट प्रतिस्थापन**: प्रोसेसर पैरामीटर में पैरामीटर प्लेसहोल्डर को निर्बाध रूप से बदलना +**यूआई एकीकरण**: एपीआई और यूआई इंटरफेस दोनों के माध्यम से पैरामीटर इनपुट को सक्षम करना +**टाइप सुरक्षा**: यह सुनिश्चित करना कि पैरामीटर प्रकार अपेक्षित प्रोसेसर पैरामीटर प्रकारों से मेल खाते हैं +**प्रलेखन**: फ्लो ब्लूप्रिंट परिभाषाओं के भीतर स्व-प्रलेखित पैरामीटर स्कीमा +**पिछड़ा संगतता**: मौजूदा फ्लो ब्लूप्रिंट के साथ संगतता बनाए रखना जो पैरामीटर का उपयोग नहीं करते हैं + +## पृष्ठभूमि + +ट्रस्टग्राफ में फ्लो ब्लूप्रिंट अब प्रोसेसर पैरामीटर का समर्थन करते हैं जिनमें या तो निश्चित मान या पैरामीटर प्लेसहोल्डर हो सकते हैं। यह रनटाइम अनुकूलन के लिए एक अवसर बनाता है। + +वर्तमान प्रोसेसर पैरामीटर का समर्थन: +निश्चित मान: `"model": "gemma3:12b"` +पैरामीटर प्लेसहोल्डर: `"model": "gemma3:{model-size}"` + +यह विनिर्देश परिभाषित करता है कि पैरामीटर कैसे हैं: +फ्लो ब्लूप्रिंट परिभाषाओं में घोषित +जब फ्लो लॉन्च होते हैं तो मान्य +प्रोसेसर पैरामीटर में प्रतिस्थापित +एपीआई और यूआई के माध्यम से उजागर + +पैरामीटराइज़्ड प्रोसेसर पैरामीटर का लाभ उठाकर, ट्रस्टग्राफ: +भिन्नताओं के लिए पैरामीटर का उपयोग करके फ्लो ब्लूप्रिंट डुप्लिकेसन को कम करता है +उपयोगकर्ताओं को परिभाषाओं को संशोधित किए बिना प्रोसेसर व्यवहार को ट्यून करने की अनुमति देता है +पैरामीटर मानों के माध्यम से पर्यावरण-विशिष्ट कॉन्फ़िगरेशन का समर्थन करता है +पैरामीटर स्कीमा सत्यापन के माध्यम से टाइप सुरक्षा बनाए रखता है + +## तकनीकी डिजाइन + +### वास्तुकला + +कॉन्फ़िगर करने योग्य पैरामीटर सिस्टम के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: + +1. **पैरामीटर स्कीमा परिभाषा** + फ्लो ब्लूप्रिंट मेटाडेटा के भीतर JSON स्कीमा-आधारित पैरामीटर परिभाषाएँ + स्ट्रिंग, नंबर, बूलियन, एनम और ऑब्जेक्ट प्रकार सहित प्रकार परिभाषाएँ + न्यूनतम/अधिकतम मान, पैटर्न और आवश्यक फ़ील्ड सहित सत्यापन नियम + + मॉड्यूल: trustgraph-flow/trustgraph/flow/definition.py + +2. **पैरामीटर रिज़ॉल्यूशन इंजन** + स्कीमा के विरुद्ध रनटाइम पैरामीटर सत्यापन + निर्दिष्ट पैरामीटर के लिए डिफ़ॉल्ट मानों का अनुप्रयोग + फ्लो निष्पादन संदर्भ में पैरामीटर इंजेक्शन + आवश्यकतानुसार प्रकार का रूपांतरण और रूपांतरण + + मॉड्यूल: trustgraph-flow/trustgraph/flow/parameter_resolver.py + +3. **पैरामीटर स्टोर एकीकरण** + स्कीमा/कॉन्फ़िग स्टोर से पैरामीटर परिभाषाओं की पुनर्प्राप्ति + अक्सर उपयोग की जाने वाली पैरामीटर परिभाषाओं का कैशिंग + केंद्रीय रूप से संग्रहीत स्कीमा के विरुद्ध सत्यापन + + मॉड्यूल: trustgraph-flow/trustgraph/flow/parameter_store.py + +4. **फ्लो लॉन्चर एक्सटेंशन** + फ्लो लॉन्च के दौरान पैरामीटर मानों को स्वीकार करने के लिए एपीआई एक्सटेंशन + पैरामीटर मैपिंग रिज़ॉल्यूशन (फ्लो नाम से परिभाषा नाम) + अमान्य पैरामीटर संयोजनों के लिए त्रुटि हैंडलिंग + + मॉड्यूल: trustgraph-flow/trustgraph/flow/launcher.py + +5. **यूआई पैरामीटर फॉर्म** + फ्लो पैरामीटर मेटाडेटा से गतिशील रूप से उत्पन्न फॉर्म + `order` फ़ील्ड का उपयोग करके क्रमबद्ध पैरामीटर प्रदर्शन + `description` फ़ील्ड का उपयोग करके वर्णनात्मक पैरामीटर लेबल + पैरामीटर प्रकार परिभाषाओं के विरुद्ध इनपुट सत्यापन + पैरामीटर प्रीसेट और टेम्पलेट + + मॉड्यूल: trustgraph-ui/components/flow-parameters/ + +### डेटा मॉडल + +#### पैरामीटर परिभाषाएँ (स्कीमा/कॉन्फ़िग में संग्रहीत) + +पैरामीटर परिभाषाएँ स्कीमा और कॉन्फ़िग सिस्टम में "पैरामीटर-प्रकार" प्रकार के साथ केंद्रीय रूप से संग्रहीत की जाती हैं: + +```json +{ + "llm-model": { + "type": "string", + "description": "LLM model to use", + "default": "gpt-4", + "enum": [ + { + "id": "gpt-4", + "description": "OpenAI GPT-4 (Most Capable)" + }, + { + "id": "gpt-3.5-turbo", + "description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)" + }, + { + "id": "claude-3", + "description": "Anthropic Claude 3 (Thoughtful & Safe)" + }, + { + "id": "gemma3:8b", + "description": "Google Gemma 3 8B (Open Source)" + } + ], + "required": false + }, + "model-size": { + "type": "string", + "description": "Model size variant", + "default": "8b", + "enum": ["2b", "8b", "12b", "70b"], + "required": false + }, + "temperature": { + "type": "number", + "description": "Model temperature for generation", + "default": 0.7, + "minimum": 0.0, + "maximum": 2.0, + "required": false + }, + "chunk-size": { + "type": "integer", + "description": "Document chunk size", + "default": 512, + "minimum": 128, + "maximum": 2048, + "required": false + } +} +``` + +#### पैरामीटर संदर्भों के साथ फ्लो ब्लूप्रिंट + +फ्लो ब्लूप्रिंट, प्रकार संदर्भों, विवरणों और क्रम के साथ पैरामीटर मेटाडेटा को परिभाषित करते हैं: + +```json +{ + "flow_class": "document-analysis", + "parameters": { + "llm-model": { + "type": "llm-model", + "description": "Primary LLM model for text completion", + "order": 1 + }, + "llm-rag-model": { + "type": "llm-model", + "description": "LLM model for RAG operations", + "order": 2, + "advanced": true, + "controlled-by": "llm-model" + }, + "llm-temperature": { + "type": "temperature", + "description": "Generation temperature for creativity control", + "order": 3, + "advanced": true + }, + "chunk-size": { + "type": "chunk-size", + "description": "Document chunk size for processing", + "order": 4, + "advanced": true + }, + "chunk-overlap": { + "type": "integer", + "description": "Overlap between document chunks", + "order": 5, + "advanced": true, + "controlled-by": "chunk-size" + } + }, + "class": { + "text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "parameters": { + "model": "{llm-model}", + "temperature": "{llm-temperature}" + } + }, + "rag-completion:{class}": { + "request": "non-persistent://tg/request/rag-completion:{class}", + "response": "non-persistent://tg/response/rag-completion:{class}", + "parameters": { + "model": "{llm-rag-model}", + "temperature": "{llm-temperature}" + } + } + }, + "flow": { + "chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "parameters": { + "chunk_size": "{chunk-size}", + "chunk_overlap": "{chunk-overlap}" + } + } + } +} +``` + +`parameters` अनुभाग प्रवाह-विशिष्ट पैरामीटर नामों (कुंजियों) को पैरामीटर मेटाडेटा ऑब्जेक्ट्स से मैप करता है जिनमें शामिल हैं: +`type`: केंद्रीय रूप से परिभाषित पैरामीटर परिभाषा का संदर्भ (उदाहरण के लिए, "llm-model") +`description`: यूआई प्रदर्शन के लिए मानव-पठनीय विवरण +`order`: पैरामीटर फ़ॉर्म के लिए प्रदर्शन क्रम (छोटे नंबर पहले दिखाई देते हैं) +`advanced` (वैकल्पिक): एक बूलियन ध्वज जो इंगित करता है कि क्या यह एक उन्नत पैरामीटर है (डिफ़ॉल्ट: false)। जब इसे true पर सेट किया जाता है, तो यूआई डिफ़ॉल्ट रूप से इस पैरामीटर को छिपा सकता है या इसे "उन्नत" अनुभाग में रख सकता है +`controlled-by` (वैकल्पिक): एक अन्य पैरामीटर का नाम जो सरल मोड में इस पैरामीटर के मान को नियंत्रित करता है। जब निर्दिष्ट किया जाता है, तो यह पैरामीटर अपने मान को नियंत्रित पैरामीटर से प्राप्त करता है जब तक कि स्पष्ट रूप से ओवरराइड न किया जाए + +यह दृष्टिकोण अनुमति देता है: +कई प्रवाह ब्लूप्रिंट में पुन: प्रयोज्य पैरामीटर प्रकार परिभाषाएँ +केंद्रीकृत पैरामीटर प्रकार प्रबंधन और सत्यापन +प्रवाह-विशिष्ट पैरामीटर विवरण और क्रम +वर्णनात्मक पैरामीटर फ़ॉर्म के साथ बेहतर यूआई अनुभव +प्रवाह में सुसंगत पैरामीटर सत्यापन +नए मानक पैरामीटर प्रकारों को आसानी से जोड़ना +बुनियादी/उन्नत मोड अलगाव के साथ सरलीकृत यूआई +संबंधित सेटिंग्स के लिए पैरामीटर मान विरासत + +#### प्रवाह लॉन्च अनुरोध + +प्रवाह लॉन्च एपीआई प्रवाह के पैरामीटर नामों का उपयोग करके पैरामीटर स्वीकार करता है: + +```json +{ + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "llm-model": "claude-3", + "llm-temperature": 0.5, + "chunk-size": 1024 + } +} +``` + +ध्यान दें: इस उदाहरण में, `llm-rag-model` स्पष्ट रूप से प्रदान नहीं किया गया है, लेकिन यह `llm-model` से "claude-3" मान को अपने `controlled-by` संबंध के कारण प्राप्त करेगा। इसी तरह, `chunk-overlap` `chunk-size` के आधार पर गणना किए गए मान को प्राप्त कर सकता है। + +सिस्टम निम्नलिखित कार्य करेगा: +1. फ्लो ब्लूप्रिंट परिभाषा से पैरामीटर मेटाडेटा निकालें +2. फ्लो पैरामीटर नामों को उनके प्रकार परिभाषाओं (जैसे, `llm-model` → `llm-model` प्रकार) में मैप करें +3. नियंत्रित-द्वारा संबंधों को हल करें (जैसे, `llm-rag-model` `llm-model` से प्राप्त होता है) +4. पैरामीटर प्रकार परिभाषाओं के विरुद्ध उपयोगकर्ता द्वारा प्रदान किए गए और प्राप्त मूल्यों को मान्य करें +5. फ्लो इंस्टेंशिएशन के दौरान हल किए गए मूल्यों को प्रोसेसर पैरामीटर में प्रतिस्थापित करें + +### कार्यान्वयन विवरण + +#### पैरामीटर रिज़ॉल्यूशन प्रक्रिया + +जब कोई फ्लो शुरू होता है, तो सिस्टम निम्नलिखित पैरामीटर रिज़ॉल्यूशन चरण करता है: + +1. **फ्लो ब्लूप्रिंट लोडिंग**: फ्लो ब्लूप्रिंट परिभाषा लोड करें और पैरामीटर मेटाडेटा निकालें +2. **मेटाडेटा निष्कर्षण**: फ्लो ब्लूप्रिंट के `parameters` अनुभाग में परिभाषित प्रत्येक पैरामीटर के लिए `type`, `description`, `order`, `advanced`, और `controlled-by` निकालें +3. **टाइप परिभाषा लुकअप**: फ्लो ब्लूप्रिंट में प्रत्येक पैरामीटर के लिए: + स्कीमा/कॉन्फ़िग स्टोर से `type` फ़ील्ड का उपयोग करके पैरामीटर प्रकार परिभाषा प्राप्त करें + प्रकार परिभाषाएँ कॉन्फ़िग सिस्टम में "parameter-type" प्रकार के साथ संग्रहीत की जाती हैं + प्रत्येक प्रकार की परिभाषा में पैरामीटर का स्कीमा, डिफ़ॉल्ट मान और सत्यापन नियम होते हैं +4. **डिफ़ॉल्ट मान रिज़ॉल्यूशन**: + फ्लो ब्लूप्रिंट में परिभाषित प्रत्येक पैरामीटर के लिए: + जांचें कि क्या उपयोगकर्ता ने इस पैरामीटर के लिए कोई मान प्रदान किया है + यदि कोई उपयोगकर्ता मान प्रदान नहीं किया गया है, तो पैरामीटर प्रकार परिभाषा से `default` मान का उपयोग करें + उपयोगकर्ता द्वारा प्रदान किए गए और डिफ़ॉल्ट मानों दोनों को शामिल करते हुए एक पूर्ण पैरामीटर मानचित्र बनाएं +5. **पैरामीटर इनहेरिटेंस रिज़ॉल्यूशन** (नियंत्रित-द्वारा संबंध): + `controlled-by` फ़ील्ड वाले पैरामीटर के लिए, जांचें कि क्या कोई मान स्पष्ट रूप से प्रदान किया गया था + यदि कोई स्पष्ट मान प्रदान नहीं किया गया है, तो नियंत्रित पैरामीटर से मान प्राप्त करें + यदि नियंत्रित पैरामीटर में भी कोई मान नहीं है, तो प्रकार परिभाषा से डिफ़ॉल्ट का उपयोग करें + जांचें कि `controlled-by` संबंधों में कोई गोलाकार निर्भरता मौजूद नहीं है +6. **सत्यापन**: प्रकार परिभाषाओं के विरुद्ध पूर्ण पैरामीटर सेट (उपयोगकर्ता द्वारा प्रदान किए गए, डिफ़ॉल्ट और प्राप्त) को मान्य करें +7. **भंडारण**: ऑडिटिंग के लिए फ्लो इंस्टेंस के साथ पूर्ण हल किए गए पैरामीटर सेट को संग्रहीत करें +8. **टेम्प्लेट प्रतिस्थापन**: प्रोसेसर पैरामीटर में पैरामीटर प्लेसहोल्डर को हल किए गए मानों से बदलें +9. **प्रोसेसर इंस्टेंशिएशन**: प्रतिस्थापित पैरामीटर के साथ प्रोसेसर बनाएं + +**महत्वपूर्ण कार्यान्वयन नोट्स:** +फ्लो सर्विस को पैरामीटर प्रकार परिभाषाओं से डिफ़ॉल्ट के साथ उपयोगकर्ता द्वारा प्रदान किए गए पैरामीटर को मर्ज करना होगा +पूर्ण पैरामीटर सेट (लागू डिफ़ॉल्ट सहित) को पता लगाने के लिए फ्लो के साथ संग्रहीत किया जाना चाहिए +पैरामीटर रिज़ॉल्यूशन फ्लो शुरू होने के समय होता है, प्रोसेसर इंस्टेंशिएशन के समय नहीं +डिफ़ॉल्ट के बिना आवश्यक पैरामीटर गायब होने से फ्लो शुरू होने में विफलता होनी चाहिए, साथ ही एक स्पष्ट त्रुटि संदेश भी + +#### नियंत्रित-द्वारा के साथ पैरामीटर इनहेरिटेंस + +`controlled-by` फ़ील्ड पैरामीटर मान इनहेरिटेंस को सक्षम करता है, जो उपयोगकर्ता इंटरफ़ेस को सरल बनाने के साथ-साथ लचीलापन बनाए रखने के लिए विशेष रूप से उपयोगी है: + +**उदाहरण परिदृश्य**: +`llm-model` पैरामीटर प्राथमिक LLM मॉडल को नियंत्रित करता है +`llm-rag-model` पैरामीटर में `"controlled-by": "llm-model"` होता है +सरल मोड में, `llm-model` को "gpt-4" पर सेट करने से स्वचालित रूप से `llm-rag-model` भी "gpt-4" पर सेट हो जाता है +उन्नत मोड में, उपयोगकर्ता `llm-rag-model` को एक अलग मान के साथ ओवरराइड कर सकते हैं + +**रिज़ॉल्यूशन नियम**: +1. यदि किसी पैरामीटर में एक स्पष्ट रूप से प्रदान किया गया मान है, तो उस मान का उपयोग करें +2. यदि कोई स्पष्ट मान नहीं है और `controlled-by` सेट है, तो नियंत्रित पैरामीटर का मान उपयोग करें +3. यदि नियंत्रित पैरामीटर में कोई मान नहीं है, तो प्रकार परिभाषा से डिफ़ॉल्ट पर वापस जाएं +4. `controlled-by` संबंधों में गोलाकार निर्भरताएँ एक सत्यापन त्रुटि का कारण बनती हैं + +**UI व्यवहार**: +बुनियादी/सरल मोड में: `controlled-by` वाले पैरामीटर छिपे हो सकते हैं या प्राप्त मान के साथ केवल-पढ़ने योग्य के रूप में दिखाए जा सकते हैं +उन्नत मोड में: सभी पैरामीटर दिखाए जाते हैं और उन्हें व्यक्तिगत रूप से कॉन्फ़िगर किया जा सकता है +जब एक नियंत्रित पैरामीटर बदलता है, तो निर्भर पैरामीटर स्वचालित रूप से अपडेट हो जाते हैं जब तक कि उन्हें स्पष्ट रूप से ओवरराइड न किया जाए + +#### पल्सर एकीकरण + +1. **स्टार्ट-फ्लो ऑपरेशन** + पल्सर स्टार्ट-फ्लो ऑपरेशन को एक `parameters` फ़ील्ड स्वीकार करना होगा जिसमें पैरामीटर मानों का एक मानचित्र होता है + स्टार्ट-फ्लो अनुरोध के लिए पल्सर स्कीमा को वैकल्पिक `parameters` फ़ील्ड को शामिल करने के लिए अपडेट किया जाना चाहिए + उदाहरण अनुरोध: + ```json + { + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +2. **गेट-फ्लो ऑपरेशन** + गेट-फ्लो प्रतिक्रिया के लिए पल्सर स्कीमा को `parameters` फ़ील्ड को शामिल करने के लिए अपडेट किया जाना चाहिए। + यह ग्राहकों को उन पैरामीटर मानों को पुनः प्राप्त करने की अनुमति देता है जिनका उपयोग फ्लो शुरू करते समय किया गया था। + उदाहरण प्रतिक्रिया: + ```json + { + "flow_id": "customer-A-flow", + "flow_class": "document-analysis", + "status": "running", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +#### फ्लो सर्विस कार्यान्वयन + +फ्लो कॉन्फ़िगरेशन सर्विस (`trustgraph-flow/trustgraph/config/service/flow.py`) को निम्नलिखित सुधारों की आवश्यकता है: + +1. **पैरामीटर रिज़ॉल्यूशन फ़ंक्शन** + ```python + async def resolve_parameters(self, flow_class, user_params): + """ + Resolve parameters by merging user-provided values with defaults. + + Args: + flow_class: The flow blueprint definition dict + user_params: User-provided parameters dict + + Returns: + Complete parameter dict with user values and defaults merged + """ + ``` + + यह फ़ंक्शन को इस प्रकार होना चाहिए: + फ़्लो ब्लूप्रिंट के `parameters` अनुभाग से पैरामीटर मेटाडेटा निकालें + प्रत्येक पैरामीटर के लिए, कॉन्फ़िगरेशन स्टोर से इसके प्रकार की परिभाषा प्राप्त करें + उन सभी पैरामीटर के लिए डिफ़ॉल्ट मान लागू करें जो उपयोगकर्ता द्वारा प्रदान नहीं किए गए हैं + `controlled-by` विरासत संबंधों को संभालें + संपूर्ण पैरामीटर सेट लौटाएं + +2. **संशोधित `handle_start_flow` विधि** + फ़्लो ब्लूप्रिंट लोड करने के बाद `resolve_parameters` को कॉल करें + टेम्पलेट प्रतिस्थापन के लिए पूरे हल किए गए पैरामीटर सेट का उपयोग करें + पूरे पैरामीटर सेट को (केवल उपयोगकर्ता द्वारा प्रदान किए गए नहीं) फ़्लो के साथ संग्रहीत करें + सत्यापित करें कि सभी आवश्यक पैरामीटर में मान हैं + +3. **पैरामीटर प्रकार प्राप्त करना** + पैरामीटर प्रकार की परिभाषाएँ "parameter-type" प्रकार के साथ कॉन्फ़िगर में संग्रहीत हैं + प्रत्येक प्रकार की परिभाषा में स्कीमा, डिफ़ॉल्ट मान और सत्यापन नियम होते हैं + अक्सर उपयोग किए जाने वाले पैरामीटर प्रकारों को कैश करें ताकि कॉन्फ़िगर लुकअप कम हो सकें + +#### कॉन्फ़िगर सिस्टम एकीकरण + +3. **फ़्लो ऑब्जेक्ट स्टोरेज** + जब कोई फ़्लो घटक कॉन्फ़िगर प्रबंधक में कॉन्फ़िगर सिस्टम में जोड़ा जाता है, तो फ़्लो ऑब्जेक्ट में हल किए गए पैरामीटर मान शामिल होने चाहिए + कॉन्फ़िगर प्रबंधक को मूल उपयोगकर्ता-प्रदान किए गए पैरामीटर और हल किए गए मान दोनों (डिफ़ॉल्ट लागू किए गए) को संग्रहीत करने की आवश्यकता होती है + कॉन्फ़िगर सिस्टम में फ़्लो ऑब्जेक्ट में शामिल होना चाहिए: + `parameters`: फ़्लो के लिए उपयोग किए गए अंतिम हल किए गए पैरामीटर मान + +#### CLI एकीकरण + +4. **लाइब्रेरी CLI कमांड** + फ़्लो शुरू करने वाले CLI कमांड में पैरामीटर समर्थन होना चाहिए: + कमांड-लाइन फ़्लैग या कॉन्फ़िगरेशन फ़ाइलों के माध्यम से पैरामीटर मान स्वीकार करें + सबमिशन से पहले फ़्लो ब्लूप्रिंट परिभाषाओं के विरुद्ध पैरामीटर को मान्य करें + जटिल पैरामीटर सेट के लिए पैरामीटर फ़ाइल इनपुट (JSON/YAML) का समर्थन करें + + फ़्लो दिखाने वाले CLI कमांड में पैरामीटर जानकारी प्रदर्शित करने की आवश्यकता होती है: + उस समय प्रदर्शित करें जब फ़्लो शुरू किया गया था, तो उपयोग किए गए पैरामीटर मान + एक फ़्लो ब्लूप्रिंट के लिए उपलब्ध पैरामीटर प्रदर्शित करें + पैरामीटर सत्यापन स्कीमा और डिफ़ॉल्ट प्रदर्शित करें + +#### प्रोसेसर बेस क्लास एकीकरण + +5. **पैरामीटरस्पेक समर्थन** + प्रोसेसर बेस क्लास को मौजूदा पैरामीटर्सस्पेक तंत्र के माध्यम से पैरामीटर प्रतिस्थापन का समर्थन करने की आवश्यकता है + पैरामीटर्सस्पेक क्लास (उपभोक्तास्पेक और प्रोड्यूसरस्पेक के समान मॉड्यूल में स्थित) को पैरामीटर टेम्पलेट प्रतिस्थापन का समर्थन करने के लिए आवश्यक होने पर बढ़ाया जाना चाहिए + प्रोसेसर को अपने पैरामीटर को कॉन्फ़िगर करने के लिए पैरामीटर्सस्पेक को कॉल करने में सक्षम होना चाहिए, जिसमें फ़्लो लॉन्च समय पर हल किए गए पैरामीटर मान शामिल हैं + पैरामीटर्सस्पेक कार्यान्वयन को: + पैरामीटर कॉन्फ़िगरेशन स्वीकार करें जिसमें पैरामीटर प्लेसहोल्डर शामिल हैं (जैसे, `{model}`, `{temperature}`) + प्रोसेसर के इंस्टेंट होने पर रनटाइम पैरामीटर प्रतिस्थापन का समर्थन करें + सत्यापित करें कि प्रतिस्थापित मान अपेक्षित प्रकार और बाधाओं से मेल खाते हैं + गुम या अमान्य पैरामीटर संदर्भों के लिए त्रुटि हैंडलिंग प्रदान करें + +#### प्रतिस्थापन नियम + +प्रोसेसर पैरामीटर में पैरामीटर `{parameter-name}` प्रारूप का उपयोग करते हैं +पैरामीटर में पैरामीटर नाम फ़्लो के `parameters` अनुभाग में कुंजियों से मेल खाते हैं +प्रतिस्थापन `{id}` और `{class}` प्रतिस्थापन के साथ-साथ होता है +अमान्य पैरामीटर संदर्भ लॉन्च-टाइम त्रुटियों का परिणाम देते हैं +केंद्रीय रूप से संग्रहीत पैरामीटर परिभाषा के आधार पर प्रकार सत्यापन होता है +**महत्वपूर्ण**: सभी पैरामीटर मान स्ट्रिंग के रूप में संग्रहीत और प्रसारित किए जाते हैं + संख्याओं को स्ट्रिंग में परिवर्तित किया जाता है (जैसे, `0.7` `"0.7"` बन जाता है) + बूलियन को लोअरकेस स्ट्रिंग में परिवर्तित किया जाता है (जैसे, `true` `"true"` बन जाता है) + यह पल्सर स्कीमा की आवश्यकता है जो `parameters = Map(String())` को परिभाषित करती है + +उदाहरण समाधान: +``` +Flow parameter mapping: "model": "llm-model" +Processor parameter: "model": "{model}" +User provides: "model": "gemma3:8b" +Final parameter: "model": "gemma3:8b" + +Example with type conversion: +Parameter type default: 0.7 (number) +Stored in flow: "0.7" (string) +Substituted in processor: "0.7" (string) +``` + +## परीक्षण रणनीति + +पैरामीटर स्कीमा सत्यापन के लिए यूनिट परीक्षण +प्रोसेसर पैरामीटर में पैरामीटर प्रतिस्थापन के लिए एकीकरण परीक्षण +विभिन्न पैरामीटर मानों के साथ फ्लो लॉन्च करने के लिए एंड-टू-एंड परीक्षण +पैरामीटर फॉर्म पीढ़ी और सत्यापन के लिए यूआई परीक्षण +कई पैरामीटर वाले फ्लो के लिए प्रदर्शन परीक्षण +किनारे के मामले: गुम पैरामीटर, अमान्य प्रकार, अपरिभाषित पैरामीटर संदर्भ + +## माइग्रेशन योजना + +1. सिस्टम को बिना पैरामीटर वाले फ्लो ब्लूप्रिंट का समर्थन करना जारी रखना चाहिए। + घोषित। +2. सिस्टम को बिना पैरामीटर वाले फ्लो का समर्थन करना जारी रखना चाहिए: + यह बिना पैरामीटर वाले फ्लो और पैरामीटर वाले फ्लो दोनों के लिए काम करता है (उनके पास डिफ़ॉल्ट होते हैं)। + +## खुले प्रश्न + + +प्रश्न: क्या पैरामीटर जटिल, नेस्टेड ऑब्जेक्ट्स का समर्थन करेंगे, या केवल साधारण प्रकारों तक सीमित रहेंगे? +उत्तर: पैरामीटर मान स्ट्रिंग के रूप में एन्कोड किए जाएंगे, इसलिए शायद हमें + केवल स्ट्रिंग तक ही सीमित रहना चाहिए। + +प्रश्न: क्या पैरामीटर प्लेसहोल्डर को कतार के नामों में अनुमति दी जानी चाहिए, या केवल + पैरामीटर में? +उत्तर: केवल पैरामीटर में, ताकि अजीब इंजेक्शन और असामान्य स्थितियों से बचा जा सके। + +प्रश्न: पैरामीटर नामों और सिस्टम वेरिएबल्स के बीच टकराव को कैसे संभालें, जैसे कि + `id` और `class`? +अ: यह सही नहीं है कि फ्लो शुरू करते समय आईडी और क्लास दोनों निर्दिष्ट किए जाएं। + +प्रश्न: क्या हमें गणना किए गए पैरामीटर (अन्य पैरामीटर से प्राप्त) का समर्थन करना चाहिए? +उत्तर: केवल स्ट्रिंग प्रतिस्थापन का उपयोग करके अजीब इंजेक्शन और विशेष मामलों को हटाना। + +## संदर्भ + +JSON स्कीमा विनिर्देश: https://json-schema.org/ +फ्लो ब्लूप्रिंट परिभाषा विनिर्देश: docs/tech-specs/flow-class-definition.md diff --git a/docs/tech-specs/flow-configurable-parameters.pt.md b/docs/tech-specs/flow-configurable-parameters.pt.md new file mode 100644 index 00000000..ab2ea41a --- /dev/null +++ b/docs/tech-specs/flow-configurable-parameters.pt.md @@ -0,0 +1,485 @@ +# Especificação Técnica de Parâmetros Configuráveis para Flow Blueprint + +## Visão Geral + +Esta especificação descreve a implementação de parâmetros configuráveis para flow blueprints no TrustGraph. Os parâmetros permitem que os usuários personalizem os parâmetros do processador no momento da execução do fluxo, fornecendo valores que substituem os espaços reservados de parâmetros na definição do flow blueprint. + +Os parâmetros funcionam por meio da substituição de variáveis de modelo nos parâmetros do processador, de forma semelhante a como as variáveis `{id}` e `{class}` funcionam, mas com valores fornecidos pelo usuário. + +A integração suporta quatro casos de uso principais: + +1. **Seleção de Modelo**: Permitindo que os usuários escolham diferentes modelos LLM (por exemplo, `gemma3:8b`, `gpt-4`, `claude-3`) para processadores. +2. **Configuração de Recursos**: Ajustando parâmetros do processador, como tamanhos de lote, tamanhos de lote e limites de concorrência. +3. **Ajuste de Comportamento**: Modificando o comportamento do processador por meio de parâmetros como temperatura, max-tokens ou limites de recuperação. +4. **Parâmetros Específicos do Ambiente**: Configurando endpoints, chaves de API ou URLs específicas da região para cada implantação. + +## Objetivos + +**Configuração Dinâmica do Processador**: Permitir a configuração em tempo de execução dos parâmetros do processador por meio da substituição de parâmetros. +**Validação de Parâmetros**: Fornecer verificação de tipo e validação para parâmetros no momento da execução do fluxo. +**Valores Padrão**: Suportar valores padrão sensatos, permitindo a substituição para usuários avançados. +**Substituição de Modelo**: Substituir perfeitamente os espaços reservados de parâmetros nos parâmetros do processador. +**Integração com a Interface do Usuário**: Permitir a entrada de parâmetros por meio de interfaces de API e de interface do usuário. +**Segurança de Tipo**: Garantir que os tipos de parâmetros correspondam aos tipos de parâmetros do processador esperados. +**Documentação**: Esquemas de parâmetros autoexplicativos dentro das definições do flow blueprint. +**Compatibilidade com Versões Anteriores**: Manter a compatibilidade com flow blueprints existentes que não usam parâmetros. + +## Contexto + +Flow blueprints no TrustGraph agora suportam parâmetros de processador que podem conter valores fixos ou espaços reservados de parâmetros. Isso cria uma oportunidade para personalização em tempo de execução. + +Os parâmetros de processador atuais suportam: +Valores fixos: `"model": "gemma3:12b"` +Espaços reservados de parâmetros: `"model": "gemma3:{model-size}"` + +Esta especificação define como os parâmetros são: +Declarados em definições de flow blueprint. +Validados quando os fluxos são iniciados. +Substituídos em parâmetros do processador. +Expostos por meio de APIs e da interface do usuário. + +Ao aproveitar os parâmetros de processador parametrizados, o TrustGraph pode: +Reduzir a duplicação de flow blueprints, usando parâmetros para variações. +Permitir que os usuários ajustem o comportamento do processador sem modificar as definições. +Suportar configurações específicas do ambiente por meio de valores de parâmetro. +Manter a segurança de tipo por meio da validação do esquema de parâmetro. + +## Design Técnico + +### Arquitetura + +O sistema de parâmetros configuráveis requer os seguintes componentes técnicos: + +1. **Definição de Esquema de Parâmetro** + Definições de parâmetros baseadas em JSON Schema dentro dos metadados do flow blueprint. + Definições de tipo, incluindo string, número, booleano, enum e tipos de objeto. + Regras de validação, incluindo valores mínimo/máximo, padrões e campos obrigatórios. + + Módulo: trustgraph-flow/trustgraph/flow/definition.py + +2. **Motor de Resolução de Parâmetros** + Validação de parâmetros em tempo de execução contra o esquema. + Aplicação de valores padrão para parâmetros não especificados. + Injeção de parâmetros no contexto de execução do fluxo. + Coerção e conversão de tipo, conforme necessário. + + Módulo: trustgraph-flow/trustgraph/flow/parameter_resolver.py + +3. **Integração com o Armazenamento de Parâmetros** + Recuperação de definições de parâmetros do armazenamento de esquema/configuração. + Cache de definições de parâmetros frequentemente usadas. + Validação contra esquemas armazenados centralmente. + + Módulo: trustgraph-flow/trustgraph/flow/parameter_store.py + +4. **Extensões do Lançador de Fluxo** + Extensões de API para aceitar valores de parâmetro durante o lançamento do fluxo. + Resolução de mapeamento de parâmetros (nomes de fluxo para nomes de definição). + Tratamento de erros para combinações de parâmetros inválidas. + + Módulo: trustgraph-flow/trustgraph/flow/launcher.py + +5. **Formulários de Parâmetro da Interface do Usuário** + Geração dinâmica de formulários a partir de metadados de parâmetros do fluxo. + Exibição ordenada de parâmetros usando o campo `order`. + Rótulos de parâmetros descritivos usando o campo `description`. + Validação de entrada contra as definições de tipo de parâmetro. + Predefinições e modelos de parâmetros. + + Módulo: trustgraph-ui/components/flow-parameters/ + +### Modelos de Dados + +#### Definições de Parâmetro (Armazenadas no Esquema/Configuração) + +As definições de parâmetros são armazenadas centralmente no sistema de esquema e configuração com o tipo "parameter-type": + +```json +{ + "llm-model": { + "type": "string", + "description": "LLM model to use", + "default": "gpt-4", + "enum": [ + { + "id": "gpt-4", + "description": "OpenAI GPT-4 (Most Capable)" + }, + { + "id": "gpt-3.5-turbo", + "description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)" + }, + { + "id": "claude-3", + "description": "Anthropic Claude 3 (Thoughtful & Safe)" + }, + { + "id": "gemma3:8b", + "description": "Google Gemma 3 8B (Open Source)" + } + ], + "required": false + }, + "model-size": { + "type": "string", + "description": "Model size variant", + "default": "8b", + "enum": ["2b", "8b", "12b", "70b"], + "required": false + }, + "temperature": { + "type": "number", + "description": "Model temperature for generation", + "default": 0.7, + "minimum": 0.0, + "maximum": 2.0, + "required": false + }, + "chunk-size": { + "type": "integer", + "description": "Document chunk size", + "default": 512, + "minimum": 128, + "maximum": 2048, + "required": false + } +} +``` + +#### Diagrama de fluxo com referências de parâmetros + +Os diagramas de fluxo definem metadados de parâmetros com referências de tipo, descrições e ordem: + +```json +{ + "flow_class": "document-analysis", + "parameters": { + "llm-model": { + "type": "llm-model", + "description": "Primary LLM model for text completion", + "order": 1 + }, + "llm-rag-model": { + "type": "llm-model", + "description": "LLM model for RAG operations", + "order": 2, + "advanced": true, + "controlled-by": "llm-model" + }, + "llm-temperature": { + "type": "temperature", + "description": "Generation temperature for creativity control", + "order": 3, + "advanced": true + }, + "chunk-size": { + "type": "chunk-size", + "description": "Document chunk size for processing", + "order": 4, + "advanced": true + }, + "chunk-overlap": { + "type": "integer", + "description": "Overlap between document chunks", + "order": 5, + "advanced": true, + "controlled-by": "chunk-size" + } + }, + "class": { + "text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "parameters": { + "model": "{llm-model}", + "temperature": "{llm-temperature}" + } + }, + "rag-completion:{class}": { + "request": "non-persistent://tg/request/rag-completion:{class}", + "response": "non-persistent://tg/response/rag-completion:{class}", + "parameters": { + "model": "{llm-rag-model}", + "temperature": "{llm-temperature}" + } + } + }, + "flow": { + "chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "parameters": { + "chunk_size": "{chunk-size}", + "chunk_overlap": "{chunk-overlap}" + } + } + } +} +``` + +A seção `parameters` mapeia nomes de parâmetros específicos do fluxo (chaves) para objetos de metadados de parâmetros que contêm: +`type`: Referência à definição de parâmetro definida centralmente (por exemplo, "llm-model") +`description`: Descrição legível por humanos para exibição na interface do usuário +`order`: Ordem de exibição para formulários de parâmetros (números menores aparecem primeiro) +`advanced` (opcional): Sinalizador booleano que indica se este é um parâmetro avançado (padrão: falso). Quando definido como verdadeiro, a interface do usuário pode ocultar este parâmetro por padrão ou colocá-lo em uma seção "Avançado" +`controlled-by` (opcional): Nome de outro parâmetro que controla o valor deste parâmetro quando no modo simples. Quando especificado, este parâmetro herda seu valor do parâmetro de controle, a menos que seja explicitamente substituído + +Esta abordagem permite: +Definições de tipos de parâmetros reutilizáveis em vários modelos de fluxo +Gerenciamento e validação centralizados de tipos de parâmetros +Descrições e ordenação de parâmetros específicos do fluxo +Experiência de interface do usuário aprimorada com formulários de parâmetros descritivos +Validação consistente de parâmetros em todos os fluxos +Adição fácil de novos tipos de parâmetros padrão +Interface do usuário simplificada com separação de modo básico/avançado +Herança de valores de parâmetros para configurações relacionadas + +#### Solicitação de Inicialização do Fluxo + +A API de inicialização do fluxo aceita parâmetros usando os nomes de parâmetros do fluxo: + +```json +{ + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "llm-model": "claude-3", + "llm-temperature": 0.5, + "chunk-size": 1024 + } +} +``` + +Nota: Neste exemplo, `llm-rag-model` não é fornecido explicitamente, mas herdará o valor "claude-3" de `llm-model` devido à sua relação `controlled-by`. Da mesma forma, `chunk-overlap` pode herdar um valor calculado com base em `chunk-size`. + +O sistema irá: +1. Extrair metadados de parâmetros da definição do blueprint do fluxo +2. Mapear os nomes dos parâmetros do fluxo para suas definições de tipo (por exemplo, `llm-model` → `llm-model` tipo) +3. Resolver as relações "controlado por" (por exemplo, `llm-rag-model` herda de `llm-model`) +4. Validar os valores fornecidos pelo usuário e os valores herdados em relação às definições de tipo dos parâmetros +5. Substituir os valores resolvidos nos parâmetros do processador durante a instanciação do fluxo + +### Detalhes da Implementação + +#### Processo de Resolução de Parâmetros + +Quando um fluxo é iniciado, o sistema executa as seguintes etapas de resolução de parâmetros: + +1. **Carregamento do Blueprint do Fluxo**: Carregar a definição do blueprint do fluxo e extrair os metadados dos parâmetros +2. **Extração de Metadados**: Extrair `type`, `description`, `order`, `advanced` e `controlled-by` para cada parâmetro definido na seção `parameters` do blueprint do fluxo +3. **Consulta da Definição de Tipo**: Para cada parâmetro no blueprint do fluxo: + Recuperar a definição de tipo do parâmetro do armazenamento de esquema/configuração usando o campo `type` + As definições de tipo são armazenadas com o tipo "parameter-type" no sistema de configuração + Cada definição de tipo contém o esquema do parâmetro, o valor padrão e as regras de validação +4. **Resolução do Valor Padrão**: + Para cada parâmetro definido no blueprint do fluxo: + Verificar se o usuário forneceu um valor para este parâmetro + Se nenhum valor do usuário for fornecido, usar o valor `default` da definição de tipo do parâmetro + Criar um mapa de parâmetros completo contendo tanto os valores fornecidos pelo usuário quanto os valores padrão +5. **Resolução de Herança de Parâmetros** (relações "controlado por"): + Para parâmetros com o campo `controlled-by`, verificar se um valor foi fornecido explicitamente + Se nenhum valor explícito for fornecido, herdar o valor do parâmetro de controle + Se o parâmetro de controle também não tiver valor, usar o padrão da definição de tipo + Validar que não existam dependências circulares nas relações `controlled-by` +6. **Validação**: Validar o conjunto completo de parâmetros (fornecidos pelo usuário, padrões e herdados) em relação às definições de tipo +7. **Armazenamento**: Armazenar o conjunto completo de parâmetros resolvidos com a instância do fluxo para auditoria +8. **Substituição de Modelos**: Substituir os espaços reservados de parâmetros nos parâmetros do processador com os valores resolvidos +9. **Instanciação do Processador**: Criar processadores com os parâmetros substituídos + +**Notas Importantes de Implementação:** +O serviço de fluxo DEVE mesclar os parâmetros fornecidos pelo usuário com os padrões das definições de tipo de parâmetro +O conjunto completo de parâmetros (incluindo os padrões aplicados) DEVE ser armazenado com o fluxo para rastreabilidade +A resolução de parâmetros ocorre no início do fluxo, não no momento da instanciação do processador +Parâmetros obrigatórios sem padrões DEVE causar a falha no início do fluxo com uma mensagem de erro clara + +#### Herança de Parâmetros com "controlado-por" + +O campo `controlled-by` permite a herança de valores de parâmetros, o que é particularmente útil para simplificar as interfaces do usuário, mantendo a flexibilidade: + +**Cenário de Exemplo**: +O parâmetro `llm-model` controla o modelo LLM primário +O parâmetro `llm-rag-model` tem `"controlled-by": "llm-model"` +No modo simples, definir `llm-model` para "gpt-4" define automaticamente `llm-rag-model` para "gpt-4" também +No modo avançado, os usuários podem substituir `llm-rag-model` com um valor diferente + +**Regras de Resolução**: +1. Se um parâmetro tiver um valor fornecido explicitamente, use esse valor +2. Se não houver valor explícito e `controlled-by` estiver definido, use o valor do parâmetro de controle +3. Se o parâmetro de controle não tiver valor, use o padrão da definição de tipo +4. Dependências circulares nas relações `controlled-by` resultam em um erro de validação + +**Comportamento da IU**: +No modo básico/simples: Parâmetros com `controlled-by` podem ser ocultos ou exibidos como somente leitura com valor herdado +No modo avançado: Todos os parâmetros são exibidos e podem ser configurados individualmente +Quando um parâmetro de controle é alterado, os parâmetros dependentes são atualizados automaticamente, a menos que sejam explicitamente substituídos + +#### Integração com Pulsar + +1. **Operação Start-Flow** + A operação start-flow do Pulsar precisa aceitar um campo `parameters` contendo um mapa de valores de parâmetros + O esquema do Pulsar para a solicitação start-flow deve ser atualizado para incluir o campo opcional `parameters` + Exemplo de solicitação: + ```json + { + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +2. **Operação Get-Flow** + O esquema Pulsar para a resposta do get-flow deve ser atualizado para incluir o campo `parameters` + Isso permite que os clientes recuperem os valores dos parâmetros que foram usados quando o fluxo foi iniciado. + Exemplo de resposta: + ```json + { + "flow_id": "customer-A-flow", + "flow_class": "document-analysis", + "status": "running", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +#### Implementação do Serviço de Fluxo + +O serviço de configuração de fluxo (`trustgraph-flow/trustgraph/config/service/flow.py`) requer as seguintes melhorias: + +1. **Função de Resolução de Parâmetros** + ```python + async def resolve_parameters(self, flow_class, user_params): + """ + Resolve parameters by merging user-provided values with defaults. + + Args: + flow_class: The flow blueprint definition dict + user_params: User-provided parameters dict + + Returns: + Complete parameter dict with user values and defaults merged + """ + ``` + + Esta função deve: + Extrair metadados de parâmetros da seção `parameters` do blueprint do fluxo + Para cada parâmetro, buscar a definição de tipo no armazenamento de configuração + Aplicar valores padrão para quaisquer parâmetros não fornecidos pelo usuário + Lidar com relacionamentos de herança `controlled-by` + Retornar o conjunto completo de parâmetros + +2. **Método `handle_start_flow` Modificado** + Chamar `resolve_parameters` após carregar o blueprint do fluxo + Usar o conjunto completo de parâmetros resolvidos para substituição de modelo + Armazenar o conjunto completo de parâmetros (não apenas os fornecidos pelo usuário) com o fluxo + Validar que todos os parâmetros obrigatórios tenham valores + +3. **Busca de Tipo de Parâmetro** + As definições de tipo de parâmetro são armazenadas na configuração com o tipo "parameter-type" + Cada definição de tipo contém esquema, valor padrão e regras de validação + Armazenar em cache os tipos de parâmetro frequentemente usados para reduzir as consultas à configuração + +#### Integração com o Sistema de Configuração + +3. **Armazenamento de Objetos de Fluxo** + Quando um fluxo é adicionado ao sistema de configuração pelo componente de fluxo no gerenciador de configuração, o objeto de fluxo deve incluir os valores de parâmetros resolvidos + O gerenciador de configuração precisa armazenar tanto os parâmetros originais fornecidos pelo usuário quanto os valores resolvidos (com os padrões aplicados) + Os objetos de fluxo no sistema de configuração devem incluir: + `parameters`: Os valores finais de parâmetros resolvidos usados para o fluxo + +#### Integração com a CLI + +4. **Comandos da CLI da Biblioteca** + Os comandos da CLI que iniciam fluxos precisam de suporte a parâmetros: + Aceitar valores de parâmetros por meio de flags de linha de comando ou arquivos de configuração + Validar parâmetros em relação às definições do blueprint do fluxo antes da submissão + Suportar a entrada de arquivos de parâmetros (JSON/YAML) para conjuntos de parâmetros complexos + + Os comandos da CLI que mostram fluxos precisam exibir informações de parâmetros: + Mostrar os valores de parâmetros usados quando o fluxo foi iniciado + Exibir os parâmetros disponíveis para um blueprint de fluxo + Mostrar os esquemas e padrões de validação de parâmetros + +#### Integração com a Classe Base do Processador + +5. **Suporte a ParameterSpec** + As classes base do processador precisam suportar a substituição de parâmetros por meio do mecanismo existente ParametersSpec + A classe ParametersSpec (localizada no mesmo módulo que ConsumerSpec e ProducerSpec) deve ser aprimorada, se necessário, para suportar a substituição de modelos de parâmetros + Os processadores devem ser capazes de invocar ParametersSpec para configurar seus parâmetros com valores de parâmetros resolvidos no momento da inicialização do fluxo + A implementação de ParametersSpec precisa: + Aceitar configurações de parâmetros que contenham espaços reservados de parâmetros (por exemplo, `{model}`, `{temperature}`) + Suportar a substituição de parâmetros em tempo de execução quando o processador é instanciado + Validar que os valores substituídos correspondam aos tipos e restrições esperados + Fornecer tratamento de erros para referências de parâmetros ausentes ou inválidos + +#### Regras de Substituição + +Os parâmetros usam o formato `{parameter-name}` nos parâmetros do processador +Os nomes dos parâmetros nos parâmetros correspondem às chaves na seção `parameters` do fluxo +A substituição ocorre juntamente com a substituição de `{id}` e `{class}` +Referências de parâmetros inválidas resultam em erros no momento da inicialização +A validação de tipo ocorre com base na definição de parâmetro armazenada centralmente +**IMPORTANTE**: Todos os valores de parâmetros são armazenados e transmitidos como strings + Os números são convertidos em strings (por exemplo, `0.7` se torna `"0.7"`) + Os booleanos são convertidos em strings em letras minúsculas (por exemplo, `true` se torna `"true"`) + Isso é necessário pelo esquema do Pulsar que define `parameters = Map(String())` + +Exemplo de resolução: +``` +Flow parameter mapping: "model": "llm-model" +Processor parameter: "model": "{model}" +User provides: "model": "gemma3:8b" +Final parameter: "model": "gemma3:8b" + +Example with type conversion: +Parameter type default: 0.7 (number) +Stored in flow: "0.7" (string) +Substituted in processor: "0.7" (string) +``` + +## Estratégia de Testes + +Testes unitários para validação do esquema de parâmetros +Testes de integração para substituição de parâmetros nos parâmetros do processador +Testes de ponta a ponta para iniciar fluxos com diferentes valores de parâmetros +Testes de interface do usuário para geração e validação de formulários de parâmetros +Testes de desempenho para fluxos com muitos parâmetros +Casos extremos: parâmetros ausentes, tipos inválidos, referências de parâmetros indefinidos + +## Plano de Migração + +1. O sistema deve continuar a suportar modelos de fluxo sem parâmetros + declarados. +2. O sistema deve continuar a suportar fluxos sem parâmetros especificados: + Isso funciona para fluxos sem parâmetros e para fluxos com parâmetros + (eles têm valores padrão). + +## Perguntas Abertas + +P: Os parâmetros devem suportar objetos aninhados complexos ou devem se limitar a tipos simples? +R: Os valores dos parâmetros serão codificados como strings, provavelmente queremos + restringir a strings. + +P: Os espaços reservados de parâmetros devem ser permitidos em nomes de filas ou apenas em + parâmetros? +R: Apenas em parâmetros para evitar injeções estranhas e casos extremos. + +P: Como lidar com conflitos entre nomes de parâmetros e variáveis do sistema, como + `id` e `class`? +R: Não é válido especificar "id" e "class" ao iniciar um fluxo. + +P: Devemos suportar parâmetros calculados (derivados de outros parâmetros)? +R: Apenas substituição de strings para evitar injeções estranhas e casos extremos. + +## Referências + +Especificação do Esquema JSON: https://json-schema.org/ +Especificação da Definição do Modelo de Fluxo: docs/tech-specs/flow-class-definition.md diff --git a/docs/tech-specs/flow-configurable-parameters.ru.md b/docs/tech-specs/flow-configurable-parameters.ru.md new file mode 100644 index 00000000..0c9dabae --- /dev/null +++ b/docs/tech-specs/flow-configurable-parameters.ru.md @@ -0,0 +1,485 @@ +# Техническая спецификация конфигурируемых параметров для шаблонов потоков + +## Обзор + +Эта спецификация описывает реализацию конфигурируемых параметров для шаблонов потоков в TrustGraph. Параметры позволяют пользователям настраивать параметры процессоров при запуске потока, предоставляя значения, которые заменяют заполнители параметров в определении шаблона потока. + +Параметры работают путем подстановки переменных в шаблонах в параметрах процессоров, аналогично тому, как работают переменные `{id}` и `{class}`, но со значениями, предоставленными пользователем. + +Интеграция поддерживает четыре основных сценария использования: + +1. **Выбор модели**: Предоставление пользователям возможности выбора различных моделей LLM (например, `gemma3:8b`, `gpt-4`, `claude-3`) для процессоров. +2. **Конфигурация ресурсов**: Настройка параметров процессоров, таких как размеры пакетов, размеры партий и лимиты параллельности. +3. **Настройка поведения**: Изменение поведения процессоров с помощью параметров, таких как температура, максимальное количество токенов или пороги извлечения. +4. **Параметры, специфичные для среды**: Настройка конечных точек, ключей API или URL-адресов, специфичных для региона, для каждого развертывания. + +## Цели + +**Динамическая конфигурация процессоров**: Обеспечение возможности динамической конфигурации параметров процессоров путем подстановки параметров. +**Проверка параметров**: Предоставление проверки типов и валидации параметров при запуске потока. +**Значения по умолчанию**: Поддержка разумных значений по умолчанию, позволяя при этом переопределять их для продвинутых пользователей. +**Подстановка шаблонов**: Бесшовная замена заполнителей параметров в параметрах процессоров. +**Интеграция с пользовательским интерфейсом**: Обеспечение ввода параметров как через API, так и через пользовательский интерфейс. +**Безопасность типов**: Обеспечение соответствия типов параметров ожидаемым типам параметров процессора. +**Документация**: Самодокументированные схемы параметров в определениях шаблонов потоков. +**Обратная совместимость**: Поддержка обратной совместимости с существующими шаблонами потоков, которые не используют параметры. + +## Предыстория + +В шаблонах потоков в TrustGraph теперь поддерживаются параметры процессоров, которые могут содержать либо фиксированные значения, либо заполнители параметров. Это создает возможность для динамической настройки. + +Текущие параметры процессоров поддерживают: +Фиксированные значения: `"model": "gemma3:12b"` +Заполнители параметров: `"model": "gemma3:{model-size}"` + +Эта спецификация определяет, как параметры: +Объявляются в определениях шаблонов потоков. +Проверяются при запуске потоков. +Подставляются в параметры процессоров. +Предоставляются через API и пользовательский интерфейс. + +Используя параметризованные параметры процессоров, TrustGraph может: +Уменьшить дублирование шаблонов потоков, используя параметры для вариаций. +Позволить пользователям настраивать поведение процессоров без изменения определений. +Поддерживать конфигурации, специфичные для среды, с помощью значений параметров. +Обеспечивать безопасность типов с помощью проверки схемы параметров. + +## Технический дизайн + +### Архитектура + +Система конфигурируемых параметров требует следующих технических компонентов: + +1. **Определение схемы параметров** + Определения параметров на основе JSON-схемы в метаданных шаблона потока. + Определения типов, включая типы string, number, boolean, enum и object. + Правила валидации, включая минимальные/максимальные значения, шаблоны и обязательные поля. + + Модуль: trustgraph-flow/trustgraph/flow/definition.py + +2. **Механизм разрешения параметров** + Проверка параметров на соответствие схеме во время выполнения. + Применение значений по умолчанию для не указанных параметров. + Внедрение параметров в контекст выполнения потока. + Преобразование типов и приведение типов при необходимости. + + Модуль: trustgraph-flow/trustgraph/flow/parameter_resolver.py + +3. **Интеграция с хранилищем параметров** + Получение определений параметров из хранилища схем/конфигураций. + Кэширование часто используемых определений параметров. + Проверка на соответствие централизованным схемам. + + Модуль: trustgraph-flow/trustgraph/flow/parameter_store.py + +4. **Расширения для запуска потоков** + Расширения API для приема значений параметров при запуске потока. + Разрешение отображения (имена потоков на имена определений). + Обработка ошибок для недействительных комбинаций параметров. + + Модуль: trustgraph-flow/trustgraph/flow/launcher.py + +5. **Формы параметров пользовательского интерфейса** + Динамическая генерация форм из метаданных параметров потока. + Отображение параметров в упорядоченном виде с использованием поля `order`. + Описательные метки параметров с использованием поля `description`. + Проверка ввода в соответствии с определениями типов параметров. + Предустановки и шаблоны параметров. + + Модуль: trustgraph-ui/components/flow-parameters/ + +### Модели данных + +#### Определения параметров (хранятся в схеме/конфигурации) + +Определения параметров хранятся централизованно в системе схем и конфигураций с типом "parameter-type": + +```json +{ + "llm-model": { + "type": "string", + "description": "LLM model to use", + "default": "gpt-4", + "enum": [ + { + "id": "gpt-4", + "description": "OpenAI GPT-4 (Most Capable)" + }, + { + "id": "gpt-3.5-turbo", + "description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)" + }, + { + "id": "claude-3", + "description": "Anthropic Claude 3 (Thoughtful & Safe)" + }, + { + "id": "gemma3:8b", + "description": "Google Gemma 3 8B (Open Source)" + } + ], + "required": false + }, + "model-size": { + "type": "string", + "description": "Model size variant", + "default": "8b", + "enum": ["2b", "8b", "12b", "70b"], + "required": false + }, + "temperature": { + "type": "number", + "description": "Model temperature for generation", + "default": 0.7, + "minimum": 0.0, + "maximum": 2.0, + "required": false + }, + "chunk-size": { + "type": "integer", + "description": "Document chunk size", + "default": 512, + "minimum": 128, + "maximum": 2048, + "required": false + } +} +``` + +#### Схема потока с ссылками на параметры + +Схемы потока определяют метаданные параметров со ссылками на типы, описаниями и порядком: + +```json +{ + "flow_class": "document-analysis", + "parameters": { + "llm-model": { + "type": "llm-model", + "description": "Primary LLM model for text completion", + "order": 1 + }, + "llm-rag-model": { + "type": "llm-model", + "description": "LLM model for RAG operations", + "order": 2, + "advanced": true, + "controlled-by": "llm-model" + }, + "llm-temperature": { + "type": "temperature", + "description": "Generation temperature for creativity control", + "order": 3, + "advanced": true + }, + "chunk-size": { + "type": "chunk-size", + "description": "Document chunk size for processing", + "order": 4, + "advanced": true + }, + "chunk-overlap": { + "type": "integer", + "description": "Overlap between document chunks", + "order": 5, + "advanced": true, + "controlled-by": "chunk-size" + } + }, + "class": { + "text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "parameters": { + "model": "{llm-model}", + "temperature": "{llm-temperature}" + } + }, + "rag-completion:{class}": { + "request": "non-persistent://tg/request/rag-completion:{class}", + "response": "non-persistent://tg/response/rag-completion:{class}", + "parameters": { + "model": "{llm-rag-model}", + "temperature": "{llm-temperature}" + } + } + }, + "flow": { + "chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "parameters": { + "chunk_size": "{chunk-size}", + "chunk_overlap": "{chunk-overlap}" + } + } + } +} +``` + +Раздел `parameters` сопоставляет имена параметров, специфичные для потока (ключи), с объектами метаданных параметров, содержащими: +`type`: Ссылка на централизованно определенное определение параметра (например, "llm-model") +`description`: Описание, понятное человеку, для отображения в пользовательском интерфейсе +`order`: Порядок отображения параметров в формах (меньшие числа отображаются первыми) +`advanced` (необязательно): Булевский флаг, указывающий, является ли этот параметр расширенным (по умолчанию: false). Если установлено значение true, пользовательский интерфейс может скрывать этот параметр по умолчанию или помещать его в раздел "Расширенные" +`controlled-by` (необязательно): Имя другого параметра, который управляет значением этого параметра в простом режиме. Если указано, этот параметр наследует свое значение от управляющего параметра, если явно не переопределен + +Этот подход позволяет: +Повторное использование определений типов параметров в нескольких шаблонах потоков +Централизованное управление и проверка типов параметров +Описания и порядок параметров, специфичные для потока +Улучшенный пользовательский интерфейс с описательными формами параметров +Последовательная проверка параметров во всех потоках +Легкое добавление новых стандартных типов параметров +Упрощенный пользовательский интерфейс с разделением на режимы "базовый/расширенный" +Наследование значений параметров для связанных настроек + +#### Запрос запуска потока + +API запуска потока принимает параметры, используя имена параметров, специфичные для потока: + +```json +{ + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "llm-model": "claude-3", + "llm-temperature": 0.5, + "chunk-size": 1024 + } +} +``` + +Примечание: В этом примере, `llm-rag-model` явно не указан, но он унаследует значение "claude-3" из `llm-model` из-за его `controlled-by` связи. Аналогично, `chunk-overlap` может унаследовать вычисленное значение на основе `chunk-size`. + +Система будет: +1. Извлекать метаданные параметров из определения схемы потока +2. Сопоставлять имена параметров потока с их определениями типов (например, `llm-model` → `llm-model` тип) +3. Разрешать отношения "контролируется" (например, `llm-rag-model` наследуется от `llm-model`) +4. Проверять предоставленные пользователем и унаследованные значения на соответствие определениям типов параметров +5. Подставлять разрешенные значения в параметры процессоров во время создания экземпляра потока + +### Детали реализации + +#### Процесс разрешения параметров + +При запуске потока система выполняет следующие шаги разрешения параметров: + +1. **Загрузка схемы потока**: Загрузить определение схемы потока и извлечь метаданные параметров +2. **Извлечение метаданных**: Извлечь `type`, `description`, `order`, `advanced` и `controlled-by` для каждого параметра, определенного в разделе `parameters` схемы потока +3. **Поиск определения типа**: Для каждого параметра в схеме потока: + Получить определение типа параметра из хранилища схем/конфигураций, используя поле `type` + Определения типов хранятся с типом "parameter-type" в системе конфигураций + Каждое определение типа содержит схему параметра, значение по умолчанию и правила проверки +4. **Разрешение значения по умолчанию**: + Для каждого параметра, определенного в схеме потока: + Проверить, предоставлено ли пользователем значение для этого параметра + Если пользовательское значение не предоставлено, использовать значение `default` из определения типа параметра + Создать полную карту параметров, содержащую как предоставленные пользователем, так и значения по умолчанию +5. **Разрешение наследования параметров** (отношения "контролируется"): + Для параметров с полем `controlled-by`, проверить, было ли предоставлено явное значение + Если явное значение не предоставлено, унаследовать значение от контролируемого параметра + Если контролируемый параметр также не имеет значения, использовать значение по умолчанию из определения типа + Проверить отсутствие циклических зависимостей в отношениях `controlled-by` +6. **Проверка**: Проверить полный набор параметров (предоставленные пользователем, значения по умолчанию и унаследованные) на соответствие определениям типов +7. **Хранение**: Сохранить полный разрешенный набор параметров с экземпляром потока для обеспечения возможности аудита +8. **Подстановка шаблонов**: Заменить заполнители параметров в параметрах процессоров разрешенными значениями +9. **Создание экземпляров процессоров**: Создать процессоры с подставленными параметрами + +**Важные замечания по реализации**: +Сервис потока ДОЛЖЕН объединять параметры, предоставленные пользователем, со значениями по умолчанию из определений типов параметров +Полный набор параметров (включая примененные значения по умолчанию) ДОЛЖЕН храниться с потоком для обеспечения отслеживаемости +Разрешение параметров происходит при запуске потока, а не при создании экземпляра процессора +Отсутствующие обязательные параметры без значений по умолчанию ДОЛЖНЫ приводить к сбою запуска потока с четким сообщением об ошибке + +#### Наследование параметров с помощью "контролируется" + +Поле `controlled-by` обеспечивает наследование значений параметров, что особенно полезно для упрощения пользовательских интерфейсов, сохраняя при этом гибкость: + +**Пример сценария**: +Параметр `llm-model` контролирует основную модель LLM +Параметр `llm-rag-model` имеет значение `"controlled-by": "llm-model"` +В простом режиме установка `llm-model` в "gpt-4" автоматически устанавливает `llm-rag-model` в "gpt-4" +В расширенном режиме пользователи могут переопределить `llm-rag-model` другим значением + +**Правила разрешения**: +1. Если параметр имеет явно предоставленное значение, используйте это значение +2. Если нет явного значения и `controlled-by` установлено, используйте значение контролируемого параметра +3. Если контролируемый параметр не имеет значения, используйте значение по умолчанию из определения типа +4. Циклические зависимости в отношениях `controlled-by` приводят к ошибке проверки + +**Поведение пользовательского интерфейса**: +В базовом/простом режиме: Параметры с `controlled-by` могут быть скрыты или показаны как доступные только для чтения со значением, полученным по наследству +В расширенном режиме: Все параметры отображаются и могут быть настроены индивидуально +При изменении контролируемого параметра зависимые параметры автоматически обновляются, если они не были явно переопределены + +#### Интеграция с Pulsar + +1. **Операция Start-Flow** + Операция start-flow в Pulsar должна принимать поле `parameters`, содержащее карту значений параметров + Схема запроса start-flow в Pulsar должна быть обновлена для включения необязательного поля `parameters` + Пример запроса: + ```json + { + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +2. **Операция Get-Flow** + Схему Pulsar для ответа get-flow необходимо обновить, чтобы включить поле `parameters`. + Это позволяет клиентам получать значения параметров, которые были использованы при запуске потока. + Пример ответа: + ```json + { + "flow_id": "customer-A-flow", + "flow_class": "document-analysis", + "status": "running", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +#### Реализация сервиса потоков + +Сервис конфигурации потоков (`trustgraph-flow/trustgraph/config/service/flow.py`) требует следующих улучшений: + +1. **Функция разрешения параметров** + ```python + async def resolve_parameters(self, flow_class, user_params): + """ + Resolve parameters by merging user-provided values with defaults. + + Args: + flow_class: The flow blueprint definition dict + user_params: User-provided parameters dict + + Returns: + Complete parameter dict with user values and defaults merged + """ + ``` + + Эта функция должна: + Извлекать метаданные параметров из раздела `parameters` схемы потока. + Для каждого параметра получать определение его типа из хранилища конфигурации. + Применять значения по умолчанию для любых параметров, которые не предоставлены пользователем. + Обрабатывать отношения наследования `controlled-by`. + Возвращать полный набор параметров. + +2. **Измененный метод `handle_start_flow`** + Вызывать `resolve_parameters` после загрузки схемы потока. + Использовать полный набор разрешенных параметров для подстановки в шаблоне. + Сохранять полный набор параметров (а не только предоставленные пользователем) вместе с потоком. + Проверять, что все необходимые параметры имеют значения. + +3. **Получение типа параметра** + Определения типов параметров хранятся в конфигурации с типом "parameter-type". + Каждое определение типа содержит схему, значение по умолчанию и правила проверки. + Кэшировать часто используемые типы параметров для уменьшения количества обращений к конфигурации. + +#### Интеграция с системой конфигурации + +3. **Хранение объектов потока** + Когда поток добавляется в систему конфигурации компонентом потока в менеджере конфигурации, объект потока должен включать разрешенные значения параметров. + Менеджер конфигурации должен хранить как исходные параметры, предоставленные пользователем, так и разрешенные значения (с применением значений по умолчанию). + Объекты потока в системе конфигурации должны включать: + `parameters`: Конечные разрешенные значения параметров, используемые для потока. + +#### Интеграция с CLI + +4. **Команды CLI для библиотеки** + Команды CLI, которые запускают потоки, должны поддерживать параметры: + Принимать значения параметров через флаги командной строки или файлы конфигурации. + Проверять параметры на соответствие определениям схемы потока перед отправкой. + Поддерживать ввод файлов параметров (JSON/YAML) для сложных наборов параметров. + + Команды CLI, которые отображают потоки, должны отображать информацию о параметрах: + Отображать значения параметров, использованные при запуске потока. + Отображать доступные параметры для схемы потока. + Отображать схемы проверки параметров и значения по умолчанию. + +#### Интеграция с базовым классом процессора + +5. **Поддержка ParameterSpec** + Базовые классы процессоров должны поддерживать подстановку параметров с помощью существующего механизма ParametersSpec. + Класс ParametersSpec (расположенный в том же модуле, что и ConsumerSpec и ProducerSpec) должен быть расширен, если это необходимо, для поддержки подстановки параметров в шаблонах. + Процессоры должны иметь возможность вызывать ParametersSpec для настройки своих параметров со значениями параметров, разрешенными во время запуска потока. + Реализация ParametersSpec должна: + Принимать конфигурации параметров, содержащие заполнители параметров (например, `{model}`, `{temperature}`). + Поддерживать подстановку параметров во время выполнения при создании экземпляра процессора. + Проверять, соответствуют ли подставленные значения ожидаемым типам и ограничениям. + Предоставлять обработку ошибок для отсутствующих или недействительных ссылок на параметры. + +#### Правила подстановки + +Параметры используют формат `{parameter-name}` в параметрах процессора. +Имена параметров в параметрах соответствуют ключам в разделе `parameters` схемы потока. +Подстановка происходит наряду с заменой `{id}` и `{class}`. +Недействительные ссылки на параметры приводят к ошибкам во время запуска. +Проверка типов происходит на основе централизованно хранящегося определения параметра. +**ВАЖНО**: Все значения параметров хранятся и передаются в виде строк. + Числа преобразуются в строки (например, `0.7` становится `"0.7"`). + Булевы значения преобразуются в строчные буквы (например, `true` становится `"true"`). + Это требуется схемой Pulsar, которая определяет `parameters = Map(String())`. + +Пример разрешения: +``` +Flow parameter mapping: "model": "llm-model" +Processor parameter: "model": "{model}" +User provides: "model": "gemma3:8b" +Final parameter: "model": "gemma3:8b" + +Example with type conversion: +Parameter type default: 0.7 (number) +Stored in flow: "0.7" (string) +Substituted in processor: "0.7" (string) +``` + +## Стратегия тестирования + +Юнит-тесты для проверки схемы параметров +Интеграционные тесты для проверки подстановки параметров в параметры процессора +Комплексные тесты для запуска потоков с разными значениями параметров +UI-тесты для генерации и проверки форм параметров +Тесты производительности для потоков со многими параметрами +Пограничные случаи: отсутствующие параметры, неверные типы, неопределенные ссылки на параметры + +## План миграции + +1. Система должна продолжать поддерживать шаблоны потоков без объявленных параметров. + 2. Система должна продолжать поддерживать потоки без указанных параметров: +Это работает для потоков без параметров и для потоков с параметрами (у которых есть значения по умолчанию). + + (имеют значения по умолчанию). + +## Открытые вопросы + +В: Должны ли параметры поддерживать сложные вложенные объекты или ограничиваться простыми типами? +О: Значения параметров будут закодированы в виде строки, поэтому, вероятно, нам стоит + ограничиваться строками. + +В: Должны ли быть разрешены заполнители параметров в именах очередей или только в + параметрах? +О: Только в параметрах, чтобы избежать странных инъекций и пограничных случаев. + +В: Как обрабатывать конфликты между именами параметров и системными переменными, такими как + `id` и `class`? +О: Недопустимо указывать id и class при запуске потока. + +В: Должны ли мы поддерживать вычисляемые параметры (выводимые из других параметров)? +О: Только простая подстановка строк, чтобы избежать странных инъекций и пограничных случаев. + +## Ссылки + +Спецификация JSON Schema: https://json-schema.org/ +Спецификация определения шаблона потока: docs/tech-specs/flow-class-definition.md diff --git a/docs/tech-specs/flow-configurable-parameters.sw.md b/docs/tech-specs/flow-configurable-parameters.sw.md new file mode 100644 index 00000000..e75e9842 --- /dev/null +++ b/docs/tech-specs/flow-configurable-parameters.sw.md @@ -0,0 +1,485 @@ +# Mfumo wa Uwekaji Njia (Flow Blueprint) - Vigezo Vinavyoweza Kubadilishwa - Maelezo ya Kiufundi + +## Maelezo + +Maelezo haya yanaeleza utekelezaji wa vigezo vinavyoweza kubadilishwa kwa mifumo ya uwekaji njia (flow blueprints) katika TrustGraph. Vigezo huruhusu watumiaji kubadilisha vigezo vya kichakato (processor) wakati wa kuanzisha mfumo wa uwekaji njia kwa kutoa maadili ambayo hubadilisha nafasi za vigezo katika ufafanuzi wa mfumo wa uwekaji njia. + +Vigezo hufanya kazi kupitia ubadilishaji wa vigezo vya kishabaha katika vigezo vya kichakato, sawa na jinsi vigezo vya `{id}` na `{class}` hufanya kazi, lakini kwa maadili ambayo hutolewa na mtumiaji. + +Uunganishaji huu unaunga mkono matumizi manne makuu: + +1. **Uchaguzi wa Mfumo**: Kuruhusu watumiaji kuchagua mifumo tofauti ya LLM (e.g., `gemma3:8b`, `gpt-4`, `claude-3`) kwa vichakato. +2. **Uwekaji Njia wa Rasilimali**: Kurekebisha vigezo vya kichakato kama vile saizi za sehemu, saizi za kundi, na mipaka ya utendaji. +3. **Urekebishaji wa Tabia**: Kubadilisha tabia ya kichakato kupitia vigezo kama vile halijoto, max-tokens, au viwango vya urejesho. +4. **Vigezo Maalum ya Mazingira**: Kusanidi sehemu za mwisho, funguo za API, au anwani za mtandao (URLs) maalum kwa eneo kwa kila uwekaji. + +## Lengo + +**Uwekaji Njia wa Kichakato Unaoweza Kubadilishwa**: Kuruhusu uwekaji njia wa vigezo vya kichakato wakati wa utendaji kupitia ubadilishaji wa vigezo. +**Uthibitisho wa Vigezo**: Kutoa ukaguzi wa aina na uthibitisho wa vigezo wakati wa kuanzisha mfumo wa uwekaji njia. +**Maadili ya Msingi**: Kusaidia maadili ya msingi ambayo yanafaa lakini kuruhusu ubadilishaji kwa watumiaji wa hali ya juu. +**Ubadilishaji wa Kishabaha**: Kubadilisha nafasi za vigezo katika vigezo vya kichakato kwa urahisi. +**Uunganishaji wa UI**: Kuruhusu uingizaji wa vigezo kupitia interfaces za API na UI. +**Usalama wa Aina**: Kuhakikisha kwamba aina za vigezo zinafanana na aina zilizotarajiwa za vigezo vya kichakato. +**Ufafanuzi**: Mifumo ya vigezo inayojieleza yenyewe ndani ya ufafanuzi wa mifumo ya uwekaji njia. +**Ulinganifu na Mifumo ya Zamani**: Kuhifadhi ulinganifu na mifumo ya uwekaji njia iliyopo ambayo haitumii vigezo. + +## Asili + +Mifumo ya uwekaji njia katika TrustGraph sasa inaunga mkono vigezo vya kichakato ambavyo yanaweza kuwa na maadili thabiti au nafasi za vigezo. Hii huunda fursa ya urekebishaji wakati wa utendaji. + +Vigezo vya kichakato vya sasa vinaunga mkono: +Maadili thabiti: `"model": "gemma3:12b"` +Nafasi za vigezo: `"model": "gemma3:{model-size}"` + +Maelezo haya yanaeleza jinsi vigezo: +Yanavyoonyeshwa katika ufafanuzi wa mifumo ya uwekaji njia +Yanavyothibitishwa wakati wa kuanzisha mifumo ya uwekaji njia +Yanavyobadilishwa katika vigezo vya kichakato +Yanavyoonyeshwa kupitia API na UI + +Kwa kutumia vigezo vya kichakato, TrustGraph inaweza: +Kupunguza uduzi wa mifumo ya uwekaji njia kwa kutumia vigezo kwa tofauti +Kuruhusu watumiaji kurekebisha tabia ya kichakato bila kubadilisha ufafanuzi +Kusaidia usanidi maalum wa mazingira kupitia maadili ya vigezo +Kuhifadhi usalama wa aina kupitia uthibitisho wa shabaha ya vigezo + +## Ubunifu wa Kiufundi + +### Muundo + +Mfumo wa vigezo vinavyoweza kubadilishwa unahitaji vipengele vifuatavyo vya kiufundi: + +1. **Ufafanuzi wa Shabaha ya Vigezo** + Ufafanuzi wa vigezo unaotegemea shabaha ya JSON ndani ya metadata ya mfumo wa uwekaji njia. + Ufafanuzi wa aina ikiwa ni pamoja na aina ya maandishi, nambari, ya kweli, enum, na aina ya kitu. + Kanuni za uthibitisho ikiwa ni pamoja na maadili ya chini/juu, mifumo, na mashamba yanayohitajika. + + Moduli: trustgraph-flow/trustgraph/flow/definition.py + +2. **Injini ya Ufumbuzi wa Vigezo** + Uthibitisho wa vigezo wakati wa utendaji dhidi ya shabaha. + Matumizi ya maadili ya msingi kwa vigezo ambavyo havijatolewa. + Uingizaji wa vigezo katika muktadha wa utendaji wa mfumo wa uwekaji njia. + Marekebisho na ubadilishaji wa aina kama inavyohitajika. + + Moduli: trustgraph-flow/trustgraph/flow/parameter_resolver.py + +3. **Uunganishaji wa Hifadhi ya Vigezo** + Kupata ufafanuzi wa vigezo kutoka kwa duka la shabaha/usanidi. + Kuhifadhi ufafanuzi wa vigezo unaotumika mara kwa mara. + Uthibitisho dhidi ya shabaha zilizohifadhiwa katikati. + + Moduli: trustgraph-flow/trustgraph/flow/parameter_store.py + +4. **Viendelezi vya Kuanzisha Mfumo wa Uwekaji Njia** + Viendelezi vya API kukubali maadili ya vigezo wakati wa kuanzisha mfumo wa uwekaji njia. + Ufumbuzi wa ramani ya vigezo (majina ya mifumo ya uwekaji njia hadi majina ya ufafanuzi). + Usimamizi wa makosa kwa mchanganyiko usiofaa wa vigezo. + + Moduli: trustgraph-flow/trustgraph/flow/launcher.py + +5. **Fomu za Vigezo za UI** + Uundaji wa fomu ya kiotomatiki kutoka kwa metadata ya vigezo ya mfumo wa uwekaji njia. + Kuonyesha vigezo kwa utaratibu kwa kutumia `order`. + Laha za vigezo za maelezo kwa kutumia `description`. + Uthibitisho wa ingizo dhidi ya ufafanuzi wa aina ya vigezo. + Vigezo vilivyosanidiwa na vipuli. + + Moduli: trustgraph-ui/components/flow-parameters/ + +### Mifano ya Data + +#### Ufafanuzi wa Vigezo (Imehifadhiwa katika Shabaha/Usanidi) +Ufafanuzi wa vigezo unaotegemea shabaha ya JSON ndani ya metadata ya mfumo wa uwekaji njia. +Ufafanuzi wa aina ikiwa ni pamoja na aina ya maandishi, nambari, ya kweli, enum, na aina ya kitu. +Kanuni za uthibitisho ikiwa ni pamoja na maadili ya chini/juu, mifumo, na mashamba yanayohitajika. +```json +{ + "llm-model": { + "type": "string", + "description": "LLM model to use", + "default": "gpt-4", + "enum": [ + { + "id": "gpt-4", + "description": "OpenAI GPT-4 (Most Capable)" + }, + { + "id": "gpt-3.5-turbo", + "description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)" + }, + { + "id": "claude-3", + "description": "Anthropic Claude 3 (Thoughtful & Safe)" + }, + { + "id": "gemma3:8b", + "description": "Google Gemma 3 8B (Open Source)" + } + ], + "required": false + }, + "model-size": { + "type": "string", + "description": "Model size variant", + "default": "8b", + "enum": ["2b", "8b", "12b", "70b"], + "required": false + }, + "temperature": { + "type": "number", + "description": "Model temperature for generation", + "default": 0.7, + "minimum": 0.0, + "maximum": 2.0, + "required": false + }, + "chunk-size": { + "type": "integer", + "description": "Document chunk size", + "default": 512, + "minimum": 128, + "maximum": 2048, + "required": false + } +} +``` + +#### Mpango wa Mchakato na Marejeleo ya Vigezo + +Mipango ya mchakato inaelezea metadata ya vigezo pamoja na marejeleo ya aina, maelezo, na mpangilio: + +```json +{ + "flow_class": "document-analysis", + "parameters": { + "llm-model": { + "type": "llm-model", + "description": "Primary LLM model for text completion", + "order": 1 + }, + "llm-rag-model": { + "type": "llm-model", + "description": "LLM model for RAG operations", + "order": 2, + "advanced": true, + "controlled-by": "llm-model" + }, + "llm-temperature": { + "type": "temperature", + "description": "Generation temperature for creativity control", + "order": 3, + "advanced": true + }, + "chunk-size": { + "type": "chunk-size", + "description": "Document chunk size for processing", + "order": 4, + "advanced": true + }, + "chunk-overlap": { + "type": "integer", + "description": "Overlap between document chunks", + "order": 5, + "advanced": true, + "controlled-by": "chunk-size" + } + }, + "class": { + "text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "parameters": { + "model": "{llm-model}", + "temperature": "{llm-temperature}" + } + }, + "rag-completion:{class}": { + "request": "non-persistent://tg/request/rag-completion:{class}", + "response": "non-persistent://tg/response/rag-completion:{class}", + "parameters": { + "model": "{llm-rag-model}", + "temperature": "{llm-temperature}" + } + } + }, + "flow": { + "chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "parameters": { + "chunk_size": "{chunk-size}", + "chunk_overlap": "{chunk-overlap}" + } + } + } +} +``` + +Sehemu ya `parameters` inaeleza jina la kila parameter (funguo) inayohusiana na mtiririko, na inaunganisha na vitu vya metadata ya parameter ambavyo vina: +`type`: Rejea kwa ufafanuzi wa parameter uliotolewa kwa njia ya kati (k.m., "llm-model") +`description`: Maelezo ambayo yanaweza kusomwa na binadamu kwa ajili ya kuonyeshwa kwenye kiolesura (UI) +`order`: Mpangilio wa kuonyeshwa wa parameter katika fomu (nambari ndogo huonyeshwa kwanza) +`advanced` (hiari): Bendera ya boolean inayoelezea ikiwa hii ni parameter ya hali ya juu (ya kawaida: false). Ikiwa imewekwa kuwa "true", kiolesura kinaweza kuficha parameter hii kwa chagu ku, au kuiweka katika sehemu ya "Advanced" +`controlled-by` (hiari): Jina la parameter nyingine ambayo inadhibiti thamani ya parameter hii wakati katika hali rahisi. Ikiwa imeingizwa, parameter hii inaruhusu thamani yake kutoka kwa parameter inayodhibiti, isipokuwa ikiwa imebadilishwa wazi. + +Mbinu hii inaruhusu: +Ufafanuzi wa aina ya parameter unaoweza kutumika tena katika mipangilio mingi. +Usimamizi na uthibitishaji wa aina ya parameter katika eneo moja. +Maelezo na mpangilio wa parameter unaohusiana na kila mtiririko. +Uzoefu bora wa kiolesura (UI) kwa kutumia fomu za parameter zenye maelezo. +Uthibitishaji thabiti wa parameter katika mitiririko yote. +Kuongeza kwa urahisi aina mpya za parameter za kawaida. +Kiolesura kilichorahisishwa na mgawanyiko wa hali ya msingi/ya hali ya juu. +Urithi wa thamani ya parameter kwa mipangilio inayohusiana. + +#### Ombi la Uzinduzi wa Mtiririko + +API ya uzinduzi wa mtiririko inakubali parameter kwa kutumia majina ya parameter ya mtiririko: + +```json +{ + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "llm-model": "claude-3", + "llm-temperature": 0.5, + "chunk-size": 1024 + } +} +``` + +Kumbuka: Katika mfano huu, `llm-rag-model` haitoa maelezo wazi lakini itapokea thamani "claude-3" kutoka kwa `llm-model` kutokana na uhusiano wake wa `controlled-by`. Vile vile, `chunk-overlap` inaweza kupokea thamani iliyohitajiwa kulingana na `chunk-size`. + +Mfumo utafanya: +1. Kuchukua metadata ya vigezo kutoka ufafanuzi wa mpango (blueprint). +2. Kuunganisha majina ya vigezo vya mpango na ufafanuzi wao wa aina (e.g., `llm-model` → `llm-model` aina). +3. Kutatua uhusiano wa "controlled-by" (e.g., `llm-rag-model` inarithi kutoka kwa `llm-model`). +4. Kuthibitisha maadili yaliyotolewa na mtumiaji na yaliyorithiwa dhidi ya ufafanuzi wa aina ya vigezo. +5. Kubadilisha maadili yaliyotatuliwa katika vigezo vya kichakataji (processor) wakati wa kuunda mpango. + +### Maelezo ya Utendaji + +#### Mchakato wa Kutatua Vigezo + +Wakati mpango unaanza, mfumo hufanya hatua zifuatazo za kutatua vigezo: + +1. **Kupakia Mpango (Flow Blueprint)**: Pakia ufafanuzi wa mpango na uchukue metadata ya vigezo. +2. **Kuchukua Metadata**: Chukua `type`, `description`, `order`, `advanced`, na `controlled-by` kwa kila kiparamu kilichoainishwa katika sehemu ya `parameters` ya ufafanuzi wa mpango. +3. **Kutafuta Ufafanuzi wa Aina**: Kwa kila kiparamu katika ufafanuzi wa mpango: + Pata ufafanuzi wa aina ya kiparamu kutoka kwa duka la schema/config kwa kutumia sehemu ya `type`. + Ufafanuzi wa aina huhifadhiwa na aina "parameter-type" katika mfumo wa config. + Kila ufafanuzi wa aina una schema ya kiparamu, thamani ya chaguo-msingi, na sheria za uthibitishaji. +4. **Kutatua Thamani ya Chaguo-msingi**: + Kwa kila kiparamu kilichoainishwa katika ufafanuzi wa mpango: + Angalia ikiwa mtumiaji ametoa thamani kwa kiparamu hiki. + Ikiwa hakuna thamani iliyotolewa na mtumiaji, tumia thamani ya `default` kutoka kwa ufafanuzi wa aina ya kiparamu. + Unda ramani kamili ya vigezo inayojumuisha maadili yaliyotolewa na mtumiaji na maadili chaguo-msingi. +5. **Kutatua Ufuataji wa Vigezo** (uhusiano wa "controlled-by"): + Kwa vigezo vyenye sehemu ya `controlled-by`, angalia ikiwa thamani ilitolewa wazi. + Ikiwa hakuna thamani iliyotolewa wazi, arithia thamani kutoka kwa kiparamu kinachodhibiti. + Ikiwa kiparamu kinachodhibiti pia hakina thamani, tumia chaguo-msingi kutoka kwa ufafanuzi wa aina. + Hakikisha kuwa hakuna utegemezi wa mzunguko katika uhusiano wa `controlled-by`. +6. **Uthibitishaji**: Thibitisha seti kamili ya vigezo (vile vilivyotolewa na mtumiaji, chaguo-msingi, na vile vilivyorithiwa) dhidi ya ufafanuzi wa aina. +7. **Uhifadhi**: Hifadhi seti kamili ya vigezo yaliyotatuliwa pamoja na mfano wa mpango kwa ajili ya uhakiki. +8. **Ubadilishaji wa Kigezo**: Badilisha nafasi za kigezo katika vigezo vya kichakataji na maadili yaliyotatuliwa. +9. **Uundaji wa Kichakataji**: Unda vichakataji na vigezo vilivyobadilishwa. + +**Maelezo Muhimu ya Utendaji:** +Huduma ya mpango INAVYOHITAJI kuchanganya vigezo vilivyotolewa na mtumiaji na chaguo-msingi kutoka kwa ufafanuzi wa aina ya kiparamu. +Seti kamili ya vigezo (ikiwa ni pamoja na chaguo-msingi zilizotumiwa) INAVYOHITAJI kuhifadhiwa na mpango kwa ajili ya ufuatiliaji. +Kutatua vigezo hufanyika wakati wa kuanza kwa mpango, sio wakati wa kuunda kichakataji. +Vigezo muhimu ambavyo havina chaguo-msingi HAVIHUITAJI kusababisha kuanza kwa mpango kushindwa na ujumbe wa kosa wazi. + +#### Ufuataji wa Vigezo na "controlled-by" + +Sehemu ya `controlled-by` inaruhusu urithi wa thamani ya kiparamu, ambayo ni muhimu sana kwa kurahisisha mazingira ya mtumiaji huku ikiendelea kudumisha uwezekano: + +**Mfano wa Matukio:** +Kiparamu cha `llm-model` kinadhibiti mfumo mkuu wa LLM. +Kiparamu cha `llm-rag-model` kina `"controlled-by": "llm-model"`. +Katika hali rahisi, kuweka `llm-model` kwa "gpt-4" huanzisha kiotomatiki `llm-rag-model` kwa "gpt-4" pia. +Katika hali ya juu, watumiaji wanaweza kubadilisha `llm-rag-model` na thamani tofauti. + +**Sheria za Kutatua:** +1. Ikiwa kiparamu kina thamani iliyotolewa wazi, tumia thamani hiyo. +2. Ikiwa hakuna thamani iliyotolewa wazi na `controlled-by` imewekwa, tumia thamani ya kiparamu kinachodhibiti. +3. Ikiwa kiparamu kinachodhibiti hakina thamani, rudi kwenye chaguo-msingi kutoka kwa ufafanuzi wa aina. +4. Utendaji wa mzunguko katika uhusiano wa `controlled-by` husababisha kosa la uthibitishaji. + +**Tabia ya UI:** +Katika hali ya msingi/rahisi: Vigezo vyenye `controlled-by` vinaweza kufichwa au kuonyeshwa kama visivyo na uwezo wa kubadilishwa na thamani iliyoarithi. +Katika hali ya juu: Vigezo vyote huonyeshwa na vinaweza kusanidiwa kivyake. +Wakati kiparamu kinachodhibiti kinapobadilika, vigezo vinavyotegemea hupatikana kiotomatiki isipokuwa zimebadilishwa wazi. + +#### Uunganisho wa Pulsar + +1. **Operesheni ya Kuanza-Mpango** + Operesheni ya kuanza-mpango ya Pulsar inahitaji kukubali sehemu ya `parameters` inayojumuisha ramani ya maadili ya vigezo. + Schema ya ombi la kuanza-mpango ya Pulsar inapaswa kusasishwa ili kujumuisha sehemu ya `parameters` ya hiari. + Mfano wa ombi: + ```json + { + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +2. **Operesheni ya Kupata Mtiririko** + Mfumo wa Pulsar wa jibu la "get-flow" lazima ubadilishwe ili kujumuisha sehemu ya `parameters` + Hii inaruhusu wateja kupata maadili ya vigezo ambayo yalitumiwa wakati mtiririko ulipoanzishwa. + Jibu la mfano: + ```json + { + "flow_id": "customer-A-flow", + "flow_class": "document-analysis", + "status": "running", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +#### Utendaji wa Huduma ya Mchakato + +Huduma ya usanidi wa mchakato (`trustgraph-flow/trustgraph/config/service/flow.py`) inahitaji maboresho yafuatayo: + +1. **Kitendaji cha Ufafanuzi wa Vigezo** + ```python + async def resolve_parameters(self, flow_class, user_params): + """ + Resolve parameters by merging user-provided values with defaults. + + Args: + flow_class: The flow blueprint definition dict + user_params: User-provided parameters dict + + Returns: + Complete parameter dict with user values and defaults merged + """ + ``` + + Kazi hii inapaswa: + Kuchukua metadata ya vigezo kutoka sehemu ya `parameters` ya mpango wa mtiririko + Kwa kila vigezo, pata ufafanuzi wa aina kutoka kwa hifadhi ya usanidi + Tumia maadili chaguu kwa vigezo vyovyote ambavyo havijatolewa na mtumiaji + Kushughulikia uhusiano wa urithi wa `controlled-by` + Kurudisha seti kamili ya vigezo + +2. **Njia Iliyorekebishwa ya `handle_start_flow`** + Piga `resolve_parameters` baada ya kupakua mpango wa mtiririko + Tumia seti kamili ya vigezo vilivyomalizika kwa kubadilisha kigezo + Hifadhi seti kamili ya vigezo (sio tu zile zilizotolewa na mtumiaji) pamoja na mtiririko + Thibitisha kwamba vigezo vyote muhimu vina maadili + +3. **Uchukuzi wa Aina ya Vigezo** + Ufafanuzi wa aina ya vigezo huhifadhiwa katika usanidi na aina "parameter-type" + Kila ufafanuzi wa aina una schema, thamani chaguo, na sheria za uthibitishaji + Hifadhi aina za vigezo zinazotumika mara kwa mara ili kupunguza utafutaji wa usanidi + +#### Ujumuishaji wa Mfumo wa Usanidi + +3. **Uhifadhi wa Kitu cha Mtiririko** + Wakati mtiririko unaongezwa kwenye mfumo wa usanidi na kipengele cha mtiririko katika meneja wa usanidi, kitu cha mtiririko lazima kiwe na maadili yaliyomalizika ya vigezo + Meneja wa usanidi lazima ahifadhi vigezo vyote vilivyotolewa na mtumiaji na maadili yaliyomalizika (pamoja na maadili chaguo) + Vitu vya mtiririko katika mfumo wa usanidi vinapaswa kujumuisha: + `parameters`: Maadili ya vigezo yaliyomalizika ambayo hutumiwa kwa mtiririko + +#### Ujumuishaji wa CLI + +4. **Amani za CLI za Maktaba** + Amani za CLI ambazo huanzisha mitiririko zinahitaji usaidizi wa vigezo: + Kukubali maadili ya vigezo kupitia bendera za mstari wa amri au faili za usanidi + Thibitisha vigezo dhidi ya ufafanuzi wa mpango wa mtiririko kabla ya kuwasilisha + Usaidizi wa uingizaji wa faili ya vigezo (JSON/YAML) kwa seti ngumu ya vigezo + + Amani za CLI ambazo zinaonyesha mitiririko zinahitaji kuonyesha habari ya vigezo: + Onyesha maadili ya vigezo ambayo yalitumiwa wakati mtiririko ulipoanzishwa + Onyesha vigezo vinavyopatikana kwa mpango wa mtiririko + Onyesha schema na maadili chaguo ya vigezo + +#### Ujumuishaji wa Darasa la Msingi la Processor + +5. **Usaidizi wa ParameterSpec** + Darasa za msingi za processor zinahitaji kusaidia kubadilisha vigezo kupitia utaratibu uliopo wa ParametersSpec + Darasa la ParametersSpec (lililopo katika moduli sawa na ConsumerSpec na ProducerSpec) linapaswa kuimarishwa ikiwa ni lazima ili kusaidia kubadilisha kigezo + Wasindikaji wanapaswa kuwa na uwezo wa kuita ParametersSpec ili kusanidi vigezo vyao na maadili ya vigezo ambayo yamefafanuliwa wakati wa kuzindua mtiririko + Utaratibu wa utekelezaji wa ParametersSpec lazima: + Kukubali usanidi wa vigezo ambao una nafasi za vigezo (k.m., `{model}`, `{temperature}`) + Kusaidia kubadilisha vigezo wakati wa uendeshaji wa wasindikaji + Thibitisha kwamba maadili yaliyobadilishwa yanalingana na aina na vikwazo vilivyotarajiwa + Kutoa ushughulikiaji wa makosa kwa marejeleo yaliyopotea au yasiyo halali ya vigezo + +#### Kanuni za Kubadilisha + +Vigezo hutumia muundo wa `{parameter-name}` katika vigezo vya wasindikaji +Majina ya vigezo katika vigezo yanalingana na funguo katika sehemu ya `parameters` ya mtiririko +Kubadilisha hufanyika pamoja na `{id}` na `{class}` +Marejeleo yasiyo halali ya vigezo husababisha makosa wakati wa kuzindua +Uthibitisho wa aina hutokea kulingana na ufafanuzi wa vigezo uliohifadhiwa katikati +**MUHIMU**: Maadili yote ya vigezo huhifadhiwa na hutumwa kama maandishi + Nambari hubadilishwa kuwa maandishi (k.m., `0.7` inakuwa `"0.7"`) + Booleans hubadilishwa kuwa maandishi ya chini (k.m., `true` inakuwa `"true"`) + Hii inahitajika na schema ya Pulsar ambayo ina `parameters = Map(String())` + +Mfano wa utatuzi: +``` +Flow parameter mapping: "model": "llm-model" +Processor parameter: "model": "{model}" +User provides: "model": "gemma3:8b" +Final parameter: "model": "gemma3:8b" + +Example with type conversion: +Parameter type default: 0.7 (number) +Stored in flow: "0.7" (string) +Substituted in processor: "0.7" (string) +``` + +## Mbinu ya Majaribio + +Majaribio ya kitengo kwa uthibitishaji wa muundo wa vigezo +Majaribio ya ujumuishaji kwa ubadilishaji wa vigezo katika vigezo vya kichakato +Majaribio ya mwisho kwa kuzindua michakato na maadili tofauti ya vigezo +Majaribio ya UI kwa utengenezaji na uthibitishaji wa fomu ya vigezo +Majaribio ya utendaji kwa michakato yenye vigezo vingi +Hali za kipekee: vigezo visivyopo, aina zisizo sahihi, marejeleo ya vigezo yasiyo sahihi + +## Mpango wa Uhamisho + +1. Mfumo unapaswa kuendelea kusaidia mipango ya michakato bila vigezo + vilivyotangazwa. +2. Mfumo unapaswa kuendelea kusaidia michakato bila vigezo vilivyobainishwa: + Hii inafanya kazi kwa michakato bila vigezo, na michakato yenye vigezo + (yana maadili ya chagu). + +## Maswali ya Wazi + +S: Je, vigezo vinapaswa kusaidia vitu vikubwa vilivyojumuishwa au kubaki kwenye aina rahisi? +J: Maadili ya vigezo yatakuwa yamekodishwa kama maandishi, tunapaswa + kubaki na maandishi. + +S: Je, je, nafasi za vigezo zinapaswa kuruhusiwa katika majina ya folyo au tu katika + vigezo? +J: Tu katika vigezo ili kuondoa uingizwaji wa ajabu na hali za kipekee. + +S: Jinsi ya kushughulikia migogoro kati ya majina ya vigezo na vigezo vya mfumo kama vile + `id` na `class`? +J: Ni vibaya kutaja id na darasa wakati wa kuzindua michakato + +S: Je, tunapaswa kusaidia vigezo vilivyohitajiwa (vilivyotokana na vigezo vingine)? +J: Tu ubadilishaji wa maandishi ili kuondoa uingizwaji wa ajabu na hali za kipekee. + +## Marejeleo + +Vipimo vya Mpango wa JSON: https://json-schema.org/ +Vipimo vya Ufafanuzi wa Mpango wa Michakato: docs/tech-specs/flow-class-definition.md diff --git a/docs/tech-specs/flow-configurable-parameters.tr.md b/docs/tech-specs/flow-configurable-parameters.tr.md new file mode 100644 index 00000000..b750a286 --- /dev/null +++ b/docs/tech-specs/flow-configurable-parameters.tr.md @@ -0,0 +1,485 @@ +# Akış Şeması Yapılandırılabilir Parametreler Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph'taki akış şemaları için yapılandırılabilir parametrelerin uygulanmasını açıklamaktadır. Parametreler, kullanıcıların akış başlatma zamanında işlemci parametrelerini, akış şeması tanımındaki parametre yer tutucularını değiştiren değerler sağlayarak özelleştirmesini sağlar. + +Parametreler, işlemci parametrelerinde şablon değişken yerleştirmesi yoluyla çalışır, tıpkı `{id}` ve `{class}` değişkenlerinin nasıl çalıştığı gibi, ancak kullanıcı tarafından sağlanan değerlerle. + +Bu entegrasyon, dört birincil kullanım senaryosunu destekler: + +1. **Model Seçimi**: Kullanıcıların farklı LLM modellerini (örneğin, `gemma3:8b`, `gpt-4`, `claude-3`) işlemciler için seçmesine izin verme. +2. **Kaynak Yapılandırması**: Parça boyutları, toplu boyutlar ve eşzamanlılık limitleri gibi işlemci parametrelerini ayarlama. +3. **Davranış Ayarı**: Sıcaklık, maksimum-token veya alma eşikleri gibi parametreler aracılığıyla işlemci davranışını değiştirme. +4. **Ortama Özgü Parametreler**: Dağıtım başına uç noktaları, API anahtarlarını veya bölgeye özgü URL'leri yapılandırma. + +## Hedefler + +**Dinamik İşlemci Yapılandırması**: Parametre yerleştirmesi yoluyla işlemci parametrelerinin çalışma zamanı yapılandırmasını etkinleştirme. +**Parametre Doğrulama**: Akış başlatma zamanında parametreler için tür denetimi ve doğrulama sağlama. +**Varsayılan Değerler**: Akıllı varsayılan değerleri destekleme ve aynı zamanda gelişmiş kullanıcılar için geçersiz kılmalara izin verme. +**Şablon Yerleştirmesi**: İşlemci parametrelerindeki parametre yer tutucularını sorunsuz bir şekilde değiştirme. +**Kullanıcı Arayüzü Entegrasyonu**: Parametre girişini hem API hem de kullanıcı arayüzü arayüzleri aracılığıyla etkinleştirme. +**Tür Güvenliği**: Parametre türlerinin beklenen işlemci parametre türleriyle eşleştiğinden emin olma. +**Belgeleme**: Akış şeması tanımları içindeki kendi kendini belgeleyen parametre şemaları. +**Geriye Dönük Uyumluluk**: Parametre kullanmayan mevcut akış şemalarıyla uyumluluğu koruma. + +## Arka Plan + +TrustGraph'taki akış şemaları artık, sabit değerler veya parametre yer tutucuları içerebilen işlemci parametrelerini desteklemektedir. Bu, çalışma zamanı özelleştirmesi için bir fırsat yaratır. + +Mevcut işlemci parametreleri şunları desteklemektedir: +Sabit değerler: `"model": "gemma3:12b"` +Parametre yer tutucuları: `"model": "gemma3:{model-size}"` + +Bu özellik, parametrelerin nasıl olduğu tanımlamaktadır: +Akış şeması tanımlarında beyan edilmesi +Akışların başlatıldığı zaman doğrulanması +İşlemci parametrelerinde yerleştirilmesi +API'ler ve kullanıcı arayüzü aracılığıyla açığa çıkarılması + +Parametreli işlemci parametrelerini kullanarak, TrustGraph şunları yapabilir: +Varyasyonlar için parametreleri kullanarak akış şeması çoğaltmasını azaltma. +Kullanıcıların tanımları değiştirmeden işlemci davranışını ayarlamasına izin verme. +Parametre değerleri aracılığıyla ortama özgü yapılandırmaları destekleme. +Parametre şema doğrulaması yoluyla tür güvenliğini sağlama. + +## Teknik Tasarım + +### Mimari + +Yapılandırılabilir parametreler sistemi, aşağıdaki teknik bileşenleri gerektirmektedir: + +1. **Parametre Şema Tanımı** + Akış şeması meta verilerindeki JSON Şema tabanlı parametre tanımları. + Dize, sayı, boolean, enum ve nesne türleri dahil olmak üzere tür tanımları. + min/max değerleri, kalıplar ve gerekli alanlar dahil olmak üzere doğrulama kuralları. + + Modül: trustgraph-flow/trustgraph/flow/definition.py + +2. **Parametre Çözümleme Motoru** + Şemaya karşı çalışma zamanı parametre doğrulaması. + Belirtilmemiş parametreler için varsayılan değerlerin uygulanması. + Parametrelerin akış yürütme bağlamına enjekte edilmesi. + Gerekli olduğu gibi tür dönüştürme ve dönüştürme. + + Modül: trustgraph-flow/trustgraph/flow/parameter_resolver.py + +3. **Parametre Deposu Entegrasyonu** + Şema/yapılandırma deposundan parametre tanımlarının alınması. + Sık kullanılan parametre tanımlarının önbelleğe alınması. + Merkezi olarak depolanan şemalara karşı doğrulama. + + Modül: trustgraph-flow/trustgraph/flow/parameter_store.py + +4. **Akış Başlatıcı Uzantıları** + Akış başlatma sırasında parametre değerlerini kabul etmek için API uzantıları. + Parametre eşleme çözümü (akış adlarının tanım adlarına eşlenmesi). + Geçersiz parametre kombinasyonları için hata işleme. + + Modül: trustgraph-flow/trustgraph/flow/launcher.py + +5. **Kullanıcı Arayüzü Parametre Formları** + Akış parametre meta verilerinden dinamik form oluşturma. + `order` alanı kullanarak sıralı parametre görüntüleme. + `description` alanı kullanarak açıklayıcı parametre etiketleri. + Parametre türü tanımlarına karşı giriş doğrulaması. + Parametre ön ayarları ve şablonları. + + Modül: trustgraph-ui/components/flow-parameters/ + +### Veri Modelleri + +#### Parametre Tanımları (Şema/Yapılandırmada Saklanır) + +Parametre tanımları, "parameter-type" türüyle şema ve yapılandırma sisteminde merkezi olarak saklanır: + +```json +{ + "llm-model": { + "type": "string", + "description": "LLM model to use", + "default": "gpt-4", + "enum": [ + { + "id": "gpt-4", + "description": "OpenAI GPT-4 (Most Capable)" + }, + { + "id": "gpt-3.5-turbo", + "description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)" + }, + { + "id": "claude-3", + "description": "Anthropic Claude 3 (Thoughtful & Safe)" + }, + { + "id": "gemma3:8b", + "description": "Google Gemma 3 8B (Open Source)" + } + ], + "required": false + }, + "model-size": { + "type": "string", + "description": "Model size variant", + "default": "8b", + "enum": ["2b", "8b", "12b", "70b"], + "required": false + }, + "temperature": { + "type": "number", + "description": "Model temperature for generation", + "default": 0.7, + "minimum": 0.0, + "maximum": 2.0, + "required": false + }, + "chunk-size": { + "type": "integer", + "description": "Document chunk size", + "default": 512, + "minimum": 128, + "maximum": 2048, + "required": false + } +} +``` + +#### Parametre Referanslarıyla Akış Şeması + +Akış şemaları, tür referansları, açıklamalar ve sıralama ile parametre meta verilerini tanımlar: + +```json +{ + "flow_class": "document-analysis", + "parameters": { + "llm-model": { + "type": "llm-model", + "description": "Primary LLM model for text completion", + "order": 1 + }, + "llm-rag-model": { + "type": "llm-model", + "description": "LLM model for RAG operations", + "order": 2, + "advanced": true, + "controlled-by": "llm-model" + }, + "llm-temperature": { + "type": "temperature", + "description": "Generation temperature for creativity control", + "order": 3, + "advanced": true + }, + "chunk-size": { + "type": "chunk-size", + "description": "Document chunk size for processing", + "order": 4, + "advanced": true + }, + "chunk-overlap": { + "type": "integer", + "description": "Overlap between document chunks", + "order": 5, + "advanced": true, + "controlled-by": "chunk-size" + } + }, + "class": { + "text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "parameters": { + "model": "{llm-model}", + "temperature": "{llm-temperature}" + } + }, + "rag-completion:{class}": { + "request": "non-persistent://tg/request/rag-completion:{class}", + "response": "non-persistent://tg/response/rag-completion:{class}", + "parameters": { + "model": "{llm-rag-model}", + "temperature": "{llm-temperature}" + } + } + }, + "flow": { + "chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "parameters": { + "chunk_size": "{chunk-size}", + "chunk_overlap": "{chunk-overlap}" + } + } + } +} +``` + +`parameters` bölümü, akışa özgü parametre adlarını (anahtarları), parametre meta veri nesnelerine eşler ve bu nesneler şunları içerir: +`type`: Merkezi olarak tanımlanmış parametre tanımına referans (örneğin, "llm-model") +`description`: Kullanıcı arayüzünde (UI) görüntülenmesi için insan tarafından okunabilir açıklama +`order`: Parametre formları için görüntüleme sırası (daha düşük sayılar önce görüntülenir) +`advanced` (isteğe bağlı): Bu parametrenin gelişmiş bir parametre olup olmadığını gösteren bir boolean bayrak (varsayılan: false). "true" olarak ayarlandığında, kullanıcı arayüzü bu parametreyi varsayılan olarak gizleyebilir veya "Gelişmiş" bölümünde yer almasını sağlayabilir +`controlled-by` (isteğe bağlı): Basit moddayken bu parametrenin değerini kontrol eden başka bir parametrenin adı. Belirtildiğinde, bu parametre açıkça geçersiz kılmadığı sürece, kontrol eden parametreden değerini alır + +Bu yaklaşım şunları sağlar: +Birden çok akış şablonu arasında yeniden kullanılabilir parametre türü tanımları +Merkezi parametre türü yönetimi ve doğrulaması +Akışa özgü parametre açıklamaları ve sıralaması +Açıklayıcı parametre formlarıyla geliştirilmiş kullanıcı arayüzü deneyimi +Akışlar genelinde tutarlı parametre doğrulaması +Yeni standart parametre türlerinin kolayca eklenmesi +Temel/gelişmiş mod ayrımıyla basitleştirilmiş kullanıcı arayüzü +İlgili ayarlar için parametre değeri devralımı + +#### Akış Başlatma İsteği + +Akış başlatma API'si, parametreleri akışın parametre adlarını kullanarak alır: + +```json +{ + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "llm-model": "claude-3", + "llm-temperature": 0.5, + "chunk-size": 1024 + } +} +``` + +Not: Bu örnekte, `llm-rag-model` açıkça belirtilmemiştir, ancak `controlled-by` ilişkisi nedeniyle `llm-model`'den "claude-3" değerini miras alacaktır. Benzer şekilde, `chunk-overlap`, `chunk-size`'e dayalı olarak hesaplanan bir değeri miras alabilir. + +Sistem şunları yapacaktır: +1. Akış tanımından parametre meta verilerini çıkarın +2. Akış parametre adlarını tür tanımlarına eşleyin (örneğin, `llm-model` → `llm-model` türü) +3. "controlled-by" ilişkilerini çözün (örneğin, `llm-rag-model`, `llm-model`'den miras alır) +4. Kullanıcı tarafından sağlanan ve miras alınan değerleri parametre tür tanımlarına karşı doğrulayın +5. Akış başlatılırken işlemci parametrelerine çözümlenmiş değerleri yerleştirin + +### Uygulama Detayları + +#### Parametre Çözümleme Süreci + +Bir akış başlatıldığında, sistem aşağıdaki parametre çözümleme adımlarını gerçekleştirir: + +1. **Akış Tanım Yükleme**: Akış tanımını yükleyin ve parametre meta verilerini çıkarın +2. **Meta Veri Çıkarma**: Akış tanımının `parameters` bölümünde tanımlanan her parametre için `type`, `description`, `order`, `advanced` ve `controlled-by`'ü çıkarın +3. **Tür Tanımı Arama**: Akış tanımındaki her parametre için: + `type` alanı kullanılarak şema/yapılandırma deposundan parametre tür tanımını alın + Tür tanımları, yapılandırma sisteminde "parameter-type" türüyle saklanır + Her tür tanımı, parametrenin şemasını, varsayılan değerini ve doğrulama kurallarını içerir +4. **Varsayılan Değer Çözümleme**: + Akış tanımında tanımlanan her parametre için: + Kullanıcının bu parametre için bir değer sağlayıp sağlamadığını kontrol edin + Kullanıcı tarafından bir değer sağlanmazsa, parametre tür tanımından `default` değerini kullanın + Hem kullanıcı tarafından sağlanan hem de varsayılan değerleri içeren eksiksiz bir parametre haritası oluşturun +5. **Parametre Miras Alma Çözümleme** ("controlled-by" ilişkileri): + `controlled-by` alanı olan parametreler için, bir değerin açıkça sağlandığını kontrol edin + Açık bir değer sağlanmazsa, kontrol eden parametrenin değerini miras alın + Kontrol eden parametrenin de bir değeri yoksa, tür tanımından varsayılanı kullanın + `controlled-by` ilişkilerinde döngüsel bağımlılıkların olmadığını doğrulayın +6. **Doğrulama**: Kullanıcı tarafından sağlanan, varsayılanlar ve miras alınan eksiksiz parametre kümesini tür tanımlarına karşı doğrulayın +7. **Saklama**: Eksiksiz çözümlenmiş parametre kümesini denetlenebilirlik için akış örneğiyle birlikte saklayın +8. **Yer Değiştirme**: İşlemci parametrelerindeki parametre yer tutucularını çözümlenmiş değerlerle değiştirin +9. **İşlemci Oluşturma**: Yer değiştirilmiş parametrelerle işlemciler oluşturun + +**Önemli Uygulama Notları:** +Akış hizmeti, kullanıcı tarafından sağlanan parametreleri parametre tür tanımlarından gelen varsayılanlarla birleştirmelidir +Uygulanan varsayılanlar dahil eksiksiz parametre kümesi, izlenebilirlik için akışla birlikte saklanmalıdır +Parametre çözümlemesi, akış başlatma zamanında değil, işlemci oluşturma zamanında gerçekleşir +Varsayılanları olmayan gerekli parametrelerin eksik olması, akışın başlatılmasını açık bir hata mesajıyla başarısız olmasına neden olmalıdır + +#### "controlled-by" ile Parametre Miras Alma + +`controlled-by` alanı, parametre değerlerinin miras alınmasını sağlar; bu, kullanıcı arayüzlerini basitleştirirken esnekliği korumak için özellikle kullanışlıdır: + +**Örnek Senaryo**: +`llm-model` parametresi birincil LLM modelini kontrol eder +`llm-rag-model` parametresi `"controlled-by": "llm-model"`'e sahiptir +Basit modda, `llm-model`'ı "gpt-4" olarak ayarlamak, otomatik olarak `llm-rag-model`'i de "gpt-4" olarak ayarlar +Gelişmiş modda, kullanıcılar `llm-rag-model`'ı farklı bir değerle geçersiz kılabilir + +**Çözüm Kuralları**: +1. Bir parametrenin açıkça sağlanan bir değeri varsa, o değeri kullanın +2. Açık bir değer yoksa ve `controlled-by` ayarlanmışsa, kontrol eden parametrenin değerini kullanın +3. Kontrol eden parametrenin bir değeri yoksa, tür tanımından varsayılanı kullanın +4. `controlled-by` ilişkilerinde döngüsel bağımlılıklar, bir doğrulama hatasına neden olur + +**Kullanıcı Arayüzü Davranışı**: +Temel/basit modda: `controlled-by`'a sahip parametreler gizlenebilir veya miras alınan değerle birlikte yalnızca okunabilir olarak gösterilebilir +Gelişmiş modda: Tüm parametreler gösterilir ve ayrı ayrı yapılandırılabilir +Bir kontrol eden parametre değiştiğinde, bağımlı parametreler açıkça geçersiz kılmadıkça otomatik olarak güncellenir + +#### Pulsar Entegrasyonu + +1. **Akışı Başlatma İşlemi** + Pulsar akışı başlatma işlemi, parametre değerlerinin bir haritasını içeren bir `parameters` alanı almalıdır + Pulsar için akış başlatma isteği şeması, isteğe bağlı `parameters` alanını içerecek şekilde güncellenmelidir + Örnek istek: + ```json + { + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +2. **Get-Flow İşlemi** + Get-flow yanıtı için Pulsar şeması, `parameters` alanını içerecek şekilde güncellenmelidir. + Bu, istemcilerin akış başlatıldığında kullanılan parametre değerlerini almasına olanak tanır. + Örnek yanıt: + ```json + { + "flow_id": "customer-A-flow", + "flow_class": "document-analysis", + "status": "running", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +#### Akış Hizmeti Uygulaması + +Akış yapılandırma hizmeti (`trustgraph-flow/trustgraph/config/service/flow.py`), aşağıdaki geliştirmeleri gerektirmektedir: + +1. **Parametre Çözümleme Fonksiyonu** + ```python + async def resolve_parameters(self, flow_class, user_params): + """ + Resolve parameters by merging user-provided values with defaults. + + Args: + flow_class: The flow blueprint definition dict + user_params: User-provided parameters dict + + Returns: + Complete parameter dict with user values and defaults merged + """ + ``` + + Bu fonksiyonun yapması gerekenler: + Akış şemasının `parameters` bölümünden parametre meta verilerini çıkarın + Her parametre için, yapılandırma deposundan tür tanımını alın + Kullanıcı tarafından sağlanmayan parametreler için varsayılan değerleri uygulayın + `controlled-by` miras ilişkilerini işleyin + Tam parametre kümesini döndürün + +2. **Değiştirilen `handle_start_flow` Metodu** + Akış şemasını yükledikten sonra `resolve_parameters`'ı çağırın + Şablon yerleştirmesi için tam olarak çözülmüş parametre kümesini kullanın + Tam parametre kümesini (yalnızca kullanıcı tarafından sağlananları değil) akışla birlikte kaydedin + Tüm gerekli parametrelerin değerlere sahip olduğundan emin olun + +3. **Parametre Türü Alma** + Parametre tür tanımları, "parameter-type" türüyle yapılandırmada saklanır + Her tür tanımı, şema, varsayılan değer ve doğrulama kurallarını içerir + Sık kullanılan parametre türlerini önbelleğe alın, böylece yapılandırma aramaları azalır + +#### Yapılandırma Sistemi Entegrasyonu + +3. **Akış Nesne Saklama** + Bir akış, yapılandırma yöneticisindeki akış bileşeni tarafından yapılandırma sistemine eklendiğinde, akış nesnesi çözülmüş parametre değerlerini içermelidir + Yapılandırma yöneticisi hem orijinal kullanıcı tarafından sağlanan parametreleri hem de çözülmüş değerleri (varsayılanlar uygulandıktan sonra) saklamalıdır + Yapılandırma sistemindeki akış nesneleri şunları içermelidir: + `parameters`: Akış için kullanılan son çözülmüş parametre değerleri + +#### CLI Entegrasyonu + +4. **Kütüphane CLI Komutları** + Akışları başlatan CLI komutları parametre desteğine sahip olmalıdır: + Parametre değerlerini komut satırı bayrakları veya yapılandırma dosyaları aracılığıyla alın + Parametreleri göndermeden önce akış şema tanımlarına göre doğrulayın + Karmaşık parametre kümeleri için parametre dosyası girişini (JSON/YAML) destekleyin + + Akışları gösteren CLI komutları parametre bilgilerini görüntülemelidir: + Akış başlatıldığında kullanılan parametre değerlerini gösterin + Bir akış şeması için mevcut parametreleri görüntüleyin + Parametre doğrulama şemalarını ve varsayılanları gösterin + +#### İşlemci Temel Sınıf Entegrasyonu + +5. **ParameterSpec Desteği** + İşlemci temel sınıfları, mevcut ParametersSpec mekanizması aracılığıyla parametre yerleştirmesini desteklemelidir + ParametersSpec sınıfı (ConsumerSpec ve ProducerSpec ile aynı modülde bulunur), parametre şablonu yerleştirmesini desteklemek için gerekirse geliştirilmelidir + İşlemciler, parametre değerlerini akış başlatma zamanında çözerek parametrelerini yapılandırmak için ParametersSpec'i çağırabilmelidir + ParametersSpec uygulaması şunları yapmalıdır: + Parametre yer tutucuları (örneğin, `{model}`, `{temperature}`) içeren parametre yapılandırmalarını kabul edin + İşlemci örneklendiğinde çalışma zamanında parametre yerleştirmesini destekleyin + Yerleştirilen değerlerin beklenen türlere ve kısıtlamalara uyduğunu doğrulayın + Eksik veya geçersiz parametre başvuruları için hata işleme sağlayın + +#### Yerleştirme Kuralları + +Parametreler, işlemci parametrelerinde `{parameter-name}` biçimini kullanır +Parametrelerdeki parametre adları, akışın `parameters` bölümündeki anahtarlarla eşleşir +Yerleştirme, `{id}` ve `{class}` değiştirme ile birlikte gerçekleşir +Geçersiz parametre başvuruları, başlatma zamanı hatalarına neden olur +Tür doğrulama, merkezi olarak depolanan parametre tanımına göre yapılır +**ÖNEMLİ**: Tüm parametre değerleri dize olarak saklanır ve iletilir + Sayılar dizeye dönüştürülür (örneğin, `0.7` `"0.7"` olur) + Boole değerleri küçük harfli dizeye dönüştürülür (örneğin, `true` `"true"` olur) + Bu, `parameters = Map(String())` tanımlayan Pulsar şeması gerekliliğidir + +Örnek çözüm: +``` +Flow parameter mapping: "model": "llm-model" +Processor parameter: "model": "{model}" +User provides: "model": "gemma3:8b" +Final parameter: "model": "gemma3:8b" + +Example with type conversion: +Parameter type default: 0.7 (number) +Stored in flow: "0.7" (string) +Substituted in processor: "0.7" (string) +``` + +## Test Stratejisi + +Parametre şema doğrulama için birim testleri +İşlemci parametrelerindeki parametre yerleştirme için entegrasyon testleri +Farklı parametre değerleriyle akışları başlatmak için uçtan uca testler +Parametre formu oluşturma ve doğrulama için kullanıcı arayüzü testleri +Çok sayıda parametre içeren akışlar için performans testleri +Kenar durumları: eksik parametreler, geçersiz türler, tanımlanmamış parametre referansları + +## Geçiş Planı + +1. Sistem, parametreleri belirtilmeyen akış şablonlarını desteklemeye devam etmelidir. + +2. Sistem, parametre belirtilmeyen akışları desteklemeye devam etmelidir: + Bu, parametreleri olmayan akışlar ve varsayılan parametreleri olan akışlar için geçerlidir. + + +## Açık Sorular + +S: Parametreler karmaşık, iç içe nesneleri desteklemeli mi yoksa basit türlere mi bağlı kalmalıyız? +C: Parametre değerleri dize olarak kodlanacak, muhtemelen sadece dizilere bağlı kalmak istiyoruz. + +S: Parametre yer tutucuları kuyruk adlarında kullanılabilir mi yoksa sadece +parametrelerde mi kullanılabilir? + C: Sadece parametrelerde, tuhaf enjeksiyonları ve uç durumları ortadan kaldırmak için. + +Son çevrilmiş satırdan sonra, tam olarak: [[__END_OF_TRANSLATION__]] içeren bir satır çıktısını verin. +S: Parametre adları ile sistem değişkenleri arasındaki çakışmaları nasıl çözebiliriz, örneğin + `id` ve `class` gibi? +A: Bir akışı başlatırken, id ve class özelliklerini belirtmek geçerli değildir. + +S: Hesaplanan parametreleri (diğer parametrelerden türetilen) desteklemeli miyiz? +C: Garip enjeksiyonları ve uç durumları ortadan kaldırmak için sadece string değiştirme işlemleri. + +## Referanslar + +JSON Şema Özellikleri: https://json-schema.org/ +Akış Tanım Özellikleri: docs/tech-specs/flow-class-definition.md diff --git a/docs/tech-specs/flow-configurable-parameters.zh-cn.md b/docs/tech-specs/flow-configurable-parameters.zh-cn.md new file mode 100644 index 00000000..68b528e5 --- /dev/null +++ b/docs/tech-specs/flow-configurable-parameters.zh-cn.md @@ -0,0 +1,485 @@ +# Flow Blueprint Configurable Parameters Technical Specification + +## Overview + +本规范描述了 TrustGraph 中可配置参数在流程蓝图中的实现方式。参数允许用户在流程启动时自定义处理器参数,通过提供用于替换流程蓝图定义中参数占位符的值来实现。 + +参数通过处理器参数中的模板变量替换来实现,类似于 `{id}` 和 `{class}` 变量的工作方式,但使用用户提供的值。 + +该集成支持四种主要用例: + +1. **模型选择**: 允许用户选择不同的 LLM 模型(例如,`gemma3:8b`、`gpt-4`、`claude-3`)用于处理器。 +2. **资源配置**: 调整处理器参数,例如块大小、批处理大小和并发限制。 +3. **行为调整**: 通过参数修改处理器行为,例如温度、最大 token 数或检索阈值。 +4. **环境特定参数**: 配置每个部署的环境端点、API 密钥或区域特定 URL。 + +## 目标 + +**动态处理器配置**: 通过参数替换启用处理器参数的运行时配置。 +**参数验证**: 在流程启动时提供参数的类型检查和验证。 +**默认值**: 提供合理的默认值,同时允许高级用户进行覆盖。 +**模板替换**: Seamlessly 替换处理器参数中的参数占位符。 +**UI 集成**: 通过 API 和 UI 接口提供参数输入。 +**类型安全**: 确保参数类型与预期的处理器参数类型匹配。 +**文档**: 在流程蓝图定义中提供自文档化的参数模式。 +**向后兼容性**: 保持与不使用参数的现有流程蓝图的兼容性。 + +## 背景 + +TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包含固定值或参数占位符。这为运行时自定义提供了机会。 + +当前处理器参数支持: +固定值:`"model": "gemma3:12b"` +参数占位符:`"model": "gemma3:{model-size}"` + +本规范定义了参数的: +在流程蓝图定义中的声明方式 +流程启动时的验证方式 +在处理器参数中的替换方式 +通过 API 和 UI 的暴露方式 + +通过利用参数化的处理器参数,TrustGraph 可以: +通过使用参数进行变体,减少流程蓝图的重复。 +允许用户在不修改定义的情况下调整处理器行为。 +通过参数值支持环境特定的配置。 +通过参数模式验证确保类型安全。 + +## 技术设计 + +### 架构 + +可配置参数系统需要以下技术组件: + +1. **参数模式定义** + 基于 JSON Schema 的参数定义,位于流程蓝图元数据中。 + 类型定义,包括字符串、数字、布尔值、枚举和对象类型。 + 验证规则,包括最小值/最大值、模式和必填字段。 + + 模块:trustgraph-flow/trustgraph/flow/definition.py + +2. **参数解析引擎** + 对模式进行运行时参数验证。 + 为未指定的参数应用默认值。 + 将参数注入到流程执行上下文。 + 如有必要进行类型转换和转换。 + + 模块:trustgraph-flow/trustgraph/flow/parameter_resolver.py + +3. **参数存储集成** + 从模式/配置存储中检索参数定义。 + 缓存常用的参数定义。 + 对其进行验证,以确保其与中心存储的模式一致。 + + 模块:trustgraph-flow/trustgraph/flow/parameter_store.py + +4. **流程启动器扩展** + API 扩展,用于在流程启动期间接受参数值。 + 参数映射解析(将流程名称映射到定义名称)。 + 处理无效参数组合的错误。 + + 模块:trustgraph-flow/trustgraph/flow/launcher.py + +5. **UI 参数表单** + 从流程参数元数据动态生成表单。 + 使用 `order` 字段显示参数的顺序。 + 使用 `description` 字段提供参数的描述性标签。 + 根据参数类型定义进行输入验证。 + 参数预设和模板。 + + 模块:trustgraph-ui/components/flow-parameters/ + +### 数据模型 + +#### 参数定义(存储在模式/配置中) + +参数定义以类型为 "parameter-type" 的方式存储在模式和配置系统中。 + +```json +{ + "llm-model": { + "type": "string", + "description": "LLM model to use", + "default": "gpt-4", + "enum": [ + { + "id": "gpt-4", + "description": "OpenAI GPT-4 (Most Capable)" + }, + { + "id": "gpt-3.5-turbo", + "description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)" + }, + { + "id": "claude-3", + "description": "Anthropic Claude 3 (Thoughtful & Safe)" + }, + { + "id": "gemma3:8b", + "description": "Google Gemma 3 8B (Open Source)" + } + ], + "required": false + }, + "model-size": { + "type": "string", + "description": "Model size variant", + "default": "8b", + "enum": ["2b", "8b", "12b", "70b"], + "required": false + }, + "temperature": { + "type": "number", + "description": "Model temperature for generation", + "default": 0.7, + "minimum": 0.0, + "maximum": 2.0, + "required": false + }, + "chunk-size": { + "type": "integer", + "description": "Document chunk size", + "default": 512, + "minimum": 128, + "maximum": 2048, + "required": false + } +} +``` + +#### 带有参数引用的流程蓝图 + +流程蓝图定义了参数元数据,包括类型引用、描述和排序: + +```json +{ + "flow_class": "document-analysis", + "parameters": { + "llm-model": { + "type": "llm-model", + "description": "Primary LLM model for text completion", + "order": 1 + }, + "llm-rag-model": { + "type": "llm-model", + "description": "LLM model for RAG operations", + "order": 2, + "advanced": true, + "controlled-by": "llm-model" + }, + "llm-temperature": { + "type": "temperature", + "description": "Generation temperature for creativity control", + "order": 3, + "advanced": true + }, + "chunk-size": { + "type": "chunk-size", + "description": "Document chunk size for processing", + "order": 4, + "advanced": true + }, + "chunk-overlap": { + "type": "integer", + "description": "Overlap between document chunks", + "order": 5, + "advanced": true, + "controlled-by": "chunk-size" + } + }, + "class": { + "text-completion:{class}": { + "request": "non-persistent://tg/request/text-completion:{class}", + "response": "non-persistent://tg/response/text-completion:{class}", + "parameters": { + "model": "{llm-model}", + "temperature": "{llm-temperature}" + } + }, + "rag-completion:{class}": { + "request": "non-persistent://tg/request/rag-completion:{class}", + "response": "non-persistent://tg/response/rag-completion:{class}", + "parameters": { + "model": "{llm-rag-model}", + "temperature": "{llm-temperature}" + } + } + }, + "flow": { + "chunker:{id}": { + "input": "persistent://tg/flow/chunk:{id}", + "output": "persistent://tg/flow/chunk-load:{id}", + "parameters": { + "chunk_size": "{chunk-size}", + "chunk_overlap": "{chunk-overlap}" + } + } + } +} +``` + +`parameters` 部分将流程特定的参数名称(键)映射到包含以下内容的参数元数据对象: +`type`:对中心定义的参数定义的引用(例如,“llm-model”) +`description`:用于UI显示的易于理解的描述 +`order`:参数表单的显示顺序(较小的数字首先显示) +`advanced`(可选):布尔标志,指示是否为高级参数(默认:false)。如果设置为true,UI可能会默认隐藏此参数或将其放置在“高级”部分 +`controlled-by`(可选):控制此参数在简单模式下值的另一个参数的名称。如果指定,此参数将从控制参数继承其值,除非显式覆盖 + +这种方法允许: +在多个流程蓝图之间重用参数类型定义 +集中管理和验证参数类型 +流程特定的参数描述和排序 +通过描述性的参数表单增强UI体验 +流程中参数验证的一致性 +轻松添加新的标准参数类型 +通过基本/高级模式分离简化UI +相关设置的参数值继承 + +#### 流程启动请求 + +流程启动API使用流程的参数名称来接受参数: + +```json +{ + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "llm-model": "claude-3", + "llm-temperature": 0.5, + "chunk-size": 1024 + } +} +``` + +注意:在这个例子中,`llm-rag-model` 没有明确提供,但会从 `llm-model` 继承值 "claude-3",这是因为 `llm-rag-model` 与 `llm-model` 之间存在 `controlled-by` 关系。 类似地,`chunk-overlap` 可能会继承一个基于 `chunk-size` 计算的值。 + +系统将执行以下操作: +1. 从流程蓝图定义中提取参数元数据 +2. 将流程参数名称映射到其类型定义(例如,`llm-model` → `llm-model` 类型) +3. 解析受控关系(例如,`llm-rag-model` 从 `llm-model` 继承) +4. 验证用户提供的和继承的值是否符合参数类型定义 +5. 在流程实例化期间,将解析的值替换到处理器参数中 + +### 实现细节 + +#### 参数解析过程 + +当启动流程时,系统执行以下参数解析步骤: + +1. **流程蓝图加载**: 加载流程蓝图定义并提取参数元数据 +2. **元数据提取**: 提取每个参数的 `type`、`description`、`order`、`advanced` 和 `controlled-by`,这些信息位于流程蓝图的 `parameters` 部分 +3. **类型定义查找**: 对于流程蓝图中的每个参数: + 使用 `type` 字段从 schema/config 存储中检索参数类型定义 + 类型定义存储在配置系统中,类型为 "parameter-type" + 每个类型定义包含参数的 schema、默认值和验证规则 +4. **默认值解析**: + 对于流程蓝图中定义的每个参数: + 检查用户是否为该参数提供了值 + 如果未提供用户值,则使用参数类型定义中的 `default` 值 + 构建一个完整的参数映射,其中包含用户提供的和默认值 +5. **参数继承解析**(受控关系): + 对于具有 `controlled-by` 字段的参数,检查是否已显式提供值 + 如果未提供显式值,则从控制参数继承该值 + 如果控制参数也无值,则从类型定义中获取默认值 + 验证 `controlled-by` 关系中是否存在循环依赖 +6. **验证**: 验证完整的参数集(用户提供的、默认值和继承的值)是否符合类型定义 +7. **存储**: 将完整的解析后的参数集与流程实例一起存储,以进行审计 +8. **模板替换**: 使用解析后的值替换处理器参数中的参数占位符 +9. **处理器实例化**: 使用替换后的参数创建处理器 + +**重要的实现说明:** +流程服务必须将用户提供的参数与参数类型定义中的默认值合并 +完整的参数集(包括应用的默认值)必须与流程一起存储,以进行可追溯性 +参数解析发生在流程启动时间,而不是处理器实例化时间 +缺少没有默认值的必需参数会导致流程启动失败,并显示清晰的错误消息 + +#### 具有 controlled-by 的参数继承 + +`controlled-by` 字段启用参数值继承,这对于简化用户界面同时保持灵活性非常有用: + +**示例场景:** +`llm-model` 参数控制主要的 LLM 模型 +`llm-rag-model` 参数具有 `"controlled-by": "llm-model"` +在简单模式下,将 `llm-model` 设置为 "gpt-4" 会自动将 `llm-rag-model` 也设置为 "gpt-4" +在高级模式下,用户可以覆盖 `llm-rag-model` 并使用不同的值 + +**解析规则:** +1. 如果参数具有显式提供的值,则使用该值 +2. 如果没有显式值且 `controlled-by` 已设置,则使用控制参数的值 +3. 如果控制参数没有值,则回退到类型定义中的默认值 +4. `controlled-by` 关系中的循环依赖会导致验证错误 + +**UI 行为:** +在基本/简单模式下:具有 `controlled-by` 的参数可能被隐藏或显示为只读,并显示继承的值 +在高级模式下:显示所有参数,并且可以单独配置 +当控制参数更改时,依赖参数会自动更新,除非显式覆盖 + +#### Pulsar 集成 + +1. **启动流程操作** + Pulsar 启动流程操作需要接受一个 `parameters` 字段,该字段包含参数值的映射 + Pulsar 启动流程请求的 schema 必须更新为包含可选的 `parameters` 字段 + 示例请求: + ```json + { + "flow_class": "document-analysis", + "flow_id": "customer-A-flow", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +2. **获取流程操作** + 必须更新 Pulsar 模式,以包含 `parameters` 字段,用于获取流程的响应。 + 这允许客户端检索在启动流程时使用的参数值。 + 示例响应: + ```json + { + "flow_id": "customer-A-flow", + "flow_class": "document-analysis", + "status": "running", + "parameters": { + "model": "claude-3", + "size": "12b", + "temp": 0.5, + "chunk": 1024 + } + } + ``` + +#### 流程服务实现 + +流程配置服务 (`trustgraph-flow/trustgraph/config/service/flow.py`) 需要以下增强: + +1. **参数解析功能** + ```python + async def resolve_parameters(self, flow_class, user_params): + """ + Resolve parameters by merging user-provided values with defaults. + + Args: + flow_class: The flow blueprint definition dict + user_params: User-provided parameters dict + + Returns: + Complete parameter dict with user values and defaults merged + """ + ``` + + 此函数应该: + 从流程蓝图的 `parameters` 部分提取参数元数据 + 对于每个参数,从配置存储中获取其类型定义 + 为任何未由用户提供的参数应用默认值 + 处理 `controlled-by` 继承关系 + 返回完整的参数集 + +2. **修改后的 `handle_start_flow` 方法** + 在加载流程蓝图后调用 `resolve_parameters` + 使用完整的解析后的参数集进行模板替换 + 将完整的参数集(不仅仅是用户提供的)与流程一起存储 + 验证所有必需的参数是否具有值 + +3. **参数类型获取** + 参数类型定义存储在配置中,类型为 "parameter-type" + 每个类型定义包含模式、默认值和验证规则 + 缓存常用的参数类型以减少配置查找 + +#### 配置系统集成 + +3. **流程对象存储** + 当流程组件在配置管理器中向配置系统添加流程时,流程对象必须包含解析后的参数值 + 配置管理器需要同时存储原始的用户提供的参数和解析后的值(已应用默认值) + 配置系统中的流程对象应包含: + `parameters`: 用于流程的最终解析后的参数值 + +#### CLI 集成 + +4. **库 CLI 命令** + 启动流程的 CLI 命令需要参数支持: + 通过命令行标志或配置文件接受参数值 + 在提交之前,根据流程蓝图定义验证参数 + 支持参数文件输入(JSON/YAML),用于复杂的参数集 + + 显示流程的 CLI 命令需要显示参数信息: + 显示启动流程时使用的参数值 + 显示流程蓝图的可用参数 + 显示参数验证模式和默认值 + +#### 处理器基础类集成 + +5. **ParameterSpec 支持** + 处理器基础类需要支持通过现有的 ParametersSpec 机制进行参数替换 + 如果需要,应增强 ParametersSpec 类(位于与 ConsumerSpec 和 ProducerSpec 相同的模块中),以支持参数模板替换 + 处理器应能够调用 ParametersSpec 来使用在流程启动时解析的参数值配置其参数 + ParametersSpec 的实现需要: + 接受包含参数占位符(例如,`{model}`,`{temperature}`)的参数配置 + 在实例化处理器时,支持运行时参数替换 + 验证替换后的值是否符合预期的类型和约束 + 为缺失或无效的参数引用提供错误处理 + +#### 替换规则 + +参数使用格式 `{parameter-name}` 在处理器参数中 +参数名称与流程的 `parameters` 部分中的键匹配 +替换操作与 `{id}` 和 `{class}` 替换同时进行 +无效的参数引用会导致启动时出错 +基于中心存储的参数定义进行类型验证 +**重要提示**:所有参数值都以字符串形式存储和传输 + 数字转换为字符串(例如,`0.7` 变为 `"0.7"`) + 布尔值转换为小写字符串(例如,`true` 变为 `"true"`) + 这是由 Pulsar 模式要求的,该模式定义了 `parameters = Map(String())` + +示例解析: +``` +Flow parameter mapping: "model": "llm-model" +Processor parameter: "model": "{model}" +User provides: "model": "gemma3:8b" +Final parameter: "model": "gemma3:8b" + +Example with type conversion: +Parameter type default: 0.7 (number) +Stored in flow: "0.7" (string) +Substituted in processor: "0.7" (string) +``` + +## 测试策略 + +用于参数模式验证的单元测试 +用于处理器参数中参数替换的集成测试 +用于使用不同参数值启动流程的端到端测试 +用于参数表单生成和验证的 UI 测试 +用于具有许多参数的流程的性能测试 +边界情况:缺少参数、无效类型、未定义的参数引用 + +## 迁移计划 + +1. 系统应继续支持未声明参数的流程蓝图。 + 2. 系统应继续支持未指定参数的流程: +这适用于没有参数的流程,以及具有参数的流程(它们具有默认值)。 + + (它们有默认值)。 + +## 开放问题 + +问:参数是否应该支持复杂的嵌套对象,还是仅限于简单类型? +答:参数值将被字符串编码,我们可能更倾向于 + 使用字符串。 + +问:是否允许在队列名称中使用参数占位符,还是仅在 + 参数中使用? +答:仅在参数中使用,以避免奇怪的注入和边缘情况。 + +问:如何处理参数名称与系统变量(如 + `id` 和 `class`)之间的冲突? +答:在启动流程时,指定 id 和 class 是无效的。 + +问:我们是否应该支持计算参数(从其他参数派生)? +答:仅进行字符串替换,以避免奇怪的注入和边缘情况。 + +## 引用 + +JSON Schema 规范:https://json-schema.org/ +流程蓝图定义规范:docs/tech-specs/flow-class-definition.md diff --git a/docs/tech-specs/graph-contexts.pt.md b/docs/tech-specs/graph-contexts.pt.md new file mode 100644 index 00000000..404f199e --- /dev/null +++ b/docs/tech-specs/graph-contexts.pt.md @@ -0,0 +1,573 @@ +# Especificação Técnica dos Contextos de Grafos + +## Visão Geral + +Esta especificação descreve as alterações nos primitivos de grafo principais do TrustGraph para +estar em conformidade com o RDF 1.2 e suportar a semântica completa do Conjunto de Dados RDF. Esta é uma +alteração que causa incompatibilidade para a série de lançamento 2.x. + +### Versionamento + +**2.0**: Lançamento para usuários iniciais. Recursos principais disponíveis, mas pode não estar totalmente + pronto para produção. +**2.1 / 2.2**: Lançamento para produção. Estabilidade e completude validadas. + +A flexibilidade em relação à maturidade é intencional - os usuários iniciais podem acessar novos +recursos antes que todos os recursos sejam aprimorados para produção. + +## Objetivos + +Os principais objetivos deste trabalho são permitir metadados sobre fatos/declarações: + +**Informações temporais**: Associar fatos a metadados de tempo + Quando um fato foi considerado verdadeiro + Quando um fato se tornou verdadeiro + Quando um fato foi descoberto como falso + +**Proveniência/Fontes**: Rastrear quais fontes suportam um fato + "Este fato foi suportado pela fonte X" + Vincular fatos aos documentos de origem + +**Veracidade/Confiança**: Registrar afirmações sobre a verdade + "A pessoa P afirmou que isso era verdade" + "A pessoa Q afirma que isso é falso" + Permitir pontuação de confiança e detecção de conflitos + +**Hipótese**: A reificação (triplas RDF-star / citadas) é o mecanismo chave +para alcançar esses resultados, pois todos exigem fazer declarações sobre declarações. + +## Contexto + +Para expressar "o fato (Alice conhece Bob) foi descoberto em 2024-01-15" ou +"a fonte X suporta a afirmação (Y causa Z)", você precisa referenciar uma aresta +como algo sobre o qual você pode fazer declarações. Triplas padrão não suportam isso. + +### Limitações Atuais + +A classe `Value` atual em `trustgraph-base/trustgraph/schema/core/primitives.py` +pode representar: +Nós URI (`is_uri=True`) +Valores literais (`is_uri=False`) + +O campo `type` existe, mas não é usado para representar tipos de dados XSD. + +## Design Técnico + +### Recursos RDF a serem Suportados + +#### Recursos Principais (Relacionados aos Objetivos de Reificação) + +Esses recursos estão diretamente relacionados aos objetivos de tempo, proveniência e veracidade: + +1. **Triplas Citadas RDF 1.2 (RDF-star)** +Arestas que apontam para outras arestas + Uma Tripla pode aparecer como o sujeito ou objeto de outra Tripla + Permite declarações sobre declarações (reificação) + Mecanismo principal para anotar fatos individuais + +2. **Conjunto de Dados RDF / Grafos Nomeados** +Suporte para vários grafos nomeados dentro de um conjunto de dados + Cada grafo identificado por um IRI + Passa de triplas (s, p, o) para quads (s, p, o, g) + Inclui um grafo padrão, mais zero ou mais grafos nomeados + O IRI do grafo pode ser um sujeito em declarações, por exemplo: + O IRI do grafo pode ser o sujeito em declarações, por exemplo: + ``` + "2024-01-15" + "high" + ``` + Nota: Os grafos nomeados são uma funcionalidade separada da reificação. Eles têm + usos além da anotação de declarações (particionamento, controle de acesso, organização de conjuntos de dados) + e devem ser tratados como uma capacidade distinta. + +3. **Nós Anônimos** (Suporte Limitado) + Nós anônimos sem um URI global + Suportados para compatibilidade ao carregar dados RDF externos + **Status limitado**: Sem garantias sobre a identidade estável após o carregamento + Encontre-os por meio de consultas curinga (correspondência por conexões, não por ID) + Não é uma funcionalidade de primeira classe - não dependa de um tratamento preciso de nós anônimos + +#### Correções Oportunas (Mudança Incompatível 2.0) + +Esses recursos não estão diretamente relacionados aos objetivos da reificação, mas são +melhorias valiosas a serem incluídas ao mesmo tempo em que são feitas alterações incompatíveis: + +4. **Tipos de Dados Literais** + Use corretamente o campo `type` para tipos de dados XSD + Exemplos: xsd:string, xsd:integer, xsd:dateTime, etc. + Corrige a limitação atual: não é possível representar datas ou inteiros corretamente + +5. **Tags de Idioma** + Suporte para atributos de idioma em literais de string (@en, @fr, etc.) + Nota: Um literal tem uma tag de idioma OU um tipo de dados, não ambos + (exceto para rdf:langString) + Importante para casos de uso de IA/multilíngues + +### Modelos de Dados + +#### Termo (renomeado de Valor) + +A classe `Value` será renomeada para `Term` para melhor refletir a terminologia RDF. +Esta renomeação tem dois propósitos: +1. Alinha a nomenclatura com os conceitos RDF (um "Termo" pode ser um IRI, literal ou nó anônimo. + nó, ou tripla entre aspas - não apenas um "valor"). +2. Exige revisão de código na interface de alteração significativa - qualquer código que ainda + faça referência a `Value` estará visivelmente quebrado e precisará ser atualizado. + +Um Termo pode representar: + +**IRI/URI** - Um nó/recurso nomeado. +**Nó Anônimo** - Um nó anônimo com escopo local. +**Literal** - Um valor de dados com um dos seguintes: + Um tipo de dados (tipo XSD), OU + Uma etiqueta de idioma. +**Tripla Citada** - Uma tripla usada como um termo (RDF 1.2). + +##### Abordagem Escolhida: Classe Única com Discriminador de Tipo + +Os requisitos de serialização determinam a estrutura - um discriminador de tipo é necessário +no formato de transmissão, independentemente da representação em Python. Uma classe única com +um campo de tipo é a opção mais adequada e está alinhada com o padrão atual `Value`. + +Códigos de tipo de caractere único fornecem serialização compacta: + +```python +from dataclasses import dataclass + +# Term type constants +IRI = "i" # IRI/URI node +BLANK = "b" # Blank node +LITERAL = "l" # Literal value +TRIPLE = "t" # Quoted triple (RDF-star) + +@dataclass +class Term: + type: str = "" # One of: IRI, BLANK, LITERAL, TRIPLE + + # For IRI terms (type == IRI) + iri: str = "" + + # For blank nodes (type == BLANK) + id: str = "" + + # For literals (type == LITERAL) + value: str = "" + datatype: str = "" # XSD datatype URI (mutually exclusive with language) + language: str = "" # Language tag (mutually exclusive with datatype) + + # For quoted triples (type == TRIPLE) + triple: "Triple | None" = None +``` + +Exemplos de uso: + +```python +# IRI term +node = Term(type=IRI, iri="http://example.org/Alice") + +# Literal with datatype +age = Term(type=LITERAL, value="42", datatype="xsd:integer") + +# Literal with language tag +label = Term(type=LITERAL, value="Hello", language="en") + +# Blank node +anon = Term(type=BLANK, id="_:b1") + +# Quoted triple (statement about a statement) +inner = Triple( + s=Term(type=IRI, iri="http://example.org/Alice"), + p=Term(type=IRI, iri="http://example.org/knows"), + o=Term(type=IRI, iri="http://example.org/Bob"), +) +reified = Term(type=TRIPLE, triple=inner) +``` + +##### Alternativas Consideradas + +**Opção B: União de classes especializadas** (`Term = IRI | BlankNode | Literal | QuotedTriple`) +Rejeitada: A serialização ainda precisaria de um discriminador de tipo, adicionando complexidade. + +**Opção C: Classe base com subclasses** +Rejeitada: Mesmo problema de serialização, além de peculiaridades da herança de dataclasses. + +#### Tripla / Quádrupla + +A classe `Triple` ganha um campo de grafo opcional para se tornar uma quádrupla: + +```python +@dataclass +class Triple: + s: Term | None = None # Subject + p: Term | None = None # Predicate + o: Term | None = None # Object + g: str | None = None # Graph name (IRI), None = default graph +``` + +Decisões de design: +**Nome do campo**: `g` para consistência com `s`, `p`, `o` +**Opcional**: `None` significa o grafo padrão (sem nome) +**Tipo**: String simples (IRI) em vez de Termo + Os nomes dos grafos são sempre IRIs + Nodos vazios como nomes de grafos são descartados (muito confusos) + Não há necessidade da totalidade do mecanismo de Termos + +Nota: O nome da classe permanece `Triple` mesmo que tecnicamente seja um quad agora. +Isso evita mudanças e "tripla" ainda é a terminologia comum para a parte s/p/o. +O contexto do grafo é metadado sobre onde a tripla reside. + +### Padrões de Consulta Candidatos + +O mecanismo de consulta atual aceita combinações de termos S, P, O. Com triplas +entre aspas, uma tripla em si se torna um termo válido nessas posições. Abaixo estão +padrões de consulta candidatos que suportam os objetivos originais. + +#### Semântica do Parâmetro do Grafo + +Seguindo as convenções do SPARQL para compatibilidade com versões anteriores: + +**`g` omitido / Nenhum**: Consulta apenas o grafo padrão +**`g` = IRI específico**: Consulta apenas aquele grafo nomeado +**`g` = curinga / `*`**: Consulta em todos os grafos (equivalente ao SPARQL + `GRAPH ?g { ... }`) + +Isso mantém as consultas simples simples e torna as consultas de grafos nomeados opcionais. + +Consultas entre grafos (g=curinga) são totalmente suportadas. O esquema do Cassandra +inclui tabelas dedicadas (SPOG, POSG, OSPG) onde g é uma coluna de agrupamento +em vez de uma chave de partição, permitindo consultas eficientes em todos os grafos. + +#### Consultas Temporais + +**Encontre todos os fatos descobertos após uma determinada data:** +``` +S: ? # any quoted triple +P: +O: > "2024-01-15"^^xsd:date # date comparison +``` + +**Descubra quando um fato específico foi considerado verdadeiro:** +``` +S: << >> # quoted triple as subject +P: +O: ? # returns the date +``` + +**Encontre fatos que se tornaram falsos:** +``` +S: ? # any quoted triple +P: +O: ? # has any value (exists) +``` + +#### Consultas de Proveniência + +**Encontre todos os fatos suportados por uma fonte específica:** +``` +S: ? # any quoted triple +P: +O: +``` + +**Descubra quais fontes sustentam um fato específico:** +``` +S: << >> # quoted triple as subject +P: +O: ? # returns source IRIs +``` + +#### Consultas de Veracidade + +**Encontre as afirmações que uma pessoa marcou como verdadeiras:** +``` +S: ? # any quoted triple +P: +O: +``` + +**Encontre asserções conflitantes (mesmo fato, diferentes níveis de veracidade):** +``` +# First query: facts asserted true +S: ? +P: +O: ? + +# Second query: facts asserted false +S: ? +P: +O: ? + +# Application logic: find intersection of subjects +``` + +**Encontre fatos com uma pontuação de confiança abaixo do limite:** +``` +S: ? # any quoted triple +P: +O: < 0.5 # numeric comparison +``` + +### Arquitetura + +Mudanças significativas necessárias em vários componentes: + +#### Este Repositório (trustgraph) + +**Primitivos de esquema** (`trustgraph-base/trustgraph/schema/core/primitives.py`) + Renomeação de Value → Term + Nova estrutura de Term com discriminador de tipo + Triple ganha campo `g` para contexto do grafo + +**Tradutores de mensagens** (`trustgraph-base/trustgraph/messaging/translators/`) + Atualização para novas estruturas de Term/Triple + Serialização/desserialização para novos campos + +**Componentes de gateway** + Lidar com novas estruturas de Term e quad + +**Núcleos de conhecimento** + Mudanças no núcleo para suportar quads e reificação + +**Gerenciador de conhecimento** + Mudanças de esquema se propagam aqui + +**Camadas de armazenamento** + Cassandra: Redesenho do esquema (veja Detalhes de Implementação) + Outros backends: Adiado para fases posteriores + +**Utilitários de linha de comando** + Atualização para novas estruturas de dados + +**Documentação da API REST** + Atualizações da especificação OpenAPI + +#### Repositórios Externos + +**API Python** (este repositório) + Atualizações da biblioteca cliente para novas estruturas + +**APIs TypeScript** (repositório separado) + Atualizações da biblioteca cliente + +**Workbench** (repositório separado) + Mudanças significativas no gerenciamento de estado + +### APIs + +#### API REST + +Documentado na especificação OpenAPI +Será necessário atualizar para novas estruturas de Term/Triple +Novos endpoints podem ser necessários para operações de contexto do grafo + +#### API Python (este repositório) + +Mudanças na biblioteca cliente para corresponder a novos primitivos +Mudanças significativas em Term (era Value) e Triple + +#### API TypeScript (repositório separado) + +Mudanças paralelas à API Python +Coordenação de lançamento separada + +#### Workbench (repositório separado) + +Mudanças significativas no gerenciamento de estado +Atualizações da interface do usuário para recursos de contexto do grafo + +### Detalhes de Implementação + +#### Implementação de Armazenamento em Fases + +Existem vários backends de armazenamento de grafos (Cassandra, Neo4j, etc.). A implementação +seguirá em fases: + +1. **Fase 1: Cassandra** + Começar com o armazenamento Cassandra próprio + O controle total sobre a camada de armazenamento permite iteração rápida + O esquema será redesenhado do zero para quads + reificação + Validar o modelo de dados e os padrões de consulta em relação a casos de uso reais + +#### Design de Esquema do Cassandra + +O Cassandra requer múltiplas tabelas para suportar diferentes padrões de acesso a consultas +(cada tabela consulta de forma eficiente pela sua chave de partição + colunas de agrupamento). + +##### Padrões de Consulta + +Com quads (g, s, p, o), cada posição pode ser especificada ou curinga, dando +16 padrões de consulta possíveis: + +| # | g | s | p | o | Descrição | +|---|---|---|---|---|-------------| +| 1 | ? | ? | ? | ? | Todos os quads | +| 2 | ? | ? | ? | o | Por objeto | +| 3 | ? | ? | p | ? | Por predicado | +| 4 | ? | ? | p | o | Por predicado + objeto | +| 5 | ? | s | ? | ? | Por sujeito | +| 6 | ? | s | ? | o | Por sujeito + objeto | +| 7 | ? | s | p | ? | Por sujeito + predicado | +| 8 | ? | s | p | o | Tripla completa (quais grafos?) | +| 9 | g | ? | ? | ? | Por grafo | +| 10 | g | ? | ? | o | Por grafo + objeto | +| 11 | g | ? | p | ? | Por grafo + predicado | +| 12 | g | ? | p | o | Por grafo + predicado + objeto | +| 13 | g | s | ? | ? | Por grafo + sujeito | +| 14 | g | s | ? | o | Por grafo + sujeito + objeto | +| 15 | g | s | p | ? | Por grafo + sujeito + predicado | +| 16 | g | s | p | o | Quad exato | + +##### Design de Tabela + +Restrição do Cassandra: Você só pode consultar de forma eficiente pela chave de partição e, em seguida, +filtrar nas colunas de agrupamento da esquerda para a direita. Para consultas com curinga "g", "g" deve ser +uma coluna de agrupamento. Para consultas com "g" especificado, "g" na chave de partição é mais +eficiente. + +**Duas famílias de tabelas necessárias:** + +**Família A: consultas com curinga "g"** (g em colunas de agrupamento) + +| Tabela | Partição | Agrupamento | Suporta padrões | +|-------|-----------|------------|-------------------| +| SPOG | (user, collection, s) | p, o, g | 5, 7, 8 | +| POSG | (user, collection, p) | o, s, g | 3, 4 | +| OSPG | (user, collection, o) | s, p, g | 2, 6 | + +**Família B: consultas com "g" especificado** (g na chave de partição) + +| Tabela | Partição | Agrupamento | Suporta padrões | +|-------|-----------|------------|-------------------| +| GSPO | (user, collection, g, s) | p, o | 9, 13, 15, 16 | +| GPOS | (user, collection, g, p) | o, s | 11, 12 | +| GOSP | (user, collection, g, o) | s, p | 10, 14 | + +**Tabela de coleção** (para iteração e exclusão em massa) + +| Tabela | Partição | Agrupamento | Propósito | +|-------|-----------|------------|---------| +| COLL | (user, collection) | g, s, p, o | Enumerar todos os quads na coleção | + +##### Caminhos de Escrita e Exclusão + +**Caminho de escrita**: Inserir em todas as 7 tabelas. + +**Caminho de exclusão da coleção**: +1. Iterar na tabela COLL para `(user, collection)` +2. Para cada quad, excluir de todas as 6 tabelas de consulta +3. Excluir da tabela COLL (ou exclusão por intervalo) + +**Caminho de exclusão de um único quad**: Excluir diretamente de todas as 7 tabelas. + +##### Custo de Armazenamento + +Cada quad é armazenado 7 vezes. Este é o custo da consulta flexível combinada +com exclusão eficiente da coleção. + +##### Triplas Citadas no Armazenamento + +O sujeito ou o objeto podem ser uma tripla em si. Opções: + +**Opção A: Serializar triplas citadas para string canônica** +``` +S: "<>" +P: http://ex/discoveredOn +O: "2024-01-15" +G: null +``` +Armazenar a tripla citada como uma string serializada nas colunas S ou O. +Consultar por correspondência exata na forma serializada. +Prós: Simples, se encaixa em padrões de índice existentes. +Contras: Não é possível consultar "encontrar triplas onde o predicado do sujeito citado é X". + +**Opção B: IDs / Hashes de Triplas** +``` +Triple table: + id: hash(s,p,o,g) + s, p, o, g: ... + +Metadata table: + subject_triple_id: + p: http://ex/discoveredOn + o: "2024-01-15" +``` +Atribua a cada tripla um ID (hash dos componentes) +As referências de metadados de reificação referenciam as triplas por ID +Prós: Separação limpa, pode indexar os IDs das triplas +Contras: Requer o cálculo/gerenciamento da identidade da tripla, pesquisas em duas fases + +**Recomendação**: Comece com a Opção A (strings serializadas) para simplificar. +A Opção B pode ser necessária se forem necessários padrões de consulta avançados sobre triplas com aspas +componentes. + +2. **Fase 2+: Outros Backends** + Neo4j e outros armazenamentos implementados em estágios subsequentes + As lições aprendidas com o Cassandra informam essas implementações + +Esta abordagem reduz os riscos do projeto, validando em um backend totalmente controlado +antes de implementar em todos os armazenamentos. + +#### Renomear Classe de Valor → Termo + +A classe `Value` será renomeada para `Term`. Isso afeta aproximadamente 78 arquivos em +todo o código-fonte. A renomeação funciona como um fator de força: qualquer código que ainda use +`Value` pode ser identificado imediatamente como precisando de revisão/atualização para compatibilidade com a versão 2.0 + + +## Considerações de Segurança + +Os grafos nomeados não são um recurso de segurança. Usuários e coleções permanecem +como os limites de segurança. Os grafos nomeados são puramente para organização de dados e +suporte de reificação. + +## Considerações de Desempenho + +Triplas com aspas adicionam profundidade de aninhamento - podem afetar o desempenho da consulta +Estratégias de indexação de grafos nomeados necessárias para consultas eficientes com escopo de grafo +O design do esquema do Cassandra precisará acomodar o armazenamento de quads de forma eficiente + +### Limite do Armazenamento Vetorial + +Os armazenamentos vetoriais sempre referenciam apenas IRIs: +Nunca arestas (triplas com aspas) +Nunca valores literais +Nunca nós vazios + +Isso mantém o armazenamento vetorial simples - ele lida com a similaridade semântica de entidades nomeadas. A estrutura do grafo lida com relacionamentos, reificação e metadados. +Triplas com aspas e grafos nomeados não complicam as operações vetoriais. + +## Estratégia de Teste + +Use a estratégia de teste existente. Como esta é uma alteração disruptiva, concentre-se extensivamente no +conjunto de testes de ponta a ponta para validar que as novas estruturas funcionam corretamente em +todos os componentes. + + +## Plano de Migração + +A versão 2.0 é uma versão disruptiva; nenhuma compatibilidade com versões anteriores é necessária +Os dados existentes podem precisar ser migrados para um novo esquema (a ser definido com base no design final) +Considere ferramentas de migração para converter triplas existentes + +## Perguntas Abertas + +**Nós vazios**: Suporte limitado confirmado. Pode ser necessário decidir sobre + estratégia de skolemização (gerar IRIs na carga, ou preservar os IDs dos nós vazios). +**Sintaxe de consulta**: Qual é a sintaxe concreta para especificar triplas com aspas + em consultas? É necessário definir a API de consulta. +~~**Vocabulário de predicados**~~: Resolvido. Qualquer predicado RDF válido é permitido, + incluindo vocabulários personalizados do usuário. Mínimas suposições sobre a validade do RDF. + Pouquíssimos valores fixos (por exemplo, `rdfs:label` usado em alguns lugares). + Estratégia: evite fixar qualquer coisa, a menos que seja absolutamente necessário. +~~**Impacto no armazenamento vetorial**~~: Resolvido. Os armazenamentos vetoriais sempre apontam para IRIs + apenas - nunca arestas, literais ou nós vazios. Triplas com aspas e + a reificação não afetam o armazenamento vetorial. +~~**Semântica do grafo nomeado**~~: Resolvido. As consultas padrão + para o grafo padrão (corresponde ao comportamento do SPARQL, compatível com versões anteriores). Parâmetro de grafo explícito + necessário para consultar grafos nomeados ou todos os grafos. + +## Referências + +[Conceitos RDF 1.2](https://www.w3.org/TR/rdf12-concepts/) +[RDF-star e SPARQL-star](https://w3c.github.io/rdf-star/) +[Conjunto de dados RDF](https://www.w3.org/TR/rdf11-concepts/#section-dataset) diff --git a/docs/tech-specs/graph-contexts.tr.md b/docs/tech-specs/graph-contexts.tr.md new file mode 100644 index 00000000..169091bb --- /dev/null +++ b/docs/tech-specs/graph-contexts.tr.md @@ -0,0 +1,573 @@ +# Graph Contexts Technical Specification + +## Overview + +Bu özellik, TrustGraph'ın temel grafik yapılarına yapılan değişiklikleri tanımlar ve +RDF 1.2 ile uyumlu olacak ve tam RDF Dataset semantiğini destekleyecek şekilde tasarlanmıştır. Bu, 2.x yayın serisi için önemli bir değişikliktir. + + +### Versioning + +**2.0**: Erken benimseyen sürüm. Temel özellikler mevcut, ancak henüz tamamen + üretim ortamına hazır olmayabilir. +**2.1 / 2.2**: Üretim sürümü. Kararlılık ve eksiksizlik doğrulandı. + +Olgunluk konusundaki esneklik kasıtlıdır; erken benimseyenler, tüm özellikler +üretim ortamına hazır hale gelmeden önce yeni yeteneklere erişebilir. + +## Goals + +Bu çalışmanın temel hedefleri, gerçekler/ifadeler hakkında meta veri sağlamaktır: + +**Zaman bilgisi**: Gerçekleri zamanla ilgili bilgilerle ilişkilendirme + Bir gerçeğin doğru olduğu düşünüldüğü zaman + Bir gerçeğin doğru hale geldiği zaman + Bir gerçeğin yanlış olduğu tespit edildiği zaman + +**Kaynak/Köken**: Bir gerçeği destekleyen kaynakları izleme + "Bu gerçek, X kaynağı tarafından desteklenmektedir" + Gerçekleri, köken belgelerine bağlama + +**Doğruluk/Güven**: Gerçekler hakkındaki iddiaları kaydetme + "Kişi P, bunun doğru olduğunu iddia etti" + "Kişi Q, bunun yanlış olduğunu iddia ediyor" + Güven puanlamasını ve çakışma tespitini etkinleştirme + +**Hipotez**: Yeniden tanımlama (RDF-star / tırnak işaretli üçlüler), bu sonuçları +elde etmek için temel mekanizmadır, çünkü bunların hepsi ifadeler hakkında ifadeler yapmayı gerektirir. + +## Background + +"Alice'in Bob'u tanıdığı" gerçeğinin "2024-01-15" tarihinde keşfedildiğini veya +"X kaynağının (Y'nin Z'ye neden olduğu) iddiasını desteklediğini" ifade etmek için, +bir kenara bir şey olarak başvurmanız ve bu kenar hakkında ifadeler yapabilmeniz gerekir. Standart üçlüler bunu desteklemez. + +### Current Limitations + +Mevcut `Value` sınıfı `trustgraph-base/trustgraph/schema/core/primitives.py` içinde +şunları temsil edebilir: +URI düğümleri (`is_uri=True`) +Literal değerler (`is_uri=False`) + +`type` alanı mevcuttur, ancak XSD veri türlerini temsil etmek için kullanılmaz. + +## Technical Design + +### RDF Features to Support + +#### Core Features (Related to Reification Goals) + +Bu özellikler, zaman, kaynak ve doğruluk hedefleriyle doğrudan ilgilidir: + +1. **RDF 1.2 Quoted Triples (RDF-star)** +Diğer kenarlara işaret eden kenarlar + Bir Üçlü, başka bir Üçlünün konusu veya nesnesi olabilir + İfadeler hakkında ifadeler yapmayı sağlar (yeniden tanımlama) + Bireysel gerçekleri açıklamak için temel mekanizma + +2. **RDF Dataset / Named Graphs** +Bir veri kümesi içindeki birden fazla adlandırılmış grafik için destek + Her grafik bir IRI ile tanımlanır + Üçlülerden (s, p, o) dörtlülere (s, p, o, g) geçiş + Bir varsayılan grafik ve sıfır veya daha fazla adlandırılmış grafik içerir + Grafik IRI'si, ifadelerin konusu olabilir, örneğin: + Grafik IRI'si, ifadelerde bir özne olabilir, örneğin: + ``` + "2024-01-15" + "high" + ``` + Not: Adlandırılmış grafikler, somutlaştırmadan ayrı bir özelliktir. Bunlar, + yalnızca ifade açıklamasının ötesinde kullanımlara sahiptir (bölümleme, erişim kontrolü, veri kümesi + organizasyonu) ve ayrı bir yetenek olarak ele alınmalıdır. + +3. **Anonim Düğümler** (Sınırlı Destek) + Küresel bir URI'ye sahip olmayan anonim düğümler + Dış RDF verilerini yüklerken uyumluluk için desteklenir + **Sınırlı durum:** Yükleme işleminden sonra kararlı bir kimlik konusunda hiçbir garanti yoktur + Bunları jokerli sorgular aracılığıyla bulun (bağlantılara göre, kimliğe göre değil) + Birincil bir özellik değildir - kesin anonim düğüm işleme özelliğine güvenmeyin + +#### Fırsatçı Düzeltmeler (2.0'ın Kırıcı Değişikliği) + +Bu özellikler, somutlaştırma hedefleriyle doğrudan ilişkili değildir, ancak +kırıcı değişiklikler yaparken dahil edilmesi değerli olan iyileştirmelerdir: + +4. **Literal Veri Tipleri** + XSD veri tipleri için `type` alanını doğru şekilde kullanın + Örnekler: xsd:string, xsd:integer, xsd:dateTime, vb. + Mevcut sınırlamayı düzeltir: tarihleri veya tamsayıları düzgün bir şekilde temsil edilemez + +5. **Dil Etiketleri** + Dize literal değerleri üzerinde dil öznitelikleri desteği (@en, @fr, vb.) + Not: Bir literal değerin ya bir dil etiketi YA da bir veri tipi vardır, ikisi birden değil + (rdf:langString hariç) + Yapay zeka/çok dilli kullanım senaryoları için önemlidir + +### Veri Modelleri + +#### Terim (Value adından değiştirildi) + +`Value` sınıfı, RDF terminolojisini daha iyi yansıtmak için `Term` olarak yeniden adlandırılacaktır. +Bu yeniden adlandırma iki amaca hizmet etmektedir: +1. İsimlendirmeyi RDF kavramlarıyla uyumlu hale getirmek (bir "Terim", bir IRI, literal, boş + düğüm veya tırnak içindeki üçlü olabilir - sadece bir "değer" değildir). +2. Değişikliklere neden olan arayüzde kod incelemesini zorlamak - hala + `Value`'a referans veren herhangi bir kod, açıkça hatalıdır ve güncellenmesi gerekir. + +Bir Terim şunları temsil edebilir: + +**IRI/URI** - Adlandırılmış bir düğüm/kaynak +**Boş Düğüm** - Yerel kapsamı olan anonim bir düğüm +**Literal (Değer)** - Ya bir veri türü (XSD türü) veya + Bir dil etiketi + **Tırnak İçine Alınmış Üçlü** - Bir terim olarak kullanılan bir üçlü (RDF 1.2) + + +##### Seçilen Yaklaşım: Tip Ayırıcısı Olan Tek Sınıf + +Serileştirme gereksinimleri yapıyı belirler - bir tür ayrımcısına ihtiyaç vardır. +Python gösteriminden bağımsız olarak, kablo formatında bir tür ayrımcısına ihtiyaç vardır. +Tek bir sınıf ve bir tür alanı, doğal bir çözümdür ve mevcut `Value` kalıbıyla uyumludur. + +Tek karakterli tür kodları, kompakt serileştirme sağlar: + +```python +from dataclasses import dataclass + +# Term type constants +IRI = "i" # IRI/URI node +BLANK = "b" # Blank node +LITERAL = "l" # Literal value +TRIPLE = "t" # Quoted triple (RDF-star) + +@dataclass +class Term: + type: str = "" # One of: IRI, BLANK, LITERAL, TRIPLE + + # For IRI terms (type == IRI) + iri: str = "" + + # For blank nodes (type == BLANK) + id: str = "" + + # For literals (type == LITERAL) + value: str = "" + datatype: str = "" # XSD datatype URI (mutually exclusive with language) + language: str = "" # Language tag (mutually exclusive with datatype) + + # For quoted triples (type == TRIPLE) + triple: "Triple | None" = None +``` + +Kullanım örnekleri: + +```python +# IRI term +node = Term(type=IRI, iri="http://example.org/Alice") + +# Literal with datatype +age = Term(type=LITERAL, value="42", datatype="xsd:integer") + +# Literal with language tag +label = Term(type=LITERAL, value="Hello", language="en") + +# Blank node +anon = Term(type=BLANK, id="_:b1") + +# Quoted triple (statement about a statement) +inner = Triple( + s=Term(type=IRI, iri="http://example.org/Alice"), + p=Term(type=IRI, iri="http://example.org/knows"), + o=Term(type=IRI, iri="http://example.org/Bob"), +) +reified = Term(type=TRIPLE, triple=inner) +``` + +##### Alternatifler + +**B Seçeneği: Özel sınıfların birleşimi** (`Term = IRI | BlankNode | Literal | QuotedTriple`) +Reddedildi: Seri hale getirme işlemi hala bir tür belirleyici gerektirecek, bu da karmaşıklığı artıracaktır. + +**C Seçeneği: Alt sınıflara sahip temel sınıf** +Reddedildi: Aynı seri hale getirme sorunu, ayrıca dataclass miras özellikleriyle ilgili sorunlar. + +#### Üçlü / Dörtlü + +`Triple` sınıfı, isteğe bağlı bir grafik alanı kazanarak dörtlü bir yapıya dönüşebilir: + +```python +@dataclass +class Triple: + s: Term | None = None # Subject + p: Term | None = None # Predicate + o: Term | None = None # Object + g: str | None = None # Graph name (IRI), None = default graph +``` + +Tasarım kararları: +**Alan adı**: `g`, `s`, `p` ve `o` ile tutarlılık için. +**İsteğe bağlı**: `None`, varsayılan grafiği (isim belirtilmemiş) ifade eder. +**Tip**: Terim yerine düz bir dize (IRI). + Grafik adları her zaman IRI'lerdir. + Boş düğümlerin grafik adı olarak kullanılması reddedildi (çok kafa karıştırıcı). + Tam Terim mekanizmasına ihtiyaç yok. + +Not: Sınıf adı teknik olarak bir dörtlü olsa bile `Triple` olarak kalır. +Bu, karmaşayı önler ve "üçlü" terimi hala s/p/o kısmı için yaygın olarak kullanılan bir terimdir. Grafik bağlamı, üçlünün nerede bulunduğu hakkında meta veridir. + + +### Olası Sorgu Desenleri + +Mevcut sorgu motoru, S, P, O terimlerinin kombinasyonlarını kabul eder. Tırnak içinde belirtilen +üçlüler, bir üçlünün kendisi bu konumlarda geçerli bir terim haline gelir. Aşağıda, +orijinal hedefleri destekleyen olası sorgu desenleri bulunmaktadır. + +#### Grafik Parametre Anlamları + +Geriye dönük uyumluluk için SPARQL kurallarına uygun olarak: + +**`g` belirtilmemiş / Yok**: Yalnızca varsayılan grafiği sorgula. +**`g` = belirli bir IRI**: Yalnızca o adlandırılmış grafiği sorgula. +**`g` = joker karakter / `*`**: Tüm grafikler arasında sorgu yap (SPARQL ile eşdeğer + `GRAPH ?g { ... }`). + +Bu, basit sorguları basit tutar ve adlandırılmış grafik sorgularını isteğe bağlı hale getirir. + +Grafik arası sorgular (g=joker karakter), tamamen desteklenir. Cassandra şeması, +g'nin bir kümeleme sütunu olduğu (bölüm anahtarı olmadığı) özel tabloları içerir (SPOG, POSG, OSPG), +bu da tüm grafikler arasında verimli sorgular yapmayı sağlar. + +#### Zamansal Sorgular + +**Belirli bir tarihten sonra keşfedilen tüm bilgileri bul:** +``` +S: ? # any quoted triple +P: +O: > "2024-01-15"^^xsd:date # date comparison +``` + +**Belirli bir bilginin ne zaman doğru olduğuna inanıldığı bulun:** +``` +S: << >> # quoted triple as subject +P: +O: ? # returns the date +``` + +**Yanlış hale gelen bilgileri bulun:** +``` +S: ? # any quoted triple +P: +O: ? # has any value (exists) +``` + +#### Kaynak Sorguları + +**Belirli bir kaynağa dayanan tüm bilgileri bulun:** +``` +S: ? # any quoted triple +P: +O: +``` + +**Belirli bir gerçeği destekleyen kaynakları bulun:** +``` +S: << >> # quoted triple as subject +P: +O: ? # returns source IRIs +``` + +#### Doğruluk Sorguları + +**Bir kişinin doğru olarak işaretlediği ifadeleri bulun:** +``` +S: ? # any quoted triple +P: +O: +``` + +**Çelişkili ifadeleri bulun (aynı gerçek, farklı doğruluk):** +``` +# First query: facts asserted true +S: ? +P: +O: ? + +# Second query: facts asserted false +S: ? +P: +O: ? + +# Application logic: find intersection of subjects +``` + +**Güvenilirlik puanı eşik değerinin altında olan bilgileri bulun:** +``` +S: ? # any quoted triple +P: +O: < 0.5 # numeric comparison +``` + +### Mimari + +Birden çok bileşende önemli değişiklikler gereklidir: + +#### Bu Depo (trustgraph) + +**Şema ilkel öğeleri** (`trustgraph-base/trustgraph/schema/core/primitives.py`) + Değer → Terim yeniden adlandırması + Tip ayrımcısına sahip yeni Terim yapısı + Üçlü, grafik bağlamı için `g` alanı kazanır + +**Mesaj çeviricileri** (`trustgraph-base/trustgraph/messaging/translators/`) + Yeni Terim/Üçlü yapıları için güncelleme + Yeni alanlar için serileştirme/deserileştirme + +**Geçit bileşenleri** + Yeni Terim ve dörtlü yapılarını işleyin + +**Bilgi çekirdekleri** + Dörtlüleri ve yeniden tanımlamayı desteklemek için çekirdek değişiklikleri + +**Bilgi yöneticisi** + Şema değişiklikleri burada yayılır + +**Depolama katmanları** + Cassandra: Şema yeniden tasarımı (Ayrıntılar için Uygulama Ayrıntılarına bakın) + Diğer arka uçlar: Daha sonraki aşamalara ertelenmiştir + +**Komut satırı araçları** + Yeni veri yapıları için güncelleme + +**REST API dokümantasyonu** + OpenAPI spesifikasyonunda güncellemeler + +#### Harici Depolar + +**Python API'si** (bu depo) + Yeni yapılar için istemci kitaplığı güncellemeleri + +**TypeScript API'leri** (ayrı depo) + İstemci kitaplığı güncellemeleri + +**Çalışma alanı** (ayrı depo) + Önemli durum yönetimi değişiklikleri + +### API'ler + +#### REST API + +OpenAPI spesifikasyonunda belgelenmiştir +Yeni Terim/Üçlü yapıları için güncellenmesi gerekecektir +Grafik bağlamı işlemleri için yeni uç noktaları gerekebilir + +#### Python API'si (bu depo) + +Yeni ilkel öğelerle eşleşen istemci kitaplığı değişiklikleri +Terim (önceden Değer) ve Üçlü için bozucu değişiklikler + +#### TypeScript API'si (ayrı depo) + +Python API'sine paralel değişiklikler +Ayrı sürüm koordinasyonu + +#### Çalışma alanı (ayrı depo) + +Önemli durum yönetimi değişiklikleri +Grafik bağlamı özellikleriyle ilgili kullanıcı arayüzü güncellemeleri + +### Uygulama Ayrıntıları + +#### Aşamalı Depolama Uygulaması + +Birden çok grafik depolama arka ucu (Cassandra, Neo4j, vb.) vardır. Uygulama +aşağıdaki aşamalarda gerçekleştirilecektir: + +1. **1. Aşama: Cassandra** + Yerel Cassandra deposuyla başlayın + Depolama katmanı üzerinde tam kontrol, hızlı yinelemeyi sağlar + Şema, dörtlüler + yeniden tanımlama için sıfırdan yeniden tasarlanacaktır + Veri modelini ve sorgu kalıplarını gerçek kullanım durumlarına göre doğrulayın + +#### Cassandra Şema Tasarımı + +Cassandra, farklı sorgu erişim modellerini desteklemek için birden fazla tablo gerektirir +(her tablo, bölüm anahtarı + kümeleme sütunları aracılığıyla verimli bir şekilde sorgulanır). + +##### Sorgu Modelleri + +"quads" (g, s, p, o) ile, her konum belirtilebilir veya joker karakter olabilir ve bu da +16 olası sorgu modeli oluşturur: + +| # | g | s | p | o | Açıklama | +|---|---|---|---|---|-------------| +| 1 | ? | ? | ? | ? | Tüm "quads" | +| 2 | ? | ? | ? | o | Nesneye göre | +| 3 | ? | ? | p | ? | Özneye göre | +| 4 | ? | ? | p | o | Özne + nesneye göre | +| 5 | ? | s | ? | ? | Konuya göre | +| 6 | ? | s | ? | o | Konu + nesneye göre | +| 7 | ? | s | p | ? | Konu + öneye göre | +| 8 | ? | s | p | o | Tam üçlü (hangi grafikler?) | +| 9 | g | ? | ? | ? | Grafiğe göre | +| 10 | g | ? | ? | o | Grafik + nesneye göre | +| 11 | g | ? | p | ? | Grafik + öneye göre | +| 12 | g | ? | p | o | Grafik + öne + nesneye göre | +| 13 | g | s | ? | ? | Grafik + konuya göre | +| 14 | g | s | ? | o | Grafik + konu + nesneye göre | +| 15 | g | s | p | ? | Grafik + konu + öneye göre | +| 16 | g | s | p | o | Tam "quad" | + +##### Tablo Tasarımı + +Cassandra kısıtlaması: Yalnızca bölüm anahtarına göre verimli bir şekilde sorgulayabilirsiniz, ardından +kümeleme sütunları üzerinde soldan sağa filtreleme yapabilirsiniz. "g" joker karakterli sorgular için, "g" bir +kümeleme sütunu olmalıdır. "g" belirtilmiş sorgular için, bölüm anahtarında bulunan "g" daha +verimlidir. + +**İki tablo ailesi gereklidir:** + +**A Ailesi: "g" joker karakterli sorgular** ("g" kümeleme sütunlarında) + +| Tablo | Bölüm | Kümeleme | Desteklenen modeller | +|-------|-----------|------------|-------------------| +| SPOG | (kullanıcı, koleksiyon, s) | p, o, g | 5, 7, 8 | +| POSG | (kullanıcı, koleksiyon, p) | o, s, g | 3, 4 | +| OSPG | (kullanıcı, koleksiyon, o) | s, p, g | 2, 6 | + +**B Ailesi: "g" belirtilmiş sorgular** ("g" bölüm anahtarında) + +| Tablo | Bölüm | Kümeleme | Desteklenen modeller | +|-------|-----------|------------|-------------------| +| GSPO | (kullanıcı, koleksiyon, g, s) | p, o | 9, 13, 15, 16 | +| GPOS | (kullanıcı, koleksiyon, g, p) | o, s | 11, 12 | +| GOSP | (kullanıcı, koleksiyon, g, o) | s, p | 10, 14 | + +**Koleksiyon tablosu** (döngüleme ve toplu silme için) + +| Tablo | Bölüm | Kümeleme | Amaç | +|-------|-----------|------------|---------| +| COLL | (kullanıcı, koleksiyon) | g, s, p, o | Koleksiyondaki tüm "quad"ları numaralandır | + +##### Yazma ve Silme Yolları + +**Yazma yolu**: Tüm 7 tabloya ekleyin. + +**Koleksiyon silme yolu**: +1. `(user, collection)` için COLL tablosunu yineleyin +2. Her "quad" için, tüm 6 sorgu tablosundan silin +3. COLL tablosundan silin (veya aralık silme) + +**Tek bir "quad" silme yolu**: Tüm 7 tabloya doğrudan silin. + +##### Depolama Maliyeti + +Her "quad" 7 kez depolanır. Bu, esnek sorgulama ile +verimli koleksiyon silme birleşiminin maliyetidir. + +##### Depolamada Alıntılanmış Üçlüler + +Konu veya nesne kendisi bir üçlü olabilir. Seçenekler: + +**A Seçeneği: Alıntılanmış üçlüleri standart bir dizeye seri hale getirin** +``` +S: "<>" +P: http://ex/discoveredOn +O: "2024-01-15" +G: null +``` +Tırnak içinde belirtilen üçlüleri, seri hale getirilmiş bir dize olarak S veya O sütunlarında saklayın. +Seri hale getirilmiş forma göre tam eşleşme ile sorgulayın. +Artı: Basit, mevcut indeks kalıplarına uyuyor. +Eksileri: "Tırnak içinde belirtilen öznenin yüklemesinin X olduğu üçlüleri bul" gibi sorguları yapmak mümkün değil. + +**B Seçeneği: Üçlü Kimlikleri / Hash'leri** +``` +Triple table: + id: hash(s,p,o,g) + s, p, o, g: ... + +Metadata table: + subject_triple_id: + p: http://ex/discoveredOn + o: "2024-01-15" +``` +Her üçlüye bir kimlik (bileşenlerin karma değeri) atayın. +Örnek meta veri referansları, kimlik numarasıyla üçlüleri belirtir. +Artı: Temiz bir ayrım, üçlü kimlik numaralarının indekslenmesini sağlar. +Eksileri: Üçlü kimliğinin hesaplanmasını/yönetilmesini gerektirir, iki aşamalı aramalar. + +**Öneri**: Basitlik için A seçeneğiyle (serileştirilmiş dizeler) başlayın. +B seçeneği, tırnak içinde belirtilen üçlü bileşenleri üzerinde gelişmiş sorgu desenleri gerekiyorsa gerekebilir. + +ÇIKTI SÖZLEŞMESİ (tam olarak aşağıdaki formatı takip etmelidir): +2. **2. Aşama+: Diğer Altyapılar** + Neo4j ve diğer depolama sistemleri, sonraki aşamalarda uygulanmıştır. + Cassandra'dan edinilen deneyimler, bu uygulamaları etkilemiştir. + +Bu yaklaşım, tamamen kontrol altında olan bir altyapıda doğrulama yaparak tasarım riskini azaltır. +Tüm depolama sistemlerine yönelik uygulamalara başlamadan önce bu doğrulama yapılır. + +#### Değer → Terim Yeniden Adlandırma + +`Value` sınıfı, `Term` olarak yeniden adlandırılacaktır. Bu, kod tabanındaki yaklaşık 78 dosyayı etkilemektedir. +Yeniden adlandırma, bir zorlama işlevi olarak görev görmektedir: hala ⟦CODE_0⟧'ı kullanan herhangi bir kod... +`Value`, 2.0 ile uyumluluk açısından gözden geçirilmesi/güncellenmesi gereken bir alan olarak hemen belirlenebilir. + + +## Güvenlik Hususları + +Adlandırılmış grafikler bir güvenlik özelliği değildir. Kullanıcılar ve koleksiyonlar, +güvenlik sınırlarıdır. Adlandırılmış grafikler tamamen veri organizasyonu ve +somutlaştırma desteği içindir. + +## Performans Hususları + +Tırnak işaretli üçlüler, iç içe derinliğini artırır - sorgu performansını etkileyebilir. +Verimli grafik kapsamlı sorgular için adlandırılmış grafik indeksleme stratejilerine ihtiyaç vardır. +Cassandra şema tasarımı, dörtlü depolamayı verimli bir şekilde karşılayacak şekilde tasarlanmalıdır. + +### Vektör Depolama Sınırı + +Vektör depoları her zaman yalnızca IRI'lere başvurur: +Asla kenarlar (tırnak işaretli üçlüler) +Asla literal değerler +Asla boş düğümler + +Bu, vektör deposunu basit tutar; adlandırılmış varlıkların semantik benzerliğini işler. Grafik yapısı, ilişkileri, somutlaştırmayı ve meta verileri yönetir. +Tırnak içinde belirtilen üçlüler ve adlandırılmış grafikler, vektör işlemlerini karmaşıklaştırmaz. + +## Test Stratejisi + +Mevcut test stratejisini kullanın. Bu, önemli bir değişiklik olduğundan, yeni yapıların tüm bileşenlerde doğru şekilde çalıştığını doğrulamak için uçtan uca test paketine kapsamlı bir şekilde odaklanılmalıdır. + +## Geçiş Planı + +2.0, önemli bir değişiklik içeren bir sürümdür; geriye dönük uyumluluk gerekmemektedir. +Mevcut verilerin, yeni şemaya aktarılması gerekebilir (son tasarım bazında belirlenecektir). +Mevcut üçlüleri dönüştürmek için geçiş araçlarını göz önünde bulundurun. + +## Açık Sorular + + +## Açık Sorular + +**Boş düğümler**: Sınırlı destek doğrulandı. Boş düğümler için bir skolemleştirme stratejisi belirlemek gerekebilir (yükleme sırasında IRI'lar oluşturmak veya boş düğüm kimliklerini korumak). + **Sorgu sözdizimi**: Alıntılanmış üçlüleri sorgularda belirtmek için somut sözdizimi nedir? Sorgu API'sini tanımlamak gerekiyor. +~~**Önerme sözlüğü**~~: Çözüldü. Herhangi bir geçerli RDF önermesi izin verilir, kullanıcı tanımlı olanlar dahil. RDF geçerliliği hakkında minimum varsayımlar. + Çok az sabit değer (örneğin, bazı yerlerde kullanılan ⟦CODE_0⟧). +~~**Önerme sözlüğü**:~~ Çözüldü. Herhangi bir geçerli RDF özneli kabul edilebilir, + kullanıcı tarafından tanımlanmış özel özneler de dahil. RDF geçerliliği hakkında çok az varsayım. + Çok az sabit değer (örneğin, bazı yerlerde kullanılan `rdfs:label`). + Strateji: Mümkün olduğunca hiçbir şeyi kilitlememeye özen gösterin. +~~**Vektör depolama etkisi**~~: Çözüldü. Vektör depoları her zaman IRI'lere işaret eder. + sadece - asla kenarlara, literal değerlere veya boş düğümlere işaret etmez. Tırnak işaretli üçlüler ve + yeniden tanımlama, vektör deposunu etkilemez. +~~**Adlandırılmış grafik semantiği**~~: Çözüldü. Sorgular varsayılan olarak + grafiğe yöneliktir (SPARQL davranışıyla eşleşir, geriye dönük uyumlu). Adlandırılmış grafiklere veya tüm + grafiklere sorgu yapmak için açık bir grafik parametresi gereklidir. + +## Referanslar + +[RDF 1.2 Kavramları](https://www.w3.org/TR/rdf12-concepts/) +[RDF-star ve SPARQL-star](https://w3c.github.io/rdf-star/) +[RDF Veri Kümesi](https://www.w3.org/TR/rdf11-concepts/#section-dataset) diff --git a/docs/tech-specs/graphql-query.ar.md b/docs/tech-specs/graphql-query.ar.md new file mode 100644 index 00000000..e19e22ea --- /dev/null +++ b/docs/tech-specs/graphql-query.ar.md @@ -0,0 +1,383 @@ +# GraphQL Query Technical Specification + +## Overview + +تصف هذه المواصفات تنفيذ واجهة استعلام GraphQL للبيانات المنظمة المخزنة في Apache Cassandra. بناءً على إمكانات البيانات المنظمة الموضحة في المواصفات الموجودة في structured-data.md، يوضح هذا المستند كيفية تنفيذ استعلامات GraphQL على جداول Cassandra التي تحتوي على كائنات منظمة مستخرجة ومُدخلة. + +سيوفر خدمة استعلام GraphQL واجهة مرنة وآمنة من حيث النوع للاستعلام عن البيانات المنظمة المخزنة في Cassandra. ستتكيف ديناميكيًا مع تغييرات المخطط، وتدعم الاستعلامات المعقدة بما في ذلك العلاقات بين الكائنات، وتتكامل بسلاسة مع بنية TrustGraph الحالية القائمة على الرسائل. + +## الأهداف + +**دعم المخططات الديناميكي**: التكيف تلقائيًا مع تغييرات المخطط في التكوين دون إعادة تشغيل الخدمة. +**الامتثال لمعايير GraphQL**: توفير واجهة GraphQL قياسية متوافقة مع أدوات GraphQL والعملاء الحاليين. +**استعلامات Cassandra فعالة**: ترجمة استعلامات GraphQL إلى استعلامات Cassandra CQL فعالة مع احترام مفاتيح التقسيم والفهارس. +**حل العلاقات**: دعم محللات الحقول GraphQL للعلاقات بين أنواع الكائنات المختلفة. +**الأمان من حيث النوع**: ضمان تنفيذ الاستعلامات وتوليد الاستجابات بطريقة آمنة من حيث النوع بناءً على تعريفات المخطط. +**أداء قابل للتوسع**: التعامل مع الاستعلامات المتزامنة بكفاءة مع تجميع الاتصالات وتحسين الاستعلامات المناسب. +**التكامل مع الطلبات والاستجابات**: الحفاظ على التوافق مع نمط الطلب/الاستجابة القائم على Pulsar في TrustGraph. +**معالجة الأخطاء**: توفير تقارير أخطاء شاملة لمطابقة المخططات وأخطاء الاستعلامات ومشكلات التحقق من صحة البيانات. + +## الخلفية + +تقوم عملية تخزين البيانات المنظمة (trustgraph-flow/trustgraph/storage/objects/cassandra/) بكتابة الكائنات إلى جداول Cassandra بناءً على تعريفات المخطط المخزنة في نظام تكوين TrustGraph. تستخدم هذه الجداول هيكل مفتاح تقسيم مركب مع مفاتيح أولية محددة في المجموعة ومحددة في المخطط، مما يتيح استعلامات فعالة داخل المجموعات. + +القيود الحالية التي تعالجها هذه المواصفات: +لا توجد واجهة استعلام للبيانات المنظمة المخزنة في Cassandra. +عدم القدرة على الاستفادة من إمكانات الاستعلام القوية لـ GraphQL للبيانات المنظمة. +عدم وجود دعم لتتبع العلاقات بين الكائنات ذات الصلة. +عدم وجود لغة استعلام موحدة للوصول إلى البيانات المنظمة. + +ستقوم خدمة استعلام GraphQL بسد هذه الفجوات من خلال: +توفير واجهة GraphQL قياسية للاستعلام عن جداول Cassandra. +توليد مخططات GraphQL ديناميكيًا من تكوين TrustGraph. +ترجمة استعلامات GraphQL بكفاءة إلى Cassandra CQL. +دعم حل العلاقات من خلال محللات الحقول. + +## التصميم الفني + +### البنية + +سيتم تنفيذ خدمة استعلام GraphQL كمعالج TrustGraph جديد باتباع الأنماط الراسخة: + +**الموقع**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**المكونات الرئيسية**: + +1. **معالج خدمة استعلام GraphQL**: + يرث من الفئة الأساسية FlowProcessor. + ينفذ نمط الطلب/الاستجابة المشابه لخدمات الاستعلام الحالية. + يراقب التكوين بحثًا عن تحديثات المخطط. + يحافظ على تزامن مخطط GraphQL مع التكوين. + +2. **مولد المخططات الديناميكي**: + يحول تعريفات TrustGraph RowSchema إلى أنواع GraphQL. + ينشئ أنواع كائنات GraphQL مع تعريفات الحقول المناسبة. + يولد نوع الاستعلام الجذر مع محللات قائمة على المجموعة. + يقوم بتحديث مخطط GraphQL عند حدوث تغييرات في التكوين. + +3. **منفذ الاستعلام**: + يحلل استعلامات GraphQL الواردة باستخدام مكتبة Strawberry. + يتحقق من صحة الاستعلامات مقابل المخطط الحالي. + ينفذ الاستعلامات ويعيد استجابات منظمة. + يتعامل مع الأخطاء بأمان مع رسائل خطأ مفصلة. + +4. **مترجم استعلامات Cassandra**: + يحول عمليات اختيار GraphQL إلى استعلامات CQL. + يحسن الاستعلامات بناءً على الفهارس ومفاتيح التقسيم المتاحة. + يتعامل مع التصفية والتقسيم والترتيب. + يدير تجميع الاتصالات ودورة حياة الجلسة. + +5. **محلل العلاقات**: + ينفذ محللات الحقول للعلاقات بين الكائنات. + يقوم بتحميل دفعات بكفاءة لتجنب استعلامات N+1. + يقوم بتخزين العلاقات التي تم حلها في سياق الطلب. + يدعم كل من تتبع العلاقات الأمامية والعكسية. + +### مراقبة مخطط التكوين + +ستقوم الخدمة بتسجيل معالج تكوين لتلقي تحديثات المخطط: + +```python +self.register_config_handler(self.on_schema_config) +``` + +عندما تتغير المخططات: +1. تحليل تعريفات المخططات الجديدة من التكوين. +2. إعادة إنشاء أنواع GraphQL والمحللات. +3. تحديث المخطط القابل للتنفيذ. +4. مسح أي ذاكرة تخزين مؤقت تعتمد على المخطط. + +### توليد مخطط GraphQL + +لكل RowSchema في التكوين، قم بإنشاء: + +1. **نوع كائن GraphQL**: + مطابقة أنواع الحقول (string → String, integer → Int, float → Float, boolean → Boolean). + وضع علامة على الحقول المطلوبة على أنها غير قابلة للقيم الفارغة في GraphQL. + إضافة أوصاف الحقول من المخطط. + +2. **حقول الاستعلام الجذرية**: + استعلام المجموعة (مثل `customers`، `transactions`). + وسائط التصفية بناءً على الحقول المفهرسة. + دعم التقسيم (limit, offset). + خيارات الفرز للحقول القابلة للفرز. + +3. **حقول العلاقات**: + تحديد علاقات المفاتيح الخارجية من المخطط. + إنشاء محللات حقول للكائنات ذات الصلة. + دعم كل من علاقات الكائنات الفردية وقوائم الكائنات. + +### تدفق تنفيذ الاستعلام + +1. **استقبال الطلب**: + استقبال ObjectsQueryRequest من Pulsar. + استخراج سلسلة استعلام GraphQL والمتغيرات. + تحديد سياق المستخدم والمجموعة. + +2. **التحقق من صحة الاستعلام**: + تحليل استعلام GraphQL باستخدام Strawberry. + التحقق من الصحة مقابل المخطط الحالي. + التحقق من عمليات اختيار الحقول وأنواع الوسائط. + +3. **توليد CQL**: + تحليل عمليات اختيار GraphQL. + إنشاء استعلام CQL مع عبارات WHERE المناسبة. + تضمين المجموعة في مفتاح التقسيم. + تطبيق عوامل التصفية بناءً على وسائط GraphQL. + +4. **تنفيذ الاستعلام**: + تنفيذ استعلام CQL مقابل Cassandra. + مطابقة النتائج مع هيكل استجابة GraphQL. + حل أي حقول علاقات. + تنسيق الاستجابة وفقًا لمواصفات GraphQL. + +5. **تسليم الاستجابة**: + إنشاء ObjectsQueryResponse مع النتائج. + تضمين أي أخطاء في التنفيذ. + إرسال الاستجابة عبر Pulsar بمعرف الارتباط. + +### نماذج البيانات + +> **ملاحظة**: يوجد مخطط StructuredQueryRequest/Response موجود في `trustgraph-base/trustgraph/schema/services/structured_query.py`. ومع ذلك، فإنه يفتقر إلى حقول مهمة (المستخدم، المجموعة) ويستخدم أنواعًا دون المستوى الأمثل. تمثل المخططات أدناه التطور الموصى به، والتي يجب إما أن تحل محل المخططات الحالية أو يتم إنشاؤها كأنواع ObjectsQueryRequest/Response جديدة. + +#### مخطط الطلب (ObjectsQueryRequest) + +```python +from pulsar.schema import Record, String, Map, Array + +class ObjectsQueryRequest(Record): + user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest) + collection = String() # Data collection identifier (required for partition key) + query = String() # GraphQL query string + variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types) + operation_name = String() # Operation to execute for multi-operation documents +``` + +**السبب وراء التغييرات من طلب الاستعلام المنظم الحالي:** +تمت إضافة الحقول `user` و `collection` لمطابقة نمط خدمات الاستعلام الأخرى. +هذه الحقول ضرورية لتحديد مساحة مفاتيح Cassandra والمجموعة. +تظل المتغيرات كـ Map(String()) في الوقت الحالي، ولكن من الأفضل أن تدعم جميع أنواع JSON. + +#### مخطط الاستجابة (ObjectsQueryResponse) + +```python +from pulsar.schema import Record, String, Array +from ..core.primitives import Error + +class GraphQLError(Record): + message = String() + path = Array(String()) # Path to the field that caused the error + extensions = Map(String()) # Additional error metadata + +class ObjectsQueryResponse(Record): + error = Error() # System-level error (connection, timeout, etc.) + data = String() # JSON-encoded GraphQL response data + errors = Array(GraphQLError) # GraphQL field-level errors + extensions = Map(String()) # Query metadata (execution time, etc.) +``` + +**الأساس المنطقي للتغييرات من الاستجابة المنظمة للاستعلامات الحالية:** +التمييز بين أخطاء النظام (`error`) وأخطاء GraphQL (`errors`). +استخدام كائنات GraphQLError منظمة بدلاً من مصفوفة سلسلة. +إضافة حقل `extensions` للامتثال لمواصفات GraphQL. +الحفاظ على البيانات كسلسلة JSON للتوافق، على الرغم من أن الأنواع الأصلية ستكون مفضلة. + +### تحسين استعلامات Cassandra + +ستقوم الخدمة بتحسين استعلامات Cassandra عن طريق: + +1. **احترام مفاتيح التقسيم:** + تضمين المجموعة دائمًا في الاستعلامات. + استخدام المفاتيح الأساسية المعرفة في المخطط بكفاءة. + تجنب عمليات المسح الكاملة للجدول. + +2. **الاستفادة من الفهارس:** + استخدام الفهارس الثانوية للتصفية. + دمج عوامل التصفية المتعددة كلما أمكن ذلك. + التحذير عندما قد تكون الاستعلامات غير فعالة. + +3. **التحميل الدفعي:** + جمع استعلامات العلاقات. + تنفيذها على دفعات لتقليل عدد الرحلات ذهابًا وإيابًا. + تخزين النتائج مؤقتًا داخل سياق الطلب. + +4. **إدارة الاتصالات:** + الحفاظ على جلسات Cassandra مستمرة. + استخدام تجميع الاتصالات. + التعامل مع إعادة الاتصال في حالة حدوث أخطاء. + +### أمثلة لاستعلامات GraphQL + +#### استعلام بسيط للمجموعة +```graphql +{ + customers(status: "active") { + customer_id + name + email + registration_date + } +} +``` + +#### استعلام مع العلاقات +```graphql +{ + orders(order_date_gt: "2024-01-01") { + order_id + total_amount + customer { + name + email + } + items { + product_name + quantity + price + } + } +} +``` + +#### استعلام مُقسّم إلى صفحات +```graphql +{ + products(limit: 20, offset: 40) { + product_id + name + price + category + } +} +``` + +### الاعتمادات الخاصة بالتنفيذ + +**Strawberry GraphQL**: لتعريف مخطط GraphQL وتنفيذ الاستعلامات. +**Cassandra Driver**: للاتصال بقاعدة البيانات (يتم استخدامه بالفعل في وحدة التخزين). +**TrustGraph Base**: لـ FlowProcessor وتعريفات المخططات. +**Configuration System**: لمراقبة المخططات وتحديثها. + +### واجهة سطر الأوامر + +سيوفر الخدمة أمر سطر أوامر: `kg-query-objects-graphql-cassandra` + +الوسائط: +`--cassandra-host`: نقطة اتصال مجموعة Cassandra. +`--cassandra-username`: اسم مستخدم المصادقة. +`--cassandra-password`: كلمة مرور المصادقة. +`--config-type`: نوع التكوين للمخططات (افتراضي: "schema"). +وسائط FlowProcessor القياسية (تكوين Pulsar، إلخ). + +## تكامل واجهة برمجة التطبيقات + +### مواضيع Pulsar + +**موضوع الإدخال**: `objects-graphql-query-request` +المخطط: ObjectsQueryRequest +يتلقى استعلامات GraphQL من خدمات البوابة. + +**موضوع الإخراج**: `objects-graphql-query-response` +المخطط: ObjectsQueryResponse +يُرجع نتائج الاستعلام والأخطاء. + +### تكامل البوابة + +ستحتاج البوابة والبوابة العكسية إلى نقاط نهاية لـ: +1. قبول استعلامات GraphQL من العملاء. +2. توجيهها إلى خدمة الاستعلام عبر Pulsar. +3. إرجاع الاستجابات إلى العملاء. +4. دعم استعلامات GraphQL الخاصة بالتحقق من المخطط. + +### تكامل أداة الوكيل + +ستتيح فئة أداة وكيل جديدة: +توليد استعلامات GraphQL من اللغة الطبيعية. +تنفيذ استعلامات GraphQL مباشرة. +تفسير وتنسيق النتائج. +التكامل مع مسارات قرار الوكيل. + +## اعتبارات الأمان + +**تحديد عمق الاستعلام**: منع الاستعلامات المتداخلة بعمق والتي يمكن أن تسبب مشاكل في الأداء. +**تحليل تعقيد الاستعلام**: الحد من تعقيد الاستعلام لمنع استنفاد الموارد. +**أذونات على مستوى الحقل**: دعم مستقبلي للتحكم في الوصول على مستوى الحقل بناءً على أدوار المستخدم. +**تنظيف الإدخال**: التحقق من صحة وتنظيف جميع مدخلات الاستعلام لمنع هجمات الحقن. +**تحديد المعدل**: تنفيذ تحديد معدل الاستعلام لكل مستخدم/مجموعة. + +## اعتبارات الأداء + +**تخطيط الاستعلام**: تحليل الاستعلامات قبل التنفيذ لتحسين توليد CQL. +**تخزين النتائج مؤقتًا**: ضع في اعتبارك تخزين البيانات التي يتم الوصول إليها بشكل متكرر مؤقتًا على مستوى محلل الحقل. +**تجميع الاتصالات**: حافظ على مجموعات اتصالات فعالة إلى Cassandra. +**العمليات الدفعية**: اجمع بين استعلامات متعددة كلما أمكن ذلك لتقليل زمن الوصول. +**المراقبة**: تتبع مقاييس أداء الاستعلام لتحسين الأداء. + +## استراتيجية الاختبار + +### اختبارات الوحدة +توليد المخططات من تعريفات RowSchema +تحليل وتدقيق استعلامات GraphQL +منطق توليد استعلامات CQL +تطبيقات محللات الحقول + +### اختبارات العقود +الامتثال لعقد رسائل Pulsar +صلاحية مخطط GraphQL +التحقق من تنسيق الاستجابة +التحقق من صحة هيكل الأخطاء + +### اختبارات التكامل +تنفيذ استعلامات شاملة مقابل نسخة اختبار Cassandra +معالجة تحديثات المخططات +حل العلاقات +الترقيم والتصفية +سيناريوهات الأخطاء + +### اختبارات الأداء +معدل نقل البيانات للاستعلامات تحت الضغط +وقت الاستجابة لتعقيدات الاستعلامات المختلفة +استخدام الذاكرة مع مجموعات نتائج كبيرة +كفاءة مجموعة الاتصالات + +## خطة الترحيل + +لا يلزم إجراء أي ترحيل نظرًا لأن هذا ميزة جديدة. ستقوم الخدمة بما يلي: +1. قراءة المخططات الموجودة من التكوين +2. الاتصال بجداول Cassandra الموجودة التي تم إنشاؤها بواسطة وحدة التخزين +3. البدء في قبول الاستعلامات على الفور عند النشر + +## الجدول الزمني + +الأسبوع 1-2: تنفيذ الخدمة الأساسية وتوليد المخططات +الأسبوع 3: تنفيذ الاستعلامات وترجمة CQL +الأسبوع 4: حل العلاقات والتحسين +الأسبوع 5: الاختبار وضبط الأداء +الأسبوع 6: التكامل مع البوابة والتوثيق + +## أسئلة مفتوحة + +1. **تطور المخططات**: كيف يجب أن تتعامل الخدمة مع الاستعلامات أثناء عمليات انتقال المخططات؟ + خيار: وضع الاستعلامات في قائمة انتظار أثناء تحديثات المخططات + خيار: دعم إصدارات متعددة من المخططات في نفس الوقت + +2. **استراتيجية التخزين المؤقت**: هل يجب تخزين نتائج الاستعلامات مؤقتًا؟ + ضع في اعتبارك: انتهاء الصلاحية بناءً على الوقت + ضع في اعتبارك: الإبطال بناءً على الأحداث + +3. **دعم التجميع**: هل يجب أن تدعم الخدمة تجميع GraphQL لدمجها مع مصادر بيانات أخرى؟ + سيمكن ذلك من إجراء استعلامات موحدة عبر البيانات المهيكلة والبيانات الرسومية + +4. **دعم الاشتراكات**: هل يجب أن تدعم الخدمة اشتراكات GraphQL للتحديثات في الوقت الفعلي؟ + سيتطلب ذلك دعم WebSocket في البوابة + +5. **أنواع قياسية مخصصة**: هل يجب دعم الأنواع القياسية المخصصة لأنواع البيانات الخاصة بالمجال؟ + أمثلة: DateTime، UUID، حقول JSON + +## المراجع + +المواصفات الفنية للبيانات المهيكلة: `docs/tech-specs/structured-data.md` +وثائق GraphQL Strawberry: https://strawberry.rocks/ +مواصفات GraphQL: https://spec.graphql.org/ +مرجع Apache Cassandra CQL: https://cassandra.apache.org/doc/stable/cassandra/cql/ +وثائق معالج التدفق TrustGraph: وثائق داخلية \ No newline at end of file diff --git a/docs/tech-specs/graphql-query.es.md b/docs/tech-specs/graphql-query.es.md new file mode 100644 index 00000000..fe28b784 --- /dev/null +++ b/docs/tech-specs/graphql-query.es.md @@ -0,0 +1,383 @@ +# Especificación Técnica de la Consulta GraphQL + +## Descripción General + +Esta especificación describe la implementación de una interfaz de consulta GraphQL para el almacenamiento de datos estructurados de TrustGraph en Apache Cassandra. Basándose en las capacidades de datos estructurados descritas en la especificación structured-data.md, este documento detalla cómo se ejecutarán las consultas GraphQL contra las tablas de Cassandra que contienen objetos estructurados extraídos e importados. + +El servicio de consulta GraphQL proporcionará una interfaz flexible y segura para consultar datos estructurados almacenados en Cassandra. Se adaptará dinámicamente a los cambios de esquema, admitirá consultas complejas que incluyan relaciones entre objetos y se integrará perfectamente con la arquitectura existente basada en mensajes de TrustGraph. + +## Objetivos + +**Soporte de Esquema Dinámico**: Adaptación automática a los cambios de esquema en la configuración sin reiniciar el servicio. +**Cumplimiento de los Estándares GraphQL**: Proporcionar una interfaz GraphQL estándar compatible con las herramientas y clientes GraphQL existentes. +**Consultas Eficientes de Cassandra**: Traducir consultas GraphQL en consultas CQL eficientes de Cassandra, respetando las claves de partición y los índices. +**Resolución de Relaciones**: Soporte para resolutores de campos GraphQL para relaciones entre diferentes tipos de objetos. +**Seguridad de Tipos**: Garantizar la ejecución de consultas y la generación de respuestas seguras, basadas en definiciones de esquema. +**Rendimiento Escalable**: Manejar consultas concurrentes de manera eficiente con un grupo de conexiones y optimización de consultas adecuados. +**Integración de Solicitud/Respuesta**: Mantener la compatibilidad con el patrón de solicitud/respuesta basado en Pulsar de TrustGraph. +**Manejo de Errores**: Proporcionar informes de errores completos para discrepancias de esquema, errores de consulta y problemas de validación de datos. + +## Antecedentes + +La implementación del almacenamiento de datos estructurados (trustgraph-flow/trustgraph/storage/objects/cassandra/) escribe objetos en tablas de Cassandra según las definiciones de esquema almacenadas en el sistema de configuración de TrustGraph. Estas tablas utilizan una estructura de clave de partición compuesta con claves primarias definidas por colección y esquema, lo que permite consultas eficientes dentro de las colecciones. + +Limitaciones actuales que esta especificación aborda: +No hay una interfaz de consulta para los datos estructurados almacenados en Cassandra. +Incapacidad de aprovechar las poderosas capacidades de consulta de GraphQL para datos estructurados. +Falta de soporte para la navegación de relaciones entre objetos relacionados. +Falta de un lenguaje de consulta estandarizado para el acceso a datos estructurados. + +El servicio de consulta GraphQL cerrará estas brechas al: +Proporcionar una interfaz GraphQL estándar para consultar tablas de Cassandra. +Generar dinámicamente esquemas GraphQL a partir de la configuración de TrustGraph. +Traducir de manera eficiente las consultas GraphQL a CQL de Cassandra. +Soporte para la resolución de relaciones a través de resolutores de campos. + +## Diseño Técnico + +### Arquitectura + +El servicio de consulta GraphQL se implementará como un nuevo procesador de flujo de TrustGraph, siguiendo patrones establecidos: + +**Ubicación del Módulo**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**Componentes Clave**: + +1. **Procesador del Servicio de Consulta GraphQL** + Extiende la clase base FlowProcessor. + Implementa un patrón de solicitud/respuesta similar a los servicios de consulta existentes. + Supervisa la configuración para las actualizaciones del esquema. + Mantiene el esquema GraphQL sincronizado con la configuración. + +2. **Generador de Esquema Dinámico** + Convierte las definiciones de esquema de TrustGraph RowSchema en tipos GraphQL. + Crea tipos de objetos GraphQL con definiciones de campos adecuadas. + Genera el tipo de consulta raíz con resolutores basados en colecciones. + Actualiza el esquema GraphQL cuando cambia la configuración. + +3. **Ejecutor de Consultas** + Analiza las consultas GraphQL entrantes utilizando la biblioteca Strawberry. + Valida las consultas contra el esquema actual. + Ejecuta las consultas y devuelve respuestas estructuradas. + Maneja los errores con elegancia con mensajes de error detallados. + +4. **Traductor de Consultas de Cassandra** + Convierte las selecciones GraphQL en consultas CQL. + Optimiza las consultas según los índices y las claves de partición disponibles. + Maneja el filtrado, la paginación y la clasificación. + Administra el grupo de conexiones y el ciclo de vida de la sesión. + +5. **Resolutor de Relaciones** + Implementa resolutores de campos para relaciones de objetos. + Realiza una carga por lotes eficiente para evitar consultas N+1. + Almacena en caché las relaciones resueltas dentro del contexto de la solicitud. + Admite la navegación de relaciones tanto directa como inversa. + +### Monitoreo del Esquema de Configuración + +El servicio se registrará con un controlador de configuración para recibir actualizaciones de esquema: + +```python +self.register_config_handler(self.on_schema_config) +``` + +Cuando los esquemas cambian: +1. Analizar las nuevas definiciones de esquema desde la configuración. +2. Regenerar los tipos y resolutores de GraphQL. +3. Actualizar el esquema ejecutable. +4. Limpiar cualquier caché dependiente del esquema. + +### Generación de Esquema GraphQL + +Para cada RowSchema en la configuración, generar: + +1. **Tipo de Objeto GraphQL**: + Mapear tipos de campo (string → String, integer → Int, float → Float, boolean → Boolean). + Marcar los campos obligatorios como no anulables en GraphQL. + Agregar descripciones de campo desde el esquema. + +2. **Campos de Consulta de Nivel Superior**: + Consulta de colección (por ejemplo, `customers`, `transactions`). + Argumentos de filtrado basados en campos indexados. + Soporte de paginación (límite, desplazamiento). + Opciones de ordenamiento para campos ordenables. + +3. **Campos de Relación**: + Identificar relaciones de clave externa desde el esquema. + Crear resolutores de campo para objetos relacionados. + Soporte tanto para relaciones de objeto único como para listas. + +### Flujo de Ejecución de Consulta + +1. **Recepción de Solicitud**: + Recibir ObjectsQueryRequest de Pulsar. + Extraer la cadena de consulta GraphQL y las variables. + Identificar el contexto de usuario y colección. + +2. **Validación de Consulta**: + Analizar la consulta GraphQL utilizando Strawberry. + Validar contra el esquema actual. + Comprobar las selecciones de campo y los tipos de argumentos. + +3. **Generación de CQL**: + Analizar las selecciones de GraphQL. + Construir la consulta CQL con las cláusulas WHERE adecuadas. + Incluir la colección en la clave de partición. + Aplicar filtros basados en los argumentos de GraphQL. + +4. **Ejecución de Consulta**: + Ejecutar la consulta CQL contra Cassandra. + Mapear los resultados a la estructura de respuesta de GraphQL. + Resolver cualquier campo de relación. + Formatear la respuesta de acuerdo con la especificación de GraphQL. + +5. **Entrega de Respuesta**: + Crear una respuesta ObjectsQueryResponse con los resultados. + Incluir cualquier error de ejecución. + Enviar la respuesta a través de Pulsar con el ID de correlación. + +### Modelos de Datos + +> **Nota**: Existe un esquema existente de StructuredQueryRequest/Response en `trustgraph-base/trustgraph/schema/services/structured_query.py`. Sin embargo, le faltan campos críticos (usuario, colección) y utiliza tipos subóptimos. Los esquemas a continuación representan la evolución recomendada, que debe reemplazar los esquemas existentes o crearse como nuevos tipos de ObjectsQueryRequest/Response. + +#### Esquema de Solicitud (ObjectsQueryRequest) + +```python +from pulsar.schema import Record, String, Map, Array + +class ObjectsQueryRequest(Record): + user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest) + collection = String() # Data collection identifier (required for partition key) + query = String() # GraphQL query string + variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types) + operation_name = String() # Operation to execute for multi-operation documents +``` + +**Justificación de los cambios desde la solicitud de consulta estructurada existente:** +Se agregaron los campos `user` y `collection` para que coincidan con el patrón de otros servicios de consulta. +Estos campos son esenciales para identificar el espacio de claves de Cassandra y la colección. +Las variables permanecen como Map(String()) por ahora, pero idealmente deberían admitir todos los tipos JSON. + +#### Esquema de respuesta (ObjectsQueryResponse) + +```python +from pulsar.schema import Record, String, Array +from ..core.primitives import Error + +class GraphQLError(Record): + message = String() + path = Array(String()) # Path to the field that caused the error + extensions = Map(String()) # Additional error metadata + +class ObjectsQueryResponse(Record): + error = Error() # System-level error (connection, timeout, etc.) + data = String() # JSON-encoded GraphQL response data + errors = Array(GraphQLError) # GraphQL field-level errors + extensions = Map(String()) # Query metadata (execution time, etc.) +``` + +**Justificación de los cambios desde StructuredQueryResponse existente:** +Distingue entre errores del sistema (`error`) y errores de GraphQL (`errors`) +Utiliza objetos GraphQLError estructurados en lugar de un array de cadenas +Agrega el campo `extensions` para el cumplimiento de la especificación de GraphQL +Mantiene los datos como una cadena JSON para la compatibilidad, aunque los tipos nativos serían preferibles + +### Optimización de consultas de Cassandra + +El servicio optimizará las consultas de Cassandra mediante: + +1. **Respetando las claves de partición:** + Siempre incluir la colección en las consultas + Utilizar eficientemente las claves primarias definidas en el esquema + Evitar escaneos completos de la tabla + +2. **Aprovechando los índices:** + Utilizar índices secundarios para filtrar + Combinar múltiples filtros siempre que sea posible + Emitir una advertencia cuando las consultas puedan ser ineficientes + +3. **Carga por lotes:** + Recopilar consultas de relaciones + Ejecutar en lotes para reducir los viajes de ida y vuelta + Almacenar en caché los resultados dentro del contexto de la solicitud + +4. **Administración de conexiones:** + Mantener sesiones de Cassandra persistentes + Utilizar un grupo de conexiones + Manejar la reconexión en caso de fallos + +### Ejemplos de consultas GraphQL + +#### Consulta simple de colección +```graphql +{ + customers(status: "active") { + customer_id + name + email + registration_date + } +} +``` + +#### Consulta con Relaciones +```graphql +{ + orders(order_date_gt: "2024-01-01") { + order_id + total_amount + customer { + name + email + } + items { + product_name + quantity + price + } + } +} +``` + +#### Consulta paginada +```graphql +{ + products(limit: 20, offset: 40) { + product_id + name + price + category + } +} +``` + +### Dependencias de Implementación + +**Strawberry GraphQL**: Para la definición del esquema GraphQL y la ejecución de consultas. +**Cassandra Driver**: Para la conectividad con la base de datos (ya utilizado en el módulo de almacenamiento). +**TrustGraph Base**: Para FlowProcessor y definiciones de esquema. +**Sistema de Configuración**: Para la supervisión y las actualizaciones del esquema. + +### Interfaz de Línea de Comandos + +El servicio proporcionará un comando de la CLI: `kg-query-objects-graphql-cassandra` + +Argumentos: +`--cassandra-host`: Punto de contacto del clúster de Cassandra. +`--cassandra-username`: Nombre de usuario de autenticación. +`--cassandra-password`: Contraseña de autenticación. +`--config-type`: Tipo de configuración para los esquemas (por defecto: "schema"). +Argumentos estándar de FlowProcessor (configuración de Pulsar, etc.). + +## Integración de la API + +### Temas de Pulsar + +**Tema de entrada**: `objects-graphql-query-request` +Esquema: ObjectsQueryRequest +Recibe consultas GraphQL de los servicios de puerta de enlace. + +**Tema de salida**: `objects-graphql-query-response` +Esquema: ObjectsQueryResponse +Devuelve los resultados de la consulta y los errores. + +### Integración de la puerta de enlace + +La puerta de enlace y la puerta de enlace inversa necesitarán puntos finales para: +1. Aceptar consultas GraphQL de los clientes. +2. Enviar a través de Pulsar al servicio de consulta. +3. Devolver respuestas a los clientes. +4. Compatibilidad con consultas de introspección de GraphQL. + +### Integración de la herramienta de agente + +Una nueva clase de herramienta de agente permitirá: +Generación de consultas GraphQL a partir de lenguaje natural. +Ejecución directa de consultas GraphQL. +Interpretación y formato de resultados. +Integración con flujos de decisión de agentes. + +## Consideraciones de seguridad + +**Limitación de la profundidad de la consulta**: Prevenir consultas profundamente anidadas que puedan causar problemas de rendimiento. +**Análisis de la complejidad de la consulta**: Limitar la complejidad de la consulta para evitar el agotamiento de recursos. +**Permisos a nivel de campo**: Futuro soporte para el control de acceso a nivel de campo basado en los roles de usuario. +**Saneamiento de entrada**: Validar y limpiar todas las entradas de la consulta para prevenir ataques de inyección. +**Limitación de velocidad**: Implementar la limitación de velocidad de las consultas por usuario/colección. + +## Consideraciones de rendimiento + +**Planificación de consultas**: Analizar las consultas antes de la ejecución para optimizar la generación de CQL. +**Caché de resultados**: Considerar el almacenamiento en caché de datos accedidos con frecuencia a nivel del resolutor de campos. +**Creación de grupos de conexiones**: Mantener grupos de conexiones eficientes a Cassandra. +**Operaciones por lotes**: Combinar múltiples consultas cuando sea posible para reducir la latencia. +**Supervisión**: Supervisar las métricas de rendimiento de las consultas para la optimización. + +## Estrategia de pruebas + +### Pruebas Unitarias +Generación de esquemas a partir de definiciones de RowSchema +Análisis y validación de consultas GraphQL +Lógica de generación de consultas CQL +Implementaciones de resolutores de campos + +### Pruebas de Contrato +Cumplimiento del contrato de mensajes Pulsar +Validez del esquema GraphQL +Verificación del formato de respuesta +Validación de la estructura de errores + +### Pruebas de Integración +Ejecución de consultas de extremo a extremo contra una instancia de prueba de Cassandra +Manejo de actualizaciones de esquema +Resolución de relaciones +Paginación y filtrado +Escenarios de error + +### Pruebas de Rendimiento +Rendimiento de consultas bajo carga +Tiempo de respuesta para diversas complejidades de consulta +Uso de memoria con conjuntos de resultados grandes +Eficiencia del pool de conexiones + +## Plan de Migración + +No se requiere migración, ya que se trata de una nueva funcionalidad. El servicio: +1. Leerá los esquemas existentes desde la configuración +2. Se conectará a las tablas de Cassandra existentes creadas por el módulo de almacenamiento +3. Comenzará a aceptar consultas inmediatamente después de la implementación + +## Cronograma + +Semana 1-2: Implementación del servicio principal y generación de esquemas +Semana 3: Ejecución de consultas y traducción de CQL +Semana 4: Resolución de relaciones y optimización +Semana 5: Pruebas y ajuste de rendimiento +Semana 6: Integración con la puerta de enlace y documentación + +## Preguntas Abiertas + +1. **Evolución del Esquema**: ¿Cómo debe el servicio manejar las consultas durante las transiciones de esquema? + Opción: Encolar consultas durante las actualizaciones de esquema + Opción: Compatibilidad con múltiples versiones de esquema simultáneamente + +2. **Estrategia de Caché**: ¿Deben almacenarse en caché los resultados de las consultas? + Considerar: Expiración basada en el tiempo + Considerar: Invalidación basada en eventos + +3. **Soporte de Federación**: ¿Debe el servicio admitir la federación de GraphQL para combinarlo con otras fuentes de datos? + Permitiría consultas unificadas a través de datos estructurados y de grafos + +4. **Soporte de Suscripciones**: ¿Debe el servicio admitir suscripciones de GraphQL para actualizaciones en tiempo real? + Requeriría soporte de WebSocket en la puerta de enlace + +5. **Escalares Personalizados**: ¿Se deben admitir tipos de datos escalares personalizados para tipos de datos específicos del dominio? + Ejemplos: DateTime, UUID, campos JSON + +## Referencias + +Especificación Técnica de Datos Estructurados: `docs/tech-specs/structured-data.md` +Documentación de Strawberry GraphQL: https://strawberry.rocks/ +Especificación de GraphQL: https://spec.graphql.org/ +Referencia de CQL de Apache Cassandra: https://cassandra.apache.org/doc/stable/cassandra/cql/ +Documentación del Procesador de Flujo de TrustGraph: Documentación interna \ No newline at end of file diff --git a/docs/tech-specs/graphql-query.he.md b/docs/tech-specs/graphql-query.he.md new file mode 100644 index 00000000..7ed2b2b1 --- /dev/null +++ b/docs/tech-specs/graphql-query.he.md @@ -0,0 +1,383 @@ +# GraphQL Query Technical Specification + +## Overview + +מפרט זה מתאר את יישום ממשק שאילתות GraphQL עבור אחסון נתונים מובנים של TrustGraph ב-Apache Cassandra. בהתבסס על יכולות הנתונים המובנים המתוארות במפרט structured-data.md, מסמך זה מפרט כיצד שאילתות GraphQL יבוצעו כנגד טבלאות Cassandra המכילות אובייקטים מובנים שחולצו והועברו. + +שירות שאילתות GraphQL יספק ממשק גמיש ובטוח טיפוסית לשאילתות נתונים מובנים המאוחסנים ב-Cassandra. הוא יסתגל באופן דינמי לשינויים בסכימה, יתמוך בשאילתות מורכבות כולל קשרים בין אובייקטים, וישתלב בצורה חלקה עם ארכיטקטורת העברת הודעות הקיימת של TrustGraph. + +## Goals + +**תמיכה דינמית בסכימה**: הסתגלות אוטומטית לשינויים בסכימה בתצורה ללא אתחולים מחדש של השירות +**עמידה בתקני GraphQL**: מתן ממשק GraphQL סטנדרטי התואם לכלי לקוחות GraphQL קיימים +**שאילתות Cassandra יעילות**: המרת שאילתות GraphQL לשאילתות CQL יעילות של Cassandra תוך כיבוד מפתחות מחיצה ואינדקסים +**פתרון קשרים**: תמיכה במאפייני פותרים עבור קשרים בין סוגי אובייקטים שונים +**בטיחות טיפוסים**: הבטחת ביצוע שאילתות ובניית תגובות בצורה בטוחה טיפוסית בהתבסס על הגדרות סכימה +**ביצועים ניתנים להרחבה**: טיפול יעיל בשאילתות מקבילות עם ניהול חיבורים מתאים ואופטימיזציה של שאילתות +**אינטגרציה של בקשות/תגובות**: שמירה על תאימות לדפוס בקשות/תגובות המבוסס על Pulsar של TrustGraph +**טיפול בשגיאות**: מתן דיווח מקיף על שגיאות עבור חוסר התאמה בסכימה, שגיאות שאילתות ובעיות אימות נתונים + +## Background + +יישום אחסון הנתונים המובנים (trustgraph-flow/trustgraph/storage/objects/cassandra/) כותב אובייקטים לטבלאות Cassandra בהתבסס על הגדרות סכימה המאוחסנות במערכת התצורה של TrustGraph. טבלאות אלה משתמשות במבנה מפתח מחיצה מורכב עם אוספים ומפתחות ראשיים המוגדרים בסכימה, המאפשרות שאילתות יעילות בתוך אוספים. + +מגבלות קיימות שספציפיקציה זו מתייחסת אליהן: +אין ממשק שאילתות עבור הנתונים המובנים המאוחסנים ב-Cassandra +חוסר יכולת לנצל את יכולות השאילתות החזקות של GraphQL עבור נתונים מובנים +חוסר תמיכה במעבר על קשרים בין אובייקטים קשורים +היעדר שפה סטנדרטית לגישה לנתונים מובנים + +שירות שאילתות GraphQL יסגור את הפערים הללו על ידי: +מתן ממשק GraphQL סטנדרטי לשאילתות של טבלאות Cassandra +יצירת סכימות GraphQL באופן דינמי מתצורה של TrustGraph +המרת יעילה של שאילתות GraphQL לשאילתות CQL של Cassandra +תמיכה בפתרון קשרים באמצעות פותרים של שדות + +## Technical Design + +### Architecture + +שירות שאילתות GraphQL ייושם כמעבד זרימה חדש של TrustGraph תוך שימוש בדפוסים מבוססים: + +**מיקום מודול**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**רכיבים מרכזיים**: + +1. **מעבד שירות שאילתות GraphQL** + מרחיב את מחלקת FlowProcessor הבסיסית + מיישם דפוס בקשה/תגובה הדומה לשירותי שאילתות קיימים + מנטר את התצורה עבור עדכוני סכימה + שומר על סכימת GraphQL מסונכרנת עם התצורה + +2. **מחולל סכימה דינמי** + ממיר הגדרות RowSchema של TrustGraph לטיפוסי GraphQL + יוצר טיפוסי אובייקטים של GraphQL עם הגדרות שדות מתאימות + מייצר טיפוס שורש Query עם פותרים מבוססי אוספים + מעדכן את סכימת GraphQL כאשר התצורה משתנה + +3. **מבצע שאילתות** + מנתח שאילתות GraphQL נכנס באמצעות ספריית Strawberry + מאמת שאילתות כנגד הסכימה הנוכחית + מבצע שאילתות ומחזיר תגובות מובנות + מטפל בשגיאות בצורה אלגנטית עם הודעות שגיאה מפורטות + +4. **מתרגם שאילתות Cassandra** + ממיר בחירות GraphQL לשאילתות CQL + מייעל שאילתות בהתבסס על אינדקסים ומפתחות מחיצה זמינים + מטפל בסינון, דפוס ומיון + מנהל ניהול חיבורים ומחזור חיים של סשן + +5. **פותר קשרים** + מיישם פותרים של שדות עבור קשרים בין אובייקטים + מבצע טעינה באצווה יעילה כדי למנוע שאילתות N+1 + שומר על קשרים פתורים בהקשר הבקשה + תומך במעבר קשרים קדימה ואחורה + +### ניטור סכימת תצורה + +השירות יירשם למטפל תצורה כדי לקבל עדכוני סכימה: + +```python +self.register_config_handler(self.on_schema_config) +``` + +כאשר סכימות משתנות: +1. ניתוח הגדרות סכימה חדשות מקובץ התצורה +2. יצירת סוגי GraphQL ופתרונות (resolvers) מחדש +3. עדכון הסכימה הביצועית +4. ניקוי מטמון כלשהו התלוי בסכימה + +### יצירת סכימת GraphQL + +עבור כל RowSchema בתצורה, יוצרים: + +1. **סוג אובייקט GraphQL**: + מיפוי סוגי שדות (string → String, integer → Int, float → Float, boolean → Boolean) + סימון שדות חובה כלא-nullable ב-GraphQL + הוספת תיאורי שדות מהסכימה + +2. **שדות שאילתה ראשיים**: + שאילתת אוסף (לדוגמה, `customers`, `transactions`) + ארגומנטים לסינון המבוססים על שדות עם אינדקס + תמיכה בדפוס של "paginate" (limit, offset) + אפשרויות מיון עבור שדות הניתנים למיון + +3. **שדות יחסים**: + זיהוי יחסי מפתח זר מהסכימה + יצירת פתרונות (resolvers) עבור אובייקטים קשורים + תמיכה הן ביחסי אובייקט בודד והן ביחסי רשימה + +### זרימת ביצוע שאילתות + +1. **קבלת בקשה**: + קבלת ObjectsQueryRequest מ-Pulsar + חילוץ מחרוזת שאילתת GraphQL ומשתנים + זיהוי משתמש והקשר של אוסף + +2. **אימות שאילתה**: + ניתוח שאילתת GraphQL באמצעות Strawberry + אימות מול הסכימה הנוכחית + בדיקת בחירות שדות וסוגי ארגומנטים + +3. **יצירת CQL**: + ניתוח בחירות GraphQL + בניית שאילתת CQL עם סעיפי WHERE מתאימים + הכללת האוסף במפתח מחיצה + החלת פילטרים המבוססים על ארגומנטים של GraphQL + +4. **ביצוע שאילתה**: + ביצוע שאילתת CQL נגד Cassandra + מיפוי תוצאות למבנה תגובת GraphQL + פתרון כל שדות היחסים + עיצוב התגובה בהתאם למפרט של GraphQL + +5. **העברת תגובה**: + יצירת ObjectsQueryResponse עם תוצאות + הכללת כל שגיאות הביצוע + שליחת תגובה דרך Pulsar עם מזהה מתאם + +### מודלים של נתונים + +> **הערה**: קיימת סכימת StructuredQueryRequest/Response קיימת ב-`trustgraph-base/trustgraph/schema/services/structured_query.py`. עם זאת, היא חסרה שדות קריטיים (משתמש, אוסף) ומשתמשת בסוגים לא אופטימליים. הסכימות שלהלן מייצגות את ההתפתחות המומלצת, שעליה להחליף את הסכימות הקיימות או ליצור סוגי ObjectsQueryRequest/Response חדשים. + +#### סכימת בקשה (ObjectsQueryRequest) + +```python +from pulsar.schema import Record, String, Map, Array + +class ObjectsQueryRequest(Record): + user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest) + collection = String() # Data collection identifier (required for partition key) + query = String() # GraphQL query string + variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types) + operation_name = String() # Operation to execute for multi-operation documents +``` + +**ההצדקה לשינויים מתוך בקשת StructuredQueryRequest קיימת:** +הוספת השדות `user` ו-`collection` כדי להתאים לדפוס של שירותי שאילתות אחרים. +שדות אלה חיוניים לזיהוי ה-keyspace והקולקציה של Cassandra. +המשתנים נשארים מסוג Map(String()) כרגע, אך באופן אידיאלי צריכים לתמוך בכל סוגי ה-JSON. + +#### סכימת תגובה (ObjectsQueryResponse) + +```python +from pulsar.schema import Record, String, Array +from ..core.primitives import Error + +class GraphQLError(Record): + message = String() + path = Array(String()) # Path to the field that caused the error + extensions = Map(String()) # Additional error metadata + +class ObjectsQueryResponse(Record): + error = Error() # System-level error (connection, timeout, etc.) + data = String() # JSON-encoded GraphQL response data + errors = Array(GraphQLError) # GraphQL field-level errors + extensions = Map(String()) # Query metadata (execution time, etc.) +``` + +**ההצדקה לשינויים מ-StructuredQueryResponse הקיים:** +מבחינה בין שגיאות מערכת (`error`) ושגיאות GraphQL (`errors`) +משתמשת באובייקטי GraphQLError מובנים במקום מערך מחרוזות +מוסיפה שדה `extensions` לצורך עמידה במפרט GraphQL +שומרת על הנתונים כמחרוזת JSON לצורך תאימות, למרות שטיפוסים מקוריים היו עדיפים + +### אופטימיזציה של שאילתות Cassandra + +השירות יבצע אופטימיזציה של שאילתות Cassandra על ידי: + +1. **כבוד למפתחות מחיצה:** + תמיד לכלול אוסף בשאילתות + להשתמש ביעילות במפתחות ראשיים המוגדרים בסכימה + להימנע מסריקות טבלה מלאות + +2. **ניצול אינדקסים:** + להשתמש באינדקסים משניים לסינון + לשלב מספר פילטרים במידת האפשר + להזהיר כאשר שאילתות עשויות להיות לא יעילות + +3. **טעינה באצווה:** + לאסוף שאילתות קשר + לבצע אותן באצווה כדי להפחית את מספר הפעמים + לשמור תוצאות בהקשר הבקשה + +4. **ניהול חיבורים:** + לשמור על סשנים קבועים של Cassandra + להשתמש בבריכת חיבורים + לטפל בחיבור מחדש במקרה של כשלים + +### דוגמאות לשאילתות GraphQL + +#### שאילתת אוסף פשוטה +```graphql +{ + customers(status: "active") { + customer_id + name + email + registration_date + } +} +``` + +#### שאילתה עם קשרים +```graphql +{ + orders(order_date_gt: "2024-01-01") { + order_id + total_amount + customer { + name + email + } + items { + product_name + quantity + price + } + } +} +``` + +#### שאילתה מדורגת +```graphql +{ + products(limit: 20, offset: 40) { + product_id + name + price + category + } +} +``` + +### תלותות יישום + +**Strawberry GraphQL**: להגדרת סכימת GraphQL ולביצוע שאילתות +**Cassandra Driver**: לחיבור למסד הנתונים (בשימוש כבר במודול האחסון) +**TrustGraph Base**: עבור FlowProcessor והגדרות סכימה +**Configuration System**: לניטור ועדכון סכימות + +### ממשק שורת הפקודה + +השירות יספק פקודת CLI: `kg-query-objects-graphql-cassandra` + +ארגומנטים: +`--cassandra-host`: נקודת מגע של אשכול Cassandra +`--cassandra-username`: שם משתמש לאימות +`--cassandra-password`: סיסמה לאימות +`--config-type`: סוג תצורה עבור סכימות (ברירת מחדל: "schema") +ארגומנטים סטנדרטיים של FlowProcessor (תצורת Pulsar, וכו') + +## אינטגרציה של API + +### נושאים של Pulsar + +**נושא קלט**: `objects-graphql-query-request` +סכימה: ObjectsQueryRequest +מקבל שאילתות GraphQL משירותי שער + +**נושא פלט**: `objects-graphql-query-response` +סכימה: ObjectsQueryResponse +מחזיר תוצאות שאילתות ושגיאות + +### אינטגרציה של שער + +השער ושער הפוך יצטרכו נקודות קצה כדי: +1. לקבל שאילתות GraphQL מלקוחות +2. להעביר לשירות השאילתות דרך Pulsar +3. להחזיר תגובות ללקוחות +4. לתמוך בשאילתות אינטרוספקציה של GraphQL + +### אינטגרציה של כלי סוכן + +מחלקה חדשה של כלי סוכן תאפשר: +יצירת שאילתות GraphQL משפה טבעית +ביצוע ישיר של שאילתות GraphQL +פרשנות ועיצוב תוצאות +שילוב עם זרימות החלטה של סוכן + +## שיקולי אבטחה + +**הגבלת עומק שאילתה**: למנוע שאילתות מקוננות עמוקות שעלולות לגרום לבעיות ביצועים +**ניתוח מורכבות שאילתה**: להגביל את מורכבות השאילתה כדי למנוע מיצוי משאבים +**הרשאות ברמת השדה**: תמיכה עתידית בשליטה על גישה ברמת השדה בהתבסס על תפקידי משתמש +**ניקוי קלט**: לאמת ולנקות את כל קלט השאילתה כדי למנוע התקפות הזרקה +**הגבלת קצב**: ליישם הגבלת קצב שאילתות למשתמש/אוסף + +## שיקולי ביצועים + +**תכנון שאילתות**: לנתח שאילתות לפני ביצוע כדי לייעל יצירת CQL +**מטמון תוצאות**: לשקול שמירת נתונים שנגישים אליהם לעתים קרובות ברמת פותר השדה +**בריכת חיבורים**: לשמור על בריכות חיבורים יעילות ל-Cassandra +**פעולות אצווה**: לשלב מספר שאילתות כאשר אפשר כדי להפחית השהיה +**ניטור**: לעקוב אחר מדדי ביצועי שאילתות לצורך אופטימיזציה + +## אסטרטגיית בדיקה + +### בדיקות יחידה +יצירת סכימה מתוך הגדרות RowSchema +ניתוח ותיקוף שאילתות GraphQL +לוגיקת יצירת שאילתות CQL +יישומים של פותרים (resolvers) של שדות + +### בדיקות חוזה +עמידה בחוזה הודעות Pulsar +תקינות סכימת GraphQL +אימות פורמט תגובה +אימות מבנה שגיאות + +### בדיקות אינטגרציה +ביצוע שאילתות מקצה לקצה מול מופע בדיקת Cassandra +טיפול בעדכוני סכימה +פתרון קשרים +דפוסים של דף אחרי דף וסינון +תרחישי שגיאות + +### בדיקות ביצועים +תפוקת שאילתות תחת עומס +זמן תגובה עבור מורכבויות שאילתות שונות +שימוש בזיכרון עם קבוצות תוצאות גדולות +יעילות של מאגר חיבורים + +## תוכנית מעבר + +אין צורך במעבר מכיוון שזו יכולת חדשה. השירות י: +1. יקרא סכימות קיימות מהתצורה +2. יתחבר לטבלאות Cassandra קיימות שנוצרו על ידי מודול האחסון +3. יתחיל לקבל שאילתות מיד עם הפריסה + +## ציר זמן + +שבוע 1-2: יישום ליבת השירות ויצירת סכימה +שבוע 3: ביצוע שאילתות ותרגום CQL +שבוע 4: פתרון קשרים ואופטימיזציה +שבוע 5: בדיקות וכוונון ביצועים +שבוע 6: שילוב עם שער ותיעוד + +## שאלות פתוחות + +1. **אבולוציה של סכימה**: כיצד השירות צריך להתמודד עם שאילתות במהלך מעברי סכימה? + אפשרות: תזמון שאילתות במהלך עדכוני סכימה + אפשרות: תמיכה במספר גרסאות סכימה בו זמנית + +2. **אסטרטגיית אחסון במטמון**: האם יש לאחסן תוצאות שאילתות במטמון? + לשקול: תפוגה מבוססת זמן + לשקול: ביטול תוקף מבוסס אירועים + +3. **תמיכה בפדרציה**: האם השירות צריך לתמוך בפדרציה של GraphQL לשילוב עם מקורות נתונים אחרים? + יאפשר שאילתות מאוחדות על נתונים מובנים וגרפיים + +4. **תמיכה במנויים**: האם השירות צריך לתמוך במנויים של GraphQL לעדכונים בזמן אמת? + ידרוש תמיכה ב-WebSocket בשער + +5. **סקלרים מותאמים אישית**: האם יש לתמוך בסקלרים מותאמים אישית עבור סוגי נתונים ספציפיים לתחום? + דוגמאות: DateTime, UUID, שדות JSON + +## הפניות + +מפרט טכני של נתונים מובנים: `docs/tech-specs/structured-data.md` +תיעוד Strawberry GraphQL: https://strawberry.rocks/ +מפרט GraphQL: https://spec.graphql.org/ +הפניה ל-Apache Cassandra CQL: https://cassandra.apache.org/doc/stable/cassandra/cql/ +תיעוד מעבד זרימת נתונים TrustGraph: תיעוד פנימי \ No newline at end of file diff --git a/docs/tech-specs/graphql-query.hi.md b/docs/tech-specs/graphql-query.hi.md new file mode 100644 index 00000000..2fa6f66d --- /dev/null +++ b/docs/tech-specs/graphql-query.hi.md @@ -0,0 +1,383 @@ +# GraphQL क्वेरी तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश अपाचे कैसेंड्रा में ट्रस्टग्राफ के संरचित डेटा भंडारण के लिए एक GraphQL क्वेरी इंटरफ़ेस के कार्यान्वयन का वर्णन करता है। संरचित-डेटा.md विनिर्देश में उल्लिखित संरचित डेटा क्षमताओं पर निर्माण करते हुए, यह दस्तावेज़ बताता है कि निकाले गए और संसाधित संरचित ऑब्जेक्ट युक्त कैसेंड्रा तालिकाओं के खिलाफ GraphQL क्वेरी कैसे निष्पादित की जाएंगी। + +GraphQL क्वेरी सेवा कैसेंड्रा में संग्रहीत संरचित डेटा के लिए एक लचीला, टाइप-सुरक्षित इंटरफ़ेस प्रदान करेगी। यह स्कीमा परिवर्तनों के लिए गतिशील रूप से अनुकूल होगा, ऑब्जेक्ट के बीच संबंधों सहित जटिल प्रश्नों का समर्थन करेगा, और ट्रस्टग्राफ के मौजूदा संदेश-आधारित वास्तुकला के साथ सहजता से एकीकृत होगा। + +## लक्ष्य + +**गतिशील स्कीमा समर्थन**: सेवा को पुनरारंभ किए बिना कॉन्फ़िगरेशन में स्कीमा परिवर्तनों के लिए स्वचालित रूप से अनुकूल होना। +**GraphQL मानकों का अनुपालन**: मौजूदा GraphQL टूलिंग और क्लाइंट के साथ संगत एक मानक GraphQL इंटरफ़ेस प्रदान करना। +**कुशल कैसेंड्रा क्वेरी**: GraphQL क्वेरी को कुशल कैसेंड्रा CQL क्वेरी में अनुवाद करना, विभाजन कुंजियों और अनुक्रमणिकाओं का सम्मान करना। +**संबंध संकल्प**: विभिन्न ऑब्जेक्ट प्रकारों के बीच संबंधों के लिए GraphQL फ़ील्ड रिज़ॉल्वर का समर्थन करना। +**टाइप सुरक्षा**: स्कीमा परिभाषाओं के आधार पर टाइप-सुरक्षित क्वेरी निष्पादन और प्रतिक्रिया पीढ़ी सुनिश्चित करना। +**मापनीय प्रदर्शन**: उचित कनेक्शन पूलिंग और क्वेरी अनुकूलन के साथ समवर्ती प्रश्नों को कुशलतापूर्वक संभालना। +**अनुरोध/प्रतिक्रिया एकीकरण**: ट्रस्टग्राफ के पल्सर-आधारित अनुरोध/प्रतिक्रिया पैटर्न के साथ संगतता बनाए रखना। +**त्रुटि प्रबंधन**: स्कीमा मिसमैच, क्वेरी त्रुटियों और डेटा सत्यापन मुद्दों के लिए व्यापक त्रुटि रिपोर्टिंग प्रदान करना। + +## पृष्ठभूमि + +संरचित डेटा भंडारण कार्यान्वयन (trustgraph-flow/trustgraph/storage/objects/cassandra/) ट्रस्टग्राफ के कॉन्फ़िगरेशन सिस्टम में संग्रहीत स्कीमा परिभाषाओं के आधार पर कैसेंड्रा तालिकाओं में ऑब्जेक्ट लिखता है। ये तालिकाएँ एक समग्र विभाजन कुंजी संरचना का उपयोग करती हैं जिसमें संग्रह और स्कीमा-परिभाषित प्राथमिक कुंजियाँ होती हैं, जो संग्रह के भीतर कुशल प्रश्नों को सक्षम करती हैं। + +वर्तमान सीमाएँ जिन्हें इस विनिर्देश द्वारा संबोधित किया गया है: +कैसेंड्रा में संग्रहीत संरचित डेटा के लिए कोई क्वेरी इंटरफ़ेस नहीं। +संरचित डेटा के लिए GraphQL की शक्तिशाली क्वेरी क्षमताओं का लाभ उठाने में असमर्थता। +संबंधित ऑब्जेक्ट के बीच संबंध ट्रैवर्सल के लिए कोई समर्थन नहीं। +संरचित डेटा एक्सेस के लिए एक मानकीकृत क्वेरी भाषा का अभाव। + +GraphQL क्वेरी सेवा इन कमियों को भरकर: +कैसेंड्रा तालिकाओं के लिए एक मानक GraphQL इंटरफ़ेस प्रदान करना। +ट्रस्टग्राफ कॉन्फ़िगरेशन से गतिशील रूप से GraphQL स्कीमा उत्पन्न करना। +कुशलतापूर्वक GraphQL क्वेरी को कैसेंड्रा CQL में अनुवाद करना। +फ़ील्ड रिज़ॉल्वर के माध्यम से संबंध संकल्प का समर्थन करना। + +## तकनीकी डिजाइन + +### वास्तुकला + +GraphQL क्वेरी सेवा को एक नए ट्रस्टग्राफ फ्लो प्रोसेसर के रूप में लागू किया जाएगा जो स्थापित पैटर्न का पालन करता है: + +**मॉड्यूल स्थान**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**मुख्य घटक**: + +1. **GraphQL क्वेरी सेवा प्रोसेसर** + बेस FlowProcessor क्लास का विस्तार करता है। + मौजूदा क्वेरी सेवाओं के समान अनुरोध/प्रतिक्रिया पैटर्न को लागू करता है। + स्कीमा अपडेट के लिए कॉन्फ़िगरेशन की निगरानी करता है। + कॉन्फ़िगरेशन के साथ GraphQL स्कीमा को सिंक्रनाइज़ रखता है। + +2. **गतिशील स्कीमा जनरेटर** + ट्रस्टग्राफ RowSchema परिभाषाओं को GraphQL प्रकारों में परिवर्तित करता है। + उचित फ़ील्ड परिभाषाओं के साथ GraphQL ऑब्जेक्ट प्रकार बनाता है। + संग्रह-आधारित रिज़ॉल्वर के साथ रूट क्वेरी प्रकार उत्पन्न करता है। + जब कॉन्फ़िगरेशन बदलता है तो GraphQL स्कीमा को अपडेट करता है। + +3. **क्वेरी निष्पादक** + Strawberry लाइब्रेरी का उपयोग करके आने वाली GraphQL क्वेरी को पार्स करता है। + वर्तमान स्कीमा के विरुद्ध क्वेरी को मान्य करता है। + क्वेरी निष्पादित करता है और संरचित प्रतिक्रियाएँ लौटाता है। + विस्तृत त्रुटि संदेशों के साथ त्रुटियों को कुशलतापूर्वक संभालता है। + +4. **कैसेंड्रा क्वेरी अनुवादक** + GraphQL चयन को CQL क्वेरी में परिवर्तित करता है। + उपलब्ध अनुक्रमणिकाओं और विभाजन कुंजियों के आधार पर क्वेरी को अनुकूलित करता है। + फ़िल्टरिंग, पेजिंग और सॉर्टिंग को संभालता है। + कनेक्शन पूलिंग और सत्र जीवनचक्र का प्रबंधन करता है। + +5. **संबंध रिज़ॉल्वर** + ऑब्जेक्ट संबंधों के लिए फ़ील्ड रिज़ॉल्वर को लागू करता है। + N+1 क्वेरी से बचने के लिए कुशल बैच लोडिंग करता है। + अनुरोध संदर्भ के भीतर हल किए गए संबंधों को कैश करता है। + आगे और पीछे दोनों संबंध ट्रैवर्सल का समर्थन करता है। + +### कॉन्फ़िगरेशन स्कीमा निगरानी + +सेवा स्कीमा अपडेट प्राप्त करने के लिए एक कॉन्फ़िगरेशन हैंडलर को पंजीकृत करेगी: + +```python +self.register_config_handler(self.on_schema_config) +``` + +जब स्कीमा बदलते हैं: +1. कॉन्फ़िगरेशन से नए स्कीमा परिभाषाओं को पार्स करें। +2. GraphQL प्रकारों और रिज़ॉल्वरों को फिर से उत्पन्न करें। +3. निष्पादन योग्य स्कीमा को अपडेट करें। +4. किसी भी स्कीमा-निर्भर कैश को साफ़ करें। + +### GraphQL स्कीमा पीढ़ी + +कॉन्फ़िगरेशन में प्रत्येक RowSchema के लिए, निम्नलिखित उत्पन्न करें: + +1. **GraphQL ऑब्जेक्ट टाइप**: + फ़ील्ड प्रकारों को मैप करें (string → String, integer → Int, float → Float, boolean → Boolean)। + आवश्यक फ़ील्ड को GraphQL में गैर-शून्य के रूप में चिह्नित करें। + स्कीमा से फ़ील्ड विवरण जोड़ें। + +2. **रूट क्वेरी फ़ील्ड**: + संग्रह क्वेरी (जैसे, `customers`, `transactions`)। + अनुक्रमित फ़ील्ड के आधार पर फ़िल्टरिंग तर्क। + पेजिंग समर्थन (सीमा, ऑफ़सेट)। + सॉर्ट करने योग्य फ़ील्ड के लिए सॉर्टिंग विकल्प। + +3. **रिलेशनशिप फ़ील्ड**: + स्कीमा से विदेशी कुंजी संबंधों की पहचान करें। + संबंधित ऑब्जेक्ट के लिए फ़ील्ड रिज़ॉल्वर बनाएं। + एकल ऑब्जेक्ट और सूची दोनों संबंधों का समर्थन करें। + +### क्वेरी निष्पादन प्रवाह + +1. **अनुरोध स्वागत**: + Pulsar से ObjectsQueryRequest प्राप्त करें। + GraphQL क्वेरी स्ट्रिंग और चर निकालें। + उपयोगकर्ता और संग्रह संदर्भ की पहचान करें। + +2. **क्वेरी सत्यापन**: + Strawberry का उपयोग करके GraphQL क्वेरी को पार्स करें। + वर्तमान स्कीमा के विरुद्ध मान्य करें। + फ़ील्ड चयन और तर्क प्रकारों की जांच करें। + +3. **CQL पीढ़ी**: + GraphQL चयन का विश्लेषण करें। + उचित WHERE खंडों के साथ CQL क्वेरी बनाएं। + विभाजन कुंजी में संग्रह शामिल करें। + GraphQL तर्कों के आधार पर फ़िल्टर लागू करें। + +4. **क्वेरी निष्पादन**: + Cassandra के खिलाफ CQL क्वेरी निष्पादित करें। + परिणामों को GraphQL प्रतिक्रिया संरचना में मैप करें। + किसी भी रिलेशनशिप फ़ील्ड को हल करें। + GraphQL विनिर्देश के अनुसार प्रतिक्रिया को प्रारूपित करें। + +5. **प्रतिक्रिया वितरण**: + परिणामों के साथ ObjectsQueryResponse बनाएं। + किसी भी निष्पादन त्रुटि को शामिल करें। + सहसंबंध आईडी के साथ Pulsar के माध्यम से प्रतिक्रिया भेजें। + +### डेटा मॉडल + +> **ध्यान दें**: `trustgraph-base/trustgraph/schema/services/structured_query.py` में एक मौजूदा StructuredQueryRequest/Response स्कीमा मौजूद है। हालाँकि, इसमें महत्वपूर्ण फ़ील्ड (उपयोगकर्ता, संग्रह) की कमी है और यह उप-इष्टतम प्रकारों का उपयोग करता है। नीचे दिए गए स्कीमा अनुशंसित विकास का प्रतिनिधित्व करते हैं, जिसे या तो मौजूदा स्कीमा को बदलने के लिए या नए ObjectsQueryRequest/Response प्रकारों के रूप में बनाया जाना चाहिए। + +#### अनुरोध स्कीमा (ObjectsQueryRequest) + +```python +from pulsar.schema import Record, String, Map, Array + +class ObjectsQueryRequest(Record): + user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest) + collection = String() # Data collection identifier (required for partition key) + query = String() # GraphQL query string + variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types) + operation_name = String() # Operation to execute for multi-operation documents +``` + +**मौजूदा StructuredQueryRequest से परिवर्तनों का तर्क:** +अन्य क्वेरी सेवाओं के पैटर्न से मेल खाने के लिए `user` और `collection` फ़ील्ड जोड़े गए। +ये फ़ील्ड कैसेंड्रा की स्पेस और कलेक्शन की पहचान करने के लिए आवश्यक हैं। +वेरिएबल अभी भी Map(String()) के रूप में हैं, लेकिन आदर्श रूप से सभी JSON प्रकारों का समर्थन करना चाहिए। + +#### प्रतिक्रिया स्कीमा (ObjectsQueryResponse) + +```python +from pulsar.schema import Record, String, Array +from ..core.primitives import Error + +class GraphQLError(Record): + message = String() + path = Array(String()) # Path to the field that caused the error + extensions = Map(String()) # Additional error metadata + +class ObjectsQueryResponse(Record): + error = Error() # System-level error (connection, timeout, etc.) + data = String() # JSON-encoded GraphQL response data + errors = Array(GraphQLError) # GraphQL field-level errors + extensions = Map(String()) # Query metadata (execution time, etc.) +``` + +**मौजूदा StructuredQueryResponse से परिवर्तनों का कारण:** +सिस्टम त्रुटियों (`error`) और GraphQL त्रुटियों (`errors`) के बीच अंतर करता है। +स्ट्रिंग सरणी के बजाय संरचित GraphQLError ऑब्जेक्ट का उपयोग करता है। +GraphQL विनिर्देश के अनुपालन के लिए `extensions` फ़ील्ड जोड़ता है। +अनुकूलता के लिए डेटा को JSON स्ट्रिंग के रूप में रखता है, हालांकि मूल प्रकार बेहतर होंगे। + +### कैसेंड्रा क्वेरी अनुकूलन + +सेवा कैसेंड्रा क्वेरी को इस प्रकार अनुकूलित करेगी: + +1. **पार्टिशन कुंजियों का सम्मान करना:** + हमेशा क्वेरी में संग्रह शामिल करें। + स्कीमा-परिभाषित प्राथमिक कुंजियों का कुशलतापूर्वक उपयोग करें। + पूर्ण तालिका स्कैन से बचें। + +2. **सूचकांकों का उपयोग करना:** + फ़िल्टरिंग के लिए द्वितीयक सूचकांकों का उपयोग करें। + जब संभव हो, तो कई फ़िल्टरों को मिलाएं। + चेतावनी दें जब क्वेरी अक्षम हो सकती हैं। + +3. **बैच लोडिंग:** + संबंध क्वेरी एकत्र करें। + राउंड ट्रिप को कम करने के लिए बैचों में निष्पादित करें। + अनुरोध संदर्भ के भीतर परिणामों को कैश करें। + +4. **कनेक्शन प्रबंधन:** + लगातार कैसेंड्रा सत्र बनाए रखें। + कनेक्शन पूलिंग का उपयोग करें। + विफलताओं पर पुनः कनेक्शन को संभालें। + +### उदाहरण GraphQL क्वेरी + +#### सरल संग्रह क्वेरी +```graphql +{ + customers(status: "active") { + customer_id + name + email + registration_date + } +} +``` + +#### संबंधों के साथ प्रश्न +```graphql +{ + orders(order_date_gt: "2024-01-01") { + order_id + total_amount + customer { + name + email + } + items { + product_name + quantity + price + } + } +} +``` + +#### पृष्ठों में विभाजित क्वेरी +```graphql +{ + products(limit: 20, offset: 40) { + product_id + name + price + category + } +} +``` + +### कार्यान्वयन निर्भरताएँ + +**स्ट्रॉबेरी ग्राफक्यूएल (Strawberry GraphQL)**: ग्राफक्यूएल स्कीमा परिभाषा और क्वेरी निष्पादन के लिए +**कैसेंड्रा ड्राइवर (Cassandra Driver)**: डेटाबेस कनेक्टिविटी के लिए (भंडारण मॉड्यूल में पहले से उपयोग किया गया) +**ट्रस्टग्राफ बेस (TrustGraph Base)**: फ्लोप्रोसेसर और स्कीमा परिभाषाओं के लिए +**कॉन्फ़िगरेशन सिस्टम (Configuration System)**: स्कीमा निगरानी और अपडेट के लिए + +### कमांड-लाइन इंटरफ़ेस + +सेवा एक CLI कमांड प्रदान करेगी: `kg-query-objects-graphql-cassandra` + +तर्क: +`--cassandra-host`: कैसेंड्रा क्लस्टर संपर्क बिंदु +`--cassandra-username`: प्रमाणीकरण उपयोगकर्ता नाम +`--cassandra-password`: प्रमाणीकरण पासवर्ड +`--config-type`: स्कीमा के लिए कॉन्फ़िगरेशन प्रकार (डिफ़ॉल्ट: "स्कीमा") +मानक फ्लोप्रोसेसर तर्क (पल्सर कॉन्फ़िगरेशन, आदि) + +## एपीआई एकीकरण + +### पल्सर विषय (Pulsar Topics) + +**इनपुट टॉपिक (Input Topic)**: `objects-graphql-query-request` +स्कीमा: ऑब्जेक्ट्सक्वेरीरिक्वेस्ट (ObjectsQueryRequest) +गेटवे सेवाओं से ग्राफक्यूएल क्वेरी प्राप्त करता है + +**आउटपुट टॉपिक (Output Topic)**: `objects-graphql-query-response` +स्कीमा: ऑब्जेक्ट्सक्वेरीरिस्पांस (ObjectsQueryResponse) +क्वेरी परिणाम और त्रुटियां लौटाता है + +### गेटवे एकीकरण + +गेटवे और रिवर्स-गेटवे को निम्नलिखित के लिए एंडपॉइंट की आवश्यकता होगी: +1. क्लाइंट से ग्राफक्यूएल क्वेरी स्वीकार करें +2. पल्सर के माध्यम से क्वेरी सेवा को आगे बढ़ाएं +3. क्लाइंट को प्रतिक्रियाएं लौटाएं +4. ग्राफक्यूएल इंट्रॉस्पेक्शन क्वेरी का समर्थन करें + +### एजेंट टूल एकीकरण + +एक नया एजेंट टूल क्लास निम्नलिखित को सक्षम करेगा: +प्राकृतिक भाषा से ग्राफक्यूएल क्वेरी पीढ़ी +प्रत्यक्ष ग्राफक्यूएल क्वेरी निष्पादन +परिणाम व्याख्या और स्वरूपण +एजेंट निर्णय प्रवाह के साथ एकीकरण + +## सुरक्षा विचार + +**क्वेरी गहराई सीमित करना (Query Depth Limiting)**: गहराई से नेस्टेड क्वेरी को रोकें जो प्रदर्शन समस्याओं का कारण बन सकती हैं +**क्वेरी जटिलता विश्लेषण (Query Complexity Analysis)**: संसाधन समाप्त होने से रोकने के लिए क्वेरी जटिलता को सीमित करें +**फ़ील्ड-लेवल अनुमतियाँ (Field-Level Permissions)**: उपयोगकर्ता भूमिकाओं के आधार पर फ़ील्ड-लेवल एक्सेस नियंत्रण के लिए भविष्य का समर्थन +**इनपुट सैनिटाइजेशन (Input Sanitization)**: इंजेक्शन हमलों को रोकने के लिए सभी क्वेरी इनपुट को मान्य और सैनिटाइज करें +**दर सीमित करना (Rate Limiting)**: प्रति उपयोगकर्ता/संग्रहण क्वेरी दर सीमित करना लागू करें + +## प्रदर्शन विचार + +**क्वेरी योजना (Query Planning)**: सीक्यूएल पीढ़ी को अनुकूलित करने के लिए निष्पादन से पहले क्वेरी का विश्लेषण करें +**परिणाम कैशिंग (Result Caching)**: फ़ील्ड रिज़ॉल्वर स्तर पर बार-बार एक्सेस किए जाने वाले डेटा को कैश करने पर विचार करें +**कनेक्शन पूलिंग (Connection Pooling)**: कैसेंड्रा के लिए कुशल कनेक्शन पूल बनाए रखें +**बैच ऑपरेशन (Batch Operations)**: जब भी संभव हो, कई क्वेरी को संयोजित करें ताकि विलंबता कम हो सके +**निगरानी (Monitoring)**: अनुकूलन के लिए क्वेरी प्रदर्शन मेट्रिक्स को ट्रैक करें + +## परीक्षण रणनीति + +### यूनिट परीक्षण +रोस्कीमा परिभाषाओं से स्कीमा पीढ़ी +ग्राफक्यूएल क्वेरी पार्सिंग और सत्यापन +सीक्यूएल क्वेरी पीढ़ी तर्क +फ़ील्ड रिज़ॉल्वर कार्यान्वयन + +### अनुबंध परीक्षण +पल्सर संदेश अनुबंध अनुपालन +ग्राफक्यूएल स्कीमा वैधता +प्रतिक्रिया प्रारूप सत्यापन +त्रुटि संरचना सत्यापन + +### एकीकरण परीक्षण +परीक्षण कैसेंड्रा उदाहरण के खिलाफ एंड-टू-एंड क्वेरी निष्पादन +स्कीमा अपडेट हैंडलिंग +संबंध संकल्प +पेजिंग और फ़िल्टरिंग +त्रुटि परिदृश्य + +### प्रदर्शन परीक्षण +लोड के तहत क्वेरी थ्रूपुट +विभिन्न क्वेरी जटिलताओं के लिए प्रतिक्रिया समय +बड़े परिणाम सेट के साथ मेमोरी उपयोग +कनेक्शन पूल दक्षता + +## माइग्रेशन योजना + +इस नई क्षमता के रूप में माइग्रेशन की आवश्यकता नहीं है। सेवा निम्नलिखित करेगी: +1. कॉन्फ़िगरेशन से मौजूदा स्कीमा पढ़ें +2. स्टोरेज मॉड्यूल द्वारा बनाए गए मौजूदा कैसेंड्रा तालिकाओं से कनेक्ट करें +3. तैनाती पर तुरंत क्वेरी स्वीकार करना शुरू करें + +## समयरेखा + +सप्ताह 1-2: कोर सेवा कार्यान्वयन और स्कीमा पीढ़ी +सप्ताह 3: क्वेरी निष्पादन और सीक्यूएल अनुवाद +सप्ताह 4: संबंध संकल्प और अनुकूलन +सप्ताह 5: परीक्षण और प्रदर्शन ट्यूनिंग +सप्ताह 6: गेटवे एकीकरण और प्रलेखन + +## खुले प्रश्न + +1. **स्कीमा विकास (Schema Evolution)**: सेवा स्कीमा संक्रमण के दौरान क्वेरी को कैसे संभालती है? + विकल्प: स्कीमा अपडेट के दौरान क्वेरी को कतार में लगाएं + विकल्प: एक साथ कई स्कीमा संस्करणों का समर्थन करें + +2. **कैशिंग रणनीति (Caching Strategy)**: क्या क्वेरी परिणामों को कैश किया जाना चाहिए? + विचार करें: समय-आधारित समाप्ति + विचार करें: घटना-आधारित अमान्यकरण + +3. **संघटन समर्थन (Federation Support)**: क्या सेवा अन्य डेटा स्रोतों के साथ संयोजन के लिए ग्राफक्यूएल संघटन का समर्थन करना चाहिए? + यह संरचित और ग्राफ डेटा में एकीकृत क्वेरी को सक्षम करेगा + +4. **सदस्यता समर्थन (Subscription Support)**: क्या सेवा वास्तविक समय अपडेट के लिए ग्राफक्यूएल सदस्यता का समर्थन करना चाहिए? + + +5. **कस्टम स्केलर:** क्या डोमेन-विशिष्ट डेटा प्रकारों के लिए कस्टम स्केलर प्रकारों का समर्थन किया जाना चाहिए? + उदाहरण: DateTime, UUID, JSON फ़ील्ड + +## संदर्भ + +स्ट्रक्चर्ड डेटा तकनीकी विनिर्देश: `docs/tech-specs/structured-data.md` +स्ट्रॉबेरी GraphQL दस्तावेज़: https://strawberry.rocks/ +GraphQL विनिर्देश: https://spec.graphql.org/ +अपाचे कैसेंड्रा CQL संदर्भ: https://cassandra.apache.org/doc/stable/cassandra/cql/ +ट्रस्टग्राफ फ्लो प्रोसेसर दस्तावेज़: आंतरिक दस्तावेज़ \ No newline at end of file diff --git a/docs/tech-specs/graphql-query.pt.md b/docs/tech-specs/graphql-query.pt.md new file mode 100644 index 00000000..428a7fb0 --- /dev/null +++ b/docs/tech-specs/graphql-query.pt.md @@ -0,0 +1,383 @@ +# Especificação Técnica da Consulta GraphQL + +## Visão Geral + +Esta especificação descreve a implementação de uma interface de consulta GraphQL para o armazenamento de dados estruturados do TrustGraph no Apache Cassandra. Baseando-se nas capacidades de dados estruturados descritas na especificação structured-data.md, este documento detalha como as consultas GraphQL serão executadas contra tabelas do Cassandra contendo objetos estruturados extraídos e ingeridos. + +O serviço de consulta GraphQL fornecerá uma interface flexível e segura para consultar dados estruturados armazenados no Cassandra. Ele se adaptará dinamicamente às alterações de esquema, suportará consultas complexas, incluindo relacionamentos entre objetos, e se integrará perfeitamente à arquitetura existente baseada em mensagens do TrustGraph. + +## Objetivos + +**Suporte Dinâmico de Esquema**: Adaptar-se automaticamente às alterações de esquema na configuração sem reinicializações do serviço. +**Conformidade com os Padrões GraphQL**: Fornecer uma interface GraphQL padrão compatível com as ferramentas e clientes GraphQL existentes. +**Consultas Eficientes do Cassandra**: Traduzir consultas GraphQL em consultas CQL eficientes do Cassandra, respeitando as chaves de partição e os índices. +**Resolução de Relacionamentos**: Suportar resolvedores de campos GraphQL para relacionamentos entre diferentes tipos de objetos. +**Segurança de Tipo**: Garantir a execução de consultas e a geração de respostas com segurança de tipo, com base nas definições do esquema. +**Desempenho Escalável**: Lidar com consultas concorrentes de forma eficiente, com um pool de conexões adequado e otimização de consultas. +**Integração de Solicitação/Resposta**: Manter a compatibilidade com o padrão de solicitação/resposta baseado no Pulsar do TrustGraph. +**Tratamento de Erros**: Fornecer relatórios de erros abrangentes para incompatibilidades de esquema, erros de consulta e problemas de validação de dados. + +## Contexto + +A implementação do armazenamento de dados estruturados (trustgraph-flow/trustgraph/storage/objects/cassandra/) grava objetos em tabelas do Cassandra com base em definições de esquema armazenadas no sistema de configuração do TrustGraph. Essas tabelas usam uma estrutura de chave de partição composta com chaves primárias definidas por coleção e esquema, permitindo consultas eficientes dentro das coleções. + +Limitações atuais que esta especificação aborda: +Não há interface de consulta para os dados estruturados armazenados no Cassandra. +Impossibilidade de aproveitar os poderosos recursos de consulta do GraphQL para dados estruturados. +Falta de suporte para a travessia de relacionamentos entre objetos relacionados. +Falta de uma linguagem de consulta padronizada para acesso a dados estruturados. + +O serviço de consulta GraphQL preencherá essas lacunas fornecendo: +Uma interface GraphQL padrão para consultar tabelas do Cassandra. +Geração dinâmica de esquemas GraphQL a partir da configuração do TrustGraph. +Tradução eficiente de consultas GraphQL para CQL do Cassandra. +Suporte para resolução de relacionamentos por meio de resolvedores de campos. + +## Design Técnico + +### Arquitetura + +O serviço de consulta GraphQL será implementado como um novo processador de fluxo do TrustGraph, seguindo padrões estabelecidos: + +**Localização do Módulo**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**Componentes Principais**: + +1. **Processador do Serviço de Consulta GraphQL** + Estende a classe base FlowProcessor. + Implementa um padrão de solicitação/resposta semelhante aos serviços de consulta existentes. + Monitora a configuração para atualizações de esquema. + Mantém o esquema GraphQL sincronizado com a configuração. + +2. **Gerador de Esquema Dinâmico** + Converte definições de RowSchema do TrustGraph em tipos GraphQL. + Cria tipos de objetos GraphQL com definições de campo adequadas. + Gera o tipo de consulta raiz com resolvedores baseados em coleções. + Atualiza o esquema GraphQL quando a configuração é alterada. + +3. **Executor de Consulta** + Analisa consultas GraphQL recebidas usando a biblioteca Strawberry. + Valida as consultas em relação ao esquema atual. + Executa as consultas e retorna respostas estruturadas. + Lida com erros de forma elegante com mensagens de erro detalhadas. + +4. **Tradutor de Consulta do Cassandra** + Converte seleções GraphQL em consultas CQL. + Otimiza as consultas com base nos índices e chaves de partição disponíveis. + Lida com filtragem, paginação e classificação. + Gerencia o pool de conexões e o ciclo de vida da sessão. + +5. **Resolvedor de Relacionamentos** + Implementa resolvedores de campos para relacionamentos entre objetos. + Realiza carregamento em lote eficiente para evitar consultas N+1. + Armazena em cache os relacionamentos resolvidos dentro do contexto da solicitação. + Suporta a travessia de relacionamentos tanto para frente quanto para trás. + +### Monitoramento do Esquema de Configuração + +O serviço registrará um manipulador de configuração para receber atualizações de esquema: + +```python +self.register_config_handler(self.on_schema_config) +``` + +Quando os esquemas mudam: +1. Analisar as novas definições de esquema a partir da configuração +2. Regenerar os tipos e resolvedores GraphQL +3. Atualizar o esquema executável +4. Limpar quaisquer caches dependentes do esquema + +### Geração de Esquema GraphQL + +Para cada RowSchema na configuração, gerar: + +1. **Tipo de Objeto GraphQL**: + Mapear tipos de campo (string → String, integer → Int, float → Float, boolean → Boolean) + Marcar campos obrigatórios como não nulos no GraphQL + Adicionar descrições de campo do esquema + +2. **Campos de Consulta Raiz**: + Consulta de coleção (por exemplo, `customers`, `transactions`) + Argumentos de filtragem com base em campos indexados + Suporte de paginação (limite, deslocamento) + Opções de ordenação para campos classificáveis + +3. **Campos de Relacionamento**: + Identificar relacionamentos de chave estrangeira do esquema + Criar resolvedores de campo para objetos relacionados + Suportar relacionamentos de objeto único e de lista + +### Fluxo de Execução da Consulta + +1. **Recepção da Requisição**: + Receber ObjectsQueryRequest do Pulsar + Extrair a string de consulta GraphQL e as variáveis + Identificar o contexto de usuário e coleção + +2. **Validação da Consulta**: + Analisar a consulta GraphQL usando Strawberry + Validar em relação ao esquema atual + Verificar as seleções de campo e os tipos de argumento + +3. **Geração de CQL**: + Analisar as seleções GraphQL + Construir a consulta CQL com as cláusulas WHERE apropriadas + Incluir a coleção na chave de partição + Aplicar filtros com base nos argumentos GraphQL + +4. **Execução da Consulta**: + Executar a consulta CQL contra o Cassandra + Mapear os resultados para a estrutura de resposta GraphQL + Resolver quaisquer campos de relacionamento + Formatar a resposta de acordo com a especificação GraphQL + +5. **Entrega da Resposta**: + Criar uma ObjectsQueryResponse com os resultados + Incluir quaisquer erros de execução + Enviar a resposta via Pulsar com o ID de correlação + +### Modelos de Dados + +> **Nota**: Um esquema StructuredQueryRequest/Response existente existe em `trustgraph-base/trustgraph/schema/services/structured_query.py`. No entanto, ele carece de campos críticos (usuário, coleção) e usa tipos subótimos. Os esquemas abaixo representam a evolução recomendada, que deve substituir os esquemas existentes ou ser criada como novos tipos ObjectsQueryRequest/Response. + +#### Esquema de Requisição (ObjectsQueryRequest) + +```python +from pulsar.schema import Record, String, Map, Array + +class ObjectsQueryRequest(Record): + user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest) + collection = String() # Data collection identifier (required for partition key) + query = String() # GraphQL query string + variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types) + operation_name = String() # Operation to execute for multi-operation documents +``` + +**Justificativa para as alterações em relação ao StructuredQueryRequest existente:** +Adicionados os campos `user` e `collection` para corresponder ao padrão de outros serviços de consulta. +Esses campos são essenciais para identificar o keyspace e a coleção do Cassandra. +As variáveis permanecem como Map(String()) por enquanto, mas idealmente deveriam suportar todos os tipos JSON. + +#### Esquema de Resposta (ObjectsQueryResponse) + +```python +from pulsar.schema import Record, String, Array +from ..core.primitives import Error + +class GraphQLError(Record): + message = String() + path = Array(String()) # Path to the field that caused the error + extensions = Map(String()) # Additional error metadata + +class ObjectsQueryResponse(Record): + error = Error() # System-level error (connection, timeout, etc.) + data = String() # JSON-encoded GraphQL response data + errors = Array(GraphQLError) # GraphQL field-level errors + extensions = Map(String()) # Query metadata (execution time, etc.) +``` + +**Justificativa para as alterações em relação à StructuredQueryResponse existente:** +Distingue entre erros do sistema (`error`) e erros do GraphQL (`errors`) +Utiliza objetos GraphQLError estruturados em vez de um array de strings +Adiciona o campo `extensions` para conformidade com a especificação do GraphQL +Mantém os dados como uma string JSON para compatibilidade, embora os tipos nativos seriam preferíveis + +### Otimização de Consultas Cassandra + +O serviço otimizará as consultas do Cassandra, através de: + +1. **Respeitando as Chaves de Partição:** + Inclua sempre a coleção nas consultas + Utilize as chaves primárias definidas no esquema de forma eficiente + Evite varreduras completas da tabela + +2. **Aproveitando os Índices:** + Utilize índices secundários para filtragem + Combine vários filtros sempre que possível + Avise quando as consultas podem ser ineficientes + +3. **Carregamento em Lote:** + Colete consultas de relacionamento + Execute em lotes para reduzir o número de viagens de ida e volta + Armazene em cache os resultados dentro do contexto da requisição + +4. **Gerenciamento de Conexões:** + Mantenha sessões persistentes do Cassandra + Utilize um pool de conexões + Lide com a reconexão em caso de falhas + +### Exemplos de Consultas GraphQL + +#### Consulta Simples de Coleção +```graphql +{ + customers(status: "active") { + customer_id + name + email + registration_date + } +} +``` + +#### Consulta com Relacionamentos +```graphql +{ + orders(order_date_gt: "2024-01-01") { + order_id + total_amount + customer { + name + email + } + items { + product_name + quantity + price + } + } +} +``` + +#### Consulta Paginação +```graphql +{ + products(limit: 20, offset: 40) { + product_id + name + price + category + } +} +``` + +### Dependências de Implementação + +**Strawberry GraphQL**: Para definição de esquema GraphQL e execução de consultas. +**Cassandra Driver**: Para conectividade com o banco de dados (já utilizado no módulo de armazenamento). +**TrustGraph Base**: Para FlowProcessor e definições de esquema. +**Configuration System**: Para monitoramento e atualizações de esquema. + +### Interface de Linha de Comando + +O serviço fornecerá um comando de CLI: `kg-query-objects-graphql-cassandra` + +Argumentos: +`--cassandra-host`: Ponto de contato do cluster Cassandra. +`--cassandra-username`: Nome de usuário de autenticação. +`--cassandra-password`: Senha de autenticação. +`--config-type`: Tipo de configuração para esquemas (padrão: "schema"). +Argumentos padrão do FlowProcessor (configuração do Pulsar, etc.). + +## Integração de API + +### Tópicos Pulsar + +**Tópico de Entrada**: `objects-graphql-query-request` +Esquema: ObjectsQueryRequest +Recebe consultas GraphQL de serviços de gateway. + +**Tópico de Saída**: `objects-graphql-query-response` +Esquema: ObjectsQueryResponse +Retorna resultados de consulta e erros. + +### Integração de Gateway + +O gateway e o gateway reverso precisarão de endpoints para: +1. Aceitar consultas GraphQL de clientes. +2. Encaminhar para o serviço de consulta via Pulsar. +3. Retornar respostas aos clientes. +4. Suportar consultas de introspecção GraphQL. + +### Integração da Ferramenta de Agente + +Uma nova classe de ferramenta de agente permitirá: +Geração de consultas GraphQL a partir de linguagem natural. +Execução direta de consultas GraphQL. +Interpretação e formatação de resultados. +Integração com fluxos de decisão do agente. + +## Considerações de Segurança + +**Limitação de Profundidade da Consulta**: Prevenir consultas profundamente aninhadas que possam causar problemas de desempenho. +**Análise de Complexidade da Consulta**: Limitar a complexidade da consulta para evitar o esgotamento de recursos. +**Permissões de Nível de Campo**: Suporte futuro para controle de acesso baseado em funções de usuário. +**Sanitização de Entrada**: Validar e sanitizar todas as entradas de consulta para prevenir ataques de injeção. +**Limitação de Taxa**: Implementar a limitação de taxa de consulta por usuário/coleção. + +## Considerações de Desempenho + +**Planejamento de Consulta**: Analisar consultas antes da execução para otimizar a geração de CQL. +**Cache de Resultados**: Considerar o cache de dados acessados com frequência no nível do resolvedor de campo. +**Pool de Conexões**: Manter pools de conexão eficientes para o Cassandra. +**Operações em Lote**: Combinar várias consultas sempre que possível para reduzir a latência. +**Monitoramento**: Rastrear métricas de desempenho da consulta para otimização. + +## Estratégia de Teste + +### Testes Unitários +Geração de esquema a partir de definições de RowSchema. +Análise e validação de consultas GraphQL. +Lógica de geração de consultas CQL. +Implementações de resolvedores de campo. + +### Testes de Contrato +Conformidade do contrato de mensagem Pulsar. +Validade do esquema GraphQL. +Verificação do formato da resposta. +Validação da estrutura de erro. + +### Testes de Integração +Execução de consulta de ponta a ponta contra uma instância de teste do Cassandra. +Tratamento de atualização de esquema. +Resolução de relacionamento. +Paginação e filtragem. +Cenários de erro. + +### Testes de Desempenho +Taxa de transferência de consultas sob carga. +Tempo de resposta para várias complexidades de consulta. +Uso de memória com grandes conjuntos de resultados. +Eficiência do pool de conexões. + +## Plano de Migração + +Não é necessária migração, pois esta é uma nova funcionalidade. O serviço irá: +1. Ler esquemas existentes da configuração. +2. Conectar-se às tabelas Cassandra existentes criadas pelo módulo de armazenamento. +3. Começar a aceitar consultas imediatamente após a implantação. + +## Perguntas Abertas + +1. **Evolução do Esquema**: Como o serviço deve lidar com consultas durante as transições de esquema? +Opção: Enfileirar consultas durante as atualizações de esquema. +Opção: Suportar várias versões de esquema simultaneamente. + +2. **Estratégia de Cache**: Os resultados da consulta devem ser armazenados em cache? +Considerar: Expiração baseada em tempo. +Considerar: Invalidação baseada em eventos. + +3. **Suporte à Federação**: O serviço deve suportar a federação GraphQL para combinar com outras fontes de dados? + Permitiria consultas unificadas em dados estruturados e de grafo. + +4. **Suporte a Assinaturas**: O serviço deve suportar assinaturas GraphQL para atualizações em tempo real? +Requereria suporte WebSocket no gateway. + + 5. **Escalares Personalizados**: O serviço deve suportar tipos escalares personalizados para tipos de dados específicos do domínio? +Exemplos: DateTime, UUID, campos JSON. + + ## Referências + +Especificação de Dados Estruturados: ⟦CODE_0⟧ + Documentação do Strawberry GraphQL: ⟦URL_0⟧ +Especificação GraphQL: ⟦URL_0⟧ +Referência CQL do Apache Cassandra: ⟦URL_0⟧ + Documentação do Flow Processor TrustGraph: Documentação interna. + +## Referências + +Especificação Técnica de Dados Estruturados: `docs/tech-specs/structured-data.md` +Documentação do Strawberry GraphQL: https://strawberry.rocks/ +Especificação do GraphQL: https://spec.graphql.org/ +Referência CQL do Apache Cassandra: https://cassandra.apache.org/doc/stable/cassandra/cql/ +Documentação do Processador de Fluxo TrustGraph: Documentação interna \ No newline at end of file diff --git a/docs/tech-specs/graphql-query.ru.md b/docs/tech-specs/graphql-query.ru.md new file mode 100644 index 00000000..974fd629 --- /dev/null +++ b/docs/tech-specs/graphql-query.ru.md @@ -0,0 +1,383 @@ +# Техническая спецификация запросов GraphQL + +## Обзор + +Эта спецификация описывает реализацию интерфейса запросов GraphQL для хранения структурированных данных TrustGraph в Apache Cassandra. Основываясь на возможностях структурированных данных, описанных в спецификации structured-data.md, этот документ подробно описывает, как запросы GraphQL будут выполняться к таблицам Cassandra, содержащим извлеченные и импортированные структурированные объекты. + +Сервис запросов GraphQL предоставит гибкий и типобезопасный интерфейс для запроса структурированных данных, хранящихся в Cassandra. Он будет динамически адаптироваться к изменениям схемы, поддерживать сложные запросы, включая отношения между объектами, и беспрепятственно интегрироваться с существующей архитектурой TrustGraph, основанной на обмене сообщениями. + +## Цели + +**Динамическая поддержка схемы**: Автоматическая адаптация к изменениям схемы в конфигурации без перезапуска сервиса. +**Соответствие стандартам GraphQL**: Предоставление стандартного интерфейса GraphQL, совместимого с существующими инструментами и клиентами GraphQL. +**Эффективные запросы к Cassandra**: Преобразование запросов GraphQL в эффективные запросы CQL к Cassandra, учитывающие первичные ключи и индексы. +**Разрешение отношений**: Поддержка решателей полей GraphQL для отношений между различными типами объектов. +**Типобезопасность**: Обеспечение типобезопасного выполнения запросов и генерации ответов на основе определений схемы. +**Масштабируемая производительность**: Эффективная обработка одновременных запросов с использованием правильного пула соединений и оптимизации запросов. +**Интеграция запросов/ответов**: Поддержка существующей архитектуры TrustGraph, основанной на шаблоне запросов/ответов с использованием Pulsar. +**Обработка ошибок**: Предоставление подробной отчетности об ошибках для несоответствий схемы, ошибок запросов и проблем проверки данных. + +## Предыстория + +Реализация хранения структурированных данных (trustgraph-flow/trustgraph/storage/objects/cassandra/) записывает объекты в таблицы Cassandra на основе определений схемы, хранящихся в системе конфигурации TrustGraph. Эти таблицы используют структуру составного первичного ключа с коллекциями и первичными ключами, определенными схемой, что обеспечивает эффективные запросы внутри коллекций. + +Текущие ограничения, которые эта спецификация решает: +Отсутствие интерфейса запросов для структурированных данных, хранящихся в Cassandra. +Невозможность использования мощных возможностей запросов GraphQL для структурированных данных. +Отсутствие поддержки обхода отношений между связанными объектами. +Отсутствие стандартизированного языка запросов для доступа к структурированным данным. + +Сервис запросов GraphQL устранит эти недостатки, предоставив: +Стандартный интерфейс GraphQL для запросов к таблицам Cassandra. +Динамическую генерацию схем GraphQL из конфигурации TrustGraph. +Эффективное преобразование запросов GraphQL в CQL для Cassandra. +Поддержку разрешения отношений с помощью решателей полей. + +## Технический дизайн + +### Архитектура + +Сервис запросов GraphQL будет реализован как новый обработчик потоков TrustGraph, следуя установленным шаблонам: + +**Местоположение модуля**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**Основные компоненты**: + +1. **Обработчик сервиса запросов GraphQL** + Расширяет базовый класс FlowProcessor. + Реализует шаблон запросов/ответов, аналогичный существующим сервисам запросов. + Отслеживает конфигурацию на предмет обновлений схемы. + Поддерживает синхронизацию схемы GraphQL с конфигурацией. + +2. **Генератор динамической схемы** + Преобразует определения RowSchema TrustGraph в типы GraphQL. + Создает типы объектов GraphQL с соответствующими определениями полей. + Генерирует корневой тип запроса с решателями на основе коллекций. + Обновляет схему GraphQL при изменении конфигурации. + +3. **Исполнитель запросов** + Анализирует входящие запросы GraphQL с использованием библиотеки Strawberry. + Проверяет запросы на соответствие текущей схеме. + Выполняет запросы и возвращает структурированные ответы. + Обрабатывает ошибки с подробными сообщениями об ошибках. + +4. **Транслятор запросов Cassandra** + Преобразует выборки GraphQL в запросы CQL. + Оптимизирует запросы на основе доступных индексов и первичных ключей. + Обрабатывает фильтрацию, пагинацию и сортировку. + Управляет пулом соединений и жизненным циклом сессии. + +5. **Разрешитель отношений** + Реализует решатели полей для отношений между объектами. + Выполняет эффективную пакетную загрузку для предотвращения запросов N+1. + Кэширует разрешенные отношения в контексте запроса. + Поддерживает как прямой, так и обратный обход отношений. + +### Мониторинг схемы конфигурации + +Сервис зарегистрирует обработчик конфигурации для получения обновлений схемы: + +```python +self.register_config_handler(self.on_schema_config) +``` + +Когда схемы меняются: +1. Разбор новых определений схемы из конфигурации +2. Регенерация типов GraphQL и решателей +3. Обновление исполняемой схемы +4. Очистка любых кэшей, зависящих от схемы + +### Генерация схемы GraphQL + +Для каждой RowSchema в конфигурации, генерируется: + +1. **Тип объекта GraphQL**: + Отображение типов полей (string → String, integer → Int, float → Float, boolean → Boolean) + Отметка обязательных полей как non-nullable в GraphQL + Добавление описаний полей из схемы + +2. **Корневые поля запроса**: + Запрос коллекции (например, `customers`, `transactions`) + Аргументы фильтрации на основе индексированных полей + Поддержка пагинации (limit, offset) + Варианты сортировки для полей, поддерживающих сортировку + +3. **Поля отношений**: + Определение отношений внешнего ключа из схемы + Создание решателей полей для связанных объектов + Поддержка как одиночных объектов, так и списков отношений + +### Поток выполнения запроса + +1. **Прием запроса**: + Получение ObjectsQueryRequest от Pulsar + Извлечение строки запроса GraphQL и переменных + Определение контекста пользователя и коллекции + +2. **Валидация запроса**: + Разбор запроса GraphQL с использованием Strawberry + Проверка на соответствие текущей схеме + Проверка выбранных полей и типов аргументов + +3. **Генерация CQL**: + Анализ выбранных элементов GraphQL + Создание запроса CQL с правильными предложениями WHERE + Включение коллекции в ключ партиции + Применение фильтров на основе аргументов GraphQL + +4. **Выполнение запроса**: + Выполнение запроса CQL к Cassandra + Отображение результатов в структуру ответа GraphQL + Разрешение любых полей отношений + Форматирование ответа в соответствии со спецификацией GraphQL + +5. **Доставка ответа**: + Создание ObjectsQueryResponse с результатами + Включение любых ошибок выполнения + Отправка ответа через Pulsar с идентификатором корреляции + +### Модели данных + +> **Примечание**: Существует существующая схема StructuredQueryRequest/Response в `trustgraph-base/trustgraph/schema/services/structured_query.py`. Однако, в ней отсутствуют критические поля (user, collection) и используются неоптимальные типы. Схемы ниже представляют собой рекомендуемую эволюцию, которая должна либо заменить существующие схемы, либо быть создана как новые типы ObjectsQueryRequest/Response. + +#### Схема запроса (ObjectsQueryRequest) + +```python +from pulsar.schema import Record, String, Map, Array + +class ObjectsQueryRequest(Record): + user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest) + collection = String() # Data collection identifier (required for partition key) + query = String() # GraphQL query string + variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types) + operation_name = String() # Operation to execute for multi-operation documents +``` + +**Обоснование изменений по сравнению с существующим запросом StructuredQueryRequest:** +Добавлены поля `user` и `collection` для соответствия шаблону других сервисов запросов. +Эти поля необходимы для идентификации пространства ключей и коллекции Cassandra. +Переменные пока остаются Map(String()), но в идеале должны поддерживать все типы JSON. + +#### Схема ответа (ObjectsQueryResponse) + +```python +from pulsar.schema import Record, String, Array +from ..core.primitives import Error + +class GraphQLError(Record): + message = String() + path = Array(String()) # Path to the field that caused the error + extensions = Map(String()) # Additional error metadata + +class ObjectsQueryResponse(Record): + error = Error() # System-level error (connection, timeout, etc.) + data = String() # JSON-encoded GraphQL response data + errors = Array(GraphQLError) # GraphQL field-level errors + extensions = Map(String()) # Query metadata (execution time, etc.) +``` + +**Обоснование изменений по сравнению с существующим StructuredQueryResponse:** +Различает системные ошибки (`error`) и ошибки GraphQL (`errors`) +Использует структурированные объекты GraphQLError вместо массива строк +Добавляет поле `extensions` для соответствия спецификации GraphQL +Сохраняет данные в виде строки JSON для совместимости, хотя нативные типы были бы предпочтительнее + +### Оптимизация запросов Cassandra + +Сервис будет оптимизировать запросы Cassandra следующим образом: + +1. **Соблюдение ключей разделов (Partition Keys):** + Всегда включайте коллекцию в запросы + Эффективно используйте первичные ключи, определенные в схеме + Избегайте полного сканирования таблицы + +2. **Использование индексов:** + Используйте вторичные индексы для фильтрации + Объединяйте несколько фильтров, когда это возможно + Предупреждайте, когда запросы могут быть неэффективными + +3. **Пакетная загрузка:** + Собирайте запросы для получения взаимосвязей + Выполняйте их пакетами для уменьшения количества обращений + Кэшируйте результаты в контексте запроса + +4. **Управление соединениями:** + Поддерживайте постоянные сессии Cassandra + Используйте пули соединений + Обрабатывайте повторное подключение в случае сбоев + +### Примеры запросов GraphQL + +#### Простой запрос коллекции +```graphql +{ + customers(status: "active") { + customer_id + name + email + registration_date + } +} +``` + +#### Запрос со связями +```graphql +{ + orders(order_date_gt: "2024-01-01") { + order_id + total_amount + customer { + name + email + } + items { + product_name + quantity + price + } + } +} +``` + +#### Разделенная на страницы выборка +```graphql +{ + products(limit: 20, offset: 40) { + product_id + name + price + category + } +} +``` + +### Зависимости реализации + +**Strawberry GraphQL**: Для определения схемы GraphQL и выполнения запросов. +**Cassandra Driver**: Для подключения к базе данных (уже используется в модуле хранения). +**TrustGraph Base**: Для FlowProcessor и определений схем. +**Configuration System**: Для мониторинга и обновления схем. + +### Интерфейс командной строки + +Сервис предоставит команду интерфейса командной строки: `kg-query-objects-graphql-cassandra` + +Аргументы: +`--cassandra-host`: Точка контакта кластера Cassandra. +`--cassandra-username`: Имя пользователя для аутентификации. +`--cassandra-password`: Пароль для аутентификации. +`--config-type`: Тип конфигурации для схем (по умолчанию: "schema"). +Стандартные аргументы FlowProcessor (конфигурация Pulsar и т.д.). + +## Интеграция API + +### Темы Pulsar + +**Входная тема**: `objects-graphql-query-request` +Схема: ObjectsQueryRequest +Получает GraphQL-запросы от шлюзовых сервисов. + +**Выходная тема**: `objects-graphql-query-response` +Схема: ObjectsQueryResponse +Возвращает результаты запросов и ошибки. + +### Интеграция с шлюзом + +Шлюз и обратный шлюз потребуют конечных точек для: +1. Приема GraphQL-запросов от клиентов. +2. Передачи запросов сервису запросов через Pulsar. +3. Возврата ответов клиентам. +4. Поддержки GraphQL-запросов на интроспекцию. + +### Интеграция с инструментом агента + +Новый класс инструмента агента позволит: +Генерировать GraphQL-запросы из естественного языка. +Выполнять GraphQL-запросы напрямую. +Интерпретировать и форматировать результаты. +Интегрироваться с потоками принятия решений агентом. + +## Вопросы безопасности + +**Ограничение глубины запросов**: Предотвращает вложенные запросы, которые могут вызвать проблемы с производительностью. +**Анализ сложности запросов**: Ограничивает сложность запросов для предотвращения исчерпания ресурсов. +**Разрешения на уровне полей**: Будущая поддержка контроля доступа на уровне полей на основе ролей пользователей. +**Санитизация входных данных**: Проверяет и очищает все входные данные запросов для предотвращения атак внедрения. +**Ограничение скорости**: Реализует ограничение скорости запросов на пользователя/коллекцию. + +## Вопросы производительности + +**Планирование запросов**: Анализирует запросы перед выполнением для оптимизации генерации CQL. +**Кэширование результатов**: Рассмотрите возможность кэширования часто используемых данных на уровне решателя полей. +**Пул соединений**: Поддерживайте эффективные пулы соединений к Cassandra. +**Пакетные операции**: Объединяйте несколько запросов, когда это возможно, для уменьшения задержки. +**Мониторинг**: Отслеживайте метрики производительности запросов для оптимизации. + +## Стратегия тестирования + +### Unit Tests +Генерация схемы на основе определений RowSchema +Разбор и проверка запросов GraphQL +Логика генерации запросов CQL +Реализации решателей полей + +### Contract Tests +Соответствие контракту сообщений Pulsar +Достоверность схемы GraphQL +Проверка формата ответа +Проверка структуры ошибок + +### Integration Tests +Комплексное выполнение запросов к тестовой инстанции Cassandra +Обработка обновлений схемы +Разрешение связей +Пагинация и фильтрация +Сценарии ошибок + +### Performance Tests +Производительность запросов при высокой нагрузке +Время отклика для различных уровней сложности запросов +Использование памяти при работе с большими наборами результатов +Эффективность пула соединений + +## План миграции + +Миграция не требуется, так как это новая функциональность. Сервис будет: +1. Считывать существующие схемы из конфигурации +2. Подключаться к существующим таблицам Cassandra, созданным модулем хранения +3. Начинать принимать запросы сразу после развертывания + +## Сроки + +1-2 неделя: Реализация основного сервиса и генерация схемы +3 неделя: Выполнение запросов и трансляция CQL +4 неделя: Разрешение связей и оптимизация +5 неделя: Тестирование и настройка производительности +6 неделя: Интеграция с шлюзом и документация + +## Открытые вопросы + +1. **Эволюция схемы**: Как сервис должен обрабатывать запросы во время изменений схемы? + Вариант: Помещать запросы в очередь во время обновлений схемы + Вариант: Поддерживать несколько версий схемы одновременно + +2. **Стратегия кэширования**: Следует ли кэшировать результаты запросов? + Рассмотреть: Временное истечение срока действия + Рассмотреть: Инвалидация на основе событий + +3. **Поддержка федерации**: Следует ли сервису поддерживать GraphQL federation для объединения с другими источниками данных? + Это позволит выполнять унифицированные запросы к структурированным и графовым данным + +4. **Поддержка подписок**: Следует ли сервису поддерживать GraphQL subscriptions для получения обновлений в реальном времени? + Это потребует поддержки WebSocket в шлюзе + +5. **Пользовательские скаляры**: Следует ли поддерживать пользовательские скалярные типы для специфических типов данных? + Примеры: DateTime, UUID, JSON-поля + +## Ссылки + +Техническая спецификация структурированных данных: `docs/tech-specs/structured-data.md` +Документация Strawberry GraphQL: https://strawberry.rocks/ +Спецификация GraphQL: https://spec.graphql.org/ +Справочник Apache Cassandra CQL: https://cassandra.apache.org/doc/stable/cassandra/cql/ +Документация TrustGraph Flow Processor: Внутренняя документация \ No newline at end of file diff --git a/docs/tech-specs/graphql-query.sw.md b/docs/tech-specs/graphql-query.sw.md new file mode 100644 index 00000000..efaa049a --- /dev/null +++ b/docs/tech-specs/graphql-query.sw.md @@ -0,0 +1,383 @@ +# Vipimo vya Kiufundi vya Umasilisho wa GraphQL + +## Muhtasari + +Maelekezo haya yanaelezea utekelezaji wa kiolesura cha uwasilisho wa GraphQL kwa kuhifadhi data iliyopangwa ya TrustGraph katika Apache Cassandra. Kujenga juu ya uwezo wa data iliyopangwa uliyoainishwa katika maelekezo ya structured-data.md, hati hii inaeleza jinsi maswali ya GraphQL yanavyotekelezwa dhidi ya meza za Cassandra zinazokuza vitu vilivyochukuliwa na vilivyomingwa. + +Huduma ya uwasilisho wa GraphQL itatoa kiolesura kinachobadilika na kinacholingana na aina kwa kuuliza data iliyopangwa iliyohifadhiwa katika Cassandra. Itabadilika moja kwa moja kwa mabadiliko ya mpango, inasaidia maswali tata ikiwa ni pamoja na uhusiano kati ya vitu, na itounganisha kikamilifu na usanifu uliopo wa TrustGraph unaotegemea ujumbe. + +## Lengo + +**Usaidizi wa Mpango Unaobadilika**: Kujifunga kiotomatiki kwa mabadiliko ya mpango bila kuacha huduma +**Uzingatiaji wa Viwango vya GraphQL**: Kutoa kiolesura cha kawaida cha GraphQL kinacholingana na zana na wateja wa GraphQL iliyopo +**Maswali ya Ufanisi ya Cassandra**: Kubadilisha maswali ya GraphQL kuwa maswali ya ufanisi ya Cassandra CQL kwa kuheshimu funguo za sehemu na fahirisi +**Suluhisho la Uhusiano**: Kusaidia suluhu za GraphQL kwa uhusiano kati ya aina tofauti za vitu +**Usalama wa Aina**: Kuhakikisha utekelezaji wa aina-salama wa maswali na utengenezaji wa majibu kulingana na maelezo ya mpango +**Utendaji Unaoweza Kukidhi Mahitaji**: Kushughulikia maswali mengi kwa ufanisi kwa kutumia udhibiti wa muunganisho na uboreshaji wa maswali +**Ujumuishaji wa Ombi/Jibu**: Kuhifadhi utangamano na mtindo wa ombi/jibu wa TrustGraph unaotegemea Pulsar +**Usimamizi wa Makosa**: Kutoa ripoti kamili ya makosa kwa kutofautiana kwa mpango, makosa ya maswali, na masuala ya uthibitisho wa data + +## Asili + +Utekelezaji wa uhifadhi wa data iliyopangwa (trustgraph-flow/trustgraph/storage/objects/cassandra/) huandika vitu kwenye meza za Cassandra kulingana na maelezo ya mpango yaliyohifadhiwa katika mfumo wa usanidi wa TrustGraph. Meza hizi hutumia muundo wa funguo ya sehemu iliyounganishwa na funguo za msingi zilizobainishwa na mpango, na kuwezesha maswali ya ufanisi ndani ya makusanyo. + +Marekebisho ya sasa ambayo maelekezo haya yanaashiria: +Hakuna kiolesura cha kuuliza kwa data iliyopangwa iliyohifadhiwa katika Cassandra +Uwasilishaji usio wa uwezo wa uwezo wa maswali ya GraphQL kwa data iliyopangwa +Usaidizi usio na uhusiano kati ya vitu vinavyohusiana +Ukosefu wa lugha ya kawaida ya kuuliza kwa upataji wa data iliyopangwa + +Huduma ya uwasilisho wa GraphQL itafunga pengo hizi kwa: +Kutoa kiolesura cha kawaida cha GraphQL kwa kuuliza meza za Cassandra +Kujenga schemas za GraphQL kwa moja kwa moja kutoka usanidi wa TrustGraph +Kubadilisha maswali ya GraphQL kwa ufanisi kwa CQL ya Cassandra +Kusaidia suluhisho la uhusiano kupitia suluhu za uwanja + +## Ubunifu wa Kiufundi + +### Usanifu + +Huduma ya uwasilisho wa GraphQL itatekelezwa kama mchakato mpya wa TrustGraph kufuatia mbinu zilizopo: + +**Eneo la Moduli**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**Vipengele Muhimu**: + +1. **Mchakato wa Huduma ya Uwasilisho wa GraphQL** + Huendelea na darasa la msingi la FlowProcessor + Inatekeleza mtindo wa ombi/jibu sawa na huduma zingine za kuuliza + Inafuatilia usanidi kwa sasisho za mpango + Inahifadhi mpango wa GraphQL inayosawazishwa na usanidi + +2. **Mjenzi wa Mpango wa Njia Moja Moja** + Inabadilisha maelezo ya TrustGraph RowSchema kuwa aina za GraphQL + Inaunda aina za vitu vya GraphQL na maelezo ya uwanja sahihi + Inazalisha aina ya mizizi ya Ombi na suluhu za msingi za makusanyo + Inasasisha mpango wa GraphQL wakati usanidi unabadilika + +3. **Mtekelezaji wa Maswali** + Inachambua maswali ya GraphQL yanayoingia kwa kutumia maktaba ya Strawberry + Inathibitisha maswali dhidi ya mpango wa sasa + Inatekeleza maswali na inarudisha majibu yaliyopangwa + Inashughulikia makosa kwa utulivu na ujumbe wa makosa wa kina + +4. **Mhubiri wa Maswali ya Cassandra** + Inabadilisha uteuzi wa GraphQL kuwa maswali ya CQL + Inaboresha maswali kulingana na fahirisi na funguo za sehemu zinazopatikana + Inashughulikia kuchujwa, upangishaji, na utaratibu + Inadhibiti udhibiti wa muunganisho na maisha ya kikao + +5. **Suluhu ya Uhusiano** + Inatekeleza suluhu za uwanja kwa uhusiano wa vitu + Inafanya upakiaji wa kundi ili kuepuka maswali ya N+1 + Inahifadhi suluhu za uhusiano ndani ya muktadha wa ombi + Inasaidia utambuzi wa uhusiano wa mbele na nyuma + +### Ufuatiliaji wa Mpango wa Usanidi + +Huduma itasajili mshukiwa wa usanidi ili kupokea sasisho za mpango: + +```python +self.register_config_handler(self.on_schema_config) +``` + +Wakati schemas hubadilika: +1. Changanua maelezo mapya ya schema kutoka kwa usanidi +2. Tengeneza upya aina za GraphQL na suluhu +3. Sasisha schema inayotumika +4. Ondoa kumbukumbu zozote zinazotegemea schema + +### Uzalishaji wa Schema ya GraphQL + +Kwa kila RowSchema katika usanidi, tengeneza: + +1. **Aina ya Kitu cha GraphQL**: + Linganisha aina za sehemu (string → String, integer → Int, float → Float, boolean → Boolean) + Weka sehemu ambazo zinahitajika kama zisizo na thamani null katika GraphQL + Ongeza maelezo ya sehemu kutoka kwa schema + +2. **Sehemu za Uchunguzi Mkuu**: + Uchunguzi wa mkusanyiko (e.g., `customers`, `transactions`) + Vigezo vya kuchujwa kulingana na sehemu zilizo na fahirisi + Usaidizi wa ukurasa (limit, offset) + Chaguo za kupanga kwa sehemu ambazo zinaweza kupangwa + +3. **Sehemu za Uhusiano**: + Tambua uhusiano wa ufunguo wa kigeni kutoka kwa schema + Unda suluhu za sehemu kwa vitu vinavyohusiana + Usaidizi wa uhusiano wa kitu kimoja na orodha + +### Mtiririko wa Utendaji wa Uchunguzi + +1. **Mapokezi ya Ombi**: + Pokea `ObjectsQueryRequest` kutoka Pulsar. + Toa mfuatano wa GraphQL na vigezo. + Tambua muktadha wa mtumiaji na mkusanyiko. + +2. **Uthibitisho wa Ombi**: + Changanua mfuatano wa GraphQL kwa kutumia Strawberry. + Thibitisha dhidi ya mpango (schema) unaoendelea. + Angalia uteuzi wa sehemu na aina za hoja (argument). + +3. **Uundaji wa Ombi la CQL**: + Jadili uteuzi wa GraphQL. + Unda ombi la CQL na vipengele sahihi vya `WHERE`. + Jumuisha mkusanyiko katika ufunguo wa sehemu (partition key). + Tumia vichujio kulingana na hoja za GraphQL. + +4. **Utendaji wa Ombi**: + Tekeleza ombi la CQL dhidi ya Cassandra. + Linganisha matokeo na muundo wa jibu la GraphQL. + Tatua sehemu zozote za uhusiano. + Tengeneza jibu kulingana na vipimo vya GraphQL. + +5. **Utoaji wa Jibu**: + Unda `ObjectsQueryResponse` na matokeo. + Jumuisha makosa yoyote ya utekelezaji. + Tuma jibu kupitia Pulsar na kitambulisho cha uhusiano (correlation ID). + +### Mifano ya Data + +> **Kumbuka**: Mpango (schema) uliopo wa `StructuredQueryRequest/Response` unafanya kazi katika `trustgraph-base/trustgraph/schema/services/structured_query.py`. Hata hivyo, hauna vipengele muhimu (mtumiaji, mkusanyiko) na hutumia aina ambazo sio bora. Mifano iliyo hapa chini inaonyesha maendeleo yanayopendekezwa, ambayo inaweza kuchukua nafasi ya mifano iliyopo au kuundwa kama aina mpya za `ObjectsQueryRequest/Response`. + +#### Mpango wa Ombi (ObjectsQueryRequest) + +```python +from pulsar.schema import Record, String, Map, Array + +class ObjectsQueryRequest(Record): + user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest) + collection = String() # Data collection identifier (required for partition key) + query = String() # GraphQL query string + variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types) + operation_name = String() # Operation to execute for multi-operation documents +``` + +**Mazingatio ya mabadiliko kutoka kwa Ombi la Ulinganisho Lililopo:** +Imeongezwa sehemu `user` na `collection` ili kuendana na mtindo wa huduma zingine za utafutaji. +Sehemu hizi ni muhimu kwa kutambua eneo la kuhifadhi data (keyspace) na mkusanyiko (collection) katika Cassandra. +Vigezo vinaendelea kuwa Map(String()) kwa sasa, lakini inapaswa kusaidia aina zote za JSON. + +#### Muundo wa Majibu (ObjectsQueryResponse) + +```python +from pulsar.schema import Record, String, Array +from ..core.primitives import Error + +class GraphQLError(Record): + message = String() + path = Array(String()) # Path to the field that caused the error + extensions = Map(String()) # Additional error metadata + +class ObjectsQueryResponse(Record): + error = Error() # System-level error (connection, timeout, etc.) + data = String() # JSON-encoded GraphQL response data + errors = Array(GraphQLError) # GraphQL field-level errors + extensions = Map(String()) # Query metadata (execution time, etc.) +``` + +**Mazingatio ya mabadiliko kutoka kwa Jibu la Uliopo la StructuredQueryResponse:** +Hutofautisha kati ya makosa ya mfumo (`error`) na makosa ya GraphQL (`errors`) +Hutumia vitu vilivyopangwa vya GraphQLError badala ya safu ya maandishi +Huongeza sehemu `extensions` ili kufuata vipimo vya GraphQL +Huhifadhi data kama mnyororo wa JSON ili kuendana, ingawa aina asilia zingekuwa bora + +### Uboreshaji wa Umasilisho wa Cassandra + +Huduma itaboresha masilisho ya Cassandra kwa: + +1. **Kufuata Vipengele vya Partition:** + Daima jumuisha mkusanyiko katika masilisho + Tumia funguo kuu zilizotolewa na mpango kwa ufanisi + Epuka uchanganuzi kamili wa jedwali + +2. **Kutumia Faharasa:** + Tumia faharasa za sekondari kwa kuchujwa + Unganisha vichujio vingi wakati inafaa + Toa onyo wakati masilisho yanaweza kuwa yasiyo na ufanisi + +3. **Upakiaji wa Kundi:** + Kusanya masilisho ya uhusiano + Tekeleza kwa makundi ili kupunguza safari za kurudi na kuja + Hifadhi matokeo ndani ya muktadha wa ombi + +4. **Usimamizi wa Muunganisho:** + Dumishe vipindi vya Cassandra vinavyoendelea + Tumia mabwalo ya muunganisho + Shughulikia muunganisho upya katika hali ya kushindwa + +### Mifano ya Masilisho ya GraphQL + +#### Masilisho ya Mkusaniko Rahisi +```graphql +{ + customers(status: "active") { + customer_id + name + email + registration_date + } +} +``` + +#### Swali na Mahusiano +```graphql +{ + orders(order_date_gt: "2024-01-01") { + order_id + total_amount + customer { + name + email + } + items { + product_name + quantity + price + } + } +} +``` + +#### Swali lililogawanywa katika kurasa. +```graphql +{ + products(limit: 20, offset: 40) { + product_id + name + price + category + } +} +``` + +### Utendaji (Implementation) + +**Strawberry GraphQL**: Kwa uainishaji wa schema ya GraphQL na utekelezaji wa swali. +**Cassandra Driver**: Kwa muunganisho wa hifadhidata (tayari inatumika katika moduli ya uhifadhi). +**TrustGraph Base**: Kwa FlowProcessor na uainishaji wa schema. +**Mfumo wa Usanidi**: Kwa ufuatiliaji na sasisho za schema. + +### Kiolesura cha Amri (Command-Line Interface) + +Huduma itatoa amri ya CLI: `kg-query-objects-graphql-cassandra` + +Majadilisho: +`--cassandra-host`: Alama ya kuwasiliana na kundi la Cassandra. +`--cassandra-username`: Jina la mtumiaji la uthibitishaji. +`--cassandra-password`: Nenosiri la uthibitishaji. +`--config-type`: Aina ya usanidi kwa schema (ya kawaida: "schema"). +Majadilisho ya kawaida ya FlowProcessor (usanidi wa Pulsar, n.k.). + +## Uunganisho wa API + +### Mada za Pulsar + +**Mada ya Ingizo**: `objects-graphql-query-request` +Schema: ObjectsQueryRequest +Inapokea maswali ya GraphQL kutoka kwa huduma za lango. + +**Mada ya Toa**: `objects-graphql-query-response` +Schema: ObjectsQueryResponse +Inarudisha matokeo ya swali na makosa. + +### Uunganisho wa Lango + +Lango na lango la kinyume (reverse-gateway) itahitaji sehemu za: +1. Kukubali maswali ya GraphQL kutoka kwa wateja. +2. Kusambaza kwa huduma ya swali kupitia Pulsar. +3. Kurudisha majibu kwa wateja. +4. Kusaidia maswali ya utafiti wa GraphQL. + +### Uunganisho wa Zana ya Wakala + +Darasa mpya la zana ya wakala itaruhusu: +Uundaji wa swali la GraphQL kutoka kwa lugha ya asili. +Utendaji wa moja kwa moja wa swali la GraphQL. +Tafsiri na umbizo wa matokeo. +Uunganisho na mtiririko wa maamuzi wa wakala. + +## Masuala ya Usalama + +**Kipengele cha Kuzuia Kina cha Swali**: Kuzuia maswali yenye kina kikubwa ambacho kinaweza kusababisha matatizo ya utendaji. +**Uchambuzi wa Ufumbuzi wa Swali**: Kupunguza ufumbuzi wa swali ili kuzuia matumizi yasiyofaa ya rasilimali. +**Ruhusa za Kawaida**: Usaidizi wa baadaye kwa udhibiti wa ufikiaji wa kawaida kulingana na majukumu ya mtumiaji. +**Usanifu wa Ingizo**: Kuhakikisha na kusafisha pembejeo zote za swali ili kuzuia mashambulizi ya kuingiza. +**Kipengele cha Kupunguza Kasi**: Kuweka kikomo cha kasi ya swali kwa kila mtumiaji/mkusanyiko. + +## Masuala ya Utendaji + +**Upangaji wa Swali**: Kuchambua maswali kabla ya utekelezaji ili kuongeza ufanisi wa uundaji wa CQL. +**Kuhifadhi Matokeo**: Kuzingatia kuhifadhi data inayopatikana mara kwa mara katika kiwango cha kielekezi cha matokeo. +**Usimamizi wa Muunganisho**: Kudumisha mizingi bora ya muunganisho kwa Cassandra. +**Operesheni za Kikundi**: Kuchanganya maswali mengi wakati inafaa ili kupunguza latensi. +**Ufuatiliaji**: Kufuatilia vipimo vya utendaji wa swali kwa ajili ya uboreshaji. + +## Mkakati wa Majaribio + +### Majaribio ya Vitengo +Uzalishaji wa schema kutoka kwenye maelezo ya RowSchema +Uchunguzi na uthibitisho wa swali la GraphQL +Mantiki ya uzalishaji wa swali la CQL +Utendaji wa suluhu za sehemu + +### Majaribio ya Mkataba +Uzingatiaji wa mkataba wa ujumbe wa Pulsar +Uthibitisho wa uhalali wa schema ya GraphQL +Uthibitisho wa muundo wa jibu +Uthibitisho wa muundo wa hitilafu + +### Majaribio ya Uunganishaji +Utendaji wa swali kamili dhidi ya mfano wa Cassandra wa majaribio +Usimamizi wa sasisho za schema +Suluhisho la uhusiano +Urekebishaji na utafutaji +Hali za hitilafu + +### Majaribio ya Utendaji +Ufanisi wa swali chini ya mzigo +Muda wa jibu kwa utata wa swali mbalimbali +Matumizi ya kumbukumbu na matokeo makubwa +Ufanisi wa kikundi cha muunganisho + +## Mpango wa Uhamishaji + +Uhamishaji hauhitajiki kwani hii ni uwezo mpya. Huduma itafanya: +1. Kusoma schema zilizopo kutoka kwenye usanidi +2. Kuunganisha na meza zilizopo za Cassandra zilizoundwa na moduli ya uhifadhi +3. Kuanza kukubali maswali mara tu inaposanikishwa + +## Muda + +Wiki 1-2: Utendaji wa msingi wa huduma na uzalishaji wa schema +Wiki 3: Utendaji wa swali na tafsiri ya CQL +Wiki 4: Suluhisho la uhusiano na uboreshaji +Wiki 5: Majaribio na uboreshaji wa utendaji +Wiki 6: Uunganisho wa lango na maandishi + +## Maswali ya Wazi + +1. **Maendeleo ya Schema**: Huduma inapaswa kushughulikia maswali vipi wakati wa mabadiliko ya schema? + Chaguo: Kuweka maswali kwenye folyo wakati wa sasisho za schema + Chaguo: Kusaidia matoleo mengi ya schema kwa wakati mmoja + +2. **Mkakati wa Uhifadhi**: Je, matokeo ya swali yanapaswa kuhifadhiwa? + Zingatia: Muda wa kumalizika + Zingatia: Ubatilishaji kulingana na tukio + +3. **Usaidizi wa Shirikisho**: Je, huduma inapaswa kusaidia shirikisho la GraphQL ili kuunganisha na vyanzo vingine vya data? + Itaruhusu maswali ya umoja katika data iliyopangwa na ya grafu + +4. **Usaidizi wa Ujiandikishaji**: Je, huduma inapaswa kusaidia uandikishaji wa GraphQL kwa sasisho za wakati halisi? + Itahitaji usaidizi wa WebSocket katika lango + +5. **Scalar Maalum**: Je, aina za scalar maalum zinapaswa kuungwa mkono kwa aina za data maalum za kikoa? + Mifano: DateTime, UUID, nafasi za JSON + +## Marejeleo + +Maelezo ya Kimataifa ya Data Iliyopangwa: `docs/tech-specs/structured-data.md` +Nyaraka za Strawberry GraphQL: https://strawberry.rocks/ +Maelezo ya GraphQL: https://spec.graphql.org/ +Marejeleo ya Apache Cassandra CQL: https://cassandra.apache.org/doc/stable/cassandra/cql/ +Nyaraka za Msimamizi wa Mtiririko wa TrustGraph: Nyaraka za ndani \ No newline at end of file diff --git a/docs/tech-specs/graphql-query.tr.md b/docs/tech-specs/graphql-query.tr.md new file mode 100644 index 00000000..393c184f --- /dev/null +++ b/docs/tech-specs/graphql-query.tr.md @@ -0,0 +1,383 @@ +# GraphQL Sorgu Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph'ın Apache Cassandra'daki yapılandırılmış veri depolaması için bir GraphQL sorgu arayüzünün uygulanmasını tanımlar. Yapılandırılmış-veri.md spesifikasyonunda belirtilen yapılandırılmış veri yeteneklerine dayanarak, bu belge, çıkarılan ve işlenen yapılandırılmış nesneleri içeren Cassandra tablolarına karşı GraphQL sorgularının nasıl yürütüleceğini ayrıntılı olarak açıklar. + +GraphQL sorgu hizmeti, Cassandra'da depolanan yapılandırılmış verileri sorgulamak için esnek, tür güvenli bir arayüz sağlayacaktır. Şema değişikliklerine dinamik olarak uyum sağlayacak, nesneler arasındaki ilişkiler de dahil olmak üzere karmaşık sorguları destekleyecek ve TrustGraph'ın mevcut mesaj tabanlı mimarisiyle sorunsuz bir şekilde entegre olacaktır. + +## Hedefler + +**Dinamik Şema Desteği**: Hizmeti yeniden başlatmaya gerek kalmadan yapılandırmadaki şema değişikliklerine otomatik olarak uyum sağlayın. +**GraphQL Standartlarına Uygunluk**: Mevcut GraphQL araçları ve istemcileriyle uyumlu, standart bir GraphQL arayüzü sağlayın. +**Verimli Cassandra Sorguları**: GraphQL sorgularını, bölüm anahtarlarını ve dizinleri dikkate alarak verimli Cassandra CQL sorgularına dönüştürün. +**İlişki Çözümlemesi**: Farklı nesne türleri arasındaki ilişkiler için GraphQL alan çözümleyicilerini destekleyin. +**Tür Güvenliği**: Şema tanımlarına göre tür güvenli sorgu yürütme ve yanıt oluşturma sağlayın. +**Ölçeklenebilir Performans**: Uygun bağlantı havuzu ve sorgu optimizasyonu ile eşzamanlı sorguları verimli bir şekilde işleyin. +**İstek/Yanıt Entegrasyonu**: TrustGraph'ın Pulsar tabanlı istek/yanıt kalıbıyla uyumluluğu koruyun. +**Hata İşleme**: Şema uyumsuzlukları, sorgu hataları ve veri doğrulama sorunları için kapsamlı hata raporlama sağlayın. + +## Arka Plan + +Yapılandırılmış veri depolama uygulaması (trustgraph-flow/trustgraph/storage/objects/cassandra/), nesneleri TrustGraph'ın yapılandırma sisteminde depolanan şema tanımlarına göre Cassandra tablolarına yazar. Bu tablolar, koleksiyonlar içindeki verimli sorguları etkinleştiren bileşik bölüm anahtarı yapısı ve şema tanımlı birincil anahtarlar kullanır. + +Bu özellik tarafından ele alınan mevcut sınırlamalar: +Cassandra'da depolanan yapılandırılmış veri için bir sorgu arayüzü yok. +Yapılandırılmış veri için GraphQL'in güçlü sorgu yeteneklerinden yararlanamama. +İlişkili nesneler arasındaki ilişki geçişi için destek eksikliği. +Yapılandırılmış veri erişimi için standart bir sorgu dili eksikliği. + +GraphQL sorgu hizmeti, bunları sağlayarak bu boşlukları dolduracaktır: +Cassandra tablolarını sorgulamak için standart bir GraphQL arayüzü. +TrustGraph yapılandırmasından dinamik olarak GraphQL şemaları oluşturma. +GraphQL sorgularını Cassandra CQL'ye verimli bir şekilde dönüştürme. +Alan çözümleyicileri aracılığıyla ilişki çözümlemesini destekleme. + +## Teknik Tasarım + +### Mimari + +GraphQL sorgu hizmeti, yerleşik kalıpları izleyen yeni bir TrustGraph akışı işlemci olarak uygulanacaktır: + +**Modül Konumu**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**Ana Bileşenler**: + +1. **GraphQL Sorgu Hizmeti İşlemcisi** + Temel FlowProcessor sınıfını genişletir. + Mevcut sorgu hizmetlerine benzer bir istek/yanıt kalıbını uygular. + Şema güncellemeleri için yapılandırmayı izler. + GraphQL şemasını yapılandırmayla senkronize tutar. + +2. **Dinamik Şema Oluşturucu** + TrustGraph RowSchema tanımlarını GraphQL türlerine dönüştürür. + Uygun alan tanımlarıyla GraphQL nesne türleri oluşturur. + Koleksiyon tabanlı çözümleyicilerle kök Sorgu türünü oluşturur. + Yapılandırma değiştiğinde GraphQL şemasını günceller. + +3. **Sorgu Yürütücüsü** + Gelen GraphQL sorgularını Strawberry kütüphanesi kullanarak ayrıştırır. + Sorguları mevcut şemaya göre doğrular. + Sorguları yürütür ve yapılandırılmış yanıtlar döndürür. + Ayrıntılı hata mesajlarıyla hataları zarif bir şekilde işler. + +4. **Cassandra Sorgu Çevirmeni** + GraphQL seçimlerini CQL sorgularına dönüştürür. + Mevcut dizinlere ve bölüm anahtarlarına göre sorguları optimize eder. + Filtrelemeyi, sayfalama ve sıralamayı işler. + Bağlantı havuzunu ve oturum yaşam döngüsünü yönetir. + +5. **İlişki Çözümleyici** + Nesne ilişkileri için alan çözümleyicilerini uygular. + N+1 sorgularından kaçınmak için verimli toplu yükleme gerçekleştirir. + Çözümlenen ilişkileri istek bağlamı içinde önbelleğe alır. + Hem ileri hem de geri ilişki geçişini destekler. + +### Yapılandırma Şeması İzleme + +Hizmet, şema güncellemelerini almak için bir yapılandırma işleyicisi kaydeder: + +```python +self.register_config_handler(self.on_schema_config) +``` + +Şemalar değiştiğinde: +1. Yapılandırmadan yeni şema tanımlarını ayrıştırın. +2. GraphQL türlerini ve çözümleyicileri yeniden oluşturun. +3. Çalıştırılabilir şemayı güncelleyin. +4. Şemaya bağlı tüm önbellekleri temizleyin. + +### GraphQL Şema Oluşturma + +Yapılandırmadaki her RowSchema için aşağıdaki öğeleri oluşturun: + +1. **GraphQL Nesne Türü**: + Alan türlerini eşleyin (string → String, integer → Int, float → Float, boolean → Boolean). + Gerekli alanları GraphQL'de nullable olmayan olarak işaretleyin. + Şemadan alan açıklamalarını ekleyin. + +2. **Kök Sorgu Alanları**: + Koleksiyon sorgusu (örneğin, `customers`, `transactions`). + İndekslenmiş alanlara göre filtreleme argümanları. + Sayfalama desteği (limit, offset). + Sıralanabilir alanlar için sıralama seçenekleri. + +3. **İlişki Alanları**: + Şemadan yabancı anahtar ilişkilerini belirleyin. + İlgili nesneler için alan çözümleyicileri oluşturun. + Hem tek nesne hem de liste ilişkilerini destekleyin. + +### Sorgu Yürütme Akışı + +1. **İstek Alma**: + Pulsar'dan ObjectsQueryRequest'i alın. + GraphQL sorgu dizesini ve değişkenlerini çıkarın. + Kullanıcıyı ve koleksiyon bağlamını belirleyin. + +2. **Sorgu Doğrulama**: + Strawberry kullanarak GraphQL sorgusunu ayrıştırın. + Mevcut şemaya göre doğrulayın. + Alan seçimlerini ve argüman türlerini kontrol edin. + +3. **CQL Oluşturma**: + GraphQL seçimlerini analiz edin. + Uygun WHERE koşullarına sahip CQL sorgusu oluşturun. + Koleksiyonu bölüm anahtarına dahil edin. + GraphQL argümanlarına göre filtreleri uygulayın. + +4. **Sorgu Yürütme**: + CQL sorgusunu Cassandra'ya karşı yürütün. + Sonuçları GraphQL yanıt yapısına eşleyin. + Herhangi bir ilişki alanını çözün. + Yanıtı GraphQL spesifikasyonuna göre biçimlendirin. + +5. **Yanıt Teslimi**: + Sonuçlarla ObjectsQueryResponse oluşturun. + Herhangi bir yürütme hatasını dahil edin. + Yanıtı korelasyon kimliğiyle Pulsar üzerinden gönderin. + +### Veri Modelleri + +> **Not**: `trustgraph-base/trustgraph/schema/services/structured_query.py`'da mevcut bir StructuredQueryRequest/Response şeması bulunmaktadır. Ancak, bu şemada kritik alanlar (kullanıcı, koleksiyon) eksiktir ve alt optimal türler kullanılmaktadır. Aşağıdaki şemalar, önerilen gelişmeyi temsil etmektedir; bu şemalar ya mevcut şemaları değiştirmeli ya da yeni ObjectsQueryRequest/Response türleri olarak oluşturulmalıdır. + +#### İstek Şeması (ObjectsQueryRequest) + +```python +from pulsar.schema import Record, String, Map, Array + +class ObjectsQueryRequest(Record): + user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest) + collection = String() # Data collection identifier (required for partition key) + query = String() # GraphQL query string + variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types) + operation_name = String() # Operation to execute for multi-operation documents +``` + +**Mevcut StructuredQueryRequest'ten yapılan değişikliklerin gerekçesi:** +Diğer sorgu hizmetlerinin kalıbına uygun olarak `user` ve `collection` alanları eklendi. +Bu alanlar, Cassandra anahtar alanını ve koleksiyonu tanımlamak için gereklidir. +Değişkenler şu anda Map(String()) olarak kalmaktadır, ancak ideal olarak tüm JSON türlerini desteklemelidir. + +#### Yanıt Şeması (ObjectsQueryResponse) + +```python +from pulsar.schema import Record, String, Array +from ..core.primitives import Error + +class GraphQLError(Record): + message = String() + path = Array(String()) # Path to the field that caused the error + extensions = Map(String()) # Additional error metadata + +class ObjectsQueryResponse(Record): + error = Error() # System-level error (connection, timeout, etc.) + data = String() # JSON-encoded GraphQL response data + errors = Array(GraphQLError) # GraphQL field-level errors + extensions = Map(String()) # Query metadata (execution time, etc.) +``` + +**Mevcut StructuredQueryResponse'tan yapılan değişikliklerin gerekçesi:** +Sistem hatalarını (`error`) ve GraphQL hatalarını (`errors`) ayırır. +Dizi yerine yapılandırılmış GraphQLError nesneleri kullanır. +GraphQL spesifikasyonuna uygunluk için `extensions` alanı eklenmiştir. +Uyumluluk için verileri JSON dizesi olarak tutar, ancak yerel türler tercih edilir. + +### Cassandra Sorgu Optimizasyonu + +Hizmet, Cassandra sorgularını aşağıdaki şekilde optimize edecektir: + +1. **Bölüm Anahtarlarına Saygı Gösterme:** + Her zaman sorgularda koleksiyonu dahil edin. + Şema tanımlı birincil anahtarları verimli bir şekilde kullanın. + Tam tablo taramalarından kaçının. + +2. **Dizinleri Kullanma:** + Filtreleme için ikincil dizinleri kullanın. + Mümkün olduğunda birden fazla filtreyi birleştirin. + Sorguların verimsiz olabileceği durumlarda uyarı verin. + +3. **Toplu Yükleme:** + İlişki sorgularını toplayın. + Gidiş-dönüş sayısını azaltmak için toplu olarak çalıştırın. + Sonuçları istek bağlamı içinde önbelleğe alın. + +4. **Bağlantı Yönetimi:** + Kalıcı Cassandra oturumlarını koruyun. + Bağlantı havuzunu kullanın. + Hatalarda yeniden bağlanmayı yönetin. + +### Örnek GraphQL Sorguları + +#### Basit Koleksiyon Sorgusu +```graphql +{ + customers(status: "active") { + customer_id + name + email + registration_date + } +} +``` + +#### İlişkilere Sahip Sorgular +```graphql +{ + orders(order_date_gt: "2024-01-01") { + order_id + total_amount + customer { + name + email + } + items { + product_name + quantity + price + } + } +} +``` + +#### Sayfalı Sorgu +```graphql +{ + products(limit: 20, offset: 40) { + product_id + name + price + category + } +} +``` + +### Uygulama Bağımlılıkları + +**Strawberry GraphQL**: GraphQL şema tanımı ve sorgu yürütme için +**Cassandra Driver**: Veritabanı bağlantısı için (depolama modülünde zaten kullanılıyor) +**TrustGraph Base**: FlowProcessor ve şema tanımları için +**Configuration System**: Şema takibi ve güncellemeleri için + +### Komut Satırı Arayüzü + +Hizmet, aşağıdaki CLI komutunu sağlayacaktır: `kg-query-objects-graphql-cassandra` + +Argümanlar: +`--cassandra-host`: Cassandra kümesi iletişim noktası +`--cassandra-username`: Kimlik doğrulama kullanıcı adı +`--cassandra-password`: Kimlik doğrulama parolası +`--config-type`: Şemalar için yapılandırma türü (varsayılan: "schema") +Standart FlowProcessor argümanları (Pulsar yapılandırması, vb.) + +## API Entegrasyonu + +### Pulsar Konuları + +**Giriş Konusu**: `objects-graphql-query-request` +Şema: ObjectsQueryRequest +Ağ geçidi hizmetlerinden GraphQL sorguları alır + +**Çıkış Konusu**: `objects-graphql-query-response` +Şema: ObjectsQueryResponse +Sorgu sonuçlarını ve hataları döndürür + +### Ağ Geçidi Entegrasyonu + +Ağ geçidi ve ters ağ geçidi, aşağıdaki işlemleri gerçekleştirmek için uç noktalarına ihtiyaç duyacaktır: +1. İstemcilerden GraphQL sorgularını kabul etme +2. Sorguları Pulsar üzerinden sorgu hizmetine yöneltme +3. Yanıtları istemcilere döndürme +4. GraphQL introspeksiyon sorgularını destekleme + +### Aracılık Aracı Entegrasyonu + +Yeni bir aracılık aracı sınıfı, aşağıdaki özellikleri sağlayacaktır: +Doğal dili GraphQL sorgusuna dönüştürme +Doğrudan GraphQL sorgusu yürütme +Sonuçların yorumlanması ve biçimlendirilmesi +Aracılık karar akışlarıyla entegrasyon + +## Güvenlik Hususları + +**Sorgu Derinliği Sınırlaması**: Performans sorunlarına neden olabilecek derinlemesine iç içe sorguları önleme +**Sorgu Karmaşıklığı Analizi**: Kaynak tükenmesini önlemek için sorgu karmaşıklığını sınırlama +**Alan Düzeyi İzinleri**: Kullanıcı rollerine göre alan düzeyinde erişim kontrolü için gelecekteki destek +**Giriş Temizleme**: Enjeksiyon saldırılarını önlemek için tüm sorgu girişlerini doğrulama ve temizleme +**Hız Sınırlaması**: Kullanıcı/koleksiyon başına sorgu hız sınırlaması uygulama + +## Performans Hususları + +**Sorgu Planlama**: CQL oluşturmayı optimize etmek için sorguları yürütmeden önce analiz etme +**Sonuç Önbelleği**: Sık erişilen verileri alan çözümleyici düzeyinde önbelleğe alma +**Bağlantı Havuzu**: Cassandra'ya verimli bağlantı havuzları sağlama +**Toplu İşlemler**: Mümkün olduğunda birden fazla sorguyu birleştirme, gecikmeyi azaltma +**İzleme**: Optimizasyon için sorgu performans metriklerini izleme + +## Test Stratejisi + +### Birim Testleri +RowSchema tanımlarından şema oluşturma +GraphQL sorgusu ayrıştırma ve doğrulama +CQL sorgusu oluşturma mantığı +Alan çözümleyici uygulamaları + +### Sözleşme Testleri +Pulsar mesaj sözleşmesi uyumluluğu +GraphQL şema geçerliliği +Yanıt formatı doğrulaması +Hata yapısı doğrulaması + +### Entegrasyon Testleri +Test Cassandra örneğine karşı uçtan uca sorgu yürütme +Şema güncelleme işleme +İlişki çözümü +Sayfalama ve filtreleme +Hata senaryoları + +### Performans Testleri +Yük altında sorgu verimliliği +Çeşitli sorgu karmaşıklıkları için yanıt süresi +Büyük sonuç kümeleriyle bellek kullanımı +Bağlantı havuzu verimliliği + +## Geçiş Planı + +Bu yeni bir özellik olduğu için herhangi bir geçiş gerekli değildir. Hizmet şunları yapacaktır: +1. Mevcut şemaları yapılandırmadan okuyacaktır +2. Depolama modülü tarafından oluşturulan mevcut Cassandra tablolarına bağlanacaktır +3. Dağıtım üzerine hemen sorguları kabul etmeye başlayacaktır + +## Zaman Çizelgesi + +1-2. Hafta: Temel hizmet uygulaması ve şema oluşturma +3. Hafta: Sorgu yürütme ve CQL çevirisi +4. Hafta: İlişki çözümü ve optimizasyon +5. Hafta: Test etme ve performans ayarlaması +6. Hafta: Ağ geçidi entegrasyonu ve dokümantasyon + +## Açık Sorular + +1. **Şema Evrimi**: Hizmet, şema geçişleri sırasında sorguları nasıl işlemelidir? + Seçenek: Şema güncellemeleri sırasında sorguları kuyruğa alın + Seçenek: Aynı anda birden fazla şema sürümünü destekleyin + +2. **Önbellekleme Stratejisi**: Sorgu sonuçları önbelleğe alınmalı mı? + Dikkat edilmesi gerekenler: Zaman tabanlı son kullanma tarihi + Dikkat edilmesi gerekenler: Olay tabanlı geçersiz kılma + +3. **Federasyon Desteği**: Hizmet, diğer veri kaynaklarıyla birleştirme için GraphQL federasyonunu desteklemeli mi? + Yapılandırılmış ve grafik veriler arasında birleşik sorguları etkinleştirir + +4. **Abonelik Desteği**: Hizmet, gerçek zamanlı güncellemeler için GraphQL aboneliklerini desteklemeli mi? + Ağ geçidinde WebSocket desteği gerektirir + +5. **Özel Ölçekler**: Hizmet, alan adlarına özgü veri türleri için özel ölçek türlerini desteklemeli mi? + Örnekler: DateTime, UUID, JSON alanları + +## Referanslar + +Yapılandırılmış Veri Teknik Özelliği: `docs/tech-specs/structured-data.md` +Strawberry GraphQL Dokümantasyonu: https://strawberry.rocks/ +GraphQL Özelliği: https://spec.graphql.org/ +Apache Cassandra CQL Referansı: https://cassandra.apache.org/doc/stable/cassandra/cql/ +TrustGraph Akış İşlemci Dokümantasyonu: İç dokümantasyon \ No newline at end of file diff --git a/docs/tech-specs/graphql-query.zh-cn.md b/docs/tech-specs/graphql-query.zh-cn.md new file mode 100644 index 00000000..8e0d8be7 --- /dev/null +++ b/docs/tech-specs/graphql-query.zh-cn.md @@ -0,0 +1,383 @@ +# GraphQL 查询技术规范 + +## 概述 + +本规范描述了用于 TrustGraph 结构化数据存储在 Apache Cassandra 中的 GraphQL 查询接口的实现。 在结构化数据功能方面,本规范基于结构化数据规范 (structured-data.md),详细说明了如何对包含提取和摄取的结构化对象的 Cassandra 表执行 GraphQL 查询。 + +GraphQL 查询服务将提供一个灵活、类型安全的接口,用于查询存储在 Cassandra 中的结构化数据。 它将动态适应模式更改,支持包括对象之间的关系在内的复杂查询,并与 TrustGraph 现有的基于消息的架构无缝集成。 + +## 目标 + +**动态模式支持**: 在不重新启动服务的情况下,自动适应配置中的模式更改 +**GraphQL 标准兼容性**: 提供与现有 GraphQL 工具和客户端兼容的标准 GraphQL 接口 +**高效的 Cassandra 查询**: 将 GraphQL 查询转换为高效的 Cassandra CQL 查询,同时尊重分区键和索引 +**关系解析**: 支持用于不同对象类型之间关系的 GraphQL 字段解析器 +**类型安全**: 基于模式定义,确保类型安全地执行查询并生成响应 +**可扩展的性能**: 通过适当的连接池和查询优化,高效地处理并发查询 +**请求/响应集成**: 保持与 TrustGraph 基于 Pulsar 的请求/响应模式的兼容性 +**错误处理**: 提供全面的错误报告,用于模式不匹配、查询错误和数据验证问题 + +## 背景 + +结构化数据存储实现 (trustgraph-flow/trustgraph/storage/objects/cassandra/) 根据存储在 TrustGraph 配置系统中的模式定义,将对象写入 Cassandra 表。 这些表使用复合分区键结构,具有集合和基于模式定义的键,从而可以在集合中实现高效的查询。 + +当前的局限性,本规范旨在解决: +缺少用于存储在 Cassandra 中的结构化数据的查询接口 +无法利用 GraphQL 的强大查询功能来处理结构化数据 +缺少对相关对象之间关系遍历的支持 +缺少用于结构化数据访问的标准化查询语言 + +GraphQL 查询服务将通过以下方式弥补这些差距: +提供用于查询 Cassandra 表的标准 GraphQL 接口 +从 TrustGraph 配置动态生成 GraphQL 模式 +高效地将 GraphQL 查询转换为 Cassandra CQL +通过字段解析器支持关系解析 + +## 技术设计 + +### 架构 + +GraphQL 查询服务将作为新的 TrustGraph 流处理器实现,遵循既定的模式: + +**模块位置**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**主要组件**: + +1. **GraphQL 查询服务处理器** + 扩展基础 FlowProcessor 类 + 实现类似于现有查询服务的请求/响应模式 + 监控配置以进行模式更新 + 保持与配置同步的 GraphQL 模式 + +2. **动态模式生成器** + 将 TrustGraph RowSchema 定义转换为 GraphQL 类型 + 创建具有适当字段定义的 GraphQL 对象类型 + 生成具有基于集合的解析器的根 Query 类型 + 在配置更改时更新 GraphQL 模式 + +3. **查询执行器** + 使用 Strawberry 库解析传入的 GraphQL 查询 + 根据当前模式验证查询 + 执行查询并返回结构化响应 + 通过详细的错误消息优雅地处理错误 + +4. **Cassandra 查询转换器** + 将 GraphQL 选择转换为 CQL 查询 + 根据可用的索引和分区键优化查询 + 处理过滤、分页和排序 + 管理连接池和会话生命周期 + +5. **关系解析器** + 实现用于对象之间关系的字段解析器 + 执行批量加载以避免 N+1 查询 + 在请求上下文中缓存解析的关系 + 支持正向和反向关系遍历 + +### 配置模式监控 + +该服务将注册一个配置处理程序以接收模式更新: + +```python +self.register_config_handler(self.on_schema_config) +``` + +当模式发生变化时: +1. 从配置中解析新的模式定义 +2. 重新生成 GraphQL 类型和解析器 +3. 更新可执行的模式 +4. 清除任何依赖于模式的缓存 + +### GraphQL 模式生成 + +对于配置中的每个 RowSchema,生成: + +1. **GraphQL 对象类型**: + 映射字段类型(string → String, integer → Int, float → Float, boolean → Boolean) + 将必需字段标记为 GraphQL 中的非空值 + 从模式中添加字段描述 + +2. **根查询字段**: + 集合查询(例如,`customers`,`transactions`) + 基于索引字段的过滤参数 + 分页支持(limit, offset) + 可排序字段的排序选项 + +3. **关系字段**: + 从模式中识别外键关系 + 为相关对象创建字段解析器 + 支持单对象和列表关系 + +### 查询执行流程 + +1. **请求接收**: + 从 Pulsar 接收 ObjectsQueryRequest + 提取 GraphQL 查询字符串和变量 + 识别用户和集合上下文 + +2. **查询验证**: + 使用 Strawberry 解析 GraphQL 查询 + 验证与当前模式 + 检查字段选择和参数类型 + +3. **CQL 生成**: + 分析 GraphQL 选择 + 构建带有适当 WHERE 子句的 CQL 查询 + 将集合包含在分区键中 + 根据 GraphQL 参数应用过滤器 + +4. **查询执行**: + 对 Cassandra 执行 CQL 查询 + 将结果映射到 GraphQL 响应结构 + 解析任何关系字段 + 格式化响应以符合 GraphQL 规范 + +5. **响应发送**: + 创建包含结果的 ObjectsQueryResponse + 包含任何执行错误 + 通过 Pulsar 发送带有相关 ID 的响应 + +### 数据模型 + +> **注意**: `trustgraph-base/trustgraph/schema/services/structured_query.py` 中存在现有的 StructuredQueryRequest/Response 模式。但是,它缺少关键字段(用户、集合),并且使用了次优类型。以下模式代表推荐的演进,应该替换现有的模式,或者创建新的 ObjectsQueryRequest/Response 类型。 + +#### 请求模式 (ObjectsQueryRequest) + +```python +from pulsar.schema import Record, String, Map, Array + +class ObjectsQueryRequest(Record): + user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest) + collection = String() # Data collection identifier (required for partition key) + query = String() # GraphQL query string + variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types) + operation_name = String() # Operation to execute for multi-operation documents +``` + +**对现有 StructuredQueryRequest 的更改原因:** +添加了 `user` 和 `collection` 字段,以匹配其他查询服务的模式。 +这些字段对于识别 Cassandra 键空间和集合至关重要。 +变量目前仍然是 Map(String()),但理想情况下应该支持所有 JSON 类型。 + +#### 响应模式 (ObjectsQueryResponse) + +```python +from pulsar.schema import Record, String, Array +from ..core.primitives import Error + +class GraphQLError(Record): + message = String() + path = Array(String()) # Path to the field that caused the error + extensions = Map(String()) # Additional error metadata + +class ObjectsQueryResponse(Record): + error = Error() # System-level error (connection, timeout, etc.) + data = String() # JSON-encoded GraphQL response data + errors = Array(GraphQLError) # GraphQL field-level errors + extensions = Map(String()) # Query metadata (execution time, etc.) +``` + +**对现有 StructuredQueryResponse 更改的理由:** +区分系统错误 (`error`) 和 GraphQL 错误 (`errors`) +使用结构化的 GraphQLError 对象,而不是字符串数组 +添加 `extensions` 字段,以符合 GraphQL 规范 +为了兼容性,将数据保留为 JSON 字符串,尽管使用原生类型会更好 + +### Cassandra 查询优化 + +该服务将通过以下方式优化 Cassandra 查询: + +1. **尊重分区键:** + 始终在查询中包含集合 + 高效使用 schema 定义的主键 + 避免全表扫描 + +2. **利用索引:** + 使用二级索引进行过滤 + 尽可能组合多个过滤器 + 当查询可能效率低下时,发出警告 + +3. **批量加载:** + 收集关系查询 + 批量执行以减少网络请求次数 + 在请求上下文中缓存结果 + +4. **连接管理:** + 维护持久的 Cassandra 会话 + 使用连接池 + 在发生故障时处理重连 + +### 示例 GraphQL 查询 + +#### 简单的集合查询 +```graphql +{ + customers(status: "active") { + customer_id + name + email + registration_date + } +} +``` + +#### 查询与关系 +```graphql +{ + orders(order_date_gt: "2024-01-01") { + order_id + total_amount + customer { + name + email + } + items { + product_name + quantity + price + } + } +} +``` + +#### 分页查询 +```graphql +{ + products(limit: 20, offset: 40) { + product_id + name + price + category + } +} +``` + +### 实现依赖 + +**Strawberry GraphQL**: 用于 GraphQL 模式定义和查询执行 +**Cassandra Driver**: 用于数据库连接(已在存储模块中使用) +**TrustGraph Base**: 用于 FlowProcessor 和模式定义 +**Configuration System**: 用于模式监控和更新 + +### 命令行界面 + +该服务将提供一个 CLI 命令:`kg-query-objects-graphql-cassandra` + +参数: +`--cassandra-host`: Cassandra 集群联系点 +`--cassandra-username`: 身份验证用户名 +`--cassandra-password`: 身份验证密码 +`--config-type`: 用于模式的配置类型(默认:"schema") +标准 FlowProcessor 参数(Pulsar 配置等) + +## API 集成 + +### Pulsar 主题 + +**输入主题**: `objects-graphql-query-request` +Schema: ObjectsQueryRequest +接收来自网关服务的 GraphQL 查询 + +**输出主题**: `objects-graphql-query-response` +Schema: ObjectsQueryResponse +返回查询结果和错误 + +### 网关集成 + +网关和反向网关需要端点来: +1. 接受来自客户端的 GraphQL 查询 +2. 通过 Pulsar 将其转发到查询服务 +3. 将响应返回给客户端 +4. 支持 GraphQL 内省查询 + +### 代理工具集成 + +一个新的代理工具类将启用: +自然语言到 GraphQL 查询的生成 +直接 GraphQL 查询执行 +结果解释和格式化 +与代理决策流程的集成 + +## 安全注意事项 + +**查询深度限制**: 阻止深度嵌套的查询,以防止性能问题 +**查询复杂度分析**: 限制查询复杂度以防止资源耗尽 +**字段级权限**: 未来支持基于用户角色的字段级访问控制 +**输入验证**: 验证和清理所有查询输入以防止注入攻击 +**速率限制**: 为每个用户/集合实施查询速率限制 + +## 性能注意事项 + +**查询规划**: 在执行之前分析查询以优化 CQL 生成 +**结果缓存**: 考虑缓存频繁访问的数据,位于字段解析器级别 +**连接池**: 维护与 Cassandra 的高效连接池 +**批量操作**: 尽可能组合多个查询以减少延迟 +**监控**: 跟踪查询性能指标以进行优化 + +## 测试策略 + +### 单元测试 +从 RowSchema 定义生成模式 +GraphQL 查询解析和验证 +CQL 查询生成逻辑 +字段解析器实现 + +### 契约测试 +Pulsar 消息契约合规性 +GraphQL 模式有效性 +响应格式验证 +错误结构验证 + +### 集成测试 +对测试 Cassandra 实例执行端到端查询 +模式更新处理 +关系解析 +分页和过滤 +错误场景 + +### 性能测试 +负载下的查询吞吐量 +各种查询复杂度的响应时间 +大结果集下的内存使用情况 +连接池效率 + +## 迁移计划 + +由于这是一个新功能,因此不需要迁移。该服务将: +1. 从配置中读取现有模式 +2. 连接到存储模块创建的现有 Cassandra 表 +3. 立即在部署后开始接受查询 + +## 时间表 + +第 1-2 周:核心服务实现和模式生成 +第 3 周:查询执行和 CQL 转换 +第 4 周:关系解析和优化 +第 5 周:测试和性能调整 +第 6 周:网关集成和文档 + +## 开放问题 + +1. **模式演进**: 服务应该如何处理查询期间的模式转换? + 选项:在模式更新期间排队查询 + 选项:同时支持多个模式版本 + +2. **缓存策略**: 是否应该缓存查询结果? + 考虑:基于时间的过期 + 考虑:基于事件的失效 + +3. **联邦支持**: 该服务是否应该支持 GraphQL 联邦,以与其他数据源组合? + 将启用跨结构化和图形数据的统一查询 + +4. **订阅支持**: 该服务是否应该支持 GraphQL 订阅以进行实时更新? + 需要网关中的 WebSocket 支持 + +5. **自定义标量**: 是否应该支持自定义标量类型,用于特定领域的的数据类型? + 示例:DateTime、UUID、JSON 字段 + +## 参考文献 + +结构化数据技术规范:`docs/tech-specs/structured-data.md` +Strawberry GraphQL 文档:https://strawberry.rocks/ +GraphQL 规范:https://spec.graphql.org/ +Apache Cassandra CQL 参考:https://cassandra.apache.org/doc/stable/cassandra/cql/ +TrustGraph Flow Processor 文档:内部文档 \ No newline at end of file diff --git a/docs/tech-specs/graphrag-performance-optimization.ar.md b/docs/tech-specs/graphrag-performance-optimization.ar.md index 1857b843..49abf016 100644 --- a/docs/tech-specs/graphrag-performance-optimization.ar.md +++ b/docs/tech-specs/graphrag-performance-optimization.ar.md @@ -1,270 +1,629 @@ -# مواصفات فنية لتحسين أداء GraphRAG +# GraphRAG Performance Optimisation Technical Specification -## نظرة عامة +## Overview -تصف هذه المواصفات تحسينات شاملة للأداء لخوارزمية GraphRAG (Graph Retrieval-Augmented Generation) في TrustGraph. تعاني التنفيذ الحالي من نقاط اختناق كبيرة في الأداء تؤثر على قابلية التوسع وأوقات الاستجابة. تعالج هذه المواصفات أربعة مجالات رئيسية للتحسين: +يصف هذا المستند تفصيليًا تحسينات الأداء الشاملة لخوارزمية GraphRAG (Graph Retrieval-Augmented Generation) في TrustGraph. تعاني التنفيذ الحالي من نقاط اختناق أداء كبيرة تحد من قابلية التوسع وأوقات الاستجابة. يتناول هذا المستند أربعة مجالات رئيسية للتحسين: -1. **تحسين اجتياز الرسم البياني**: التخلص من استعلامات قاعدة البيانات المتكررة وغير الفعالة وتنفيذ استكشاف الرسم البياني المجمّع. +1. **تحسين اجتياز الرسم البياني**: التخلص من استعلامات قاعدة البيانات المتكررة غير الفعالة وتنفيذ استكشاف الرسم البياني المجمّع. 2. **تحسين حل التسميات**: استبدال استرداد التسميات التسلسلي بعمليات متوازية/مجمعة. -3. **تحسين استراتيجية التخزين المؤقت**: تنفيذ تخزين مؤقت ذكي مع الإخلاء حسب الأقل استخدامًا (LRU) والتحميل المسبق. -4. **تحسين الاستعلام**: إضافة تجميع النتائج وتخزين تضمينات الاستعلام لتحسين أوقات الاستجابة. +3. **تحسين استراتيجية التخزين المؤقت**: تنفيذ تخزين مؤقت ذكي مع إخلاء LRU والتعبئة المسبقة. +4. **تحسين الاستعلام**: إضافة تدوين النتائج وتخزين تضمينات الاستعلام لتحسين أوقات الاستجابة. ## الأهداف -- **تقليل حجم استعلامات قاعدة البيانات**: تحقيق تقليل بنسبة 50-80% في إجمالي استعلامات قاعدة البيانات من خلال التجميع والتخزين المؤقت. -- **تحسين أوقات الاستجابة**: استهداف سرعة بناء الرسوم البيانية الفرعية 3-5 مرات أسرع وحل التسميات 2-3 مرات أسرع. -- **تعزيز قابلية التوسع**: دعم رسوم بيانية معرفية أكبر مع إدارة أفضل للذاكرة. -- **الحفاظ على الدقة**: الحفاظ على وظائف GraphRAG الحالية وجودة النتائج. -- **تمكين التزامن**: تحسين إمكانات المعالجة المتوازية للطلبات المتزامنة المتعددة. -- **تقليل البصمة الذاكرة**: تنفيذ هياكل بيانات وإدارة ذاكرة فعالة. -- **إضافة إمكانية المراقبة**: تضمين مقاييس الأداء وقدرات المراقبة. -- **ضمان الموثوقية**: إضافة معالجة مناسبة للأخطاء وآليات المهلة. +**تقليل حجم استعلامات قاعدة البيانات**: تحقيق تقليل بنسبة 50-80٪ في إجمالي استعلامات قاعدة البيانات من خلال التجميع والتخزين المؤقت. +**تحسين أوقات الاستجابة**: استهداف سرعة بناء الرسوم البيانية الفرعية بمقدار 3-5 مرات وسرعة حل التسميات بمقدار 2-3 مرات. +**تعزيز قابلية التوسع**: دعم رسوم بيانية معرفية أكبر مع إدارة أفضل للذاكرة. +**الحفاظ على الدقة**: الحفاظ على وظائف GraphRAG الحالية وجودة النتائج. +**تمكين التزامن**: تحسين إمكانيات المعالجة المتوازية للطلبات المتزامنة المتعددة. +**تقليل البصمة الذاكرة**: تنفيذ هياكل بيانات وإدارة ذاكرة فعالة. +**إضافة إمكانية المراقبة**: تضمين مقاييس الأداء وقدرات المراقبة. +**ضمان الموثوقية**: إضافة معالجة مناسبة للأخطاء وآليات المهلة. ## الخلفية -يظهر التنفيذ الحالي لـ GraphRAG في `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` عدة مشاكل أداء حرجة تؤثر بشدة على قابلية توسع النظام: +يُظهر التنفيذ الحالي لـ GraphRAG في `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` العديد من مشكلات الأداء الهامة التي تؤثر بشدة على قابلية توسع النظام: -### المشاكل الحالية في الأداء +### المشكلات الحالية في الأداء -**1. اجتياز الرسم البياني غير الفعال (`follow_edges` function، الأسطر 79-127)** -- يقوم بإجراء 3 استعلامات منفصلة لقاعدة البيانات لكل كيان ولكل مستوى عمق. -- نمط الاستعلام: استعلامات تعتمد على الموضوع، تعتمد على المرجع، وتعتمد على الكائن لكل كيان. -- لا يوجد تجميع: يعالج كل استعلام كيانًا واحدًا فقط في كل مرة. -- لا يوجد اكتشاف دورة: يمكن إعادة زيارة نفس العقد عدة مرات. -- يؤدي التنفيذ المتكرر بدون تجميع إلى تعقيد أسي. -- التعقيد الزمني: O(entities × max_path_length × triple_limit³) +**1. اجتياز الرسم البياني غير الفعال (دالة `follow_edges`، الأسطر 79-127)** +يقوم بإجراء 3 استعلامات لقاعدة البيانات لكل كيان لكل مستوى عمق. +نمط الاستعلام: استعلامات تعتمد على الموضوع، واستعلامات تعتمد على الرابط، واستعلامات تعتمد على الكائن لكل كيان. +لا يوجد تجميع: يعالج كل استعلام كيانًا واحدًا فقط في كل مرة. +لا يوجد اكتشاف دورات: يمكن إعادة زيارة نفس العقد عدة مرات. +يؤدي التنفيذ المتكرر بدون تدوين إلى تعقيد أسي. +التعقيد الزمني: O(entities × max_path_length × triple_limit³) -**2. حل تسلسلي للتسميات (`get_labelgraph` function، الأسطر 144-171)** -- يعالج كل مكون ثلاثي (الموضوع، المرجع، الكائن) بالتسلسل. -- قد يؤدي كل استدعاء `maybe_label` إلى تشغيل استعلام قاعدة بيانات. -- لا يوجد تنفيذ متوازي أو تجميع لاستعلامات التسميات. -- يؤدي إلى ما يصل إلى 3 × مكالمات قاعدة بيانات فردية لحجم الرسوم البيانية الفرعية. +**2. حل تسلسلي للتسميات (دالة `get_labelgraph`، الأسطر 144-171)** +يعالج كل مكون ثلاثي (موضوع، رابط، كائن) بالتسلسل. +قد يؤدي كل استدعاء لـ `maybe_label` إلى استعلام لقاعدة البيانات. +لا يوجد تنفيذ متوازي أو تجميع لاستعلامات التسمية. +يؤدي إلى ما يصل إلى 3 × استعلامات قاعدة بيانات فردية بحجم الرسم البياني الفرعي. -**3. استراتيجية تخزين مؤقت بدائية (`maybe_label` function، الأسطر 62-77)** -- ذاكرة تخزين مؤقت بسيطة للقواميس بدون حدود حجم أو TTL (وقت انتهاء الصلاحية). -- لا توجد سياسة إخلاء ذاكرة التخزين المؤقت تؤدي إلى نمو غير محدود للذاكرة. -- تؤدي أخطاء ذاكرة التخزين المؤقت إلى استعلامات قاعدة بيانات فردية. -- لا يوجد تحميل مسبق أو تسخين ذكي لذاكرة التخزين المؤقت. +**3. استراتيجية تخزين مؤقت بدائية (دالة `maybe_label`، الأسطر 62-77)** +ذاكرة تخزين مؤقت بسيطة للقواميس بدون حدود حجم أو TTL. +لا توجد سياسة إخلاء للتخزين المؤقت تؤدي إلى نمو غير محدود للذاكرة. +تؤدي أخطاء التخزين المؤقت إلى استعلامات قاعدة بيانات فردية. +لا يوجد تعبئة مسبقة أو تخزين مؤقت ذكي. -**4. أنماط استعلام غير مثالية** -- استعلامات تشابه متجه الكيان غير مخزنة مؤقتًا بين الطلبات المتشابهة. -- لا يوجد تجميع للنتائج لـ أنماط الاستعلام المتكررة. -- استعلامات غير محسنة لـ الأنماط الشائعة للوصول. +**4. أنماط استعلام دون المستوى الأمثل** +استعلامات تشابه متجه الكيان غير مخزنة مؤقتًا بين الطلبات المتشابهة. +لا يوجد تدوين للنتائج لأنماط الاستعلام المتكررة. +أنماط استعلام مفقودة للوصول الشائع. -**5. مشاكل حرجة في دورة حياة الكائنات (`rag.py:96-102`)** -- **كائن GraphRag يتم إعادة إنشاؤه لكل طلب**: يتم إنشاء نسخة جديدة لكل استعلام، مما يؤدي إلى فقدان جميع فوائد ذاكرة التخزين المؤقت. -- **عمر كائن الاستعلام قصير للغاية**: يتم إنشاؤه وتدميره داخل تنفيذ استعلام واحد (الأسطر 201-207). -- **تتم إعادة تعيين ذاكرة التخزين المؤقت للتسميات لكل طلب**: يتم فقدان تسخين ذاكرة التخزين المؤقت والمعرفة المتراكمة بين الطلبات. -- **نفقات إعادة إنشاء العميل**: قد يتم إعادة إنشاء عملاء قاعدة البيانات لكل طلب. -- **لا يوجد تحسين عبر الطلبات**: لا يمكن الاستفادة من أنماط الاستعلام أو مشاركة النتائج. +**5. مشكلات حرجة في عمر الكائن (`rag.py:96-102`)** +**يتم إعادة إنشاء كائن GraphRag لكل طلب**: يتم إنشاء نسخة جديدة لكل استعلام، مما يفقد جميع فوائد التخزين المؤقت. +**عمر كائن الاستعلام قصير للغاية**: يتم إنشاؤه وتدميره داخل تنفيذ استعلام واحد (الأسطر 201-207). +**يتم إعادة تعيين ذاكرة التخزين المؤقت للتسميات لكل طلب**: يتم فقد التخزين المؤقت والتراكم المعرفي بين الطلبات. +**نفقات إعادة إنشاء العميل**: قد يتم إعادة إنشاء عملاء قاعدة البيانات لكل طلب. +**لا يوجد تحسين عبر الطلبات**: لا يمكن الاستفادة من أنماط الاستعلام أو مشاركة النتائج. ### تحليل تأثير الأداء -السيناريو الأسوأ حاليًا لطلب نموذجي: -- **استرداد الكيان**: استعلام تشابه متجه واحد. -- **اجتياز الرسم البياني**: entities × max_path_length × 3 × triple_limit استعلامات. -- **حل التسميات**: subgraph_size × 3 استعلامات تسمية فردية. +السيناريو الأسوأ الحالي لطلب نموذجي: +**استرداد الكيان**: استعلام واحد لتقارب المتجهات. +**اجتياز الرسم البياني**: entities × max_path_length × 3 × triple_limit استعلامات. +**حل التسميات**: subgraph_size × 3 استعلامات تسمية فردية. -بالإعدادات الافتراضية (50 كيانًا، طول المسار 2، حد ثلاثي 30، حجم الرسم البياني الفرعية 150): -- **الحد الأدنى من الاستعلامات**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 استعلام لقاعدة البيانات**. -- **وقت الاستجابة**: 15-30 ثانية للرسوم البيانية متوسطة الحجم. -- **استخدام الذاكرة**: نمو غير محدود لذاكرة التخزين المؤقت بمرور الوقت. -- **فعالية ذاكرة التخزين المؤقت**: 0% - تتم إعادة تعيين ذاكرة التخزين المؤقت في كل طلب. -- **نفقات إنشاء الكائنات**: يتم إنشاء/تدمير كائنات GraphRag + Query لكل طلب. +للإعدادات الافتراضية (50 كيانًا، وطول المسار 2، وقيود على 30 ثلاثية، وحجم الرسم البياني الفرعي 150): +**عدد الاستعلامات:** 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9451 استعلامًا لقاعدة البيانات** +**وقت الاستجابة:** 15-30 ثانية للرسوم البيانية متوسطة الحجم +**استخدام الذاكرة:** نمو غير محدود لذاكرة التخزين المؤقت بمرور الوقت +**فعالية التخزين المؤقت:** 0% - يتم إعادة تعيين ذاكرة التخزين المؤقت في كل طلب +**تكلفة إنشاء الكائنات:** يتم إنشاء كائنات GraphRag + Query وتدميرها لكل طلب -تعالج هذه المواصفات هذه الثغرات من خلال تنفيذ استعلامات مجمعة، وتخزين مؤقت ذكي، ومعالجة متوازية. من خلال تحسين أنماط الاستعلام والوصول إلى البيانات، يمكن لـ TrustGraph: -- دعم الرسوم البيانية المعرفية على مستوى المؤسسات مع ملايين الكيانات. -- توفير أوقات استجابة فرعية من الثانية للطلبات النموذجية. -- التعامل مع مئات الطلبات المتزامنة لـ GraphRAG. -- التوسع بكفاءة مع حجم الرسم البيانية وتعقيدها. +تعالج هذه المواصفات هذه الثغرات من خلال تنفيذ الاستعلامات المجمعة، والتخزين المؤقت الذكي، والمعالجة المتوازية. من خلال تحسين أنماط الاستعلام والوصول إلى البيانات، يمكن لـ TrustGraph: +دعم رسوم بيانية معرفية على نطاق المؤسسات تحتوي على ملايين الكيانات +توفير أوقات استجابة أقل من ثانية للاستعلامات النموذجية +التعامل مع مئات طلبات GraphRAG المتزامنة +التوسع بكفاءة مع حجم الرسم البياني وتعقيده -## التصميم التقني +## التصميم الفني -### البنية التحتية +### البنية -يتطلب تحسين أداء GraphRAG المكونات التقنية التالية: +يتطلب تحسين أداء GraphRAG المكونات الفنية التالية: -#### 1. **إعادة هيكلة معمارية لدورة حياة الكائنات** - - **جعل GraphRag طويل الأمد**: نقل مثيل GraphRag إلى مستوى المعالج للاستمرار عبر الطلبات. - - **الحفاظ على ذاكرات التخزين المؤقت**: الحفاظ على ذاكرة التخزين المؤقت للتسميات، وذاكرة التخزين المؤقت للتضمينات، وذاكرة التخزين المؤقت لنتائج الاستعلام بين الطلبات. - - **تحسين كائن الاستعلام**: إعادة هيكلة الاستعلام كسياق تنفيذ خفيف الوزن، وليس حاوية بيانات. - - **استمرارية الاتصال**: الحفاظ على اتصالات عملاء قاعدة البيانات عبر الطلبات. +#### 1. **إعادة هيكلة دورة حياة الكائنات** + **جعل GraphRag يعمل لفترة أطول:** نقل مثيل GraphRag إلى مستوى المعالج للاستمرارية عبر الطلبات + **الحفاظ على ذاكرة التخزين المؤقت:** الحفاظ على ذاكرة التخزين المؤقت للتسميات، وذاكرة التخزين المؤقت للتضمينات، وذاكرة التخزين المؤقت لنتائج الاستعلام بين الطلبات + **تحسين كائن الاستعلام:** إعادة هيكلة الاستعلام كسياق تنفيذ خفيف الوزن، وليس حاوية بيانات + **استمرارية الاتصال:** الحفاظ على اتصالات عميل قاعدة البيانات عبر الطلبات الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (تم التعديل) -#### 2. **محرك اجتياز محسّن للرسم البياني** - - استبدال `follow_edges` المتكرر ببحث عرضي تكراري. - - تنفيذ معالجة مجمعة للكيانات على كل مستوى من مستويات الاجتياز. - - إضافة اكتشاف دورة باستخدام تتبع العقد التي تمت زيارتها. - - تضمين إنهاء مبكر عند الوصول إلى الحدود. +#### 2. **محرك اجتياز الرسم البياني المحسن** + استبدال `follow_edges` التكراري ببحث عرضي تكراري + تنفيذ معالجة مجمعة للكيانات في كل مستوى من مستويات الاجتياز + إضافة اكتشاف الدورات باستخدام تتبع العقد التي تمت زيارتها + تضمين الإنهاء المبكر عند الوصول إلى الحدود الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` -#### 3. **نظام حل تسميات متوازي** - - تجميع استعلامات التسميات لعدة كيانات في وقت واحد. - - تنفيذ أنماط async/await للوصول المتزامن إلى قاعدة البيانات. - - إضافة تحميل مسبق ذكي لـ أنماط التسميات الشائعة. - - تضمين استراتيجيات تسخين لذاكرة التخزين المؤقت للتسميات. +#### 3. **نظام حل التسميات المتوازي** + تجميع استعلامات التسميات لعدة كيانات في وقت واحد + تنفيذ أنماط async/await للوصول المتزامن إلى قاعدة البيانات + إضافة استرجاع استباقي لأنماط التسميات الشائعة + تضمين استراتيجيات تسخين ذاكرة التخزين المؤقت للتسميات الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` #### 4. **طبقة تخزين مؤقت محافظة للتسميات** - - ذاكرة تخزين مؤقت LRU مع TTL قصير للتسميات فقط (5 دقائق) لتحقيق التوازن بين الأداء مقابل الاتساق. - - مقاييس ذاكرة التخزين المؤقت ونسبة الضبط. - - **لا يوجد تخزين مؤقت للتضمينات**: يتم بالفعل تخزين التضمينات مؤقتًا لكل استعلام. - - **لا يوجد تخزين مؤقت للنتائج**: يمنع نتائج الرسوم البيانية الفرعية القديمة من الكيانات/العلاقات المحذوفة. + ذاكرة تخزين مؤقت LRU مع TTL قصيرة للتسميات فقط (5 دقائق) لتحقيق التوازن بين الأداء والاتساق + مراقبة مقاييس ذاكرة التخزين المؤقت ونسبة النجاح + **لا يوجد تخزين مؤقت للتضمينات:** يتم تخزينها بالفعل لكل استعلام، ولا يوجد فائدة عبر الاستعلامات + **لا يوجد تخزين مؤقت لنتائج الاستعلام:** بسبب مخاوف اتساق تغييرات الرسم البياني - الوحدة: `trustgraph-flow/trust/graph/label_cache.py` + الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` -#### 5. **تحسين الاستعلام والمراقبة** - - جمع مقاييس الأداء. - - تطبيق مهلة على الاستعلامات. - - إضافة دائرة كهربائية لمنع الاستخدام المفرط للموارد. +#### 5. **إطار تحسين الاستعلام** + تحليل الاستعلام واقتراحات التحسين + منسق استعلامات مجمعة للوصول إلى قاعدة البيانات + تجميع الاتصالات وإدارة مهلة الاستعلام + مراقبة الأداء وجمع المقاييس - الوحدة: `trustgraph-flow/trust/graph/query_optimizer.py` + الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` -## اعتبارات الاتساق للذاكرة المؤقتة +### نماذج البيانات -**موازنات بين بيانات قديمة**: -- **ذاكرة التخزين المؤقت للتسميات (TTL 5 دقائق)**: خطر تقديم تسميات الكيانات المحذوفة/المتجددة. -- **لا يوجد تخزين مؤقت للتضمينات**: ليس مطلوبًا - يتم تخزين التضمينات بالفعل مؤقتًا لكل استعلام. -- **لا يوجد تخزين مؤقت للنتائج**: يمنع نتائج الرسم البياني الفرعية القديمة من الكيانات/العلاقات المحذوفة. +#### حالة اجتياز الرسم البياني المحسنة -**استراتيجيات التخفيف**: -- **قيم TTL متحفظة**: الموازنة بين مكاسب الأداء (10-20٪) مقابل نضارة البيانات. -- **خطافات إبطال ذاكرة التخزين المؤقت**: تكامل اختياري مع أحداث تعديل الرسم البياني. -- **لوحات معلومات المراقبة**: تتبع معدلات ضرب ذاكرة التخزين المؤقت مقابل حوادث التقادم. -- **سياسات ذاكرة التخزين المؤقت القابلة للتكوين**: السماح بضبط لكل نشر بناءً على تكرار التعديل. +يحتفظ محرك الاجتياز بالحالة لتجنب العمليات المتكررة: -**تكوين ذاكرة التخزين المؤقت الموصى به حسب معدل تعديل الرسم البياني**: -- **تعديل عالي (>100 تغيير / ساعة)**: TTL = 60 ثانية، أحجام ذاكرة تخزين مؤقت أصغر. -- **تعديل متوسط (10-100 تغيير / ساعة)**: TTL = 300 ثانية (افتراضي). -- **تعديل منخفض (<10 تغيير / ساعة)**: TTL = 600 ثانية، أحجام ذاكرة تخزين مؤقت أكبر. +```python +@dataclass +class TraversalState: + visited_entities: Set[str] + current_level_entities: Set[str] + next_level_entities: Set[str] + subgraph: Set[Tuple[str, str, str]] + depth: int + query_batch: List[TripleQuery] +``` -## الاعتبارات الأمنية +تسمح هذه الطريقة بما يلي: +الكشف الفعال عن الدورات من خلال تتبع الكيانات التي تمت زيارتها. +إعداد استعلامات مجمعة في كل مستوى من مستويات التكرار. +إدارة حالة فعالة من حيث الذاكرة. +الإنهاء المبكر عند الوصول إلى حدود الحجم. -**منع حقن الاستعلام**: -- التحقق من صحة جميع معرفات الكيانات ومعلمات الاستعلام. -- استخدام استعلامات مُعلمات لجميع التفاعلات مع قاعدة البيانات. -- تنفيذ حدود تعقيد الاستعلام لمنع هجمات الحرمان من الخدمة. +#### هيكل ذاكرة تخزين مؤقتة مُحسّن -**حماية الموارد**: -- فرض حدود قصوى لحجم الرسم البياني الفرعية. -- تنفيذ مهلات على الاستعلام لمنع استنفاد الموارد. -- إضافة مراقبة استخدام الذاكرة وحدود. +```python +@dataclass +class CacheEntry: + value: Any + timestamp: float + access_count: int + ttl: Optional[float] -**التحكم في الوصول**: -- الحفاظ على عزل المستخدم والمجموعة الحالي. -- إضافة تسجيل تدقيق للعمليات التي تؤثر على الأداء. -- تنفيذ تحديد المعدل للعمليات المكلفة. +class CacheManager: + label_cache: LRUCache[str, CacheEntry] + embedding_cache: LRUCache[str, CacheEntry] + query_result_cache: LRUCache[str, CacheEntry] + cache_stats: CacheStatistics +``` + +#### هياكل الاستعلامات المجمعة + +```python +@dataclass +class BatchTripleQuery: + entities: List[str] + query_type: QueryType # SUBJECT, PREDICATE, OBJECT + limit_per_entity: int + +@dataclass +class BatchLabelQuery: + entities: List[str] + predicate: str = LABEL +``` + +### واجهات برمجة التطبيقات (APIs) + +#### واجهات برمجة تطبيقات جديدة: + +**واجهة برمجة تطبيقات GraphTraversal** +```python +async def optimized_follow_edges_batch( + entities: List[str], + max_depth: int, + triple_limit: int, + max_subgraph_size: int +) -> Set[Tuple[str, str, str]] +``` + +**واجهة برمجة تطبيقات (API) لحل مشكلات التسمية الدفعية.** +```python +async def resolve_labels_batch( + entities: List[str], + cache_manager: CacheManager +) -> Dict[str, str] +``` + +**واجهة برمجة تطبيقات إدارة ذاكرة التخزين المؤقت** +```python +class CacheManager: + async def get_or_fetch_label(self, entity: str) -> str + async def get_or_fetch_embeddings(self, query: str) -> List[float] + async def cache_query_result(self, query_hash: str, result: Any, ttl: int) + def get_cache_statistics(self) -> CacheStatistics +``` + +#### واجهات برمجة التطبيقات (APIs) المعدلة: + +**GraphRag.query()** - تم تحسينها مع تحسينات في الأداء: +إضافة معلمة `cache_manager` للتحكم في التخزين المؤقت. +تضمين قيمة الإرجاع `performance_metrics`. +إضافة معلمة `query_timeout` للموثوقية. + +**فئة Query** - تم إعادة هيكلتها لمعالجة الدفعات: +استبدال معالجة الكيانات الفردية بعمليات الدفعات. +إضافة مديري سياق غير متزامنين لتنظيف الموارد. +تضمين استدعاءات رد الاتصال للتقدم لعمليات طويلة الأمد. + +### تفاصيل التنفيذ + +#### المرحلة 0: إعادة هيكلة عمرية معمارية حاسمة + +**التنفيذ الحالي الذي يمثل مشكلة:** +```python +# INEFFICIENT: GraphRag recreated every request +class Processor(FlowProcessor): + async def on_request(self, msg, consumer, flow): + # PROBLEM: New GraphRag instance per request! + self.rag = GraphRag( + embeddings_client = flow("embeddings-request"), + graph_embeddings_client = flow("graph-embeddings-request"), + triples_client = flow("triples-request"), + prompt_client = flow("prompt-request"), + verbose=True, + ) + # Cache starts empty every time - no benefit from previous requests + response = await self.rag.query(...) + +# VERY SHORT-LIVED: Query object created/destroyed per request +class GraphRag: + async def query(self, query, user="trustgraph", collection="default", ...): + q = Query(rag=self, user=user, collection=collection, ...) # Created + kg = await q.get_labelgraph(query) # Used briefly + # q automatically destroyed when function exits +``` + +**هيكل معماري مُحسّن وعالي الأداء:** +```python +class Processor(FlowProcessor): + def __init__(self, **params): + super().__init__(**params) + self.rag_instance = None # Will be initialized once + self.client_connections = {} + + async def initialize_rag(self, flow): + """Initialize GraphRag once, reuse for all requests""" + if self.rag_instance is None: + self.rag_instance = LongLivedGraphRag( + embeddings_client=flow("embeddings-request"), + graph_embeddings_client=flow("graph-embeddings-request"), + triples_client=flow("triples-request"), + prompt_client=flow("prompt-request"), + verbose=True, + ) + return self.rag_instance + + async def on_request(self, msg, consumer, flow): + # REUSE the same GraphRag instance - caches persist! + rag = await self.initialize_rag(flow) + + # Query object becomes lightweight execution context + response = await rag.query_with_context( + query=v.query, + execution_context=QueryContext( + user=v.user, + collection=v.collection, + entity_limit=entity_limit, + # ... other params + ) + ) + +class LongLivedGraphRag: + def __init__(self, ...): + # CONSERVATIVE caches - balance performance vs consistency + self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness + # Note: No embedding cache - already cached per-query, no cross-query benefit + # Note: No query result cache due to consistency concerns + self.performance_metrics = PerformanceTracker() + + async def query_with_context(self, query: str, context: QueryContext): + # Use lightweight QueryExecutor instead of heavyweight Query object + executor = QueryExecutor(self, context) # Minimal object + return await executor.execute(query) + +@dataclass +class QueryContext: + """Lightweight execution context - no heavy operations""" + user: str + collection: str + entity_limit: int + triple_limit: int + max_subgraph_size: int + max_path_length: int + +class QueryExecutor: + """Lightweight execution context - replaces old Query class""" + def __init__(self, rag: LongLivedGraphRag, context: QueryContext): + self.rag = rag + self.context = context + # No heavy initialization - just references + + async def execute(self, query: str): + # All heavy lifting uses persistent rag caches + return await self.rag.execute_optimized_query(query, self.context) +``` + +هذا التغيير المعماري يوفر: +**تقليل بنسبة 10-20٪ في استعلامات قاعدة البيانات** للرسوم البيانية التي تحتوي على علاقات شائعة (مقارنة بـ 0٪ حاليًا). +**إزالة تكلفة إنشاء الكائنات** لكل طلب. +**تجميع الاتصالات المستمرة وإعادة استخدام العملاء**. +**تحسينات عبر الطلبات** ضمن إطارات زمنية للتخزين المؤقت (TTL). + +**قيود مهمة تتعلق بتناسق التخزين المؤقت:** +يؤدي التخزين المؤقت طويل الأجل إلى خطر حدوث بيانات قديمة عندما يتم حذف الكيانات/التصنيفات أو تعديلها في الرسم البياني الأساسي. يوفر التخزين المؤقت الأقل استخدامًا (LRU) مع إطار زمني للتخزين (TTL) توازنًا بين مكاسب الأداء وحداثة البيانات، ولكنه لا يمكنه اكتشاف تغييرات الرسم البياني في الوقت الفعلي. + +#### المرحلة الأولى: تحسين اجتياز الرسم البياني. + +**مشاكل التنفيذ الحالية:** +```python +# INEFFICIENT: 3 queries per entity per level +async def follow_edges(self, ent, subgraph, path_length): + # Query 1: s=ent, p=None, o=None + res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit) + # Query 2: s=None, p=ent, o=None + res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit) + # Query 3: s=None, p=None, o=ent + res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit) +``` + +**التنفيذ الأمثل:** +```python +async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]: + visited = set() + current_level = set(entities) + subgraph = set() + + for depth in range(max_depth): + if not current_level or len(subgraph) >= self.max_subgraph_size: + break + + # Batch all queries for current level + batch_queries = [] + for entity in current_level: + if entity not in visited: + batch_queries.extend([ + TripleQuery(s=entity, p=None, o=None), + TripleQuery(s=None, p=entity, o=None), + TripleQuery(s=None, p=None, o=entity) + ]) + + # Execute all queries concurrently + results = await self.execute_batch_queries(batch_queries) + + # Process results and prepare next level + next_level = set() + for result in results: + subgraph.update(result.triples) + next_level.update(result.new_entities) + + visited.update(current_level) + current_level = next_level - visited + + return subgraph +``` + +#### المرحلة الثانية: حل التسميات المتوازية + +**التنفيذ التسلسلي الحالي:** +```python +# INEFFICIENT: Sequential processing +for edge in subgraph: + s = await self.maybe_label(edge[0]) # Individual query + p = await self.maybe_label(edge[1]) # Individual query + o = await self.maybe_label(edge[2]) # Individual query +``` + +**التنفيذ المتوازي المُحسّن:** +```python +async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: + # Collect all unique entities needing labels + entities_to_resolve = set() + for s, p, o in subgraph: + entities_to_resolve.update([s, p, o]) + + # Remove already cached entities + uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache] + + # Batch query for all uncached labels + if uncached_entities: + label_results = await self.batch_label_query(uncached_entities) + self.label_cache.update(label_results) + + # Apply labels to subgraph + return [ + (self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o)) + for s, p, o in subgraph + ] +``` + +#### المرحلة الثالثة: استراتيجية التخزين المؤقت المتقدمة + +**ذاكرة تخزين مؤقت LRU مع TTL:** +```python +class LRUCacheWithTTL: + def __init__(self, max_size: int, default_ttl: int = 3600): + self.cache = OrderedDict() + self.max_size = max_size + self.default_ttl = default_ttl + self.access_times = {} + + async def get(self, key: str) -> Optional[Any]: + if key in self.cache: + # Check TTL expiration + if time.time() - self.access_times[key] > self.default_ttl: + del self.cache[key] + del self.access_times[key] + return None + + # Move to end (most recently used) + self.cache.move_to_end(key) + return self.cache[key] + return None + + async def put(self, key: str, value: Any): + if key in self.cache: + self.cache.move_to_end(key) + else: + if len(self.cache) >= self.max_size: + # Remove least recently used + oldest_key = next(iter(self.cache)) + del self.cache[oldest_key] + del self.access_times[oldest_key] + + self.cache[key] = value + self.access_times[key] = time.time() +``` + +#### المرحلة الرابعة: تحسين الاستعلامات والمراقبة + +**جمع مقاييس الأداء:** +```python +@dataclass +class PerformanceMetrics: + total_queries: int + cache_hits: int + cache_misses: int + avg_response_time: float + subgraph_construction_time: float + label_resolution_time: float + total_entities_processed: int + memory_usage_mb: float +``` + +**مهلة الاستعلام وقاطع الدائرة:** +```python +async def execute_with_timeout(self, query_func, timeout: int = 30): + try: + return await asyncio.wait_for(query_func(), timeout=timeout) + except asyncio.TimeoutError: + logger.error(f"Query timeout after {timeout}s") + raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s") +``` + +## اعتبارات تناسق ذاكرة التخزين المؤقت + +**موازنات بين قدوم البيانات:** +**ذاكرة تخزين مؤقت للتسميات (TTL مدته 5 دقائق):** خطر عرض تسميات الكيانات المحذوفة/المُعادة تسميتها. +**لا يوجد تخزين مؤقت للتضمينات:** غير ضروري - يتم تخزين التضمينات بالفعل لكل استعلام. +**لا يوجد تخزين مؤقت للنتائج:** يمنع النتائج الفرعية غير المستقرة من الرسوم البيانية الناتجة عن الكيانات/العلاقات المحذوفة. + +**استراتيجيات التخفيف:** +**قيم TTL محافظة:** الموازنة بين مكاسب الأداء (10-20٪) مع تحديث البيانات. +**خطافات إبطال ذاكرة التخزين المؤقت:** تكامل اختياري مع أحداث تعديل الرسم البياني. +**لوحات مراقبة:** تتبع معدلات نجاح ذاكرة التخزين المؤقت مقابل حوادث عدم الاستقرار. +**سياسات ذاكرة تخزين مؤقت قابلة للتكوين:** السماح بضبط لكل توزيع بناءً على تكرار التعديل. + +**تكوين ذاكرة التخزين المؤقت الموصى به بناءً على معدل تعديل الرسم البياني:** +**تعديل مرتفع (>100 تغيير/ساعة):** TTL=60 ثانية، أحجام ذاكرة تخزين مؤقت أصغر. +**تعديل متوسط (10-100 تغيير/ساعة):** TTL=300 ثانية (افتراضي). +**تعديل منخفض (<10 تغيير/ساعة):** TTL=600 ثانية، أحجام ذاكرة تخزين مؤقت أكبر. + +## اعتبارات الأمان + +**منع حقن الاستعلام:** +التحقق من صحة جميع معرفات الكيانات ومعلمات الاستعلام. +استخدم استعلامات مُعلمات لجميع التفاعلات مع قاعدة البيانات. +تنفيذ حدود تعقيد الاستعلام لمنع هجمات الحرمان من الخدمة. + +**حماية الموارد:** +فرض حدود قصوى لحجم الرسم البياني. +تنفيذ مهلات الاستعلام لمنع استنفاد الموارد. +إضافة مراقبة حدود استخدام الذاكرة. + +**التحكم في الوصول:** +الحفاظ على عزل المستخدمين والمجموعات الحالي. +إضافة تسجيل تدقيق للعمليات التي تؤثر على الأداء. +تنفيذ تحديد المعدل للعمليات المكلفة. ## اعتبارات الأداء ### التحسينات المتوقعة في الأداء -**تقليل الاستعلام**: -- الحالي: ~ 9000+ استعلام لطلب نموذجي. -- مُحسَّن: ~ 50-100 استعلام مجمعة (تقليل بنسبة 98٪). +**تقليل عدد الاستعلامات:** +الحالي: ~9000+ استعلام للطلب النموذجي. +مُحسَّن: ~50-100 استعلام مجمعة (تقليل بنسبة 98٪). -**تحسينات أوقات الاستجابة**: -- اجتياز الرسم البياني: 15-20 ثانية → 3-5 ثوانٍ (4-5 مرات أسرع). -- حل التسميات: 8-12 ثانية → 2-4 ثوانٍ (3 مرات أسرع). -- الاستعلام الإجمالي: 25-35 ثانية → 6-10 ثوانٍ (تحسين بمقدار 3-4 مرات). +**تحسينات في وقت الاستجابة:** +اجتياز الرسم البياني: 15-20 ثانية → 3-5 ثوانٍ (أسرع بـ 4-5 مرات). +حل التسميات: 8-12 ثانية → 2-4 ثوانٍ (أسرع بـ 3 مرات). +الاستعلام الإجمالي: 25-35 ثانية → 6-10 ثوانٍ (تحسين بنسبة 3-4 مرات). -**كفاءة الذاكرة**: -- أحجام ذاكرة التخزين المؤقت المحدودة تمنع تسرب الذاكرة. -- هياكل بيانات فعالة تقلل البصمة الذاكرة بنسبة ~ 40٪. -- إدارة أفضل للذاكرة من خلال التنظيف المناسب للموارد. +**كفاءة الذاكرة:** +تمنع أحجام ذاكرة التخزين المؤقت المحددة تسرب الذاكرة. +تقلل الهياكل البيانية الفعالة من البصمة الذاكرة بنسبة ~40٪. +جمع القمامة بشكل أفضل من خلال التنظيف المناسب للموارد. -**تحسينات قابلية التوسع**: -- دعم رسوم بيانية معرفية أكبر بنسبة 3-5 مرات (محدود باحتياجات اتساق ذاكرة التخزين المؤقت). -- سعة أعلى للطلبات المتزامنة بنسبة 3-5 مرات. -- استخدام أفضل للموارد من خلال إعادة استخدام الاتصال. +**توقعات واقعية للأداء:** +**ذاكرة تخزين مؤقت للتسميات:** تقليل استعلام بنسبة 10-20٪ للرسوم البيانية ذات العلاقات الشائعة. +**تحسين التجميع:** تقليل استعلام بنسبة 50-80٪ (التحسين الأساسي). +**تحسين عمر الكائن:** إزالة النفقات العامة لإنشاء الطلبات لكل طلب. +**تحسين إجمالي:** تحسين وقت الاستجابة بنسبة 3-4 مرات بشكل أساسي من خلال التجميع. + +**تحسينات قابلية التوسع:** +دعم رسوم بيانية معرفية أكبر بـ 3-5 مرات (محدود بمتطلبات تناسق ذاكرة التخزين المؤقت). +سعة أعلى للطلبات المتزامنة بـ 3-5 مرات. +استخدام أفضل للموارد من خلال إعادة استخدام الاتصالات. ### مراقبة الأداء -**مقاييس في الوقت الفعلي**: -- أوقات تنفيذ الاستعلام حسب نوع العملية. -- معدلات ضرب وفعالية ذاكرة التخزين المؤقت. -- استخدام مجموعة اتصالات قاعدة البيانات. -- استخدام الذاكرة وجمع البيانات المهملة. +**مقاييس في الوقت الفعلي:** +أوقات تنفيذ الاستعلام حسب نوع العملية. +نسب نجاح ذاكرة التخزين المؤقت وفعاليتها. +استخدام مجموعة اتصالات قاعدة البيانات. +استخدام الذاكرة وتأثير جمع القمامة. -**قياس الأداء**: -- اختبار أداء مقابل التنفيذ الحالي. -- اختبار التحميل بأحجام بيانات وتعقيدات مختلفة. -- اختبار الضغط لحدود الموارد. -- اختبار الانحدار للتحسينات في الأداء. +**قياس الأداء:** +اختبارات انحدار الأداء الآلية +اختبارات التحميل باستخدام أحجام بيانات واقعية +معايير مقارنة مقابل التنفيذ الحالي ## استراتيجية الاختبار -### اختبار الوحدة -- اختبار مكون فردي لـ الاجتياز، والتخزين المؤقت، وحل التسميات. -- محاكاة تفاعلات قاعدة البيانات لاختبار الأداء. -- اختبار الإخلاء و TTL ذاكرة التخزين المؤقت. -- سيناريوهات معالجة الأخطاء والمهلات. +### اختبارات الوحدة +اختبار المكونات الفردية للتنقل والتخزين المؤقت وحل التسميات +محاكاة تفاعلات قاعدة البيانات لأغراض اختبار الأداء +اختبار إزالة التخزين المؤقت وانتهاء صلاحية TTL +معالجة الأخطاء وسيناريوهات المهلة الزمنية ### اختبار التكامل -- اختبار GraphRAG الشامل مع التحسينات. -- اختبار تفاعل قاعدة البيانات مع بيانات حقيقية. -- اختبار التعامل مع الطلبات المتزامنة وإدارة الموارد. -- الكشف عن تسرب الذاكرة والتحقق من تنظيف الموارد. +اختبار شامل لاستعلامات GraphRAG مع التحسينات +اختبار تفاعلات قاعدة البيانات باستخدام بيانات حقيقية +معالجة الطلبات المتزامنة وإدارة الموارد +اكتشاف تسرب الذاكرة والتحقق من تنظيف الموارد ### اختبار الأداء -- اختبار أداء مقابل التنفيذ الحالي. -- اختبار التحميل بأحجام وتعقيدات مختلفة للرسم البياني. -- اختبار الضغط لحدود الذاكرة والاتصال. -- اختبار الانحدار للتحسينات في الأداء. +اختبارات قياس الأداء مقابل التنفيذ الحالي +اختبارات التحميل بأحجام وتعقيدات رسومية مختلفة +اختبارات الضغط لحدود الذاكرة والاتصالات +اختبارات الانحدار لتحسينات الأداء ### اختبار التوافق -- التحقق من توافق واجهة برمجة تطبيقات GraphRAG الحالية. -- الاختبار مع خلفيات قاعدة بيانات رسم بياني مختلفة. -- التحقق من دقة النتائج مقارنة بالتنفيذ الحالي. +التحقق من توافق واجهة برمجة تطبيقات GraphRAG الحالية +الاختبار مع قواعد بيانات رسومية مختلفة +التحقق من دقة النتائج مقارنة بالتنفيذ الحالي ## خطة التنفيذ -### النهج المباشر للتنفيذ -نظرًا للسماح بتغييرات واجهة برمجة التطبيقات، قم بتنفيذ التحسينات مباشرة دون تعقيد الترحيل: +### نهج التنفيذ المباشر +نظرًا لأن واجهات برمجة التطبيقات مسموح لها بالتغيير، قم بتنفيذ التحسينات مباشرةً دون تعقيد الترحيل: -1. **استبدل طريقة `follow_edges`**: أعد كتابة مع اجتياز مجمّع تكراري. -2. **تحسين `get_labelgraph`**: قم بتنفيذ حل تسميات متوازي. -3. **أضف GraphRag طويل الأمد**: قم بتعديل المعالج لاستخدام نسخة مستمرة. -4. **قم بتنفيذ استراتيجية التخزين المؤقت**: أضف طبقة تخزين مؤقت إلى فئة GraphRag. +1. **استبدال `follow_edges`:** أعد كتابة باستخدام تجول دفعي تكراري +2. **تحسين `get_labelgraph`:** قم بتنفيذ حل تسميات متوازي +3. **إضافة GraphRag طويل الأمد:** قم بتعديل المعالج للحفاظ على مثيل دائم +4. **تنفيذ التخزين المؤقت للتسميات:** أضف ذاكرة تخزين مؤقت LRU مع TTL إلى فئة GraphRag ### نطاق التغييرات -- **فئة الاستعلام**: استبدل ~50 سطرًا في `follow_edges`، وأضف ~30 سطرًا للتعامل مع التجميع. -- **فئة GraphRag**: أضف طبقة تخزين مؤقت (~40 سطرًا). -- **فئة المعالج**: قم بتعديل لاستخدام مثيل GraphRag دائم (~20 سطرًا). -- **إجمالي**: ~ 140 سطرًا من التغييرات المركزة، في الغالب داخل الفئات الحالية. +**فئة الاستعلام:** استبدل ~50 سطرًا في `follow_edges`، وأضف ~30 سطرًا لمعالجة الدفعات +**فئة GraphRag:** أضف طبقة التخزين المؤقت (~40 سطرًا) +**فئة المعالج:** قم بتعديل لاستخدام مثيل GraphRag دائم (~20 سطرًا) +**الإجمالي:** ~140 سطرًا من التغييرات المركزة، معظمها داخل الفئات الحالية -## جدول زمني +## الجدول الزمني **الأسبوع 1: التنفيذ الأساسي** -- استبدل `follow_edges` باجتياز تكراري مجمّع. -- قم بتنفيذ حل تسميات متوازي في `get_labelgraph`. -- أضف مثيل GraphRag طويل الأمد إلى المعالج. -- قم بتنفيذ طبقة التخزين المؤقت للتسميات. +استبدل `follow_edges` بالتجول الدفعي التكراري +قم بتنفيذ حل تسميات متوازي في `get_labelgraph` +أضف مثيل GraphRag طويل الأمد إلى المعالج +قم بتنفيذ طبقة التخزين المؤقت للتسميات **الأسبوع 2: الاختبار والتكامل** -- اختبارات الوحدة لمنطق الاجتياز والتخزين المؤقت الجديد. -- قياس الأداء مقابل التنفيذ الحالي. -- اختبار التكامل مع بيانات الرسم البياني الحقيقية. -- مراجعة الكود والتحسين. +اختبارات الوحدة لمنطق التجول والتخزين المؤقت الجديد +قياس أداء مقابل التنفيذ الحالي +اختبار التكامل مع بيانات رسومية حقيقية +مراجعة التعليمات البرمجية والتحسين **الأسبوع 3: النشر** -- نشر التنفيذ المُحسَّن. -- مراقبة تحسينات الأداء. -- ضبط TTL ذاكرة التخزين المؤقت وأحجام الدفعات بناءً على الاستخدام الفعلي. +نشر التنفيذ المحسن +مراقبة تحسينات الأداء +ضبط TTL للتخزين المؤقت وأحجام الدفعات بناءً على الاستخدام الفعلي ## أسئلة مفتوحة -- **تجميع الاتصال بقاعدة البيانات**: هل يجب علينا تنفيذ تجميع اتصال مخصص أم الاعتماد على تجميع عملاء قاعدة البيانات الحالي؟ -- **استمرارية ذاكرة التخزين المؤقت**: هل يجب أن تستمر ذاكرات التخزين المؤقت للتسميات والتضمينات عبر عمليات إعادة تشغيل الخدمة؟ -- **التخزين المؤقت الموزع**: بالنسبة لنشر متعدد المثيلات، هل يجب علينا تنفيذ تخزين مؤقت موزع باستخدام Redis/Memcached؟ -- **تنسيق نتيجة الاستعلام**: هل يجب علينا تحسين التمثيل الداخلي للثلاثي لتحسين كفاءة الذاكرة؟ -- **تكامل المراقبة**: ما هي المقاييس التي يجب عرضها على أنظمة المراقبة الحالية (Prometheus، إلخ)؟ +**تجميع الاتصالات بقاعدة البيانات:** هل يجب علينا تنفيذ تجميع اتصالات مخصص أم الاعتماد على تجميع عملاء قاعدة البيانات الحالي؟ +**استمرارية التخزين المؤقت:** هل يجب أن تستمر ذاكرات التخزين المؤقت للتسميات والتضمينات عبر عمليات إعادة تشغيل الخدمة؟ +**التخزين المؤقت الموزع:** بالنسبة لنشرات متعددة المثيلات، هل يجب علينا تنفيذ تخزين مؤقت موزع باستخدام Redis/Memcached؟ +**تنسيق نتيجة الاستعلام:** هل يجب علينا تحسين التمثيل الداخلي للثلاثيات لتحسين كفاءة الذاكرة؟ +**تكامل المراقبة:** ما هي المقاييس التي يجب عرضها على أنظمة المراقبة الحالية (Prometheus، إلخ)؟ ## المراجع -- [التنفيذ الأصلي لـ GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) -- [مبادئ معمارية TrustGraph](architecture-principles.md) -- [مواصفات إدارة المجموعة](collection-management.md) \ No newline at end of file +[التنفيذ الأصلي لـ GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +[مبادئ معمارية TrustGraph](architecture-principles.md) +[مواصفات إدارة المجموعة](collection-management.md) diff --git a/docs/tech-specs/graphrag-performance-optimization.he.md b/docs/tech-specs/graphrag-performance-optimization.he.md index 60a650d2..8e28c46d 100644 --- a/docs/tech-specs/graphrag-performance-optimization.he.md +++ b/docs/tech-specs/graphrag-performance-optimization.he.md @@ -1,101 +1,629 @@ -# מפרט טכני לאופטימיזציה של ביצועים של GraphRAG +# מפרט טכני לשיפור ביצועי GraphRAG ## סקירה כללית -מפרט זה מתאר אופטימיזציות מקיפות לביצועים של האלגוריתם GraphRAG (Graph Retrieval-Augmented Generation) ב-TrustGraph. יישום הנוכחי סובל מחסמי ביצועים משמעותיים המגבילים את יכולת ההרחבה וזמני התגובה. מפרט זה מתייחס לארבעה תחומים עיקריים של אופטימיזציה: +מפרט זה מתאר שיפורי ביצועים מקיפים עבור אלגוריתם GraphRAG (Graph Retrieval-Augmented Generation) ב-TrustGraph. יישום הנוכחי סובל מבעיות ביצועים משמעותיות המגבילות את יכולת ההרחבה וזמני התגובה. מפרט זה מתייחס לארבעה תחומים עיקריים של אופטימיזציה: -1. **אופטימיזציה של מעבר גרפים**: הסרת שאילתות מסד נתונים רקורסיביות לא יעילות ויישום חקר גרפים בטעינה. -2. **אופטימיזציה של פתרון תגים**: החלפת שליפת תגים רציפה בפעולות מקבילות/בטעינה. -3. **שיפור אסטרטגיית אחסון במטמון**: יישום אחסון במטמון חכם עם פינוי LRU ואחזור מראש. -4. **אופטימיזציה של שאילתות**: הוספת שמירת תוצאות ואחסון במטמון של הטבעות לשיפור זמני התגובה. +1. **אופטימיזציה של מעבר גרפים**: ביטול שאילתות מסד נתונים רקורסיביות לא יעילות ויישום חקר גרפים באצווה. +2. **אופטימיזציה של פתרון תגיות**: החלפת אחזור תגיות רציף בפעולות מקבילות/באצווה. +3. **שיפור אסטרטגיית אחסון במטמון**: יישום אחסון במטמון חכם עם פינוי LRU וטעינה מראש. +4. **אופטימיזציה של שאילתות**: הוספת שמירת תוצאות במטמון ואחסון במטמון של הטמעות לשיפור זמני התגובה. ## מטרות -- **הפחתת נפח שאילתות מסד נתונים**: השגת הפחתה של 50-80% בסך כל שאילתות מסד הנתונים באמצעות טעינה ואחסון במטמון. -- **שיפור זמני תגובה**: כוונון ל-3-5 פעמים מהירות יותר בבניית תת-גרף ו-2-3 פעמים מהירות יותר בפתרון תגים. -- **שיפור יכולת הרחבה**: תמיכה בגרפי ידע גדולים יותר עם ניהול זיכרון טוב יותר. -- **שימור דיוק**: שמירה על הפונקציונליות ואיכות התוצאות של GraphRAG הקיימים. -- **אפשרות לריבוי משימות**: שיפור יכולות עיבוד מקבילי עבור בקשות מקבילות מרובות. -- **הפחתת טביעת רגל של זיכרון**: יישום מבני נתונים וניהול זיכרון יעילים. -- **הוספת יכולת ניטור**: הכללת מדדי ביצועים ויכולות ניטור. -- **הבטחת אמינות**: הוספת טיפול שגיאות ומנגנוני זמן קצובים מתאימים. +**הפחתת נפח שאילתות מסד הנתונים**: השגת הפחתה של 50-80% בסך כל שאילתות מסד הנתונים באמצעות אצווה ואחסון במטמון. +**שיפור זמני תגובה**: יעד לבניית תת-גרפים מהירה פי 3-5 ופתרון תגיות מהיר פי 2-3. +**שיפור יכולת הרחבה**: תמיכה בגרפי ידע גדולים יותר עם ניהול זיכרון טוב יותר. +**שמירה על דיוק**: שמירה על פונקציונליות ואיכות תוצאות GraphRAG הקיימות. +**אפשרות לעיבוד מקבילי**: שיפור יכולות עיבוד מקבילי עבור בקשות מרובות בו-זמנית. +**הפחתת טביעת רגל של זיכרון**: יישום מבני נתונים וניהול זיכרון יעילים. +**הוספת יכולת ניטור**: הכללת מדדי ביצועים ויכולות ניטור. +**הבטחת אמינות**: הוספת טיפול בשגיאות ומנגנוני תזמון מתאימים. ## רקע -יישום ה-GraphRAG הנוכחי ב-`trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` מציג מספר בעיות ביצועים קריטיות המשפיעות באופן משמעותי על יכולת ההרחבה של המערכת: +יישום GraphRAG הנוכחי ב-`trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` מציג מספר בעיות ביצועים קריטיות המשפיעות באופן משמעותי על יכולת ההרחבה של המערכת: ### בעיות ביצועים נוכחיות **1. מעבר גרפים לא יעיל (פונקציה `follow_edges`, שורות 79-127)** -- מבצע 3 שאילתות נפרדות למסד הנתונים עבור כל ישות בכל רמת עומק. -- תבנית שאילתה: שאילתות מבוססות נושא, שאילתות מבוססות פרידיקט ושאילתות מבוססות אובייקט עבור כל ישות. -- ללא טעינה: כל שאילתה מעבדת רק ישות אחת בכל פעם. -- ללא זיהוי מעגלים: ניתן לחזור על צמתים זהים מספר פעמים. -- יישום רקורסיבי ללא שמירה במטמון מוביל למורכבות אקספוננציאלית. -- מורכבות זמן: O(entities × max_path_length × triple_limit³) +מבצע 3 שאילתות נפרדות למסד הנתונים עבור כל ישות בכל רמת עומק. +תבנית שאילתה: שאילתות מבוססות נושא, מבוססות פרידיקט ומבוססות אובייקט עבור כל ישות. +ללא אצווה: כל שאילתה מעבדת רק ישות אחת בכל פעם. +ללא זיהוי מעגלים: ניתן לחזור על צמתים זהים מספר פעמים. +יישום רקורסיבי ללא שמירה במטמון מוביל למורכבות אקספוננציאלית. +מורכבות זמן: O(entities × max_path_length × triple_limit³) -**2. פתרון תגים רציף (פונקציה `get_labelgraph`, שורות 144-171)** -- מעבד כל מרכיב משולש (נושא, פרידיקט, אובייקט) באופן רציף. -- כל קריאה ל-`maybe_label` עלולה לגרום לשאילתת מסד נתונים. -- ללא ביצוע מקבילי או טעינה של שאילתות תגים. -- גורם עד ל-3 × קריאות מסד נתונים בודדות עבור גודל תת-גרף. +**2. פתרון תגיות רציף (פונקציה `get_labelgraph`, שורות 144-171)** +מעבד כל רכיב משולש (נושא, פרידיקט, אובייקט) ברצף. +כל קריאה ל-`maybe_label` עלולה לגרום לשאילתה למסד הנתונים. +ללא ביצוע מקבילי או אצווה של שאילתות תגיות. +גורם עד ל-3 × קריאות אישיות למסד הנתונים עבור גודל תת-גרף. **3. אסטרטגיית אחסון במטמון בסיסית (פונקציה `maybe_label`, שורות 62-77)** -- מטמון מילון פשוט ללא מגבלות גודל או TTL. -- מדיניות פינוי מטמון חסרה גורמת לצמיחה בלתי מוגבלת של הזיכרון. -- אי-הצלחה במטמון גורמת לשאילתות מסד נתונים בודדות. -- ללא אחזור מראש או חימום מטמון חכם. +מטמון מילון פשוט ללא מגבלות גודל או TTL. +מדיניות פינוי מטמון חסרת גבולות מובילה לצמיחה בלתי מוגבלת של זיכרון. +החסרה במטמון גורמת לשאילתות נפרדות למסד הנתונים. +ללא טעינה מראש או אחסון במטמון חכם. **4. תבניות שאילתות לא אופטימליות** -- שאילתות דמיון וקטורי של ישויות אינן מאוחסנות במטמון בין בקשות דומות. -- ללא שמירת תוצאות לשאילתות דומות. -- אופטימיזציה חסרה של שאילתות לתבניות גישה נפוצות. +שאילתות דמיון וקטורי לישויות אינן מאוחסנות במטמון בין בקשות דומות. +ללא שמירת תוצאות במטמון לתבניות שאילתות חוזרות. +חסרים אופטימיזציות שאילתות לתבניות גישה נפוצות. -**5. בעיות קריטיות בתוחלת החיים של אובייקטים (`rag.py:96-102`)** -- **אובייקט GraphRag נוצר מחדש עבור כל בקשה**: מופעל מופע חדש עבור כל שאילתה, תוך אובדן כל היתרונות של המטמון. -- **אובייקט שאילתה קצר מועד במיוחד**: נוצר ונהרס במהלך ביצוע שאילתה בודד (שורות 201-207). -- **מטמון תגים מאופס עבור כל בקשה**: חימום מטמון וידע שנצבר אובדים בין בקשות. -- **תקורה של יצירת לקוח**: לקוחות מסד נתונים מוקמים מחדש באופן פוטנציאלי עבור כל בקשה. -- **ללא אופטימיזציה חוצת בקשות**: לא ניתן להפיק תועלת מתבניות שאילתה או שיתוף תוצאות. +**5. בעיות קריטיות של חיי אובייקט (`rag.py:96-102`)** +**אובייקט GraphRag נוצר מחדש עבור כל בקשה**: מופע חדש נוצר עבור כל שאילתה, תוך אובדן כל יתרונות המטמון. +**אובייקט שאילתה בעל אורך חיים קצר ביותר**: נוצר ונהרס בתוך ביצוע שאילתה יחיד (שורות 201-207). +**מטמון תגיות מאופס עבור כל בקשה**: חימום מטמון וידע שנצבר אובדים בין בקשות. +**תקורה של יצירת לקוח מחדש**: לקוחות מסד נתונים פוטנציאליים מוקמים מחדש עבור כל בקשה. +**ללא אופטימיזציה חוצה בקשות**: לא ניתן להפיק תועלת מתבניות שאילתות או שיתוף תוצאות. -### ניתוח השפעה על ביצועים +### ניתוח השפעת ביצועים תרחיש גרוע ביותר נוכחי עבור שאילתה טיפוסית: -- **אחזור ישות**: שאילתת דמיון וקטורית אחת. -- **מעבר גרפים**: entities × max_path_length × 3 × triple_limit שאילתות. -- **פתרון תגים**: subgraph_size × 3 שאילתות תגים בודדות. +**אחזור ישות**: שאילתת דמיון וקטורית אחת. +**מעבר גרפים**: entities × max_path_length × 3 × שאילתות triple_limit. +**פתרון תגיות**: 3 × שאילתות תגיות אישיות עבור גודל תת-גרף. +פלט חוזה (יש לעקוב אחר הפורמט המדויק). +עבור פרמטרים ברירת מחדל (50 ישויות, אורך נתיב 2, מגבלת 30 משולשים, גודל תת-גרף 150): +**מספר שאילתות מינימלי**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 שאילתות למסד נתונים** +**זמן תגובה**: 15-30 שניות עבור גרפים בגודל בינוני +**שימוש בזיכרון**: צמיחה בלתי מוגבלת של מטמון לאורך זמן +**יעילות מטמון**: 0% - המטמון מאופס בכל בקשה +**תקורה של יצירת אובייקטים**: אובייקטי GraphRag + שאילתה נוצרים/נמחקים עבור כל בקשה -עבור פרמטרים ברירת מחדל (50 ישויות, אורך נתיב 2, מגבלת משולש 30, גודל תת-גרף 150): -- **מספר מינימלי של שאילתות**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 שאילתות למסד נתונים** -- **זמן תגובה**: 15-30 שניות עבור גרפים בגודל בינוני. -- **שימוש בזיכרון**: צמיחה בלתי מוגבלת של המטמון לאורך זמן. -- **יעילות מטמון**: 0% - מטמון מאופס בכל בקשה. -- **תקורה של יצירת אובייקטים**: אובייקטי GraphRag + Query נוצרים/נהרסים עבור כל בקשה. - -מפרט זה מתייחס לפערים אלה על ידי יישום שאילתות בטעינה, אחסון במטמון חכם ועיבוד מקבילי. על ידי אופטימיזציה של תבניות שאילתות וגישה לנתונים, TrustGraph יכולה: - -- לתמוך בגרפי ידע בקנה מידה ארגוני עם מיליוני ישויות. -- לספק זמני תגובה של פחות משנייה עבור שאילתות טיפוסיות. -- לטפל במאות בקשות GraphRAG מקבילות. -- להתרחב ביעילות עם גודל ומורכבות הגרף. +מפרט זה מתייחס לפערים אלה על ידי יישום שאילתות באצווה, מטמון חכם ועיבוד מקבילי. על ידי אופטימיזציה של דפוסי שאילתות וגישה לנתונים, TrustGraph יכולה: +לתמוך בגרפי ידע בקנה מידה ארגוני עם מיליוני ישויות +לספק זמני תגובה של פחות משנייה עבור שאילתות טיפוסיות +לטפל במאות בקשות GraphRAG מקבילות +להתרחב ביעילות עם גודל ומורכבות הגרף ## עיצוב טכני ### ארכיטקטורה -אופטימיזציה של ביצועי GraphRAG דורשת את הרכיבים הטכניים הבאים: +אופטימיזציית הביצועים של GraphRAG דורשת את הרכיבים הטכניים הבאים: -#### 1. **שינוי ארכיטקטורת תוחלת החיים של אובייקטים** - - **הפיכת GraphRag למוחזקת לאורך זמן**: העברת מופע GraphRag לרמת Processor לקבלת עמידות בין בקשות. - - **שמירה על מטמונים**: שמירה על מטמון תגים, מטמון הטבעות ומטמון תוצאות שאילתות בין בקשות. - - **אופטימיזציה של אובייקט שאילתה**: שינוי Query להקשר ביצוע קל משקל, לא מיכל נתונים. - - **שמירת חיבור**: שמירה על חיבורי מסד נתונים לשימוש חוזר. +#### 1. **שינוי ארכיטקטורה של משך חיי אובייקטים** + **הפוך את GraphRag לבעל חיים ארוך**: העבר את המופע של GraphRag לרמה של המעבד לצורך שמירה בין בקשות + **שמור על מטמון**: שמור על מטמון תוויות, מטמון הטבעות ומטמון תוצאות שאילתה בין בקשות + **אופטימיזציה של אובייקט שאילתה**: שנה את מבנה אובייקט השאילתה כהקשר ביצוע קל משקל, ולא כמכל נתונים + **שמירה על חיבורים**: שמור על חיבורי לקוח למסד הנתונים בין בקשות -#### 2. טעינה ובקשה - - שאילתות יבוצעו בטעינה, המפחיתות את מספר השאילתות הכולל. + מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (עודכן) -#### 3. אחסון במטמון - - מטמון תגים ישמור תוצאות כדי לשפר את יעילות השאילתה. +#### 2. **מנוע מעבר גרפים מותאם** + החלף את `follow_edges` רקורסיבי בחיפוש רוחב-ראשוני איטרטיבי + הטמעת עיבוד אצווה של ישויות בכל רמת מעבר + הוסף זיהוי מעגלים באמצעות מעקב אחר צמתים מבקרים + כלול סיום מוקדם כאשר מגיעים למגבלות -#### 4. מדיניות - - מדיניות שאילתה תאפשר גבולות כדי לשפר את הביצועים. \ No newline at end of file + מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` + +#### 3. **מערכת פתרון תוויות מקבילה** + שאילתות תוויות באצווה עבור מספר ישויות בו-זמנית + הטמעת דפוסי async/await לגישה מקבילה למסד הנתונים + הוסף אחזור מוקדם לדפוסי תוויות נפוצים + כלול אסטרטגיות חימום מטמון תוויות + + מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` + +#### 4. **שכבת מטמון תוויות שמרנית** + מטמון LRU עם TTL קצר עבור תוויות בלבד (5 דקות) כדי לאזן בין ביצועים ועקביות + ניטור מדדי מטמון ויחס פגיעות + **ללא מטמון הטבעות**: כבר שמורים עבור כל שאילתה, אין יתרון בין שאילתות + **ללא מטמון תוצאות שאילתה**: עקב חששות לגבי עקביות שינוי גרף + + מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` + +#### 5. **מסגרת אופטימיזציה של שאילתות** + ניתוח אופטימיזציה של דפוסי שאילתות והצעות + מתאם שאילתות באצווה לגישה למסד הנתונים + ניהול בריכת חיבורים וזמן קצוב של שאילתות + ניטור ביצועים ואיסוף מדדים + + מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` + +### מודלים של נתונים + +#### מצב מעבר גרפים מותאם + +מנוע המעבר שומר על מצב כדי להימנע מפעולות מיותרות: + +```python +@dataclass +class TraversalState: + visited_entities: Set[str] + current_level_entities: Set[str] + next_level_entities: Set[str] + subgraph: Set[Tuple[str, str, str]] + depth: int + query_batch: List[TripleQuery] +``` + +גישה זו מאפשרת: +זיהוי יעיל של מעגלים באמצעות מעקב אחר ישויות שביקרו +הכנת שאילתות באצווה בכל רמת מעבר +ניהול מצב חסכוני בזיכרון +סיום מוקדם כאשר מגיעים למגבלות גודל + +#### מבנה מטמון משופר + +```python +@dataclass +class CacheEntry: + value: Any + timestamp: float + access_count: int + ttl: Optional[float] + +class CacheManager: + label_cache: LRUCache[str, CacheEntry] + embedding_cache: LRUCache[str, CacheEntry] + query_result_cache: LRUCache[str, CacheEntry] + cache_stats: CacheStatistics +``` + +#### מבני שאילתות אצווה + +```python +@dataclass +class BatchTripleQuery: + entities: List[str] + query_type: QueryType # SUBJECT, PREDICATE, OBJECT + limit_per_entity: int + +@dataclass +class BatchLabelQuery: + entities: List[str] + predicate: str = LABEL +``` + +### ממשקי API + +#### ממשקי API חדשים: + +**ממשק GraphTraversal API** +```python +async def optimized_follow_edges_batch( + entities: List[str], + max_depth: int, + triple_limit: int, + max_subgraph_size: int +) -> Set[Tuple[str, str, str]] +``` + +**ממשק API לפתרון תגיות אצווה** +```python +async def resolve_labels_batch( + entities: List[str], + cache_manager: CacheManager +) -> Dict[str, str] +``` + +**ממשק ניהול מטמון (Cache Management API)** +```python +class CacheManager: + async def get_or_fetch_label(self, entity: str) -> str + async def get_or_fetch_embeddings(self, query: str) -> List[float] + async def cache_query_result(self, query_hash: str, result: Any, ttl: int) + def get_cache_statistics(self) -> CacheStatistics +``` + +#### ממשקי API שעודכנו: + +**GraphRag.query()** - שופר עם אופטימיזציות ביצועים: +הוסף פרמטר cache_manager לשליטה על המטמון +הוסף ערך החזרה performance_metrics +הוסף פרמטר query_timeout לאמינות + +**מחלקה Query** - שופרה לעיבוד באצווה: +החלף עיבוד ישויות בודדות בפעולות באצווה +הוסף מנהלי הקשר אסינכרוניים לניקוי משאבים +הוסף פונקציות החזרה (callbacks) להתקדמות עבור פעולות ארוכות + +### פרטי יישום + +#### שלב 0: שינוי ארכיטקטורה קריטי + +**יישום בעייתי נוכחי:** +```python +# INEFFICIENT: GraphRag recreated every request +class Processor(FlowProcessor): + async def on_request(self, msg, consumer, flow): + # PROBLEM: New GraphRag instance per request! + self.rag = GraphRag( + embeddings_client = flow("embeddings-request"), + graph_embeddings_client = flow("graph-embeddings-request"), + triples_client = flow("triples-request"), + prompt_client = flow("prompt-request"), + verbose=True, + ) + # Cache starts empty every time - no benefit from previous requests + response = await self.rag.query(...) + +# VERY SHORT-LIVED: Query object created/destroyed per request +class GraphRag: + async def query(self, query, user="trustgraph", collection="default", ...): + q = Query(rag=self, user=user, collection=collection, ...) # Created + kg = await q.get_labelgraph(query) # Used briefly + # q automatically destroyed when function exits +``` + +**ארכיטקטורה ארוכת טווח ומותאמת:** +```python +class Processor(FlowProcessor): + def __init__(self, **params): + super().__init__(**params) + self.rag_instance = None # Will be initialized once + self.client_connections = {} + + async def initialize_rag(self, flow): + """Initialize GraphRag once, reuse for all requests""" + if self.rag_instance is None: + self.rag_instance = LongLivedGraphRag( + embeddings_client=flow("embeddings-request"), + graph_embeddings_client=flow("graph-embeddings-request"), + triples_client=flow("triples-request"), + prompt_client=flow("prompt-request"), + verbose=True, + ) + return self.rag_instance + + async def on_request(self, msg, consumer, flow): + # REUSE the same GraphRag instance - caches persist! + rag = await self.initialize_rag(flow) + + # Query object becomes lightweight execution context + response = await rag.query_with_context( + query=v.query, + execution_context=QueryContext( + user=v.user, + collection=v.collection, + entity_limit=entity_limit, + # ... other params + ) + ) + +class LongLivedGraphRag: + def __init__(self, ...): + # CONSERVATIVE caches - balance performance vs consistency + self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness + # Note: No embedding cache - already cached per-query, no cross-query benefit + # Note: No query result cache due to consistency concerns + self.performance_metrics = PerformanceTracker() + + async def query_with_context(self, query: str, context: QueryContext): + # Use lightweight QueryExecutor instead of heavyweight Query object + executor = QueryExecutor(self, context) # Minimal object + return await executor.execute(query) + +@dataclass +class QueryContext: + """Lightweight execution context - no heavy operations""" + user: str + collection: str + entity_limit: int + triple_limit: int + max_subgraph_size: int + max_path_length: int + +class QueryExecutor: + """Lightweight execution context - replaces old Query class""" + def __init__(self, rag: LongLivedGraphRag, context: QueryContext): + self.rag = rag + self.context = context + # No heavy initialization - just references + + async def execute(self, query: str): + # All heavy lifting uses persistent rag caches + return await self.rag.execute_optimized_query(query, self.context) +``` + +שינוי ארכיטקטורה זה מספק: +**הפחתת שאילתות מסד נתונים ב-10-20%** עבור גרפים עם קשרים נפוצים (בהשוואה ל-0% כיום) +**ביטול תקורה של יצירת אובייקטים** עבור כל בקשה +**בריכת חיבורים קבועה** ושימוש חוזר בלקוח +**אופטימיזציה בין בקשות** בתוך חלונות TTL של מטמון + +**מגבלה חשובה של עקביות מטמון:** +אחסון מטמון לטווח ארוך מכניס סיכון של מידע מיושן כאשר ישויות/תוויות נמחקים או משתנים בגרף הבסיסי. מטמון LRU עם TTL מספק איזון בין שיפורי ביצועים ורעננות נתונים, אך אינו יכול לזהות שינויים בזמן אמת בגרף. + +#### שלב 1: אופטימיזציה של מעבר גרפים + +**בעיות ביישום הנוכחי:** +```python +# INEFFICIENT: 3 queries per entity per level +async def follow_edges(self, ent, subgraph, path_length): + # Query 1: s=ent, p=None, o=None + res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit) + # Query 2: s=None, p=ent, o=None + res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit) + # Query 3: s=None, p=None, o=ent + res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit) +``` + +**יישום אופטימלי:** +```python +async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]: + visited = set() + current_level = set(entities) + subgraph = set() + + for depth in range(max_depth): + if not current_level or len(subgraph) >= self.max_subgraph_size: + break + + # Batch all queries for current level + batch_queries = [] + for entity in current_level: + if entity not in visited: + batch_queries.extend([ + TripleQuery(s=entity, p=None, o=None), + TripleQuery(s=None, p=entity, o=None), + TripleQuery(s=None, p=None, o=entity) + ]) + + # Execute all queries concurrently + results = await self.execute_batch_queries(batch_queries) + + # Process results and prepare next level + next_level = set() + for result in results: + subgraph.update(result.triples) + next_level.update(result.new_entities) + + visited.update(current_level) + current_level = next_level - visited + + return subgraph +``` + +#### שלב 2: פתרון מקבילי של תגיות + +**יישום סדרתי נוכחי:** +```python +# INEFFICIENT: Sequential processing +for edge in subgraph: + s = await self.maybe_label(edge[0]) # Individual query + p = await self.maybe_label(edge[1]) # Individual query + o = await self.maybe_label(edge[2]) # Individual query +``` + +**יישום מקבילי אופטימלי:** +```python +async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: + # Collect all unique entities needing labels + entities_to_resolve = set() + for s, p, o in subgraph: + entities_to_resolve.update([s, p, o]) + + # Remove already cached entities + uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache] + + # Batch query for all uncached labels + if uncached_entities: + label_results = await self.batch_label_query(uncached_entities) + self.label_cache.update(label_results) + + # Apply labels to subgraph + return [ + (self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o)) + for s, p, o in subgraph + ] +``` + +#### שלב 3: אסטרטגיית אחסון מטמון מתקדמת + +**מטמון LRU עם TTL:** +```python +class LRUCacheWithTTL: + def __init__(self, max_size: int, default_ttl: int = 3600): + self.cache = OrderedDict() + self.max_size = max_size + self.default_ttl = default_ttl + self.access_times = {} + + async def get(self, key: str) -> Optional[Any]: + if key in self.cache: + # Check TTL expiration + if time.time() - self.access_times[key] > self.default_ttl: + del self.cache[key] + del self.access_times[key] + return None + + # Move to end (most recently used) + self.cache.move_to_end(key) + return self.cache[key] + return None + + async def put(self, key: str, value: Any): + if key in self.cache: + self.cache.move_to_end(key) + else: + if len(self.cache) >= self.max_size: + # Remove least recently used + oldest_key = next(iter(self.cache)) + del self.cache[oldest_key] + del self.access_times[oldest_key] + + self.cache[key] = value + self.access_times[key] = time.time() +``` + +#### שלב 4: אופטימיזציה וניטור של שאילתות + +**איסוף מדדי ביצועים:** +```python +@dataclass +class PerformanceMetrics: + total_queries: int + cache_hits: int + cache_misses: int + avg_response_time: float + subgraph_construction_time: float + label_resolution_time: float + total_entities_processed: int + memory_usage_mb: float +``` + +**זמן תגובה מקסימלי ומנגנון ניתוב מחדש:** +```python +async def execute_with_timeout(self, query_func, timeout: int = 30): + try: + return await asyncio.wait_for(query_func(), timeout=timeout) + except asyncio.TimeoutError: + logger.error(f"Query timeout after {timeout}s") + raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s") +``` + +## שיקולים בנוגע לעקביות מטמון + +**פשרות בנוגע לרעננות נתונים:** +**מטמון תוויות (TTL של 5 דקות)**: סיכון להצגת תוויות של ישויות שנמחקו/ששמותיהן שונו. +**ללא שמירת מטמון של הטמעות (embeddings)**: לא נדרש - הטמעות כבר שמורות מטמון עבור כל שאילתה. +**ללא שמירת מטמון של תוצאות**: מונע קבלת תוצאות תת-גרף לא עדכניות מישויות/קשרים שנמחקו. + +**אסטרטגיות הפחתה:** +**ערכי TTL שמרניים**: איזון בין שיפורי ביצועים (10-20%) לבין רעננות נתונים. +**מנגנוני ביטול מטמון**: שילוב אופציונלי עם אירועי שינוי בגרף. +**לוחות מחוונים לניטור**: מעקב אחר אחוזי פגיעה במטמון (cache hit rates) לעומת מקרים של נתונים לא עדכניים. +**מדיניות מטמון הניתנות לתצורה**: אפשרות לכוונון פר-פריסה בהתאם לתדירות השינויים. + +**תצורת מטמון מומלצת בהתאם לקצב שינויים בגרף:** +**קצב שינויים גבוה (>100 שינויים/שעה)**: TTL=60 שניות, גדלי מטמון קטנים יותר. +**קצב שינויים בינוני (10-100 שינויים/שעה)**: TTL=300 שניות (ברירת מחדל). +**קצב שינויים נמוך (<10 שינויים/שעה)**: TTL=600 שניות, גדלי מטמון גדולים יותר. + +## שיקולים בנוגע לאבטחה + +**מניעת הזרקת שאילתות:** +אימות כל מזהי ישויות ופרמטרים של שאילתות. +שימוש בשאילתות מפורמטות עבור כל אינטראקציות עם מסד הנתונים. +יישום מגבלות על מורכבות השאילתות כדי למנוע התקפות מניעת שירות (DoS). + +**הגנה על משאבים:** +אכיפת מגבלות על גודל תת-גרף מקסימלי. +יישום זמני קצבה לשאילתות כדי למנוע מיצוי משאבים. +הוספת ניטור מגבלות לשימוש בזיכרון. + +**בקרת גישה:** +שמירה על בידוד משתמשים ואוספים קיימים. +הוספת רישום ביקורת עבור פעולות המשפיעות על הביצועים. +יישום הגבלת קצב עבור פעולות יקרות. + +## שיקולים בנוגע לביצועים + +### שיפורי ביצועים צפויים + +**הפחתת מספר שאילתות:** +נוכחי: ~9,000+ שאילתות עבור בקשה טיפוסית. +אופטימלי: ~50-100 שאילתות מקובצות (הפחתה של 98%). + +**שיפורי זמן תגובה:** +מעבר בגרף: 15-20 שניות → 3-5 שניות (מהיר פי 4-5). +פתרון תוויות: 8-12 שניות → 2-4 שניות (מהיר פי 3). +שאילתה כוללת: 25-35 שניות → 6-10 שניות (שיפור של פי 3-4). + +**יעילות זיכרון:** +גדלי מטמון מוגבלים מונעים דליפות זיכרון. +מבני נתונים יעילים מפחיתים את טביעת הרגל של הזיכרון בערך ב-40%. +איסוף אשפה טוב יותר באמצעות ניקוי משאבים נכון. + +**ציפיות ריאליות בנוגע לביצועים:** +**מטמון תוויות**: הפחתה של 10-20% במספר השאילתות עבור גרפים עם קשרים נפוצים. +**אופטימיזציה של קיבוץ**: הפחתה של 50-80% במספר השאילתות (אופטימיזציה עיקרית). +**אופטימיזציה של חיי אובייקט**: ביטול תקורה של יצירה מחדש בכל בקשה. +**שיפור כולל**: שיפור של פי 3-4 בזמן התגובה בעיקר בזכות קיבוץ. + +**שיפורי יכולת הרחבה:** +תמיכה בגרפי ידע גדולים פי 3-5 (מוגבל על ידי צרכי עקביות מטמון). +קיבולת גבוהה יותר פי 3-5 של בקשות מקבילות. +ניצול טוב יותר של משאבים באמצעות שימוש חוזר בחיבורים. + +### ניטור ביצועים + +**מדדים בזמן אמת:** +זמני ביצוע שאילתות לפי סוג פעולה. +אחוזי פגיעה במטמון ויעילות. +שימוש בבריכת חיבורים למסד הנתונים. +שימוש בזיכרון והשפעת איסוף אשפה. + +**בדיקות ביצועים:** +בדיקות רגרסיה אוטומטיות לביצועים +בדיקות עומסים עם נפחי נתונים ריאליים +השוואות ביצועים מול המימוש הנוכחי + +## אסטרטגיית בדיקות + +### בדיקות יחידה +בדיקת רכיבים בודדים עבור מעבר, אחסון במטמון ופתרון תגיות +הדמיית אינטראקציות עם מסד נתונים לצורך בדיקות ביצועים +בדיקת פינוי מטמון ותפוגה של זמן תפוגה (TTL) +בדיקת טיפול בשגיאות ותסריטי תזמון + +### בדיקות אינטגרציה +בדיקות מקצה לקצה של שאילתות GraphRAG עם אופטימיזציות +בדיקת אינטראקציות עם מסד נתונים עם נתונים אמיתיים +טיפול בבקשות מקבילות וניהול משאבים +זיהוי דליפות זיכרון ואימות ניקוי משאבים + +### בדיקות ביצועים +בדיקות ביצועים מול המימוש הנוכחי +בדיקות עומסים עם גדלים ומורכבויות גרף משתנים +בדיקות לחץ עבור מגבלות זיכרון וחיבורים +בדיקות רגרסיה לשיפורי ביצועים + +### בדיקות תאימות +אימות תאימות של ממשקי API קיימים של GraphRAG +בדיקה עם מנועי גרפים שונים +אימות דיוק התוצאות בהשוואה למימוש הנוכחי + +## תוכנית יישום + +### גישת יישום ישירה +מכיוון שמותר לשנות ממשקי API, ליישם אופטימיזציות ישירות ללא מורכבות של העברה: + +1. **החלפת `follow_edges`:** כתיבה מחדש עם מעבר אצווה איטרטיבי +2. **אופטימיזציה של `get_labelgraph`:** יישום פתרון תגיות מקבילי +3. **הוספת GraphRag ארוך טווח:** שינוי של מעבד כדי לשמור על מופע קבוע +4. **יישום אחסון במטמון של תגיות:** הוספת מטמון LRU עם TTL למחלקת GraphRag + +### היקף השינויים +**מחלקה של שאילתות:** החלפת כ-50 שורות ב-`follow_edges`, הוספת כ-30 שורות לטיפול באצווה +**מחלקה של GraphRag:** הוספת שכבת אחסון במטמון (כ-40 שורות) +**מחלקה של מעבד:** שינוי לשימוש במופע קבוע של GraphRag (כ-20 שורות) +**סה"כ:** כ-140 שורות של שינויים ממוקדים, בעיקר בתוך מחלקות קיימות + +## ציר זמן + +**שבוע 1: יישום ליבה** +החלפת `follow_edges` עם מעבר אצווה איטרטיבי +יישום פתרון תגיות מקבילי ב-`get_labelgraph` +הוספת מופע GraphRag ארוך טווח למעבד +יישום שכבת אחסון במטמון של תגיות + +**שבוע 2: בדיקות ושילוב** +בדיקות יחידה ללוגיקה חדשה של מעבר ואחסון במטמון +בדיקות ביצועים מול המימוש הנוכחי +בדיקות אינטגרציה עם נתוני גרף אמיתיים +סקירת קוד ואופטימיזציה + +**שבוע 3: פריסה** +פריסת המימוש המותאם +ניטור שיפורי ביצועים +כוונון עדין של זמן תפוגה של מטמון וגדלי אצווה בהתבסס על שימוש אמיתי + +## שאלות פתוחות + +**בריכת חיבורים למסד נתונים:** האם עלינו ליישם בריכת חיבורים מותאמת אישית או להסתמך על בריכת חיבורים קיימת של לקוח מסד נתונים? +**שימור מטמון:** האם מטמון התגיות וההטבעות צריך להתמיד בין הפעלות מחדש של השירות? +**אחסון במטמון מבוזר:** עבור פריסות מרובות מופעים, האם עלינו ליישם אחסון במטמון מבוזר עם Redis/Memcached? +**פורמט תוצאות שאילתה:** האם עלינו לייעל את הייצוג הפנימי של משולש לטובת יעילות זיכרון טובה יותר? +**שילוב ניטור:** אילו מדדים יש לחשוף למערכות ניטור קיימות (Prometheus, וכו')? + +## הפניות + +[מימוש מקורי של GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +[עקרונות ארכיטקטורה של TrustGraph](architecture-principles.md) +[מפרט ניהול אוספים](collection-management.md) diff --git a/docs/tech-specs/graphrag-performance-optimization.hi.md b/docs/tech-specs/graphrag-performance-optimization.hi.md index cccdcd26..9830dd9b 100644 --- a/docs/tech-specs/graphrag-performance-optimization.hi.md +++ b/docs/tech-specs/graphrag-performance-optimization.hi.md @@ -2,125 +2,125 @@ ## अवलोकन -यह विनिर्देश ट्रस्टग्राफ में ग्राफआरएजी (ग्राफ रिट्रीवल-ऑगमेंटेड जनरेशन) एल्गोरिथ्म के लिए व्यापक प्रदर्शन अनुकूलन का वर्णन करता है। वर्तमान कार्यान्वयन महत्वपूर्ण प्रदर्शन बाधाओं से ग्रस्त है जो स्केलेबिलिटी और प्रतिक्रिया समय को सीमित करते हैं। यह विनिर्देश चार प्राथमिक अनुकूलन क्षेत्रों को संबोधित करता है: +यह विनिर्देश ट्रस्टग्राफ में ग्राफआरएजी (ग्राफ रिट्रीवल-ऑगमेंटेड जनरेशन) एल्गोरिदम के लिए व्यापक प्रदर्शन अनुकूलन का वर्णन करता है। वर्तमान कार्यान्वयन में महत्वपूर्ण प्रदर्शन बाधाएं हैं जो स्केलेबिलिटी और प्रतिक्रिया समय को सीमित करती हैं। यह विनिर्देश चार प्राथमिक अनुकूलन क्षेत्रों को संबोधित करता है: -1. **ग्राफ ट्रैवर्सल अनुकूलन**: अक्षम पुनरावर्ती डेटाबेस प्रश्नों को समाप्त करें और बैच किए गए ग्राफ अन्वेषण को लागू करें। -2. **लेबल रिज़ॉल्यूशन अनुकूलन**: अनुक्रमिक लेबल पुनर्प्राप्ति को समानांतर/बैच संचालन से बदलें। -3. **कैशिंग रणनीति में सुधार**: एलआरयू निष्कासन और पूर्व-भार के साथ बुद्धिमान कैशिंग लागू करें। -4. **क्वेरी अनुकूलन**: बेहतर प्रतिक्रिया समय के लिए परिणाम मेमोइजेशन और एम्बेडिंग कैशिंग जोड़ें। +1. **ग्राफ ट्रैवर्सल अनुकूलन**: अक्षम पुनरावर्ती डेटाबेस प्रश्नों को समाप्त करें और बैच में ग्राफ अन्वेषण लागू करें। +2. **लेबल रिज़ॉल्यूशन अनुकूलन**: क्रमिक लेबल फ़ेचिंग को समानांतर/बैच संचालन से बदलें। +3. **कैशिंग रणनीति में सुधार**: एलआरयू निष्कासन और प्रीफ़ेचिंग के साथ बुद्धिमान कैशिंग लागू करें। +4. **क्वेरी अनुकूलन**: बेहतर प्रतिक्रिया समय के लिए परिणाम मेमोइज़ेशन और एम्बेडिंग कैशिंग जोड़ें। ## लक्ष्य -- **डेटाबेस क्वेरी की मात्रा को कम करें**: बैचिंग और कैशिंग के माध्यम से कुल डेटाबेस क्वेरी में 50-80% की कमी प्राप्त करें। -- **प्रतिक्रिया समय में सुधार**: उपग्राफ निर्माण में 3-5 गुना तेजी और लेबल रिज़ॉल्यूशन में 2-3 गुना तेजी लाने का लक्ष्य रखें। -- **स्केलेबिलिटी में वृद्धि**: बेहतर मेमोरी प्रबंधन के साथ बड़े नॉलेज ग्राफ का समर्थन करें। -- **सटीकता बनाए रखें**: मौजूदा ग्राफआरएजी कार्यक्षमता और परिणाम गुणवत्ता को संरक्षित करें। -- **समवर्ती को सक्षम करें**: एकाधिक समवर्ती अनुरोधों के लिए समानांतर प्रसंस्करण क्षमताओं में सुधार करें। -- **मेमोरी पदचिह्न को कम करें**: कुशल डेटा संरचनाओं और मेमोरी प्रबंधन को लागू करें। -- **अवलोकनशीलता जोड़ें**: प्रदर्शन मेट्रिक्स और निगरानी क्षमताओं को शामिल करें। -- **विश्वसनीयता सुनिश्चित करें**: उचित त्रुटि प्रबंधन और टाइमआउट तंत्र जोड़ें। +**डेटाबेस क्वेरी की मात्रा को कम करें**: बैचिंग और कैशिंग के माध्यम से कुल डेटाबेस प्रश्नों में 50-80% की कमी प्राप्त करें। +**प्रतिक्रिया समय में सुधार**: सबग्राफ निर्माण और लेबल रिज़ॉल्यूशन में 3-5 गुना तेजी और 2-3 गुना तेजी लाने का लक्ष्य रखें। +**स्केलेबिलिटी में वृद्धि**: बेहतर मेमोरी प्रबंधन के साथ बड़े नॉलेज ग्राफ का समर्थन करें। +**सटीकता बनाए रखें**: मौजूदा ग्राफआरएजी कार्यक्षमता और परिणाम गुणवत्ता को संरक्षित करें। +**समवर्तीता सक्षम करें**: एकाधिक समवर्ती अनुरोधों के लिए समानांतर प्रसंस्करण क्षमताओं में सुधार करें। +**मेमोरी पदचिह्न को कम करें**: कुशल डेटा संरचनाओं और मेमोरी प्रबंधन को लागू करें। +**अवलोकनशीलता जोड़ें**: प्रदर्शन मेट्रिक्स और निगरानी क्षमताओं को शामिल करें। +**विश्वसनीयता सुनिश्चित करें**: उचित त्रुटि हैंडलिंग और टाइमआउट तंत्र जोड़ें। ## पृष्ठभूमि -`trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` में वर्तमान ग्राफआरएजी कार्यान्वयन में कई महत्वपूर्ण प्रदर्शन संबंधी समस्याएं हैं जो सिस्टम स्केलेबिलिटी को गंभीर रूप से प्रभावित करती हैं: +`trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` में वर्तमान ग्राफआरएजी कार्यान्वयन में कई महत्वपूर्ण प्रदर्शन मुद्दे हैं जो सिस्टम स्केलेबिलिटी को गंभीर रूप से प्रभावित करते हैं: ### वर्तमान प्रदर्शन समस्याएं **1. अक्षम ग्राफ ट्रैवर्सल (`follow_edges` फ़ंक्शन, लाइनें 79-127)** -- प्रति इकाई प्रति गहराई स्तर पर 3 अलग डेटाबेस क्वेरी करता है। -- क्वेरी पैटर्न: प्रत्येक इकाई के लिए विषय-आधारित, विधेय-आधारित और वस्तु-आधारित क्वेरी। -- कोई बैचिंग नहीं: प्रत्येक क्वेरी एक बार में केवल एक इकाई को संसाधित करती है। -- कोई चक्र का पता नहीं: एक ही नोड्स को कई बार पुनः देख सकता है। -- मेमोइजेशन के बिना पुनरावर्ती कार्यान्वयन घातीय जटिलता की ओर ले जाता है। -- समय जटिलता: O(entities × max_path_length × triple_limit³) +प्रत्येक इकाई प्रति गहराई स्तर के लिए 3 अलग-अलग डेटाबेस क्वेरी करता है। +क्वेरी पैटर्न: प्रत्येक इकाई के लिए विषय-आधारित, विधेय-आधारित और ऑब्जेक्ट-आधारित क्वेरी। +कोई बैचिंग नहीं: प्रत्येक क्वेरी एक समय में केवल एक इकाई को संसाधित करती है। +कोई चक्र का पता नहीं: समान नोड्स को कई बार फिर से देख सकता है। +मेमोइज़ेशन के बिना पुनरावर्ती कार्यान्वयन घातीय जटिलता की ओर ले जाता है। +समय जटिलता: O(entities × max_path_length × triple_limit³) -**2. अनुक्रमिक लेबल रिज़ॉल्यूशन (`get_labelgraph` फ़ंक्शन, लाइनें 144-171)** -- प्रत्येक ट्रिपल घटक (विषय, विधेय, वस्तु) को क्रमिक रूप से संसाधित करता है। -- प्रत्येक `maybe_label` कॉल संभावित रूप से एक डेटाबेस क्वेरी को ट्रिगर करता है। -- लेबल क्वेरी का कोई समानांतर निष्पादन या बैचिंग नहीं। -- प्रति उपग्राफ आकार में 3 अलग डेटाबेस कॉल होते हैं। +**2. क्रमिक लेबल रिज़ॉल्यूशन (`get_labelgraph` फ़ंक्शन, लाइनें 144-171)** +प्रत्येक ट्रिपल घटक (विषय, विधेय, ऑब्जेक्ट) को क्रमिक रूप से संसाधित करता है। +प्रत्येक `maybe_label` कॉल संभावित रूप से एक डेटाबेस क्वेरी को ट्रिगर करता है। +लेबल क्वेरी के समानांतर निष्पादन या बैचिंग नहीं। +परिणाम में subgraph_size × 3 व्यक्तिगत डेटाबेस कॉल होते हैं। **3. आदिम कैशिंग रणनीति (`maybe_label` फ़ंक्शन, लाइनें 62-77)** -- बिना आकार सीमा या टीटीएल के सरल शब्दकोश कैश। -- कोई कैश निष्कासन नीति नहीं है, जिससे असीमित मेमोरी वृद्धि होती है। -- कैश मिस व्यक्तिगत डेटाबेस क्वेरी को ट्रिगर करते हैं। -- कोई पूर्व-भार या बुद्धिमान कैश वार्मिंग नहीं है। +आकार सीमा या टीटीएल के बिना एक साधारण शब्दकोश कैश। +कोई कैश निष्कासन नीति नहीं जिसके परिणामस्वरूप असीमित मेमोरी वृद्धि होती है। +कैश मिस व्यक्तिगत डेटाबेस क्वेरी को ट्रिगर करते हैं। +कोई प्रीफ़ेचिंग या बुद्धिमान कैश वार्मिंग नहीं। **4. उप-इष्टतम क्वेरी पैटर्न** -- समान अनुरोधों के बीच इकाई वेक्टर समानता क्वेरी का कैश नहीं किया जाता है। -- दोहराए गए क्वेरी पैटर्न के लिए कोई परिणाम मेमोइजेशन नहीं है। -- सामान्य एक्सेस पैटर्न के लिए क्वेरी अनुकूलन गायब है। +समान अनुरोधों के बीच इकाई वेक्टर समानता क्वेरी कैश नहीं की जाती हैं। +दोहराए गए क्वेरी पैटर्न के लिए कोई परिणाम मेमोइज़ेशन नहीं। +सामान्य एक्सेस पैटर्न के लिए कोई क्वेरी अनुकूलन नहीं। **5. महत्वपूर्ण ऑब्जेक्ट लाइफटाइम मुद्दे (`rag.py:96-102`)** -- **प्रत्येक अनुरोध के लिए GraphRag ऑब्जेक्ट फिर से बनाया गया**: प्रत्येक क्वेरी के लिए एक नया उदाहरण बनाया जाता है, जिससे सभी कैश लाभ खो जाते हैं। -- **क्वेरी ऑब्जेक्ट बहुत कम समय तक जीवित रहता है**: एक ही क्वेरी निष्पादन के भीतर बनाया और नष्ट किया जाता है (लाइनें 201-207)। -- **प्रत्येक अनुरोध के लिए लेबल कैश रीसेट किया जाता है**: कैश वार्मिंग और संचित ज्ञान अनुरोधों के बीच खो जाता है। -- **क्लाइंट पुनर्निर्माण ओवरहेड**: प्रत्येक अनुरोध के लिए डेटाबेस क्लाइंट संभावित रूप से फिर से स्थापित किए जाते हैं। -- **कोई क्रॉस-अनुरोध अनुकूलन नहीं**: क्वेरी पैटर्न या परिणाम साझाकरण से लाभ नहीं हो सकता है। +**प्रत्येक अनुरोध के लिए GraphRag ऑब्जेक्ट फिर से बनाया गया**: प्रत्येक क्वेरी के लिए एक नया उदाहरण बनाया जाता है, जिससे सभी कैश लाभ खो जाते हैं। +**क्वेरी ऑब्जेक्ट बहुत कम समय तक रहता है**: एकल क्वेरी निष्पादन के भीतर बनाया और नष्ट किया जाता है (लाइनें 201-207)। +**प्रत्येक अनुरोध के लिए लेबल कैश रीसेट**: कैश वार्मिंग और संचित ज्ञान के बीच खो जाता है। +**क्लाइंट पुन: निर्माण ओवरहेड**: प्रत्येक अनुरोध के लिए डेटाबेस क्लाइंट संभावित रूप से फिर से स्थापित होते हैं। +**क्रॉस-रिक्वेस्ट अनुकूलन नहीं**: क्वेरी पैटर्न या परिणाम साझाकरण से लाभ नहीं उठाया जा सकता है। ### प्रदर्शन प्रभाव विश्लेषण एक विशिष्ट क्वेरी के लिए वर्तमान सबसे खराब स्थिति परिदृश्य: -- **इकाई पुनर्प्राप्ति**: 1 वेक्टर समानता क्वेरी -- **ग्राफ ट्रैवर्सल**: entities × max_path_length × 3 × triple_limit क्वेरी -- **लेबल रिज़ॉल्यूशन**: subgraph_size × 3 व्यक्तिगत लेबल क्वेरी +**इकाई पुनर्प्राप्ति**: 1 वेक्टर समानता क्वेरी +**ग्राफ ट्रैवर्सल**: entities × max_path_length × 3 × triple_limit क्वेरी +**लेबल रिज़ॉल्यूशन**: subgraph_size × 3 व्यक्तिगत लेबल क्वेरी -डिफ़ॉल्ट मापदंडों के लिए (50 इकाइयां, पथ लंबाई 2, 30 ट्रिपल सीमा, 150 उपग्राफ आकार): -- **न्यूनतम क्वेरी**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 डेटाबेस क्वेरी** -- **प्रतिक्रिया समय**: मध्यम आकार के ग्राफ के लिए 15-30 सेकंड -- **मेमोरी उपयोग**: समय के साथ असीमित कैश वृद्धि -- **कैश प्रभावशीलता**: 0% - प्रत्येक अनुरोध पर कैश रीसेट होते हैं -- **ऑब्जेक्ट निर्माण ओवरहेड**: GraphRag + Query ऑब्जेक्ट प्रति अनुरोध बनाए जाते हैं/नष्ट किए जाते हैं +डिफ़ॉल्ट मापदंडों के लिए (50 एंटिटीज, पथ लंबाई 2, 30 ट्रिपल सीमा, 150 सबग्राफ आकार): +**न्यूनतम क्वेरीज़**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 डेटाबेस क्वेरीज़** +**प्रतिक्रिया समय**: मध्यम आकार के ग्राफ़ के लिए 15-30 सेकंड +**मेमोरी उपयोग**: समय के साथ असीमित कैश वृद्धि +**कैश प्रभावशीलता**: 0% - प्रत्येक अनुरोध पर कैश रीसेट हो जाते हैं +**ऑब्जेक्ट निर्माण ओवरहेड**: प्रति अनुरोध बनाए गए/विनाशित GraphRag + Query ऑब्जेक्ट -यह विनिर्देश बैच किए गए प्रश्नों, बुद्धिमान कैशिंग और समानांतर प्रसंस्करण को लागू करके इन कमियों को संबोधित करता है। क्वेरी पैटर्न और डेटा एक्सेस को अनुकूलित करके, ट्रस्टग्राफ: -- लाखों इकाइयों के साथ उद्यम-स्तरीय नॉलेज ग्राफ का समर्थन कर सकता है। -- विशिष्ट क्वेरी के लिए उप-सेकंड प्रतिक्रिया समय प्रदान कर सकता है। -- सैकड़ों समवर्ती GraphRAG अनुरोधों को संभाल सकता है। -- ग्राफ आकार और जटिलता के साथ कुशलतापूर्वक स्केल कर सकता है। +यह विनिर्देश इन कमियों को बैच क्वेरी, बुद्धिमान कैशिंग और समानांतर प्रसंस्करण को लागू करके संबोधित करता है। क्वेरी पैटर्न और डेटा एक्सेस को अनुकूलित करके, TrustGraph निम्न कार्य कर सकता है: +लाखों एंटिटीज वाले एंटरप्राइज-स्केल नॉलेज ग्राफ़ का समर्थन करें +विशिष्ट क्वेरीज़ के लिए उप-सेकंड प्रतिक्रिया समय प्रदान करें +सैकड़ों समवर्ती GraphRAG अनुरोधों को संभालें +ग्राफ के आकार और जटिलता के साथ कुशलतापूर्वक स्केल करें -## तकनीकी डिजाइन +## तकनीकी डिज़ाइन ### आर्किटेक्चर -ग्राफआरएजी प्रदर्शन अनुकूलन के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: +GraphRAG प्रदर्शन अनुकूलन के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: #### 1. **ऑब्जेक्ट लाइफटाइम आर्किटेक्चरल रीफैक्टर** - - **GraphRag को लंबे समय तक चलने वाला बनाएं**: GraphRag उदाहरण को प्रोसेसर स्तर पर लगातार रहने के लिए स्थानांतरित करें। - - **कैश को संरक्षित करें**: अनुरोधों के बीच लेबल कैश, एम्बेडिंग कैश और क्वेरी परिणाम कैश बनाए रखें। - - **क्वेरी ऑब्जेक्ट को अनुकूलित करें**: क्वेरी को एक हल्के निष्पादन संदर्भ, डेटा कंटेनर के रूप में रीफैक्टर करें। - - **कनेक्शन दृढ़ता**: अनुरोधों में डेटाबेस क्लाइंट कनेक्शन बनाए रखें। + **GraphRag को लंबे समय तक चलने वाला बनाएं**: GraphRag इंस्टेंस को प्रोसेसर स्तर पर ले जाएं ताकि यह अनुरोधों के बीच बना रहे + **कैश बनाए रखें**: लेबल कैश, एम्बेडिंग कैश और क्वेरी परिणाम कैश को अनुरोधों के बीच बनाए रखें + **क्वेरी ऑब्जेक्ट को अनुकूलित करें**: Query को एक हल्के निष्पादन संदर्भ के रूप में रीफैक्टर करें, डेटा कंटेनर के रूप में नहीं + **कनेक्शन दृढ़ता**: डेटाबेस क्लाइंट कनेक्शन को अनुरोधों के बीच बनाए रखें मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (संशोधित) #### 2. **अनुकूलित ग्राफ ट्रैवर्सल इंजन** - - पुनरावर्ती `follow_edges` को पुनरावृत्त चौड़ाई-पहली खोज से बदलें। - - प्रत्येक ट्रैवर्सल स्तर पर बैच किए गए इकाई प्रसंस्करण को लागू करें। - - देखे गए नोड ट्रैकिंग का उपयोग करके चक्र का पता लगाएं। - - सीमाओं तक पहुंचने पर प्रारंभिक समाप्ति शामिल करें। + पुनरावर्ती `follow_edges` को पुनरावृत्त चौड़ाई-पहली खोज से बदलें + प्रत्येक ट्रैवर्सल स्तर पर बैच एंटिटी प्रोसेसिंग लागू करें + देखे गए नोड ट्रैकिंग का उपयोग करके चक्र का पता लगाएं + सीमाओं तक पहुंचने पर प्रारंभिक समाप्ति शामिल करें मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` #### 3. **समानांतर लेबल रिज़ॉल्यूशन सिस्टम** - - एक साथ कई इकाइयों के लिए लेबल क्वेरी को बैच करें। - - समवर्ती डेटाबेस एक्सेस के लिए एसिंक्रोनस/अवेट पैटर्न लागू करें। - - सामान्य लेबल पैटर्न के लिए बुद्धिमान पूर्व-भार जोड़ें। - - लेबल कैश वार्मिंग रणनीतियों को शामिल करें। + एक साथ कई एंटिटीज के लिए लेबल क्वेरीज़ को बैच करें + समवर्ती डेटाबेस एक्सेस के लिए एसिंक्रोनस/अवेट पैटर्न लागू करें + सामान्य लेबल पैटर्न के लिए बुद्धिमान प्रीफ़ेटिंग जोड़ें + लेबल कैश वार्मिंग रणनीतियों शामिल करें मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` -#### 4. **रूढ़िवादी लेबल कैशिंग परत** - - प्रदर्शन बनाम स्थिरता को संतुलित करने के लिए केवल लेबल के लिए एलआरयू कैश (5 मिनट) के साथ छोटा टीटीएल। - - कैश मेट्रिक्स और हिट अनुपात निगरानी। - - **कोई एम्बेडिंग कैशिंग नहीं**: पहले से ही प्रति-क्वेरी कैश किया गया, कोई क्रॉस-क्वेरी लाभ नहीं। - - **कोई क्वेरी परिणाम कैशिंग नहीं**: ग्राफ परिवर्तन स्थिरता संबंधी चिंताओं के कारण। +#### 4. **रूढ़िवादी लेबल कैशिंग लेयर** + प्रदर्शन बनाम स्थिरता को संतुलित करने के लिए केवल लेबल के लिए लघु TTL के साथ LRU कैश (5 मिनट) + कैश मेट्रिक्स और हिट अनुपात निगरानी + **कोई एम्बेडिंग कैशिंग नहीं**: पहले से ही प्रति-क्वेरी कैश किया गया है, कोई क्रॉस-क्वेरी लाभ नहीं + **कोई क्वेरी परिणाम कैशिंग नहीं**: ग्राफ परिवर्तन स्थिरता संबंधी चिंताओं के कारण मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` #### 5. **क्वेरी अनुकूलन ढांचा** - - क्वेरी पैटर्न विश्लेषण और अनुकूलन सुझाव। - - डेटाबेस एक्सेस के लिए बैच क्वेरी समन्वयक। - - कनेक्शन पूलिंग और क्वेरी टाइमआउट प्रबंधन। - - प्रदर्शन निगरानी और मेट्रिक्स संग्रह। + क्वेरी पैटर्न विश्लेषण और अनुकूलन सुझाव + डेटाबेस एक्सेस के लिए बैच क्वेरी समन्वयक + कनेक्शन पूलिंग और क्वेरी टाइमआउट प्रबंधन + प्रदर्शन निगरानी और मेट्रिक्स संग्रह मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` @@ -128,7 +128,7 @@ #### अनुकूलित ग्राफ ट्रैवर्सल स्थिति -ट्रैवर्सल इंजन अनावश्यक संचालन से बचने के लिए स्थिति बनाए रखता है: +ट्रैवर्सल इंजन अनावश्यक कार्यों से बचने के लिए स्थिति बनाए रखता है: ```python @dataclass @@ -141,4 +141,489 @@ class TraversalState: query_batch: List[TripleQuery] ``` -#### \ No newline at end of file +यह दृष्टिकोण निम्नलिखित सुविधाएँ प्रदान करता है: +विज़िट किए गए एंटिटी को ट्रैक करके कुशल चक्र का पता लगाना +प्रत्येक ट्रैवर्सल स्तर पर बैच में क्वेरी तैयार करना +मेमोरी-कुशल स्थिति प्रबंधन +जब आकार की सीमाएँ पूरी हो जाती हैं तो प्रारंभिक समाप्ति + +#### बेहतर कैश संरचना + +```python +@dataclass +class CacheEntry: + value: Any + timestamp: float + access_count: int + ttl: Optional[float] + +class CacheManager: + label_cache: LRUCache[str, CacheEntry] + embedding_cache: LRUCache[str, CacheEntry] + query_result_cache: LRUCache[str, CacheEntry] + cache_stats: CacheStatistics +``` + +#### बैच क्वेरी संरचनाएं + +```python +@dataclass +class BatchTripleQuery: + entities: List[str] + query_type: QueryType # SUBJECT, PREDICATE, OBJECT + limit_per_entity: int + +@dataclass +class BatchLabelQuery: + entities: List[str] + predicate: str = LABEL +``` + +### एपीआई (APIs) + +#### नए एपीआई (New APIs): + +**ग्राफ ट्रावर्सल एपीआई (GraphTraversal API)** +```python +async def optimized_follow_edges_batch( + entities: List[str], + max_depth: int, + triple_limit: int, + max_subgraph_size: int +) -> Set[Tuple[str, str, str]] +``` + +**बैच लेबल रिज़ॉल्यूशन एपीआई** +```python +async def resolve_labels_batch( + entities: List[str], + cache_manager: CacheManager +) -> Dict[str, str] +``` + +**कैश प्रबंधन एपीआई** +```python +class CacheManager: + async def get_or_fetch_label(self, entity: str) -> str + async def get_or_fetch_embeddings(self, query: str) -> List[float] + async def cache_query_result(self, query_hash: str, result: Any, ttl: int) + def get_cache_statistics(self) -> CacheStatistics +``` + +#### संशोधित एपीआई: + +**GraphRag.query()** - प्रदर्शन अनुकूलन के साथ बेहतर: +कैश नियंत्रण के लिए `cache_manager` पैरामीटर जोड़ें +`performance_metrics` रिटर्न वैल्यू शामिल करें +विश्वसनीयता के लिए `query_timeout` पैरामीटर जोड़ें + +**क्वेरी क्लास** - बैच प्रोसेसिंग के लिए पुनर्गठित: +व्यक्तिगत इकाई प्रसंस्करण को बैच ऑपरेशनों से बदलें +संसाधन सफाई के लिए एसिंक्रोनस कॉन्टेक्स्ट मैनेजर जोड़ें +लंबे समय तक चलने वाले ऑपरेशनों के लिए प्रगति कॉलबैक शामिल करें + +### कार्यान्वयन विवरण + +#### चरण 0: महत्वपूर्ण आर्किटेक्चरल लाइफटाइम रिफैक्टर + +**वर्तमान समस्याग्रस्त कार्यान्वयन:** +```python +# INEFFICIENT: GraphRag recreated every request +class Processor(FlowProcessor): + async def on_request(self, msg, consumer, flow): + # PROBLEM: New GraphRag instance per request! + self.rag = GraphRag( + embeddings_client = flow("embeddings-request"), + graph_embeddings_client = flow("graph-embeddings-request"), + triples_client = flow("triples-request"), + prompt_client = flow("prompt-request"), + verbose=True, + ) + # Cache starts empty every time - no benefit from previous requests + response = await self.rag.query(...) + +# VERY SHORT-LIVED: Query object created/destroyed per request +class GraphRag: + async def query(self, query, user="trustgraph", collection="default", ...): + q = Query(rag=self, user=user, collection=collection, ...) # Created + kg = await q.get_labelgraph(query) # Used briefly + # q automatically destroyed when function exits +``` + +**अनुकूलित, दीर्घकालिक संरचना:** +```python +class Processor(FlowProcessor): + def __init__(self, **params): + super().__init__(**params) + self.rag_instance = None # Will be initialized once + self.client_connections = {} + + async def initialize_rag(self, flow): + """Initialize GraphRag once, reuse for all requests""" + if self.rag_instance is None: + self.rag_instance = LongLivedGraphRag( + embeddings_client=flow("embeddings-request"), + graph_embeddings_client=flow("graph-embeddings-request"), + triples_client=flow("triples-request"), + prompt_client=flow("prompt-request"), + verbose=True, + ) + return self.rag_instance + + async def on_request(self, msg, consumer, flow): + # REUSE the same GraphRag instance - caches persist! + rag = await self.initialize_rag(flow) + + # Query object becomes lightweight execution context + response = await rag.query_with_context( + query=v.query, + execution_context=QueryContext( + user=v.user, + collection=v.collection, + entity_limit=entity_limit, + # ... other params + ) + ) + +class LongLivedGraphRag: + def __init__(self, ...): + # CONSERVATIVE caches - balance performance vs consistency + self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness + # Note: No embedding cache - already cached per-query, no cross-query benefit + # Note: No query result cache due to consistency concerns + self.performance_metrics = PerformanceTracker() + + async def query_with_context(self, query: str, context: QueryContext): + # Use lightweight QueryExecutor instead of heavyweight Query object + executor = QueryExecutor(self, context) # Minimal object + return await executor.execute(query) + +@dataclass +class QueryContext: + """Lightweight execution context - no heavy operations""" + user: str + collection: str + entity_limit: int + triple_limit: int + max_subgraph_size: int + max_path_length: int + +class QueryExecutor: + """Lightweight execution context - replaces old Query class""" + def __init__(self, rag: LongLivedGraphRag, context: QueryContext): + self.rag = rag + self.context = context + # No heavy initialization - just references + + async def execute(self, query: str): + # All heavy lifting uses persistent rag caches + return await self.rag.execute_optimized_query(query, self.context) +``` + +यह वास्तुशिल्पीय परिवर्तन निम्नलिखित सुविधाएँ प्रदान करता है: +**सामान्य संबंधों वाले ग्राफों के लिए डेटाबेस क्वेरी में 10-20% की कमी** (वर्तमान में 0% की तुलना में) +प्रत्येक अनुरोध के लिए **ऑब्जेक्ट निर्माण ओवरहेड को समाप्त करना** +**स्थायी कनेक्शन पूलिंग** और क्लाइंट पुन: उपयोग +**कैश टीटीएल विंडो के भीतर क्रॉस-अनुरोध अनुकूलन** + +**महत्वपूर्ण कैश स्थिरता सीमा:** +दीर्घकालिक कैशिंग से अप्रचलन का जोखिम होता है जब अंतर्निहित ग्राफ में एंटिटीज/लेबल हटा दिए जाते हैं या संशोधित किए जाते हैं। एलआरयू कैश जिसमें टीटीएल है, प्रदर्शन लाभ और डेटा ताज़गी के बीच संतुलन प्रदान करता है, लेकिन यह वास्तविक समय में ग्राफ परिवर्तनों का पता नहीं लगा सकता है। + +#### चरण 1: ग्राफ ट्रैवर्सल अनुकूलन + +**वर्तमान कार्यान्वयन समस्याएं:** +```python +# INEFFICIENT: 3 queries per entity per level +async def follow_edges(self, ent, subgraph, path_length): + # Query 1: s=ent, p=None, o=None + res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit) + # Query 2: s=None, p=ent, o=None + res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit) + # Query 3: s=None, p=None, o=ent + res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit) +``` + +**अनुकूलित कार्यान्वयन:** +```python +async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]: + visited = set() + current_level = set(entities) + subgraph = set() + + for depth in range(max_depth): + if not current_level or len(subgraph) >= self.max_subgraph_size: + break + + # Batch all queries for current level + batch_queries = [] + for entity in current_level: + if entity not in visited: + batch_queries.extend([ + TripleQuery(s=entity, p=None, o=None), + TripleQuery(s=None, p=entity, o=None), + TripleQuery(s=None, p=None, o=entity) + ]) + + # Execute all queries concurrently + results = await self.execute_batch_queries(batch_queries) + + # Process results and prepare next level + next_level = set() + for result in results: + subgraph.update(result.triples) + next_level.update(result.new_entities) + + visited.update(current_level) + current_level = next_level - visited + + return subgraph +``` + +#### चरण 2: समानांतर लेबल समाधान + +**वर्तमान अनुक्रमिक कार्यान्वयन:** +```python +# INEFFICIENT: Sequential processing +for edge in subgraph: + s = await self.maybe_label(edge[0]) # Individual query + p = await self.maybe_label(edge[1]) # Individual query + o = await self.maybe_label(edge[2]) # Individual query +``` + +**अनुकूलित समानांतर कार्यान्वयन:** +```python +async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: + # Collect all unique entities needing labels + entities_to_resolve = set() + for s, p, o in subgraph: + entities_to_resolve.update([s, p, o]) + + # Remove already cached entities + uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache] + + # Batch query for all uncached labels + if uncached_entities: + label_results = await self.batch_label_query(uncached_entities) + self.label_cache.update(label_results) + + # Apply labels to subgraph + return [ + (self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o)) + for s, p, o in subgraph + ] +``` + +#### चरण 3: उन्नत कैशिंग रणनीति + +**एलआरयू (LRU) कैश टीटीएल (TTL) के साथ:** +```python +class LRUCacheWithTTL: + def __init__(self, max_size: int, default_ttl: int = 3600): + self.cache = OrderedDict() + self.max_size = max_size + self.default_ttl = default_ttl + self.access_times = {} + + async def get(self, key: str) -> Optional[Any]: + if key in self.cache: + # Check TTL expiration + if time.time() - self.access_times[key] > self.default_ttl: + del self.cache[key] + del self.access_times[key] + return None + + # Move to end (most recently used) + self.cache.move_to_end(key) + return self.cache[key] + return None + + async def put(self, key: str, value: Any): + if key in self.cache: + self.cache.move_to_end(key) + else: + if len(self.cache) >= self.max_size: + # Remove least recently used + oldest_key = next(iter(self.cache)) + del self.cache[oldest_key] + del self.access_times[oldest_key] + + self.cache[key] = value + self.access_times[key] = time.time() +``` + +#### चरण 4: क्वेरी अनुकूलन और निगरानी + +**प्रदर्शन मेट्रिक्स संग्रह:** +```python +@dataclass +class PerformanceMetrics: + total_queries: int + cache_hits: int + cache_misses: int + avg_response_time: float + subgraph_construction_time: float + label_resolution_time: float + total_entities_processed: int + memory_usage_mb: float +``` + +**क्वेरी टाइमआउट और सर्किट ब्रेकर:** +```python +async def execute_with_timeout(self, query_func, timeout: int = 30): + try: + return await asyncio.wait_for(query_func(), timeout=timeout) + except asyncio.TimeoutError: + logger.error(f"Query timeout after {timeout}s") + raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s") +``` + +## कैश कंसिस्टेंसी पर विचार + +**डेटा स्टेलनेस ट्रेड-ऑफ:** +**लेबल कैश (5 मिनट TTL)**: डिलीट किए गए/रीनेम किए गए एंटिटी लेबल को प्रदर्शित करने का जोखिम। +**कोई एम्बेडिंग कैशिंग नहीं:** आवश्यक नहीं है - एम्बेडिंग पहले से ही प्रति-क्वेरी कैश किए गए हैं। +**कोई परिणाम कैशिंग नहीं:** डिलीट किए गए एंटिटीज/रिलेशनशिप से पुराने सबग्राफ परिणामों को रोकता है। + +**शमन रणनीतियाँ:** +**रूढ़िवादी TTL मान:** प्रदर्शन लाभ (10-20%) को डेटा की ताजगी के साथ संतुलित करें। +**कैश अमान्यकरण हुक:** ग्राफ उत्परिवर्तन घटनाओं के साथ वैकल्पिक एकीकरण। +**निगरानी डैशबोर्ड:** कैश हिट दरों बनाम स्टेलनेस घटनाओं को ट्रैक करें। +**कॉन्फ़िगर करने योग्य कैश नीतियां:** उत्परिवर्तन आवृत्ति के आधार पर प्रति-तैनाती ट्यूनिंग की अनुमति दें। + +**ग्राफ उत्परिवर्तन दर द्वारा अनुशंसित कैश कॉन्फ़िगरेशन:** +**उच्च उत्परिवर्तन (>100 परिवर्तन/घंटा):** TTL=60s, छोटे कैश आकार। +**मध्यम उत्परिवर्तन (10-100 परिवर्तन/घंटा):** TTL=300s (डिफ़ॉल्ट)। +**कम उत्परिवर्तन (<10 परिवर्तन/घंटा):** TTL=600s, बड़े कैश आकार। + +## सुरक्षा संबंधी विचार + +**क्वेरी इंजेक्शन रोकथाम:** +सभी एंटिटी पहचानकर्ताओं और क्वेरी मापदंडों को मान्य करें। +सभी डेटाबेस इंटरैक्शन के लिए पैरामीटराइज़्ड क्वेरी का उपयोग करें। +DoS हमलों को रोकने के लिए क्वेरी जटिलता सीमाएं लागू करें। + +**संसाधन सुरक्षा:** +अधिकतम सबग्राफ आकार सीमाओं को लागू करें। +संसाधन समाप्त होने से रोकने के लिए क्वेरी टाइमआउट लागू करें। +मेमोरी उपयोग निगरानी और सीमाएं जोड़ें। + +**पहुंच नियंत्रण:** +मौजूदा उपयोगकर्ता और संग्रह अलगाव बनाए रखें। +प्रदर्शन-प्रभावित करने वाले कार्यों के लिए ऑडिट लॉगिंग जोड़ें। +महंगे कार्यों के लिए दर सीमित करना लागू करें। + +## प्रदर्शन संबंधी विचार + +### अपेक्षित प्रदर्शन सुधार + +**क्वेरी में कमी:** +वर्तमान: विशिष्ट अनुरोध के लिए ~9,000+ क्वेरी +अनुकूलित: ~50-100 बैच क्वेरी (98% कमी) + +**प्रतिक्रिया समय में सुधार:** +ग्राफ ट्रैवर्सल: 15-20s → 3-5s (4-5x तेज़) +लेबल रिज़ॉल्यूशन: 8-12s → 2-4s (3x तेज़) +कुल क्वेरी: 25-35s → 6-10s (3-4x सुधार) + +**मेमोरी दक्षता:** +बाउंडेड कैश आकार मेमोरी लीक को रोकते हैं। +कुशल डेटा संरचनाएं मेमोरी पदचिह्न को ~40% तक कम करती हैं। +उचित संसाधन सफाई के माध्यम से बेहतर कचरा संग्रह। + +**यथार्थवादी प्रदर्शन अपेक्षाएं:** +**लेबल कैश:** सामान्य संबंधों वाले ग्राफ़ के लिए 10-20% क्वेरी में कमी। +**बैचिंग अनुकूलन:** 50-80% क्वेरी में कमी (प्राथमिक अनुकूलन)। +**ऑब्जेक्ट लाइफटाइम अनुकूलन:** प्रति-अनुरोध निर्माण ओवरहेड को समाप्त करें। +**कुल सुधार:** बैचिंग से मुख्य रूप से 3-4x प्रतिक्रिया समय में सुधार। + +**स्केलेबिलिटी में सुधार:** +3-5x बड़े नॉलेज ग्राफ़ के लिए समर्थन (कैश कंसिस्टेंसी आवश्यकताओं द्वारा सीमित)। +3-5x उच्च समवर्ती अनुरोध क्षमता। +कनेक्शन पुन: उपयोग के माध्यम से बेहतर संसाधन उपयोग। + +### प्रदर्शन निगरानी + +**रियल-टाइम मेट्रिक्स:** +ऑपरेशन प्रकार द्वारा क्वेरी निष्पादन समय। +कैश हिट अनुपात और प्रभावशीलता। +डेटाबेस कनेक्शन पूल उपयोग। +मेमोरी उपयोग और कचरा संग्रह प्रभाव। + +**प्रदर्शन बेंचमार्किंग:** +स्वचालित प्रदर्शन प्रतिगमन परीक्षण +वास्तविक डेटा वॉल्यूम के साथ लोड परीक्षण +वर्तमान कार्यान्वयन के खिलाफ तुलना बेंचमार्क + +## परीक्षण रणनीति + +### यूनिट परीक्षण +ट्रैवर्सल, कैशिंग और लेबल रिज़ॉल्यूशन के लिए व्यक्तिगत घटक परीक्षण +प्रदर्शन परीक्षण के लिए मॉक डेटाबेस इंटरैक्शन +कैश निष्कासन और TTL समाप्ति परीक्षण +त्रुटि हैंडलिंग और टाइमआउट परिदृश्य + +### एकीकरण परीक्षण +अनुकूलन के साथ एंड-टू-एंड GraphRAG क्वेरी परीक्षण +वास्तविक डेटा के साथ डेटाबेस इंटरैक्शन परीक्षण +समवर्ती अनुरोध हैंडलिंग और संसाधन प्रबंधन +मेमोरी लीक का पता लगाना और संसाधन सफाई सत्यापन + +### प्रदर्शन परीक्षण +वर्तमान कार्यान्वयन के खिलाफ बेंचमार्क परीक्षण +विभिन्न ग्राफ आकारों और जटिलताओं के साथ लोड परीक्षण +मेमोरी और कनेक्शन सीमाओं के लिए तनाव परीक्षण +प्रदर्शन सुधारों के लिए प्रतिगमन परीक्षण + +### अनुकूलता परीक्षण +मौजूदा GraphRAG API संगतता सत्यापित करें +विभिन्न ग्राफ डेटाबेस बैकएंड के साथ परीक्षण करें +वर्तमान कार्यान्वयन की तुलना में परिणाम सटीकता को मान्य करें + +## कार्यान्वयन योजना + +### प्रत्यक्ष कार्यान्वयन दृष्टिकोण +चूंकि API में परिवर्तन की अनुमति है, इसलिए माइग्रेशन जटिलता के बिना अनुकूलन को सीधे लागू करें: + +1. **`follow_edges` विधि को बदलें**: पुनरावृत्त बैच ट्रैवर्सल के साथ फिर से लिखें +2. **`get_labelgraph` को अनुकूलित करें**: समानांतर लेबल रिज़ॉल्यूशन लागू करें +3. **लंबे समय तक चलने वाला GraphRag जोड़ें**: प्रोसेसर को एक स्थायी उदाहरण बनाए रखने के लिए संशोधित करें +4. **लेबल कैशिंग लागू करें**: GraphRag क्लास में LRU कैश और TTL जोड़ें + +### परिवर्तनों का दायरा +**क्वेरी क्लास**: `follow_edges` में ~50 पंक्तियों को बदलें, बैच हैंडलिंग के लिए ~30 पंक्तियाँ जोड़ें +**GraphRag क्लास**: एक कैशिंग परत जोड़ें (~40 पंक्तियाँ) +**प्रोसेसर क्लास**: एक स्थायी GraphRag उदाहरण का उपयोग करने के लिए संशोधित करें (~20 पंक्तियाँ) +**कुल**: केंद्रित परिवर्तनों की ~140 पंक्तियाँ, ज्यादातर मौजूदा कक्षाओं के भीतर + +## समयरेखा + +**सप्ताह 1: मुख्य कार्यान्वयन** +बैच पुनरावृत्त ट्रैवर्सल के साथ `follow_edges` को बदलें +`get_labelgraph` में समानांतर लेबल रिज़ॉल्यूशन लागू करें +प्रोसेसर में एक लंबे समय तक चलने वाला GraphRag उदाहरण जोड़ें +एक लेबल कैशिंग परत लागू करें + +**सप्ताह 2: परीक्षण और एकीकरण** +नए ट्रैवर्सल और कैशिंग तर्क के लिए यूनिट परीक्षण +वर्तमान कार्यान्वयन के खिलाफ प्रदर्शन बेंचमार्किंग +वास्तविक ग्राफ डेटा के साथ एकीकरण परीक्षण +कोड समीक्षा और अनुकूलन + +**सप्ताह 3: परिनियोजन** +अनुकूलित कार्यान्वयन को तैनात करें +प्रदर्शन सुधारों की निगरानी करें +वास्तविक उपयोग के आधार पर कैश TTL और बैच आकारों को ठीक करें + +## खुले प्रश्न + +**डेटाबेस कनेक्शन पूलिंग**: क्या हमें कस्टम कनेक्शन पूलिंग लागू करनी चाहिए या मौजूदा डेटाबेस क्लाइंट पूलिंग पर भरोसा करना चाहिए? +**कैश दृढ़ता**: क्या लेबल और एम्बेडिंग कैश सेवा पुनरारंभों में बने रहने चाहिए? +**वितरित कैशिंग**: मल्टी-इंस्टेंस परिनियोजन के लिए, क्या हमें Redis/Memcached के साथ वितरित कैशिंग लागू करनी चाहिए? +**क्वेरी परिणाम प्रारूप**: क्या हमें बेहतर मेमोरी दक्षता के लिए आंतरिक ट्रिपल प्रतिनिधित्व को अनुकूलित करना चाहिए? +**निगरानी एकीकरण**: मौजूदा निगरानी प्रणालियों (Prometheus, आदि) के लिए कौन से मेट्रिक्स उजागर किए जाने चाहिए? + +## संदर्भ + +[GraphRAG मूल कार्यान्वयन](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +[ट्रस्टग्राफ आर्किटेक्चर सिद्धांत](architecture-principles.md) +[संग्रह प्रबंधन विनिर्देश](collection-management.md) diff --git a/docs/tech-specs/graphrag-performance-optimization.pt.md b/docs/tech-specs/graphrag-performance-optimization.pt.md new file mode 100644 index 00000000..8b04b106 --- /dev/null +++ b/docs/tech-specs/graphrag-performance-optimization.pt.md @@ -0,0 +1,629 @@ +# Especificação Técnica de Otimização de Desempenho do GraphRAG + +## Visão Geral + +Esta especificação descreve otimizações abrangentes de desempenho para o algoritmo GraphRAG (Graph Retrieval-Augmented Generation) no TrustGraph. A implementação atual sofre de gargalos de desempenho significativos que limitam a escalabilidade e os tempos de resposta. Esta especificação aborda quatro áreas principais de otimização: + +1. **Otimização de Traversal de Grafos**: Eliminar consultas ineficientes ao banco de dados e implementar exploração de grafos em lote. +2. **Otimização de Resolução de Rótulos**: Substituir a busca sequencial de rótulos por operações paralelas/em lote. +3. **Aprimoramento da Estratégia de Cache**: Implementar um cache inteligente com remoção LRU (Least Recently Used) e pré-busca. +4. **Otimização de Consultas**: Adicionar memorização de resultados e cache de incorporações para melhorar os tempos de resposta. + +## Objetivos + +**Reduzir o Volume de Consultas ao Banco de Dados**: Alcançar uma redução de 50-80% no volume total de consultas ao banco de dados por meio de loteamento e cache. +**Melhorar os Tempos de Resposta**: Almejar uma construção de subgrafo 3-5 vezes mais rápida e uma resolução de rótulos 2-3 vezes mais rápida. +**Aprimorar a Escalabilidade**: Suportar grafos de conhecimento maiores com melhor gerenciamento de memória. +**Manter a Precisão**: Preservar a funcionalidade e a qualidade dos resultados do GraphRAG existentes. +**Habilitar a Concorrência**: Melhorar as capacidades de processamento paralelo para vários запросов simultâneos. +**Reduzir a Pegada de Memória**: Implementar estruturas de dados e gerenciamento de memória eficientes. +**Adicionar Observabilidade**: Incluir métricas de desempenho e capacidades de monitoramento. +**Garantir a Confiabilidade**: Adicionar tratamento de erros adequado e mecanismos de tempo limite. + +## Contexto + +A implementação atual do GraphRAG em `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` apresenta vários problemas de desempenho críticos que afetam severamente a escalabilidade do sistema: + +### Problemas de Desempenho Atuais + +**1. Traversal de Grafos Ineficiente (função `follow_edges`, linhas 79-127)** +Realiza 3 consultas separadas ao banco de dados por entidade por nível de profundidade. +Padrão de consulta: consultas baseadas em sujeito, baseadas em predicado e baseadas em objeto para cada entidade. +Sem loteamento: Cada consulta processa apenas uma entidade por vez. +Sem detecção de ciclo: Pode revisitar os mesmos nós várias vezes. +A implementação recursiva sem memorização leva a uma complexidade exponencial. +Complexidade de tempo: O(entidades × max_path_length × triple_limit³) + +**2. Resolução Sequencial de Rótulos (função `get_labelgraph`, linhas 144-171)** +Processa cada componente de tripla (sujeito, predicado, objeto) sequencialmente. +Cada chamada de `maybe_label` pode acionar uma consulta ao banco de dados. +Sem execução paralela ou loteamento de consultas de rótulos. +Resulta em até 3 × subgraph_size chamadas individuais ao banco de dados. + +**3. Estratégia de Cache Primitiva (função `maybe_label`, linhas 62-77)** +Cache de dicionário simples sem limites de tamanho ou TTL (Time To Live). +A ausência de uma política de remoção de cache leva a um crescimento de memória ilimitado. +Falhas de cache acionam consultas individuais ao banco de dados. +Sem pré-busca ou aquecimento inteligente do cache. + +**4. Padrões de Consulta Subótimos** +Consultas de similaridade de vetores de entidade não são armazenadas em cache entre запросов semelhantes. +Sem memorização de resultados para padrões de consulta repetidos. +Otimização de consulta ausente para padrões de acesso comuns. + +**5. Problemas Críticos de Tempo de Vida de Objetos (`rag.py:96-102`)** +**Objeto GraphRag recriado por запросом**: Uma nova instância é criada para cada consulta, perdendo todos os benefícios do cache. +**Objeto de consulta com vida extremamente curta**: Criado e destruído dentro da execução de uma única consulta (linhas 201-207). +**Cache de rótulos redefinido por запросом**: O aquecimento do cache e o conhecimento acumulado são perdidos entre запросов. +**Sobrecarga de recriação do cliente**: Clientes de banco de dados podem ser reestabelecidos para cada запросом. +**Sem otimização entre запросов**: Não é possível se beneficiar de padrões de consulta ou compartilhamento de resultados. + +### Análise de Impacto no Desempenho + +Cenário de pior caso atual para uma consulta típica: +**Recuperação de Entidade**: 1 consulta de similaridade de vetor. +**Traversal de Grafos**: entidades × max_path_length × 3 × consultas de triplas. +**Resolução de Rótulos**: subgraph_size × 3 consultas individuais de rótulos. + +Para parâmetros padrão (50 entidades, comprimento do caminho 2, limite de 30 triplas, tamanho do subgrafo de 150): +**Consultas mínimas**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9.451 consultas ao banco de dados** +**Tempo de resposta**: 15-30 segundos para grafos de tamanho moderado +**Uso de memória**: Crescimento ilimitado do cache ao longo do tempo +**Eficiência do cache**: 0% - os caches são reiniciados em cada solicitação +**Sobrecarga de criação de objetos**: Objetos GraphRag + Query criados/destruídos por solicitação + +Esta especificação aborda essas lacunas implementando consultas em lote, cache inteligente e processamento paralelo. Ao otimizar padrões de consulta e acesso a dados, o TrustGraph pode: +Suportar grafos de conhecimento em escala empresarial com milhões de entidades +Fornecer tempos de resposta de menos de um segundo para consultas típicas +Lidar com centenas de solicitações GraphRAG simultâneas +Escalar de forma eficiente com o tamanho e a complexidade do grafo + +## Design Técnico + +### Arquitetura + +A otimização de desempenho do GraphRAG requer os seguintes componentes técnicos: + +#### 1. **Refatoração Arquitetural do Ciclo de Vida dos Objetos** + **Tornar o GraphRag de longa duração**: Mover a instância GraphRag para o nível do Processador para persistência entre solicitações + **Preservar caches**: Manter o cache de rótulos, o cache de incorporações e o cache de resultados de consulta entre solicitações + **Otimizar o objeto Query**: Refatorar o Query como um contexto de execução leve, não como um contêiner de dados + **Persistência de conexão**: Manter as conexões do cliente do banco de dados entre solicitações + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (modificado) + +#### 2. **Motor de Traversal de Grafos Otimizado** + Substituir a recursão `follow_edges` por busca em largura iterativa + Implementar o processamento em lote de entidades em cada nível de traversal + Adicionar detecção de ciclo usando o rastreamento de nós visitados + Incluir a terminação antecipada quando os limites são atingidos + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` + +#### 3. **Sistema de Resolução de Rótulos Paralelo** + Agrupar consultas de rótulos para várias entidades simultaneamente + Implementar padrões async/await para acesso concorrente ao banco de dados + Adicionar pré-busca inteligente para padrões de rótulos comuns + Incluir estratégias de aquecimento de cache de rótulos + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` + +#### 4. **Camada de Cache Conservadora de Rótulos** + Cache LRU com TTL curto apenas para rótulos (5 minutos) para equilibrar desempenho e consistência + Monitoramento de métricas e taxa de acerto do cache + **Sem cache de incorporações**: Já armazenado em cache por consulta, sem benefício entre consultas + **Sem cache de resultados de consulta**: Devido a preocupações com a consistência da mutação do grafo + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` + +#### 5. **Framework de Otimização de Consulta** + Análise e sugestões de otimização de padrões de consulta + Coordenador de consultas em lote para acesso ao banco de dados + Pool de conexões e gerenciamento de tempo limite de consulta + Monitoramento de desempenho e coleta de métricas + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` + +### Modelos de Dados + +#### Estado Otimizado de Traversal de Grafos + +O motor de traversal mantém o estado para evitar operações redundantes: + +```python +@dataclass +class TraversalState: + visited_entities: Set[str] + current_level_entities: Set[str] + next_level_entities: Set[str] + subgraph: Set[Tuple[str, str, str]] + depth: int + query_batch: List[TripleQuery] +``` + +Esta abordagem permite: +Detecção eficiente de ciclos através do rastreamento de entidades visitadas. +Preparação de consultas em lote em cada nível de travessia. +Gerenciamento de estado com eficiência de memória. +Término antecipado quando os limites de tamanho são atingidos. + +#### Estrutura de Cache Aprimorada + +```python +@dataclass +class CacheEntry: + value: Any + timestamp: float + access_count: int + ttl: Optional[float] + +class CacheManager: + label_cache: LRUCache[str, CacheEntry] + embedding_cache: LRUCache[str, CacheEntry] + query_result_cache: LRUCache[str, CacheEntry] + cache_stats: CacheStatistics +``` + +#### Estruturas de Consulta em Lote + +```python +@dataclass +class BatchTripleQuery: + entities: List[str] + query_type: QueryType # SUBJECT, PREDICATE, OBJECT + limit_per_entity: int + +@dataclass +class BatchLabelQuery: + entities: List[str] + predicate: str = LABEL +``` + +### APIs + +#### Novas APIs: + +**API de GraphTraversal** +```python +async def optimized_follow_edges_batch( + entities: List[str], + max_depth: int, + triple_limit: int, + max_subgraph_size: int +) -> Set[Tuple[str, str, str]] +``` + +**API de Resolução de Rótulos em Lote** +```python +async def resolve_labels_batch( + entities: List[str], + cache_manager: CacheManager +) -> Dict[str, str] +``` + +**API de Gerenciamento de Cache** +```python +class CacheManager: + async def get_or_fetch_label(self, entity: str) -> str + async def get_or_fetch_embeddings(self, query: str) -> List[float] + async def cache_query_result(self, query_hash: str, result: Any, ttl: int) + def get_cache_statistics(self) -> CacheStatistics +``` + +#### APIs Modificados: + +**GraphRag.query()** - Aprimorado com otimizações de desempenho: +Adicionado parâmetro `cache_manager` para controle de cache. +Incluído valor de retorno `performance_metrics`. +Adicionado parâmetro `query_timeout` para confiabilidade. + +**Classe Query** - Refatorada para processamento em lote: +Substituição do processamento individual de entidades por operações em lote. +Adicionados gerenciadores de contexto assíncronos para limpeza de recursos. +Incluídas funções de retorno de progresso para operações de longa duração. + +### Detalhes da Implementação + +#### Fase 0: Refatoração Crítica do Ciclo de Vida da Arquitetura + +**Implementação Atualmente Problemática:** +```python +# INEFFICIENT: GraphRag recreated every request +class Processor(FlowProcessor): + async def on_request(self, msg, consumer, flow): + # PROBLEM: New GraphRag instance per request! + self.rag = GraphRag( + embeddings_client = flow("embeddings-request"), + graph_embeddings_client = flow("graph-embeddings-request"), + triples_client = flow("triples-request"), + prompt_client = flow("prompt-request"), + verbose=True, + ) + # Cache starts empty every time - no benefit from previous requests + response = await self.rag.query(...) + +# VERY SHORT-LIVED: Query object created/destroyed per request +class GraphRag: + async def query(self, query, user="trustgraph", collection="default", ...): + q = Query(rag=self, user=user, collection=collection, ...) # Created + kg = await q.get_labelgraph(query) # Used briefly + # q automatically destroyed when function exits +``` + +**Arquitetura Otimizada e de Longa Duração:** +```python +class Processor(FlowProcessor): + def __init__(self, **params): + super().__init__(**params) + self.rag_instance = None # Will be initialized once + self.client_connections = {} + + async def initialize_rag(self, flow): + """Initialize GraphRag once, reuse for all requests""" + if self.rag_instance is None: + self.rag_instance = LongLivedGraphRag( + embeddings_client=flow("embeddings-request"), + graph_embeddings_client=flow("graph-embeddings-request"), + triples_client=flow("triples-request"), + prompt_client=flow("prompt-request"), + verbose=True, + ) + return self.rag_instance + + async def on_request(self, msg, consumer, flow): + # REUSE the same GraphRag instance - caches persist! + rag = await self.initialize_rag(flow) + + # Query object becomes lightweight execution context + response = await rag.query_with_context( + query=v.query, + execution_context=QueryContext( + user=v.user, + collection=v.collection, + entity_limit=entity_limit, + # ... other params + ) + ) + +class LongLivedGraphRag: + def __init__(self, ...): + # CONSERVATIVE caches - balance performance vs consistency + self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness + # Note: No embedding cache - already cached per-query, no cross-query benefit + # Note: No query result cache due to consistency concerns + self.performance_metrics = PerformanceTracker() + + async def query_with_context(self, query: str, context: QueryContext): + # Use lightweight QueryExecutor instead of heavyweight Query object + executor = QueryExecutor(self, context) # Minimal object + return await executor.execute(query) + +@dataclass +class QueryContext: + """Lightweight execution context - no heavy operations""" + user: str + collection: str + entity_limit: int + triple_limit: int + max_subgraph_size: int + max_path_length: int + +class QueryExecutor: + """Lightweight execution context - replaces old Query class""" + def __init__(self, rag: LongLivedGraphRag, context: QueryContext): + self.rag = rag + self.context = context + # No heavy initialization - just references + + async def execute(self, query: str): + # All heavy lifting uses persistent rag caches + return await self.rag.execute_optimized_query(query, self.context) +``` + +Esta mudança arquitetural oferece: +**Redução de 10-20% nas consultas ao banco de dados** para grafos com relacionamentos comuns (em comparação com 0% atualmente) +**Eliminação da sobrecarga de criação de objetos** para cada requisição +**Pool de conexões persistentes** e reutilização do cliente +**Otimização entre requisições** dentro das janelas de tempo de vida (TTL) do cache + +**Limitação Importante de Consistência do Cache:** +O cache de longo prazo introduz o risco de dados desatualizados quando entidades/rótulos são excluídos ou modificados no grafo subjacente. O cache LRU com TTL oferece um equilíbrio entre ganhos de desempenho e frescor dos dados, mas não pode detectar alterações em tempo real no grafo. + +#### Fase 1: Otimização de Traversal de Grafos + +**Problemas na Implementação Atual:** +```python +# INEFFICIENT: 3 queries per entity per level +async def follow_edges(self, ent, subgraph, path_length): + # Query 1: s=ent, p=None, o=None + res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit) + # Query 2: s=None, p=ent, o=None + res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit) + # Query 3: s=None, p=None, o=ent + res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit) +``` + +**Implementação Otimizada:** +```python +async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]: + visited = set() + current_level = set(entities) + subgraph = set() + + for depth in range(max_depth): + if not current_level or len(subgraph) >= self.max_subgraph_size: + break + + # Batch all queries for current level + batch_queries = [] + for entity in current_level: + if entity not in visited: + batch_queries.extend([ + TripleQuery(s=entity, p=None, o=None), + TripleQuery(s=None, p=entity, o=None), + TripleQuery(s=None, p=None, o=entity) + ]) + + # Execute all queries concurrently + results = await self.execute_batch_queries(batch_queries) + + # Process results and prepare next level + next_level = set() + for result in results: + subgraph.update(result.triples) + next_level.update(result.new_entities) + + visited.update(current_level) + current_level = next_level - visited + + return subgraph +``` + +#### Fase 2: Resolução Paralela de Rótulos + +**Implementação Sequencial Atual:** +```python +# INEFFICIENT: Sequential processing +for edge in subgraph: + s = await self.maybe_label(edge[0]) # Individual query + p = await self.maybe_label(edge[1]) # Individual query + o = await self.maybe_label(edge[2]) # Individual query +``` + +**Implementação Paralela Otimizada:** +```python +async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: + # Collect all unique entities needing labels + entities_to_resolve = set() + for s, p, o in subgraph: + entities_to_resolve.update([s, p, o]) + + # Remove already cached entities + uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache] + + # Batch query for all uncached labels + if uncached_entities: + label_results = await self.batch_label_query(uncached_entities) + self.label_cache.update(label_results) + + # Apply labels to subgraph + return [ + (self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o)) + for s, p, o in subgraph + ] +``` + +#### Fase 3: Estratégia Avançada de Cache + +**Cache LRU com TTL:** +```python +class LRUCacheWithTTL: + def __init__(self, max_size: int, default_ttl: int = 3600): + self.cache = OrderedDict() + self.max_size = max_size + self.default_ttl = default_ttl + self.access_times = {} + + async def get(self, key: str) -> Optional[Any]: + if key in self.cache: + # Check TTL expiration + if time.time() - self.access_times[key] > self.default_ttl: + del self.cache[key] + del self.access_times[key] + return None + + # Move to end (most recently used) + self.cache.move_to_end(key) + return self.cache[key] + return None + + async def put(self, key: str, value: Any): + if key in self.cache: + self.cache.move_to_end(key) + else: + if len(self.cache) >= self.max_size: + # Remove least recently used + oldest_key = next(iter(self.cache)) + del self.cache[oldest_key] + del self.access_times[oldest_key] + + self.cache[key] = value + self.access_times[key] = time.time() +``` + +#### Fase 4: Otimização de Consulta e Monitoramento + +**Coleta de Métricas de Desempenho:** +```python +@dataclass +class PerformanceMetrics: + total_queries: int + cache_hits: int + cache_misses: int + avg_response_time: float + subgraph_construction_time: float + label_resolution_time: float + total_entities_processed: int + memory_usage_mb: float +``` + +**Tempo Limite de Consulta e Disjuntor:** +```python +async def execute_with_timeout(self, query_func, timeout: int = 30): + try: + return await asyncio.wait_for(query_func(), timeout=timeout) + except asyncio.TimeoutError: + logger.error(f"Query timeout after {timeout}s") + raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s") +``` + +## Considerações sobre a Consistência do Cache + +**Compensações entre a Atualidade dos Dados:** +**Cache de rótulos (TTL de 5 minutos)**: Risco de exibir rótulos de entidades excluídas/renomeadas. +**Sem cache de embeddings**: Não é necessário - os embeddings já são armazenados em cache por consulta. +**Sem cache de resultados**: Impede que resultados de subgrafos desatualizados sejam exibidos devido à exclusão de entidades/relacionamentos. + +**Estratégias de Mitigação:** +**Valores de TTL conservadores**: Equilibre os ganhos de desempenho (10-20%) com a atualização dos dados. +**Hooks de invalidação de cache**: Integração opcional com eventos de mutação do grafo. +**Painéis de monitoramento**: Acompanhe as taxas de acerto do cache versus incidentes de desatualização. +**Políticas de cache configuráveis**: Permite ajustes específicos para cada implantação, com base na frequência de mutação. + +**Configuração de Cache Recomendada pela Taxa de Mutação do Grafo:** +**Alta mutação (>100 alterações/hora)**: TTL=60s, tamanhos de cache menores. +**Média mutação (10-100 alterações/hora)**: TTL=300s (padrão). +**Baixa mutação (<10 alterações/hora)**: TTL=600s, tamanhos de cache maiores. + +## Considerações de Segurança + +**Prevenção de Injeção de Consulta:** +Valide todos os identificadores de entidade e parâmetros de consulta. +Use consultas parametrizadas para todas as interações com o banco de dados. +Implemente limites de complexidade de consulta para evitar ataques de negação de serviço (DoS). + +**Proteção de Recursos:** +Aplique limites máximos de tamanho de subgrafo. +Implemente tempos limite de consulta para evitar o esgotamento de recursos. +Adicione monitoramento e limites de uso de memória. + +**Controle de Acesso:** +Mantenha o isolamento existente de usuários e coleções. +Adicione registro de auditoria para operações que afetam o desempenho. +Implemente limitação de taxa para operações dispendiosas. + +## Considerações de Desempenho + +### Melhorias de Desempenho Esperadas + +**Redução de Consultas:** +Atual: ~9.000+ consultas para um pedido típico. +Otimizado: ~50-100 consultas agrupadas (redução de 98%). + +**Melhorias no Tempo de Resposta:** +Travessia do grafo: 15-20s → 3-5s (4-5 vezes mais rápido). +Resolução de rótulos: 8-12s → 2-4s (3 vezes mais rápido). +Consulta geral: 25-35s → 6-10s (melhora de 3-4 vezes). + +**Eficiência de Memória:** +Tamanhos de cache limitados evitam vazamentos de memória. +Estruturas de dados eficientes reduzem a pegada de memória em ~40%. +Melhor coleta de lixo através da limpeza adequada de recursos. + +**Expectativas Realistas de Desempenho:** +**Cache de rótulos**: Redução de 10-20% nas consultas para grafos com relacionamentos comuns. +**Otimização de agrupamento**: Redução de 50-80% nas consultas (otimização primária). +**Otimização do ciclo de vida do objeto**: Elimina a sobrecarga de criação por pedido. +**Melhora geral**: Melhoria de 3-4 vezes no tempo de resposta, principalmente devido ao agrupamento. + +**Melhorias de Escalabilidade:** +Suporte para grafos de conhecimento 3-5 vezes maiores (limitado pelas necessidades de consistência do cache). +Capacidade de solicitação concorrente 3-5 vezes maior. +Melhor utilização de recursos através da reutilização de conexões. + +### Monitoramento de Desempenho + +**Métricas em Tempo Real:** +Tempos de execução de consultas por tipo de operação. +Taxas de acerto e eficácia do cache. +Utilização do pool de conexões do banco de dados. +Uso de memória e impacto da coleta de lixo. + +**Benchmarking de Desempenho:** +Testes de regressão de desempenho automatizados +Testes de carga com volumes de dados realistas +Benchmarks de comparação com a implementação atual + +## Estratégia de Testes + +### Testes Unitários +Teste de componentes individuais para travessia, cache e resolução de rótulos +Simulações de interações com o banco de dados para testes de desempenho +Testes de expiração de cache e TTL +Tratamento de erros e cenários de timeout + +### Testes de Integração +Testes de ponta a ponta de consultas GraphRAG com otimizações +Testes de interação com o banco de dados com dados reais +Tratamento de solicitações concorrentes e gerenciamento de recursos +Detecção de vazamentos de memória e verificação da limpeza de recursos + +### Testes de Desempenho +Testes de benchmark contra a implementação atual +Testes de carga com tamanhos e complexidades de grafos variáveis +Testes de estresse para limites de memória e conexões +Testes de regressão para melhorias de desempenho + +### Testes de Compatibilidade +Verificar a compatibilidade da API GraphRAG existente +Testar com vários backends de banco de dados de grafos +Validar a precisão dos resultados em comparação com a implementação atual + +## Plano de Implementação + +### Abordagem de Implementação Direta +Como as APIs podem ser alteradas, implemente as otimizações diretamente sem a complexidade da migração: + +1. **Substituir `follow_edges`**: Reescrever com travessia em lote iterativa +2. **Otimizar `get_labelgraph`**: Implementar resolução de rótulos paralela +3. **Adicionar GraphRag de longa duração**: Modificar o Processador para manter uma instância persistente +4. **Implementar cache de rótulos**: Adicionar um cache LRU com TTL à classe GraphRag + +### Escopo das Alterações +**Classe de consulta**: Substituir ~50 linhas em `follow_edges`, adicionar ~30 linhas para tratamento em lote +**Classe GraphRag**: Adicionar uma camada de cache (~40 linhas) +**Classe Processador**: Modificar para usar uma instância persistente de GraphRag (~20 linhas) +**Total**: ~140 linhas de alterações focadas, principalmente dentro das classes existentes + +## Cronograma + +**Semana 1: Implementação Central** +Substituir `follow_edges` por travessia iterativa em lote +Implementar resolução de rótulos paralela em `get_labelgraph` +Adicionar uma instância de longa duração de GraphRag ao Processador +Implementar a camada de cache de rótulos + +**Semana 2: Testes e Integração** +Testes unitários para a nova lógica de travessia e cache +Benchmarking de desempenho contra a implementação atual +Testes de integração com dados de grafos reais +Revisão de código e otimização + +**Semana 3: Implantação** +Implantar a implementação otimizada +Monitorar as melhorias de desempenho +Ajustar o TTL do cache e os tamanhos do lote com base no uso real + +## Perguntas Abertas + +**Pool de Conexões do Banco de Dados**: Devemos implementar um pool de conexões personalizado ou usar o pool de conexões do cliente do banco de dados existente? +**Persistência do Cache**: Os caches de rótulos e embeddings devem persistir entre as reinicializações do serviço? +**Cache Distribuído**: Para implantações multi-instância, devemos implementar um cache distribuído com Redis/Memcached? +**Formato do Resultado da Consulta**: Devemos otimizar a representação interna da tripla para uma melhor eficiência de memória? +**Integração de Monitoramento**: Quais métricas devem ser expostas aos sistemas de monitoramento existentes (Prometheus, etc.)? + +## Referências + +[Implementação Original do GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +[Princípios de Arquitetura do TrustGraph](architecture-principles.md) +[Especificação de Gerenciamento de Coleções](collection-management.md) diff --git a/docs/tech-specs/graphrag-performance-optimization.ru.md b/docs/tech-specs/graphrag-performance-optimization.ru.md index c69fddca..f4b8b82d 100644 --- a/docs/tech-specs/graphrag-performance-optimization.ru.md +++ b/docs/tech-specs/graphrag-performance-optimization.ru.md @@ -1,83 +1,82 @@ -# Техническое задание по оптимизации производительности GraphRAG +# Техническая спецификация оптимизации производительности GraphRAG ## Обзор -Данное техническое задание описывает комплексные оптимизации производительности алгоритма GraphRAG (Graph Retrieval-Augmented Generation) в системе TrustGraph. Текущая реализация страдает от существенных проблем с производительностью, которые ограничивают масштабируемость и время отклика. Данное задание охватывает четыре основные области оптимизации: +Эта спецификация описывает комплексные оптимизации производительности для алгоритма GraphRAG (Graph Retrieval-Augmented Generation) в TrustGraph. Текущая реализация страдает от значительных узких мест в производительности, которые ограничивают масштабируемость и время отклика. Эта спецификация охватывает четыре основные области оптимизации: -1. **Оптимизация обхода графа**: Устранение неэффективных рекурсивных запросов к базе данных и реализация пакетной обработки графа. -2. **Оптимизация разрешения меток**: Замена последовательной выборки меток параллельными/пакетными операциями. -3. **Улучшение стратегии кэширования**: Реализация интеллектуального кэширования с вытеснением по алгоритму LRU и предварительной загрузкой. -4. **Оптимизация запросов**: Добавление мемоизации результатов и кэширования векторов для повышения скорости отклика. +1. **Оптимизация обхода графа**: Исключение неэффективных рекурсивных запросов к базе данных и реализация пакетной обработки графа. +2. **Оптимизация разрешения меток**: Замена последовательной загрузки меток параллельными/пакетными операциями. +3. **Улучшение стратегии кэширования**: Реализация интеллектуального кэширования с вытеснением по принципу LRU и предварительной загрузкой. +4. **Оптимизация запросов**: Добавление мемоизации результатов и кэширования вложений для повышения скорости отклика. ## Цели -- **Сокращение количества запросов к базе данных**: Достижение снижения общего количества запросов к базе данных на 50-80% за счет пакетной обработки и кэширования. -- **Улучшение времени отклика**: Ускорение построения подграфа в 3-5 раза и ускорение разрешения меток в 2-3 раза. -- **Повышение масштабируемости**: Поддержка более крупных графовых баз знаний с улучшением управления памятью. -- **Сохранение точности**: Сохранение существующей функциональности GraphRAG и качества результатов. -- **Обеспечение параллельности**: Улучшение возможностей параллельной обработки для множества одновременных запросов. -- **Уменьшение занимаемой памяти**: Реализация эффективных структур данных и управления памятью. -- **Добавление наблюдаемости**: Включение метрик производительности и возможностей мониторинга. -- **Обеспечение надежности**: Добавление механизмов обработки ошибок и таймаутов. +**Сокращение объема запросов к базе данных**: Достижение снижения общего количества запросов к базе данных на 50-80% за счет пакетной обработки и кэширования. +**Улучшение времени отклика**: Целевое увеличение скорости построения подграфов в 3-5 раз и ускорение разрешения меток в 2-3 раза. +**Повышение масштабируемости**: Поддержка более крупных графов знаний с улучшением управления памятью. +**Сохранение точности**: Сохранение существующей функциональности GraphRAG и качества результатов. +**Обеспечение параллельности**: Улучшение возможностей параллельной обработки для нескольких одновременных запросов. +**Уменьшение объема памяти**: Реализация эффективных структур данных и управления памятью. +**Добавление возможностей мониторинга**: Включение показателей производительности и возможностей мониторинга. +**Обеспечение надежности**: Добавление надлежащей обработки ошибок и механизмов таймаута. -## Описание проблемы +## Предыстория -Текущая реализация GraphRAG, находящаяся в файле `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py`, имеет ряд критических проблем с производительностью, которые серьезно влияют на масштабируемость системы: +Текущая реализация GraphRAG в `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` имеет несколько критических проблем с производительностью, которые серьезно влияют на масштабируемость системы: ### Текущие проблемы с производительностью -**1. Неэффективный обход графа (`follow_edges` function, строки 79-127)** -- Выполняет 3 отдельных запроса к базе данных для каждой сущности на каждом уровне глубины. -- Шаблон запроса: запросы на основе субъекта, предиката и объекта для каждой сущности. -- Отсутствие пакетной обработки: Каждый запрос обрабатывает только одну сущность за раз. -- Отсутствие обнаружения циклов: Может повторно посещать одни и те же узлы несколько раз. -- Рекурсивная реализация без мемоизации приводит к экспоненциальной сложности. -- Временная сложность: O(entities × max_path_length × triple_limit³) +**1. Неэффективный обход графа (функция `follow_edges`, строки 79-127)** +Выполняет 3 отдельных запроса к базе данных для каждой сущности на каждом уровне глубины. +Шаблон запроса: запросы на основе субъекта, запросы на основе предиката и запросы на основе объекта для каждой сущности. +Без пакетной обработки: Каждый запрос обрабатывает только одну сущность за раз. +Без обнаружения циклов: Может повторно посещать одни и те же узлы несколько раз. +Рекурсивная реализация без мемоизации приводит к экспоненциальной сложности. +Временная сложность: O(entities × max_path_length × triple_limit³) -**2. Последовательное разрешение меток (`get_labelgraph` function, строки 144-171)** -- Обрабатывает каждый компонент тройки (субъект, предикат, объект) последовательно. -- Каждый вызов `maybe_label` потенциально вызывает запрос к базе данных. -- Отсутствует параллельное выполнение или пакетная обработка запросов меток. -- Приводит до 3 × subgraph_size отдельных запросов к базе данных. +**2. Последовательное разрешение меток (функция `get_labelgraph`, строки 144-171)** +Обрабатывает каждый компонент тройки (субъект, предикат, объект) последовательно. +Каждый вызов `maybe_label` потенциально вызывает запрос к базе данных. +Без параллельного выполнения или пакетной обработки запросов меток. +В результате получается до 3 × subgraph_size отдельных вызовов базы данных. -**3. Примитивная стратегия кэширования (`maybe_label` function, строки 62-77)** -- Простой кэш в виде словаря без ограничений размера или TTL. -- Отсутствие политики вытеснения из кэша приводит к неограниченному росту использования памяти. -- Пропуски в кэше вызывают отдельные запросы к базе данных. -- Отсутствует предварительная загрузка или интеллектуальное "прогрев" кэша. +**3. Примитивная стратегия кэширования (функция `maybe_label`, строки 62-77)** +Простой кэш в виде словаря без ограничений размера или TTL. +Отсутствие политики вытеснения кэша приводит к неограниченному росту памяти. +Пропуски кэша вызывают отдельные запросы к базе данных. +Без предварительной загрузки или интеллектуального подогрева кэша. **4. Субоптимальные шаблоны запросов** -- Запросы на поиск сходства векторов сущностей не кэшируются между похожими запросами. -- Отсутствует мемоизация результатов для повторяющихся шаблонов запросов. -- Отсутствует оптимизация запросов для распространенных сценариев доступа. +Запросы на сравнение векторного сходства сущностей не кэшируются между похожими запросами. +Без мемоизации результатов для повторяющихся шаблонов запросов. +Отсутствие оптимизации запросов для распространенных шаблонов доступа. -**5. Критические проблемы с временем жизни объектов (`rag.py:96-102`)** -- **Объект GraphRag пересоздается для каждого запроса**: Новый экземпляр создается для каждого запроса, что приводит к потере всех преимуществ кэширования. -- **Объект Query имеет очень короткое время жизни**: Создается и уничтожается в рамках выполнения одного запроса (строки 201-207). -- **Кэш меток сбрасывается для каждого запроса**: "Прогрев" кэша и накопленные знания теряются между запросами. -- **Накладные расходы на повторное создание клиента**: Клиенты базы данных потенциально переподключаются для каждого запроса. -- **Отсутствует оптимизация между запросами**: Невозможно воспользоваться преимуществами шаблонов запросов или совместного использования результатов. +**5. Критические проблемы с жизненным циклом объектов (`rag.py:96-102`)** +**Объект GraphRag создается для каждого запроса**: Новый экземпляр создается для каждого запроса, что приводит к потере всех преимуществ кэша. +**Объект запроса имеет очень короткий срок службы**: Создается и уничтожается в течение выполнения одного запроса (строки 201-207). +**Кэш меток сбрасывается для каждого запроса**: Подогрев кэша и накопленные знания теряются между запросами. +**Накладные расходы на повторное создание клиента**: Клиенты базы данных потенциально повторно устанавливаются для каждого запроса. +**Без оптимизации между запросами**: Невозможно извлечь выгоду из шаблонов запросов или совместного использования результатов. ### Анализ влияния на производительность Текущий наихудший сценарий для типичного запроса: -- **Извлечение сущности**: 1 запрос на поиск сходства векторов. -- **Обход графа**: entities × max_path_length × 3 × triple_limit запросов. -- **Разрешение меток**: subgraph_size × 3 отдельных запросов на метки. +**Извлечение сущности**: 1 запрос на сравнение векторного сходства. +**Обход графа**: entities × max_path_length × 3 × triple_limit запросов. +**Разрешение меток**: subgraph_size × 3 отдельных запросов на разрешение меток. -Для параметров по умолчанию (50 сущностей, глубина 2, лимит 30 троек, размер подграфа 150): -- **Минимальное количество запросов**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 запросов к базе данных**. -- **Время отклика**: 15-30 секунд для графов умеренного размера. -- **Использование памяти**: Неограниченный рост кэша со временем. -- **Эффективность кэша**: 0% - кэш сбрасывается при каждом запросе. -- **Накладные расходы на создание объектов**: Объекты GraphRag + Query создаются/уничтожаются для каждого запроса. +Для параметров по умолчанию (50 сущностей, длина пути 2, ограничение в 30 тройки, размер подграфа 150): +**Минимальное количество запросов**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9451 запрос к базе данных** +**Время отклика**: 15-30 секунд для графов среднего размера +**Использование памяти**: Неограниваемый рост кэша со временем +**Эффективность кэша**: 0% - кэши сбрасываются при каждом запросе +**Накладные расходы на создание объектов**: Объекты GraphRag + Query создаются/удаляются для каждого запроса -Данное техническое задание решает эти проблемы путем реализации пакетных запросов, интеллектуального кэширования и параллельной обработки. Оптимизируя шаблоны запросов и доступ к данным, TrustGraph может: - -- Поддерживать графовые базы знаний предприятия с миллионами сущностей. -- Обеспечивать время отклика менее 1 секунды для типичных запросов. -- Обрабатывать сотни одновременных запросов GraphRAG. -- Эффективно масштабироваться с ростом размера и сложности графа. +Эта спецификация решает эти проблемы, реализуя пакетные запросы, интеллектуальное кэширование и параллельную обработку. Оптимизируя шаблоны запросов и доступ к данным, TrustGraph может: +Поддерживать графы знаний корпоративного уровня с миллионами сущностей +Обеспечивать время отклика менее 1 секунды для типичных запросов +Обрабатывать сотни одновременных запросов GraphRAG +Эффективно масштабироваться в зависимости от размера и сложности графа ## Технический дизайн @@ -85,40 +84,546 @@ Оптимизация производительности GraphRAG требует следующих технических компонентов: -#### 1. **Архитектурная реорганизация для управления временем жизни объектов** - - **Сделать GraphRag долгоживущим**: Перенести экземпляр GraphRag на уровень Processor для сохранения данных между запросами. - - **Сохранить кэши**: Поддерживать кэш меток, кэш векторов и кэш результатов запросов между запросами. - - **Оптимизировать объект Query**: Рефакторинг Query как легковесного контекста выполнения, а не контейнера данных. - - **Сохранение подключений**: Поддерживать подключения к базе данных между запросами. +#### 1. **Архитектурная реорганизация жизненного цикла объектов** + **Сделать GraphRag долгоживущим**: Переместить экземпляр GraphRag на уровень Processor для сохранения между запросами + **Сохранять кэши**: Поддерживать кэш меток, кэш вложений и кэш результатов запросов между запросами + **Оптимизировать объект Query**: Переработать Query как легковесный контекст выполнения, а не контейнер данных + **Сохранять подключения к базе данных**: Поддерживать подключения к базе данных между запросами Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (изменен) #### 2. **Оптимизированный движок обхода графа** - - Заменить рекурсивный `follow_edges` итеративным поиском в ширину. - - Реализовать пакетную обработку сущностей на каждом уровне обхода. - - Добавить обнаружение циклов с отслеживанием посещенных узлов. - - Включить раннее завершение при достижении лимитов. + Заменить рекурсивную `follow_edges` на итеративный поиск в ширину + Реализовать пакетную обработку сущностей на каждом уровне обхода + Добавить обнаружение циклов с помощью отслеживания посещенных узлов + Включить раннее завершение при достижении лимитов Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` #### 3. **Параллельная система разрешения меток** - - Пакетная обработка запросов меток для нескольких сущностей одновременно. - - Реализация паттернов async/await для параллельного доступа к базе данных. - - Добавление интеллектуальной предварительной загрузки для распространенных шаблонов меток. - - Включение стратегий "прогрева" кэша меток. + Пакетные запросы меток для нескольких сущностей одновременно + Реализовать шаблоны async/await для параллельного доступа к базе данных + Добавить интеллектуальную предварительную загрузку для распространенных шаблонов меток + Включить стратегии предварительного заполнения кэша меток Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` #### 4. **Консервативный слой кэширования меток** - - Кэш LRU с коротким TTL только для меток (5 минут) для баланса между производительностью и согласованностью. - - Мониторинг метрик кэша и коэффициента попадания. - - **Без кэширования векторов**: Уже кэшируются на уровне запроса, нет пользы для между запросами. - - **Без кэширования результатов запросов**: Из-за проблем согласованности данных в графе. + Кэш LRU с коротким TTL только для меток (5 минут) для баланса между производительностью и согласованностью + Мониторинг метрик кэша и коэффициента попадания + **Без кэширования вложений**: Уже кэшируются для каждого запроса, нет преимуществ для межзапросных данных + **Без кэширования результатов запросов**: Из-за проблем согласованности изменений графа Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` #### 5. **Фреймворк оптимизации запросов** - - Анализ шаблонов запросов и предложения по оптимизации. - - Координатор пакетных запросов для доступа к базе данных. - - Пулинг подключений и управление таймаутами запросов. - - Мониторинг производительности. \ No newline at end of file + Анализ шаблонов запросов и предложения по оптимизации + Пакетный координатор запросов для доступа к базе данных + Управление пулами соединений и временем ожидания запросов + Мониторинг производительности и сбор метрик + + Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` + +### Модели данных + +#### Оптимизированное состояние обхода графа + +Движок обхода поддерживает состояние для предотвращения избыточных операций: + +```python +@dataclass +class TraversalState: + visited_entities: Set[str] + current_level_entities: Set[str] + next_level_entities: Set[str] + subgraph: Set[Tuple[str, str, str]] + depth: int + query_batch: List[TripleQuery] +``` + +Этот подход позволяет: +Эффективное обнаружение циклов за счет отслеживания посещенных сущностей. +Подготовку запросов пакетами на каждом уровне обхода. +Экономичное использование памяти для управления состоянием. +Раннее завершение, когда достигнуты ограничения по размеру. + +#### Улучшенная структура кэша + +```python +@dataclass +class CacheEntry: + value: Any + timestamp: float + access_count: int + ttl: Optional[float] + +class CacheManager: + label_cache: LRUCache[str, CacheEntry] + embedding_cache: LRUCache[str, CacheEntry] + query_result_cache: LRUCache[str, CacheEntry] + cache_stats: CacheStatistics +``` + +#### Структуры пакетных запросов + +```python +@dataclass +class BatchTripleQuery: + entities: List[str] + query_type: QueryType # SUBJECT, PREDICATE, OBJECT + limit_per_entity: int + +@dataclass +class BatchLabelQuery: + entities: List[str] + predicate: str = LABEL +``` + +### API + +#### Новые API: + +**API GraphTraversal** +```python +async def optimized_follow_edges_batch( + entities: List[str], + max_depth: int, + triple_limit: int, + max_subgraph_size: int +) -> Set[Tuple[str, str, str]] +``` + +**API для разрешения меток пакетов** +```python +async def resolve_labels_batch( + entities: List[str], + cache_manager: CacheManager +) -> Dict[str, str] +``` + +**API управления кэшем** +```python +class CacheManager: + async def get_or_fetch_label(self, entity: str) -> str + async def get_or_fetch_embeddings(self, query: str) -> List[float] + async def cache_query_result(self, query_hash: str, result: Any, ttl: int) + def get_cache_statistics(self) -> CacheStatistics +``` + +#### Измененные API: + +**GraphRag.query()** - Улучшено с оптимизациями производительности: +Добавлен параметр cache_manager для управления кэшем. +Добавлено возвращаемое значение performance_metrics. +Добавлен параметр query_timeout для повышения надежности. + +**Класс Query** - Рефакторинг для пакетной обработки: +Замена обработки отдельных сущностей на пакетные операции. +Добавлены асинхронные контекстные менеджеры для очистки ресурсов. +Добавлены обратные вызовы для отслеживания прогресса длительных операций. + +### Детали реализации + +#### Фаза 0: Критическая архитектурная реорганизация жизненного цикла + +**Текущая проблемная реализация:** +```python +# INEFFICIENT: GraphRag recreated every request +class Processor(FlowProcessor): + async def on_request(self, msg, consumer, flow): + # PROBLEM: New GraphRag instance per request! + self.rag = GraphRag( + embeddings_client = flow("embeddings-request"), + graph_embeddings_client = flow("graph-embeddings-request"), + triples_client = flow("triples-request"), + prompt_client = flow("prompt-request"), + verbose=True, + ) + # Cache starts empty every time - no benefit from previous requests + response = await self.rag.query(...) + +# VERY SHORT-LIVED: Query object created/destroyed per request +class GraphRag: + async def query(self, query, user="trustgraph", collection="default", ...): + q = Query(rag=self, user=user, collection=collection, ...) # Created + kg = await q.get_labelgraph(query) # Used briefly + # q automatically destroyed when function exits +``` + +**Оптимизированная архитектура с длительным сроком службы:** +```python +class Processor(FlowProcessor): + def __init__(self, **params): + super().__init__(**params) + self.rag_instance = None # Will be initialized once + self.client_connections = {} + + async def initialize_rag(self, flow): + """Initialize GraphRag once, reuse for all requests""" + if self.rag_instance is None: + self.rag_instance = LongLivedGraphRag( + embeddings_client=flow("embeddings-request"), + graph_embeddings_client=flow("graph-embeddings-request"), + triples_client=flow("triples-request"), + prompt_client=flow("prompt-request"), + verbose=True, + ) + return self.rag_instance + + async def on_request(self, msg, consumer, flow): + # REUSE the same GraphRag instance - caches persist! + rag = await self.initialize_rag(flow) + + # Query object becomes lightweight execution context + response = await rag.query_with_context( + query=v.query, + execution_context=QueryContext( + user=v.user, + collection=v.collection, + entity_limit=entity_limit, + # ... other params + ) + ) + +class LongLivedGraphRag: + def __init__(self, ...): + # CONSERVATIVE caches - balance performance vs consistency + self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness + # Note: No embedding cache - already cached per-query, no cross-query benefit + # Note: No query result cache due to consistency concerns + self.performance_metrics = PerformanceTracker() + + async def query_with_context(self, query: str, context: QueryContext): + # Use lightweight QueryExecutor instead of heavyweight Query object + executor = QueryExecutor(self, context) # Minimal object + return await executor.execute(query) + +@dataclass +class QueryContext: + """Lightweight execution context - no heavy operations""" + user: str + collection: str + entity_limit: int + triple_limit: int + max_subgraph_size: int + max_path_length: int + +class QueryExecutor: + """Lightweight execution context - replaces old Query class""" + def __init__(self, rag: LongLivedGraphRag, context: QueryContext): + self.rag = rag + self.context = context + # No heavy initialization - just references + + async def execute(self, query: str): + # All heavy lifting uses persistent rag caches + return await self.rag.execute_optimized_query(query, self.context) +``` + +Это архитектурное изменение обеспечивает: +**Сокращение количества запросов к базе данных на 10-20%** для графов с общими связями (по сравнению с текущими 0%) +**Устранение накладных расходов на создание объектов** для каждого запроса +**Постоянное использование пула соединений и повторное использование клиентов** +**Оптимизация между запросами** в пределах временных окон TTL кэша + +**Важное ограничение согласованности кэша:** +Долгосрочное кэширование создает риск устаревания данных, когда сущности/метки удаляются или изменяются в базовом графе. Кэш LRU с TTL обеспечивает баланс между повышением производительности и актуальностью данных, но не может обнаруживать изменения в графе в режиме реального времени. + +#### Фаза 1: Оптимизация обхода графа + +**Проблемы текущей реализации:** +```python +# INEFFICIENT: 3 queries per entity per level +async def follow_edges(self, ent, subgraph, path_length): + # Query 1: s=ent, p=None, o=None + res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit) + # Query 2: s=None, p=ent, o=None + res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit) + # Query 3: s=None, p=None, o=ent + res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit) +``` + +**Оптимизированная реализация:** +```python +async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]: + visited = set() + current_level = set(entities) + subgraph = set() + + for depth in range(max_depth): + if not current_level or len(subgraph) >= self.max_subgraph_size: + break + + # Batch all queries for current level + batch_queries = [] + for entity in current_level: + if entity not in visited: + batch_queries.extend([ + TripleQuery(s=entity, p=None, o=None), + TripleQuery(s=None, p=entity, o=None), + TripleQuery(s=None, p=None, o=entity) + ]) + + # Execute all queries concurrently + results = await self.execute_batch_queries(batch_queries) + + # Process results and prepare next level + next_level = set() + for result in results: + subgraph.update(result.triples) + next_level.update(result.new_entities) + + visited.update(current_level) + current_level = next_level - visited + + return subgraph +``` + +#### Фаза 2: Параллельное разрешение меток + +**Текущая последовательная реализация:** +```python +# INEFFICIENT: Sequential processing +for edge in subgraph: + s = await self.maybe_label(edge[0]) # Individual query + p = await self.maybe_label(edge[1]) # Individual query + o = await self.maybe_label(edge[2]) # Individual query +``` + +**Оптимизированная параллельная реализация:** +```python +async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: + # Collect all unique entities needing labels + entities_to_resolve = set() + for s, p, o in subgraph: + entities_to_resolve.update([s, p, o]) + + # Remove already cached entities + uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache] + + # Batch query for all uncached labels + if uncached_entities: + label_results = await self.batch_label_query(uncached_entities) + self.label_cache.update(label_results) + + # Apply labels to subgraph + return [ + (self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o)) + for s, p, o in subgraph + ] +``` + +#### Фаза 3: Продвинутая стратегия кэширования + +**Кэш LRU с TTL:** +```python +class LRUCacheWithTTL: + def __init__(self, max_size: int, default_ttl: int = 3600): + self.cache = OrderedDict() + self.max_size = max_size + self.default_ttl = default_ttl + self.access_times = {} + + async def get(self, key: str) -> Optional[Any]: + if key in self.cache: + # Check TTL expiration + if time.time() - self.access_times[key] > self.default_ttl: + del self.cache[key] + del self.access_times[key] + return None + + # Move to end (most recently used) + self.cache.move_to_end(key) + return self.cache[key] + return None + + async def put(self, key: str, value: Any): + if key in self.cache: + self.cache.move_to_end(key) + else: + if len(self.cache) >= self.max_size: + # Remove least recently used + oldest_key = next(iter(self.cache)) + del self.cache[oldest_key] + del self.access_times[oldest_key] + + self.cache[key] = value + self.access_times[key] = time.time() +``` + +#### Фаза 4: Оптимизация запросов и мониторинг + +**Сбор показателей производительности:** +```python +@dataclass +class PerformanceMetrics: + total_queries: int + cache_hits: int + cache_misses: int + avg_response_time: float + subgraph_construction_time: float + label_resolution_time: float + total_entities_processed: int + memory_usage_mb: float +``` + +**Тайм-аут запроса и предохранитель:** +```python +async def execute_with_timeout(self, query_func, timeout: int = 30): + try: + return await asyncio.wait_for(query_func(), timeout=timeout) + except asyncio.TimeoutError: + logger.error(f"Query timeout after {timeout}s") + raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s") +``` + +## Соображения по обеспечению согласованности кэша + +**Компромиссы между актуальностью данных:** +**Кэш меток (TTL 5 минут):** Риск предоставления устаревших меток сущностей (удаленных или переименованных). +**Отсутствие кэширования вложений:** Не требуется, так как вложения уже кэшируются для каждого запроса. +**Отсутствие кэширования результатов:** Предотвращает получение устаревших результатов подграфов из-за удаленных сущностей/связей. + +**Стратегии смягчения:** +**Консервативные значения TTL:** Баланс между приростом производительности (10-20%) и актуальностью данных. +**Хуки для аннулирования кэша:** Необязательная интеграция с событиями изменения графа. +**Панели мониторинга:** Отслеживание показателей попадания в кэш по сравнению с инцидентами устаревания данных. +**Настраиваемые политики кэширования:** Возможность тонкой настройки для каждого развертывания в зависимости от частоты изменений. + +**Рекомендуемая конфигурация кэша в зависимости от частоты изменений графа:** +**Высокая частота изменений (>100 изменений/час):** TTL=60 секунд, меньшие размеры кэша. +**Средняя частота изменений (10-100 изменений/час):** TTL=300 секунд (по умолчанию). +**Низкая частота изменений (<10 изменений/час):** TTL=600 секунд, большие размеры кэша. + +## Соображения безопасности + +**Предотвращение внедрения запросов:** +Проверка всех идентификаторов сущностей и параметров запроса. +Использование параметризованных запросов для всех взаимодействий с базой данных. +Реализация ограничений на сложность запросов для предотвращения атак типа "отказ в обслуживании" (DoS). + +**Защита ресурсов:** +Применение ограничений на максимальный размер подграфа. +Реализация таймаутов запросов для предотвращения исчерпания ресурсов. +Добавление мониторинга и ограничений использования памяти. + +**Контроль доступа:** +Поддержание существующей изоляции пользователей и коллекций. +Добавление ведения журнала аудита для операций, влияющих на производительность. +Реализация ограничения скорости для дорогостоящих операций. + +## Соображения производительности + +### Ожидаемые улучшения производительности + +**Сокращение количества запросов:** +Сейчас: ~9000+ запросов для типичного запроса. +Оптимизировано: ~50-100 пакетных запросов (снижение на 98%). + +**Улучшение времени отклика:** +Обход графа: 15-20 секунд → 3-5 секунд (в 4-5 раза быстрее). +Разрешение меток: 8-12 секунд → 2-4 секунды (в 3 раза быстрее). +Общий запрос: 25-35 секунд → 6-10 секунд (улучшение в 3-4 раза). + +**Эффективность использования памяти:** +Ограниченные размеры кэша предотвращают утечки памяти. +Эффективные структуры данных уменьшают объем используемой памяти примерно на 40%. +Улучшен сбор мусора благодаря правильной очистке ресурсов. + +**Реалистичные ожидания производительности:** +**Кэш меток:** Уменьшение количества запросов на 10-20% для графов с общими связями. +**Оптимизация пакетной обработки:** Уменьшение количества запросов на 50-80% (основная оптимизация). +**Оптимизация времени жизни объектов:** Исключение накладных расходов на создание объектов для каждого запроса. +**Общее улучшение:** Улучшение времени отклика в 3-4 раза, в основном за счет пакетной обработки. + +**Улучшения масштабируемости:** +Поддержка графов знаний в 3-5 раза большего размера (ограничено потребностями согласованности кэша). +Увеличение количества одновременных запросов в 3-5 раза. +Лучшее использование ресурсов благодаря повторному использованию соединений. + +### Мониторинг производительности + +**Метрики в реальном времени:** +Время выполнения запросов по типу операции. +Показатели попадания в кэш и его эффективность. +Использование пула соединений с базой данных. +Использование памяти и влияние сборки мусора. + +**Бенчмаркинг производительности:** +Автоматизированное регрессионное тестирование производительности +Тестирование нагрузки с использованием реалистичных объемов данных +Сравнительные тесты с текущей реализацией + +## Стратегия тестирования + +### Модульное тестирование +Тестирование отдельных компонентов для обхода графа, кэширования и разрешения меток +Эмуляция взаимодействия с базой данных для тестирования производительности +Тестирование вытеснения из кэша и истечения срока действия TTL +Обработка ошибок и сценарии таймаутов + +### Интеграционное тестирование +Комплексное тестирование запросов GraphRAG с оптимизациями +Тестирование взаимодействия с базой данных с использованием реальных данных +Обработка одновременных запросов и управление ресурсами +Обнаружение утечек памяти и проверка очистки ресурсов + +### Тестирование производительности +Тестирование производительности по сравнению с текущей реализацией +Тестирование нагрузки с различными размерами и сложностью графов +Стресс-тестирование для проверки лимитов памяти и соединений +Регрессионное тестирование для проверки улучшений производительности + +### Тестирование совместимости +Проверка совместимости существующего API GraphRAG +Тестирование с различными бэкендами графовых баз данных +Проверка точности результатов по сравнению с текущей реализацией + +## План реализации + +### Прямой подход к реализации +Поскольку API могут изменяться, реализуйте оптимизации напрямую без сложности миграции: + +1. **Замените метод `follow_edges`**: Перепишите с использованием пакетного итеративного обхода +2. **Оптимизируйте `get_labelgraph`**: Реализуйте параллельное разрешение меток +3. **Добавьте долгоживущий GraphRag**: Измените Processor для поддержания постоянной инстанции +4. **Реализуйте кэширование меток**: Добавьте кэш LRU с TTL в класс GraphRag + +### Область изменений +**Класс запроса**: Замените ~50 строк в `follow_edges`, добавьте ~30 строк для обработки пакетов +**Класс GraphRag**: Добавьте слой кэширования (~40 строк) +**Класс Processor**: Измените для использования постоянной инстанции GraphRag (~20 строк) +**Всего**: ~140 строк целенаправленных изменений, в основном в существующих классах + +## Временная шкала + +**Неделя 1: Основная реализация** +Замените `follow_edges` пакетным итеративным обходом +Реализуйте параллельное разрешение меток в `get_labelgraph` +Добавьте долгоживущую инстанцию GraphRag в Processor +Реализуйте слой кэширования меток + +**Неделя 2: Тестирование и интеграция** +Модульные тесты для новой логики обхода и кэширования +Бенчмаркинг производительности по сравнению с текущей реализацией +Интеграционное тестирование с реальными данными графа +Проверка кода и оптимизация + +**Неделя 3: Развертывание** +Разверните оптимизированную реализацию +Отслеживайте улучшения производительности +Тонкая настройка TTL кэша и размеров пакетов на основе реального использования + +## Открытые вопросы + +**Пул соединений с базой данных**: Следует ли нам реализовать собственный пул соединений или использовать существующий пул соединений от клиента базы данных? +**Постоянство кэша**: Должны ли кэши меток и внедрений сохраняться после перезапуска службы? +**Распределенное кэширование**: Для развернутых в нескольких экземплярах систем следует ли нам реализовать распределенное кэширование с использованием Redis/Memcached? +**Формат результата запроса**: Следует ли нам оптимизировать внутреннее представление тройки для повышения эффективности использования памяти? +**Интеграция мониторинга**: Какие метрики следует предоставлять существующим системам мониторинга (Prometheus и т. д.)? + +## Ссылки + +[Оригинальная реализация GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +[Принципы архитектуры TrustGraph](architecture-principles.md) +[Спецификация управления коллекциями](collection-management.md) diff --git a/docs/tech-specs/graphrag-performance-optimization.sw.md b/docs/tech-specs/graphrag-performance-optimization.sw.md index 2b07ce51..94f8a2fb 100644 --- a/docs/tech-specs/graphrag-performance-optimization.sw.md +++ b/docs/tech-specs/graphrag-performance-optimization.sw.md @@ -1,119 +1,421 @@ -# GraphRAG Utendaji Uboreshaji Maelezo ya Kiufundi +# Vipimo vya Ufanisi wa GraphRAG kwa Uboreshaji wa Kawaida -## Muhtasari +## Maelezo -Maelezo haya yanaeleza uboreshaji kamili wa utendaji wa algorithm ya GraphRAG (Graph Retrieval-Augmented Generation) katika TrustGraph. Matumizi ya sasa yana vizuizi vya utendaji muhimu ambavyo hu limit scalability na muda wa majibu. Maelezo haya yanashughulikia maeneo manne makuu ya uboreshaji: +Hati hii inaeleza uboreshaji wa kina wa utendaji wa algorithm ya GraphRAG (Graph Retrieval-Augmented Generation) katika TrustGraph. Utaratibu wa sasa una matatizo makubwa ya utendaji ambayo yanapunguza uwezo wa kupanuka na wakati wa majibu. Hati hii inashughulikia maeneo manne makuu ya uboreshaji: -1. **Uboreshaji wa Ufuatiliaji wa Grafu**: Ondoa maswali ya hivi karibuni ya database na utumie utafiti wa kikundi. -2. **Uboreshaji wa Utatuzi wa Labe**: Badilisha upataji wa mlolongo wa lebo kwa operesheni za sambamba/kikundi. -3. **Uboreshaji wa Mkakati wa Kumbukumbu**: Implement caching kwa akili pamoja na uondoshaji wa LRU na utaratibu wa kupata data. -4. **Uboreshaji wa Maswali**: Ongeza kumbukumbu ya matokeo na caching ya embeddings ili kuboresha muda wa majibu. +1. **Uboreshaji wa Ufuatiliaji wa Grafu**: Ondoa maswali ya hivi karibuni ya hivi karibuni ya hivi karibuni na tekeleza utafutaji wa grafu wa kikundi +2. **Uboreshaji wa Utatuzi wa Lebo**: Badilisha upekuzi wa hivi karibuni wa lebo na shughuli za sambamba/za kikundi +3. **Uboreshaji wa Mkakati wa Kumbukumbu**: Tekeleza kumbukumbu mahiri na kuondoa kwa LRU na utabiri +4. **Uboreshaji wa Ulipaji**: Ongeza kumbukumbu ya matokeo na kumbukumbu ya uingizaji kwa kuboresha wakati wa majibu -## Malengo +## Lengo -- **Punguza Idadi ya Maswali ya Database**: Punguza kwa 50-80% jumla ya maswali ya database kupitia kikundi na caching. -- **Boresha Muda wa Majibu**: Lenga ujenzi wa subgraph wa haraka 3-5x na utatuzi wa lebo wa haraka 2-3x. -- **Boresha Scalability**: Unga grafu kubwa zaidi za maarifa na usimamizi bora wa kumbukumbu. -- **Dumishe Usahihi**: Dumishe utendakazi na ubora wa matokeo ya GraphRAG iliyopo. -- **Wezesha Ujazo**: Boresha uwezo wa usindikaji sambamba kwa maombi mengi sambamba. -- **Punguza Uwepo wa Kumbukumbu**: Implement miundo ya data na usimamizi wa kumbukumbu bora. -- **Ongeza Ufuatiliaji**: Jumuisha metriki za utendaji na uwezo wa ufuatiliaji. -- **Hakikisha Utiaji Njia**: Ongeza utunzaji sahihi wa makosa na mitaratibu ya muda. +**Punguza Kiasi cha Maswali ya Hivi Karibuni**: Pata kupunguzwa kwa 50-80% katika jumla ya maswali ya hivi karibuni kupitia kikundi na kumbukumbu +**Boresha Wakati wa Majibu**: Lenga ujenzi wa subgrafu wa haraka 3-5x na utatuzi wa lebo wa haraka 2-3x +**Boresha Uwezo wa Kupanuka**: Unga grafu kubwa za maarifa na usimamizi bora wa kumbukumbu +**Dumishe Usahihi**: Dumishe utendaji na ubora wa matokeo ya GraphRAG iliyopo +**Wezesha Ulinganifu**: Boresha uwezo wa usindikaji sambamba kwa maombi mengi ya sambamba +**Punguza Uzito wa Kumbukumbu**: Tekeleza miundo ya data na usimamizi wa kumbukumbu bora +**Ongeza Ufuatiliaji**: Jumuisha metriki za utendaji na uwezo wa ufuatiliaji +**Hakikisha Utendaji**: Ongeza ushughulikiaji sahihi wa makosa na mitambo ya muda ## Asili -Matumizi ya sasa ya GraphRAG katika `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` ina masuala muhimu ya utendaji ambayo yanaathiri sana scalability ya mfumo: +Utaratibu wa sasa wa GraphRAG katika `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` una masuala muhimu ya utendaji ambayo yanaathiri sana uwezo wa kupanuka wa mfumo: ### Matatizo ya Sasa ya Utendaji -**1. Ufuatiliaji Usio na Ufanisi wa Grafu (`follow_edges` function, mistari 79-127)** -- Hufanya maswali 3 tofauti ya database kwa kila entiti kwa kila ngazi. -- Mfumo wa swali: maswali yanayozingatia mada, yanayozingatia predikat, na yanayozingatia kitu kwa kila entiti. -- Hakuna kikundi: Kila swali hutumia entiti moja tu wakati mmoja. -- Hakuna ugunduzi wa mzunguko: Inaweza kutembelea nodi sawa mara nyingi. -- Matumizi ya recursive bila kumbukumbu hupelekea utata wa kielelekeo. -- Utata wa muda: O(entities × max_path_length × triple_limit³) +**1. Ufuatiliaji Usio na Ufanisi wa Grafu (kitendaji cha `follow_edges`, mistari 79-127)** +Hufanya maswali 3 tofauti ya hivi karibuni kwa kila kitu kwa kila kiwango cha kina +Mfumo wa swali: maswali ya msingi ya mada, maswali ya msingi ya tabia, na maswali ya msingi ya kitu kwa kila kitu +Hakuna kikundi: Kila swali huchakata kitu kimoja wakati mmoja +Hakuna utambuzi wa mzunguko: Inaweza kurudi kwenye nodi sawa mara nyingi +Utaratibu wa hivi karibuni bila kumbukumbu husababisha utata wa kielelekevu +Utata wa wakati: O(vitabu × urefu_max_ya_njia × triple_limit³) -**2. Utatuzi Mfululizo wa Labe (`get_labelgraph` function, mistari 144-171)** -- Hufanya usindikaji wa kila sehemu ya triple (mada, predikat, kitu) mfululizo. -- Kila wito wa `maybe_label` inaweza kusababisha swali la database. -- Hakuna utekelezaji au kikundi sambamba wa maswali ya lebo. -- Hupelekea hadi simu 3 × subgraph_size za database. +**2. Utatuzi wa Hivi Karibuni wa Lebo (kitendaji cha `get_labelgraph`, mistari 144-171)** +Huchakata kila sehemu ya tatu (mhusika, tabia, kitu) kwa hivi karibuni +Kila wito wa `maybe_label` inaweza kusababisha swali la hivi karibuni la hivi karibuni +Hakuna utekelezaji sambamba au kikundi cha maswali ya lebo +Hupelekea hadi simu 3 × ya hivi karibuni ya hivi karibuni ya hivi karibuni. -**3. Mkakati wa Msingi wa Kumbukumbu (`maybe_label` function, mistari 62-77)** -- Cache rahisi ya kamusi bila mipaka ya saizi au TTL. -- Hakuna sera ya kuondolewa kwa cache hupelekea ukuaji usio na kikomo wa kumbukumbu. -- Upotezaji wa cache husababisha maswali ya database ya kibinafsi. -- Hakuna kupata data au uongezaji mahiri wa cache. +**3. Mkakati wa Kumbukumbu wa Msingi (kitendaji cha `maybe_label`, mistari 62-77)** +Kumbukumbu rahisi ya kamusi bila mipaka ya saizi au TTL +Hakuna sera ya kuondoa kumbukumbu inayosababisha ukuaji usio na kikomo wa kumbukumbu +Kupoteza kumbukumbu hutuma maswali ya hivi karibuni ya hivi karibuni ya hivi karibuni +Hakuna utabiri au uongezaji mahiri wa kumbukumbu -**4. Mfumo Usio bora wa Maswali** -- Maswali ya ufanano wa vector ya entiti hayahifadhiwi kati ya maombi sawa. -- Hakuna kumbukumbu ya matokeo kwa mifumo ya swali iliyorudiwa. -- Uboreshaji wa maswali unokosekana kwa mifumo ya kawaida ya ufikiaji. +**4. Mfumo Usio na Ufanisi wa Maswali** +Maswali ya ufanano wa vekta ya kitu hayahifadhiwi kati ya maombi sawa +Hakuna kumbukumbu ya matokeo kwa mifumo ya swali iliyorudiwa +Uboreshaji wa swali unaokosekana kwa mifumo ya kawaida ya ufikiaji -**5. Masuala Muhimu ya Muda wa Kitu (`rag.py:96-102`)** -- **Kitu cha GraphRag kinaundwa kila maombi**: Instance mpya huundwa kwa kila swali, na kupoteza faida zote za cache. -- **Kitu cha swali kina muda mfupi sana**: Huundwa na kuharibiwa ndani ya utekelezaji wa swali moja (mistari 201-207). -- **Cache ya lebo huwezeshwa kila maombi**: Uongezaji wa cache na maarifa yaliyokusanywa hayapotei kati ya maombi. -- **Utoaji wa upya wa mteja**: Wateja wa database wanaweza kuanzishwa tena kwa kila maombi. -- **Uboreshaji usio na maombi**: Haiwezi kufaidika na mifumo ya swali au kushiriki matokeo. +**5. Masuala Muhimu ya Maisha ya Kitu (`rag.py:96-102`)** +**Kitu cha GraphRag kinaundwa kwa kila ombi**: Toleo jipya huundwa kwa kila swali, na kupoteza faida zote za kumbukumbu +**Kitu cha swali kina muda mfupi sana**: Huundwa na kuharibiwa ndani ya utekelezaji wa swali moja (mistari 201-207) +**Kumbukumbu ya lebo inarejeshwa kwa kila ombi**: Uongezaji wa kumbukumbu na maarifa yaliyokusanywa yanapotea kati ya maombi +**Upeo wa upya wa mteja**: Wateja wa hivi karibuni wanaweza kuanzishwa tena kwa kila ombi +**Hakuna uboreshaji wa kati ya maombi**: Haiwezi kufaidika na mifumo ya swali au ushirikishwaji wa matokeo -### Uchambuzi wa Athari za Utendaji +### Uchambuzi wa Athari ya Utendaji -Jalada la mbaya zaidi linalowezekana kwa swali la kawaida: -- **Uongezaji wa Entiti**: Swali 1 la ufanano wa vector -- **Ufuatiliaji wa Grafu**: entities × max_path_length × 3 × maswali ya triple_limit -- **Utatuzi wa Labe**: maswali ya lebo ya `subgraph_size` × 3 ya kibinafsi +Hali mbaya zaidi ya sasa kwa swali la kawaida: +**Upekuzi wa Kitu**: swali 1 la ufanano wa vekta +**Ufuatiliaji wa Grafu**: vitu × urefu_max_ya_njia × 3 × maswali ya hivi karibuni ya hivi karibuni ya hivi karibuni +**Utatuzi wa Lebo**: maswali ya hivi karibuni ya hivi karibuni ya hivi karibuni ya subgrafu_size × 3 -Kwa vigezo vya chagu msingi (entities 50, urefu wa njia 2, kikomo cha triple 30, saizi ya subgraph 150): -- **Maswali ya chini**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **maswali 9,451 ya database** -- **Muda wa majibu**: 15-30 sekunde kwa grafu za ukubwa wa wastani -- **Matumizi ya kumbukumbu**: Ukuaji usio na kikomo wa cache baada ya muda -- **Ufanisi wa cache**: 0% - caches huwezeshwa kila maombi -- **Utoaji wa kitu**: Kitu cha GraphRag + Kitu cha swali kinaundwa/kuharibiwa kwa kila maombi +Kwa vigezo chache (vitu 50, urefu wa njia 2, kikomo cha triplet 30, saizi ya subgraph 150): +**Maswali ya chini**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **maswali 9,451 ya hifadhidata** +**Wakati wa majibu**: Sekunde 15-30 kwa vielelezo vya saizi ya wastani +**Matumizi ya kumbukumbu**: Ukubwa wa kumbukumbu unaoongezeka bila kikomo baada ya muda +**Ufanisi wa kumbukumbu**: 0% - kumbukumbu hurejeshwa kila ombi +**Utozo wa kuunda vitu**: Vitu vya GraphRag + Query vinaundwa/vinaharibiwa kwa kila ombi -Maelezo haya yanashughulikia pengo hizi kwa kutumia maswali ya kikundi, caching kwa akili, na usindikaji sambamba. Kwa kuongeza ufanisi wa mifumo ya swali na ufikiaji wa data, TrustGraph inaweza: -- Unga grafu kubwa za maarifa na milioni ya entiti -- Kutoa muda wa majibu wa chini ya sekunde kwa swali la kawaida -- Kushughulikia maombi ya GraphRAG ya sambamba mamia -- Kuongezeka kwa ufanisi na saizi na utata wa grafu +Maelezo haya yanaangazia pengo hizi kwa kutumia maswali ya kikundi, uhifadhi mahiri, na usindikaji wa sambamba. Kwa kuboresha mifumo ya maswali na ufikiaji wa data, TrustGraph inaweza: +Kusaidia vielelezo vya maarifa vya kiwango cha shirika na mamilioni ya vitu +Kutoa wakati wa majibu ya chini ya sekunde kwa maswali ya kawaida +Kushughulikia maombi mamia ya GraphRAG kwa wakati mmoja +Kuongezeka kwa ufanisi na saizi na utata wa vielelezo -## Ubunifu wa Kiufundi +## Muundo wa Kiufundi ### Usanifu Uboreshaji wa utendaji wa GraphRAG unahitaji vipengele hivi vya kiufundi: -#### 1. **Urekebishaji wa Usanifu wa Muda wa Kitu** - - **Fanya GraphRag kuwa wa muda mrefu**: Hamisha instance ya GraphRag hadi ngazi ya Processor ili kudumu katika maombi. - - **Dumishe caches**: Dumishe cache ya lebo, cache ya embedding, na cache ya matokeo ya swali kati ya maombi. - - **Boresha Kitu cha Swali**: Rekebisha Swali kama muktadha wa utekelezaji nyepesi, sio kontena ya data. - - **Usaidizi wa miunganisho**: Dumishe miunganisho ya mteja wa database katika maombi. +#### 1. **Urekebishaji wa Usanifu wa Muda wa Vitu** + **Fanya GraphRag iwe na muda mrefu**: Hamisha mfano wa GraphRag hadi ngazi ya Processor ili kudumu katika maombi + **Ondoa kumbukumbu**: Dumishe kumbukumbu ya lebo, kumbukumbu ya uingizaji, na kumbukumbu ya matokeo ya swali kati ya maombi + **Boresha kitu cha Swali**: Rekebisha Swali ili iwe mfumo wa utekelezaji mwepesi, sio chombo cha data + **Usaidizi wa muunganisho**: Dumishe miunganisho ya mteja wa hifadhidata katika maombi - Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (imebadilishwa) + Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (iliyorekebishwa) -#### 2. **Njia Iliyo bora ya Ufuatiliaji wa Grafu** - - Badilisha `follow_edges` ya recursive na utafutaji wa msingi wa upana wa iterative - - Implement utunzaji wa kikundi wa entiti katika kila ngazi ya utafutaji -- Ongeza ugunduzi wa mzunguko kwa kufuatilia nodi zilizotembelea -- Jumuisha kumalizika mapema wakati mipaka inafikiwa +#### 2. **Injini Iliyoboreshwa ya Ufuatiliaji wa Vielelezo** + Badilisha `follow_edges` ya kurudia na utafutaji wa upana wa mara kwa mara + Tekeleza usindikaji wa kikundi wa vitu katika kila ngazi ya ufuatiliaji + Ongeza ugunduzi wa mzunguko kwa kufuatilia nodi zilizotembelewa + Jumuisha kumalizika mapema wakati mipaka inafikiwa Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` -#### 3. **Mfumo Sambamba wa Utatuzi wa Labe** - - Kundi maswali ya lebo kwa entiti nyingi wakati mmoja - - Implement mifumo ya async/kusubiri kwa ufikiaji wa sambamba wa database - - Ongeza kupata data mahiri kwa mifumo ya kawaida ya lebo - - Jumusha mikakati ya uongezaji wa lebo +#### 3. **Mfumo wa Ufafanuzi wa Lebo Sambamba** + Kikundi maswali ya lebo kwa vitu vingi kwa wakati mmoja + Tekeleza mifumo ya async/await kwa ufikiaji sambamba wa hifadhidata + Ongeza upakiaji wa akili kwa mifumo ya kawaida ya lebo + Jumuisha mikakati ya ukausha wa kumbukumbu ya lebo - Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolution.py` + Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` -#### 4. **Mkakati wa Kina wa Kumbukumbu** -- Implement cache ya LRU na TTL -- Zana za ufuatiliaji wa utendaji wa cache -- Usalama wa maswali na utunzaji wa rasilimali +#### 4. **Nafasi ya Kumbukumbu ya Lebo Iliyohifadhiwa** + Kumbukumbu ya LRU na TTL fupi kwa lebo pekee (dakika 5) ili kusawazisha utendaji na uthabiti + Fuatilia metriki na uwiano wa hit + **Hakuna ukaushaji wa uingizaji**: Tayari umehifadhiwa kwa kila swali, hakuna faida ya kati ya maswali + **Hakuna ukaushaji wa matokeo ya swali**: Kutokana na wasiwasi wa uthabiti wa mabadiliko ya vielelezo -**Mbinu ya Ufuatiliaji ya Kumbukumbu**: + Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` + +#### 5. **Mfumo wa Uboreshaji wa Swali** + Uchambuzi na mapendekezo ya uboreshaji wa mfumo wa swali + Mratibu wa swali la kikundi kwa ufikiaji wa hifadhidata + Uunganisho wa mabwawa na usimamaji wa muda wa swali + Ufuatiliaji wa utendaji na ukusanyaji wa metriki + + Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` + +### Mifano ya Data + +#### Hali Iliyoboreshwa ya Ufuatiliaji wa Vielelezo + +Injini ya ufuatiliaji inahifadhi hali ili kuepuka shughuli za ziada: + +```python +@dataclass +class TraversalState: + visited_entities: Set[str] + current_level_entities: Set[str] + next_level_entities: Set[str] + subgraph: Set[Tuple[str, str, str]] + depth: int + query_batch: List[TripleQuery] +``` + +Mbinu hii inaruhusu: +Uchunguzi wa haraka wa mzunguko kupitia kufuatilia vitu vilivyotembelewa +Maandalizi ya maswali kwa wingi katika kila ngazi ya utafutaji +Usimamizi wa hali unaohifadhi kumbukumbu +Kukomesha mapema wakati mipaka ya ukubwa inafikiwa + +#### Muundo Ulioboreshwa wa Kumbukumbu (Cache) + +```python +@dataclass +class CacheEntry: + value: Any + timestamp: float + access_count: int + ttl: Optional[float] + +class CacheManager: + label_cache: LRUCache[str, CacheEntry] + embedding_cache: LRUCache[str, CacheEntry] + query_result_cache: LRUCache[str, CacheEntry] + cache_stats: CacheStatistics +``` + +#### Muundo wa Maswali ya Kundi + +```python +@dataclass +class BatchTripleQuery: + entities: List[str] + query_type: QueryType # SUBJECT, PREDICATE, OBJECT + limit_per_entity: int + +@dataclass +class BatchLabelQuery: + entities: List[str] + predicate: str = LABEL +``` + +### API + +#### API mpya: + +**API ya GraphTraversal** +```python +async def optimized_follow_edges_batch( + entities: List[str], + max_depth: int, + triple_limit: int, + max_subgraph_size: int +) -> Set[Tuple[str, str, str]] +``` + +**API ya Utatuzi wa Lebo za Kundi** +```python +async def resolve_labels_batch( + entities: List[str], + cache_manager: CacheManager +) -> Dict[str, str] +``` + +**API ya Usimamizi wa Kumbukumbu (Cache)** +```python +class CacheManager: + async def get_or_fetch_label(self, entity: str) -> str + async def get_or_fetch_embeddings(self, query: str) -> List[float] + async def cache_query_result(self, query_hash: str, result: Any, ttl: int) + def get_cache_statistics(self) -> CacheStatistics +``` + +#### API Zilizobadilishwa: + +**GraphRag.query()** - Imeboreshwa kwa matumizi bora: +Ongeza parameter ya `cache_manager` kwa udhibiti wa kumbukumbu. +Jumuisha thamani ya kurudiwa ya `performance_metrics`. +Ongeza parameter ya `query_timeout` kwa uaminifu. + +**Darasa la `Query`** - Limepangwa upya kwa usindikaji wa jumla: +Badilisha usindikaji wa kila kitu kwa shughuli za jumla. +Ongeza menejeri wa muktadha wa async kwa usafi wa rasilimali. +Jumuisha miongozo ya maendeleo kwa operesheni za muda mrefu. + +### Maelezo ya Utendaji + +#### Awamu ya 0: Urekebishaji Muhimu wa Muundo na Muda wa Maisha + +**Utendaji Sasa Usiofaa:** +```python +# INEFFICIENT: GraphRag recreated every request +class Processor(FlowProcessor): + async def on_request(self, msg, consumer, flow): + # PROBLEM: New GraphRag instance per request! + self.rag = GraphRag( + embeddings_client = flow("embeddings-request"), + graph_embeddings_client = flow("graph-embeddings-request"), + triples_client = flow("triples-request"), + prompt_client = flow("prompt-request"), + verbose=True, + ) + # Cache starts empty every time - no benefit from previous requests + response = await self.rag.query(...) + +# VERY SHORT-LIVED: Query object created/destroyed per request +class GraphRag: + async def query(self, query, user="trustgraph", collection="default", ...): + q = Query(rag=self, user=user, collection=collection, ...) # Created + kg = await q.get_labelgraph(query) # Used briefly + # q automatically destroyed when function exits +``` + +**Muundo Ulioboreshwa na Umeundwa Kudumu:** +```python +class Processor(FlowProcessor): + def __init__(self, **params): + super().__init__(**params) + self.rag_instance = None # Will be initialized once + self.client_connections = {} + + async def initialize_rag(self, flow): + """Initialize GraphRag once, reuse for all requests""" + if self.rag_instance is None: + self.rag_instance = LongLivedGraphRag( + embeddings_client=flow("embeddings-request"), + graph_embeddings_client=flow("graph-embeddings-request"), + triples_client=flow("triples-request"), + prompt_client=flow("prompt-request"), + verbose=True, + ) + return self.rag_instance + + async def on_request(self, msg, consumer, flow): + # REUSE the same GraphRag instance - caches persist! + rag = await self.initialize_rag(flow) + + # Query object becomes lightweight execution context + response = await rag.query_with_context( + query=v.query, + execution_context=QueryContext( + user=v.user, + collection=v.collection, + entity_limit=entity_limit, + # ... other params + ) + ) + +class LongLivedGraphRag: + def __init__(self, ...): + # CONSERVATIVE caches - balance performance vs consistency + self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness + # Note: No embedding cache - already cached per-query, no cross-query benefit + # Note: No query result cache due to consistency concerns + self.performance_metrics = PerformanceTracker() + + async def query_with_context(self, query: str, context: QueryContext): + # Use lightweight QueryExecutor instead of heavyweight Query object + executor = QueryExecutor(self, context) # Minimal object + return await executor.execute(query) + +@dataclass +class QueryContext: + """Lightweight execution context - no heavy operations""" + user: str + collection: str + entity_limit: int + triple_limit: int + max_subgraph_size: int + max_path_length: int + +class QueryExecutor: + """Lightweight execution context - replaces old Query class""" + def __init__(self, rag: LongLivedGraphRag, context: QueryContext): + self.rag = rag + self.context = context + # No heavy initialization - just references + + async def execute(self, query: str): + # All heavy lifting uses persistent rag caches + return await self.rag.execute_optimized_query(query, self.context) +``` + +Mabadiliko haya ya usanifu yanatoa: +**Punguuzo la 10-20% la maswali ya hifadhidata** kwa grafu zilizo na uhusiano wa kawaida (kulinganisha na 0% kwa sasa) +**Kuondolewa kwa gharama ya ziada ya uundaji wa vitu** kwa kila ombi +**Uunganishaji wa kudumu na matumizi ya upya** kwa wateja +**Uboreshaji wa ombi hadi ombi** ndani ya vipindi vya muda wa kuhifadhi (TTL) + +**Kizuia Muhimu cha Utangamano wa Kumbukumbu:** +Uhifadhi wa muda mrefu unaweza kusababisha data kuwa potofu wakati vitu/lebo zinafutwa au kubadilishwa katika grafu iliyoko. Kumbukumbu ya LRU yenye TTL hutoa usawa kati ya faida za utendaji na usafi wa data, lakini haiwezi kuchunguza mabadiliko ya grafu ya wakati halisi. + +#### Awamu ya 1: Uboreshaji wa Ufuatiliaji wa Grafu + +**Matatizo ya Utendaji wa Sasa:** +```python +# INEFFICIENT: 3 queries per entity per level +async def follow_edges(self, ent, subgraph, path_length): + # Query 1: s=ent, p=None, o=None + res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit) + # Query 2: s=None, p=ent, o=None + res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit) + # Query 3: s=None, p=None, o=ent + res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit) +``` + +**Utekelezaji Ulioboreshwa:** +```python +async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]: + visited = set() + current_level = set(entities) + subgraph = set() + + for depth in range(max_depth): + if not current_level or len(subgraph) >= self.max_subgraph_size: + break + + # Batch all queries for current level + batch_queries = [] + for entity in current_level: + if entity not in visited: + batch_queries.extend([ + TripleQuery(s=entity, p=None, o=None), + TripleQuery(s=None, p=entity, o=None), + TripleQuery(s=None, p=None, o=entity) + ]) + + # Execute all queries concurrently + results = await self.execute_batch_queries(batch_queries) + + # Process results and prepare next level + next_level = set() + for result in results: + subgraph.update(result.triples) + next_level.update(result.new_entities) + + visited.update(current_level) + current_level = next_level - visited + + return subgraph +``` + +#### Awamu ya 2: Utatuzi wa Lebo Sambamba + +**Utendaji wa Sasa wa Mfululizo:** +```python +# INEFFICIENT: Sequential processing +for edge in subgraph: + s = await self.maybe_label(edge[0]) # Individual query + p = await self.maybe_label(edge[1]) # Individual query + o = await self.maybe_label(edge[2]) # Individual query +``` + +**Utekelezaji Ufuatao Mfumo Sambamba Uliorekebishwa:** +```python +async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: + # Collect all unique entities needing labels + entities_to_resolve = set() + for s, p, o in subgraph: + entities_to_resolve.update([s, p, o]) + + # Remove already cached entities + uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache] + + # Batch query for all uncached labels + if uncached_entities: + label_results = await self.batch_label_query(uncached_entities) + self.label_cache.update(label_results) + + # Apply labels to subgraph + return [ + (self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o)) + for s, p, o in subgraph + ] +``` + +#### Awamu ya 3: Mkakati wa Kupanua Data (Caching) wa Juu + +**Kupanua Data (Cache) la LRU pamoja na TTL:** ```python class LRUCacheWithTTL: def __init__(self, max_size: int, default_ttl: int = 3600): @@ -149,92 +451,179 @@ class LRUCacheWithTTL: self.access_times[key] = time.time() ``` -#### 5. **Uboreshaji wa Swali na Ufuatiliaji** -- **Ukusanyaji wa Metriki za Utendaji**: -- **Upekuzi na Muda**: -- **Usimamizi wa Rasilimali**: -- **Ufuatiliaji**: +#### Awamu ya 4: Ubora wa Ufuatiliaji na Ufuatiliaji -**Muda wa Majibu**: -- Ufuatiliaji wa utendaji wa GraphRAG -- Ufuatiliaji wa maswali ya database -- Ufuatiliaji wa matumizi ya kumbukumbu -- Ufuatiliaji wa utekelezaji wa maombi +**Ukusanyaji wa Vipimo vya Utendaji:** +```python +@dataclass +class PerformanceMetrics: + total_queries: int + cache_hits: int + cache_misses: int + avg_response_time: float + subgraph_construction_time: float + label_resolution_time: float + total_entities_processed: int + memory_usage_mb: float +``` -## Mkakati wa Kujaribu +**Mipangilio ya Muda wa Muda na Mfumo wa Kuzuia:** +```python +async def execute_with_timeout(self, query_func, timeout: int = 30): + try: + return await asyncio.wait_for(query_func(), timeout=timeout) + except asyncio.TimeoutError: + logger.error(f"Query timeout after {timeout}s") + raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s") +``` -### Kujaribu Kawaida -- Kujaribu sehemu kwa sehemu kwa utafutaji, caching, na utatuzi wa lebo -- Ujaribu bandia wa mashambulio ya database kwa utendaji -- Kujaribu cache ya uondoshaji na utekelezaji wa TTL -- Kujaribu utunzaji na muda wa makosa +## Mawasilisho ya Ulinganishaji wa Kumbukumbu (Cache) -### Kujaribu Kuunganisha -- Kujaribu swali la GraphRAG kamili na uboreshaji -- Kujaribu mashambulio ya database ya kweli -- Kujaribu uendeshaji sambamba na usimamizi wa rasilimali -- Kujaribu ugunduzi na usimamizi wa rasilimali -- Kujaribu utangamano na API iliyopo ya GraphRAG -- Kujaribu na nyuma tofauti za database -- Kuhakikisha usahihi wa matokeo ikilinganisha na utumizi wa sasa +**Ulinganishaji wa Uharibifu wa Data:** +**Kumbukumbu ya lebo (TTL ya dakika 5)**: Hatari ya kuonyesha lebo za vitu ambazo zimefutwa/kubadilishwa +**Hakuna uwekaji kumbukumbu wa embeddings**: Haihitajiki - embeddings tayari zimehifadhiwa kwa kila swali +**Hakuna uwekaji kumbukumbu wa matokeo**: Inazuia matokeo ya subgrafu ya zamani kutoka kwa vitu/uhusiano ambao wamefutwa -### Kujaribu Utendaji -- Kujaribu utendaji dhidi ya utumizi wa sasa -- Kujaribu mzigo kwa saizi tofauti na utata wa grafu -- Kujaribu shinikizo kwa mipaka ya kumbukumbu na muunganisho -- Kujaribu utangamano kwa uboreshaji wa utendaji +**Mikakati ya Kupunguza Madhara:** +**Manufaa ya TTL ya kihafidhia:** Kusawazisha faida za utendaji (10-20%) na usafi wa data +**Viunganishi vya kutengua kumbukumbu:** Uunganishi wa hiari na matukio ya mabadiliko ya grafu +**Dashibodi za ufuatiliaji:** Kufuatilia viwango vya hit ya kumbukumbu dhidi ya matukio ya usafi +**Mawasilisho ya kumbukumbu yanayoweza kusanidi:** Kuruhusu urekebishaji kwa kila usakinishaji kulingana na masafa ya mabadiliko -### Kujaribu Utangamano -- Hakikisha utangamano wa API ya GraphRAG iliyopo -- Jaribu na nyuma tofauti za database -- Hakikisha usahihi wa matokeo ikilinganisha na utumizi wa sasa +**Mawasilisho Yanayopendekezwa ya Kumbukumbu Kulingana na Kasi ya Mabadiliko ya Grafu:** +**Mabadiliko ya juu (>100 mabadiliko/saa)**: TTL=60s, saizi ndogo za kumbukumbu +**Mabadiliko ya wastani (10-100 mabadiliko/saa)**: TTL=300s (ya kawaida) +**Mabadiliko ya chini (<10 mabadiliko/saa)**: TTL=600s, saizi kubwa za kumbukumbu -## Mpango wa Utekelezaji +## Mawasilisho ya Usalama -### Njia ya Utekelezaji Moja kwa Moja -Kwa kuwa API zinaidhinishwa kubadilika, implement uboreshaji moja kwa moja bila utata wa uhamishaji: +**Kuzuia Uingizwaji wa Swali:** +Thibitisha kitambulisho vyote vya vitu na vigezo vya swali +Tumia maswali yaliyoparametishwa kwa mwingiliano wote wa hifadhidata +Tekeleza mipaka ya utata wa swali ili kuzuia mashambulizi ya aina ya kukataa huduma (DoS) -1. **Badilisha njia ya `follow_edges`**: Andika upya na utafutaji ulioidhinishwa wa kikundi -2. **Boresha `get_labelgraph`**: Implement utatuzi sambamba wa lebo -3. **Ongeza GraphRag ya muda mrefu**: Badilisha Processor ili itumie instance ya GraphRag iliyodumu -4. **Implement cache ya lebo**: Ongeza safu ya caching kwenye darasa la GraphRag +**Ulinzi wa Rasilimali:** +Enforce mipaka ya juu ya saizi ya subgrafu +Tekeleza muda wa mwisho wa swali ili kuzuia kutokuwa na rasilimali +Ongeza ufuatiliaji na mipaka ya matumizi ya kumbukumbu -### Nguvu ya Marekebisho -- **Darasa la swali**: Badilisha ~50 mistari katika `follow_edges`, ongeza ~30 mistari ya utunzaji wa kikundi -- **Darasa la GraphRag**: Ongeza safu ya caching (~40 mistari) -- **Darasa la Processor**: Badilisha ili utumie instance ya GraphRag iliyodumu (~20 mistari) -- **Jumla**: ~140 mistari ya mabadiliko iliyolengwa, haswa ndani ya madarasa yaliyopo +**Kidhibiti cha Ufikiaji:** +Endeleza kutengwa kwa watumiaji na ukusanyaji iliyopo +Ongeza uandikaji wa ukaguzi kwa operesheni zinazoathiri utendaji +Tekeleza kikomo cha kiwango kwa operesheni ghali + +## Mawasilisho ya Utendaji + +### Maboresho Yanayotarajiwa ya Utendaji + +**Upunguzaji wa Swali:** +Sasa: ~9,000+ maswali kwa ombi la kawaida +Yaliyoboreshwa: ~50-100 maswali yaliyunganishwa (upunguzaji wa 98%) + +**Maboresho ya Muda wa Jibu:** +Ufuatiliaji wa grafu: 15-20s → 3-5s (haraka 4-5x) +Utatuzi wa lebo: 8-12s → 2-4s (haraka 3x) +Swali kamili: 25-35s → 6-10s (maboresho ya 3-4x) + +**Ufanisi wa Kumbukumbu:** +Saizi zilizokadiriwa za kumbukumbu inazuia uvujaji wa kumbukumbu +Miundo ya data inayofaa hupunguza athari ya kumbukumbu kwa ~40% +Urekebishaji wa taka bora kupitia usafi sahihi wa rasilimali + +**Mataifa ya Kweli ya Utendaji:** +**Kumbukumbu ya lebo**: Upunguzaji wa 10-20% wa swali kwa grafu zilizo na uhusiano wa kawaida +**Uboreshaji wa uunganisho**: Upunguzaji wa 50-80% wa swali (uboresho mkuu) +**Uboreshaji wa maisha ya kitu**: Ondoa gharama ya kila ombi +**Maboresho ya jumla**: Maboresho ya 3-4x ya muda wa jibu hasa kutoka kwa uunganisho + +**Maboresho ya Uwezo wa Kupanuka:** +Usaidizi wa grafu za maarifa kubwa 3-5x (vikomo na mahitaji ya ulinganishaji wa utendaji) +Uwezo wa juu 3-5x wa ombi la wakati mmoja +Matumizi bora ya rasilimali kupitia matumizi ya upya ya muunganisho + +### Ufuatiliaji wa Utendaji + +**Hesabu za Muda Halisi:** +Muda wa utekelezaji wa swali kwa aina ya operesheni +Viwango vya hit na ufanisi wa kumbukumbu +Matumizi ya kikundi cha muunganisho wa hifadhidata +Matumizi ya kumbukumbu na athari ya urekebishaji wa taka + +**Ufuatiliaji wa Utendaji:** +Mtihirika wa kiotomatiki wa utendaji +Mtihirika wa mzigo ukitumia data halisi +Viwango vya utendaji dhidi ya utekelezaji wa sasa + +## Mkakati wa Mtihirika + +### Mtihirika wa Vitengo +Mtihirika wa vipengele vya mtu binafsi kwa ajili ya utekelezaji, kuhifadhi, na utatuzi wa lebo +Mwingiliano wa bandarini ya bandarini kwa ajili ya mtihirika wa utendaji +Mtihirika wa kuondoa data kutoka kwa kumbukumbu na muda wa kumalizika +Usimamizi wa makosa na hali za muda + +### Mtihirika wa Uunganisho +Mtihirika wa mwisho hadi mwisho wa swali la GraphRAG ukiwa na uboreshaji +Mtihirika wa mwingiliano wa bandarini ya bandarini ukitumia data halisi +Usimamizi wa ombi la wakati mmoja na rasilimali +Udagano wa uvujaji wa kumbukumbu na uthibitisho wa kusafisha rasilimali + +### Mtihirika wa Utendaji +Mtihirika dhidi ya utekelezaji wa sasa +Mtihirika wa mzigo ukitumia saizi na utata tofauti wa grafu +Mtihirika wa shinikizo kwa mipaka ya kumbukumbu na uunganisho +Mtihirika wa utendaji kwa uboreshaji + +### Mtihirika wa Ulinganishi +Thibitisha ulinganishi wa API ya GraphRAG iliyopo +Mtihirika ukitumia bandarini ya bandarini tofauti za bandarini ya grafu +Thibitisha usahihi wa matokeo ikilinganishwa na utekelezaji wa sasa + +## Mpango wa Utendaji + +### Mbinu ya Utendaji Moja kwa Moja +Kwa kuwa API zinaweza kubadilika, tekeleza uboreshaji moja kwa moja bila utata wa uhamishaji: + +1. **Badilisha `follow_edges` mbinu**: Andika upya ukitumia utekelezaji wa kikundi +2. **Boresha `get_labelgraph`**: Tepeleza utatuzi wa lebo kwa wingi +3. **Ongeza GraphRag ya muda mrefu**: Badilisha Processor ili kudumisha mfano wa kudumu +4. **Tepeleza uhifadhi wa lebo**: Ongeza kumbukumbu ya LRU na TTL kwa darasa la GraphRag + +### Wigo wa Mabadiliko +**Darasa la swali**: Badilisha mistari ~50 katika `follow_edges`, ongeza mistari ~30 ya utunzaji wa kikundi +**Darasa la GraphRag**: Ongeza safu ya kuhifadhi (~mistari 40) +**Darasa la Processor**: Badilisha ili kutumia mfano wa kudumu wa GraphRag (~mistari 20) +**Jumla**: ~mistari 140 ya mabadiliko, hasa ndani ya madarasa yaliyopo ## Ratiba -**Wiki ya 1: Utumizi wa Msingi** -- Badilisha `follow_edges` na utafutaji wa kikundi wa iterative -- Implement utatuzi wa sambamba wa lebo katika `get_labelgraph` -- Ongeza instance ya GraphRag iliyodumu kwa Processor -- Implement safu ya caching ya lebo +**Wiki ya 1: Utendaji wa Msingi** +Badilisha `follow_edges` ukitumia utekelezaji wa kikundi +Tepeleza utatuzi wa lebo kwa wingi katika `get_labelgraph` +Ongeza mfano wa GraphRag wa muda mrefu kwa Processor +Tepeleza safu ya uhifadhi -**Wiki ya 2: Kujaribu na Kuunganisha** -- Kujaribu kawaida kwa mantiki mpya ya utafutaji na caching -- Kujaribu utendaji dhidi ya utumizi wa sasa -- Kujaribu kuunganisha na data ya grafu ya kweli -- Tathmini ya msimamizi wa msimamizi wa msimamizi wa msimamizi wa msimamizi -- Kujaribu utangamano +**Wiki ya 2: Mtihirika na Uunganisho** +Mtihirika wa vitengo kwa ajili ya utekelezaji mpya wa utekelezaji na uhifadhi +Ufuatiliaji wa utendaji dhidi ya utekelezaji wa sasa +Mtihirika wa uunganisho ukitumia data halisi ya grafu +Mtihirika wa msimamizi na uboreshaji **Wiki ya 3: Utekelezaji** -- Tepeleza utumizi uliorekebishwa -- Fuatilia uboreshaji wa utendaji -- Rekebisha TTL ya cache na saizi za kikundi kulingana na matumizi halisi +Tepeleza utekelezaji ulioboreshwa +Fuatilia uboreshaji wa utendaji +Punguza muda wa TTL wa kumbukumbu na saizi za kikundi kulingana na matumizi halisi -## Maswali Yaliyofungwa +## Maswali ya Funguo -- **Pooli ya Muunganisho wa Database**: Je, tunapaswa kutumia pooli ya muunganisho ya database maalum au kutegemea pooli ya mteja wa database iliyopo? -- **Usaidizi wa Kumbukumbu**: Je, cache ya lebo na ya embedding inapaswa kuendelea katika kuchelewesha huduma? -- **Kumbukumbu Iliyosambaa**: Kwa usimamizi wa idadi nyingi, je, tunapaswa kutumia kumbukumbu iliyosambaa kwa Redis/Memcached? -- **Umbizo la Matokeo ya Swali**: Je, tunapaswa kuongeza ufanisi wa uwakilishi wa ndani wa triple kwa ufanisi bora wa kumbukumbu? -- **Uunganisho wa Ufuatiliaji**: Metriki gani zinapaswa kuonyeshwa kwenye mifumo ya ufuatiliaji iliyopo (Prometheus, n.k.)? +**Uunganisho wa Bandarini**: Je, tunapaswa kutekeleza uunganisho wa bandarini maalum au kutegemea uunganisho wa bandarini wa bandarini ya bandarini iliyopo? +**Ukurasa wa Kumbukumbu**: Je, kumbukumbu za lebo na uwekaji wa kumbukumbu zinapaswa kudumu katika kuanzishwa upya za huduma? +**Ukurasa Uliogawanyika**: Kwa matoleo mengi, je, tunapaswa kutekeleza ukurasa uliogawanyika ukitumia Redis/Memcached? +**Muundo wa Matokeo ya Swali**: Je, tunapaswa kuboresha uwakilishi wa ndani wa triple ili kuboresha ufanisi wa kumbukumbu? +**Uunganisho wa Ufuatiliaji**: Vipimo vipi vinapaswa kuonyeshwa kwa mifumo ya ufuatiliaji iliyopo (Prometheus, n.k.)? ## Marejeleo -- [Utekelezaji wa awali wa GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) -- [Kanuni za Usanifu za TrustGraph](architecture-principles.md) -- [Maelezo ya Usimamizi wa Mkusanyiko](collection-management.md) \ No newline at end of file +[Utekelezaji Asili wa GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +[Kanuni za Usanifu wa TrustGraph](architecture-principles.md) +[Maelekezo ya Usimamizi wa Mkusanyiko](collection-management.md) diff --git a/docs/tech-specs/graphrag-performance-optimization.tr.md b/docs/tech-specs/graphrag-performance-optimization.tr.md new file mode 100644 index 00000000..bdb1d687 --- /dev/null +++ b/docs/tech-specs/graphrag-performance-optimization.tr.md @@ -0,0 +1,629 @@ +# GraphRAG Performans Optimizasyonu Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph'taki GraphRAG (Graf Çıkarım Destekli Üretim) algoritması için kapsamlı performans iyileştirmelerini açıklamaktadır. Mevcut uygulama, ölçeklenebilirliği ve yanıt sürelerini sınırlayan önemli performans darboğazlarına sahiptir. Bu özellik, dört birincil optimizasyon alanını ele almaktadır: + +1. **Graf Gezinme Optimizasyonu**: Verimsiz yinelemeli veritabanı sorgularını ortadan kaldırın ve toplu grafik keşfi uygulayın. +2. **Etiket Çözümleme Optimizasyonu**: Sıralı etiket alma işlemlerini, paralel/toplu işlemlere dönüştürün. +3. **Önbellekleme Stratejisi İyileştirmesi**: LRU (En Son Kullanılmayan) çıkarma ve ön yükleme ile akıllı bir önbellekleme uygulayın. +4. **Sorgu Optimizasyonu**: İyileştirilmiş yanıt süreleri için sonuç memoizasyonu ve gömme önbelleği ekleyin. + +## Hedefler + +**Veritabanı Sorgusu Hacmini Azaltın**: Toplu işleme ve önbellekleme yoluyla toplam veritabanı sorgularında %50-80'lik bir azalma elde edin. +**Yanıt Sürelerini İyileştirin**: Alt grafik oluşturma için 3-5 kat daha hızlı ve etiket çözümleme için 2-3 kat daha hızlı hedefleyin. +**Ölçeklenebilirliği Artırın**: Daha iyi bellek yönetimi ile daha büyük bilgi grafiklerini destekleyin. +**Doğruluğu Koruyun**: Mevcut GraphRAG işlevselliğini ve sonuç kalitesini koruyun. +**Eşzamanlılığı Etkinleştirin**: Çoklu eşzamanlı istekler için paralel işleme yeteneklerini iyileştirin. +**Bellek Ayak İzini Azaltın**: Verimli veri yapıları ve bellek yönetimi uygulayın. +**Gözlemlenebilirliği Ekleyin**: Performans ölçümleri ve izleme yetenekleri ekleyin. +**Güvenilirliği Sağlayın**: Uygun hata işleme ve zaman aşımı mekanizmaları ekleyin. + +## Arka Plan + +`trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` içindeki mevcut GraphRAG uygulaması, sistem ölçeklenebilirliğini önemli ölçüde etkileyen çeşitli kritik performans sorunları sergilemektedir: + +### Mevcut Performans Sorunları + +**1. Verimsiz Graf Gezinme (`follow_edges` fonksiyonu, 79-127 satırlar)** +Her varlık için her derinlik seviyesinde 3 ayrı veritabanı sorgusu yapar. +Sorgu kalıbı: Her varlık için konu tabanlı, öznelik tabanlı ve nesne tabanlı sorgular. +Toplu işleme yok: Her sorgu yalnızca bir varlığı işler. +Döngü algılama yok: Aynı düğümlere birden çok kez geri dönülebilir. +Memoizasyon olmadan yinelemeli uygulama, üstel karmaşıklığa yol açar. +Zaman karmaşıklığı: O(varlıklar × max_path_length × triple_limit³) + +**2. Sıralı Etiket Çözümleme (`get_labelgraph` fonksiyonu, 144-171 satırlar)** +Her üç bileşenli (konu, öznelik, nesne) üçlü öğeyi sırasıyla işler. +Her `maybe_label` çağrısı potansiyel olarak bir veritabanı sorgusu tetikler. +Etiket sorgularının paralel yürütülmesi veya toplu işlenmesi yoktur. +subgraph_size × 3 adet ayrı veritabanı çağrısına yol açar. + +**3. Basit Önbellekleme Stratejisi (`maybe_label` fonksiyonu, 62-77 satırlar)** +Boyut sınırları veya TTL (Yaşam Süresi) olmadan basit bir sözlük önbelleği. +Önbellek çıkarma politikası olmaması, sınırsız bellek büyümesine yol açar. +Önbellek hataları, ayrı veritabanı sorgularını tetikler. +Ön yükleme veya akıllı önbellek önleme yoktur. + +**4. Alt Optimum Sorgu Kalıpları** +Benzer istekler arasında varlık vektör benzerliği sorguları önbelleğe alınmaz. +Tekrarlayan sorgu kalıpları için sonuç memoizasyonu yoktur. +Yaygın erişim kalıpları için sorgu optimizasyonu eksiktir. + +**5. Kritik Nesne Ömrü Sorunları (`rag.py:96-102`)** +**GraphRag nesnesi her istek için yeniden oluşturulur**: Her sorgu için yeni bir örnek oluşturulur, böylece tüm önbellek avantajları kaybolur. +**Sorgu nesnesi son derece kısa ömürlüdür**: Tek bir sorgu yürütmesi içinde oluşturulur ve yok edilir (201-207 satırlar). +**Etiket önbelleği her istek için sıfırlanır**: Önbellek önleme ve birikmiş bilgi istekler arasında kaybolur. +**İstemci yeniden oluşturma ek yükü**: Veritabanı istemcileri potansiyel olarak her istek için yeniden oluşturulur. +**İstekler arası optimizasyon yok**: Sorgu kalıplarından veya sonuç paylaşımından yararlanamaz. + +### Performans Etki Analizi + +Tipik bir sorgu için mevcut en kötü senaryo: +**Varlık Alma**: 1 vektör benzerliği sorgusu. +**Graf Gezinme**: varlıklar × max_path_length × 3 × triple_limit sorgusu. +**Etiket Çözümleme**: subgraph_size × 3 adet ayrı etiket sorgusu. + +Varsayılan parametreler için (50 varlık, yol uzunluğu 2, 30 üçlü sınırı, 150 alt grafik boyutu): +**Minimum sorgular**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9.451 veritabanı sorgusu** +**Yanıt süresi**: Orta büyüklükteki grafikler için 15-30 saniye +**Bellek kullanımı**: Zamanla sınırsız önbellek büyümesi +**Önbellek etkinliği**: %0 - her istekte önbellekler sıfırlanır +**Nesne oluşturma ek yükü**: Her istek için oluşturulan/silinen GraphRag + Sorgu nesneleri + +Bu özellik, toplu sorguları, akıllı önbelleği ve paralel işleme uygulayarak bu eksiklikleri giderir. Sorgu kalıplarını ve veri erişimini optimize ederek TrustGraph şunları yapabilir: +Milyonlarca varlığa sahip kurumsal ölçekli bilgi grafiklerini destekleyin +Tipik sorgular için saniyeden daha kısa yanıt süreleri sağlayın +Yüzlerce eşzamanlı GraphRAG isteğini işleyin +Grafik boyutu ve karmaşıklığıyla verimli bir şekilde ölçeklendirin + +## Teknik Tasarım + +### Mimari + +GraphRAG performans optimizasyonu, aşağıdaki teknik bileşenleri gerektirir: + +#### 1. **Nesne Ömrü Mimari Yeniden Düzenlemesi** + **GraphRag'i uzun ömürlü hale getirin**: GraphRag örneğini, istekler arasında süreklilik sağlamak için İşlemci seviyesine taşıyın + **Önbellekleri koruyun**: Etiket önbelleğini, gömme önbelleğini ve sorgu sonucu önbelleğini istekler arasında koruyun + **Sorgu nesnesini optimize edin**: Sorguyu, veri kapsayıcısı değil, hafif bir yürütme bağlamı olarak yeniden düzenleyin + **Bağlantı sürekliliği**: Veritabanı istemci bağlantılarını istekler arasında koruyun + + Modül: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (değiştirildi) + +#### 2. **Optimize Edilmiş Grafik Gezinme Motoru** + Özyinelemeli `follow_edges`'ı yinelemeli genişlik öncelikli arama ile değiştirin + Her gezinme seviyesinde toplu varlık işleme uygulayın + Ziyaret edilen düğüm takibi kullanarak döngü algılama ekleyin + Sınırlar aşıldığında erken sonlandırma ekleyin + + Modül: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` + +#### 3. **Paralel Etiket Çözümleme Sistemi** + Birden çok varlık için etiket sorgularını aynı anda toplu olarak sorgulayın + Eşzamanlı veritabanı erişimi için asenkron/bekle kalıplarını uygulayın + Yaygın etiket kalıpları için akıllı ön yükleme ekleyin + Etiket önbelleği ısıtma stratejileri ekleyin + + Modül: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` + +#### 4. **Muhafazakar Etiket Önbelleği Katmanı** + Performans ve tutarlılık dengesini sağlamak için yalnızca etiketler için kısa TTL'ye sahip LRU önbelleği (5 dakika) + Önbellek metriklerini ve isabet oranını izleme + **Gömme önbelleği yok**: Zaten her sorgu için önbelleğe alınmıştır, sorgular arası bir fayda yoktur + **Sorgu sonucu önbelleği yok**: Grafik mutasyon tutarlılığı endişeleri nedeniyle + + Modül: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` + +#### 5. **Sorgu Optimizasyon Çerçevesi** + Sorgu kalıbı analizi ve optimizasyon önerileri + Veritabanı erişimi için toplu sorgu koordinatörü + Bağlantı havuzu ve sorgu zaman aşımı yönetimi + Performans izleme ve ölçüm toplama + + Modül: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` + +### Veri Modelleri + +#### Optimize Edilmiş Grafik Gezinme Durumu + +Gezinme motoru, gereksiz işlemleri önlemek için durumu korur: + +```python +@dataclass +class TraversalState: + visited_entities: Set[str] + current_level_entities: Set[str] + next_level_entities: Set[str] + subgraph: Set[Tuple[str, str, str]] + depth: int + query_batch: List[TripleQuery] +``` + +Bu yaklaşım şunları sağlar: +Ziyaret edilen varlıkları takip ederek verimli döngü tespiti +Her gezinme seviyesinde toplu sorgu hazırlama +Bellek verimli durum yönetimi +Boyut limitlerine ulaşıldığında erken sonlandırma + +#### Gelişmiş Önbellek Yapısı + +```python +@dataclass +class CacheEntry: + value: Any + timestamp: float + access_count: int + ttl: Optional[float] + +class CacheManager: + label_cache: LRUCache[str, CacheEntry] + embedding_cache: LRUCache[str, CacheEntry] + query_result_cache: LRUCache[str, CacheEntry] + cache_stats: CacheStatistics +``` + +#### Toplu Sorgu Yapıları + +```python +@dataclass +class BatchTripleQuery: + entities: List[str] + query_type: QueryType # SUBJECT, PREDICATE, OBJECT + limit_per_entity: int + +@dataclass +class BatchLabelQuery: + entities: List[str] + predicate: str = LABEL +``` + +### API'ler + +#### Yeni API'ler: + +**GraphTraversal API'si** +```python +async def optimized_follow_edges_batch( + entities: List[str], + max_depth: int, + triple_limit: int, + max_subgraph_size: int +) -> Set[Tuple[str, str, str]] +``` + +**Toplu Etiket Çözümleme API'si** +```python +async def resolve_labels_batch( + entities: List[str], + cache_manager: CacheManager +) -> Dict[str, str] +``` + +**Önbellek Yönetimi API'si** +```python +class CacheManager: + async def get_or_fetch_label(self, entity: str) -> str + async def get_or_fetch_embeddings(self, query: str) -> List[float] + async def cache_query_result(self, query_hash: str, result: Any, ttl: int) + def get_cache_statistics(self) -> CacheStatistics +``` + +#### Değiştirilmiş API'ler: + +**GraphRag.query()** - Performans optimizasyonlarıyla geliştirildi: +Önbellek kontrolü için `cache_manager` parametresi eklendi. +Performans metriklerini içeren `performance_metrics` dönüş değeri eklendi. +Güvenilirlik için `query_timeout` parametresi eklendi. + +**Query sınıfı** - Toplu işleme için yeniden düzenlendi: +Bireysel varlık işleme yerine toplu işlemler kullanıldı. +Kaynak temizliği için asenkron bağlam yöneticileri eklendi. +Uzun süren işlemler için ilerleme geri çağırmaları eklendi. + +### Uygulama Detayları + +#### Aşama 0: Kritik Mimari Yaşam Döngüsü Yeniden Düzenlemesi + +**Mevcut Sorunlu Uygulama:** +```python +# INEFFICIENT: GraphRag recreated every request +class Processor(FlowProcessor): + async def on_request(self, msg, consumer, flow): + # PROBLEM: New GraphRag instance per request! + self.rag = GraphRag( + embeddings_client = flow("embeddings-request"), + graph_embeddings_client = flow("graph-embeddings-request"), + triples_client = flow("triples-request"), + prompt_client = flow("prompt-request"), + verbose=True, + ) + # Cache starts empty every time - no benefit from previous requests + response = await self.rag.query(...) + +# VERY SHORT-LIVED: Query object created/destroyed per request +class GraphRag: + async def query(self, query, user="trustgraph", collection="default", ...): + q = Query(rag=self, user=user, collection=collection, ...) # Created + kg = await q.get_labelgraph(query) # Used briefly + # q automatically destroyed when function exits +``` + +**Optimize Edilmiş, Uzun Ömürlü Mimari:** +```python +class Processor(FlowProcessor): + def __init__(self, **params): + super().__init__(**params) + self.rag_instance = None # Will be initialized once + self.client_connections = {} + + async def initialize_rag(self, flow): + """Initialize GraphRag once, reuse for all requests""" + if self.rag_instance is None: + self.rag_instance = LongLivedGraphRag( + embeddings_client=flow("embeddings-request"), + graph_embeddings_client=flow("graph-embeddings-request"), + triples_client=flow("triples-request"), + prompt_client=flow("prompt-request"), + verbose=True, + ) + return self.rag_instance + + async def on_request(self, msg, consumer, flow): + # REUSE the same GraphRag instance - caches persist! + rag = await self.initialize_rag(flow) + + # Query object becomes lightweight execution context + response = await rag.query_with_context( + query=v.query, + execution_context=QueryContext( + user=v.user, + collection=v.collection, + entity_limit=entity_limit, + # ... other params + ) + ) + +class LongLivedGraphRag: + def __init__(self, ...): + # CONSERVATIVE caches - balance performance vs consistency + self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness + # Note: No embedding cache - already cached per-query, no cross-query benefit + # Note: No query result cache due to consistency concerns + self.performance_metrics = PerformanceTracker() + + async def query_with_context(self, query: str, context: QueryContext): + # Use lightweight QueryExecutor instead of heavyweight Query object + executor = QueryExecutor(self, context) # Minimal object + return await executor.execute(query) + +@dataclass +class QueryContext: + """Lightweight execution context - no heavy operations""" + user: str + collection: str + entity_limit: int + triple_limit: int + max_subgraph_size: int + max_path_length: int + +class QueryExecutor: + """Lightweight execution context - replaces old Query class""" + def __init__(self, rag: LongLivedGraphRag, context: QueryContext): + self.rag = rag + self.context = context + # No heavy initialization - just references + + async def execute(self, query: str): + # All heavy lifting uses persistent rag caches + return await self.rag.execute_optimized_query(query, self.context) +``` + +Bu mimari değişiklik şunları sağlar: +**Ortak ilişkileri olan grafikler için veritabanı sorgu sayısında %10-20'lik bir azalma** (şu anda %0'a kıyasla) +Her istek için **ortadan kaldırılan nesne oluşturma ek yükü** +**Sürekli bağlantı havuzu** ve istemci yeniden kullanımı +Önbellek TTL (Yaşam Süresi) aralıkları içinde **istemler arası optimizasyon** + +**Önemli Önbellek Tutarlılık Sınırlaması:** +Uzun süreli önbellekleme, temel grafikteki varlıkların/etiketlerin silindiği veya değiştirildiği durumlarda, güncelliği kaybetme riski oluşturur. LRU (En Son Kullanılmayan) önbelleği, performans kazanımları ile veri tazeliği arasında bir denge sağlarken, gerçek zamanlı grafik değişikliklerini tespit edemez. + +#### 1. Aşama: Grafik Gezinme Optimizasyonu + +**Mevcut Uygulama Sorunları:** +```python +# INEFFICIENT: 3 queries per entity per level +async def follow_edges(self, ent, subgraph, path_length): + # Query 1: s=ent, p=None, o=None + res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit) + # Query 2: s=None, p=ent, o=None + res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit) + # Query 3: s=None, p=None, o=ent + res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit) +``` + +**Optimize Edilmiş Uygulama:** +```python +async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]: + visited = set() + current_level = set(entities) + subgraph = set() + + for depth in range(max_depth): + if not current_level or len(subgraph) >= self.max_subgraph_size: + break + + # Batch all queries for current level + batch_queries = [] + for entity in current_level: + if entity not in visited: + batch_queries.extend([ + TripleQuery(s=entity, p=None, o=None), + TripleQuery(s=None, p=entity, o=None), + TripleQuery(s=None, p=None, o=entity) + ]) + + # Execute all queries concurrently + results = await self.execute_batch_queries(batch_queries) + + # Process results and prepare next level + next_level = set() + for result in results: + subgraph.update(result.triples) + next_level.update(result.new_entities) + + visited.update(current_level) + current_level = next_level - visited + + return subgraph +``` + +#### 2. Aşama: Paralel Etiket Çözümlemesi + +**Mevcut Sıralı Uygulama:** +```python +# INEFFICIENT: Sequential processing +for edge in subgraph: + s = await self.maybe_label(edge[0]) # Individual query + p = await self.maybe_label(edge[1]) # Individual query + o = await self.maybe_label(edge[2]) # Individual query +``` + +**Optimize Edilmiş Paralel Uygulama:** +```python +async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: + # Collect all unique entities needing labels + entities_to_resolve = set() + for s, p, o in subgraph: + entities_to_resolve.update([s, p, o]) + + # Remove already cached entities + uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache] + + # Batch query for all uncached labels + if uncached_entities: + label_results = await self.batch_label_query(uncached_entities) + self.label_cache.update(label_results) + + # Apply labels to subgraph + return [ + (self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o)) + for s, p, o in subgraph + ] +``` + +#### 3. Aşama: Gelişmiş Önbellekleme Stratejisi + +**TTL ile LRU Önbelleği:** +```python +class LRUCacheWithTTL: + def __init__(self, max_size: int, default_ttl: int = 3600): + self.cache = OrderedDict() + self.max_size = max_size + self.default_ttl = default_ttl + self.access_times = {} + + async def get(self, key: str) -> Optional[Any]: + if key in self.cache: + # Check TTL expiration + if time.time() - self.access_times[key] > self.default_ttl: + del self.cache[key] + del self.access_times[key] + return None + + # Move to end (most recently used) + self.cache.move_to_end(key) + return self.cache[key] + return None + + async def put(self, key: str, value: Any): + if key in self.cache: + self.cache.move_to_end(key) + else: + if len(self.cache) >= self.max_size: + # Remove least recently used + oldest_key = next(iter(self.cache)) + del self.cache[oldest_key] + del self.access_times[oldest_key] + + self.cache[key] = value + self.access_times[key] = time.time() +``` + +#### 4. Aşama: Sorgu Optimizasyonu ve İzleme + +**Performans Metrikleri Toplama:** +```python +@dataclass +class PerformanceMetrics: + total_queries: int + cache_hits: int + cache_misses: int + avg_response_time: float + subgraph_construction_time: float + label_resolution_time: float + total_entities_processed: int + memory_usage_mb: float +``` + +**Sorgu Zaman Aşımı ve Devre Kesici:** +```python +async def execute_with_timeout(self, query_func, timeout: int = 30): + try: + return await asyncio.wait_for(query_func(), timeout=timeout) + except asyncio.TimeoutError: + logger.error(f"Query timeout after {timeout}s") + raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s") +``` + +## Önbellek Tutarlılık Hususları + +**Veri Güncelliği Dengesi:** +**Etiket önbelleği (5 dakika TTL):** Silinmiş/yeniden adlandırılmış varlık etiketlerini sunma riski. +**Gömme önbelleği yok:** Gerekli değil - gömmeler zaten her sorgu için önbelleğe alınmıştır. +**Sonuç önbelleği yok:** Silinmiş varlıklar/ilişkilerden kaynaklanan eski alt grafik sonuçlarını önler. + +**Azaltma Stratejileri:** +**Muhafazakar TTL değerleri:** Performans kazanımları (10-20%) ile veri güncelliği arasındaki denge. +**Önbellek geçersiz kılma kancaları:** İsteğe bağlı olarak grafik mutasyon olaylarıyla entegrasyon. +**İzleme panoları:** Önbellek isabet oranlarını, veri güncelliği sorunlarıyla karşılaştırarak izleyin. +**Yapılandırılabilir önbellek politikaları:** Mutasyon sıklığına göre dağıtıma özel ayarlamalar yapılmasına izin verir. + +**Grafik Mutasyon Oranına Göre Önerilen Önbellek Yapılandırması:** +**Yüksek mutasyon (>100 değişiklik/saat):** TTL=60s, daha küçük önbellek boyutları. +**Orta mutasyon (10-100 değişiklik/saat):** TTL=300s (varsayılan). +**Düşük mutasyon (<10 değişiklik/saat):** TTL=600s, daha büyük önbellek boyutları. + +## Güvenlik Hususları + +**Sorgu Enjeksiyonunu Önleme:** +Tüm varlık tanımlayıcılarını ve sorgu parametrelerini doğrulayın. +Tüm veritabanı etkileşimleri için parametreli sorgular kullanın. +DoS saldırılarını önlemek için sorgu karmaşıklığı limitleri uygulayın. + +**Kaynak Koruması:** +Maksimum alt grafik boyutları limitlerini uygulayın. +Kaynak tükenmesini önlemek için sorgu zaman aşımlarını uygulayın. +Bellek kullanımı izleme ve limitleri ekleyin. + +**Erişim Kontrolü:** +Mevcut kullanıcı ve koleksiyon izolasyonunu koruyun. +Performansı etkileyen işlemler için denetim kaydı ekleyin. +Pahalı işlemler için hız sınırlaması uygulayın. + +## Performans Hususları + +### Beklenen Performans İyileştirmeleri + +**Sorgu Azaltma:** +Mevcut: Tipik bir istek için ~9.000+ sorgu. +Optimize edilmiş: ~50-100 toplu sorgu (98% azalma). + +**Yanıt Süresi İyileştirmeleri:** +Grafik geçişi: 15-20s → 3-5s (4-5 kat daha hızlı). +Etiket çözümü: 8-12s → 2-4s (3 kat daha hızlı). +Genel sorgu: 25-35s → 6-10s (3-4 kat iyileşme). + +**Bellek Verimliliği:** +Sınırlı önbellek boyutları, bellek sızıntılarını önler. +Verimli veri yapıları, bellek ayak izini yaklaşık %40 azaltır. +Uygun kaynak temizliği sayesinde daha iyi çöp toplama. + +**Gerçekçi Performans Beklentileri:** +**Etiket önbelleği:** Ortak ilişkilere sahip grafikler için sorgu azaltmada %10-20. +**Toplu optimizasyon:** %50-80 sorgu azaltma (birincil optimizasyon). +**Nesne ömrü optimizasyonu:** Her istekte oluşturma ek yükünü ortadan kaldırır. +**Genel iyileşme:** Toplu işlemden kaynaklanan 3-4 kat yanıt süresi iyileşmesi. + +**Ölçeklenebilirlik İyileştirmeleri:** +3-5 kat daha büyük bilgi grafiklerini destekler (önbellek tutarlılık ihtiyaçları ile sınırlıdır). +3-5 kat daha yüksek eşzamanlı istek kapasitesi. +Bağlantı yeniden kullanımı sayesinde daha iyi kaynak kullanımı. + +### Performans İzleme + +**Gerçek Zamanlı Metrikler:** +İşlem türüne göre sorgu yürütme süreleri. +Önbellek isabet oranları ve etkinliği. +Veritabanı bağlantı havuzu kullanımı. +Bellek kullanımı ve çöp toplama etkisi. + +**Performans Karşılaştırması:** +Otomatik performans gerileme testi +Gerçekçi veri hacimleriyle yük testi +Mevcut uygulamaya karşı karşılaştırma testleri + +## Test Stratejisi + +### Birim Testi +Gezinme, önbellekleme ve etiket çözümleme için bireysel bileşen testi +Performans testi için sahte veritabanı etkileşimleri +Önbellek temizleme ve TTL (Yaşam Süresi) sonlandırma testi +Hata işleme ve zaman aşımı senaryoları + +### Entegrasyon Testi +Optimizasyonlarla uçtan uca GraphRAG sorgu testi +Gerçek verilerle veritabanı etkileşim testi +Eşzamanlı istek işleme ve kaynak yönetimi +Bellek sızıntısı tespiti ve kaynak temizleme doğrulaması + +### Performans Testi +Mevcut uygulamaya karşı karşılaştırma testi +Farklı grafik boyutları ve karmaşıklıklarla yük testi +Bellek ve bağlantı limitleri için stres testi +Performans iyileştirmeleri için regresyon testi + +### Uyumluluk Testi +Mevcut GraphRAG API uyumluluğunu doğrulayın +Çeşitli grafik veritabanı arka uçlarıyla test yapın +Mevcut uygulamaya kıyasla sonuç doğruluğunu doğrulayın + +## Uygulama Planı + +### Doğrudan Uygulama Yaklaşımı +API'lerin değişmesine izin verildiğinden, geçiş karmaşıklığı olmadan doğrudan optimizasyonları uygulayın: + +1. **`follow_edges` yöntemini değiştirin**: Yinelemeli toplu işleme ile yeniden yazın +2. **`get_labelgraph`'ı optimize edin**: Paralel etiket çözümlemeyi uygulayın +3. **Uzun ömürlü GraphRag ekleyin**: Kalıcı bir örnek tutmak için İşlemci'yi değiştirin +4. **Etiket önbelleğini uygulayın**: GraphRag sınıfına TTL ile LRU (En Son Kullanılan) önbelleği ekleyin + +### Değişiklik Kapsamı +**Sorgu sınıfı**: `follow_edges` içinde ~50 satırı değiştirin, toplu işleme için ~30 satır ekleyin +**GraphRag sınıfı**: Önbellekleme katmanı ekleyin (~40 satır) +**İşlemci sınıfı**: Kalıcı bir GraphRag örneği kullanmak için değiştirin (~20 satır) +**Toplam**: Odaklanmış değişikliklerin ~140 satırı, çoğunlukla mevcut sınıfların içinde + +## Zaman Çizelgesi + +**1. Hafta: Temel Uygulama** +`follow_edges`'ı toplu yinelemeli gezinmeyle değiştirin +`get_labelgraph` içinde paralel etiket çözümlemeyi uygulayın +İşlemci'ye uzun ömürlü GraphRag örneği ekleyin +Etiket önbellekleme katmanı uygulayın + +**2. Hafta: Test ve Entegrasyon** +Yeni gezinme ve önbellekleme mantığı için birim testleri +Mevcut uygulamaya karşı performans karşılaştırması +Gerçek grafik verileriyle entegrasyon testi +Kod incelemesi ve optimizasyon + +**3. Hafta: Dağıtım** +Optimize edilmiş uygulamayı dağıtın +Performans iyileştirmelerini izleyin +Gerçek kullanım temelinde önbellek TTL'sini ve toplu boyutları ayarlayın + +## Açık Sorular + +**Veritabanı Bağlantı Havuzu**: Özel bir bağlantı havuzu mu uygulamalıyız yoksa mevcut veritabanı istemci havuzuna mı güvenmeliyiz? +**Önbellek Kalıcılığı**: Etiket ve gömme önbellekleri hizmet yeniden başlatmalarında kalıcı mı olmalı? +**Dağıtılmış Önbellekleme**: Çok örnekli dağıtımlar için Redis/Memcached ile dağıtılmış önbellekleme mi uygulamalıyız? +**Sorgu Sonucu Formatı**: Daha iyi bellek verimliliği için dahili üçlü gösterimi optimize etmeli miyiz? +**İzleme Entegrasyonu**: Hangi ölçümler mevcut izleme sistemlerine (Prometheus, vb.) maruz bırakılmalıdır? + +## Referanslar + +[GraphRAG Orijinal Uygulaması](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +[TrustGraph Mimari Prensipleri](architecture-principles.md) +[Koleksiyon Yönetimi Özellikleri](collection-management.md) diff --git a/docs/tech-specs/graphrag-performance-optimization.zh-cn.md b/docs/tech-specs/graphrag-performance-optimization.zh-cn.md index 77ed6312..3c26c71d 100644 --- a/docs/tech-specs/graphrag-performance-optimization.zh-cn.md +++ b/docs/tech-specs/graphrag-performance-optimization.zh-cn.md @@ -2,125 +2,125 @@ ## 概述 -本规范描述了 TrustGraph 中 GraphRAG(基于图的检索增强生成)算法的全面性能优化。当前的实现存在严重的性能瓶颈,限制了可扩展性和响应时间。本规范解决了四个主要优化领域: +本规范描述了 TrustGraph 中 GraphRAG (基于图的检索增强生成) 算法的全面性能优化。当前的实现存在严重的性能瓶颈,限制了可扩展性和响应时间。本规范解决了四个主要的优化领域: -1. **图遍历优化**: 消除低效的递归数据库查询,并实现批处理图探索。 -2. **标签解析优化**: 替换顺序标签获取方式,采用并行/批处理操作。 -3. **缓存策略增强**: 实现智能缓存,采用 LRU 淘汰策略和预取。 -4. **查询优化**: 添加结果备忘和嵌入缓存,以提高响应时间。 +1. **图遍历优化**: 消除低效的递归数据库查询,并实现批量图探索 +2. **标签解析优化**: 使用并行/批量操作替换顺序标签获取 +3. **缓存策略增强**: 实现智能缓存,采用 LRU 淘汰策略和预取 +4. **查询优化**: 添加结果记忆化和嵌入式缓存,以提高响应时间 ## 目标 -- **减少数据库查询量**: 通过批处理和缓存,实现总数据库查询量的 50-80% 减少。 -- **提高响应时间**: 目标是子图构建速度提升 3-5 倍,标签解析速度提升 2-3 倍。 -- **增强可扩展性**: 支持更大的知识图谱,并改进内存管理。 -- **保持准确性**: 保持现有的 GraphRAG 功能和结果质量。 -- **启用并发性**: 提高并行处理能力,支持多个并发请求。 -- **减少内存占用**: 实施高效的数据结构和内存管理。 -- **增加可观察性**: 包含性能指标和监控功能。 -- **确保可靠性**: 添加适当的错误处理和超时机制。 +**减少数据库查询量**: 通过批量和缓存,实现总数据库查询量减少 50-80% +**提高响应时间**: 目标是子图构建速度提高 3-5 倍,标签解析速度提高 2-3 倍 +**增强可扩展性**: 更好地管理内存,支持更大的知识图谱 +**保持准确性**: 保持现有的 GraphRAG 功能和结果质量 +**启用并发性**: 提高并行处理能力,以支持多个并发请求 +**减少内存占用**: 实现高效的数据结构和内存管理 +**增加可观察性**: 包含性能指标和监控功能 +**确保可靠性**: 添加适当的错误处理和超时机制 ## 背景 -`trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` 中当前的 GraphRAG 实现存在以下关键性能问题,严重影响系统可扩展性: +在 `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` 中的当前 GraphRAG 实现存在几个关键的性能问题,严重影响系统的可扩展性: ### 当前性能问题 **1. 低效的图遍历 (`follow_edges` 函数,第 79-127 行)** -- 对每个实体、每个深度级别执行 3 次独立的数据库查询。 -- 查询模式:针对每个实体的基于主体、基于谓词和基于对象的查询。 -- 没有批处理:每次查询只处理一个实体。 -- 没有循环检测:可能多次访问相同的节点。 -- 没有备忘功能的递归实现会导致指数级复杂度。 -- 时间复杂度:O(entities × max_path_length × triple_limit³) +对每个实体,每个深度级别执行 3 次独立的数据库查询 +查询模式:针对主体、谓词和对象进行查询 +没有批量处理:每次查询仅处理一个实体 +没有循环检测:可以多次访问相同的节点 +没有记忆化的递归实现会导致指数级复杂度 +时间复杂度:O(entities × max_path_length × triple_limit³) -**2. 顺序标签解析 (`get_labelgraph` 函数,第 144-171 行)** -- 顺序处理每个三元组组件(主体、谓词、对象)。 -- 每次 `maybe_label` 调用可能触发数据库查询。 -- 没有并行执行或批处理标签查询。 -- 导致最多 subgraph_size × 3 次独立的数据库调用。 +**2. 顺序的标签解析 (`get_labelgraph` 函数,第 144-171 行)** +顺序处理每个三元组组件 (主体、谓词、对象) +每次 `maybe_label` 调用可能触发数据库查询 +没有并行执行或批量标签查询 +导致最多 subgraph_size × 3 次独立的数据库调用 -**3. 原始缓存策略 (`maybe_label` 函数,第 62-77 行)** -- 简单的字典缓存,没有大小限制或 TTL(生存时间)。 -- 没有缓存淘汰策略导致内存无限增长。 -- 缓存未命中会触发单独的数据库查询。 -- 没有预取或智能缓存预热。 +**3. 原始的缓存策略 (`maybe_label` 函数,第 62-77 行)** +简单的字典缓存,没有大小限制或 TTL +没有缓存淘汰策略会导致内存无限增长 +缓存未命中会触发独立的数据库查询 +没有预取或智能缓存预热 **4. 不佳的查询模式** -- 实体向量相似度查询未在相似请求之间缓存。 -- 没有重复查询模式的结果备忘。 -- 缺少常见访问模式的查询优化。 +实体向量相似性查询在相似请求之间没有缓存 +没有对重复查询模式进行结果记忆化 +缺少针对常见访问模式的查询优化 **5. 关键的对象生命周期问题 (`rag.py:96-102`)** -- **`GraphRag` 对象每个请求都重新创建**: 每次查询都会创建新的实例,失去所有缓存优势。 -- **`Query` 对象生存时间极短**: 创建并销毁于单个查询执行中 (第 201-207 行)。 -- **标签缓存每个请求都重置**: 缓存预热和积累的知识在请求之间丢失。 -- **客户端重新创建开销**: 数据库客户端可能为每个请求重新建立连接。 -- **没有跨请求优化**: 无法从查询模式或结果共享中受益。 +**GraphRag 对象每个请求重新创建**: 为每个查询创建一个新的实例,失去所有缓存的好处 +**查询对象寿命极短**: 在单个查询执行中创建和销毁 (第 201-207 行) +**标签缓存每个请求重置**: 缓存预热和积累的知识在请求之间丢失 +**客户端重新创建开销**: 数据库客户端可能为每个请求重新建立 +**没有跨请求优化**: 无法从查询模式或结果共享中受益 ### 性能影响分析 -当前典型的查询最坏情况: -- **实体检索**: 1 次向量相似度查询。 -- **图遍历**: entities × max_path_length × 3 × triple_limit 次查询。 -- **标签解析**: subgraph_size × 3 次独立的标签查询。 +当前典型查询的最坏情况: +**实体检索**: 1 次向量相似性查询 +**图遍历**: entities × max_path_length × 3 × triple_limit 次查询 +**标签解析**: subgraph_size × 3 次独立的标签查询 -对于默认参数(50 个实体,路径长度 2,30 个三元组限制,150 个子图大小): -- **最小查询次数**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 次数据库查询** -- **响应时间**: 中等大小图的响应时间为 15-30 秒。 -- **内存使用**: 缓存无限增长。 -- **缓存有效性**: 0% - 每次请求都重置缓存。 -- **对象创建开销**: 为每个请求创建/销毁 `GraphRag` + `Query` 对象。 +对于默认参数(50个实体,路径长度2,30个三元组限制,150个子图大小): +**最小查询次数**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451次数据库查询** +**响应时间**: 中等大小图的响应时间为15-30秒 +**内存使用**: 缓存会随着时间增长 +**缓存有效性**: 0% - 每次请求都会重置缓存 +**对象创建开销**: 每个请求都会创建/销毁GraphRag + Query对象 -本规范通过实施批处理查询、智能缓存和并行处理来解决这些问题。 通过优化查询模式和数据访问,TrustGraph 可以: -- 支持数百万个实体的企业级知识图谱。 -- 为典型的查询提供亚秒级的响应时间。 -- 处理数百个并发的 GraphRAG 请求。 -- 通过图的大小和复杂性实现高效扩展。 +本规范通过实现批量查询、智能缓存和并行处理来解决这些问题。通过优化查询模式和数据访问,TrustGraph可以: +支持拥有数百万个实体的企业级知识图谱 +为典型的查询提供亚秒级的响应时间 +处理数百个并发的GraphRAG请求 +随着图的大小和复杂性而高效扩展 ## 技术设计 ### 架构 -GraphRAG 性能优化需要以下技术组件: +GraphRAG性能优化需要以下技术组件: #### 1. **对象生命周期架构重构** - - **使 `GraphRag` 长期存在**: 将 `GraphRag` 实例移动到 Processor 级别,以在请求之间保持持久性。 - - **保留缓存**: 保持标签缓存、嵌入缓存和查询结果缓存在请求之间。 - - **优化 `Query` 对象**: 将 `Query` 重构为轻量级执行上下文,而不是数据容器。 - - **连接持久化**: 在请求之间保持数据库客户端连接。 + **使GraphRag具有长期生命周期**: 将GraphRag实例移动到处理器级别,以便在请求之间保持持久性 + **保留缓存**: 在请求之间维护标签缓存、嵌入缓存和查询结果缓存 + **优化Query对象**: 将Query重构为轻量级的执行上下文,而不是数据容器 + **连接持久化**: 在请求之间保持数据库客户端连接 模块: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (已修改) #### 2. **优化的图遍历引擎** - - 将递归的 `follow_edges` 替换为迭代的广度优先搜索。 - - 在每个遍历级别实施批处理实体处理。 - - 添加循环检测,使用已访问节点跟踪。 - - 包含当达到限制时提前终止。 + 使用迭代广度优先搜索替换递归的`follow_edges` + 在每个遍历级别实现批量实体处理 + 添加循环检测,使用已访问节点跟踪 + 在达到限制时包含早期终止 模块: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` #### 3. **并行标签解析系统** - - 批量处理多个实体同时的标签查询。 - - 实施 async/await 模式以进行并发数据库访问。 - - 添加常见的标签模式的智能预取。 - - 包含标签缓存预热策略。 + 批量查询多个实体的标签 + 使用async/await模式进行并发数据库访问 + 添加智能预取,用于常见的标签模式 + 包含标签缓存预热策略 模块: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` #### 4. **保守的标签缓存层** - - LRU 缓存,带短 TTL(5 分钟)用于仅限标签,以平衡性能与一致性。 - - 缓存指标和命中率监控。 - - **不缓存嵌入**: 已针对每个查询进行缓存,没有跨查询的优势。 - - **不缓存查询结果**: 由于图的mutation一致性问题。 + 使用LRU缓存,仅对标签使用,TTL为5分钟,以平衡性能与一致性 + 监控缓存指标和命中率 + **不缓存嵌入**: 已经针对每个查询进行缓存,没有跨查询的好处 + **不缓存查询结果**: 由于图的突变一致性问题 模块: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` #### 5. **查询优化框架** - - 查询模式分析和优化建议。 - - 数据库访问的批处理查询协调器。 - - 连接池和查询超时管理。 - - 性能监控和指标收集。 + 查询模式分析和优化建议 + 批量查询协调器,用于数据库访问 + 连接池和查询超时管理 + 性能监控和指标收集 模块: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` @@ -142,10 +142,10 @@ class TraversalState: ``` 这种方法允许: -- 通过跟踪已访问实体实现高效的循环检测。 -- 在每个遍历级别批处理查询准备。 -- 通过内存效率的状态管理。 -- 当达到大小限制时提前终止。 +通过跟踪访问的实体实现高效的循环检测 +在每个遍历层级进行批量查询准备 +内存效率高的状态管理 +当达到大小限制时,可以提前终止 #### 增强的缓存结构 @@ -164,7 +164,7 @@ class CacheManager: cache_stats: CacheStatistics ``` -#### 批处理查询结构 +#### 批量查询结构 ```python @dataclass @@ -179,9 +179,9 @@ class BatchLabelQuery: predicate: str = LABEL ``` -### API +### API 接口 -#### 新 API: +#### 新增 API 接口: **图遍历 API** ```python @@ -206,159 +206,424 @@ async def resolve_labels_batch( class CacheManager: async def get_or_fetch_label(self, entity: str) -> str async def get_or_fetch_embeddings(self, query: str) -> List[float] - async def cache_query_result(self, query: str, result: Any, timeout: int = 3600) - def total_cache_size(self) -> int + async def cache_query_result(self, query_hash: str, result: Any, ttl: int) + def get_cache_statistics(self) -> CacheStatistics ``` -#### 接口变更 +#### 修改后的 API: -**查询类**: 将 `follow_edges` 方法替换为批处理迭代遍历 -**GraphRag 类**: 添加标签缓存层 -**Processor 类**: 修改以使用持久的 `GraphRag` 实例 -**总**: 大约 140 行的代码更改,主要集中在现有的类中。 +**GraphRag.query()** - 增强了性能优化: +添加了 cache_manager 参数以进行缓存控制 +包含 performance_metrics 返回值 +添加了 query_timeout 参数以提高可靠性 -## 缓存一致性注意事项 +**Query 类** - 进行了重构,用于批量处理: +将单个实体处理替换为批量操作 +添加了异步上下文管理器以进行资源清理 +包含进度回调函数,用于长时间运行的操作 + +### 实施细节 + +#### 阶段 0:关键架构生命周期重构 + +**当前存在问题的实现:** +```python +# INEFFICIENT: GraphRag recreated every request +class Processor(FlowProcessor): + async def on_request(self, msg, consumer, flow): + # PROBLEM: New GraphRag instance per request! + self.rag = GraphRag( + embeddings_client = flow("embeddings-request"), + graph_embeddings_client = flow("graph-embeddings-request"), + triples_client = flow("triples-request"), + prompt_client = flow("prompt-request"), + verbose=True, + ) + # Cache starts empty every time - no benefit from previous requests + response = await self.rag.query(...) + +# VERY SHORT-LIVED: Query object created/destroyed per request +class GraphRag: + async def query(self, query, user="trustgraph", collection="default", ...): + q = Query(rag=self, user=user, collection=collection, ...) # Created + kg = await q.get_labelgraph(query) # Used briefly + # q automatically destroyed when function exits +``` + +**优化后的长期运行架构:** +```python +class Processor(FlowProcessor): + def __init__(self, **params): + super().__init__(**params) + self.rag_instance = None # Will be initialized once + self.client_connections = {} + + async def initialize_rag(self, flow): + """Initialize GraphRag once, reuse for all requests""" + if self.rag_instance is None: + self.rag_instance = LongLivedGraphRag( + embeddings_client=flow("embeddings-request"), + graph_embeddings_client=flow("graph-embeddings-request"), + triples_client=flow("triples-request"), + prompt_client=flow("prompt-request"), + verbose=True, + ) + return self.rag_instance + + async def on_request(self, msg, consumer, flow): + # REUSE the same GraphRag instance - caches persist! + rag = await self.initialize_rag(flow) + + # Query object becomes lightweight execution context + response = await rag.query_with_context( + query=v.query, + execution_context=QueryContext( + user=v.user, + collection=v.collection, + entity_limit=entity_limit, + # ... other params + ) + ) + +class LongLivedGraphRag: + def __init__(self, ...): + # CONSERVATIVE caches - balance performance vs consistency + self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness + # Note: No embedding cache - already cached per-query, no cross-query benefit + # Note: No query result cache due to consistency concerns + self.performance_metrics = PerformanceTracker() + + async def query_with_context(self, query: str, context: QueryContext): + # Use lightweight QueryExecutor instead of heavyweight Query object + executor = QueryExecutor(self, context) # Minimal object + return await executor.execute(query) + +@dataclass +class QueryContext: + """Lightweight execution context - no heavy operations""" + user: str + collection: str + entity_limit: int + triple_limit: int + max_subgraph_size: int + max_path_length: int + +class QueryExecutor: + """Lightweight execution context - replaces old Query class""" + def __init__(self, rag: LongLivedGraphRag, context: QueryContext): + self.rag = rag + self.context = context + # No heavy initialization - just references + + async def execute(self, query: str): + # All heavy lifting uses persistent rag caches + return await self.rag.execute_optimized_query(query, self.context) +``` + +这种架构上的改变提供了: +**对于具有常见关系的图,数据库查询减少 10-20%**(相对于目前 0% 的减少) +**消除了每个请求中的对象创建开销** +**持久连接池和客户端重用** +**缓存 TTL 窗口内的跨请求优化** + +**重要的缓存一致性限制:** +长期缓存会带来数据陈旧的风险,尤其是在底层图中删除或修改实体/标签时。 LRU 缓存和 TTL 在性能提升和数据新鲜度之间提供了一种平衡,但无法检测到实时图的变化。 + +#### 第一阶段:图遍历优化 + +**当前实现的缺点:** +```python +# INEFFICIENT: 3 queries per entity per level +async def follow_edges(self, ent, subgraph, path_length): + # Query 1: s=ent, p=None, o=None + res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit) + # Query 2: s=None, p=ent, o=None + res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit) + # Query 3: s=None, p=None, o=ent + res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit) +``` + +**优化实现:** +```python +async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]: + visited = set() + current_level = set(entities) + subgraph = set() + + for depth in range(max_depth): + if not current_level or len(subgraph) >= self.max_subgraph_size: + break + + # Batch all queries for current level + batch_queries = [] + for entity in current_level: + if entity not in visited: + batch_queries.extend([ + TripleQuery(s=entity, p=None, o=None), + TripleQuery(s=None, p=entity, o=None), + TripleQuery(s=None, p=None, o=entity) + ]) + + # Execute all queries concurrently + results = await self.execute_batch_queries(batch_queries) + + # Process results and prepare next level + next_level = set() + for result in results: + subgraph.update(result.triples) + next_level.update(result.new_entities) + + visited.update(current_level) + current_level = next_level - visited + + return subgraph +``` + +#### 第二阶段:并行标签解析 + +**当前的顺序实现方式:** +```python +# INEFFICIENT: Sequential processing +for edge in subgraph: + s = await self.maybe_label(edge[0]) # Individual query + p = await self.maybe_label(edge[1]) # Individual query + o = await self.maybe_label(edge[2]) # Individual query +``` + +**优化后的并行实现:** +```python +async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: + # Collect all unique entities needing labels + entities_to_resolve = set() + for s, p, o in subgraph: + entities_to_resolve.update([s, p, o]) + + # Remove already cached entities + uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache] + + # Batch query for all uncached labels + if uncached_entities: + label_results = await self.batch_label_query(uncached_entities) + self.label_cache.update(label_results) + + # Apply labels to subgraph + return [ + (self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o)) + for s, p, o in subgraph + ] +``` + +#### 第三阶段:高级缓存策略 + +**LRU 缓存与 TTL:** +```python +class LRUCacheWithTTL: + def __init__(self, max_size: int, default_ttl: int = 3600): + self.cache = OrderedDict() + self.max_size = max_size + self.default_ttl = default_ttl + self.access_times = {} + + async def get(self, key: str) -> Optional[Any]: + if key in self.cache: + # Check TTL expiration + if time.time() - self.access_times[key] > self.default_ttl: + del self.cache[key] + del self.access_times[key] + return None + + # Move to end (most recently used) + self.cache.move_to_end(key) + return self.cache[key] + return None + + async def put(self, key: str, value: Any): + if key in self.cache: + self.cache.move_to_end(key) + else: + if len(self.cache) >= self.max_size: + # Remove least recently used + oldest_key = next(iter(self.cache)) + del self.cache[oldest_key] + del self.access_times[oldest_key] + + self.cache[key] = value + self.access_times[key] = time.time() +``` + +#### 第四阶段:查询优化和监控 + +**性能指标收集:** +```python +@dataclass +class PerformanceMetrics: + total_queries: int + cache_hits: int + cache_misses: int + avg_response_time: float + subgraph_construction_time: float + label_resolution_time: float + total_entities_processed: int + memory_usage_mb: float +``` + +**查询超时和断路器:** +```python +async def execute_with_timeout(self, query_func, timeout: int = 30): + try: + return await asyncio.wait_for(query_func(), timeout=timeout) + except asyncio.TimeoutError: + logger.error(f"Query timeout after {timeout}s") + raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s") +``` + +## 缓存一致性考虑 **数据时效性权衡:** -- **标签缓存 (5 分钟 TTL)**: 存在提供已删除/重命名的实体标签的风险。 -- **不缓存嵌入**: 不需要 - 嵌入已经针对每个查询进行缓存。 -- **不缓存查询结果**: 防止从已删除实体/关系中获取过时子图结果。 +**标签缓存 (5 分钟 TTL)**:存在提供已删除/重命名的实体标签的风险。 +**不缓存嵌入 (embeddings)**:不需要 - 嵌入已按查询缓存。 +**不缓存结果**:防止从已删除的实体/关系中获取过时的子图结果。 **缓解策略:** -- **保守的 TTL 值**: 平衡性能收益(10-20%)与数据新鲜度。 -- **缓存失效钩子**: 可选地集成图 mutation 事件。 -- **监控仪表板**: 跟踪缓存命中率与时效性事件。 -- **可配置的缓存策略**: 允许根据 mutation 频率进行每个部署的调整。 +**保守的 TTL 值**:在性能提升 (10-20%) 和数据新鲜度之间取得平衡。 +**缓存失效钩子**:可选地与图的修改事件集成。 +**监控仪表板**:跟踪缓存命中率与数据时效性事件。 +**可配置的缓存策略**:允许根据修改频率进行按部署的调整。 -**推荐的缓存配置(根据图的 mutation 速率):** -- **高 mutation(每小时 > 100 次更改)**: TTL=60 秒,较小的缓存大小。 -- **中等 mutation(每小时 10-100 次更改)**: TTL=300 秒(默认值)。 -- **低 mutation(每小时 < 10 次更改)**: TTL=600 秒,较大的缓存大小。 +**根据图修改速率推荐的缓存配置:** +**高修改速率 (>100 次/小时)**:TTL=60 秒,较小的缓存大小。 +**中等修改速率 (10-100 次/小时)**:TTL=300 秒 (默认值)。 +**低修改速率 (<10 次/小时)**:TTL=600 秒,较大的缓存大小。 -## 安全注意事项 +## 安全性考虑 -**防止查询注入:** -- 验证所有实体标识符和查询参数。 -- 对所有数据库交互使用参数化查询。 -- 实施查询复杂度限制,以防止拒绝服务攻击。 +**查询注入防护:** +验证所有实体标识符和查询参数。 +对所有数据库交互使用参数化查询。 +实施查询复杂度限制以防止拒绝服务 (DoS) 攻击。 **资源保护:** -- 强制执行最大子图大小限制。 -- 实施查询超时,以防止资源耗尽。 -- 添加内存使用监控和限制。 +强制执行最大子图大小限制。 +实施查询超时以防止资源耗尽。 +添加内存使用情况监控和限制。 **访问控制:** -- 维护现有的用户和集合隔离。 -- 添加对性能影响操作的审计日志。 -- 实施速率限制,以防止昂贵操作。 +维护现有的用户和集合隔离。 +添加对影响性能的操作的审计日志。 +实施速率限制以防止对昂贵操作的滥用。 -## 性能注意事项 +## 性能考虑 -### 预期性能提升 +### 预期的性能提升 **查询减少:** -- 当前:典型的请求大约为 9,000+ 次查询。 -- 优化后:大约 50-100 次批处理查询(减少 98%)。 +当前:典型请求需要 ~9,000+ 次查询。 +优化后:~50-100 个批处理查询 (减少 98%)。 **响应时间改进:** -- 图遍历:15-20 秒 → 3-5 秒(快 4-5 倍)。 -- 标签解析:8-12 秒 → 2-4 秒(快 3 倍)。 -- 总体查询:25-35 秒 → 6-10 秒(提高 3-4 倍)。 +图遍历:15-20 秒 → 3-5 秒 (快 4-5 倍)。 +标签解析:8-12 秒 → 2-4 秒 (快 3 倍)。 +总体查询:25-35 秒 → 6-10 秒 (提升 3-4 倍)。 **内存效率:** -- 边界缓存大小可防止内存泄漏。 -- 高效的数据结构可将内存占用减少 40%。 -- 通过适当的资源清理实现更好的垃圾回收。 +限制的缓存大小可防止内存泄漏。 +高效的数据结构可减少内存占用 ~40%。 +通过适当的资源清理实现更好的垃圾回收。 + +**现实的性能期望:** +**标签缓存**:对于具有常见关系的图,查询减少 10-20%。 +**批处理优化**:查询减少 50-80% (主要优化)。 +**对象生命周期优化**:消除每个请求的创建开销。 +**总体改进**:主要通过批处理实现响应时间提升 3-4 倍。 **可扩展性改进:** -- 支持更大的知识图谱(受缓存一致性需求的限制)。 -- 更高的并发请求容量。 -- 通过连接重用实现更好的资源利用率。 +支持 3-5 倍更大的知识图 (受缓存一致性需求限制)。 +3-5 倍更高的并发请求容量。 +通过连接重用实现更好的资源利用率。 ### 性能监控 **实时指标:** -- 查询执行时间(按操作类型)。 -- 缓存命中率和有效性。 -- 数据库连接池利用率。 -- 内存使用情况和垃圾回收影响。 +按操作类型划分的查询执行时间。 +缓存命中率和有效性。 +数据库连接池利用率。 +内存使用情况和垃圾回收影响。 -**性能基准测试:** -- 针对当前实现的自动化性能回归测试。 -- 使用真实数据量的负载测试。 -- 针对内存和连接限制进行压力测试。 -- 针对性能改进进行回归测试。 +**性能基准测试 (Xìngnéng Jīzhǔ Cèshì):** +自动化性能回归测试 (Zìdònghuà xìngnéng huíguī cèshì) +使用真实数据量的负载测试 (Shǐyòng zhēnshí shùjùliàng de fùzài cèshì) +与当前实现相比的基准测试 (Yǔ xiàncái shíxiàn xiāngbǐ de jīzhǔ cèshì) -## 测试策略 +## 测试策略 (Cèshì Cèlüè) -### 单元测试 -- 对遍历、缓存和标签解析等各个组件进行测试。 -- 模拟数据库交互以进行性能测试。 -- 缓存淘汰和 TTL 到期测试。 -- 错误处理和超时场景。 +### 单元测试 (Dānyuán Cèshì) +对遍历、缓存和标签解析等各个组件进行单独测试 (Duì biànlì, cáichǔ hé biāoqiān jiěshì děng gège zǔjiàn jìnxíng dānduǒ cèshì) +模拟数据库交互以进行性能测试 (Mónǐ shùjùkù jiāohù yǐ jìnxíng xìngnéng cèshì) +缓存驱逐和 TTL 过期测试 (Cáichǔ qūzhí hé TTL guòqí cèshì) +错误处理和超时场景测试 (Cuòwù chǔlǐ hé chāoshí chǎngjǐng cèshì) -### 集成测试 -- 使用优化后的 GraphRAG 查询进行端到端测试。 -- 使用真实数据进行数据库交互测试。 -- 并发请求处理和资源管理。 -- 内存泄漏检测和资源清理验证。 +### 集成测试 (Jíchéng Cèshì) +使用优化后的 GraphRAG 查询的端到端测试 (Shǐyòng yōuhuà hòu de GraphRAG shōuchá de duān dào duān cèshì) +使用真实数据的数据库交互测试 (Shǐyòng zhēnshí shùjù de shùjùkù jiāohù cèshì) +并发请求处理和资源管理测试 (Bìngfā qǐngqiú chǔlǐ hé zīyuán guǎnlǐ cèshì) +内存泄漏检测和资源清理验证 (Nèicún liūlèi jiǎncè hé zīyuán qīnglǐ yànzhèng) -### 性能测试 -- 针对当前实现进行基准测试。 -- 使用不同大小和复杂度的知识图谱进行负载测试。 -- 针对内存和连接限制进行压力测试。 -- 针对性能改进进行回归测试。 +### 性能测试 (Xìngnéng Cèshì) +与当前实现相比的基准测试 (Yǔ xiàncái shíxiàn xiāngbǐ de jīzhǔ cèshì) +使用不同大小和复杂度的图的负载测试 (Shǐyòng bùtóng dàxiǎo hé fùzá dù de tú de fùzài cèshì) +压力测试以确定内存和连接限制 (Yālì cèshì yǐ quèdìng nèicún hé liánjiē xiànzhì) +用于性能改进的回归测试 (Yòng yú xìngnéng gǎijìn de huíguī cèshì) -### 兼容性测试 -- 验证现有的 GraphRAG API 兼容性。 -- 测试与各种图数据库后端兼容性。 -- 验证与当前实现相比的结果准确性。 +### 兼容性测试 (Jiānróng Xìng Cèshì) +验证现有 GraphRAG API 的兼容性 (Yànzhèng xiàn yǒu GraphRAG API de jiānróng xìng) +使用各种图数据库后端进行测试 (Shǐyòng gè zhǒng tú shùjùkù hòudùàn jìnxíng cèshì) +验证与当前实现相比的结果准确性 (Yànzhèng yǔ xiàncái shíxiàn xiāngbǐ de jiéguǒ zhǔnquè xìng) -## 实施计划 +## 实施计划 (Shíshī Jìhuà) -### 直接实施方法 -由于允许更改 API,因此直接实施优化,而无需迁移的复杂性: +### 直接实施方法 (Zhíjiē Shíshī Fāngfǎ) +由于允许 API 更改,因此在不引入迁移复杂性的情况下,直接实施优化:(Yóuyú yǔnxǔ API gēnggǎi, yīncǐ zài bù yǐnrù qiān yí fùzá xìng de qíngkuàng xià, zhíjiē shíshī yōuhuà:) -1. **替换 `follow_edges` 方法**: 使用迭代的批处理遍历进行重写。 -2. **优化 `get_labelgraph`**: 实施并行标签解析。 -3. **添加长期存在的 `GraphRag` 实例**: 修改 `Processor` 以使用持久的实例。 -4. **实施标签缓存**: 在 `GraphRag` 类中添加 LRU 缓存。 +1. **替换 `follow_edges` 方法**: 使用迭代批量遍历重写 (Tiānyuē `follow_edges` fāngfǎ: Shǐyòng diànxìng pīliàng biànlì chóngxīn xiě) +2. **优化 `get_labelgraph`**: 实施并行标签解析 (Yōuhuà `get_labelgraph`: Shíshī bìngxíng biāoqiān jiěshì) +3. **添加长期 GraphRag**: 修改处理器以维护持久实例 (Tiānjiā chángqí GraphRag: Gǎixiāng chǔlǐ qì yǐ wéihù chíjiǔ yǐnshì) +4. **实施标签缓存**: 为 GraphRag 类添加 LRU 缓存和 TTL (Shíshī biāoqiān cáichǔ: Wèi GraphRag lèi tiānjiā LRU cáichǔ hé TTL) -### 更改范围 -- **`Query` 类**: 替换 `follow_edges` 方法,添加约 30 行批处理处理代码。 -- **`GraphRag` 类**: 添加标签缓存层。 -- **`Processor` 类**: 修改以使用持久的 `GraphRag` 实例,约 20 行代码。 -- **总计**: 大约 140 行的集中代码更改,主要集中在现有的类中。 +### 变更范围 (Biàngēng Fànwéi) +**查询类 (Query Class)**: 替换 `follow_edges` 中的 ~50 行代码,添加 ~30 行批量处理代码 (Tiānyuē `follow_edges` zhōng de ~50 háng dàimǎ, tiānjiā ~30 háng pīliàng chǔlǐ dàimǎ) +**GraphRag 类 (GraphRag Class)**: 添加缓存层 (~40 行代码) (Tiānjiā cáichǔ céng (~40 háng dàimǎ)) +**处理器类 (Processor Class)**: 修改为使用持久的 GraphRag 实例 (~20 行代码) (Gǎixiāng wéi shǐyòng chíjiǔ de GraphRag yǐnshì (~20 háng dàimǎ)) +**总计 (Zǒngjì)**: ~140 行专注于的变更,主要在现有类中 (~140 háng zhuānzhù yú de biàngēng, zhǔyào zài xiàn yǒu lèi zhōng) -## 时间表 +## 时间线 (Shíjiān Xiàn) -**第一周:核心实施** -- 替换 `follow_edges` 方法为批处理迭代遍历。 -- 在 `get_labelgraph` 中实现并行标签解析。 -- 将 `GraphRag` 实例添加到 `Processor`,使其长期存在。 -- 在 `GraphRag` 类中实现标签缓存层。 +**第一周: 核心实施 (Dì Yī Zhōu: Héxīn Shíshī)** +使用批量迭代遍历替换 `follow_edges` (Shǐyòng pīliàng diànxìng biànlì tiānyuē `follow_edges`) +在 `get_labelgraph` 中实施并行标签解析 (Zài `get_labelgraph` zhōng shíshī bìngxíng biāoqiān jiěshì) +向处理器添加长期 GraphRag 实例 (Xiàng chǔlǐ qì tiānjiā chángqí GraphRag yǐnshì) +实施标签缓存层 (Shíshī biāoqiān cáichǔ céng) -**第二周:测试和集成** -- 对新的遍历和缓存逻辑进行单元测试。 -- 针对当前实现进行性能基准测试。 -- 使用真实图数据进行集成测试。 -- 代码审查和优化。 +**第二周: 测试和集成 (Dì Èr Zhōu: Cèshì hé Jíchéng)** +对新的遍历和缓存逻辑进行单元测试 (Duì xīn de biànlì hé cáichǔ luójí jìnxíng dānyuán cèshì) +与当前实现相比进行性能基准测试 (Yǔ xiàncái shíxiàn xiāngbǐ jìnxíng xìngnéng jīzhǔ cèshì) +使用真实图数据进行集成测试 (Shǐyòng zhēnshí tú shùjù jìnxíng jíchéng cèshì) +代码审查和优化 (Dàimǎ shěnchá hé yōuhuà) -**第三周:部署** -- 部署优化的实现。 -- 监控性能改进。 -- 根据实际使用情况微调缓存 TTL 和批处理大小。 +**第三周: 部署 (Dì Sān Zhōu: Bùshǔ)** +部署优化后的实现 (Bùshǔ yōuhuà hòu de shíshī) +监控性能改进 (Jiānkòng xìngnéng gǎijìn) +根据实际使用情况微调缓存 TTL 和批量大小 (Gēnjù shíjì shǐyòng qíngkuàng wēitiáo cáichǔ TTL hé pīliàng dàxiǎo) -## 开放问题 +## 开放性问题 (Kāifàng Xìng Wèntí) -- **数据库连接池**: 是否应实施自定义连接池,或依赖于现有的数据库客户端池? -- **缓存持久性**: 是否应跨服务重启持久化标签和嵌入缓存? -- **分布式缓存**: 对于多实例部署,是否应实现分布式缓存(例如,使用 Redis/Memcached)? -- **查询结果格式**: 是否应优化内部三元组表示以实现更好的内存效率? -- **监控集成**: 哪些指标应暴露给现有的监控系统(例如,Prometheus)? +**数据库连接池 (Shùjùkù Liánjiē Chí)**: 我们应该实施自定义连接池,还是依赖于现有的数据库客户端连接池?(Wǒmen yīnggāi shíshī zìdìngyì liánjiē chí, háishì yīlài yú xiàn yǒu de shùjùkù kèfāngliánjiē chí?) +**缓存持久性 (Cáichǔ Chíjiǔ Xìng)**: 标签和嵌入式缓存是否应该在服务重启后持久存在?(Biāoqiān hé qiànrùshì cáichǔ shìfǒu yīnggāi zài fúwù chóngqí hòu chíjiǔ cúnzài?) +**分布式缓存 (Fēn Bùshì Cáichǔ)**: 对于多实例部署,我们是否应该实施具有 Redis/Memcached 的分布式缓存?(Duìyú duō yǐnshì bùshǔ, wǒmen shìfǒu yīnggāi shíshī yǒuyú Redis/Memcached de fēn bùshì cáichǔ?) +**查询结果格式 (Shōuchá Jiéguǒ Géshì)**: 我们是否应该优化内部三元组表示以获得更好的内存效率?(Wǒmen shìfǒu yīnggāi yōuhuà nèibù sān yuánzǔ biǎoshì yǐ huòdé gèng hǎo de nèicún xiàolǜ?) +**监控集成 (Jiānkòng Jíchéng)**: 哪些指标应该暴露给现有的监控系统(Prometheus 等)?(Nǎxiē zhǐbiāo yīnggāi bàolù gěi xiàn yǒu de jiānkòng xìtǒng (Prometheus děng)?) -## 参考资料 +## 参考文献 (Cānkǎo Z tàiliào) -- [GraphRAG 原始实现](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) -- [TrustGraph 架构原则](architecture-principles.md) -- [集合管理规范](collection-management.md) \ No newline at end of file +GraphRAG API 文档 (GraphRAG API 文档) +示例代码 (Lìmiàn dàimǎ) +相关论文 (Xiāngguān lùnwén) diff --git a/docs/tech-specs/import-export-graceful-shutdown.ar.md b/docs/tech-specs/import-export-graceful-shutdown.ar.md new file mode 100644 index 00000000..c5c9b9f0 --- /dev/null +++ b/docs/tech-specs/import-export-graceful-shutdown.ar.md @@ -0,0 +1,682 @@ +# المواصفات الفنية للإغلاق التدريجي للاستيراد/التصدير + +## بيان المشكلة + +بوابة TrustGraph تواجه حاليًا فقدان الرسائل أثناء إغلاق WebSocket في كل من عمليات الاستيراد والتصدير. يحدث هذا بسبب حالات السباق حيث يتم التخلص من الرسائل أثناء النقل قبل وصولها إلى وجهتها (قوائم انتظار Pulsar للاستيراد، عملاء WebSocket للتصدير). + +### مشاكل جانب الاستيراد +1. مخزن مؤقت asyncio.Queue الخاص بالناشر غير فارغ عند الإغلاق. +2. يتم إغلاق WebSocket قبل التأكد من وصول الرسائل الموجودة في قائمة الانتظار إلى Pulsar. +3. لا يوجد آلية تأكيد لتسليم الرسائل بنجاح. + +### مشاكل جانب التصدير +1. يتم تأكيد الرسائل في Pulsar قبل التسليم الناجح إلى العملاء. +2. تؤدي قيم المهلة الثابتة إلى فقدان الرسائل عندما تكون قوائم الانتظار ممتلئة. +3. لا يوجد آلية للتحكم في التدفق للتعامل مع المستهلكين البطيئين. +4. نقاط تخزين مؤقت متعددة حيث يمكن فقدان البيانات. + +## نظرة عامة على البنية + +``` +Import Flow: +Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue + +Export Flow: +Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client +``` + +## التحسينات المقترحة + +### 1. تحسينات الناشر (جانب الاستيراد) + +#### أ. تفريغ سلس للانتظار + +**الملف:** `trustgraph-base/trustgraph/base/publisher.py` + +```python +class Publisher: + def __init__(self, client, topic, schema=None, max_size=10, + chunking_enabled=True, drain_timeout=5.0): + self.client = client + self.topic = topic + self.schema = schema + self.q = asyncio.Queue(maxsize=max_size) + self.chunking_enabled = chunking_enabled + self.running = True + self.draining = False # New state for graceful shutdown + self.task = None + self.drain_timeout = drain_timeout + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + try: + producer = self.client.create_producer( + topic=self.topic, + schema=JsonSchema(self.schema), + chunking_enabled=self.chunking_enabled, + ) + + drain_end_time = None + + while self.running or self.draining: + try: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s") + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + if not self.q.empty(): + logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining") + self.draining = False + break + + # Calculate wait timeout based on mode + if self.draining: + # Shorter timeout during draining to exit quickly when empty + timeout = min(0.1, drain_end_time - time.time()) + else: + # Normal operation timeout + timeout = 0.25 + + # Get message from queue + id, item = await asyncio.wait_for( + self.q.get(), + timeout=timeout + ) + + # Send the message (single place for sending) + if id: + producer.send(item, { "id": id }) + else: + producer.send(item) + + except asyncio.TimeoutError: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + except asyncio.QueueEmpty: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + # Flush producer before closing + if producer: + producer.flush() + producer.close() + + except Exception as e: + logger.error(f"Exception in publisher: {e}", exc_info=True) + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def send(self, id, item): + """Send still works normally - just adds to queue""" + if self.draining: + # Optionally reject new messages during drain + raise RuntimeError("Publisher is shutting down, not accepting new messages") + await self.q.put((id, item)) +``` + +**المزايا الرئيسية للتصميم:** +**موقع إرسال واحد**: جميع استدعاءات `producer.send()` تحدث في مكان واحد داخل الطريقة `run()`. +**آلة حالة واضحة:** ثلاثة حالات واضحة - قيد التشغيل، في مرحلة التفريغ، متوقفة. +**حماية من المهلة الزمنية:** لن تتعطل بشكل دائم أثناء التفريغ. +**إمكانية مراقبة أفضل:** تسجيل واضح لتقدم التفريغ والانتقالات بين الحالات. +**رفض الرسائل الاختياري:** يمكن رفض الرسائل الجديدة أثناء مرحلة الإغلاق. + +#### ب. ترتيب الإغلاق المحسّن + +**الملف:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py` + +```python +class TriplesImport: + async def destroy(self): + """Enhanced destroy with proper shutdown order""" + # Step 1: Stop accepting new messages + self.running.stop() + + # Step 2: Wait for publisher to drain its queue + logger.info("Draining publisher queue...") + await self.publisher.stop() + + # Step 3: Close websocket only after queue is drained + if self.ws: + await self.ws.close() +``` + +### 2. تحسينات المشترك (الجانب التصديري) + +#### أ. نمط التصريف المتكامل + +**الملف:** `trustgraph-base/trustgraph/base/subscriber.py` + +```python +class Subscriber: + def __init__(self, client, topic, subscription, consumer_name, + schema=None, max_size=100, metrics=None, + backpressure_strategy="block", drain_timeout=5.0): + # ... existing init ... + self.backpressure_strategy = backpressure_strategy + self.running = True + self.draining = False # New state for graceful shutdown + self.drain_timeout = drain_timeout + self.pending_acks = {} # Track messages awaiting delivery + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + if self.metrics: + self.metrics.state("stopped") + + try: + self.consumer = self.client.subscribe( + topic = self.topic, + subscription_name = self.subscription, + consumer_name = self.consumer_name, + schema = JsonSchema(self.schema), + ) + + if self.metrics: + self.metrics.state("running") + + logger.info("Subscriber running...") + drain_end_time = None + + while self.running or self.draining: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s") + + # Stop accepting new messages from Pulsar during drain + self.consumer.pause_message_listener() + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + async with self.lock: + total_pending = sum( + q.qsize() for q in + list(self.q.values()) + list(self.full.values()) + ) + if total_pending > 0: + logger.warning(f"Drain timeout reached with {total_pending} messages in queues") + self.draining = False + break + + # Check if we can exit drain mode + if self.draining: + async with self.lock: + all_empty = all( + q.empty() for q in + list(self.q.values()) + list(self.full.values()) + ) + if all_empty and len(self.pending_acks) == 0: + logger.info("Subscriber queues drained successfully") + self.draining = False + break + + # Process messages only if not draining + if not self.draining: + try: + msg = await asyncio.to_thread( + self.consumer.receive, + timeout_millis=250 + ) + except _pulsar.Timeout: + continue + except Exception as e: + logger.error(f"Exception in subscriber receive: {e}", exc_info=True) + raise e + + if self.metrics: + self.metrics.received() + + # Process the message + await self._process_message(msg) + else: + # During draining, just wait for queues to empty + await asyncio.sleep(0.1) + + except Exception as e: + logger.error(f"Subscriber exception: {e}", exc_info=True) + + finally: + # Negative acknowledge any pending messages + for msg in self.pending_acks.values(): + self.consumer.negative_acknowledge(msg) + self.pending_acks.clear() + + if self.consumer: + self.consumer.unsubscribe() + self.consumer.close() + self.consumer = None + + if self.metrics: + self.metrics.state("stopped") + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def _process_message(self, msg): + """Process a single message with deferred acknowledgment""" + # Store message for later acknowledgment + msg_id = str(uuid.uuid4()) + self.pending_acks[msg_id] = msg + + try: + id = msg.properties()["id"] + except: + id = None + + value = msg.value() + delivery_success = False + + async with self.lock: + # Deliver to specific subscribers + if id in self.q: + delivery_success = await self._deliver_to_queue( + self.q[id], value + ) + + # Deliver to all subscribers + for q in self.full.values(): + if await self._deliver_to_queue(q, value): + delivery_success = True + + # Acknowledge only on successful delivery + if delivery_success: + self.consumer.acknowledge(msg) + del self.pending_acks[msg_id] + else: + # Negative acknowledge for retry + self.consumer.negative_acknowledge(msg) + del self.pending_acks[msg_id] + + async def _deliver_to_queue(self, queue, value): + """Deliver message to queue with backpressure handling""" + try: + if self.backpressure_strategy == "block": + # Block until space available (no timeout) + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_oldest": + # Drop oldest message if queue full + if queue.full(): + try: + queue.get_nowait() + if self.metrics: + self.metrics.dropped() + except asyncio.QueueEmpty: + pass + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_new": + # Drop new message if queue full + if queue.full(): + if self.metrics: + self.metrics.dropped() + return False + await queue.put(value) + return True + + except Exception as e: + logger.error(f"Failed to deliver message: {e}") + return False +``` + +**المزايا الرئيسية للتصميم (مطابقة لنمط الناشر):** +**موقع معالجة واحد:** تتم جميع عمليات معالجة الرسائل في الطريقة `run()`. +**آلة حالة واضحة:** ثلاثة حالات واضحة - قيد التشغيل، في مرحلة التفريغ، متوقفة. +**الإيقاف المؤقت أثناء التفريغ:** تتوقف عن قبول رسائل جديدة من Pulsar أثناء تفريغ قوائم الانتظار الحالية. +**حماية ضد المهلة:** لن تتعطل إلى أجل غير مسمى أثناء التفريغ. +**تنظيف صحيح:** تعترف بأي رسائل لم يتم تسليمها على الإغلاق. + +#### ب. تحسينات معالج التصدير + +**الملف:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py` + +```python +class TriplesExport: + async def destroy(self): + """Enhanced destroy with graceful shutdown""" + # Step 1: Signal stop to prevent new messages + self.running.stop() + + # Step 2: Wait briefly for in-flight messages + await asyncio.sleep(0.5) + + # Step 3: Unsubscribe and stop subscriber (triggers queue drain) + if hasattr(self, 'subs'): + await self.subs.unsubscribe_all(self.id) + await self.subs.stop() + + # Step 4: Close websocket last + if self.ws and not self.ws.closed: + await self.ws.close() + + async def run(self): + """Enhanced run with better error handling""" + self.subs = Subscriber( + client = self.pulsar_client, + topic = self.queue, + consumer_name = self.consumer, + subscription = self.subscriber, + schema = Triples, + backpressure_strategy = "block" # Configurable + ) + + await self.subs.start() + + self.id = str(uuid.uuid4()) + q = await self.subs.subscribe_all(self.id) + + consecutive_errors = 0 + max_consecutive_errors = 5 + + while self.running.get(): + try: + resp = await asyncio.wait_for(q.get(), timeout=0.5) + await self.ws.send_json(serialize_triples(resp)) + consecutive_errors = 0 # Reset on success + + except asyncio.TimeoutError: + continue + + except queue.Empty: + continue + + except Exception as e: + logger.error(f"Exception sending to websocket: {str(e)}") + consecutive_errors += 1 + + if consecutive_errors >= max_consecutive_errors: + logger.error("Too many consecutive errors, shutting down") + break + + # Brief pause before retry + await asyncio.sleep(0.1) + + # Graceful cleanup handled in destroy() +``` + +### 3. تحسينات على مستوى المقابس. + +**الملف:** `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` + +```python +class SocketEndpoint: + async def listener(self, ws, dispatcher, running): + """Enhanced listener with graceful shutdown""" + async for msg in ws: + if msg.type == WSMsgType.TEXT: + await dispatcher.receive(msg) + continue + elif msg.type == WSMsgType.BINARY: + await dispatcher.receive(msg) + continue + else: + # Graceful shutdown on close + logger.info("Websocket closing, initiating graceful shutdown") + running.stop() + + # Allow time for dispatcher cleanup + await asyncio.sleep(1.0) + break + + async def handle(self, request): + """Enhanced handler with better cleanup""" + # ... existing setup code ... + + try: + async with asyncio.TaskGroup() as tg: + running = Running() + + dispatcher = await self.dispatcher( + ws, running, request.match_info + ) + + worker_task = tg.create_task( + self.worker(ws, dispatcher, running) + ) + + lsnr_task = tg.create_task( + self.listener(ws, dispatcher, running) + ) + + except ExceptionGroup as e: + logger.error("Exception group occurred:", exc_info=True) + + # Attempt graceful dispatcher shutdown + try: + await asyncio.wait_for( + dispatcher.destroy(), + timeout=5.0 + ) + except asyncio.TimeoutError: + logger.warning("Dispatcher shutdown timed out") + except Exception as de: + logger.error(f"Error during dispatcher cleanup: {de}") + + except Exception as e: + logger.error(f"Socket exception: {e}", exc_info=True) + + finally: + # Ensure dispatcher cleanup + if dispatcher and hasattr(dispatcher, 'destroy'): + try: + await dispatcher.destroy() + except: + pass + + # Ensure websocket is closed + if ws and not ws.closed: + await ws.close() + + return ws +``` + +## خيارات التكوين + +إضافة دعم للتكوين لضبط السلوك: + +```python +# config.py +class GracefulShutdownConfig: + # Publisher settings + PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout + + # Subscriber settings + SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new" + SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure + + # Socket settings + SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown + MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown + + # Monitoring + LOG_QUEUE_STATS = True # Log queue statistics on shutdown + METRICS_ENABLED = True # Enable metrics collection +``` + +## استراتيجية الاختبار + +### اختبارات الوحدة + +```python +async def test_publisher_queue_drain(): + """Verify Publisher drains queue on shutdown""" + publisher = Publisher(...) + + # Fill queue with messages + for i in range(10): + await publisher.send(f"id-{i}", {"data": i}) + + # Stop publisher + await publisher.stop() + + # Verify all messages were sent + assert publisher.q.empty() + assert mock_producer.send.call_count == 10 + +async def test_subscriber_deferred_ack(): + """Verify Subscriber only acks on successful delivery""" + subscriber = Subscriber(..., backpressure_strategy="drop_new") + + # Fill queue to capacity + queue = await subscriber.subscribe("test") + for i in range(100): + await queue.put({"data": i}) + + # Try to add message when full + msg = create_mock_message() + await subscriber._process_message(msg) + + # Verify negative acknowledgment + assert msg.negative_acknowledge.called + assert not msg.acknowledge.called +``` + +### اختبارات التكامل + +```python +async def test_import_graceful_shutdown(): + """Test import path handles shutdown gracefully""" + # Setup + import_handler = TriplesImport(...) + await import_handler.start() + + # Send messages + messages = [] + for i in range(100): + msg = {"metadata": {...}, "triples": [...]} + await import_handler.receive(msg) + messages.append(msg) + + # Shutdown while messages in flight + await import_handler.destroy() + + # Verify all messages reached Pulsar + received = await pulsar_consumer.receive_all() + assert len(received) == 100 + +async def test_export_no_message_loss(): + """Test export path doesn't lose acknowledged messages""" + # Setup Pulsar with test messages + for i in range(100): + await pulsar_producer.send({"data": i}) + + # Start export handler + export_handler = TriplesExport(...) + export_task = asyncio.create_task(export_handler.run()) + + # Receive some messages + received = [] + for _ in range(50): + msg = await websocket.receive() + received.append(msg) + + # Force shutdown + await export_handler.destroy() + + # Continue receiving until websocket closes + while not websocket.closed: + try: + msg = await websocket.receive() + received.append(msg) + except: + break + + # Verify no acknowledged messages were lost + assert len(received) >= 50 +``` + +## خطة التنفيذ + +### المرحلة الأولى: الإصلاحات الحرجة (الأسبوع الأول) +إصلاح توقيت إقرار المشترك (لمنع فقدان الرسائل) +إضافة تفريغ قائمة الناشر +النشر في بيئة الاختبار + +### المرحلة الثانية: الإغلاق التدريجي (الأسبوع الثاني) +تطبيق تنسيق الإغلاق +إضافة استراتيجيات الضغط العكسي +اختبار الأداء + +### المرحلة الثالثة: المراقبة والضبط (الأسبوع الثالث) +إضافة مقاييس لعمق قائمة الانتظار +إضافة تنبيهات لفقدان الرسائل +ضبط قيم المهلة بناءً على بيانات الإنتاج + +## المراقبة والتنبيهات + +### المقاييس التي يجب تتبعها +`publisher.queue.depth` - حجم قائمة الانتظار الحالية للناشر +`publisher.messages.dropped` - الرسائل المفقودة أثناء الإغلاق +`subscriber.messages.negatively_acknowledged` - عمليات التسليم الفاشلة +`websocket.graceful_shutdowns` - عمليات الإغلاق التدريجي الناجحة +`websocket.forced_shutdowns` - عمليات الإغلاق القسري/المهلة + +### التنبيهات +عمق قائمة الانتظار للناشر > 80٪ من السعة +أي فقدان للرسائل أثناء الإغلاق +معدل الإقرار السلبي للمشترك > 1٪ +تجاوز مهلة الإغلاق + +## التوافق مع الإصدارات السابقة + +جميع التغييرات تحافظ على التوافق مع الإصدارات السابقة: +السلوك الافتراضي لم يتغير بدون تكوين +تستمر عمليات النشر الحالية في العمل +تدهور تدريجي في حالة عدم توفر الميزات الجديدة + +## اعتبارات الأمان + +لم يتم إدخال مسارات هجوم جديدة +يمنع الضغط العكسي هجمات استنفاد الذاكرة +تمنع الحدود القابلة للتكوين إساءة استخدام الموارد + +## تأثير الأداء + +تكلفة إضافية قليلة أثناء التشغيل العادي +قد يستغرق الإغلاق ما يصل إلى 5 ثوانٍ إضافية (قابل للتكوين) +يحد استخدام الذاكرة من خلال حدود حجم قائمة الانتظار +التأثير على وحدة المعالجة المركزية ضئيل (<1٪ زيادة) \ No newline at end of file diff --git a/docs/tech-specs/import-export-graceful-shutdown.es.md b/docs/tech-specs/import-export-graceful-shutdown.es.md new file mode 100644 index 00000000..803f9195 --- /dev/null +++ b/docs/tech-specs/import-export-graceful-shutdown.es.md @@ -0,0 +1,682 @@ +# Especificación Técnica para el Cierre de Sesión Gratuito de Importación/Exportación + +## Declaración del Problema + +Actualmente, la puerta de enlace TrustGraph experimenta pérdida de mensajes durante el cierre de la conexión websocket tanto en las operaciones de importación como de exportación. Esto ocurre debido a condiciones de carrera donde los mensajes en tránsito se descartan antes de llegar a su destino (colas Pulsar para importaciones, clientes websocket para exportaciones). + +### Problemas del Lado de Importación +1. El búfer de la cola asyncio del publicador no se vacía durante el apagado. +2. La conexión websocket se cierra antes de asegurarse de que los mensajes en cola lleguen a Pulsar. +3. No hay un mecanismo de confirmación para la entrega exitosa de mensajes. + +### Problemas del Lado de Exportación +1. Los mensajes se confirman en Pulsar antes de la entrega exitosa a los clientes. +2. Los tiempos de espera codificados de forma rígida causan la pérdida de mensajes cuando las colas están llenas. +3. No hay un mecanismo de retroalimentación para manejar consumidores lentos. +4. Múltiples puntos de búfer donde los datos pueden perderse. + +## Descripción General de la Arquitectura + +``` +Import Flow: +Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue + +Export Flow: +Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client +``` + +## Soluciones propuestas + +### 1. Mejoras para el publicador (lado de importación) + +#### A. Vaciado de la cola de forma gradual + +**Archivo**: `trustgraph-base/trustgraph/base/publisher.py` + +```python +class Publisher: + def __init__(self, client, topic, schema=None, max_size=10, + chunking_enabled=True, drain_timeout=5.0): + self.client = client + self.topic = topic + self.schema = schema + self.q = asyncio.Queue(maxsize=max_size) + self.chunking_enabled = chunking_enabled + self.running = True + self.draining = False # New state for graceful shutdown + self.task = None + self.drain_timeout = drain_timeout + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + try: + producer = self.client.create_producer( + topic=self.topic, + schema=JsonSchema(self.schema), + chunking_enabled=self.chunking_enabled, + ) + + drain_end_time = None + + while self.running or self.draining: + try: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s") + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + if not self.q.empty(): + logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining") + self.draining = False + break + + # Calculate wait timeout based on mode + if self.draining: + # Shorter timeout during draining to exit quickly when empty + timeout = min(0.1, drain_end_time - time.time()) + else: + # Normal operation timeout + timeout = 0.25 + + # Get message from queue + id, item = await asyncio.wait_for( + self.q.get(), + timeout=timeout + ) + + # Send the message (single place for sending) + if id: + producer.send(item, { "id": id }) + else: + producer.send(item) + + except asyncio.TimeoutError: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + except asyncio.QueueEmpty: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + # Flush producer before closing + if producer: + producer.flush() + producer.close() + + except Exception as e: + logger.error(f"Exception in publisher: {e}", exc_info=True) + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def send(self, id, item): + """Send still works normally - just adds to queue""" + if self.draining: + # Optionally reject new messages during drain + raise RuntimeError("Publisher is shutting down, not accepting new messages") + await self.q.put((id, item)) +``` + +**Beneficios Clave del Diseño:** +**Ubicación Única para el Envío**: Todas las llamadas a `producer.send()` se realizan en un solo lugar dentro del método `run()`. +**Máquina de Estados Clara**: Tres estados claros: en ejecución, en drenaje, detenido. +**Protección contra Tiempo de Espera**: No se quedará bloqueado indefinidamente durante el drenaje. +**Mejor Observabilidad**: Registro claro del progreso del drenaje y las transiciones de estado. +**Rechazo de Mensajes Opcional**: Puede rechazar nuevos mensajes durante la fase de apagado. + +#### B. Orden de Apagado Mejorado + +**Archivo**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py` + +```python +class TriplesImport: + async def destroy(self): + """Enhanced destroy with proper shutdown order""" + # Step 1: Stop accepting new messages + self.running.stop() + + # Step 2: Wait for publisher to drain its queue + logger.info("Draining publisher queue...") + await self.publisher.stop() + + # Step 3: Close websocket only after queue is drained + if self.ws: + await self.ws.close() +``` + +### 2. Mejoras para el Suscriptor (Lado de Exportación) + +#### A. Patrón de Drenaje Integrado + +**Archivo**: `trustgraph-base/trustgraph/base/subscriber.py` + +```python +class Subscriber: + def __init__(self, client, topic, subscription, consumer_name, + schema=None, max_size=100, metrics=None, + backpressure_strategy="block", drain_timeout=5.0): + # ... existing init ... + self.backpressure_strategy = backpressure_strategy + self.running = True + self.draining = False # New state for graceful shutdown + self.drain_timeout = drain_timeout + self.pending_acks = {} # Track messages awaiting delivery + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + if self.metrics: + self.metrics.state("stopped") + + try: + self.consumer = self.client.subscribe( + topic = self.topic, + subscription_name = self.subscription, + consumer_name = self.consumer_name, + schema = JsonSchema(self.schema), + ) + + if self.metrics: + self.metrics.state("running") + + logger.info("Subscriber running...") + drain_end_time = None + + while self.running or self.draining: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s") + + # Stop accepting new messages from Pulsar during drain + self.consumer.pause_message_listener() + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + async with self.lock: + total_pending = sum( + q.qsize() for q in + list(self.q.values()) + list(self.full.values()) + ) + if total_pending > 0: + logger.warning(f"Drain timeout reached with {total_pending} messages in queues") + self.draining = False + break + + # Check if we can exit drain mode + if self.draining: + async with self.lock: + all_empty = all( + q.empty() for q in + list(self.q.values()) + list(self.full.values()) + ) + if all_empty and len(self.pending_acks) == 0: + logger.info("Subscriber queues drained successfully") + self.draining = False + break + + # Process messages only if not draining + if not self.draining: + try: + msg = await asyncio.to_thread( + self.consumer.receive, + timeout_millis=250 + ) + except _pulsar.Timeout: + continue + except Exception as e: + logger.error(f"Exception in subscriber receive: {e}", exc_info=True) + raise e + + if self.metrics: + self.metrics.received() + + # Process the message + await self._process_message(msg) + else: + # During draining, just wait for queues to empty + await asyncio.sleep(0.1) + + except Exception as e: + logger.error(f"Subscriber exception: {e}", exc_info=True) + + finally: + # Negative acknowledge any pending messages + for msg in self.pending_acks.values(): + self.consumer.negative_acknowledge(msg) + self.pending_acks.clear() + + if self.consumer: + self.consumer.unsubscribe() + self.consumer.close() + self.consumer = None + + if self.metrics: + self.metrics.state("stopped") + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def _process_message(self, msg): + """Process a single message with deferred acknowledgment""" + # Store message for later acknowledgment + msg_id = str(uuid.uuid4()) + self.pending_acks[msg_id] = msg + + try: + id = msg.properties()["id"] + except: + id = None + + value = msg.value() + delivery_success = False + + async with self.lock: + # Deliver to specific subscribers + if id in self.q: + delivery_success = await self._deliver_to_queue( + self.q[id], value + ) + + # Deliver to all subscribers + for q in self.full.values(): + if await self._deliver_to_queue(q, value): + delivery_success = True + + # Acknowledge only on successful delivery + if delivery_success: + self.consumer.acknowledge(msg) + del self.pending_acks[msg_id] + else: + # Negative acknowledge for retry + self.consumer.negative_acknowledge(msg) + del self.pending_acks[msg_id] + + async def _deliver_to_queue(self, queue, value): + """Deliver message to queue with backpressure handling""" + try: + if self.backpressure_strategy == "block": + # Block until space available (no timeout) + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_oldest": + # Drop oldest message if queue full + if queue.full(): + try: + queue.get_nowait() + if self.metrics: + self.metrics.dropped() + except asyncio.QueueEmpty: + pass + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_new": + # Drop new message if queue full + if queue.full(): + if self.metrics: + self.metrics.dropped() + return False + await queue.put(value) + return True + + except Exception as e: + logger.error(f"Failed to deliver message: {e}") + return False +``` + +**Beneficios clave del diseño (que coinciden con el patrón del editor):** +**Ubicación de procesamiento única**: Todo el procesamiento de mensajes se realiza en el método `run()`. +**Máquina de estados limpia**: Tres estados claros: en ejecución, vaciado, detenido. +**Pausa durante el vaciado**: Deja de aceptar nuevos mensajes de Pulsar mientras vacía las colas existentes. +**Protección por tiempo de espera**: No se quedará bloqueado indefinidamente durante el vaciado. +**Limpieza adecuada**: Reconoce negativamente cualquier mensaje no entregado al apagar. + +#### B. Mejoras del controlador de exportación + +**Archivo**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py` + +```python +class TriplesExport: + async def destroy(self): + """Enhanced destroy with graceful shutdown""" + # Step 1: Signal stop to prevent new messages + self.running.stop() + + # Step 2: Wait briefly for in-flight messages + await asyncio.sleep(0.5) + + # Step 3: Unsubscribe and stop subscriber (triggers queue drain) + if hasattr(self, 'subs'): + await self.subs.unsubscribe_all(self.id) + await self.subs.stop() + + # Step 4: Close websocket last + if self.ws and not self.ws.closed: + await self.ws.close() + + async def run(self): + """Enhanced run with better error handling""" + self.subs = Subscriber( + client = self.pulsar_client, + topic = self.queue, + consumer_name = self.consumer, + subscription = self.subscriber, + schema = Triples, + backpressure_strategy = "block" # Configurable + ) + + await self.subs.start() + + self.id = str(uuid.uuid4()) + q = await self.subs.subscribe_all(self.id) + + consecutive_errors = 0 + max_consecutive_errors = 5 + + while self.running.get(): + try: + resp = await asyncio.wait_for(q.get(), timeout=0.5) + await self.ws.send_json(serialize_triples(resp)) + consecutive_errors = 0 # Reset on success + + except asyncio.TimeoutError: + continue + + except queue.Empty: + continue + + except Exception as e: + logger.error(f"Exception sending to websocket: {str(e)}") + consecutive_errors += 1 + + if consecutive_errors >= max_consecutive_errors: + logger.error("Too many consecutive errors, shutting down") + break + + # Brief pause before retry + await asyncio.sleep(0.1) + + # Graceful cleanup handled in destroy() +``` + +### 3. Mejoras a nivel de socket + +**Archivo**: `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` + +```python +class SocketEndpoint: + async def listener(self, ws, dispatcher, running): + """Enhanced listener with graceful shutdown""" + async for msg in ws: + if msg.type == WSMsgType.TEXT: + await dispatcher.receive(msg) + continue + elif msg.type == WSMsgType.BINARY: + await dispatcher.receive(msg) + continue + else: + # Graceful shutdown on close + logger.info("Websocket closing, initiating graceful shutdown") + running.stop() + + # Allow time for dispatcher cleanup + await asyncio.sleep(1.0) + break + + async def handle(self, request): + """Enhanced handler with better cleanup""" + # ... existing setup code ... + + try: + async with asyncio.TaskGroup() as tg: + running = Running() + + dispatcher = await self.dispatcher( + ws, running, request.match_info + ) + + worker_task = tg.create_task( + self.worker(ws, dispatcher, running) + ) + + lsnr_task = tg.create_task( + self.listener(ws, dispatcher, running) + ) + + except ExceptionGroup as e: + logger.error("Exception group occurred:", exc_info=True) + + # Attempt graceful dispatcher shutdown + try: + await asyncio.wait_for( + dispatcher.destroy(), + timeout=5.0 + ) + except asyncio.TimeoutError: + logger.warning("Dispatcher shutdown timed out") + except Exception as de: + logger.error(f"Error during dispatcher cleanup: {de}") + + except Exception as e: + logger.error(f"Socket exception: {e}", exc_info=True) + + finally: + # Ensure dispatcher cleanup + if dispatcher and hasattr(dispatcher, 'destroy'): + try: + await dispatcher.destroy() + except: + pass + + # Ensure websocket is closed + if ws and not ws.closed: + await ws.close() + + return ws +``` + +## Opciones de configuración + +Agregar soporte de configuración para ajustar el comportamiento: + +```python +# config.py +class GracefulShutdownConfig: + # Publisher settings + PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout + + # Subscriber settings + SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new" + SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure + + # Socket settings + SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown + MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown + + # Monitoring + LOG_QUEUE_STATS = True # Log queue statistics on shutdown + METRICS_ENABLED = True # Enable metrics collection +``` + +## Estrategia de pruebas + +### Pruebas unitarias + +```python +async def test_publisher_queue_drain(): + """Verify Publisher drains queue on shutdown""" + publisher = Publisher(...) + + # Fill queue with messages + for i in range(10): + await publisher.send(f"id-{i}", {"data": i}) + + # Stop publisher + await publisher.stop() + + # Verify all messages were sent + assert publisher.q.empty() + assert mock_producer.send.call_count == 10 + +async def test_subscriber_deferred_ack(): + """Verify Subscriber only acks on successful delivery""" + subscriber = Subscriber(..., backpressure_strategy="drop_new") + + # Fill queue to capacity + queue = await subscriber.subscribe("test") + for i in range(100): + await queue.put({"data": i}) + + # Try to add message when full + msg = create_mock_message() + await subscriber._process_message(msg) + + # Verify negative acknowledgment + assert msg.negative_acknowledge.called + assert not msg.acknowledge.called +``` + +### Pruebas de Integración + +```python +async def test_import_graceful_shutdown(): + """Test import path handles shutdown gracefully""" + # Setup + import_handler = TriplesImport(...) + await import_handler.start() + + # Send messages + messages = [] + for i in range(100): + msg = {"metadata": {...}, "triples": [...]} + await import_handler.receive(msg) + messages.append(msg) + + # Shutdown while messages in flight + await import_handler.destroy() + + # Verify all messages reached Pulsar + received = await pulsar_consumer.receive_all() + assert len(received) == 100 + +async def test_export_no_message_loss(): + """Test export path doesn't lose acknowledged messages""" + # Setup Pulsar with test messages + for i in range(100): + await pulsar_producer.send({"data": i}) + + # Start export handler + export_handler = TriplesExport(...) + export_task = asyncio.create_task(export_handler.run()) + + # Receive some messages + received = [] + for _ in range(50): + msg = await websocket.receive() + received.append(msg) + + # Force shutdown + await export_handler.destroy() + + # Continue receiving until websocket closes + while not websocket.closed: + try: + msg = await websocket.receive() + received.append(msg) + except: + break + + # Verify no acknowledged messages were lost + assert len(received) >= 50 +``` + +## Plan de Implementación + +### Fase 1: Correcciones Críticas (Semana 1) +Corregir el tiempo de confirmación del suscriptor (prevenir la pérdida de mensajes) +Agregar el vaciado de la cola del publicador +Implementar en el entorno de pruebas + +### Fase 2: Cierre Gratuito (Semana 2) +Implementar la coordinación del cierre +Agregar estrategias de contrapresión +Pruebas de rendimiento + +### Fase 3: Monitoreo y Ajuste (Semana 3) +Agregar métricas para las profundidades de la cola +Agregar alertas para la pérdida de mensajes +Ajustar los valores de tiempo de espera según los datos de producción + +## Monitoreo y Alertas + +### Métricas a Monitorear +`publisher.queue.depth` - Tamaño actual de la cola del publicador +`publisher.messages.dropped` - Mensajes perdidos durante el cierre +`subscriber.messages.negatively_acknowledged` - Entregas fallidas +`websocket.graceful_shutdowns` - Cierres gratuitos exitosos +`websocket.forced_shutdowns` - Cierres forzados/por tiempo de espera + +### Alertas +Profundidad de la cola del publicador > 80% de capacidad +Cualquier pérdida de mensajes durante el cierre +Tasa de acuse de recibo negativo del suscriptor > 1% +Tiempo de espera del cierre excedido + +## Compatibilidad con Versiones Anteriores + +Todos los cambios mantienen la compatibilidad con versiones anteriores: +El comportamiento predeterminado no cambia sin configuración +Las implementaciones existentes continúan funcionando +Degradación gradual si las nuevas funciones no están disponibles + +## Consideraciones de Seguridad + +No se introducen nuevos vectores de ataque +La contrapresión evita los ataques de agotamiento de memoria +Los límites configurables previenen el abuso de recursos + +## Impacto en el Rendimiento + +Sobre carga mínima durante la operación normal +El cierre puede tardar hasta 5 segundos más (configurable) +El uso de memoria está limitado por los límites del tamaño de la cola +El impacto en la CPU es insignificante (<1% de aumento) \ No newline at end of file diff --git a/docs/tech-specs/import-export-graceful-shutdown.he.md b/docs/tech-specs/import-export-graceful-shutdown.he.md new file mode 100644 index 00000000..6d92cdf4 --- /dev/null +++ b/docs/tech-specs/import-export-graceful-shutdown.he.md @@ -0,0 +1,682 @@ +# מפרט טכני לסגירה חלקה של ייבוא/יצוא + +## הצהרת בעיה + +שער TrustGraph חווה כרגע אובדן הודעות במהלך סגירת WebSocket בפעולות ייבוא ויצוא כאחד. זה קורה עקב מצבי מירוץ שבהם הודעות בתנועה נזרקות לפני שהן מגיעות ליעדים שלהן (תורי Pulsar לייבוא, לקוחות WebSocket לייצוא). + +### בעיות בצד הייבוא +1. מאגר ה-asyncio.Queue של המפרסם אינו מרוקן במהלך השבתה. +2. WebSocket נסגר לפני הבטחה שהודעות בתור יגיעו ל-Pulsar. +3. אין מנגנון אישור עבור מסירת הודעות מוצלחת. + +### בעיות בצד היצוא +1. הודעות מאושרות ב-Pulsar לפני מסירה מוצלחת ללקוחות. +2. זמני תפוגה מוגדרים מראש גורמים לאובדן הודעות כאשר התורים מלאים. +3. אין מנגנון לחץ נגדי לטיפול בצרכנים איטיים. +4. נקודות מאגר מרובות שבהן ניתן לאבד נתונים. + +## סקירה כללית של הארכיטקטורה + +``` +Import Flow: +Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue + +Export Flow: +Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client +``` + +## תיקונים מוצעים + +### 1. שיפורים עבור מפרסמים (צד הייבוא) + +#### א. ניקוז תור חלק + +**קובץ:** `trustgraph-base/trustgraph/base/publisher.py` + +```python +class Publisher: + def __init__(self, client, topic, schema=None, max_size=10, + chunking_enabled=True, drain_timeout=5.0): + self.client = client + self.topic = topic + self.schema = schema + self.q = asyncio.Queue(maxsize=max_size) + self.chunking_enabled = chunking_enabled + self.running = True + self.draining = False # New state for graceful shutdown + self.task = None + self.drain_timeout = drain_timeout + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + try: + producer = self.client.create_producer( + topic=self.topic, + schema=JsonSchema(self.schema), + chunking_enabled=self.chunking_enabled, + ) + + drain_end_time = None + + while self.running or self.draining: + try: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s") + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + if not self.q.empty(): + logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining") + self.draining = False + break + + # Calculate wait timeout based on mode + if self.draining: + # Shorter timeout during draining to exit quickly when empty + timeout = min(0.1, drain_end_time - time.time()) + else: + # Normal operation timeout + timeout = 0.25 + + # Get message from queue + id, item = await asyncio.wait_for( + self.q.get(), + timeout=timeout + ) + + # Send the message (single place for sending) + if id: + producer.send(item, { "id": id }) + else: + producer.send(item) + + except asyncio.TimeoutError: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + except asyncio.QueueEmpty: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + # Flush producer before closing + if producer: + producer.flush() + producer.close() + + except Exception as e: + logger.error(f"Exception in publisher: {e}", exc_info=True) + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def send(self, id, item): + """Send still works normally - just adds to queue""" + if self.draining: + # Optionally reject new messages during drain + raise RuntimeError("Publisher is shutting down, not accepting new messages") + await self.q.put((id, item)) +``` + +**יתרונות עיצוב מרכזיים:** +**מיקום שליחה יחיד**: כל הקריאות ל-`producer.send()` מתרחשות במקום אחד בתוך השיטה `run()`. +**מצב פעולה ברור:** שלושה מצבים ברורים - פעיל, ריקון, עצור. +**הגנה מפני תזמון מוגזם:** לא יימשך ללא הגבלת זמן במהלך הריקון. +**יכולת ניטור משופרת:** רישום ברור של התקדמות הריקון ומעברי מצב. +**דחיית הודעות אופציונלית:** ניתן לדחות הודעות חדשות במהלך שלב השבתה. + +#### ב. סדר השבתה משופר + +**קובץ:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py` + +```python +class TriplesImport: + async def destroy(self): + """Enhanced destroy with proper shutdown order""" + # Step 1: Stop accepting new messages + self.running.stop() + + # Step 2: Wait for publisher to drain its queue + logger.info("Draining publisher queue...") + await self.publisher.stop() + + # Step 3: Close websocket only after queue is drained + if self.ws: + await self.ws.close() +``` + +### 2. שיפורים למנויים (צד היצוא) + +#### א. תבנית ניקוז משולבת + +**קובץ**: `trustgraph-base/trustgraph/base/subscriber.py` + +```python +class Subscriber: + def __init__(self, client, topic, subscription, consumer_name, + schema=None, max_size=100, metrics=None, + backpressure_strategy="block", drain_timeout=5.0): + # ... existing init ... + self.backpressure_strategy = backpressure_strategy + self.running = True + self.draining = False # New state for graceful shutdown + self.drain_timeout = drain_timeout + self.pending_acks = {} # Track messages awaiting delivery + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + if self.metrics: + self.metrics.state("stopped") + + try: + self.consumer = self.client.subscribe( + topic = self.topic, + subscription_name = self.subscription, + consumer_name = self.consumer_name, + schema = JsonSchema(self.schema), + ) + + if self.metrics: + self.metrics.state("running") + + logger.info("Subscriber running...") + drain_end_time = None + + while self.running or self.draining: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s") + + # Stop accepting new messages from Pulsar during drain + self.consumer.pause_message_listener() + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + async with self.lock: + total_pending = sum( + q.qsize() for q in + list(self.q.values()) + list(self.full.values()) + ) + if total_pending > 0: + logger.warning(f"Drain timeout reached with {total_pending} messages in queues") + self.draining = False + break + + # Check if we can exit drain mode + if self.draining: + async with self.lock: + all_empty = all( + q.empty() for q in + list(self.q.values()) + list(self.full.values()) + ) + if all_empty and len(self.pending_acks) == 0: + logger.info("Subscriber queues drained successfully") + self.draining = False + break + + # Process messages only if not draining + if not self.draining: + try: + msg = await asyncio.to_thread( + self.consumer.receive, + timeout_millis=250 + ) + except _pulsar.Timeout: + continue + except Exception as e: + logger.error(f"Exception in subscriber receive: {e}", exc_info=True) + raise e + + if self.metrics: + self.metrics.received() + + # Process the message + await self._process_message(msg) + else: + # During draining, just wait for queues to empty + await asyncio.sleep(0.1) + + except Exception as e: + logger.error(f"Subscriber exception: {e}", exc_info=True) + + finally: + # Negative acknowledge any pending messages + for msg in self.pending_acks.values(): + self.consumer.negative_acknowledge(msg) + self.pending_acks.clear() + + if self.consumer: + self.consumer.unsubscribe() + self.consumer.close() + self.consumer = None + + if self.metrics: + self.metrics.state("stopped") + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def _process_message(self, msg): + """Process a single message with deferred acknowledgment""" + # Store message for later acknowledgment + msg_id = str(uuid.uuid4()) + self.pending_acks[msg_id] = msg + + try: + id = msg.properties()["id"] + except: + id = None + + value = msg.value() + delivery_success = False + + async with self.lock: + # Deliver to specific subscribers + if id in self.q: + delivery_success = await self._deliver_to_queue( + self.q[id], value + ) + + # Deliver to all subscribers + for q in self.full.values(): + if await self._deliver_to_queue(q, value): + delivery_success = True + + # Acknowledge only on successful delivery + if delivery_success: + self.consumer.acknowledge(msg) + del self.pending_acks[msg_id] + else: + # Negative acknowledge for retry + self.consumer.negative_acknowledge(msg) + del self.pending_acks[msg_id] + + async def _deliver_to_queue(self, queue, value): + """Deliver message to queue with backpressure handling""" + try: + if self.backpressure_strategy == "block": + # Block until space available (no timeout) + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_oldest": + # Drop oldest message if queue full + if queue.full(): + try: + queue.get_nowait() + if self.metrics: + self.metrics.dropped() + except asyncio.QueueEmpty: + pass + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_new": + # Drop new message if queue full + if queue.full(): + if self.metrics: + self.metrics.dropped() + return False + await queue.put(value) + return True + + except Exception as e: + logger.error(f"Failed to deliver message: {e}") + return False +``` + +**יתרונות עיצוב מרכזיים (התאמה לדפוס של המפרסם):** +**מיקום עיבוד יחיד**: כל עיבוד ההודעות מתבצע בשיטה `run()`. +**מצב מכונה נקי**: שלושה מצבים ברורים - פעיל, ריקון, עצור. +**השהיה במהלך ריקון**: מפסיק לקבל הודעות חדשות מ-Pulsar תוך כדי ריקון תורים קיימים. +**הגנה מפני תזמון מוגזם**: לא ייקפא ללא סיבה במהלך הריקון. +**ניקוי תקין**: מודה בשלילה על כל הודעות שלא נמסרו בעת השבתה. + +#### ב. שיפורים למטפל ייצוא + +**קובץ:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py` + +```python +class TriplesExport: + async def destroy(self): + """Enhanced destroy with graceful shutdown""" + # Step 1: Signal stop to prevent new messages + self.running.stop() + + # Step 2: Wait briefly for in-flight messages + await asyncio.sleep(0.5) + + # Step 3: Unsubscribe and stop subscriber (triggers queue drain) + if hasattr(self, 'subs'): + await self.subs.unsubscribe_all(self.id) + await self.subs.stop() + + # Step 4: Close websocket last + if self.ws and not self.ws.closed: + await self.ws.close() + + async def run(self): + """Enhanced run with better error handling""" + self.subs = Subscriber( + client = self.pulsar_client, + topic = self.queue, + consumer_name = self.consumer, + subscription = self.subscriber, + schema = Triples, + backpressure_strategy = "block" # Configurable + ) + + await self.subs.start() + + self.id = str(uuid.uuid4()) + q = await self.subs.subscribe_all(self.id) + + consecutive_errors = 0 + max_consecutive_errors = 5 + + while self.running.get(): + try: + resp = await asyncio.wait_for(q.get(), timeout=0.5) + await self.ws.send_json(serialize_triples(resp)) + consecutive_errors = 0 # Reset on success + + except asyncio.TimeoutError: + continue + + except queue.Empty: + continue + + except Exception as e: + logger.error(f"Exception sending to websocket: {str(e)}") + consecutive_errors += 1 + + if consecutive_errors >= max_consecutive_errors: + logger.error("Too many consecutive errors, shutting down") + break + + # Brief pause before retry + await asyncio.sleep(0.1) + + # Graceful cleanup handled in destroy() +``` + +### 3. שיפורים ברמת החיבור (Socket) + +**קובץ:** `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` + +```python +class SocketEndpoint: + async def listener(self, ws, dispatcher, running): + """Enhanced listener with graceful shutdown""" + async for msg in ws: + if msg.type == WSMsgType.TEXT: + await dispatcher.receive(msg) + continue + elif msg.type == WSMsgType.BINARY: + await dispatcher.receive(msg) + continue + else: + # Graceful shutdown on close + logger.info("Websocket closing, initiating graceful shutdown") + running.stop() + + # Allow time for dispatcher cleanup + await asyncio.sleep(1.0) + break + + async def handle(self, request): + """Enhanced handler with better cleanup""" + # ... existing setup code ... + + try: + async with asyncio.TaskGroup() as tg: + running = Running() + + dispatcher = await self.dispatcher( + ws, running, request.match_info + ) + + worker_task = tg.create_task( + self.worker(ws, dispatcher, running) + ) + + lsnr_task = tg.create_task( + self.listener(ws, dispatcher, running) + ) + + except ExceptionGroup as e: + logger.error("Exception group occurred:", exc_info=True) + + # Attempt graceful dispatcher shutdown + try: + await asyncio.wait_for( + dispatcher.destroy(), + timeout=5.0 + ) + except asyncio.TimeoutError: + logger.warning("Dispatcher shutdown timed out") + except Exception as de: + logger.error(f"Error during dispatcher cleanup: {de}") + + except Exception as e: + logger.error(f"Socket exception: {e}", exc_info=True) + + finally: + # Ensure dispatcher cleanup + if dispatcher and hasattr(dispatcher, 'destroy'): + try: + await dispatcher.destroy() + except: + pass + + # Ensure websocket is closed + if ws and not ws.closed: + await ws.close() + + return ws +``` + +## אפשרויות תצורה + +הוספת תמיכה בתצורה לשינוי התנהגות: + +```python +# config.py +class GracefulShutdownConfig: + # Publisher settings + PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout + + # Subscriber settings + SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new" + SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure + + # Socket settings + SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown + MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown + + # Monitoring + LOG_QUEUE_STATS = True # Log queue statistics on shutdown + METRICS_ENABLED = True # Enable metrics collection +``` + +## אסטרטגיית בדיקות + +### בדיקות יחידה + +```python +async def test_publisher_queue_drain(): + """Verify Publisher drains queue on shutdown""" + publisher = Publisher(...) + + # Fill queue with messages + for i in range(10): + await publisher.send(f"id-{i}", {"data": i}) + + # Stop publisher + await publisher.stop() + + # Verify all messages were sent + assert publisher.q.empty() + assert mock_producer.send.call_count == 10 + +async def test_subscriber_deferred_ack(): + """Verify Subscriber only acks on successful delivery""" + subscriber = Subscriber(..., backpressure_strategy="drop_new") + + # Fill queue to capacity + queue = await subscriber.subscribe("test") + for i in range(100): + await queue.put({"data": i}) + + # Try to add message when full + msg = create_mock_message() + await subscriber._process_message(msg) + + # Verify negative acknowledgment + assert msg.negative_acknowledge.called + assert not msg.acknowledge.called +``` + +### בדיקות אינטגרציה + +```python +async def test_import_graceful_shutdown(): + """Test import path handles shutdown gracefully""" + # Setup + import_handler = TriplesImport(...) + await import_handler.start() + + # Send messages + messages = [] + for i in range(100): + msg = {"metadata": {...}, "triples": [...]} + await import_handler.receive(msg) + messages.append(msg) + + # Shutdown while messages in flight + await import_handler.destroy() + + # Verify all messages reached Pulsar + received = await pulsar_consumer.receive_all() + assert len(received) == 100 + +async def test_export_no_message_loss(): + """Test export path doesn't lose acknowledged messages""" + # Setup Pulsar with test messages + for i in range(100): + await pulsar_producer.send({"data": i}) + + # Start export handler + export_handler = TriplesExport(...) + export_task = asyncio.create_task(export_handler.run()) + + # Receive some messages + received = [] + for _ in range(50): + msg = await websocket.receive() + received.append(msg) + + # Force shutdown + await export_handler.destroy() + + # Continue receiving until websocket closes + while not websocket.closed: + try: + msg = await websocket.receive() + received.append(msg) + except: + break + + # Verify no acknowledged messages were lost + assert len(received) >= 50 +``` + +## תוכנית הטמעה + +### שלב 1: תיקונים קריטיים (שבוע 1) +תיקון תזמון אישור מנויים (מניעת אובדן הודעות) +הוספת ניקוז תור משדר +הטמעה בסביבת בדיקות + +### שלב 2: השבתה חלקה (שבוע 2) +הטמעת תיאום השבתה +הוספת אסטרטגיות לחץ נגדי +בדיקות ביצועים + +### שלב 3: ניטור וכוונון (שבוע 3) +הוספת מדדים לעומק תורים +הוספת התראות לאובדן הודעות +כוונון ערכי זמן קצוב בהתבסס על נתוני ייצור + +## ניטור והתראות + +### מדדים שיש לעקוב אחריהם +`publisher.queue.depth` - גודל נוכחי של תור המשדר +`publisher.messages.dropped` - הודעות שאבדו במהלך השבתה +`subscriber.messages.negatively_acknowledged` - משלוחים שנכשלו +`websocket.graceful_shutdowns` - השבתות חלקות מוצלחות +`websocket.forced_shutdowns` - השבתות בכוח/עקב חריגה מהזמן הקצוב + +### התראות +עומק תור המשדר > 80% מהקיבולת +כל אובדן הודעות במהלך השבתה +קצב אישור שלילי של מנויים > 1% +חריגה מהזמן הקצוב להשבתה + +## תאימות לאחור + +כל השינויים שומרים על תאימות לאחור: +התנהגות ברירת המחדל לא משתנה ללא תצורה +הטמעות קיימות ממשיכות לתפקד +ירידה הדרגתית בפעולה אם תכונות חדשות אינן זמינות + +## שיקולי אבטחה + +לא הוצגו וקטורי תקיפה חדשים +לחץ נגדי מונע התקפות של התעמקות זיכרון +מגבלות הניתנות לתצורה מונעות ניצול משאבים + +## השפעה על הביצועים + +תקורה מינימלית במהלך פעולה רגילה +השבתה עשויה לקחת עד 5 שניות נוספות (ניתן להגדרה) +השימוש בזיכרון מוגבל על ידי מגבלות גודל התור +השפעה על ה-CPU זניחה (<1% עלייה) \ No newline at end of file diff --git a/docs/tech-specs/import-export-graceful-shutdown.hi.md b/docs/tech-specs/import-export-graceful-shutdown.hi.md new file mode 100644 index 00000000..e5957e50 --- /dev/null +++ b/docs/tech-specs/import-export-graceful-shutdown.hi.md @@ -0,0 +1,682 @@ +# आयात/निर्यात के लिए सुचारू शटडाउन तकनीकी विनिर्देश + +## समस्या विवरण + +ट्रस्टग्राफ गेटवे वर्तमान में आयात और निर्यात दोनों कार्यों के दौरान वेबसॉकेट बंद होने के समय संदेश हानि का अनुभव करता है। यह दौड़ की स्थितियों के कारण होता है जहां पारगमन में मौजूद संदेश अपने गंतव्य (आयात के लिए पल्सर कतारों, निर्यात के लिए वेबसॉकेट क्लाइंट) तक पहुंचने से पहले त्याग दिए जाते हैं। + +### आयात-पक्ष की समस्याएं +1. प्रकाशक का asyncio.Queue बफर शटडाउन पर खाली नहीं होता है। +2. वेबसॉकेट बंद होने से पहले यह सुनिश्चित नहीं किया जाता है कि कतारबद्ध संदेश पल्सर तक पहुंचें। +3. सफल संदेश वितरण के लिए कोई स्वीकृति तंत्र नहीं है। + +### निर्यात-पक्ष की समस्याएं +1. संदेशों को क्लाइंट को सफलतापूर्वक वितरित होने से पहले पल्सर में स्वीकार किया जाता है। +2. हार्ड-कोडेड टाइमआउट के कारण संदेश ड्रॉप हो जाते हैं जब कतारें भरी होती हैं। +3. धीमी उपभोक्ताओं को संभालने के लिए कोई बैकप्रेशर तंत्र नहीं है। +4. कई बफर बिंदु जहां डेटा खो सकता है। + +## वास्तुकला अवलोकन + +``` +Import Flow: +Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue + +Export Flow: +Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client +``` + +## प्रस्तावित सुधार + +### 1. प्रकाशक में सुधार (आयात पक्ष) + +#### ए. सुचारू कतार खाली करना + +**फ़ाइल**: `trustgraph-base/trustgraph/base/publisher.py` + +```python +class Publisher: + def __init__(self, client, topic, schema=None, max_size=10, + chunking_enabled=True, drain_timeout=5.0): + self.client = client + self.topic = topic + self.schema = schema + self.q = asyncio.Queue(maxsize=max_size) + self.chunking_enabled = chunking_enabled + self.running = True + self.draining = False # New state for graceful shutdown + self.task = None + self.drain_timeout = drain_timeout + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + try: + producer = self.client.create_producer( + topic=self.topic, + schema=JsonSchema(self.schema), + chunking_enabled=self.chunking_enabled, + ) + + drain_end_time = None + + while self.running or self.draining: + try: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s") + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + if not self.q.empty(): + logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining") + self.draining = False + break + + # Calculate wait timeout based on mode + if self.draining: + # Shorter timeout during draining to exit quickly when empty + timeout = min(0.1, drain_end_time - time.time()) + else: + # Normal operation timeout + timeout = 0.25 + + # Get message from queue + id, item = await asyncio.wait_for( + self.q.get(), + timeout=timeout + ) + + # Send the message (single place for sending) + if id: + producer.send(item, { "id": id }) + else: + producer.send(item) + + except asyncio.TimeoutError: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + except asyncio.QueueEmpty: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + # Flush producer before closing + if producer: + producer.flush() + producer.close() + + except Exception as e: + logger.error(f"Exception in publisher: {e}", exc_info=True) + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def send(self, id, item): + """Send still works normally - just adds to queue""" + if self.draining: + # Optionally reject new messages during drain + raise RuntimeError("Publisher is shutting down, not accepting new messages") + await self.q.put((id, item)) +``` + +**मुख्य डिज़ाइन लाभ:** +**एकल प्रेषण स्थान**: सभी `producer.send()` कॉल `run()` विधि के भीतर एक ही स्थान पर होते हैं। +**स्वच्छ स्टेट मशीन**: तीन स्पष्ट अवस्थाएँ - चल रही, खाली करने की प्रक्रिया में, बंद। +**टाइमआउट सुरक्षा**: खाली करने के दौरान अनिश्चित काल तक नहीं रुकेगा। +**बेहतर अवलोकन क्षमता**: खाली करने की प्रगति और अवस्था परिवर्तनों का स्पष्ट लॉगिंग। +**वैकल्पिक संदेश अस्वीकृति**: शटडाउन चरण के दौरान नए संदेशों को अस्वीकार किया जा सकता है। + +#### बी. बेहतर शटडाउन क्रम + +**फ़ाइल**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py` + +```python +class TriplesImport: + async def destroy(self): + """Enhanced destroy with proper shutdown order""" + # Step 1: Stop accepting new messages + self.running.stop() + + # Step 2: Wait for publisher to drain its queue + logger.info("Draining publisher queue...") + await self.publisher.stop() + + # Step 3: Close websocket only after queue is drained + if self.ws: + await self.ws.close() +``` + +### 2. ग्राहक सुधार (निर्यात पक्ष) + +#### ए. एकीकृत जल निकासी पैटर्न + +**फ़ाइल**: `trustgraph-base/trustgraph/base/subscriber.py` + +```python +class Subscriber: + def __init__(self, client, topic, subscription, consumer_name, + schema=None, max_size=100, metrics=None, + backpressure_strategy="block", drain_timeout=5.0): + # ... existing init ... + self.backpressure_strategy = backpressure_strategy + self.running = True + self.draining = False # New state for graceful shutdown + self.drain_timeout = drain_timeout + self.pending_acks = {} # Track messages awaiting delivery + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + if self.metrics: + self.metrics.state("stopped") + + try: + self.consumer = self.client.subscribe( + topic = self.topic, + subscription_name = self.subscription, + consumer_name = self.consumer_name, + schema = JsonSchema(self.schema), + ) + + if self.metrics: + self.metrics.state("running") + + logger.info("Subscriber running...") + drain_end_time = None + + while self.running or self.draining: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s") + + # Stop accepting new messages from Pulsar during drain + self.consumer.pause_message_listener() + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + async with self.lock: + total_pending = sum( + q.qsize() for q in + list(self.q.values()) + list(self.full.values()) + ) + if total_pending > 0: + logger.warning(f"Drain timeout reached with {total_pending} messages in queues") + self.draining = False + break + + # Check if we can exit drain mode + if self.draining: + async with self.lock: + all_empty = all( + q.empty() for q in + list(self.q.values()) + list(self.full.values()) + ) + if all_empty and len(self.pending_acks) == 0: + logger.info("Subscriber queues drained successfully") + self.draining = False + break + + # Process messages only if not draining + if not self.draining: + try: + msg = await asyncio.to_thread( + self.consumer.receive, + timeout_millis=250 + ) + except _pulsar.Timeout: + continue + except Exception as e: + logger.error(f"Exception in subscriber receive: {e}", exc_info=True) + raise e + + if self.metrics: + self.metrics.received() + + # Process the message + await self._process_message(msg) + else: + # During draining, just wait for queues to empty + await asyncio.sleep(0.1) + + except Exception as e: + logger.error(f"Subscriber exception: {e}", exc_info=True) + + finally: + # Negative acknowledge any pending messages + for msg in self.pending_acks.values(): + self.consumer.negative_acknowledge(msg) + self.pending_acks.clear() + + if self.consumer: + self.consumer.unsubscribe() + self.consumer.close() + self.consumer = None + + if self.metrics: + self.metrics.state("stopped") + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def _process_message(self, msg): + """Process a single message with deferred acknowledgment""" + # Store message for later acknowledgment + msg_id = str(uuid.uuid4()) + self.pending_acks[msg_id] = msg + + try: + id = msg.properties()["id"] + except: + id = None + + value = msg.value() + delivery_success = False + + async with self.lock: + # Deliver to specific subscribers + if id in self.q: + delivery_success = await self._deliver_to_queue( + self.q[id], value + ) + + # Deliver to all subscribers + for q in self.full.values(): + if await self._deliver_to_queue(q, value): + delivery_success = True + + # Acknowledge only on successful delivery + if delivery_success: + self.consumer.acknowledge(msg) + del self.pending_acks[msg_id] + else: + # Negative acknowledge for retry + self.consumer.negative_acknowledge(msg) + del self.pending_acks[msg_id] + + async def _deliver_to_queue(self, queue, value): + """Deliver message to queue with backpressure handling""" + try: + if self.backpressure_strategy == "block": + # Block until space available (no timeout) + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_oldest": + # Drop oldest message if queue full + if queue.full(): + try: + queue.get_nowait() + if self.metrics: + self.metrics.dropped() + except asyncio.QueueEmpty: + pass + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_new": + # Drop new message if queue full + if queue.full(): + if self.metrics: + self.metrics.dropped() + return False + await queue.put(value) + return True + + except Exception as e: + logger.error(f"Failed to deliver message: {e}") + return False +``` + +**मुख्य डिज़ाइन लाभ (प्रकाशक पैटर्न से मेल खाता):** +**एकल प्रसंस्करण स्थान**: सभी संदेश प्रसंस्करण `run()` विधि में होता है। +**स्वच्छ स्टेट मशीन**: तीन स्पष्ट अवस्थाएँ - चल रही, खाली करने की प्रक्रिया में, बंद। +**खाली करते समय विराम**: मौजूदा कतारों को खाली करते समय, पल्सर से नए संदेश स्वीकार करना बंद हो जाता है। +**समय-सीमा सुरक्षा**: खाली करने की प्रक्रिया के दौरान अनिश्चित काल तक नहीं रुकेगा। +**उचित सफाई**: शटडाउन पर, किसी भी अप्राप्त संदेश को नकारात्मक रूप से स्वीकार किया जाता है। + +#### बी. एक्सपोर्ट हैंडलर में सुधार + +**फ़ाइल**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py` + +```python +class TriplesExport: + async def destroy(self): + """Enhanced destroy with graceful shutdown""" + # Step 1: Signal stop to prevent new messages + self.running.stop() + + # Step 2: Wait briefly for in-flight messages + await asyncio.sleep(0.5) + + # Step 3: Unsubscribe and stop subscriber (triggers queue drain) + if hasattr(self, 'subs'): + await self.subs.unsubscribe_all(self.id) + await self.subs.stop() + + # Step 4: Close websocket last + if self.ws and not self.ws.closed: + await self.ws.close() + + async def run(self): + """Enhanced run with better error handling""" + self.subs = Subscriber( + client = self.pulsar_client, + topic = self.queue, + consumer_name = self.consumer, + subscription = self.subscriber, + schema = Triples, + backpressure_strategy = "block" # Configurable + ) + + await self.subs.start() + + self.id = str(uuid.uuid4()) + q = await self.subs.subscribe_all(self.id) + + consecutive_errors = 0 + max_consecutive_errors = 5 + + while self.running.get(): + try: + resp = await asyncio.wait_for(q.get(), timeout=0.5) + await self.ws.send_json(serialize_triples(resp)) + consecutive_errors = 0 # Reset on success + + except asyncio.TimeoutError: + continue + + except queue.Empty: + continue + + except Exception as e: + logger.error(f"Exception sending to websocket: {str(e)}") + consecutive_errors += 1 + + if consecutive_errors >= max_consecutive_errors: + logger.error("Too many consecutive errors, shutting down") + break + + # Brief pause before retry + await asyncio.sleep(0.1) + + # Graceful cleanup handled in destroy() +``` + +### 3. सॉकेट-स्तरीय सुधार + +**फ़ाइल**: `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` + +```python +class SocketEndpoint: + async def listener(self, ws, dispatcher, running): + """Enhanced listener with graceful shutdown""" + async for msg in ws: + if msg.type == WSMsgType.TEXT: + await dispatcher.receive(msg) + continue + elif msg.type == WSMsgType.BINARY: + await dispatcher.receive(msg) + continue + else: + # Graceful shutdown on close + logger.info("Websocket closing, initiating graceful shutdown") + running.stop() + + # Allow time for dispatcher cleanup + await asyncio.sleep(1.0) + break + + async def handle(self, request): + """Enhanced handler with better cleanup""" + # ... existing setup code ... + + try: + async with asyncio.TaskGroup() as tg: + running = Running() + + dispatcher = await self.dispatcher( + ws, running, request.match_info + ) + + worker_task = tg.create_task( + self.worker(ws, dispatcher, running) + ) + + lsnr_task = tg.create_task( + self.listener(ws, dispatcher, running) + ) + + except ExceptionGroup as e: + logger.error("Exception group occurred:", exc_info=True) + + # Attempt graceful dispatcher shutdown + try: + await asyncio.wait_for( + dispatcher.destroy(), + timeout=5.0 + ) + except asyncio.TimeoutError: + logger.warning("Dispatcher shutdown timed out") + except Exception as de: + logger.error(f"Error during dispatcher cleanup: {de}") + + except Exception as e: + logger.error(f"Socket exception: {e}", exc_info=True) + + finally: + # Ensure dispatcher cleanup + if dispatcher and hasattr(dispatcher, 'destroy'): + try: + await dispatcher.destroy() + except: + pass + + # Ensure websocket is closed + if ws and not ws.closed: + await ws.close() + + return ws +``` + +## कॉन्फ़िगरेशन विकल्प + +व्यवहार को अनुकूलित करने के लिए कॉन्फ़िगरेशन समर्थन जोड़ें: + +```python +# config.py +class GracefulShutdownConfig: + # Publisher settings + PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout + + # Subscriber settings + SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new" + SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure + + # Socket settings + SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown + MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown + + # Monitoring + LOG_QUEUE_STATS = True # Log queue statistics on shutdown + METRICS_ENABLED = True # Enable metrics collection +``` + +## परीक्षण रणनीति + +### यूनिट परीक्षण + +```python +async def test_publisher_queue_drain(): + """Verify Publisher drains queue on shutdown""" + publisher = Publisher(...) + + # Fill queue with messages + for i in range(10): + await publisher.send(f"id-{i}", {"data": i}) + + # Stop publisher + await publisher.stop() + + # Verify all messages were sent + assert publisher.q.empty() + assert mock_producer.send.call_count == 10 + +async def test_subscriber_deferred_ack(): + """Verify Subscriber only acks on successful delivery""" + subscriber = Subscriber(..., backpressure_strategy="drop_new") + + # Fill queue to capacity + queue = await subscriber.subscribe("test") + for i in range(100): + await queue.put({"data": i}) + + # Try to add message when full + msg = create_mock_message() + await subscriber._process_message(msg) + + # Verify negative acknowledgment + assert msg.negative_acknowledge.called + assert not msg.acknowledge.called +``` + +### एकीकरण परीक्षण (एकीकरण परीक्षण) + +```python +async def test_import_graceful_shutdown(): + """Test import path handles shutdown gracefully""" + # Setup + import_handler = TriplesImport(...) + await import_handler.start() + + # Send messages + messages = [] + for i in range(100): + msg = {"metadata": {...}, "triples": [...]} + await import_handler.receive(msg) + messages.append(msg) + + # Shutdown while messages in flight + await import_handler.destroy() + + # Verify all messages reached Pulsar + received = await pulsar_consumer.receive_all() + assert len(received) == 100 + +async def test_export_no_message_loss(): + """Test export path doesn't lose acknowledged messages""" + # Setup Pulsar with test messages + for i in range(100): + await pulsar_producer.send({"data": i}) + + # Start export handler + export_handler = TriplesExport(...) + export_task = asyncio.create_task(export_handler.run()) + + # Receive some messages + received = [] + for _ in range(50): + msg = await websocket.receive() + received.append(msg) + + # Force shutdown + await export_handler.destroy() + + # Continue receiving until websocket closes + while not websocket.closed: + try: + msg = await websocket.receive() + received.append(msg) + except: + break + + # Verify no acknowledged messages were lost + assert len(received) >= 50 +``` + +## रोलआउट योजना + +### चरण 1: महत्वपूर्ण सुधार (सप्ताह 1) +सब्सक्राइबर स्वीकृति समय को ठीक करें (संदेश हानि को रोकें) +पब्लिशर क्यू को खाली करने की सुविधा जोड़ें +स्टेजिंग वातावरण में तैनात करें + +### चरण 2: सुचारू शटडाउन (सप्ताह 2) +शटडाउन समन्वय लागू करें +बैकप्रेशर रणनीतियों को जोड़ें +प्रदर्शन परीक्षण + +### चरण 3: निगरानी और ट्यूनिंग (सप्ताह 3) +क्यू की गहराई के लिए मेट्रिक्स जोड़ें +संदेश ड्रॉप के लिए अलर्ट जोड़ें +उत्पादन डेटा के आधार पर टाइमआउट मानों को ट्यून करें + +## निगरानी और अलर्ट + +### ट्रैक करने के लिए मेट्रिक्स +`publisher.queue.depth` - वर्तमान पब्लिशर क्यू का आकार +`publisher.messages.dropped` - शटडाउन के दौरान खोए गए संदेश +`subscriber.messages.negatively_acknowledged` - विफल डिलीवरी +`websocket.graceful_shutdowns` - सफल सुचारू शटडाउन +`websocket.forced_shutdowns` - मजबूर/टाइमआउट शटडाउन + +### अलर्ट +पब्लिशर क्यू की गहराई > 80% क्षमता +शटडाउन के दौरान कोई भी संदेश ड्रॉप +सब्सक्राइबर नकारात्मक स्वीकृति दर > 1% +शटडाउन टाइमआउट समाप्त + +## पिछली अनुकूलता + +सभी परिवर्तनों में पिछली अनुकूलता बनी हुई है: +कॉन्फ़िगरेशन के बिना डिफ़ॉल्ट व्यवहार अपरिवर्तित रहता है +मौजूदा डिप्लॉयमेंट सामान्य रूप से काम करना जारी रखते हैं +यदि नई सुविधाएँ अनुपलब्ध हैं तो सुचारू गिरावट + +## सुरक्षा संबंधी विचार + +कोई नया आक्रमण वेक्टर नहीं जोड़ा गया +बैकप्रेशर मेमोरी थकावट हमलों को रोकता है +कॉन्फ़िगर करने योग्य सीमाएँ संसाधन दुरुपयोग को रोकती हैं + +## प्रदर्शन प्रभाव + +सामान्य संचालन के दौरान न्यूनतम ओवरहेड +शटडाउन में 5 सेकंड तक अधिक समय लग सकता है (कॉन्फ़िगर करने योग्य) +मेमोरी उपयोग क्यू आकार सीमाओं द्वारा सीमित है +CPU पर प्रभाव नगण्य (<1% वृद्धि) \ No newline at end of file diff --git a/docs/tech-specs/import-export-graceful-shutdown.pt.md b/docs/tech-specs/import-export-graceful-shutdown.pt.md new file mode 100644 index 00000000..bfbb250d --- /dev/null +++ b/docs/tech-specs/import-export-graceful-shutdown.pt.md @@ -0,0 +1,682 @@ +# Especificação Técnica de Desligamento Gratuito de Importação/Exportação + +## Declaração do Problema + +Atualmente, o gateway TrustGraph experimenta perda de mensagens durante o fechamento do WebSocket tanto em operações de importação quanto de exportação. Isso ocorre devido a condições de corrida em que as mensagens em trânsito são descartadas antes de atingir seu destino (filas Pulsar para importações, clientes WebSocket para exportações). + +### Problemas no Lado da Importação +1. O buffer da fila asyncio do publicador não é esvaziado durante o desligamento. +2. O WebSocket é fechado antes de garantir que as mensagens enfileiradas cheguem ao Pulsar. +3. Não há mecanismo de confirmação para a entrega bem-sucedida da mensagem. + +### Problemas no Lado da Exportação +1. As mensagens são confirmadas no Pulsar antes da entrega bem-sucedida aos clientes. +2. Os tempos limite fixos causam a perda de mensagens quando as filas estão cheias. +3. Não há mecanismo de controle de fluxo para lidar com consumidores lentos. +4. Múltiplos pontos de buffer onde os dados podem ser perdidos. + +## Visão Geral da Arquitetura + +``` +Import Flow: +Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue + +Export Flow: +Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client +``` + +## Correções Propostas + +### 1. Melhorias no Publicador (Lado da Importação) + +#### A. Esvaziamento Gratuito da Fila + +**Arquivo**: `trustgraph-base/trustgraph/base/publisher.py` + +```python +class Publisher: + def __init__(self, client, topic, schema=None, max_size=10, + chunking_enabled=True, drain_timeout=5.0): + self.client = client + self.topic = topic + self.schema = schema + self.q = asyncio.Queue(maxsize=max_size) + self.chunking_enabled = chunking_enabled + self.running = True + self.draining = False # New state for graceful shutdown + self.task = None + self.drain_timeout = drain_timeout + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + try: + producer = self.client.create_producer( + topic=self.topic, + schema=JsonSchema(self.schema), + chunking_enabled=self.chunking_enabled, + ) + + drain_end_time = None + + while self.running or self.draining: + try: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s") + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + if not self.q.empty(): + logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining") + self.draining = False + break + + # Calculate wait timeout based on mode + if self.draining: + # Shorter timeout during draining to exit quickly when empty + timeout = min(0.1, drain_end_time - time.time()) + else: + # Normal operation timeout + timeout = 0.25 + + # Get message from queue + id, item = await asyncio.wait_for( + self.q.get(), + timeout=timeout + ) + + # Send the message (single place for sending) + if id: + producer.send(item, { "id": id }) + else: + producer.send(item) + + except asyncio.TimeoutError: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + except asyncio.QueueEmpty: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + # Flush producer before closing + if producer: + producer.flush() + producer.close() + + except Exception as e: + logger.error(f"Exception in publisher: {e}", exc_info=True) + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def send(self, id, item): + """Send still works normally - just adds to queue""" + if self.draining: + # Optionally reject new messages during drain + raise RuntimeError("Publisher is shutting down, not accepting new messages") + await self.q.put((id, item)) +``` + +**Principais Vantagens do Design:** +**Local de Envio Único**: Todas as chamadas de `producer.send()` ocorrem em um único local dentro do método `run()`. +**Máquina de Estados Clara**: Três estados claros - em execução, esvaziando, parado. +**Proteção por Timeout**: Não fica indefinidamente travado durante o esvaziamento. +**Melhor Observabilidade**: Registro claro do progresso do esvaziamento e das transições de estado. +**Rejeição de Mensagens Opcional**: Pode rejeitar novas mensagens durante a fase de desligamento. + +#### B. Ordem de Desligamento Aprimorada + +**Arquivo**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py` + +```python +class TriplesImport: + async def destroy(self): + """Enhanced destroy with proper shutdown order""" + # Step 1: Stop accepting new messages + self.running.stop() + + # Step 2: Wait for publisher to drain its queue + logger.info("Draining publisher queue...") + await self.publisher.stop() + + # Step 3: Close websocket only after queue is drained + if self.ws: + await self.ws.close() +``` + +### 2. Melhorias para o Assinante (Lado de Exportação) + +#### A. Padrão de Drenagem Integrado + +**Arquivo**: `trustgraph-base/trustgraph/base/subscriber.py` + +```python +class Subscriber: + def __init__(self, client, topic, subscription, consumer_name, + schema=None, max_size=100, metrics=None, + backpressure_strategy="block", drain_timeout=5.0): + # ... existing init ... + self.backpressure_strategy = backpressure_strategy + self.running = True + self.draining = False # New state for graceful shutdown + self.drain_timeout = drain_timeout + self.pending_acks = {} # Track messages awaiting delivery + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + if self.metrics: + self.metrics.state("stopped") + + try: + self.consumer = self.client.subscribe( + topic = self.topic, + subscription_name = self.subscription, + consumer_name = self.consumer_name, + schema = JsonSchema(self.schema), + ) + + if self.metrics: + self.metrics.state("running") + + logger.info("Subscriber running...") + drain_end_time = None + + while self.running or self.draining: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s") + + # Stop accepting new messages from Pulsar during drain + self.consumer.pause_message_listener() + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + async with self.lock: + total_pending = sum( + q.qsize() for q in + list(self.q.values()) + list(self.full.values()) + ) + if total_pending > 0: + logger.warning(f"Drain timeout reached with {total_pending} messages in queues") + self.draining = False + break + + # Check if we can exit drain mode + if self.draining: + async with self.lock: + all_empty = all( + q.empty() for q in + list(self.q.values()) + list(self.full.values()) + ) + if all_empty and len(self.pending_acks) == 0: + logger.info("Subscriber queues drained successfully") + self.draining = False + break + + # Process messages only if not draining + if not self.draining: + try: + msg = await asyncio.to_thread( + self.consumer.receive, + timeout_millis=250 + ) + except _pulsar.Timeout: + continue + except Exception as e: + logger.error(f"Exception in subscriber receive: {e}", exc_info=True) + raise e + + if self.metrics: + self.metrics.received() + + # Process the message + await self._process_message(msg) + else: + # During draining, just wait for queues to empty + await asyncio.sleep(0.1) + + except Exception as e: + logger.error(f"Subscriber exception: {e}", exc_info=True) + + finally: + # Negative acknowledge any pending messages + for msg in self.pending_acks.values(): + self.consumer.negative_acknowledge(msg) + self.pending_acks.clear() + + if self.consumer: + self.consumer.unsubscribe() + self.consumer.close() + self.consumer = None + + if self.metrics: + self.metrics.state("stopped") + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def _process_message(self, msg): + """Process a single message with deferred acknowledgment""" + # Store message for later acknowledgment + msg_id = str(uuid.uuid4()) + self.pending_acks[msg_id] = msg + + try: + id = msg.properties()["id"] + except: + id = None + + value = msg.value() + delivery_success = False + + async with self.lock: + # Deliver to specific subscribers + if id in self.q: + delivery_success = await self._deliver_to_queue( + self.q[id], value + ) + + # Deliver to all subscribers + for q in self.full.values(): + if await self._deliver_to_queue(q, value): + delivery_success = True + + # Acknowledge only on successful delivery + if delivery_success: + self.consumer.acknowledge(msg) + del self.pending_acks[msg_id] + else: + # Negative acknowledge for retry + self.consumer.negative_acknowledge(msg) + del self.pending_acks[msg_id] + + async def _deliver_to_queue(self, queue, value): + """Deliver message to queue with backpressure handling""" + try: + if self.backpressure_strategy == "block": + # Block until space available (no timeout) + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_oldest": + # Drop oldest message if queue full + if queue.full(): + try: + queue.get_nowait() + if self.metrics: + self.metrics.dropped() + except asyncio.QueueEmpty: + pass + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_new": + # Drop new message if queue full + if queue.full(): + if self.metrics: + self.metrics.dropped() + return False + await queue.put(value) + return True + + except Exception as e: + logger.error(f"Failed to deliver message: {e}") + return False +``` + +**Principais Vantagens do Design (compatível com o padrão do Editor):** +**Local de Processamento Único**: Todo o processamento de mensagens ocorre no método `run()` +**Máquina de Estados Clara**: Três estados claros - em execução, esvaziando, parado +**Pausa Durante o Esvaziamento**: Interrompe a aceitação de novas mensagens do Pulsar enquanto esvazia as filas existentes +**Proteção por Timeout**: Não fica indefinidamente travado durante o esvaziamento +**Limpeza Adequada**: Reconhece negativamente quaisquer mensagens não entregues durante o desligamento + +#### B. Melhorias no Manipulador de Exportação + +**Arquivo**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py` + +```python +class TriplesExport: + async def destroy(self): + """Enhanced destroy with graceful shutdown""" + # Step 1: Signal stop to prevent new messages + self.running.stop() + + # Step 2: Wait briefly for in-flight messages + await asyncio.sleep(0.5) + + # Step 3: Unsubscribe and stop subscriber (triggers queue drain) + if hasattr(self, 'subs'): + await self.subs.unsubscribe_all(self.id) + await self.subs.stop() + + # Step 4: Close websocket last + if self.ws and not self.ws.closed: + await self.ws.close() + + async def run(self): + """Enhanced run with better error handling""" + self.subs = Subscriber( + client = self.pulsar_client, + topic = self.queue, + consumer_name = self.consumer, + subscription = self.subscriber, + schema = Triples, + backpressure_strategy = "block" # Configurable + ) + + await self.subs.start() + + self.id = str(uuid.uuid4()) + q = await self.subs.subscribe_all(self.id) + + consecutive_errors = 0 + max_consecutive_errors = 5 + + while self.running.get(): + try: + resp = await asyncio.wait_for(q.get(), timeout=0.5) + await self.ws.send_json(serialize_triples(resp)) + consecutive_errors = 0 # Reset on success + + except asyncio.TimeoutError: + continue + + except queue.Empty: + continue + + except Exception as e: + logger.error(f"Exception sending to websocket: {str(e)}") + consecutive_errors += 1 + + if consecutive_errors >= max_consecutive_errors: + logger.error("Too many consecutive errors, shutting down") + break + + # Brief pause before retry + await asyncio.sleep(0.1) + + # Graceful cleanup handled in destroy() +``` + +### 3. Melhorias no Nível de Socket + +**Arquivo**: `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` + +```python +class SocketEndpoint: + async def listener(self, ws, dispatcher, running): + """Enhanced listener with graceful shutdown""" + async for msg in ws: + if msg.type == WSMsgType.TEXT: + await dispatcher.receive(msg) + continue + elif msg.type == WSMsgType.BINARY: + await dispatcher.receive(msg) + continue + else: + # Graceful shutdown on close + logger.info("Websocket closing, initiating graceful shutdown") + running.stop() + + # Allow time for dispatcher cleanup + await asyncio.sleep(1.0) + break + + async def handle(self, request): + """Enhanced handler with better cleanup""" + # ... existing setup code ... + + try: + async with asyncio.TaskGroup() as tg: + running = Running() + + dispatcher = await self.dispatcher( + ws, running, request.match_info + ) + + worker_task = tg.create_task( + self.worker(ws, dispatcher, running) + ) + + lsnr_task = tg.create_task( + self.listener(ws, dispatcher, running) + ) + + except ExceptionGroup as e: + logger.error("Exception group occurred:", exc_info=True) + + # Attempt graceful dispatcher shutdown + try: + await asyncio.wait_for( + dispatcher.destroy(), + timeout=5.0 + ) + except asyncio.TimeoutError: + logger.warning("Dispatcher shutdown timed out") + except Exception as de: + logger.error(f"Error during dispatcher cleanup: {de}") + + except Exception as e: + logger.error(f"Socket exception: {e}", exc_info=True) + + finally: + # Ensure dispatcher cleanup + if dispatcher and hasattr(dispatcher, 'destroy'): + try: + await dispatcher.destroy() + except: + pass + + # Ensure websocket is closed + if ws and not ws.closed: + await ws.close() + + return ws +``` + +## Opções de Configuração + +Adicionar suporte para configuração para ajustar o comportamento: + +```python +# config.py +class GracefulShutdownConfig: + # Publisher settings + PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout + + # Subscriber settings + SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new" + SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure + + # Socket settings + SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown + MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown + + # Monitoring + LOG_QUEUE_STATS = True # Log queue statistics on shutdown + METRICS_ENABLED = True # Enable metrics collection +``` + +## Estratégia de Testes + +### Testes Unitários + +```python +async def test_publisher_queue_drain(): + """Verify Publisher drains queue on shutdown""" + publisher = Publisher(...) + + # Fill queue with messages + for i in range(10): + await publisher.send(f"id-{i}", {"data": i}) + + # Stop publisher + await publisher.stop() + + # Verify all messages were sent + assert publisher.q.empty() + assert mock_producer.send.call_count == 10 + +async def test_subscriber_deferred_ack(): + """Verify Subscriber only acks on successful delivery""" + subscriber = Subscriber(..., backpressure_strategy="drop_new") + + # Fill queue to capacity + queue = await subscriber.subscribe("test") + for i in range(100): + await queue.put({"data": i}) + + # Try to add message when full + msg = create_mock_message() + await subscriber._process_message(msg) + + # Verify negative acknowledgment + assert msg.negative_acknowledge.called + assert not msg.acknowledge.called +``` + +### Testes de Integração + +```python +async def test_import_graceful_shutdown(): + """Test import path handles shutdown gracefully""" + # Setup + import_handler = TriplesImport(...) + await import_handler.start() + + # Send messages + messages = [] + for i in range(100): + msg = {"metadata": {...}, "triples": [...]} + await import_handler.receive(msg) + messages.append(msg) + + # Shutdown while messages in flight + await import_handler.destroy() + + # Verify all messages reached Pulsar + received = await pulsar_consumer.receive_all() + assert len(received) == 100 + +async def test_export_no_message_loss(): + """Test export path doesn't lose acknowledged messages""" + # Setup Pulsar with test messages + for i in range(100): + await pulsar_producer.send({"data": i}) + + # Start export handler + export_handler = TriplesExport(...) + export_task = asyncio.create_task(export_handler.run()) + + # Receive some messages + received = [] + for _ in range(50): + msg = await websocket.receive() + received.append(msg) + + # Force shutdown + await export_handler.destroy() + + # Continue receiving until websocket closes + while not websocket.closed: + try: + msg = await websocket.receive() + received.append(msg) + except: + break + + # Verify no acknowledged messages were lost + assert len(received) >= 50 +``` + +## Plano de Implementação + +### Fase 1: Correções Críticas (Semana 1) +Corrigir o tempo de reconhecimento do assinante (evitar perda de mensagens) +Adicionar esvaziamento da fila do publicador +Implantar no ambiente de teste + +### Fase 2: Desligamento Gradual (Semana 2) +Implementar coordenação de desligamento +Adicionar estratégias de backpressure +Testes de desempenho + +### Fase 3: Monitoramento e Ajuste (Semana 3) +Adicionar métricas para profundidade da fila +Adicionar alertas para perda de mensagens +Ajustar valores de timeout com base em dados de produção + +## Monitoramento e Alertas + +### Métricas a serem Monitoradas +`publisher.queue.depth` - Tamanho atual da fila do publicador +`publisher.messages.dropped` - Mensagens perdidas durante o desligamento +`subscriber.messages.negatively_acknowledged` - Entregas falhadas +`websocket.graceful_shutdowns` - Desligamentos graduais bem-sucedidos +`websocket.forced_shutdowns` - Desligamentos forçados/por timeout + +### Alertas +Profundidade da fila do publicador > 80% da capacidade +Qualquer perda de mensagens durante o desligamento +Taxa de reconhecimento negativo do assinante > 1% +Timeout de desligamento excedido + +## Compatibilidade com Versões Anteriores + +Todas as alterações mantêm a compatibilidade com versões anteriores: +Comportamento padrão inalterado sem configuração +Implantações existentes continuam a funcionar +Degradação gradual se novos recursos não estiverem disponíveis + +## Considerações de Segurança + +Nenhum novo vetor de ataque introduzido +O backpressure impede ataques de esgotamento de memória +Limites configuráveis ​​evitam o abuso de recursos + +## Impacto no Desempenho + +Sobrecarga mínima durante a operação normal +O desligamento pode levar até 5 segundos a mais (configurável) +O uso de memória é limitado pelos limites do tamanho da fila +O impacto na CPU é insignificante (<1% de aumento) \ No newline at end of file diff --git a/docs/tech-specs/import-export-graceful-shutdown.ru.md b/docs/tech-specs/import-export-graceful-shutdown.ru.md new file mode 100644 index 00000000..4f1a0708 --- /dev/null +++ b/docs/tech-specs/import-export-graceful-shutdown.ru.md @@ -0,0 +1,682 @@ +# Техническая спецификация корректного завершения работы импорта/экспорта + +## Описание проблемы + +В настоящее время шлюз TrustGraph испытывает потерю сообщений во время закрытия WebSocket как при импорте, так и при экспорте. Это происходит из-за гонок, когда сообщения, находящиеся в процессе передачи, отбрасываются до того, как они достигнут своего назначения (очереди Pulsar для импорта, клиенты WebSocket для экспорта). + +### Проблемы на стороне импорта +1. Буфер asyncio.Queue издателя не очищается при завершении работы. +2. WebSocket закрывается до того, как будет гарантировано, что сообщения в очереди достигнут Pulsar. +3. Отсутствует механизм подтверждения успешной доставки сообщений. + +### Проблемы на стороне экспорта +1. Сообщения подтверждаются в Pulsar до успешной доставки клиентам. +2. Жестко заданные таймауты приводят к потере сообщений, когда очереди заполнены. +3. Отсутствует механизм обратной связи для обработки медленных потребителей. +4. Несколько буферных областей, где данные могут быть потеряны. + +## Обзор архитектуры + +``` +Import Flow: +Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue + +Export Flow: +Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client +``` + +## Предлагаемые исправления + +### 1. Улучшения для издателя (сторона импорта) + +#### A. Плавная очистка очереди + +**Файл**: `trustgraph-base/trustgraph/base/publisher.py` + +```python +class Publisher: + def __init__(self, client, topic, schema=None, max_size=10, + chunking_enabled=True, drain_timeout=5.0): + self.client = client + self.topic = topic + self.schema = schema + self.q = asyncio.Queue(maxsize=max_size) + self.chunking_enabled = chunking_enabled + self.running = True + self.draining = False # New state for graceful shutdown + self.task = None + self.drain_timeout = drain_timeout + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + try: + producer = self.client.create_producer( + topic=self.topic, + schema=JsonSchema(self.schema), + chunking_enabled=self.chunking_enabled, + ) + + drain_end_time = None + + while self.running or self.draining: + try: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s") + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + if not self.q.empty(): + logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining") + self.draining = False + break + + # Calculate wait timeout based on mode + if self.draining: + # Shorter timeout during draining to exit quickly when empty + timeout = min(0.1, drain_end_time - time.time()) + else: + # Normal operation timeout + timeout = 0.25 + + # Get message from queue + id, item = await asyncio.wait_for( + self.q.get(), + timeout=timeout + ) + + # Send the message (single place for sending) + if id: + producer.send(item, { "id": id }) + else: + producer.send(item) + + except asyncio.TimeoutError: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + except asyncio.QueueEmpty: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + # Flush producer before closing + if producer: + producer.flush() + producer.close() + + except Exception as e: + logger.error(f"Exception in publisher: {e}", exc_info=True) + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def send(self, id, item): + """Send still works normally - just adds to queue""" + if self.draining: + # Optionally reject new messages during drain + raise RuntimeError("Publisher is shutting down, not accepting new messages") + await self.q.put((id, item)) +``` + +**Основные преимущества дизайна:** +**Единое место отправки:** Все вызовы `producer.send()` происходят в одном месте внутри метода `run()`. +**Чистая конечная машина состояний:** Три четких состояния - работа, слив, остановка. +**Защита от таймаута:** Не зависнет бесконечно во время слива. +**Улучшенная наблюдаемость:** Четкое логирование хода слива и переходов состояний. +**Опциональное отклонение сообщений:** Может отклонять новые сообщения во время фазы завершения работы. + +#### B. Улучшенный порядок завершения работы + +**Файл:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py` + +```python +class TriplesImport: + async def destroy(self): + """Enhanced destroy with proper shutdown order""" + # Step 1: Stop accepting new messages + self.running.stop() + + # Step 2: Wait for publisher to drain its queue + logger.info("Draining publisher queue...") + await self.publisher.stop() + + # Step 3: Close websocket only after queue is drained + if self.ws: + await self.ws.close() +``` + +### 2. Улучшения для подписчиков (экспортная сторона) + +#### A. Интегрированная схема отвода + +**Файл**: `trustgraph-base/trustgraph/base/subscriber.py` + +```python +class Subscriber: + def __init__(self, client, topic, subscription, consumer_name, + schema=None, max_size=100, metrics=None, + backpressure_strategy="block", drain_timeout=5.0): + # ... existing init ... + self.backpressure_strategy = backpressure_strategy + self.running = True + self.draining = False # New state for graceful shutdown + self.drain_timeout = drain_timeout + self.pending_acks = {} # Track messages awaiting delivery + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + if self.metrics: + self.metrics.state("stopped") + + try: + self.consumer = self.client.subscribe( + topic = self.topic, + subscription_name = self.subscription, + consumer_name = self.consumer_name, + schema = JsonSchema(self.schema), + ) + + if self.metrics: + self.metrics.state("running") + + logger.info("Subscriber running...") + drain_end_time = None + + while self.running or self.draining: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s") + + # Stop accepting new messages from Pulsar during drain + self.consumer.pause_message_listener() + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + async with self.lock: + total_pending = sum( + q.qsize() for q in + list(self.q.values()) + list(self.full.values()) + ) + if total_pending > 0: + logger.warning(f"Drain timeout reached with {total_pending} messages in queues") + self.draining = False + break + + # Check if we can exit drain mode + if self.draining: + async with self.lock: + all_empty = all( + q.empty() for q in + list(self.q.values()) + list(self.full.values()) + ) + if all_empty and len(self.pending_acks) == 0: + logger.info("Subscriber queues drained successfully") + self.draining = False + break + + # Process messages only if not draining + if not self.draining: + try: + msg = await asyncio.to_thread( + self.consumer.receive, + timeout_millis=250 + ) + except _pulsar.Timeout: + continue + except Exception as e: + logger.error(f"Exception in subscriber receive: {e}", exc_info=True) + raise e + + if self.metrics: + self.metrics.received() + + # Process the message + await self._process_message(msg) + else: + # During draining, just wait for queues to empty + await asyncio.sleep(0.1) + + except Exception as e: + logger.error(f"Subscriber exception: {e}", exc_info=True) + + finally: + # Negative acknowledge any pending messages + for msg in self.pending_acks.values(): + self.consumer.negative_acknowledge(msg) + self.pending_acks.clear() + + if self.consumer: + self.consumer.unsubscribe() + self.consumer.close() + self.consumer = None + + if self.metrics: + self.metrics.state("stopped") + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def _process_message(self, msg): + """Process a single message with deferred acknowledgment""" + # Store message for later acknowledgment + msg_id = str(uuid.uuid4()) + self.pending_acks[msg_id] = msg + + try: + id = msg.properties()["id"] + except: + id = None + + value = msg.value() + delivery_success = False + + async with self.lock: + # Deliver to specific subscribers + if id in self.q: + delivery_success = await self._deliver_to_queue( + self.q[id], value + ) + + # Deliver to all subscribers + for q in self.full.values(): + if await self._deliver_to_queue(q, value): + delivery_success = True + + # Acknowledge only on successful delivery + if delivery_success: + self.consumer.acknowledge(msg) + del self.pending_acks[msg_id] + else: + # Negative acknowledge for retry + self.consumer.negative_acknowledge(msg) + del self.pending_acks[msg_id] + + async def _deliver_to_queue(self, queue, value): + """Deliver message to queue with backpressure handling""" + try: + if self.backpressure_strategy == "block": + # Block until space available (no timeout) + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_oldest": + # Drop oldest message if queue full + if queue.full(): + try: + queue.get_nowait() + if self.metrics: + self.metrics.dropped() + except asyncio.QueueEmpty: + pass + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_new": + # Drop new message if queue full + if queue.full(): + if self.metrics: + self.metrics.dropped() + return False + await queue.put(value) + return True + + except Exception as e: + logger.error(f"Failed to deliver message: {e}") + return False +``` + +**Основные преимущества дизайна (соответствие шаблону издателя):** +**Единое место обработки сообщений**: Вся обработка сообщений происходит в методе `run()` +**Чистая конечная машина состояний**: Три четких состояния - работа, слив, остановка +**Приостановка во время слива**: Прекращает прием новых сообщений из Pulsar во время слива существующих очередей +**Защита от таймаутов**: Не зависнет бесконечно во время слива +**Правильная очистка**: Отправляет отрицательные подтверждения для любых неотправленных сообщений при завершении работы + +#### B. Улучшения обработчика экспорта + +**Файл**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py` + +```python +class TriplesExport: + async def destroy(self): + """Enhanced destroy with graceful shutdown""" + # Step 1: Signal stop to prevent new messages + self.running.stop() + + # Step 2: Wait briefly for in-flight messages + await asyncio.sleep(0.5) + + # Step 3: Unsubscribe and stop subscriber (triggers queue drain) + if hasattr(self, 'subs'): + await self.subs.unsubscribe_all(self.id) + await self.subs.stop() + + # Step 4: Close websocket last + if self.ws and not self.ws.closed: + await self.ws.close() + + async def run(self): + """Enhanced run with better error handling""" + self.subs = Subscriber( + client = self.pulsar_client, + topic = self.queue, + consumer_name = self.consumer, + subscription = self.subscriber, + schema = Triples, + backpressure_strategy = "block" # Configurable + ) + + await self.subs.start() + + self.id = str(uuid.uuid4()) + q = await self.subs.subscribe_all(self.id) + + consecutive_errors = 0 + max_consecutive_errors = 5 + + while self.running.get(): + try: + resp = await asyncio.wait_for(q.get(), timeout=0.5) + await self.ws.send_json(serialize_triples(resp)) + consecutive_errors = 0 # Reset on success + + except asyncio.TimeoutError: + continue + + except queue.Empty: + continue + + except Exception as e: + logger.error(f"Exception sending to websocket: {str(e)}") + consecutive_errors += 1 + + if consecutive_errors >= max_consecutive_errors: + logger.error("Too many consecutive errors, shutting down") + break + + # Brief pause before retry + await asyncio.sleep(0.1) + + # Graceful cleanup handled in destroy() +``` + +### 3. Улучшения на уровне сокетов + +**Файл**: `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` + +```python +class SocketEndpoint: + async def listener(self, ws, dispatcher, running): + """Enhanced listener with graceful shutdown""" + async for msg in ws: + if msg.type == WSMsgType.TEXT: + await dispatcher.receive(msg) + continue + elif msg.type == WSMsgType.BINARY: + await dispatcher.receive(msg) + continue + else: + # Graceful shutdown on close + logger.info("Websocket closing, initiating graceful shutdown") + running.stop() + + # Allow time for dispatcher cleanup + await asyncio.sleep(1.0) + break + + async def handle(self, request): + """Enhanced handler with better cleanup""" + # ... existing setup code ... + + try: + async with asyncio.TaskGroup() as tg: + running = Running() + + dispatcher = await self.dispatcher( + ws, running, request.match_info + ) + + worker_task = tg.create_task( + self.worker(ws, dispatcher, running) + ) + + lsnr_task = tg.create_task( + self.listener(ws, dispatcher, running) + ) + + except ExceptionGroup as e: + logger.error("Exception group occurred:", exc_info=True) + + # Attempt graceful dispatcher shutdown + try: + await asyncio.wait_for( + dispatcher.destroy(), + timeout=5.0 + ) + except asyncio.TimeoutError: + logger.warning("Dispatcher shutdown timed out") + except Exception as de: + logger.error(f"Error during dispatcher cleanup: {de}") + + except Exception as e: + logger.error(f"Socket exception: {e}", exc_info=True) + + finally: + # Ensure dispatcher cleanup + if dispatcher and hasattr(dispatcher, 'destroy'): + try: + await dispatcher.destroy() + except: + pass + + # Ensure websocket is closed + if ws and not ws.closed: + await ws.close() + + return ws +``` + +## Варианты конфигурации + +Добавить поддержку конфигурации для настройки поведения: + +```python +# config.py +class GracefulShutdownConfig: + # Publisher settings + PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout + + # Subscriber settings + SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new" + SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure + + # Socket settings + SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown + MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown + + # Monitoring + LOG_QUEUE_STATS = True # Log queue statistics on shutdown + METRICS_ENABLED = True # Enable metrics collection +``` + +## Стратегия тестирования + +### Юнит-тесты + +```python +async def test_publisher_queue_drain(): + """Verify Publisher drains queue on shutdown""" + publisher = Publisher(...) + + # Fill queue with messages + for i in range(10): + await publisher.send(f"id-{i}", {"data": i}) + + # Stop publisher + await publisher.stop() + + # Verify all messages were sent + assert publisher.q.empty() + assert mock_producer.send.call_count == 10 + +async def test_subscriber_deferred_ack(): + """Verify Subscriber only acks on successful delivery""" + subscriber = Subscriber(..., backpressure_strategy="drop_new") + + # Fill queue to capacity + queue = await subscriber.subscribe("test") + for i in range(100): + await queue.put({"data": i}) + + # Try to add message when full + msg = create_mock_message() + await subscriber._process_message(msg) + + # Verify negative acknowledgment + assert msg.negative_acknowledge.called + assert not msg.acknowledge.called +``` + +### Интеграционные тесты + +```python +async def test_import_graceful_shutdown(): + """Test import path handles shutdown gracefully""" + # Setup + import_handler = TriplesImport(...) + await import_handler.start() + + # Send messages + messages = [] + for i in range(100): + msg = {"metadata": {...}, "triples": [...]} + await import_handler.receive(msg) + messages.append(msg) + + # Shutdown while messages in flight + await import_handler.destroy() + + # Verify all messages reached Pulsar + received = await pulsar_consumer.receive_all() + assert len(received) == 100 + +async def test_export_no_message_loss(): + """Test export path doesn't lose acknowledged messages""" + # Setup Pulsar with test messages + for i in range(100): + await pulsar_producer.send({"data": i}) + + # Start export handler + export_handler = TriplesExport(...) + export_task = asyncio.create_task(export_handler.run()) + + # Receive some messages + received = [] + for _ in range(50): + msg = await websocket.receive() + received.append(msg) + + # Force shutdown + await export_handler.destroy() + + # Continue receiving until websocket closes + while not websocket.closed: + try: + msg = await websocket.receive() + received.append(msg) + except: + break + + # Verify no acknowledged messages were lost + assert len(received) >= 50 +``` + +## План внедрения + +### Фаза 1: Критические исправления (Неделя 1) +Исправить время подтверждения подписки (предотвратить потерю сообщений) +Добавить очистку очереди издателя +Развернуть в тестовой среде + +### Фаза 2: Плавное завершение работы (Неделя 2) +Реализовать координацию завершения работы +Добавить стратегии обратной связи +Тестирование производительности + +### Фаза 3: Мониторинг и настройка (Неделя 3) +Добавить метрики для глубины очередей +Добавить оповещения о потере сообщений +Настроить значения тайм-аутов на основе данных производственной среды + +## Мониторинг и оповещения + +### Метрики для отслеживания +`publisher.queue.depth` - Текущий размер очереди издателя +`publisher.messages.dropped` - Сообщения, потерянные во время завершения работы +`subscriber.messages.negatively_acknowledged` - Неудачные доставки +`websocket.graceful_shutdowns` - Успешные плавные завершения работы +`websocket.forced_shutdowns` - Принудительные/тайм-аут завершения работы + +### Оповещения +Глубина очереди издателя > 80% от максимальной емкости +Любая потеря сообщений во время завершения работы +Частота отрицательных подтверждений от подписчика > 1% +Превышен тайм-аут завершения работы + +## Обратная совместимость + +Все изменения сохраняют обратную совместимость: +Поведение по умолчанию не изменено без конфигурации +Существующие развертывания продолжают работать +Плавное снижение производительности в случае недоступности новых функций + +## Вопросы безопасности + +Не введено новых векторов атак +Обратная связь предотвращает атаки, приводящие к исчерпанию памяти +Настраиваемые лимиты предотвращают злоупотребление ресурсами + +## Влияние на производительность + +Минимальные накладные расходы во время нормальной работы +Завершение работы может занять до 5 секунд больше (настраивается) +Использование памяти ограничено лимитами размера очереди +Влияние на ЦП незначительно (<1% увеличение) \ No newline at end of file diff --git a/docs/tech-specs/import-export-graceful-shutdown.sw.md b/docs/tech-specs/import-export-graceful-shutdown.sw.md new file mode 100644 index 00000000..cbb1b54f --- /dev/null +++ b/docs/tech-specs/import-export-graceful-shutdown.sw.md @@ -0,0 +1,682 @@ +# Vipimo vya Kiufundi vya Uanzishaji na Kukomesha Kazi kwa Ufasaha (Import/Export) + +## Tatizo + +Hivi sasa, mlango wa TrustGraph unapoteza ujumbe wakati wa kufunga muunganisho wa websocket katika operesheni za uanzishaji na kukomesha kazi. Hii hutokea kwa sababu ya migogoro ambapo ujumbe unaendelea hutupwa kabla ya kufika kwa lengo lake (mifereji ya Pulsar kwa uanzishaji, wateja wa websocket kwa kukomesha kazi). + +### Masuala ya Upande wa Uanzishaji +1. Picha ya folyo ya `asyncio.Queue` ya mchapishaji haijafunguliwa wakati wa kukomesha kazi. +2. Websocket hufungwa kabla ya kuhakikisha kwamba ujumbe uliopangwa kufika kwenye Pulsar. +3. Hakuna mfumo wa uthibitisho wa uwasilishaji wa ujumbe kwa mafanikio. + +### Masuala ya Upande wa Kukomesha Kazi +1. Ujumbe unaidhinishwa katika Pulsar kabla ya uwasilishaji wa mafanikio kwa wateja. +2. Muda uliopangwa (timeouts) husababisha kupotea kwa ujumbe wakati mifereji imejaa. +3. Hakuna mfumo wa kudhibiti kasi (backpressure) wa kushughulikia watumiaji (consumers) ambao ni polepole. +4. Vituo vingi vya kuhifadhi ambapo data inaweza kupotea. + +## Muhtasari wa Muundo + +``` +Import Flow: +Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue + +Export Flow: +Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client +``` + +## Marekebisho Yanayopendekezwa + +### 1. Maboresho ya Mchapishaji (Upande wa Uingizaji) + +#### A. Kusafisha Kina Kesi ya Mfululizo + +**Faili**: `trustgraph-base/trustgraph/base/publisher.py` + +```python +class Publisher: + def __init__(self, client, topic, schema=None, max_size=10, + chunking_enabled=True, drain_timeout=5.0): + self.client = client + self.topic = topic + self.schema = schema + self.q = asyncio.Queue(maxsize=max_size) + self.chunking_enabled = chunking_enabled + self.running = True + self.draining = False # New state for graceful shutdown + self.task = None + self.drain_timeout = drain_timeout + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + try: + producer = self.client.create_producer( + topic=self.topic, + schema=JsonSchema(self.schema), + chunking_enabled=self.chunking_enabled, + ) + + drain_end_time = None + + while self.running or self.draining: + try: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s") + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + if not self.q.empty(): + logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining") + self.draining = False + break + + # Calculate wait timeout based on mode + if self.draining: + # Shorter timeout during draining to exit quickly when empty + timeout = min(0.1, drain_end_time - time.time()) + else: + # Normal operation timeout + timeout = 0.25 + + # Get message from queue + id, item = await asyncio.wait_for( + self.q.get(), + timeout=timeout + ) + + # Send the message (single place for sending) + if id: + producer.send(item, { "id": id }) + else: + producer.send(item) + + except asyncio.TimeoutError: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + except asyncio.QueueEmpty: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + # Flush producer before closing + if producer: + producer.flush() + producer.close() + + except Exception as e: + logger.error(f"Exception in publisher: {e}", exc_info=True) + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def send(self, id, item): + """Send still works normally - just adds to queue""" + if self.draining: + # Optionally reject new messages during drain + raise RuntimeError("Publisher is shutting down, not accepting new messages") + await self.q.put((id, item)) +``` + +**Manufaa Muhimu ya Ubunifu:** +**Eneo Moja la Kutuma:** Wito wote wa `producer.send()` hutokea katika sehemu moja ndani ya mbinu ya `run()`. +**Mashine ya Hali Safi:** Hali tatu wazi - inafanya kazi, inatakatishwa, imesimama. +**Ulinzi wa Muda:** Haingii katika hali ya kukwama kwa muda usio na kikomo wakati wa utaratibu wa utakatishaji. +**Ufuatiliaji Bora:** Uandikaji wazi wa maendeleo ya utaratibu wa utakatishaji na mabadiliko ya hali. +**Kukataa kwa Ujumbe (Hiari):** Inaweza kukataa ujumbe mpya wakati wa awamu ya kuzima. + +#### B. Mpangilio Ulioboreshwa wa Kuzima + +**Faili:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py` + +```python +class TriplesImport: + async def destroy(self): + """Enhanced destroy with proper shutdown order""" + # Step 1: Stop accepting new messages + self.running.stop() + + # Step 2: Wait for publisher to drain its queue + logger.info("Draining publisher queue...") + await self.publisher.stop() + + # Step 3: Close websocket only after queue is drained + if self.ws: + await self.ws.close() +``` + +### 2. Maboresho kwa Wateja (Upande wa Uhamisho) + +#### A. Mfumo Uliounganishwa wa Utoaji + +**Faili**: `trustgraph-base/trustgraph/base/subscriber.py` + +```python +class Subscriber: + def __init__(self, client, topic, subscription, consumer_name, + schema=None, max_size=100, metrics=None, + backpressure_strategy="block", drain_timeout=5.0): + # ... existing init ... + self.backpressure_strategy = backpressure_strategy + self.running = True + self.draining = False # New state for graceful shutdown + self.drain_timeout = drain_timeout + self.pending_acks = {} # Track messages awaiting delivery + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + if self.metrics: + self.metrics.state("stopped") + + try: + self.consumer = self.client.subscribe( + topic = self.topic, + subscription_name = self.subscription, + consumer_name = self.consumer_name, + schema = JsonSchema(self.schema), + ) + + if self.metrics: + self.metrics.state("running") + + logger.info("Subscriber running...") + drain_end_time = None + + while self.running or self.draining: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s") + + # Stop accepting new messages from Pulsar during drain + self.consumer.pause_message_listener() + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + async with self.lock: + total_pending = sum( + q.qsize() for q in + list(self.q.values()) + list(self.full.values()) + ) + if total_pending > 0: + logger.warning(f"Drain timeout reached with {total_pending} messages in queues") + self.draining = False + break + + # Check if we can exit drain mode + if self.draining: + async with self.lock: + all_empty = all( + q.empty() for q in + list(self.q.values()) + list(self.full.values()) + ) + if all_empty and len(self.pending_acks) == 0: + logger.info("Subscriber queues drained successfully") + self.draining = False + break + + # Process messages only if not draining + if not self.draining: + try: + msg = await asyncio.to_thread( + self.consumer.receive, + timeout_millis=250 + ) + except _pulsar.Timeout: + continue + except Exception as e: + logger.error(f"Exception in subscriber receive: {e}", exc_info=True) + raise e + + if self.metrics: + self.metrics.received() + + # Process the message + await self._process_message(msg) + else: + # During draining, just wait for queues to empty + await asyncio.sleep(0.1) + + except Exception as e: + logger.error(f"Subscriber exception: {e}", exc_info=True) + + finally: + # Negative acknowledge any pending messages + for msg in self.pending_acks.values(): + self.consumer.negative_acknowledge(msg) + self.pending_acks.clear() + + if self.consumer: + self.consumer.unsubscribe() + self.consumer.close() + self.consumer = None + + if self.metrics: + self.metrics.state("stopped") + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def _process_message(self, msg): + """Process a single message with deferred acknowledgment""" + # Store message for later acknowledgment + msg_id = str(uuid.uuid4()) + self.pending_acks[msg_id] = msg + + try: + id = msg.properties()["id"] + except: + id = None + + value = msg.value() + delivery_success = False + + async with self.lock: + # Deliver to specific subscribers + if id in self.q: + delivery_success = await self._deliver_to_queue( + self.q[id], value + ) + + # Deliver to all subscribers + for q in self.full.values(): + if await self._deliver_to_queue(q, value): + delivery_success = True + + # Acknowledge only on successful delivery + if delivery_success: + self.consumer.acknowledge(msg) + del self.pending_acks[msg_id] + else: + # Negative acknowledge for retry + self.consumer.negative_acknowledge(msg) + del self.pending_acks[msg_id] + + async def _deliver_to_queue(self, queue, value): + """Deliver message to queue with backpressure handling""" + try: + if self.backpressure_strategy == "block": + # Block until space available (no timeout) + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_oldest": + # Drop oldest message if queue full + if queue.full(): + try: + queue.get_nowait() + if self.metrics: + self.metrics.dropped() + except asyncio.QueueEmpty: + pass + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_new": + # Drop new message if queue full + if queue.full(): + if self.metrics: + self.metrics.dropped() + return False + await queue.put(value) + return True + + except Exception as e: + logger.error(f"Failed to deliver message: {e}") + return False +``` + +**Manufaa Muhimu ya Ubunifu (kulingana na mtindo wa Mchapishaji):** +**Eneo Moja la Ufuatiliaji**: Ufuatiliaji wote wa ujumbe hutokea katika njia ya `run()` +**Mashine Safi ya Hali**: Hali tatu wazi - inafanya kazi, inachosha, imesimama +**Kusitisha Wakati wa Kuchosha**: Inasimamisha kupokea ujumbe mpya kutoka Pulsar wakati inachosha folyo zilizopo +**Ulinzi wa Muda**: Haingii katika hali ya kukwama kwa muda usio na kikomo wakati wa kuchosha +**Usafi Sawa**: Inatambua vibaya ujumbe wowote usiofikishwa wakati wa kuzima + +#### B. Maboresho ya Kidhibiti cha Uhamisho + +**Faili**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py` + +```python +class TriplesExport: + async def destroy(self): + """Enhanced destroy with graceful shutdown""" + # Step 1: Signal stop to prevent new messages + self.running.stop() + + # Step 2: Wait briefly for in-flight messages + await asyncio.sleep(0.5) + + # Step 3: Unsubscribe and stop subscriber (triggers queue drain) + if hasattr(self, 'subs'): + await self.subs.unsubscribe_all(self.id) + await self.subs.stop() + + # Step 4: Close websocket last + if self.ws and not self.ws.closed: + await self.ws.close() + + async def run(self): + """Enhanced run with better error handling""" + self.subs = Subscriber( + client = self.pulsar_client, + topic = self.queue, + consumer_name = self.consumer, + subscription = self.subscriber, + schema = Triples, + backpressure_strategy = "block" # Configurable + ) + + await self.subs.start() + + self.id = str(uuid.uuid4()) + q = await self.subs.subscribe_all(self.id) + + consecutive_errors = 0 + max_consecutive_errors = 5 + + while self.running.get(): + try: + resp = await asyncio.wait_for(q.get(), timeout=0.5) + await self.ws.send_json(serialize_triples(resp)) + consecutive_errors = 0 # Reset on success + + except asyncio.TimeoutError: + continue + + except queue.Empty: + continue + + except Exception as e: + logger.error(f"Exception sending to websocket: {str(e)}") + consecutive_errors += 1 + + if consecutive_errors >= max_consecutive_errors: + logger.error("Too many consecutive errors, shutting down") + break + + # Brief pause before retry + await asyncio.sleep(0.1) + + # Graceful cleanup handled in destroy() +``` + +### 3. Maboresho ya Kawaida ya Soketi + +**Faili**: `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` + +```python +class SocketEndpoint: + async def listener(self, ws, dispatcher, running): + """Enhanced listener with graceful shutdown""" + async for msg in ws: + if msg.type == WSMsgType.TEXT: + await dispatcher.receive(msg) + continue + elif msg.type == WSMsgType.BINARY: + await dispatcher.receive(msg) + continue + else: + # Graceful shutdown on close + logger.info("Websocket closing, initiating graceful shutdown") + running.stop() + + # Allow time for dispatcher cleanup + await asyncio.sleep(1.0) + break + + async def handle(self, request): + """Enhanced handler with better cleanup""" + # ... existing setup code ... + + try: + async with asyncio.TaskGroup() as tg: + running = Running() + + dispatcher = await self.dispatcher( + ws, running, request.match_info + ) + + worker_task = tg.create_task( + self.worker(ws, dispatcher, running) + ) + + lsnr_task = tg.create_task( + self.listener(ws, dispatcher, running) + ) + + except ExceptionGroup as e: + logger.error("Exception group occurred:", exc_info=True) + + # Attempt graceful dispatcher shutdown + try: + await asyncio.wait_for( + dispatcher.destroy(), + timeout=5.0 + ) + except asyncio.TimeoutError: + logger.warning("Dispatcher shutdown timed out") + except Exception as de: + logger.error(f"Error during dispatcher cleanup: {de}") + + except Exception as e: + logger.error(f"Socket exception: {e}", exc_info=True) + + finally: + # Ensure dispatcher cleanup + if dispatcher and hasattr(dispatcher, 'destroy'): + try: + await dispatcher.destroy() + except: + pass + + # Ensure websocket is closed + if ws and not ws.closed: + await ws.close() + + return ws +``` + +## Chaguo za Usanidi + +Ongeza usaidizi wa usanidi ili kurekebisha tabia: + +```python +# config.py +class GracefulShutdownConfig: + # Publisher settings + PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout + + # Subscriber settings + SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new" + SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure + + # Socket settings + SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown + MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown + + # Monitoring + LOG_QUEUE_STATS = True # Log queue statistics on shutdown + METRICS_ENABLED = True # Enable metrics collection +``` + +## Mkakati wa Majaribio + +### Majaribio ya Kitengo + +```python +async def test_publisher_queue_drain(): + """Verify Publisher drains queue on shutdown""" + publisher = Publisher(...) + + # Fill queue with messages + for i in range(10): + await publisher.send(f"id-{i}", {"data": i}) + + # Stop publisher + await publisher.stop() + + # Verify all messages were sent + assert publisher.q.empty() + assert mock_producer.send.call_count == 10 + +async def test_subscriber_deferred_ack(): + """Verify Subscriber only acks on successful delivery""" + subscriber = Subscriber(..., backpressure_strategy="drop_new") + + # Fill queue to capacity + queue = await subscriber.subscribe("test") + for i in range(100): + await queue.put({"data": i}) + + # Try to add message when full + msg = create_mock_message() + await subscriber._process_message(msg) + + # Verify negative acknowledgment + assert msg.negative_acknowledge.called + assert not msg.acknowledge.called +``` + +### Majaribio ya Uunganishaji + +```python +async def test_import_graceful_shutdown(): + """Test import path handles shutdown gracefully""" + # Setup + import_handler = TriplesImport(...) + await import_handler.start() + + # Send messages + messages = [] + for i in range(100): + msg = {"metadata": {...}, "triples": [...]} + await import_handler.receive(msg) + messages.append(msg) + + # Shutdown while messages in flight + await import_handler.destroy() + + # Verify all messages reached Pulsar + received = await pulsar_consumer.receive_all() + assert len(received) == 100 + +async def test_export_no_message_loss(): + """Test export path doesn't lose acknowledged messages""" + # Setup Pulsar with test messages + for i in range(100): + await pulsar_producer.send({"data": i}) + + # Start export handler + export_handler = TriplesExport(...) + export_task = asyncio.create_task(export_handler.run()) + + # Receive some messages + received = [] + for _ in range(50): + msg = await websocket.receive() + received.append(msg) + + # Force shutdown + await export_handler.destroy() + + # Continue receiving until websocket closes + while not websocket.closed: + try: + msg = await websocket.receive() + received.append(msg) + except: + break + + # Verify no acknowledged messages were lost + assert len(received) >= 50 +``` + +## Mpango wa Utendaji + +### Awamu ya 1: Marekebisho Muhimu (Wiki ya 1) +Marekebisho ya muda wa utambuzi wa mshabiki (kuzuia upotevu wa ujumbe) +Ongeza utaratibu wa kusafisha folyo ya mchapishaji +Tuma kwenye mazingira ya majaribio + +### Awamu ya 2: Kusitisha kwa Ufasaha (Wiki ya 2) +Lenga kusitisha kwa ufasaha +Ongeza mikakati ya shinikizo nyuma +Vipimo vya utendaji + +### Awamu ya 3: Ufuatiliaji na Urekebishaji (Wiki ya 3) +Ongeza vipimo vya kina ya folyo +Ongeza arifa za upotevu wa ujumbe +Rekebisha maadili ya muda wa kusubiri kulingana na data ya uzalishaji + +## Ufuatiliaji na Arifa + +### Vipimo vya Kufuata +`publisher.queue.depth` - Ukubwa wa sasa wa folyo ya mchapishaji +`publisher.messages.dropped` - Ujumbe uliopotea wakati wa kusitisha +`subscriber.messages.negatively_acknowledged` - Utoaji ambao haujafanikiwa +`websocket.graceful_shutdowns` - Kusitisha kwa ufasaha ambavyo vimefanikiwa +`websocket.forced_shutdowns` - Kusitisha kwa nguvu/kwa muda mrefu + +### Arifa +Kina cha folyo ya mchapishaji > 80% ya uwezo +Upotevu wowote wa ujumbe wakati wa kusitisha +Kiwango cha kukataa cha mshabiki > 1% +Muda wa kusitisha umepita + +## Ulinganifu na Mifumo ya Zamani + +Marekebisho yote yanahifadhi ulinganifu na mifumo ya zamani: +Tabia ya kawaida haibadiliki bila usanidi +Uwekaji wa sasa unaendelea kufanya kazi +Kupungua kwa utendaji ikiwa vipengele vipya havipatikani + +## Masuala ya Usalama + +Vipengele vipya vya mashambulizi haviongezwi +Shinikizo nyuma huzuia mashambulizi ya kutumia kumbukumbu nyingi +Mipaka inayoweza kusanidiwa huzuia matumizi mabaya ya rasilimali + +## Athari za Utendaji + +Uwezekano mdogo wakati wa operesheni ya kawaida +Kusitisha kunaweza kuchukua sekunde 5 zaidi (inaweza kusanidiwa) +Matumizi ya kumbukumbu yanapingika na mipaka ya ukubwa wa folyo +Athari ya CPU ni ndogo (<1% ya ongezeko) \ No newline at end of file diff --git a/docs/tech-specs/import-export-graceful-shutdown.tr.md b/docs/tech-specs/import-export-graceful-shutdown.tr.md new file mode 100644 index 00000000..6dc2e997 --- /dev/null +++ b/docs/tech-specs/import-export-graceful-shutdown.tr.md @@ -0,0 +1,682 @@ +# İçe/Dışa Aktarma, Zarif Kapanış Teknik Özellikleri + +## Problem Tanımı + +TrustGraph ağ geçidi, hem içe aktarma hem de dışa aktarma işlemlerinde websocket kapanışı sırasında mesaj kaybı yaşamaktadır. Bu, aktarım halindeki mesajların, hedeflerine (içe aktarmalar için Pulsar kuyrukları, dışa aktarmalar için websocket istemcileri) ulaşmadan önce atıldığı yarış koşulları nedeniyle oluşmaktadır. + +### İçe Aktarma Tarafındaki Sorunlar +1. Yayınlayıcının asyncio.Queue tamponu, kapanışta boşaltılmamaktadır. +2. Websocket, kuyruğa alınmış mesajların Pulsar'a ulaşmasını sağladıktan sonra kapanmaktadır. +3. Başarılı mesaj teslimatı için bir onay mekanizması bulunmamaktadır. + +### Dışa Aktarma Tarafındaki Sorunlar +1. Mesajlar, istemcilere başarılı bir şekilde teslim edilmeden önce Pulsar'da onaylanmaktadır. +2. Sabit kodlu zaman aşımı değerleri, kuyruklar dolduğunda mesaj kayıplarına neden olmaktadır. +3. Yavaş tüketicileri işlemek için bir geri basınç mekanizması bulunmamaktadır. +4. Verilerin kaybolabileceği birden fazla tampon noktası bulunmaktadır. + +## Mimari Genel Bakış + +``` +Import Flow: +Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue + +Export Flow: +Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client +``` + +## Önerilen Çözümler + +### 1. Yayıncı İyileştirmeleri (İçe Aktarma Tarafı) + +#### A. Zarif Kuyruk Boşaltma + +**Dosya**: `trustgraph-base/trustgraph/base/publisher.py` + +```python +class Publisher: + def __init__(self, client, topic, schema=None, max_size=10, + chunking_enabled=True, drain_timeout=5.0): + self.client = client + self.topic = topic + self.schema = schema + self.q = asyncio.Queue(maxsize=max_size) + self.chunking_enabled = chunking_enabled + self.running = True + self.draining = False # New state for graceful shutdown + self.task = None + self.drain_timeout = drain_timeout + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + try: + producer = self.client.create_producer( + topic=self.topic, + schema=JsonSchema(self.schema), + chunking_enabled=self.chunking_enabled, + ) + + drain_end_time = None + + while self.running or self.draining: + try: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s") + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + if not self.q.empty(): + logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining") + self.draining = False + break + + # Calculate wait timeout based on mode + if self.draining: + # Shorter timeout during draining to exit quickly when empty + timeout = min(0.1, drain_end_time - time.time()) + else: + # Normal operation timeout + timeout = 0.25 + + # Get message from queue + id, item = await asyncio.wait_for( + self.q.get(), + timeout=timeout + ) + + # Send the message (single place for sending) + if id: + producer.send(item, { "id": id }) + else: + producer.send(item) + + except asyncio.TimeoutError: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + except asyncio.QueueEmpty: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + # Flush producer before closing + if producer: + producer.flush() + producer.close() + + except Exception as e: + logger.error(f"Exception in publisher: {e}", exc_info=True) + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def send(self, id, item): + """Send still works normally - just adds to queue""" + if self.draining: + # Optionally reject new messages during drain + raise RuntimeError("Publisher is shutting down, not accepting new messages") + await self.q.put((id, item)) +``` + +**Temel Tasarım Avantajları:** +**Tek Gönderme Konumu**: Tüm `producer.send()` çağrıları, `run()` metodu içinde tek bir yerde gerçekleşir. +**Temiz Durum Makinesi**: Üç açık durum - çalışıyor, boşaltılıyor, durdurulmuş. +**Zaman Aşımı Koruması**: Boşaltma sırasında sonsuza kadar takılmayacaktır. +**Daha İyi Gözlemlenebilirlik**: Boşaltma ilerlemesi ve durum geçişlerinin açık bir şekilde günlüğe kaydedilmesi. +**İsteğe Bağlı Mesaj Reddi**: Kapatma aşamasında yeni mesajları reddedebilir. + +#### B. İyileştirilmiş Kapatma Sırası + +**Dosya**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py` + +```python +class TriplesImport: + async def destroy(self): + """Enhanced destroy with proper shutdown order""" + # Step 1: Stop accepting new messages + self.running.stop() + + # Step 2: Wait for publisher to drain its queue + logger.info("Draining publisher queue...") + await self.publisher.stop() + + # Step 3: Close websocket only after queue is drained + if self.ws: + await self.ws.close() +``` + +### 2. Abonelik İyileştirmeleri (Dışa Aktarma Tarafı) + +#### A. Entegre Boşaltma Modeli + +**Dosya**: `trustgraph-base/trustgraph/base/subscriber.py` + +```python +class Subscriber: + def __init__(self, client, topic, subscription, consumer_name, + schema=None, max_size=100, metrics=None, + backpressure_strategy="block", drain_timeout=5.0): + # ... existing init ... + self.backpressure_strategy = backpressure_strategy + self.running = True + self.draining = False # New state for graceful shutdown + self.drain_timeout = drain_timeout + self.pending_acks = {} # Track messages awaiting delivery + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + if self.metrics: + self.metrics.state("stopped") + + try: + self.consumer = self.client.subscribe( + topic = self.topic, + subscription_name = self.subscription, + consumer_name = self.consumer_name, + schema = JsonSchema(self.schema), + ) + + if self.metrics: + self.metrics.state("running") + + logger.info("Subscriber running...") + drain_end_time = None + + while self.running or self.draining: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s") + + # Stop accepting new messages from Pulsar during drain + self.consumer.pause_message_listener() + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + async with self.lock: + total_pending = sum( + q.qsize() for q in + list(self.q.values()) + list(self.full.values()) + ) + if total_pending > 0: + logger.warning(f"Drain timeout reached with {total_pending} messages in queues") + self.draining = False + break + + # Check if we can exit drain mode + if self.draining: + async with self.lock: + all_empty = all( + q.empty() for q in + list(self.q.values()) + list(self.full.values()) + ) + if all_empty and len(self.pending_acks) == 0: + logger.info("Subscriber queues drained successfully") + self.draining = False + break + + # Process messages only if not draining + if not self.draining: + try: + msg = await asyncio.to_thread( + self.consumer.receive, + timeout_millis=250 + ) + except _pulsar.Timeout: + continue + except Exception as e: + logger.error(f"Exception in subscriber receive: {e}", exc_info=True) + raise e + + if self.metrics: + self.metrics.received() + + # Process the message + await self._process_message(msg) + else: + # During draining, just wait for queues to empty + await asyncio.sleep(0.1) + + except Exception as e: + logger.error(f"Subscriber exception: {e}", exc_info=True) + + finally: + # Negative acknowledge any pending messages + for msg in self.pending_acks.values(): + self.consumer.negative_acknowledge(msg) + self.pending_acks.clear() + + if self.consumer: + self.consumer.unsubscribe() + self.consumer.close() + self.consumer = None + + if self.metrics: + self.metrics.state("stopped") + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def _process_message(self, msg): + """Process a single message with deferred acknowledgment""" + # Store message for later acknowledgment + msg_id = str(uuid.uuid4()) + self.pending_acks[msg_id] = msg + + try: + id = msg.properties()["id"] + except: + id = None + + value = msg.value() + delivery_success = False + + async with self.lock: + # Deliver to specific subscribers + if id in self.q: + delivery_success = await self._deliver_to_queue( + self.q[id], value + ) + + # Deliver to all subscribers + for q in self.full.values(): + if await self._deliver_to_queue(q, value): + delivery_success = True + + # Acknowledge only on successful delivery + if delivery_success: + self.consumer.acknowledge(msg) + del self.pending_acks[msg_id] + else: + # Negative acknowledge for retry + self.consumer.negative_acknowledge(msg) + del self.pending_acks[msg_id] + + async def _deliver_to_queue(self, queue, value): + """Deliver message to queue with backpressure handling""" + try: + if self.backpressure_strategy == "block": + # Block until space available (no timeout) + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_oldest": + # Drop oldest message if queue full + if queue.full(): + try: + queue.get_nowait() + if self.metrics: + self.metrics.dropped() + except asyncio.QueueEmpty: + pass + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_new": + # Drop new message if queue full + if queue.full(): + if self.metrics: + self.metrics.dropped() + return False + await queue.put(value) + return True + + except Exception as e: + logger.error(f"Failed to deliver message: {e}") + return False +``` + +**Temel Tasarım Avantajları (Yayıncı modeline uygun):** +**Tek İşlem Konumu**: Tüm mesaj işleme, `run()` metodu içinde gerçekleşir. +**Temiz Durum Makinesi**: Üç açık durum - çalışıyor, boşaltma, durdurulmuş. +**Boşaltma Sırasında Duraklama**: Mevcut kuyrukları boşaltırken, Pulsar'dan yeni mesaj kabul etmeyi durdurur. +**Zaman Aşımı Koruması**: Boşaltma sırasında sonsuza kadar takılmayacaktır. +**Doğru Temizleme**: Kapatma sırasında teslim edilmemiş mesajlar varsa, bunlara ilişkin olumsuz onaylar gönderilir. + +#### B. Dışa Aktarma İşleyici İyileştirmeleri + +**Dosya**: `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py` + +```python +class TriplesExport: + async def destroy(self): + """Enhanced destroy with graceful shutdown""" + # Step 1: Signal stop to prevent new messages + self.running.stop() + + # Step 2: Wait briefly for in-flight messages + await asyncio.sleep(0.5) + + # Step 3: Unsubscribe and stop subscriber (triggers queue drain) + if hasattr(self, 'subs'): + await self.subs.unsubscribe_all(self.id) + await self.subs.stop() + + # Step 4: Close websocket last + if self.ws and not self.ws.closed: + await self.ws.close() + + async def run(self): + """Enhanced run with better error handling""" + self.subs = Subscriber( + client = self.pulsar_client, + topic = self.queue, + consumer_name = self.consumer, + subscription = self.subscriber, + schema = Triples, + backpressure_strategy = "block" # Configurable + ) + + await self.subs.start() + + self.id = str(uuid.uuid4()) + q = await self.subs.subscribe_all(self.id) + + consecutive_errors = 0 + max_consecutive_errors = 5 + + while self.running.get(): + try: + resp = await asyncio.wait_for(q.get(), timeout=0.5) + await self.ws.send_json(serialize_triples(resp)) + consecutive_errors = 0 # Reset on success + + except asyncio.TimeoutError: + continue + + except queue.Empty: + continue + + except Exception as e: + logger.error(f"Exception sending to websocket: {str(e)}") + consecutive_errors += 1 + + if consecutive_errors >= max_consecutive_errors: + logger.error("Too many consecutive errors, shutting down") + break + + # Brief pause before retry + await asyncio.sleep(0.1) + + # Graceful cleanup handled in destroy() +``` + +### 3. Soket Seviyesindeki İyileştirmeler + +**Dosya**: `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` + +```python +class SocketEndpoint: + async def listener(self, ws, dispatcher, running): + """Enhanced listener with graceful shutdown""" + async for msg in ws: + if msg.type == WSMsgType.TEXT: + await dispatcher.receive(msg) + continue + elif msg.type == WSMsgType.BINARY: + await dispatcher.receive(msg) + continue + else: + # Graceful shutdown on close + logger.info("Websocket closing, initiating graceful shutdown") + running.stop() + + # Allow time for dispatcher cleanup + await asyncio.sleep(1.0) + break + + async def handle(self, request): + """Enhanced handler with better cleanup""" + # ... existing setup code ... + + try: + async with asyncio.TaskGroup() as tg: + running = Running() + + dispatcher = await self.dispatcher( + ws, running, request.match_info + ) + + worker_task = tg.create_task( + self.worker(ws, dispatcher, running) + ) + + lsnr_task = tg.create_task( + self.listener(ws, dispatcher, running) + ) + + except ExceptionGroup as e: + logger.error("Exception group occurred:", exc_info=True) + + # Attempt graceful dispatcher shutdown + try: + await asyncio.wait_for( + dispatcher.destroy(), + timeout=5.0 + ) + except asyncio.TimeoutError: + logger.warning("Dispatcher shutdown timed out") + except Exception as de: + logger.error(f"Error during dispatcher cleanup: {de}") + + except Exception as e: + logger.error(f"Socket exception: {e}", exc_info=True) + + finally: + # Ensure dispatcher cleanup + if dispatcher and hasattr(dispatcher, 'destroy'): + try: + await dispatcher.destroy() + except: + pass + + # Ensure websocket is closed + if ws and not ws.closed: + await ws.close() + + return ws +``` + +## Yapılandırma Seçenekleri + +Davranışı ayarlamak için yapılandırma desteği ekleyin: + +```python +# config.py +class GracefulShutdownConfig: + # Publisher settings + PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout + + # Subscriber settings + SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new" + SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure + + # Socket settings + SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown + MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown + + # Monitoring + LOG_QUEUE_STATS = True # Log queue statistics on shutdown + METRICS_ENABLED = True # Enable metrics collection +``` + +## Test Stratejisi + +### Birim Testleri + +```python +async def test_publisher_queue_drain(): + """Verify Publisher drains queue on shutdown""" + publisher = Publisher(...) + + # Fill queue with messages + for i in range(10): + await publisher.send(f"id-{i}", {"data": i}) + + # Stop publisher + await publisher.stop() + + # Verify all messages were sent + assert publisher.q.empty() + assert mock_producer.send.call_count == 10 + +async def test_subscriber_deferred_ack(): + """Verify Subscriber only acks on successful delivery""" + subscriber = Subscriber(..., backpressure_strategy="drop_new") + + # Fill queue to capacity + queue = await subscriber.subscribe("test") + for i in range(100): + await queue.put({"data": i}) + + # Try to add message when full + msg = create_mock_message() + await subscriber._process_message(msg) + + # Verify negative acknowledgment + assert msg.negative_acknowledge.called + assert not msg.acknowledge.called +``` + +### Entegrasyon Testleri + +```python +async def test_import_graceful_shutdown(): + """Test import path handles shutdown gracefully""" + # Setup + import_handler = TriplesImport(...) + await import_handler.start() + + # Send messages + messages = [] + for i in range(100): + msg = {"metadata": {...}, "triples": [...]} + await import_handler.receive(msg) + messages.append(msg) + + # Shutdown while messages in flight + await import_handler.destroy() + + # Verify all messages reached Pulsar + received = await pulsar_consumer.receive_all() + assert len(received) == 100 + +async def test_export_no_message_loss(): + """Test export path doesn't lose acknowledged messages""" + # Setup Pulsar with test messages + for i in range(100): + await pulsar_producer.send({"data": i}) + + # Start export handler + export_handler = TriplesExport(...) + export_task = asyncio.create_task(export_handler.run()) + + # Receive some messages + received = [] + for _ in range(50): + msg = await websocket.receive() + received.append(msg) + + # Force shutdown + await export_handler.destroy() + + # Continue receiving until websocket closes + while not websocket.closed: + try: + msg = await websocket.receive() + received.append(msg) + except: + break + + # Verify no acknowledged messages were lost + assert len(received) >= 50 +``` + +## Dağıtım Planı + +### Aşama 1: Kritik Düzeltmeler (1. Hafta) +Abonelik onayı zamanlaması düzeltildi (mesaj kaybını önler) +Yayıncı kuyruğu boşaltma özelliği eklendi +Staging ortamına dağıtıldı + +### Aşama 2: Düzenli Kapanış (2. Hafta) +Kapanış koordinasyonu uygulandı +Geri basınç stratejileri eklendi +Performans testi + +### Aşama 3: İzleme ve Ayarlama (3. Hafta) +Kuyruk derinlikleri için metrikler eklendi +Mesaj kayıpları için uyarılar eklendi +Üretim verilerine göre zaman aşımı değerleri ayarlandı + +## İzleme ve Uyarılar + +### İzlenecek Metrikler +`publisher.queue.depth` - Mevcut yayıncı kuyruğu boyutu +`publisher.messages.dropped` - Kapanma sırasında kaybolan mesajlar +`subscriber.messages.negatively_acknowledged` - Başarısız teslimatlar +`websocket.graceful_shutdowns` - Başarılı düzenli kapanışlar +`websocket.forced_shutdowns` - Zorlanmış/zaman aşımı kapanışları + +### Uyarılar +Yayıncı kuyruğu derinliği %80 kapasitenin üzerinde +Kapanma sırasında herhangi bir mesaj kaybı +Abonelik olumsuz onay oranı > %1 +Kapanış zaman aşımı aşıldı + +## Geriye Dönük Uyumluluk + +Tüm değişiklikler geriye dönük uyumluluğu korur: +Yapılandırma olmadan varsayılan davranış değişmedi +Mevcut dağıtımlar çalışmaya devam ediyor +Yeni özellikler kullanılamıyorsa, kademeli bozulma + +## Güvenlik Hususları + +Herhangi bir yeni saldırı vektörü tanıtılmadı +Geri basınç, bellek tükenmesi saldırılarını önler +Yapılandırılabilir sınırlar, kaynak kötüye kullanımını önler + +## Performans Etkisi + +Normal çalışma sırasında minimum ek yük +Kapanma, 5 saniyeye kadar daha uzun sürebilir (yapılandırılabilir) +Bellek kullanımı, kuyruk boyutu sınırları ile sınırlıdır +CPU etkisi ihmal edilebilir (<%1 artış) \ No newline at end of file diff --git a/docs/tech-specs/import-export-graceful-shutdown.zh-cn.md b/docs/tech-specs/import-export-graceful-shutdown.zh-cn.md new file mode 100644 index 00000000..f1dbd9f0 --- /dev/null +++ b/docs/tech-specs/import-export-graceful-shutdown.zh-cn.md @@ -0,0 +1,682 @@ +# 导入/导出 优雅关闭 技术规范 + +## 问题陈述 + +TrustGraph 网关在导入和导出操作中,在 WebSocket 连接关闭时,目前存在消息丢失的问题。 这是由于存在竞争条件,导致正在传输的消息在到达目的地之前被丢弃(对于导入,是丢弃到 Pulsar 队列的消息;对于导出,是丢弃到 WebSocket 客户端的消息)。 + +### 导入端问题 +1. 发布者的 asyncio.Queue 缓冲区在关闭时未被清空 +2. 在确保所有排队的消息到达 Pulsar 之前,WebSocket 连接关闭 +3. 没有用于确认消息成功传递的机制 + +### 导出端问题 +1. 消息在成功传递到客户端之前,已在 Pulsar 中得到确认 +2. 预定义的超时时间会导致队列已满时消息丢失 +3. 没有用于处理慢速消费者的反压机制 +4. 存在多个缓冲区,数据可能在此处丢失 + +## 架构概述 + +``` +Import Flow: +Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue + +Export Flow: +Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client +``` + +## 建议的修复方案 + +### 1. 发布者改进(导入端) + +#### A. 优雅的队列清空 + +**文件**: `trustgraph-base/trustgraph/base/publisher.py` + +```python +class Publisher: + def __init__(self, client, topic, schema=None, max_size=10, + chunking_enabled=True, drain_timeout=5.0): + self.client = client + self.topic = topic + self.schema = schema + self.q = asyncio.Queue(maxsize=max_size) + self.chunking_enabled = chunking_enabled + self.running = True + self.draining = False # New state for graceful shutdown + self.task = None + self.drain_timeout = drain_timeout + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + try: + producer = self.client.create_producer( + topic=self.topic, + schema=JsonSchema(self.schema), + chunking_enabled=self.chunking_enabled, + ) + + drain_end_time = None + + while self.running or self.draining: + try: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s") + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + if not self.q.empty(): + logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining") + self.draining = False + break + + # Calculate wait timeout based on mode + if self.draining: + # Shorter timeout during draining to exit quickly when empty + timeout = min(0.1, drain_end_time - time.time()) + else: + # Normal operation timeout + timeout = 0.25 + + # Get message from queue + id, item = await asyncio.wait_for( + self.q.get(), + timeout=timeout + ) + + # Send the message (single place for sending) + if id: + producer.send(item, { "id": id }) + else: + producer.send(item) + + except asyncio.TimeoutError: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + except asyncio.QueueEmpty: + # If draining and queue is empty, we're done + if self.draining and self.q.empty(): + logger.info("Publisher queue drained successfully") + self.draining = False + break + continue + + # Flush producer before closing + if producer: + producer.flush() + producer.close() + + except Exception as e: + logger.error(f"Exception in publisher: {e}", exc_info=True) + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def send(self, id, item): + """Send still works normally - just adds to queue""" + if self.draining: + # Optionally reject new messages during drain + raise RuntimeError("Publisher is shutting down, not accepting new messages") + await self.q.put((id, item)) +``` + +**主要设计优势:** +**单一发送位置:** 所有 `producer.send()` 调用都发生在 `run()` 方法内的单一位置。 +**清晰的状态机:** 三个明确的状态 - 运行中、正在排空、已停止。 +**超时保护:** 在排空过程中不会无限期挂起。 +**更好的可观察性:** 清晰地记录排空进度和状态转换。 +**可选的消息拒绝:** 可以在关闭阶段拒绝新的消息。 + +#### B. 改进的关闭顺序 + +**文件:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py` + +```python +class TriplesImport: + async def destroy(self): + """Enhanced destroy with proper shutdown order""" + # Step 1: Stop accepting new messages + self.running.stop() + + # Step 2: Wait for publisher to drain its queue + logger.info("Draining publisher queue...") + await self.publisher.stop() + + # Step 3: Close websocket only after queue is drained + if self.ws: + await self.ws.close() +``` + +### 2. 订阅者改进(导出端) + +#### A. 集成排空模式 + +**文件**: `trustgraph-base/trustgraph/base/subscriber.py` + +```python +class Subscriber: + def __init__(self, client, topic, subscription, consumer_name, + schema=None, max_size=100, metrics=None, + backpressure_strategy="block", drain_timeout=5.0): + # ... existing init ... + self.backpressure_strategy = backpressure_strategy + self.running = True + self.draining = False # New state for graceful shutdown + self.drain_timeout = drain_timeout + self.pending_acks = {} # Track messages awaiting delivery + + async def stop(self): + """Initiate graceful shutdown with draining""" + self.running = False + self.draining = True + + if self.task: + # Wait for run() to complete draining + await self.task + + async def run(self): + """Enhanced run method with integrated draining logic""" + while self.running or self.draining: + if self.metrics: + self.metrics.state("stopped") + + try: + self.consumer = self.client.subscribe( + topic = self.topic, + subscription_name = self.subscription, + consumer_name = self.consumer_name, + schema = JsonSchema(self.schema), + ) + + if self.metrics: + self.metrics.state("running") + + logger.info("Subscriber running...") + drain_end_time = None + + while self.running or self.draining: + # Start drain timeout when entering drain mode + if self.draining and drain_end_time is None: + drain_end_time = time.time() + self.drain_timeout + logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s") + + # Stop accepting new messages from Pulsar during drain + self.consumer.pause_message_listener() + + # Check drain timeout + if self.draining and time.time() > drain_end_time: + async with self.lock: + total_pending = sum( + q.qsize() for q in + list(self.q.values()) + list(self.full.values()) + ) + if total_pending > 0: + logger.warning(f"Drain timeout reached with {total_pending} messages in queues") + self.draining = False + break + + # Check if we can exit drain mode + if self.draining: + async with self.lock: + all_empty = all( + q.empty() for q in + list(self.q.values()) + list(self.full.values()) + ) + if all_empty and len(self.pending_acks) == 0: + logger.info("Subscriber queues drained successfully") + self.draining = False + break + + # Process messages only if not draining + if not self.draining: + try: + msg = await asyncio.to_thread( + self.consumer.receive, + timeout_millis=250 + ) + except _pulsar.Timeout: + continue + except Exception as e: + logger.error(f"Exception in subscriber receive: {e}", exc_info=True) + raise e + + if self.metrics: + self.metrics.received() + + # Process the message + await self._process_message(msg) + else: + # During draining, just wait for queues to empty + await asyncio.sleep(0.1) + + except Exception as e: + logger.error(f"Subscriber exception: {e}", exc_info=True) + + finally: + # Negative acknowledge any pending messages + for msg in self.pending_acks.values(): + self.consumer.negative_acknowledge(msg) + self.pending_acks.clear() + + if self.consumer: + self.consumer.unsubscribe() + self.consumer.close() + self.consumer = None + + if self.metrics: + self.metrics.state("stopped") + + if not self.running and not self.draining: + return + + # If handler drops out, sleep a retry + await asyncio.sleep(1) + + async def _process_message(self, msg): + """Process a single message with deferred acknowledgment""" + # Store message for later acknowledgment + msg_id = str(uuid.uuid4()) + self.pending_acks[msg_id] = msg + + try: + id = msg.properties()["id"] + except: + id = None + + value = msg.value() + delivery_success = False + + async with self.lock: + # Deliver to specific subscribers + if id in self.q: + delivery_success = await self._deliver_to_queue( + self.q[id], value + ) + + # Deliver to all subscribers + for q in self.full.values(): + if await self._deliver_to_queue(q, value): + delivery_success = True + + # Acknowledge only on successful delivery + if delivery_success: + self.consumer.acknowledge(msg) + del self.pending_acks[msg_id] + else: + # Negative acknowledge for retry + self.consumer.negative_acknowledge(msg) + del self.pending_acks[msg_id] + + async def _deliver_to_queue(self, queue, value): + """Deliver message to queue with backpressure handling""" + try: + if self.backpressure_strategy == "block": + # Block until space available (no timeout) + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_oldest": + # Drop oldest message if queue full + if queue.full(): + try: + queue.get_nowait() + if self.metrics: + self.metrics.dropped() + except asyncio.QueueEmpty: + pass + await queue.put(value) + return True + + elif self.backpressure_strategy == "drop_new": + # Drop new message if queue full + if queue.full(): + if self.metrics: + self.metrics.dropped() + return False + await queue.put(value) + return True + + except Exception as e: + logger.error(f"Failed to deliver message: {e}") + return False +``` + +**主要设计优势(与发布者模式匹配):** +**单一处理位置:** 所有消息处理都在 `run()` 方法中进行。 +**清晰的状态机:** 三个明确的状态 - 运行中、正在排空、已停止。 +**排空期间暂停:** 在排空现有队列时,停止从 Pulsar 接收新消息。 +**超时保护:** 在排空过程中不会无限期挂起。 +**正确的清理:** 在关闭时,会对任何未发送的消息进行否定确认。 + +#### B. 导出处理程序改进 + +**文件:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py` + +```python +class TriplesExport: + async def destroy(self): + """Enhanced destroy with graceful shutdown""" + # Step 1: Signal stop to prevent new messages + self.running.stop() + + # Step 2: Wait briefly for in-flight messages + await asyncio.sleep(0.5) + + # Step 3: Unsubscribe and stop subscriber (triggers queue drain) + if hasattr(self, 'subs'): + await self.subs.unsubscribe_all(self.id) + await self.subs.stop() + + # Step 4: Close websocket last + if self.ws and not self.ws.closed: + await self.ws.close() + + async def run(self): + """Enhanced run with better error handling""" + self.subs = Subscriber( + client = self.pulsar_client, + topic = self.queue, + consumer_name = self.consumer, + subscription = self.subscriber, + schema = Triples, + backpressure_strategy = "block" # Configurable + ) + + await self.subs.start() + + self.id = str(uuid.uuid4()) + q = await self.subs.subscribe_all(self.id) + + consecutive_errors = 0 + max_consecutive_errors = 5 + + while self.running.get(): + try: + resp = await asyncio.wait_for(q.get(), timeout=0.5) + await self.ws.send_json(serialize_triples(resp)) + consecutive_errors = 0 # Reset on success + + except asyncio.TimeoutError: + continue + + except queue.Empty: + continue + + except Exception as e: + logger.error(f"Exception sending to websocket: {str(e)}") + consecutive_errors += 1 + + if consecutive_errors >= max_consecutive_errors: + logger.error("Too many consecutive errors, shutting down") + break + + # Brief pause before retry + await asyncio.sleep(0.1) + + # Graceful cleanup handled in destroy() +``` + +### 3. Socket 级别改进 + +**文件**: `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` + +```python +class SocketEndpoint: + async def listener(self, ws, dispatcher, running): + """Enhanced listener with graceful shutdown""" + async for msg in ws: + if msg.type == WSMsgType.TEXT: + await dispatcher.receive(msg) + continue + elif msg.type == WSMsgType.BINARY: + await dispatcher.receive(msg) + continue + else: + # Graceful shutdown on close + logger.info("Websocket closing, initiating graceful shutdown") + running.stop() + + # Allow time for dispatcher cleanup + await asyncio.sleep(1.0) + break + + async def handle(self, request): + """Enhanced handler with better cleanup""" + # ... existing setup code ... + + try: + async with asyncio.TaskGroup() as tg: + running = Running() + + dispatcher = await self.dispatcher( + ws, running, request.match_info + ) + + worker_task = tg.create_task( + self.worker(ws, dispatcher, running) + ) + + lsnr_task = tg.create_task( + self.listener(ws, dispatcher, running) + ) + + except ExceptionGroup as e: + logger.error("Exception group occurred:", exc_info=True) + + # Attempt graceful dispatcher shutdown + try: + await asyncio.wait_for( + dispatcher.destroy(), + timeout=5.0 + ) + except asyncio.TimeoutError: + logger.warning("Dispatcher shutdown timed out") + except Exception as de: + logger.error(f"Error during dispatcher cleanup: {de}") + + except Exception as e: + logger.error(f"Socket exception: {e}", exc_info=True) + + finally: + # Ensure dispatcher cleanup + if dispatcher and hasattr(dispatcher, 'destroy'): + try: + await dispatcher.destroy() + except: + pass + + # Ensure websocket is closed + if ws and not ws.closed: + await ws.close() + + return ws +``` + +## 配置选项 + +添加配置支持,用于调整行为: + +```python +# config.py +class GracefulShutdownConfig: + # Publisher settings + PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout + + # Subscriber settings + SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain + BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new" + SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure + + # Socket settings + SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown + MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown + + # Monitoring + LOG_QUEUE_STATS = True # Log queue statistics on shutdown + METRICS_ENABLED = True # Enable metrics collection +``` + +## 测试策略 + +### 单元测试 + +```python +async def test_publisher_queue_drain(): + """Verify Publisher drains queue on shutdown""" + publisher = Publisher(...) + + # Fill queue with messages + for i in range(10): + await publisher.send(f"id-{i}", {"data": i}) + + # Stop publisher + await publisher.stop() + + # Verify all messages were sent + assert publisher.q.empty() + assert mock_producer.send.call_count == 10 + +async def test_subscriber_deferred_ack(): + """Verify Subscriber only acks on successful delivery""" + subscriber = Subscriber(..., backpressure_strategy="drop_new") + + # Fill queue to capacity + queue = await subscriber.subscribe("test") + for i in range(100): + await queue.put({"data": i}) + + # Try to add message when full + msg = create_mock_message() + await subscriber._process_message(msg) + + # Verify negative acknowledgment + assert msg.negative_acknowledge.called + assert not msg.acknowledge.called +``` + +### 集成测试 + +```python +async def test_import_graceful_shutdown(): + """Test import path handles shutdown gracefully""" + # Setup + import_handler = TriplesImport(...) + await import_handler.start() + + # Send messages + messages = [] + for i in range(100): + msg = {"metadata": {...}, "triples": [...]} + await import_handler.receive(msg) + messages.append(msg) + + # Shutdown while messages in flight + await import_handler.destroy() + + # Verify all messages reached Pulsar + received = await pulsar_consumer.receive_all() + assert len(received) == 100 + +async def test_export_no_message_loss(): + """Test export path doesn't lose acknowledged messages""" + # Setup Pulsar with test messages + for i in range(100): + await pulsar_producer.send({"data": i}) + + # Start export handler + export_handler = TriplesExport(...) + export_task = asyncio.create_task(export_handler.run()) + + # Receive some messages + received = [] + for _ in range(50): + msg = await websocket.receive() + received.append(msg) + + # Force shutdown + await export_handler.destroy() + + # Continue receiving until websocket closes + while not websocket.closed: + try: + msg = await websocket.receive() + received.append(msg) + except: + break + + # Verify no acknowledged messages were lost + assert len(received) >= 50 +``` + +## 部署计划 + +### 第一阶段:关键修复(第一周) +修复订阅者确认时序问题(防止消息丢失) +添加发布者队列排空功能 +部署到测试环境 + +### 第二阶段:平滑关闭(第二周) +实施关闭协调 +添加反压策略 +性能测试 + +### 第三阶段:监控与调优(第三周) +添加队列深度的指标 +添加消息丢失的告警 +根据生产数据调整超时值 + +## 监控与告警 + +### 跟踪指标 +`publisher.queue.depth` - 当前发布者队列大小 +`publisher.messages.dropped` - 关闭期间丢失的消息数量 +`subscriber.messages.negatively_acknowledged` - 失败的交付 +`websocket.graceful_shutdowns` - 成功的平滑关闭 +`websocket.forced_shutdowns` - 强制/超时关闭 + +### 告警 +发布者队列深度超过 80% 的容量 +关闭期间出现任何消息丢失 +订阅者否定确认率 > 1% +关闭超时 + +## 向后兼容性 + +所有更改都保持向后兼容性: +在没有配置的情况下,默认行为保持不变 +现有部署继续正常运行 +如果新的功能不可用,则会进行优雅降级 + +## 安全注意事项 + +没有引入新的攻击向量 +反压可防止内存耗尽攻击 +可配置的限制可防止资源滥用 + +## 性能影响 + +正常运行期间的开销很小 +关闭可能需要长达 5 秒(可配置) +内存使用量受队列大小限制 +CPU 影响可以忽略不计(<1% 的增加) \ No newline at end of file diff --git a/docs/tech-specs/jsonl-prompt-output.ar.md b/docs/tech-specs/jsonl-prompt-output.ar.md index 33808fdc..d61dc67a 100644 --- a/docs/tech-specs/jsonl-prompt-output.ar.md +++ b/docs/tech-specs/jsonl-prompt-output.ar.md @@ -1,74 +1,455 @@ -# JSONL Prompt Output Technical Specification +# المواصفات الفنية للإخراج بتنسيق JSONL -## Overview +## نظرة عامة -تصف هذه المواصفات تنفيذ تنسيق إخراج JSONL (JSON Lines) لنتائج المطالبات في TrustGraph. يتيح JSONL استخراجًا مقاومًا للتقطيع للبيانات المنظمة من استجابات نماذج اللغة الكبيرة (LLM)، مما يعالج المشكلات الهامة المتعلقة بتلف مخرجات JSON array عندما تصل استجابات نماذج اللغة الكبيرة إلى حدود عدد الرموز المميزة للإخراج. +تصف هذه المواصفات تطبيق تنسيق JSONL (JSON Lines) للإخراج +في TrustGraph. يتيح JSONL استخراجًا مقاومًا للتقطيع للبيانات المنظمة من +استجابات نماذج اللغة الكبيرة (LLM)، مما يعالج المشكلات الهامة المتعلقة +بتلف مخرجات JSON array عندما تصل استجابات نماذج اللغة الكبيرة إلى حدود +الرموز المميزة للإخراج. -تدعم هذه التنفيذ حالات الاستخدام التالية: +يدعم هذا التطبيق حالات الاستخدام التالية: -1. **استخراج مقاوم للتقطيع**: استخراج نتائج جزئية صالحة حتى عندما يتم تقطيع إخراج نموذج اللغة الكبيرة في منتصف الاستجابة. -2. **استخراج واسع النطاق**: التعامل مع استخراج العديد من العناصر دون خطر الفشل التام بسبب حدود عدد الرموز المميزة. -3. **استخراج متعدد الأنواع**: دعم استخراج أنواع متعددة من الكيانات (التعريفات، والعلاقات، والكيانات، والسمات) في طلب واحد. -4. **إخراج متوافق مع البث**: تمكين المعالجة المستقبلية للبث/المعالجة التزايدية لنتائج الاستخراج. +1. **الاستخراج المقاوم للتقطيع**: استخراج نتائج جزئية صالحة حتى عندما + يتم اقتطاع إخراج نموذج اللغة الكبيرة في منتصف الاستجابة. +2. **الاستخراج على نطاق واسع**: التعامل مع استخراج العديد من العناصر دون + خطر الفشل التام بسبب حدود الرموز المميزة. +3. **الاستخراج بأنواع متعددة**: دعم استخراج أنواع متعددة من الكيانات + (التعريفات، والعلاقات، والكيانات، والسمات) في طلب واحد. +4. **الإخراج المتوافق مع التدفق**: تمكين المعالجة المستقبلية التدريجية/المتزايدة + لنتائج الاستخراج. ## الأهداف -* **تحسين مقاومة الأخطاء**: التعامل مع الحالات التي يتم فيها تقطيع استجابات نماذج اللغة الكبيرة. -* **زيادة الكفاءة**: تحسين استخدام الذاكرة في معالجة الاستجابات الكبيرة. -* **تسهيل التوسع**: دعم حالات استخدام أكثر تعقيدًا تتطلب استخراج أنواع متعددة من البيانات. +**التوافق مع الإصدارات السابقة**: تظل الطلبات الحالية التي تستخدم `response-type: "text"` و + `response-type: "json"` تعمل دون تعديل. +**مقاومة التقطيع**: تؤدي مخرجات نماذج اللغة الكبيرة الجزئية إلى نتائج + جزئية صالحة بدلاً من الفشل التام. +**التحقق من المخطط**: دعم التحقق من مخطط JSON للكائنات الفردية. +**الاتحادات المميزة**: دعم المخرجات ذات الأنواع المختلطة باستخدام حقل `type` + مميز. +**تغييرات API الحد الأدنى**: توسيع تكوين الطلب الحالي بنوع استجابة جديد + ومفتاح مخطط. -## التغييرات +## الخلفية -* إضافة تنسيق إخراج جديد: JSONL -* تعديل طريقة تحليل استجابات نماذج اللغة الكبيرة -* تعديل واجهات برمجة التطبيقات (APIs) لدمج التنسيق الجديد +### البنية الحالية -## تفاصيل التنفيذ +يدعم خدمة الطلبات نوعين من الاستجابات: -### تحليل JSONL +1. `response-type: "text"` - استجابة نصية خام يتم إرجاعها كما هي. +2. `response-type: "json"` - JSON يتم تحليله من الاستجابة، ويتم التحقق منه مقابل + `schema` اختياري. -يتم تحليل استجابات JSONL سطرًا بسطر، مما يسمح باستخراج جزئي حتى في حالة حدوث أخطاء أو تقطيع. +التنفيذ الحالي في `trustgraph-flow/trustgraph/template/prompt_manager.py`: -### مخططات التحقق +```python +class Prompt: + def __init__(self, template, response_type = "text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema +``` -يتم التحقق من صحة كل كائن JSONL بشكل فردي مقابل المخطط المحدد. +### القيود الحالية -### واجهات برمجة التطبيقات (APIs) +عندما تطلب مطالبات الاستخراج إخراجًا بتنسيق مصفوفات JSON (`[{...}, {...}, ...]`): -تظل واجهات برمجة التطبيقات (APIs) ثابتة. لا يلزم إجراء تغييرات على التعليمات البرمجية التي تستهلك النتائج. +**تلف بسبب الاقتطاع**: إذا وصلت LLM إلى حدود رموز الإخراج أثناء المصفوفة، يصبح + الرد بأكمله JSON غير صالح ولا يمكن تحليله. +**التحليل الكل أو لا شيء**: يجب استقبال الإخراج الكامل قبل التحليل. +**لا توجد نتائج جزئية**: يؤدي الرد المقتطع إلى عدم وجود بيانات قابلة للاستخدام. +**غير موثوق به للاستخراج الكبير**: كلما زاد عدد العناصر المستخرجة، زاد خطر الفشل. -## خطة الترحيل +تعالج هذه المواصفات هذه القيود من خلال تقديم تنسيق JSONL لمطالبات +الاستخراج، حيث يكون كل عنصر مستخرج كائن JSON كامل في سطر منفصل. -1. **تنفيذ**: تنفيذ التحليل والتحقق من صحة JSONL. -2. **ترحيل المطالبات**: ترحيل المطالبات الحالية إلى تنسيق JSONL. -3. **تحديث التعليمات البرمجية**: تحديث التعليمات البرمجية التي تستهلك النتائج للتعامل مع التغييرات. -4. **الاختبار**: إجراء اختبار شامل لضمان التكامل السليم. + +## التصميم الفني + +### إضافة نوع استجابة جديد + +أضف نوع استجابة جديد `"jsonl"` بالإضافة إلى الأنواع الموجودة `"text"` و `"json"`. + +#### تغييرات التكوين + +**قيمة نوع الاستجابة الجديدة:** + +``` +"response-type": "jsonl" +``` + +**تفسير المخطط:** + +يتم استخدام المفتاح `"schema"` الموجود لكل من نوعي الاستجابة `"json"` و `"jsonl"`. +يعتمد التفسير على نوع الاستجابة: + +`"json"`: يصف المخطط الاستجابة بأكملها (عادةً ما يكون مصفوفة أو كائن). +`"jsonl"`: يصف المخطط كل سطر/كائن فردي. + +```json +{ + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["entity", "definition"] + } +} +``` + +هذا يمنع التغييرات في أدوات تكوين المطالبات والمحررات. + +### مواصفات تنسيق JSONL + +#### الاستخراج البسيط + +بالنسبة للمطالبات التي تستخرج نوعًا واحدًا من الكائنات (التعريفات، العلاقات، +الموضوعات، الصفوف)، يكون الإخراج عبارة عن كائن JSON واحد لكل سطر بدون أي غلاف: + +**تنسيق إخراج المطالبة:** +``` +{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"} +{"entity": "chlorophyll", "definition": "Green pigment in plants"} +{"entity": "mitochondria", "definition": "Powerhouse of the cell"} +``` + +**مقارنة مع تنسيق مصفوفة JSON السابق:** +```json +[ + {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, + {"entity": "chlorophyll", "definition": "Green pigment in plants"}, + {"entity": "mitochondria", "definition": "Powerhouse of the cell"} +] +``` + +إذا قام نموذج اللغة الكبير بقطع النص بعد السطر الثاني، فإن تنسيق مصفوفة JSON ينتج عنه JSON غير صالح، +بينما ينتج عن JSONL كائنان صالحان. + +#### استخراج أنواع مختلطة (الاتحادات المميزة) + +بالنسبة إلى التعليمات التي تستخرج أنواعًا متعددة من الكائنات (مثل التعريفات والأمثلة). +العلاقات، أو الكيانات، والعلاقات، والخصائص)، استخدم `"type"` +الحقل كعامل تمييز: + +**تنسيق إخراج التعليمات:** +``` +{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"} +{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true} +{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"} +{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true} +``` + +**مخطط للاتحادات المميّزة يستخدم `oneOf`:** +```json +{ + "response-type": "jsonl", + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { "const": "definition" }, + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["type", "entity", "definition"] + }, + { + "type": "object", + "properties": { + "type": { "const": "relationship" }, + "subject": { "type": "string" }, + "predicate": { "type": "string" }, + "object": { "type": "string" }, + "object-entity": { "type": "boolean" } + }, + "required": ["type", "subject", "predicate", "object", "object-entity"] + } + ] + } +} +``` + +#### استخراج علم المفاهيم + +لاستخراج علم المفاهيم بناءً على الكيانات والعلاقات والخصائص: + +**تنسيق إخراج التعليمات البرمجية:** +``` +{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"} +{"type": "entity", "entity": "beef", "entity_type": "fo/Food"} +{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"} +{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"} +``` + +### تفاصيل التنفيذ + +#### فئة المطالبة (Prompt Class) + +لا تتطلب الفئة الحالية `Prompt` أي تغييرات. يتم إعادة استخدام الحقل `schema` +لـ JSONL، ويتم تحديد تفسيره بواسطة `response_type`: + +```python +class Prompt: + def __init__(self, template, response_type="text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema # Interpretation depends on response_type +``` + +#### PromptManager.load_config + +لا توجد تغييرات مطلوبة - عملية تحميل التكوين الحالية تتعامل بالفعل مع +`schema`. + +#### تحليل JSONL + +إضافة طريقة تحليل جديدة لنتائج JSONL: + +```python +def parse_jsonl(self, text): + """ + Parse JSONL response, returning list of valid objects. + + Invalid lines (malformed JSON, empty lines) are skipped with warnings. + This provides truncation resilience - partial output yields partial results. + """ + results = [] + + for line_num, line in enumerate(text.strip().split('\n'), 1): + line = line.strip() + + # Skip empty lines + if not line: + continue + + # Skip markdown code fence markers if present + if line.startswith('```'): + continue + + try: + obj = json.loads(line) + results.append(obj) + except json.JSONDecodeError as e: + # Log warning but continue - this provides truncation resilience + logger.warning(f"JSONL parse error on line {line_num}: {e}") + + return results +``` + +#### تغييرات في PromptManager.invoke + +قم بتوسيع طريقة "invoke" للتعامل مع نوع الاستجابة الجديد: + +```python +async def invoke(self, id, input, llm): + logger.debug("Invoking prompt template...") + + terms = self.terms | self.prompts[id].terms | input + resp_type = self.prompts[id].response_type + + prompt = { + "system": self.system_template.render(terms), + "prompt": self.render(id, input) + } + + resp = await llm(**prompt) + + if resp_type == "text": + return resp + + if resp_type == "json": + try: + obj = self.parse_json(resp) + except: + logger.error(f"JSON parse failed: {resp}") + raise RuntimeError("JSON parse fail") + + if self.prompts[id].schema: + try: + validate(instance=obj, schema=self.prompts[id].schema) + logger.debug("Schema validation successful") + except Exception as e: + raise RuntimeError(f"Schema validation fail: {e}") + + return obj + + if resp_type == "jsonl": + objects = self.parse_jsonl(resp) + + if not objects: + logger.warning("JSONL parse returned no valid objects") + return [] + + # Validate each object against schema if provided + if self.prompts[id].schema: + validated = [] + for i, obj in enumerate(objects): + try: + validate(instance=obj, schema=self.prompts[id].schema) + validated.append(obj) + except Exception as e: + logger.warning(f"Object {i} failed schema validation: {e}") + return validated + + return objects + + raise RuntimeError(f"Response type {resp_type} not known") +``` + +### المطالبات المتأثرة + +يجب ترحيل المطالبات التالية إلى تنسيق JSONL: + +| معرف المطالبة | الوصف | حقل النوع | +|-----------|-------------|------------| +| `extract-definitions` | استخراج الكيانات/التعريفات | لا (نوع واحد) | +| `extract-relationships` | استخراج العلاقات | لا (نوع واحد) | +| `extract-topics` | استخراج الموضوعات/التعريفات | لا (نوع واحد) | +| `extract-rows` | استخراج الصفوف المنظمة | لا (نوع واحد) | +| `agent-kg-extract` | استخراج التعريفات والعلاقات المجمعة | نعم: `"definition"`، `"relationship"` | +| `extract-with-ontologies` / `ontology-extract` | الاستخراج القائم على علم الوجود | نعم: `"entity"`، `"relationship"`، `"attribute"` | + +### تغييرات واجهة برمجة التطبيقات (API) + +#### من وجهة نظر العميل + +تحليل JSONL شفاف لمستخدمي واجهة برمجة التطبيقات (API) لخدمة المطالبات. يتم التحليل +من جانب الخادم في خدمة المطالبات، ويتم إرجاع الاستجابة عبر الحقل القياسي +`PromptResponse.object` كمصفوفة JSON مسلسلة. + +عندما يستدعي العملاء خدمة المطالبات (عبر `PromptClient.prompt()` أو ما شابه): + +**`response-type: "json"`** مع مخطط المصفوفة → يتلقى العميل كائن Python `list` +**`response-type: "jsonl"`** → يتلقى العميل كائن Python `list` + +من وجهة نظر العميل، فإن كلا الخيارين يُرجِعان هياكل بيانات متطابقة. +الفرق يكمن بالكامل في كيفية تحليل مخرجات نموذج اللغة الكبير (LLM) من جهة الخادم: + +تنسيق مصفوفة JSON: استدعاء واحد لـ `json.loads()`؛ يفشل تمامًا إذا تم اقتطاعه. +تنسيق JSONL: تحليل سطريًا؛ ينتج عنه نتائج جزئية إذا تم اقتطاعه. + +هذا يعني أن التعليمات البرمجية للعميل الحالية التي تتوقع قائمة من مطالبات الاستخراج +لا تتطلب أي تغييرات عند ترحيل المطالبات من تنسيق JSON إلى تنسيق JSONL. + +#### القيمة المُرجَعة من الخادم + +بالنسبة لـ `response-type: "jsonl"`، تُرجع الطريقة `PromptManager.invoke()` +`list[dict]` تحتوي على جميع الكائنات التي تم تحليلها والتحقق من صحتها بنجاح. يتم بعد ذلك تسلسل هذه +القائمة إلى JSON لحقل `PromptResponse.object`. + +#### معالجة الأخطاء + +نتائج فارغة: تُرجع قائمة فارغة `[]` مع سجل تحذير. +فشل جزئي في التحليل: تُرجع قائمة بالكائنات التي تم تحليلها بنجاح مع + سجلات تحذير للأخطاء. +فشل كامل في التحليل: تُرجع قائمة فارغة `[]` مع سجلات تحذير. + +هذا يختلف عن `response-type: "json"` الذي يثير `RuntimeError` في حالة +فشل التحليل. السلوك المتسامح لـ JSONL مقصود لتوفير مقاومة للاقتطاع. + + +### مثال على التكوين + +مثال كامل لتكوين المطالبة: + +```json +{ + "prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"\", \"definition\": \"\"}", + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "The entity name" + }, + "definition": { + "type": "string", + "description": "A clear definition of the entity" + } + }, + "required": ["entity", "definition"] + } +} +``` ## اعتبارات الأمان -* تستخدم طريقة التحليل وظيفة `json.loads()` القياسية، وهي آمنة ضد هجمات حقن التعليمات البرمجية. -* تستخدم وظيفة التحقق من المخطط `jsonschema.validate()` لفرض سياسات المخططات. -* لا توجد نقاط ضعف أمنية جديدة تم تقديمها. +**التحقق من صحة الإدخال**: يستخدم تحليل JSON معيار `json.loads()` وهو آمن + ضد هجمات الحقن. +**التحقق من صحة المخطط**: يستخدم `jsonschema.validate()` لفرض المخطط. +**لا توجد مساحة هجومية جديدة**: تحليل JSONL أكثر أمانًا بشكل صارم من تحليل مصفوفة JSON + بسبب المعالجة سطرًا بسطر. ## اعتبارات الأداء -* يستهلك تحليل JSONL سطرًا بسطر ذاكرة أقل من تحميل مصفوفات JSON بأكملها. -* أداء التحليل مماثل لتحليل مصفوفات JSON. -* يضيف التحقق من المخطط تكلفة إضافية، ولكن يسمح بالنتائج الجزئية في حالة فشل التحقق. - +**الذاكرة**: يستخدم التحليل سطرًا بسطر ذاكرة قصوى أقل من تحميل مصفوفات JSON كاملة. + **زمن الوصول**: أداء التحليل مماثل لأداء تحليل مصفوفة JSON. +**التحقق من الصحة**: يتم تشغيل التحقق من صحة المخطط لكل كائن، مما يضيف حملًا إضافيًا ولكنه +يمكّن النتائج الجزئية في حالة فشل التحقق من الصحة. + ## استراتيجية الاختبار -* **اختبارات الوحدة**: اختبار تحليل JSONL، والتحقق من صحة المخططات، والتوافق مع الإصدارات السابقة. -* **اختبارات التكامل**: اختبار سير العمل الشامل، بما في ذلك المحاكاة لتقطيع الاستجابة. -* **اختبارات جودة الاستخراج**: مقارنة نتائج الاستخراج بين تنسيقات JSON ومصفوفات JSON. +### اختبارات الوحدة + + +تحليل JSONL مع إدخال صالح. +تحليل JSONL مع أسطر فارغة. +تحليل JSONL مع أقسام التعليمات البرمجية بتنسيق Markdown. +تحليل JSONL مع سطر نهائي مقطوع. +تحليل JSONL مع أسطر JSON غير صالحة متداخلة. +التحقق من صحة المخطط مع اتحاد `oneOf` المميّز. +التوافق مع الإصدارات السابقة: تظل المطالبات `"text"` و `"json"` الحالية دون تغيير. + +### اختبارات التكامل + +استخراج شامل مع مطالبات JSONL. +الاستخراج مع محاكاة القطع (استجابة محدودة بشكل مصطنع). +الاستخراج المختلط الأنواع مع مميز النوع. +استخراج علم الوجود مع الأنواع الثلاثة. + +### اختبارات جودة الاستخراج. + +مقارنة نتائج الاستخراج: تنسيق JSONL مقابل تنسيق مصفوفة JSON. +التحقق من قدرة تحمل التقصير: ينتج عن تنسيق JSONL نتائج جزئية في الحالات التي يفشل فيها تنسيق JSON. + +## خطة الترحيل + +### المرحلة الأولى: التنفيذ + +1. تنفيذ الطريقة `parse_jsonl()` في `PromptManager`. +2. توسيع `invoke()` للتعامل مع `response-type: "jsonl"`. +3. إضافة اختبارات الوحدة. + +### المرحلة الثانية: ترحيل المطالبات + +1. تحديث المطالبة `extract-definitions` والإعدادات. +2. تحديث المطالبة `extract-relationships` والإعدادات. +3. تحديث المطالبة `extract-topics` والإعدادات. +4. تحديث المطالبة `extract-rows` والإعدادات. +5. تحديث المطالبة `agent-kg-extract` والإعدادات. +6. تحديث المطالبة `extract-with-ontologies` والإعدادات. + +### المرحلة الثالثة: التحديثات اللاحقة + +1. تحديث أي كود يستهلك نتائج الاستخراج للتعامل مع نوع الإرجاع القائمة. +2. تحديث الكود الذي يصنف الاستخراجات ذات الأنواع المختلطة باستخدام الحقل `type`. +3. تحديث الاختبارات التي تؤكد على تنسيق إخراج الاستخراج. ## أسئلة مفتوحة -لا يوجد أسئلة مفتوحة في الوقت الحالي. +لا يوجد حاليًا. ## المراجع -* التنفيذ الحالي: `trustgraph-flow/trustgraph/template/prompt_manager.py` -* مواصفات JSON Lines: https://jsonlines.org/ -* مواصفات JSON Schema `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof -* مواصفة ذات صلة: بث استجابات نماذج اللغة الكبيرة (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file +التنفيذ الحالي: `trustgraph-flow/trustgraph/template/prompt_manager.py`. +مواصفات JSON Lines: https://jsonlines.org/. +مخطط JSON `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof. +المواصفة ذات الصلة: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`). diff --git a/docs/tech-specs/jsonl-prompt-output.es.md b/docs/tech-specs/jsonl-prompt-output.es.md index 99fffe19..60eefbd2 100644 --- a/docs/tech-specs/jsonl-prompt-output.es.md +++ b/docs/tech-specs/jsonl-prompt-output.es.md @@ -1,75 +1,455 @@ -# Especificación Técnica de la Salida JSONL para Consultas +# Especificación técnica de la salida de JSONL para prompts ## Resumen -Esta especificación describe la implementación del formato de salida JSONL (JSON Lines) para las respuestas de las consultas en TrustGraph. JSONL permite la extracción resistente a la truncación de datos estructurados de las respuestas de los LLM (Large Language Models), abordando problemas críticos con las salidas de matrices JSON que se corrompen cuando las respuestas de los LLM alcanzan los límites de tokens de salida. +Esta especificación describe la implementación del formato de salida JSONL (JSON Lines) +para respuestas de prompts en TrustGraph. JSONL permite la extracción resistente a +la truncación de datos estructurados de las respuestas de los LLM, abordando problemas +críticos con las salidas de matrices JSON que se corrompen cuando las respuestas de +los LLM alcanzan los límites de tokens de salida. Esta implementación admite los siguientes casos de uso: -1. **Extracción Resistente a la Truncación**: Extrae resultados parciales válidos incluso cuando la salida del LLM se trunca a la mitad de la respuesta. -2. **Extracción a Gran Escala**: Maneja la extracción de muchos elementos sin riesgo de fallo completo debido a los límites de tokens. -3. **Extracción de Tipos Mixtos**: Admite la extracción de múltiples tipos de entidades (definiciones, relaciones, entidades, atributos) en una sola consulta. -4. **Salida Compatible con Transmisión**: Permite el procesamiento futuro de transmisión/incremental de los resultados de la extracción. +1. **Extracción resistente a la truncación**: Extraer resultados parciales válidos + incluso cuando la salida del LLM se trunca a la mitad de la respuesta. +2. **Extracción a gran escala**: Manejar la extracción de muchos elementos sin riesgo + de fallo completo debido a los límites de tokens. +3. **Extracción de tipos mixtos**: Admitir la extracción de múltiples tipos de + entidades (definiciones, relaciones, entidades, atributos) en un solo prompt. +4. **Salida compatible con el streaming**: Permitir el procesamiento futuro de + resultados de extracción de forma incremental. ## Objetivos -- **Compatibilidad Inversa**: Las consultas existentes que utilizan `response-type: "text"` y `response-type: "json"` no se ven afectadas. -- **Flexibilidad**: Permite la extracción de datos estructurados de manera más robusta y eficiente. -- **Mejora de la Experiencia del Usuario**: Proporciona resultados parciales en caso de truncamiento, mejorando la experiencia del usuario. +**Compatibilidad con versiones anteriores**: Las indicaciones existentes que utilizan `response-type: "text"` y + `response-type: "json"` siguen funcionando sin modificaciones. +**Resiliencia a la truncación**: Las salidas parciales del LLM producen resultados válidos parciales + en lugar de un fallo completo. +**Validación de esquema**: Soporte para la validación de esquemas JSON para objetos individuales. +**Uniones discriminadas**: Soporte para salidas de tipos mixtos utilizando un campo `type` + discriminador. +**Cambios mínimos en la API**: Extiende la configuración de indicaciones existente con un nuevo + tipo de respuesta y clave de esquema. -## Consideraciones de Diseño +## Contexto -- **Formato JSONL**: Cada línea de la salida representa un objeto JSON independiente. -- **Resistencia a la Truncación**: La extracción se realiza línea por línea, lo que permite recuperar datos parciales incluso si la respuesta se trunca. -- **Validación de Esquema**: Se valida cada objeto JSON contra un esquema definido para garantizar la calidad de los datos. +### Arquitectura actual -## Cambios en el Código +El servicio de indicaciones admite dos tipos de respuesta: -- Se introduce un nuevo tipo de respuesta: `response-type: "jsonl"`. -- Se implementa un método de análisis para procesar archivos JSONL línea por línea. -- Se modifica el método de invocación para manejar el nuevo tipo de respuesta y aplicar la validación de esquema. +1. `response-type: "text"`: Respuesta de texto sin formato devuelta tal cual. +2. `response-type: "json"`: JSON analizado de la respuesta, validado contra + un esquema `schema` opcional. -## Prompts Afectados +Implementación actual en `trustgraph-flow/trustgraph/template/prompt_manager.py`: + +```python +class Prompt: + def __init__(self, template, response_type = "text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema +``` + +### Limitaciones actuales + +Cuando las indicaciones de extracción solicitan una salida en formato de matrices JSON (`[{...}, {...}, ...]`): + +**Corrupción por truncamiento**: Si el LLM alcanza los límites de tokens de salida a la mitad de la matriz, + toda la respuesta se vuelve JSON inválido y no se puede analizar. +**Análisis todo o nada**: Debe recibir la salida completa antes de analizarla. +**Sin resultados parciales**: Una respuesta truncada produce cero datos utilizables. +**No es fiable para extracciones grandes**: Cuantos más elementos se extraen, mayor es el riesgo de fallo. + +Esta especificación aborda estas limitaciones introduciendo el formato JSONL para +las indicaciones de extracción, donde cada elemento extraído es un objeto JSON completo en su +propia línea. + +## Diseño técnico + +### Extensión del tipo de respuesta + +Agregue un nuevo tipo de respuesta `"jsonl"` junto con los tipos existentes `"text"` y `"json"`. + +#### Cambios de configuración + +**Nuevo valor del tipo de respuesta:** + +``` +"response-type": "jsonl" +``` + +**Interpretación del esquema:** + +La clave existente `"schema"` se utiliza tanto para el tipo de respuesta `"json"` como para el tipo de respuesta `"jsonl"`. +La interpretación depende del tipo de respuesta: + +`"json"`: El esquema describe toda la respuesta (típicamente un array u objeto). +`"jsonl"`: El esquema describe cada línea/objeto individual. + +```json +{ + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["entity", "definition"] + } +} +``` + +Esto evita cambios en las herramientas de configuración y los editores. + +### Especificación del formato JSONL + +#### Extracción simple + +Para los prompts que extraen un solo tipo de objeto (definiciones, relaciones, +temas, filas), la salida es un objeto JSON por línea sin envoltorio: + +**Formato de salida del prompt:** +``` +{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"} +{"entity": "chlorophyll", "definition": "Green pigment in plants"} +{"entity": "mitochondria", "definition": "Powerhouse of the cell"} +``` + +**Contraste con el formato anterior de matriz JSON:** +```json +[ + {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, + {"entity": "chlorophyll", "definition": "Green pigment in plants"}, + {"entity": "mitochondria", "definition": "Powerhouse of the cell"} +] +``` + +Si el modelo de lenguaje (LLM) trunca después de la línea 2, el formato de matriz JSON produce JSON inválido, +mientras que JSONL produce dos objetos válidos. + +#### Extracción de Tipos Mixtos (Uniones Discriminadas) + +Para las indicaciones que extraen múltiples tipos de objetos (por ejemplo, tanto definiciones como +relaciones, o entidades, relaciones y atributos), utilice un campo `"type"` +como discriminador: + +**Formato de salida de la indicación:** +``` +{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"} +{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true} +{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"} +{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true} +``` + +**Esquema para uniones discriminadas utiliza `oneOf`:** +```json +{ + "response-type": "jsonl", + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { "const": "definition" }, + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["type", "entity", "definition"] + }, + { + "type": "object", + "properties": { + "type": { "const": "relationship" }, + "subject": { "type": "string" }, + "predicate": { "type": "string" }, + "object": { "type": "string" }, + "object-entity": { "type": "boolean" } + }, + "required": ["type", "subject", "predicate", "object", "object-entity"] + } + ] + } +} +``` + +#### Extracción de Ontología + +Para la extracción basada en ontologías con entidades, relaciones y atributos: + +**Formato de salida del prompt:** +``` +{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"} +{"type": "entity", "entity": "beef", "entity_type": "fo/Food"} +{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"} +{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"} +``` + +### Detalles de implementación + +#### Clase Prompt + +La clase `Prompt` existente no requiere cambios. El campo `schema` se reutiliza +para JSONL, y su interpretación está determinada por `response_type`: + +```python +class Prompt: + def __init__(self, template, response_type="text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema # Interpretation depends on response_type +``` + +#### PromptManager.load_config + +No se requieren cambios: la carga de configuración existente ya gestiona la +clave `schema`. + +#### Análisis de JSONL + +Agregar un nuevo método de análisis para respuestas JSONL: + +```python +def parse_jsonl(self, text): + """ + Parse JSONL response, returning list of valid objects. + + Invalid lines (malformed JSON, empty lines) are skipped with warnings. + This provides truncation resilience - partial output yields partial results. + """ + results = [] + + for line_num, line in enumerate(text.strip().split('\n'), 1): + line = line.strip() + + # Skip empty lines + if not line: + continue + + # Skip markdown code fence markers if present + if line.startswith('```'): + continue + + try: + obj = json.loads(line) + results.append(obj) + except json.JSONDecodeError as e: + # Log warning but continue - this provides truncation resilience + logger.warning(f"JSONL parse error on line {line_num}: {e}") + + return results +``` + +#### Cambios en PromptManager.invoke + +Extender el método invoke para manejar el nuevo tipo de respuesta: + +```python +async def invoke(self, id, input, llm): + logger.debug("Invoking prompt template...") + + terms = self.terms | self.prompts[id].terms | input + resp_type = self.prompts[id].response_type + + prompt = { + "system": self.system_template.render(terms), + "prompt": self.render(id, input) + } + + resp = await llm(**prompt) + + if resp_type == "text": + return resp + + if resp_type == "json": + try: + obj = self.parse_json(resp) + except: + logger.error(f"JSON parse failed: {resp}") + raise RuntimeError("JSON parse fail") + + if self.prompts[id].schema: + try: + validate(instance=obj, schema=self.prompts[id].schema) + logger.debug("Schema validation successful") + except Exception as e: + raise RuntimeError(f"Schema validation fail: {e}") + + return obj + + if resp_type == "jsonl": + objects = self.parse_jsonl(resp) + + if not objects: + logger.warning("JSONL parse returned no valid objects") + return [] + + # Validate each object against schema if provided + if self.prompts[id].schema: + validated = [] + for i, obj in enumerate(objects): + try: + validate(instance=obj, schema=self.prompts[id].schema) + validated.append(obj) + except Exception as e: + logger.warning(f"Object {i} failed schema validation: {e}") + return validated + + return objects + + raise RuntimeError(f"Response type {resp_type} not known") +``` + +### Prompts Afectados Los siguientes prompts deben migrarse al formato JSONL: -| ID del Prompt | Descripción | Campo Tipo | -|---|---|---| -| `extract-definitions` | Extracción de entidades y definiciones | No (tipo único) | -| `extract-relationships` | Extracción de relaciones | No (tipo único) | -| `extract-topics` | Extracción de temas y definiciones | No (tipo único) | -| `extract-rows` | Extracción de filas estructuradas | No (tipo único) | -| `agent-kg-extract` | Extracción combinada de definiciones y relaciones | Sí: `"definition"`, `"relationship"` | -| `extract-with-ontologies` / `ontology-extract` | Extracción basada en ontologías | Sí: `"entity"`, `"relationship"`, `"attribute"` | +| ID del Prompt | Descripción | Campo de Tipo | +|-----------|-------------|------------| +| `extract-definitions` | Extracción de entidades/definiciones | No (un solo tipo) | +| `extract-relationships` | Extracción de relaciones | No (un solo tipo) | +| `extract-topics` | Extracción de temas/definiciones | No (un solo tipo) | +| `extract-rows` | Extracción de filas estructuradas | No (un solo tipo) | +| `agent-kg-extract` | Extracción combinada de definiciones + relaciones | Sí: `"definition"`, `"relationship"` | +| `extract-with-ontologies` / `ontology-extract` | Extracción basada en ontología | Sí: `"entity"`, `"relationship"`, `"attribute"` | -## API +### Cambios en la API -No se esperan cambios en la API para los clientes. La diferencia es interna en el procesamiento de la respuesta. +#### Perspectiva del Cliente -## Estrategia de Pruebas +El análisis JSONL es transparente para los clientes de la API del servicio de prompts. El análisis se +realiza en el servidor en el servicio de prompts, y la respuesta se devuelve a través del +campo estándar `PromptResponse.object` como una matriz JSON serializada. -- Pruebas unitarias para validar el análisis de JSONL y la gestión de errores. -- Pruebas de integración para verificar el flujo completo de la extracción. -- Pruebas de rendimiento para evaluar el impacto en la latencia y el uso de memoria. +Cuando los clientes llaman al servicio de prompts (a través de `PromptClient.prompt()` o similar): + +**`response-type: "json"`** con esquema de matriz → el cliente recibe Python `list` +**`response-type: "jsonl"`** → el cliente recibe Python `list` + +Desde la perspectiva del cliente, ambos devuelven estructuras de datos idénticas. La +diferencia es completamente en cómo se analiza la salida del LLM en el servidor: + +Formato de matriz JSON: Una sola llamada a `json.loads()`; falla completamente si se trunca +Formato JSONL: Análisis línea por línea; produce resultados parciales si se trunca + +Esto significa que el código de cliente existente que espera una lista de los prompts de extracción +no requiere cambios al migrar los prompts de JSON a JSONL. + +#### Valor de Retorno del Servidor + +Para `response-type: "jsonl"`, el método `PromptManager.invoke()` devuelve un +`list[dict]` que contiene todos los objetos analizados y validados correctamente. Esta +lista se serializa luego a JSON para el campo `PromptResponse.object`. + +#### Manejo de Errores + +Resultados vacíos: Devuelve una lista vacía `[]` con un registro de advertencia +Fallo parcial de análisis: Devuelve una lista de objetos analizados correctamente con + registros de advertencia para los fallos +Fallo completo de análisis: Devuelve una lista vacía `[]` con registros de advertencia + +Esto difiere de `response-type: "json"` que lanza `RuntimeError` en +caso de fallo de análisis. El comportamiento permisivo para JSONL es intencional para proporcionar +resistencia a la truncación. + +### Ejemplo de Configuración + +Ejemplo completo de configuración de prompt: + +```json +{ + "prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"\", \"definition\": \"\"}", + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "The entity name" + }, + "definition": { + "type": "string", + "description": "A clear definition of the entity" + } + }, + "required": ["entity", "definition"] + } +} +``` + +## Consideraciones de seguridad + +**Validación de entrada**: El análisis JSON utiliza `json.loads()` estándar, que es seguro + contra ataques de inyección. +**Validación de esquema**: Utiliza `jsonschema.validate()` para la aplicación de esquemas. +**Sin nueva superficie de ataque**: El análisis de JSONL es estrictamente más seguro que el análisis de matrices JSON + debido al procesamiento línea por línea. + +## Consideraciones de rendimiento + +**Memoria**: El análisis línea por línea utiliza menos memoria máxima que la carga de matrices JSON completas. + +**Latencia**: El rendimiento del análisis es comparable al análisis de matrices JSON. +**Validación**: La validación de esquema se ejecuta por objeto, lo que añade sobrecarga, pero + permite resultados parciales en caso de fallo de la validación. + +## Estrategia de pruebas + +### Pruebas Unitarias + +Análisis de JSONL con entrada válida +Análisis de JSONL con líneas vacías +Análisis de JSONL con bloques de código Markdown +Análisis de JSONL con línea final truncada +Análisis de JSONL con líneas JSON inválidas intercaladas +Validación de esquema con uniones discriminadas `oneOf` +Compatibilidad hacia atrás: las indicaciones existentes `"text"` y `"json"` no se modifican + +### Pruebas de Integración + +Extracción de extremo a extremo con indicaciones JSONL +Extracción con truncamiento simulado (respuesta artificialmente limitada) +Extracción de tipos mixtos con discriminador de tipo +Extracción de ontología con los tres tipos + +### Pruebas de Calidad de Extracción + +Comparar los resultados de la extracción: formato JSONL frente a formato de matriz JSON. +Verificar la resistencia a la truncación: JSONL produce resultados parciales donde JSON falla. ## Plan de Migración -1. Implementación de la lógica de análisis JSONL y la gestión del nuevo tipo de respuesta. -2. Migración de los prompts afectados al formato JSONL. -3. Actualización de cualquier código dependiente del formato de salida. +### Fase 1: Implementación -## Consideraciones de Seguridad +1. Implementar el método `parse_jsonl()` en `PromptManager`. +2. Extender `invoke()` para manejar `response-type: "jsonl"`. +3. Agregar pruebas unitarias. -- El análisis JSONL utiliza las funciones estándar de `json.loads()`, lo que minimiza los riesgos de seguridad. -- La validación de esquema ayuda a garantizar la integridad de los datos. +### Fase 2: Migración de Prompts + +1. Actualizar el prompt y la configuración de `extract-definitions`. +2. Actualizar el prompt y la configuración de `extract-relationships`. +3. Actualizar el prompt y la configuración de `extract-topics`. +4. Actualizar el prompt y la configuración de `extract-rows`. +5. Actualizar el prompt y la configuración de `agent-kg-extract`. +6. Actualizar el prompt y la configuración de `extract-with-ontologies`. + +### Fase 3: Actualizaciones Posteriores + +1. Actualizar cualquier código que consuma los resultados de la extracción para manejar el tipo de retorno de lista. +2. Actualizar el código que categoriza las extracciones de tipos mixtos según el campo `type`. +3. Actualizar las pruebas que afirman sobre el formato de salida de la extracción. ## Preguntas Abiertas -Ninguna en este momento. +Ninguna por el momento. ## Referencias -- Implementación actual: `trustgraph-flow/trustgraph/template/prompt_manager.py` -- Especificación JSON Lines: https://jsonlines.org/ -- JSON Schema `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof -- Especificación relacionada: Transmisión de Respuestas de LLM (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file +Implementación actual: `trustgraph-flow/trustgraph/template/prompt_manager.py`. +Especificación de JSON Lines: https://jsonlines.org/. +Esquema JSON `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof. +Especificación relacionada: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`). diff --git a/docs/tech-specs/jsonl-prompt-output.he.md b/docs/tech-specs/jsonl-prompt-output.he.md index 9effc1e6..2573e562 100644 --- a/docs/tech-specs/jsonl-prompt-output.he.md +++ b/docs/tech-specs/jsonl-prompt-output.he.md @@ -1,51 +1,455 @@ -# מפרט טכני של פלט JSONL עבור הנחיות +# מפרט טכני של פלט JSONL ## סקירה כללית -מפרט זה מתאר את יישום פורמט הפלט JSONL (JSON Lines) עבור תגובות הנחיות ב-TrustGraph. JSONL מאפשר חילוץ נתונים מובנים מעמידים בסיכויים גבוהים יותר מתגובות של מודלי שפה גדולים (LLM), ומטפל בבעיות קריטיות שמתרחשות כאשר פלטי JSON מערך פגומים כאשר תגובות LLM מגיעות למגבלות של מספר הטוקנים. +מפרט זה מתאר את יישום פורמט הפלט JSONL (JSON Lines) +עבור תשובות לשאילתות ב-TrustGraph. JSONL מאפשר חילוץ עמיד לקיטוע +של נתונים מובנים מתשובות של מודלי שפה גדולים (LLM), תוך התמודדות עם בעיות +קריטיות שבהן פלט מערך JSON נפגע כאשר תשובות ה-LLM מגיעות למגבלות +של מספר הטוקנים. -יישום זה תומך בתרחישים הבאים: +יישום זה תומך בתרחישי שימוש הבאים: -1. **חילוץ עמיד בפני קיטוע:** חילוץ תוצאות חלקיות תקפות גם כאשר פלט LLM מקוטע באמצע התגובה. -2. **חילוץ בקנה מידה גדול:** טיפול בחילוץ של פריטים רבים מבלי להסתכן בכשל מוחלט עקב מגבלות טוקנים. -3. **חילוץ מסוגים מעורבים:** תמיכה בחילוץ סוגים מרובים של ישויות (entities) (הגדרות, קשרים, נושאים וכו') -4. **שיפור ביצועים:** חילוץ יעיל יותר וצריכת זיכרון נמוכה יותר בהשוואה לפורמט JSON מערך. +1. **חילוץ עמיד לקיטוע**: חילוץ תוצאות חלקיות ותקינות גם כאשר + פלט ה-LLM מקוטע באמצע התגובה. +2. **חילוץ בקנה מידה גדול**: טיפול בחילוץ של פריטים רבים מבלי + להסתכן בכשל מוחלט עקב מגבלות טוקנים. +3. **חילוץ מסוגים מעורבים**: תמיכה בחילוץ של סוגי ישויות מרובים + (הגדרות, קשרים, ישויות, תכונות) בשאילתה אחת. +4. **פלט תואם לסטרימינג**: אפשור עיבוד עתידי של תוצאות החילוץ + בצורה של סטרימינג/הדרגתית. + +## מטרות + +**תאימות לאחור**: שאילתות קיימות המשתמשות ב-`response-type: "text"` ו- + `response-type: "json"` ממשיכות לעבוד ללא שינוי. +**עמידות לקיטוע**: פלטים חלקיים של LLM מניבים תוצאות חלקיות ותקינות + במקום כשל מוחלט. +**אימות סכימה**: תמיכה באימות סכימה של JSON עבור אובייקטים בודדים. +**איחודים מובחנים**: תמיכה בפלטים מסוגים מעורבים באמצעות שדה `type` + מפריד. +**שינויים מינימליים ב-API**: הרחבת תצורת השאילתה הקיימת עם סוג + תגובה חדש ומפתח סכימה. + +## רקע + +### ארכיטקטורה נוכחית + +שירות השאילתות תומך בשני סוגי תגובה: + +1. `response-type: "text"` - תגובה טקסטואלית גולמית המוחזרת כפי שהיא. +2. `response-type: "json"` - JSON המנותח מהתגובה, ומאומת כנגד + `schema` אופציונלי. + +יישום נוכחי ב-`trustgraph-flow/trustgraph/template/prompt_manager.py`: + +```python +class Prompt: + def __init__(self, template, response_type = "text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema +``` + +### מגבלות נוכחיות + +כאשר הנחיות החילוץ מבקשות פלט כמערכים מסוג JSON (`[{...}, {...}, ...]`): + +**שחיתות עקב קיטום**: אם מודל השפה (LLM) מגיע למגבלת מספר הטוקנים במהלך יצירת המערך, + התגובה כולה הופכת ל-JSON לא חוקי ואי אפשר לנתח אותה. +**ניתוח "הכל או כלום":** יש לקבל את הפלט השלם לפני הניתוח. +**אין תוצאות חלקיות:** תגובה מקוטעת מניבה אפס נתונים שניתן להשתמש בהם. +**לא אמין עבור חילוצים גדולים:** ככל שיותר פריטים מחולצים, כך גדל הסיכון לכישלון. + +מפרט זה מתייחס למגבלות אלה על ידי הצגת פורמט JSONL עבור +הנחיות חילוץ, כאשר כל פריט מחולץ הוא אובייקט JSON שלם בשורה +משלו. + +## עיצוב טכני + +### הרחבת סוג התגובה + +הוסף סוג תגובה חדש `"jsonl"` לצד סוגי `"text"` ו-`"json"` הקיימים. + +#### שינויי תצורה + +**ערך חדש עבור סוג התגובה:** + +``` +"response-type": "jsonl" +``` + +**פרשנות של הסכימה:** + +המפתח הקיים `"schema"` משמש הן עבור סוג התגובה `"json"` והן עבור סוג התגובה `"jsonl"`. +הפרשנות תלויה בסוג התגובה: + +`"json"`: הסכימה מתארת את כל התגובה (בדרך כלל מערך או אובייקט). +`"jsonl"`: הסכימה מתארת כל שורה/אובייקט בנפרד. + +```json +{ + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["entity", "definition"] + } +} +``` + +זה מונע שינויים בכלי התצורה ובתוכנות העריכה. + +### מפרט פורמט JSONL + +#### חילוץ פשוט + +עבור שאילתות המפיקות סוג אחד של אובייקט (הגדרות, קשרים, +נושאים, שורות), הפלט הוא אובייקט JSON אחד בכל שורה, ללא עטיפה: + +**פורמט פלט של השאילתה:** +``` +{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"} +{"entity": "chlorophyll", "definition": "Green pigment in plants"} +{"entity": "mitochondria", "definition": "Powerhouse of the cell"} +``` + +**ניגוד לפורמט מערך JSON הקודם:** +```json +[ + {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, + {"entity": "chlorophyll", "definition": "Green pigment in plants"}, + {"entity": "mitochondria", "definition": "Powerhouse of the cell"} +] +``` + +אם מודל השפה הגדול (LLM) מקצר אחרי השורה 2, פורמט מערך ה-JSON ייתן JSON לא תקין, +בעוד ש-JSONL ייתן שני אובייקטים תקינים. + +#### חילוץ של טיפוסים מעורבים (איחודים מובחנים) + +עבור הנחיות המפיקות מספר סוגים של אובייקטים (לדוגמה, גם הגדרות וגם +קשרים, או ישויות, קשרים ומאפיינים), השתמש בשדה `"type"` +כמבחין: + +**פורמט פלט של ההנחיה:** +``` +{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"} +{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true} +{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"} +{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true} +``` + +**הסכימה עבור איחודים מובחנים משתמשת ב-`oneOf`:** +```json +{ + "response-type": "jsonl", + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { "const": "definition" }, + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["type", "entity", "definition"] + }, + { + "type": "object", + "properties": { + "type": { "const": "relationship" }, + "subject": { "type": "string" }, + "predicate": { "type": "string" }, + "object": { "type": "string" }, + "object-entity": { "type": "boolean" } + }, + "required": ["type", "subject", "predicate", "object", "object-entity"] + } + ] + } +} +``` + +#### חילוץ אונטולוגיה + +עבור חילוץ המבוסס על אונטולוגיה, הכולל ישויות, קשרים ומאפיינים: + +**פורמט פלט של ההנחיה:** +``` +{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"} +{"type": "entity", "entity": "beef", "entity_type": "fo/Food"} +{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"} +{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"} +``` + +### פרטי יישום + +#### מחלקת Prompt + +המחלקה הקיימת `Prompt` אינה דורשת שינויים. השדה `schema` משמש מחדש +עבור JSONL, והפרשנות שלו נקבעת על ידי `response_type`: + +```python +class Prompt: + def __init__(self, template, response_type="text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema # Interpretation depends on response_type +``` + +#### PromptManager.load_config + +אין צורך בשינויים - הטעינה הקיימת של התצורה כבר מטפלת במפתח +`schema`. + +#### ניתוח JSONL + +הוסף שיטת ניתוח חדשה לתגובות JSONL: + +```python +def parse_jsonl(self, text): + """ + Parse JSONL response, returning list of valid objects. + + Invalid lines (malformed JSON, empty lines) are skipped with warnings. + This provides truncation resilience - partial output yields partial results. + """ + results = [] + + for line_num, line in enumerate(text.strip().split('\n'), 1): + line = line.strip() + + # Skip empty lines + if not line: + continue + + # Skip markdown code fence markers if present + if line.startswith('```'): + continue + + try: + obj = json.loads(line) + results.append(obj) + except json.JSONDecodeError as e: + # Log warning but continue - this provides truncation resilience + logger.warning(f"JSONL parse error on line {line_num}: {e}") + + return results +``` + +#### שינויים ב-PromptManager.invoke + +הרחב את השיטה invoke כדי לטפל בסוג התגובה החדש: + +```python +async def invoke(self, id, input, llm): + logger.debug("Invoking prompt template...") + + terms = self.terms | self.prompts[id].terms | input + resp_type = self.prompts[id].response_type + + prompt = { + "system": self.system_template.render(terms), + "prompt": self.render(id, input) + } + + resp = await llm(**prompt) + + if resp_type == "text": + return resp + + if resp_type == "json": + try: + obj = self.parse_json(resp) + except: + logger.error(f"JSON parse failed: {resp}") + raise RuntimeError("JSON parse fail") + + if self.prompts[id].schema: + try: + validate(instance=obj, schema=self.prompts[id].schema) + logger.debug("Schema validation successful") + except Exception as e: + raise RuntimeError(f"Schema validation fail: {e}") + + return obj + + if resp_type == "jsonl": + objects = self.parse_jsonl(resp) + + if not objects: + logger.warning("JSONL parse returned no valid objects") + return [] + + # Validate each object against schema if provided + if self.prompts[id].schema: + validated = [] + for i, obj in enumerate(objects): + try: + validate(instance=obj, schema=self.prompts[id].schema) + validated.append(obj) + except Exception as e: + logger.warning(f"Object {i} failed schema validation: {e}") + return validated + + return objects + + raise RuntimeError(f"Response type {resp_type} not known") +``` + +### הנחיות מושפעות + +ההנחיות הבאות צריכות להיות מועברות לפורמט JSONL: + +| מזהה הנחיה | תיאור | שדה סוג | +|-----------|-------------|------------| +| `extract-definitions` | חילוץ ישויות/הגדרות | לא (סוג בודד) | +| `extract-relationships` | חילוץ קשרים | לא (סוג בודד) | +| `extract-topics` | חילוץ נושא/הגדרה | לא (סוג בודד) | +| `extract-rows` | חילוץ שורה מובנית | לא (סוג בודד) | +| `agent-kg-extract` | חילוץ משולב של הגדרה + קשר | כן: `"definition"`, `"relationship"` | +| `extract-with-ontologies` / `ontology-extract` | חילוץ מבוסס אונטולוגיה | כן: `"entity"`, `"relationship"`, `"attribute"` | ### שינויים ב-API -* **לקוח:** אין שינויים נדרשים בצד הלקוח. לקוחות ממשיכים לקבל רשימה של אובייקטים (list of objects) כפלט, ללא הבדל אם מדובר בפורמט JSON או JSONL. -* **שרת:** שינוי בצד השרת לטובת ניתוח (parsing) של קבצי JSONL שורות-אחר-שורות (line-by-line) כדי לאפשר חילוץ חלקי גם במקרה של קיטוע. +#### נקודת מבט של הלקוח -### תוכנית מעבר +ניתוח JSONL שקוף למשתמשי ה-API של שירות ההנחיות. הניתוח מתבצע +בצד השרת בשירות ההנחיות, והתגובה מוחזרת באמצעות השדה הסטנדרטי +`PromptResponse.object` כמערך JSON מוסרי. -* **שלב 1: יישום:** יישום פונקציית ניתוח JSONL חדשה בצד השרת. -* **שלב 2: מעבר הנחיות:** מעבר הדרגתי של הנחיות קיימות לפורמט JSONL. -* **שלב 3: עדכונים נלווים:** עדכון קוד צד לקוח (אם יש) כדי להתאים לפורמט הפלט החדש. +כאשר לקוחות קוראים לשירות ההנחיות (דרך `PromptClient.prompt()` או דומה): + +**`response-type: "json"`** עם סכימת מערך → הלקוח מקבל `list` בפייתון +**`response-type: "jsonl"`** → הלקוח מקבל `list` בפייתון + +מנקודת מבטו של הלקוח, שתי השיטות מחזירות מבני נתונים זהים. ההבדל +הוא אך ורק באופן שבו פלט ה-LLM מנותח בצד השרת: + +פורמט מערך JSON: קריאה אחת ל-`json.loads()`; נכשל לחלוטין אם הוא חתוך +פורמט JSONL: ניתוח שורה אחר שורה; מייצר תוצאות חלקיות אם הוא חתוך + +המשמעות היא שקוד לקוח קיים שמצפה לרשימה מהנחיות חילוץ +אינו דורש שינויים בעת העברת הנחיות מפורמט JSON לפורמט JSONL. + +#### ערך החזרה של השרת + +עבור `response-type: "jsonl"`, השיטה `PromptManager.invoke()` מחזירה +`list[dict]` המכיל את כל האובייקטים שנותחו ואומתו בהצלחה. +רשימה זו מוסרת אז ל-JSON עבור השדה `PromptResponse.object`. + +#### טיפול בשגיאות + +תוצאות ריקות: מחזיר רשימה ריקה `[]` עם רישום אזהרה +כשל חלקי בניתוח: מחזיר רשימה של אובייקטים שנותחו בהצלחה עם + רישומי אזהרה עבור כשלים +כשל מוחלט בניתוח: מחזיר רשימה ריקה `[]` עם רישומי אזהרה + +זה שונה מ-`response-type: "json"` שמגביר `RuntimeError` +בעת כשל בניתוח. ההתנהגות הסלחנית עבור JSONL היא מכוונת כדי לספק +עמידות לחיתוך. + +### דוגמה לתצורה + +דוגמה מלאה לתצורה של הנחיה: + +```json +{ + "prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"\", \"definition\": \"\"}", + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "The entity name" + }, + "definition": { + "type": "string", + "description": "A clear definition of the entity" + } + }, + "required": ["entity", "definition"] + } +} +``` ## שיקולי אבטחה -* **אימות קלט:** ניתוח JSON משתמש בפונקציה `json.loads()` הסטנדרטית, הבטוחה מפני התקפות הזרקה (injection). -* **אימות סכימה:** שימוש ב-`jsonschema.validate()` לאכיפת סכימה. -* **ללא משטח תקיפה חדש:** ניתוח JSONL בטוח יותר מניתוח JSON מערך עקב עיבוד שורות-אחר-שורות. +**בדיקת תקינות קלט**: ניתוח JSON משתמש ב-`json.loads()` הסטנדרטי, שהוא בטוח + מפני התקפות הזרקה. +**בדיקת תאימות סכימה**: משתמש ב-`jsonschema.validate()` לאכיפת סכימה. +**ללא משטח תקיפה חדש**: ניתוח JSONL בטוח יותר מניתוח מערך JSON + בשל עיבוד שורה אחר שורה. ## שיקולי ביצועים -* **זיכרון:** ניתוח שורות-אחר-שורות משתמש בפחות זיכרון שיא בהשוואה לטעינת מערכי JSON שלמים. -* **השהייה:** ביצועי הניתוח דומים לניתוח מערכי JSON. -* **אימות:** אימות סכימה מתבצע עבור כל אובייקט, מה שמוסיף תקורה, אך מאפשר קבלת תוצאות חלקיות גם במקרה של כשל באימות. +**זיכרון**: ניתוח שורה אחר שורה משתמש בפחות זיכרון שיא בהשוואה לטעינת מערכי JSON שלמים. + +**השהיה**: ביצועי הניתוח דומים לניתוח מערך JSON. +**בדיקת תאימות**: בדיקת תאימות סכימה מתבצעת עבור כל אובייקט, מה שמוסיף תקורה אך + מאפשר תוצאות חלקיות במקרה של כשל בבדיקת התאימות. -### שיקולים נוספים +## אסטרטגיית בדיקות -* **אמינות:** פלט JSONL מאפשר המשך עיבוד גם במקרה של שגיאות או קיטועים, בעוד שפלט JSON מערך עלול לגרום לכשל מוחלט. -* **גמישות:** תמיכה בסוגים מעורבים של ישויות (entities) מאפשרת חילוץ נתונים מורכבים יותר. +### בדיקות יחידה + +ניתוח JSONL עם קלט תקין. +ניתוח JSONL עם שורות ריקות. +ניתוח JSONL עם גדרות קוד Markdown. +ניתוח JSONL עם שורה אחרונה חתוכה. +ניתוח JSONL עם שורות JSON לא תקינות המפוזרות. +בדיקת תאימות סכימה עם איחודים מובחנים של `oneOf`. +תאימות לאחור: הנחיות `"text"` ו-`"json"` קיימות אינן משתנות. + +### בדיקות אינטגרציה + +חילוץ מקצה לקצה עם הנחיות JSONL. +חילוץ עם קיצוץ מדומם (תגובה מוגבלת באופן מלאכותי). +חילוץ מסוגים מעורבים עם מפריד סוגים. +חילוץ אונטולוגיה עם שלושת הסוגים. + +### בדיקות איכות חילוץ + +השוואת תוצאות חילוץ: פורמט JSONL לעומת מערך JSON. +בדיקת עמידות בפני קיטוע: JSONL מניב תוצאות חלקיות כאשר JSON נכשל. + +## תוכנית מעבר + +### שלב 1: הטמעה + +1. הטמעת שיטה `parse_jsonl()` ב-`PromptManager`. +2. הרחבת `invoke()` כדי לטפל ב-`response-type: "jsonl"`. +3. הוספת בדיקות יחידה. + +### שלב 2: מעבר להנחיות + +1. עדכון ההנחיה והתצורה של `extract-definitions`. +2. עדכון ההנחיה והתצורה של `extract-relationships`. +3. עדכון ההנחיה והתצורה של `extract-topics`. +4. עדכון ההנחיה והתצורה של `extract-rows`. +5. עדכון ההנחיה והתצורה של `agent-kg-extract`. +6. עדכון ההנחיה והתצורה של `extract-with-ontologies`. + +### שלב 3: עדכונים במערכות משימתיות + +1. עדכון כל קוד המשתמש בתוצאות החילוץ כדי לטפל בסוג החזרה של רשימה. +2. עדכון קוד המקטלג חילוצים מסוגים מעורבים לפי שדה `type`. +3. עדכון בדיקות המאמתות את פורמט הפלט של החילוץ. ## שאלות פתוחות -אף אחת בשלב זה. +אין כרגע. ## הפניות -* יישום נוכחי: `trustgraph-flow/trustgraph/template/prompt_manager.py` -* מפרט JSON Lines: https://jsonlines.org/ -* סכימת JSON `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof -* מפרט קשור: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file +יישום נוכחי: `trustgraph-flow/trustgraph/template/prompt_manager.py`. +מפרט JSON Lines: https://jsonlines.org/. +סכימת JSON `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof. +מפרט קשור: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`). diff --git a/docs/tech-specs/jsonl-prompt-output.hi.md b/docs/tech-specs/jsonl-prompt-output.hi.md index 04ee53f4..72310ff2 100644 --- a/docs/tech-specs/jsonl-prompt-output.hi.md +++ b/docs/tech-specs/jsonl-prompt-output.hi.md @@ -2,87 +2,454 @@ ## अवलोकन -यह विनिर्देश ट्रस्टग्राफ में प्रॉम्प्ट प्रतिक्रियाओं के लिए JSONL (JSON लाइन्स) आउटपुट प्रारूप के कार्यान्वयन का वर्णन करता है। JSONL, LLM (लार्ज लैंग्वेज मॉडल) प्रतिक्रियाओं से संरचित डेटा के ट्रंकेशन-प्रतिरोधी निष्कर्षण को सक्षम बनाता है, जो JSON सरणियों के आउटपुट के साथ महत्वपूर्ण समस्याओं को संबोधित करता है जब LLM प्रतिक्रियाएं आउटपुट टोकन सीमाओं तक पहुँच जाती हैं। +यह विनिर्देश ट्रस्टग्राफ में प्रॉम्प्ट प्रतिक्रियाओं के लिए JSONL (JSON लाइन्स) आउटपुट प्रारूप के कार्यान्वयन का वर्णन करता है। JSONL, LLM प्रतिक्रियाओं से संरचित डेटा को निकालने में सक्षम बनाता है, जो कि LLM प्रतिक्रियाओं के आउटपुट टोकन सीमाओं तक पहुंचने पर JSON सरणी आउटपुट के दूषित होने जैसी महत्वपूर्ण समस्याओं को हल करता है। + + + + यह कार्यान्वयन निम्नलिखित उपयोग मामलों का समर्थन करता है: -1. **ट्रंकेशन-प्रतिरोधी निष्कर्षण**: LLM आउटपुट के बीच में काटे जाने पर भी, वैध आंशिक परिणाम निकालें। -2. **बड़े पैमाने पर निष्कर्षण**: टोकन सीमाओं के कारण पूर्ण विफलता के जोखिम के बिना, कई वस्तुओं का निष्कर्षण संभालें। -3. **मिश्रित-प्रकार निष्कर्षण**: एक ही प्रॉम्प्ट में कई इकाई प्रकारों (परिभाषाएं, संबंध, एंटिटीज, विशेषताएँ) का निष्कर्षण समर्थन करें। -4. **स्ट्रीमिंग-संगत आउटपुट**: निष्कर्षण परिणामों की भविष्य की स्ट्रीमिंग/इंक्रीमेंटल प्रोसेसिंग को सक्षम करें। +1. **ट्रंकेशन-रेज़िलिएंट एक्सट्रैक्शन (Truncation-Resilient Extraction)**: वैध आंशिक परिणाम निकालें, भले ही + एलएलएम (LLM) आउटपुट प्रतिक्रिया के बीच में ही काट दिया गया हो। +2. **बड़े पैमाने पर एक्सट्रैक्शन (Large-Scale Extraction)**: टोकन सीमाओं के कारण पूर्ण विफलता के जोखिम के बिना, कई वस्तुओं के निष्कर्षण को संभालें। + 3. **मिश्रित-प्रकार एक्सट्रैक्शन (Mixed-Type Extraction)**: एक ही प्रॉम्प्ट में कई इकाई प्रकारों (परिभाषाओं, संबंधों, संस्थाओं, विशेषताओं) के निष्कर्षण का समर्थन करें। +4. **स्ट्रीमिंग-संगत आउटपुट (Streaming-Compatible Output)**: निष्कर्षण परिणामों की भविष्य की स्ट्रीमिंग/क्रमिक + प्रसंस्करण को सक्षम करें। + + ## लक्ष्य -- **पिछला संगतता**: `response-type: "json"` और `response-type: "text"` के साथ मौजूदा प्रॉम्प्ट अपरिवर्तित रहेंगे। -- **आंशिक परिणाम**: ट्रंकेशन के मामले में, आंशिक परिणाम प्राप्त करने की क्षमता। -- **सरल एपीआई**: क्लाइंट-साइड कोड में कोई बदलाव की आवश्यकता नहीं है। +**पिछड़ा संगतता (Backward Compatibility)**: मौजूदा प्रॉम्प्ट जो `response-type: "text"` और का उपयोग करते हैं, + `response-type: "json"` बिना किसी बदलाव के काम करना जारी रखते हैं। +**अतिसंयमी लचीलापन (Truncation Resilience)**: आंशिक एलएलएम आउटपुट आंशिक, मान्य परिणाम देते हैं, + पूर्ण विफलता के बजाय। +**स्कीमा सत्यापन (Schema Validation)**: व्यक्तिगत ऑब्जेक्ट के लिए JSON स्कीमा सत्यापन का समर्थन। +**विभेदक संघ (Discriminated Unions)**: `type` फ़ील्ड का उपयोग करके मिश्रित-प्रकार के आउटपुट का समर्थन। + विभेदक। +**न्यूनतम एपीआई परिवर्तन (Minimal API Changes)**: नए प्रतिक्रिया प्रकार और स्कीमा कुंजी के साथ मौजूदा प्रॉम्प्ट कॉन्फ़िगरेशन का विस्तार। + -## सुरक्षा विचार +## पृष्ठभूमि -- **इनपुट सत्यापन**: JSON पार्सिंग मानक `json.loads()` का उपयोग करता है जो इंजेक्शन हमलों के खिलाफ सुरक्षित है। -- **स्कीमा सत्यापन**: स्कीमा प्रवर्तन के लिए `jsonschema.validate()` का उपयोग किया जाता है। -- **कोई नया हमला सतह नहीं**: JSONL पार्सिंग, पंक्ति-दर-पंक्ति प्रसंस्करण के कारण JSON सरणी पार्सिंग की तुलना में सख्त रूप से सुरक्षित है। +### वर्तमान आर्किटेक्चर -## प्रदर्शन विचार +प्रॉम्प्ट सेवा दो प्रकार के प्रतिक्रियाओं का समर्थन करती है: -- **मेमोरी**: पंक्ति-दर-पंक्ति पार्सिंग, पूर्ण JSON सरणियों को लोड करने की तुलना में कम पीक मेमोरी का उपयोग करता है। -- **विलंबता**: पार्सिंग प्रदर्शन JSON सरणी पार्सिंग के समान है। -- **सत्यापन**: स्कीमा सत्यापन प्रति-वस्तु चलता है, जो ओवरहेड जोड़ता है लेकिन सत्यापन विफलता पर आंशिक परिणामों को सक्षम करता है। +1. `response-type: "text"` - बिना किसी बदलाव के वापस की गई कच्ची टेक्स्ट प्रतिक्रिया +2. `response-type: "json"` - प्रतिक्रिया से पार्स किया गया JSON, जिसकी जाँच `response-type: "json"` के विरुद्ध की जाती है + वैकल्पिक `schema` + +`trustgraph-flow/trustgraph/template/prompt_manager.py` में वर्तमान कार्यान्वयन: + +```python +class Prompt: + def __init__(self, template, response_type = "text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema +``` + +### वर्तमान सीमाएँ + +जब निष्कर्षण प्रॉम्प्ट आउटपुट को JSON सरणियों (`[{...}, {...}, ...]`) के रूप में मांगते हैं: + +**अतिसंक्षेपण भ्रष्टाचार**: यदि LLM आउटपुट टोकन सीमाओं को सरणी के बीच में पार करता है, तो + संपूर्ण प्रतिक्रिया अमान्य JSON बन जाती है और इसे पार्स नहीं किया जा सकता है। +**सब कुछ या कुछ नहीं पार्सिंग**: पार्स करने से पहले पूर्ण आउटपुट प्राप्त करना आवश्यक है। +**कोई आंशिक परिणाम नहीं**: एक छोटा आउटपुट शून्य उपयोगी डेटा उत्पन्न करता है। +**बड़े निष्कर्षणों के लिए अविश्वसनीय**: अधिक निकाले गए आइटम = उच्च विफलता जोखिम। + +यह विनिर्देश इन सीमाओं को JSONL प्रारूप को पेश करके संबोधित करता है, जहाँ प्रत्येक निकाले गए आइटम को अपनी +पंक्ति पर एक पूर्ण JSON ऑब्जेक्ट के रूप में दर्शाया जाता है। + + +## तकनीकी डिज़ाइन + +### प्रतिक्रिया प्रकार विस्तार + +मौजूदा `"text"` और `"json"` प्रकारों के साथ एक नया प्रतिक्रिया प्रकार `"jsonl"` जोड़ें। + +#### कॉन्फ़िगरेशन परिवर्तन + +**नया प्रतिक्रिया प्रकार मान:** + +``` +"response-type": "jsonl" +``` + +**स्कीमा व्याख्या:** + +मौजूदा `"schema"` कुंजी का उपयोग `"json"` और `"jsonl"` दोनों प्रतिक्रिया प्रकारों के लिए किया जाता है। +व्याख्या प्रतिक्रिया के प्रकार पर निर्भर करती है: + +`"json"`: स्कीमा संपूर्ण प्रतिक्रिया का वर्णन करता है (आमतौर पर एक सरणी या ऑब्जेक्ट)। +`"jsonl"`: स्कीमा प्रत्येक व्यक्तिगत पंक्ति/ऑब्जेक्ट का वर्णन करता है। + +```json +{ + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["entity", "definition"] + } +} +``` + +यह प्रॉम्प्ट कॉन्फ़िगरेशन टूलिंग और संपादकों में बदलावों से बचाता है। + +### JSONL प्रारूप विनिर्देश + +#### सरल निष्कर्षण + +उन प्रॉम्प्ट के लिए जो केवल एक प्रकार की वस्तु (परिभाषाएँ, संबंध, +विषय, पंक्तियाँ) निकालते हैं, आउटपुट में बिना किसी अतिरिक्त आवरण के प्रति पंक्ति एक JSON ऑब्जेक्ट होता है: + +**प्रॉम्प्ट आउटपुट प्रारूप:** +``` +{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"} +{"entity": "chlorophyll", "definition": "Green pigment in plants"} +{"entity": "mitochondria", "definition": "Powerhouse of the cell"} +``` + +**पिछले JSON सरणी प्रारूप के साथ अंतर:** +```json +[ + {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, + {"entity": "chlorophyll", "definition": "Green pigment in plants"}, + {"entity": "mitochondria", "definition": "Powerhouse of the cell"} +] +``` + +यदि एलएलएम (LLM) दूसरी पंक्ति के बाद कट जाता है, तो JSON सरणी प्रारूप अमान्य JSON उत्पन्न करता है, +जबकि JSONL दो मान्य ऑब्जेक्ट उत्पन्न करता है। + +#### मिश्रित-प्रकार निष्कर्षण (भेदभावपूर्ण संघ) + +उन प्रॉम्प्ट के लिए जो ऑब्जेक्ट के कई प्रकारों को निकालते हैं (उदाहरण के लिए, परिभाषाएँ और +संबंध, या इकाइयाँ, संबंध और विशेषताएँ), एक `"type"` +फ़ील्ड को विभेदक के रूप में उपयोग करें: + +**प्रॉम्प्ट आउटपुट प्रारूप:** +``` +{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"} +{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true} +{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"} +{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true} +``` + +**विभेदक संघों के लिए स्कीमा `oneOf` का उपयोग करता है:** +```json +{ + "response-type": "jsonl", + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { "const": "definition" }, + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["type", "entity", "definition"] + }, + { + "type": "object", + "properties": { + "type": { "const": "relationship" }, + "subject": { "type": "string" }, + "predicate": { "type": "string" }, + "object": { "type": "string" }, + "object-entity": { "type": "boolean" } + }, + "required": ["type", "subject", "predicate", "object", "object-entity"] + } + ] + } +} +``` + +#### शब्दावली निष्कर्षण + +संस्थाओं, संबंधों और विशेषताओं के साथ शब्दावली-आधारित निष्कर्षण के लिए: + +**प्रॉम्प्ट आउटपुट प्रारूप:** +``` +{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"} +{"type": "entity", "entity": "beef", "entity_type": "fo/Food"} +{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"} +{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"} +``` + +### कार्यान्वयन विवरण + +#### प्रॉम्प्ट क्लास + +मौजूदा `Prompt` क्लास में कोई बदलाव आवश्यक नहीं है। `schema` फ़ील्ड का पुन: उपयोग किया गया है। +JSONL के लिए, जिसका अर्थ `response_type` द्वारा निर्धारित किया जाता है: + +```python +class Prompt: + def __init__(self, template, response_type="text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema # Interpretation depends on response_type +``` + +#### प्रॉम्प्टमैनेजर.लोड_कॉन्फ़िगरेशन + +कोई बदलाव आवश्यक नहीं है - मौजूदा कॉन्फ़िगरेशन लोड करने की प्रक्रिया पहले से ही +`schema` कुंजी को संभालती है। + +#### JSONL पार्सिंग + +JSONL प्रतिक्रियाओं के लिए एक नई पार्सिंग विधि जोड़ें: + +```python +def parse_jsonl(self, text): + """ + Parse JSONL response, returning list of valid objects. + + Invalid lines (malformed JSON, empty lines) are skipped with warnings. + This provides truncation resilience - partial output yields partial results. + """ + results = [] + + for line_num, line in enumerate(text.strip().split('\n'), 1): + line = line.strip() + + # Skip empty lines + if not line: + continue + + # Skip markdown code fence markers if present + if line.startswith('```'): + continue + + try: + obj = json.loads(line) + results.append(obj) + except json.JSONDecodeError as e: + # Log warning but continue - this provides truncation resilience + logger.warning(f"JSONL parse error on line {line_num}: {e}") + + return results +``` + +#### प्रॉम्प्टमैनेजर.इनवॉइक में बदलाव + +इनवॉइक विधि को नए प्रतिक्रिया प्रकार को संभालने के लिए विस्तारित करें: + +```python +async def invoke(self, id, input, llm): + logger.debug("Invoking prompt template...") + + terms = self.terms | self.prompts[id].terms | input + resp_type = self.prompts[id].response_type + + prompt = { + "system": self.system_template.render(terms), + "prompt": self.render(id, input) + } + + resp = await llm(**prompt) + + if resp_type == "text": + return resp + + if resp_type == "json": + try: + obj = self.parse_json(resp) + except: + logger.error(f"JSON parse failed: {resp}") + raise RuntimeError("JSON parse fail") + + if self.prompts[id].schema: + try: + validate(instance=obj, schema=self.prompts[id].schema) + logger.debug("Schema validation successful") + except Exception as e: + raise RuntimeError(f"Schema validation fail: {e}") + + return obj + + if resp_type == "jsonl": + objects = self.parse_jsonl(resp) + + if not objects: + logger.warning("JSONL parse returned no valid objects") + return [] + + # Validate each object against schema if provided + if self.prompts[id].schema: + validated = [] + for i, obj in enumerate(objects): + try: + validate(instance=obj, schema=self.prompts[id].schema) + validated.append(obj) + except Exception as e: + logger.warning(f"Object {i} failed schema validation: {e}") + return validated + + return objects + + raise RuntimeError(f"Response type {resp_type} not known") +``` + +### प्रभावित संकेत (प्रॉम्प्ट) + +निम्नलिखित संकेतों को JSONL प्रारूप में स्थानांतरित किया जाना चाहिए: + +| संकेत आईडी | विवरण | प्रकार फ़ील्ड | +|-----------|-------------|------------| +| `extract-definitions` | इकाई/परिभाषा निष्कर्षण | नहीं (एकल प्रकार) | +| `extract-relationships` | संबंध निष्कर्षण | नहीं (एकल प्रकार) | +| `extract-topics` | विषय/परिभाषा निष्कर्षण | नहीं (एकल प्रकार) | +| `extract-rows` | संरचित पंक्ति निष्कर्षण | नहीं (एकल प्रकार) | +| `agent-kg-extract` | संयुक्त परिभाषा + संबंध निष्कर्षण | हाँ: `"definition"`, `"relationship"` | +| `extract-with-ontologies` / `ontology-extract` | ज्ञान-आधारित निष्कर्षण | हाँ: `"entity"`, `"relationship"`, `"attribute"` | + +### एपीआई में बदलाव + +#### क्लाइंट का दृष्टिकोण + +JSONL पार्सिंग, प्रॉम्प्ट सर्विस एपीआई उपयोगकर्ताओं के लिए पारदर्शी है। पार्सिंग प्रॉम्प्ट सर्विस में सर्वर-साइड पर होता है, और प्रतिक्रिया मानक ⟦CODE_0⟧ फ़ील्ड के रूप में एक क्रमबद्ध JSON सरणी के माध्यम से वापस की जाती है। + +`PromptResponse.object` + +जब ग्राहक प्रॉम्प्ट सेवा को कॉल करते हैं (`PromptClient.prompt()` या इसी तरह के माध्यम से): + +**`response-type: "json"`** जिसमें एरे स्कीमा है → ग्राहक को पायथन `list` प्राप्त होता है। +**`response-type: "jsonl"`** → ग्राहक को पायथन `list` प्राप्त होता है। + +ग्राहक के दृष्टिकोण से, दोनों समान डेटा संरचनाएं लौटाते हैं। +अंतर पूरी तरह से इस बात में है कि सर्वर-साइड पर एलएलएम आउटपुट को कैसे पार्स किया जाता है: + +JSON सरणी प्रारूप: एक `json.loads()` कॉल; यदि छोटा किया गया तो पूरी तरह से विफल हो जाता है। +JSONL प्रारूप: लाइन-दर-लाइन पार्सिंग; यदि छोटा किया गया तो आंशिक परिणाम देता है। + +इसका मतलब है कि मौजूदा क्लाइंट कोड जो एक्सट्रैक्शन प्रॉम्प्ट से एक सूची की अपेक्षा करता है, +को JSON से JSONL प्रारूप में प्रॉम्प्ट माइग्रेट करते समय किसी भी बदलाव की आवश्यकता नहीं होती है। + +#### सर्वर रिटर्न वैल्यू + +`response-type: "jsonl"` के लिए, `PromptManager.invoke()` विधि एक +`list[dict]` लौटाती है जिसमें सभी सफलतापूर्वक पार्स और मान्य किए गए ऑब्जेक्ट शामिल होते हैं। इस +सूची को तब `PromptResponse.object` फ़ील्ड के लिए JSON में क्रमबद्ध किया जाता है। + +#### त्रुटि प्रबंधन + +खाली परिणाम: खाली सूची `[]` लौटाता है चेतावनी लॉग के साथ। +आंशिक पार्स विफलता: सफलतापूर्वक पार्स किए गए ऑब्जेक्ट की सूची लौटाता है, + विफलताओं के लिए चेतावनी लॉग के साथ। +पूर्ण पार्स विफलता: खाली सूची `[]` लौटाता है, चेतावनी लॉग के साथ। + +यह `response-type: "json"` से अलग है, जो पार्स विफलता पर `RuntimeError` उत्पन्न करता है। +JSONL के लिए उदार व्यवहार जानबूझकर प्रदान किया गया है ताकि ट्रंकेशन के प्रति लचीलापन मिल सके। + + +### कॉन्फ़िगरेशन उदाहरण + +पूर्ण प्रॉम्प्ट कॉन्फ़िगरेशन उदाहरण: + +```json +{ + "prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"\", \"definition\": \"\"}", + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "The entity name" + }, + "definition": { + "type": "string", + "description": "A clear definition of the entity" + } + }, + "required": ["entity", "definition"] + } +} +``` + +## सुरक्षा संबंधी विचार + +**इनपुट सत्यापन**: JSON पार्सिंग मानक `json.loads()` का उपयोग करता है, जो इंजेक्शन हमलों के खिलाफ सुरक्षित है। + **स्कीमा सत्यापन**: स्कीमा प्रवर्तन के लिए ⟦CODE_0⟧ का उपयोग करता है। +**स्कीमा सत्यापन**: स्कीमा के अनुपालन को सुनिश्चित करने के लिए `jsonschema.validate()` का उपयोग करता है। +**कोई नया आक्रमण क्षेत्र नहीं**: JSONL पार्सिंग, लाइन-दर-लाइन प्रसंस्करण के कारण, JSON सरणी पार्सिंग की तुलना में बहुत अधिक सुरक्षित है। + + +## प्रदर्शन संबंधी विचार + +**मेमोरी**: पंक्ति-दर-पंक्ति पार्सिंग, पूरे JSON सरणियों को लोड करने की तुलना में कम चरम मेमोरी का उपयोग करती है। + **विलंबता**: पार्सिंग प्रदर्शन, JSON सरणी पार्सिंग के समान है। +**सत्यापन**: स्कीमा सत्यापन प्रत्येक ऑब्जेक्ट के लिए किया जाता है, जिससे ओवरहेड बढ़ता है, लेकिन सत्यापन विफलता पर आंशिक परिणाम प्राप्त करने की अनुमति मिलती है। + + ## परीक्षण रणनीति ## परीक्षण रणनीति -### यूनिट टेस्ट +### यूनिट परीक्षण (Unit Tests) -- मान्य इनपुट के साथ JSONL पार्सिंग। -- खाली पंक्तियों के साथ JSONL पार्सिंग। -- Markdown कोड फ़ेंस के साथ JSONL पार्सिंग। -- अंतिम पंक्ति के काटे जाने के साथ JSONL पार्सिंग। -- अमान्य JSON पंक्तियों के साथ JSONL पार्सिंग। -- `oneOf` विभेदक यूनियनों के साथ स्कीमा सत्यापन। -- पिछड़ा संगतता: मौजूदा `"text"` और `"json"` प्रॉम्प्ट अपरिवर्तित। +मान्य इनपुट के साथ JSONL पार्सिंग +खाली पंक्तियों के साथ JSONL पार्सिंग +मार्कडाउन कोड फ़ेंस के साथ JSONL पार्सिंग +कटे हुए अंतिम पंक्ति के साथ JSONL पार्सिंग +अमान्य JSON पंक्तियों के साथ JSONL पार्सिंग +`oneOf` विभेदक संघों के साथ स्कीमा सत्यापन +पिछली अनुकूलता: मौजूदा `"text"` और `"json"` प्रॉम्प्ट अपरिवर्तित -### एकीकरण परीक्षण +### एकीकरण परीक्षण (Integration Tests) -- JSONL प्रॉम्प्ट के साथ एंड-टू-एंड निष्कर्षण। -- सिमुलेटेड ट्रंकेशन (कृत्रिम रूप से सीमित प्रतिक्रिया) के साथ निष्कर्षण। -- प्रकार विभेदक के साथ मिश्रित-प्रकार निष्कर्षण। -- सभी तीन प्रकारों के साथ ऑन्टोलॉजी निष्कर्षण। +JSONL प्रॉम्प्ट के साथ एंड-टू-एंड निष्कर्षण +अनुकरणित कटाई के साथ निष्कर्षण (कृत्रिम रूप से सीमित प्रतिक्रिया) +टाइप डिस्क्रिमिनेटर के साथ मिश्रित-प्रकार निष्कर्षण +सभी तीन प्रकारों के साथ ऑन्टोलॉजी निष्कर्षण -### निष्कर्षण गुणवत्ता परीक्षण +### निष्कर्षण गुणवत्ता परीक्षण (Extraction Quality Tests) -- JSONL बनाम JSON सरणी प्रारूप: निष्कर्षण परिणामों की तुलना। -- ट्रंकेशन प्रतिरोधी: JSONL आंशिक परिणाम देता है जहां JSON विफल रहता है। +निष्कर्षण परिणामों की तुलना करें: JSONL बनाम JSON सरणी प्रारूप +ट्रंकेशन के प्रति लचीलापन की जाँच करें: JSONL आंशिक परिणाम देता है जहाँ JSON विफल रहता है -## प्रवासन योजना +## माइग्रेशन योजना ### चरण 1: कार्यान्वयन -1. `PromptManager` में `parse_jsonl()` विधि लागू करें। -2. `invoke()` का विस्तार `response-type: "jsonl"` को संभालने के लिए। -3. यूनिट टेस्ट जोड़ें। +1. `parse_jsonl()` विधि को `PromptManager` में लागू करें +2. `invoke()` को `response-type: "jsonl"` को संभालने के लिए विस्तारित करें +3. यूनिट परीक्षण जोड़ें -### चरण 2: प्रॉम्प्ट प्रवासन +### चरण 2: प्रॉम्प्ट माइग्रेशन -1. `extract-definitions` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। -2. `extract-relationships` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। -3. `extract-topics` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। -4. `extract-rows` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। -5. `agent-kg-extract` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। -6. `extract-with-ontologies` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। +1. `extract-definitions` प्रॉम्प्ट और कॉन्फ़िगरेशन को अपडेट करें +2. `extract-relationships` प्रॉम्प्ट और कॉन्फ़िगरेशन को अपडेट करें +3. `extract-topics` प्रॉम्प्ट और कॉन्फ़िगरेशन को अपडेट करें +4. `extract-rows` प्रॉम्प्ट और कॉन्फ़िगरेशन को अपडेट करें +5. `agent-kg-extract` प्रॉम्प्ट और कॉन्फ़िगरेशन को अपडेट करें +6. `extract-with-ontologies` प्रॉम्प्ट और कॉन्फ़िगरेशन को अपडेट करें ### चरण 3: डाउनस्ट्रीम अपडेट -1. निष्कर्षण परिणामों को संभालने के लिए निष्कर्षण परिणामों का उपभोग करने वाले किसी भी कोड को अपडेट करें। -2. `type` फ़ील्ड द्वारा वर्गीकृत मिश्रित-प्रकार निष्कर्षण के लिए कोड को अपडेट करें। -3. निष्कर्षण आउटपुट प्रारूप पर जोर देने वाले परीक्षणों को अपडेट करें। +1. निष्कर्षण परिणामों का उपयोग करने वाले किसी भी कोड को सूची रिटर्न प्रकार को संभालने के लिए अपडेट करें +2. `type` फ़ील्ड द्वारा मिश्रित-प्रकार के निष्कर्षणों को वर्गीकृत करने वाले कोड को अपडेट करें +3. निष्कर्षण आउटपुट प्रारूप पर दावा करने वाले परीक्षणों को अपडेट करें ## खुले प्रश्न -इस समय कोई नहीं। +फिलहाल कोई नहीं। ## संदर्भ -- वर्तमान कार्यान्वयन: `trustgraph-flow/trustgraph/template/prompt_manager.py` -- JSON लाइन्स विनिर्देश: https://jsonlines.org/ -- JSON स्कीमा `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof -- संबंधित विनिर्देश: स्ट्रीमिंग LLM प्रतिक्रियाएं (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file +वर्तमान कार्यान्वयन: `trustgraph-flow/trustgraph/template/prompt_manager.py` +JSON लाइन्स विनिर्देश: https://jsonlines.org/ +JSON स्कीमा `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof +संबंधित विनिर्देश: स्ट्रीमिंग LLM प्रतिक्रियाएँ (`docs/tech-specs/streaming-llm-responses.md`) diff --git a/docs/tech-specs/jsonl-prompt-output.pt.md b/docs/tech-specs/jsonl-prompt-output.pt.md new file mode 100644 index 00000000..f80cf765 --- /dev/null +++ b/docs/tech-specs/jsonl-prompt-output.pt.md @@ -0,0 +1,455 @@ +# Especificação Técnica de Saída de Prompt JSONL + +## Visão Geral + +Esta especificação descreve a implementação do formato de saída JSONL (JSON Lines) +para respostas de prompt no TrustGraph. JSONL permite a extração de dados estruturados +de forma resiliente à truncagem das respostas de LLM, abordando problemas críticos +relacionados à corrupção de saídas de matriz JSON quando as respostas de LLM atingem +os limites de tokens de saída. + +Esta implementação suporta os seguintes casos de uso: + +1. **Extração Resistente à Truncagem**: Extrair resultados parciais válidos mesmo quando + a saída do LLM é truncada no meio da resposta. +2. **Extração em Larga Escala**: Lidar com a extração de muitos itens sem risco de + falha completa devido a limites de tokens. +3. **Extração de Tipos Mistos**: Suportar a extração de vários tipos de entidades + (definições, relacionamentos, entidades, atributos) em um único prompt. +4. **Saída Compatível com Streaming**: Permitir o processamento futuro de streaming/incremental + dos resultados da extração. + +## Objetivos + +**Compatibilidade com versões anteriores**: As instruções existentes que usam `response-type: "text"` e + `response-type: "json"` continuam a funcionar sem modificação. +**Resiliência à truncagem**: Saídas parciais do LLM produzem resultados válidos parciais + em vez de falha completa. +**Validação de esquema**: Suporte à validação de esquema JSON para objetos individuais. +**Uniões discriminadas**: Suporte a saídas de tipos mistos usando um campo `type` + discriminador. +**Alterações mínimas na API**: Estenda a configuração de instruções existente com um novo + tipo de resposta e chave de esquema. + +## Contexto + +### Arquitetura atual + +O serviço de instruções suporta dois tipos de resposta: + +1. `response-type: "text"` - Resposta de texto bruto retornada como está. +2. `response-type: "json"` - JSON analisado da resposta, validado contra + um `schema` opcional. + +Implementação atual em `trustgraph-flow/trustgraph/template/prompt_manager.py`: + +```python +class Prompt: + def __init__(self, template, response_type = "text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema +``` + +### Limitações Atuais + +Quando os prompts de extração solicitam a saída como arrays JSON (`[{...}, {...}, ...]`): + +**Corrupção por truncamento**: Se o LLM atinge os limites de tokens de saída no meio do array, a + resposta inteira se torna JSON inválido e não pode ser analisada. +**Análise "tudo ou nada"**: É necessário receber a saída completa antes de analisar. +**Sem resultados parciais**: Uma resposta truncada produz zero dados utilizáveis. +**Não confiável para grandes extrações**: Quanto mais itens extraídos, maior o risco de falha. + +Esta especificação aborda essas limitações introduzindo o formato JSONL para +prompts de extração, onde cada item extraído é um objeto JSON completo em sua +própria linha. + +## Design Técnico + +### Extensão do Tipo de Resposta + +Adicione um novo tipo de resposta `"jsonl"`, juntamente com os tipos existentes `"text"` e `"json"`. + +#### Alterações de Configuração + +**Novo valor do tipo de resposta:** + +``` +"response-type": "jsonl" +``` + +**Interpretação do esquema:** + +A chave existente `"schema"` é usada tanto para o tipo de resposta `"json"` quanto para o tipo de resposta `"jsonl"`. +A interpretação depende do tipo de resposta: + +`"json"`: O esquema descreve toda a resposta (geralmente um array ou objeto). +`"jsonl"`: O esquema descreve cada linha/objeto individual. + +```json +{ + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["entity", "definition"] + } +} +``` + +Isso evita alterações nas ferramentas de configuração e nos editores. + +### Especificação do Formato JSONL + +#### Extração Simples + +Para prompts que extraem um único tipo de objeto (definições, relacionamentos, +tópicos, linhas), a saída é um objeto JSON por linha, sem wrapper: + +**Formato de saída do prompt:** +``` +{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"} +{"entity": "chlorophyll", "definition": "Green pigment in plants"} +{"entity": "mitochondria", "definition": "Powerhouse of the cell"} +``` + +**Contraste com o formato anterior de array JSON:** +```json +[ + {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, + {"entity": "chlorophyll", "definition": "Green pigment in plants"}, + {"entity": "mitochondria", "definition": "Powerhouse of the cell"} +] +``` + +Se o LLM truncar após a linha 2, o formato de array JSON resulta em JSON inválido, +enquanto o JSONL produz dois objetos válidos. + +#### Extração de Tipos Mistos (Uniões Discriminadas) + +Para prompts que extraem vários tipos de objetos (por exemplo, definições e +relacionamentos, ou entidades, relacionamentos e atributos), use um campo `"type"` +como discriminador: + +**Formato de saída do prompt:** +``` +{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"} +{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true} +{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"} +{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true} +``` + +**Esquema para uniões discriminadas usa `oneOf`:** +```json +{ + "response-type": "jsonl", + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { "const": "definition" }, + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["type", "entity", "definition"] + }, + { + "type": "object", + "properties": { + "type": { "const": "relationship" }, + "subject": { "type": "string" }, + "predicate": { "type": "string" }, + "object": { "type": "string" }, + "object-entity": { "type": "boolean" } + }, + "required": ["type", "subject", "predicate", "object", "object-entity"] + } + ] + } +} +``` + +#### Extração de Ontologia + +Para extração baseada em ontologia com entidades, relacionamentos e atributos: + +**Formato de saída do prompt:** +``` +{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"} +{"type": "entity", "entity": "beef", "entity_type": "fo/Food"} +{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"} +{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"} +``` + +### Detalhes de Implementação + +#### Classe Prompt + +A classe `Prompt` existente não requer alterações. O campo `schema` é reutilizado +para JSONL, com sua interpretação determinada por `response_type`: + +```python +class Prompt: + def __init__(self, template, response_type="text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema # Interpretation depends on response_type +``` + +#### PromptManager.load_config + +Nenhuma alteração necessária - o carregamento da configuração existente já lida com a +`schema` chave. + +#### Análise de JSONL + +Adicionar um novo método de análise para respostas JSONL: + +```python +def parse_jsonl(self, text): + """ + Parse JSONL response, returning list of valid objects. + + Invalid lines (malformed JSON, empty lines) are skipped with warnings. + This provides truncation resilience - partial output yields partial results. + """ + results = [] + + for line_num, line in enumerate(text.strip().split('\n'), 1): + line = line.strip() + + # Skip empty lines + if not line: + continue + + # Skip markdown code fence markers if present + if line.startswith('```'): + continue + + try: + obj = json.loads(line) + results.append(obj) + except json.JSONDecodeError as e: + # Log warning but continue - this provides truncation resilience + logger.warning(f"JSONL parse error on line {line_num}: {e}") + + return results +``` + +#### Alterações no PromptManager.invoke + +Estenda o método invoke para lidar com o novo tipo de resposta: + +```python +async def invoke(self, id, input, llm): + logger.debug("Invoking prompt template...") + + terms = self.terms | self.prompts[id].terms | input + resp_type = self.prompts[id].response_type + + prompt = { + "system": self.system_template.render(terms), + "prompt": self.render(id, input) + } + + resp = await llm(**prompt) + + if resp_type == "text": + return resp + + if resp_type == "json": + try: + obj = self.parse_json(resp) + except: + logger.error(f"JSON parse failed: {resp}") + raise RuntimeError("JSON parse fail") + + if self.prompts[id].schema: + try: + validate(instance=obj, schema=self.prompts[id].schema) + logger.debug("Schema validation successful") + except Exception as e: + raise RuntimeError(f"Schema validation fail: {e}") + + return obj + + if resp_type == "jsonl": + objects = self.parse_jsonl(resp) + + if not objects: + logger.warning("JSONL parse returned no valid objects") + return [] + + # Validate each object against schema if provided + if self.prompts[id].schema: + validated = [] + for i, obj in enumerate(objects): + try: + validate(instance=obj, schema=self.prompts[id].schema) + validated.append(obj) + except Exception as e: + logger.warning(f"Object {i} failed schema validation: {e}") + return validated + + return objects + + raise RuntimeError(f"Response type {resp_type} not known") +``` + +### Prompts Afetados + +Os seguintes prompts devem ser migrados para o formato JSONL: + +| ID do Prompt | Descrição | Campo de Tipo | +|-----------|-------------|------------| +| `extract-definitions` | Extração de entidade/definição | Não (tipo único) | +| `extract-relationships` | Extração de relacionamento | Não (tipo único) | +| `extract-topics` | Extração de tópico/definição | Não (tipo único) | +| `extract-rows` | Extração de linha estruturada | Não (tipo único) | +| `agent-kg-extract` | Extração combinada de definição + relacionamento | Sim: `"definition"`, `"relationship"` | +| `extract-with-ontologies` / `ontology-extract` | Extração baseada em ontologia | Sim: `"entity"`, `"relationship"`, `"attribute"` | + +### Alterações na API + +#### Perspectiva do Cliente + +A análise JSONL é transparente para os chamadores da API do serviço de prompt. A análise ocorre +no lado do servidor no serviço de prompt, e a resposta é retornada através do campo padrão +`PromptResponse.object` como um array JSON serializado. + +Quando os clientes chamam o serviço de prompt (via `PromptClient.prompt()` ou similar): + +**`response-type: "json"`** com esquema de array → o cliente recebe `list` do Python +**`response-type: "jsonl"`** → o cliente recebe `list` do Python + +Da perspectiva do cliente, ambos retornam estruturas de dados idênticas. A +diferença está inteiramente em como a saída do LLM é analisada no lado do servidor: + +Formato de array JSON: Uma única chamada `json.loads()`; falha completamente se truncado +Formato JSONL: Análise linha por linha; produz resultados parciais se truncado + +Isso significa que o código do cliente existente que espera uma lista de prompts de extração +não requer alterações ao migrar prompts de JSON para JSONL. + +#### Valor de Retorno do Servidor + +Para `response-type: "jsonl"`, o método `PromptManager.invoke()` retorna um +`list[dict]` contendo todos os objetos analisados e validados com sucesso. Esta +lista é então serializada para JSON para o campo `PromptResponse.object`. + +#### Tratamento de Erros + +Resultados vazios: Retorna uma lista vazia `[]` com um log de aviso +Falha parcial na análise: Retorna uma lista de objetos analisados com sucesso com + logs de aviso para as falhas +Falha completa na análise: Retorna uma lista vazia `[]` com logs de aviso + +Isso difere de `response-type: "json"`, que lança `RuntimeError` em +caso de falha na análise. O comportamento tolerante para JSONL é intencional para fornecer +resiliência à truncagem. + +### Exemplo de Configuração + +Exemplo completo de configuração de prompt: + +```json +{ + "prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"\", \"definition\": \"\"}", + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "The entity name" + }, + "definition": { + "type": "string", + "description": "A clear definition of the entity" + } + }, + "required": ["entity", "definition"] + } +} +``` + +## Considerações de Segurança + +**Validação de Entrada**: A análise JSON utiliza o padrão `json.loads()`, que é seguro + contra ataques de injeção. +**Validação de Esquema**: Utiliza `jsonschema.validate()` para a aplicação do esquema. +**Sem Nova Superfície de Ataque**: A análise de JSONL é estritamente mais segura do que a análise de arrays JSON + devido ao processamento linha por linha. + +## Considerações de Desempenho + +**Memória**: A análise linha por linha usa menos memória máxima do que o carregamento de arrays JSON completos. + **Latência**: O desempenho da análise é comparável à análise de arrays JSON. +**Validação**: A validação de esquema é executada por objeto, o que adiciona sobrecarga, mas +permite resultados parciais em caso de falha na validação. + + +## Estratégia de Testes + +### Testes Unitários + +Análise de JSONL com entrada válida +Análise de JSONL com linhas vazias +Análise de JSONL com blocos de código Markdown +Análise de JSONL com linha final truncada +Análise de JSONL com linhas JSON inválidas intercaladas +Validação de esquema com uniões discriminadas `oneOf` +Compatibilidade com versões anteriores: prompts `"text"` e `"json"` existentes permanecem inalterados + +### Testes de Integração + +Extração ponta a ponta com prompts JSONL +Extração com truncamento simulado (resposta artificialmente limitada) +Extração de tipos mistos com discriminador de tipo +Extração de ontologia com todos os três tipos + +### Testes de Qualidade de Extração + +Compare os resultados da extração: formato JSONL versus array JSON. +Verifique a resiliência à truncagem: o JSONL produz resultados parciais onde o JSON falha. + +## Plano de Migração + +### Fase 1: Implementação + +1. Implemente o método `parse_jsonl()` em `PromptManager`. +2. Estenda `invoke()` para lidar com `response-type: "jsonl"`. +3. Adicione testes unitários. + +### Fase 2: Migração de Prompts + +1. Atualize o prompt e a configuração `extract-definitions`. +2. Atualize o prompt e a configuração `extract-relationships`. +3. Atualize o prompt e a configuração `extract-topics`. +4. Atualize o prompt e a configuração `extract-rows`. +5. Atualize o prompt e a configuração `agent-kg-extract`. +6. Atualize o prompt e a configuração `extract-with-ontologies`. + +### Fase 3: Atualizações para Sistemas Dependentes + +1. Atualize qualquer código que consuma os resultados da extração para lidar com o tipo de retorno de lista. +2. Atualize o código que categoriza extrações de tipos mistos pelo campo `type`. +3. Atualize os testes que afirmam o formato da saída da extração. + +## Perguntas Abertas + +Nenhuma neste momento. + +## Referências + +Implementação atual: `trustgraph-flow/trustgraph/template/prompt_manager.py` +Especificação JSON Lines: https://jsonlines.org/ +Esquema JSON `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof +Especificação relacionada: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`) diff --git a/docs/tech-specs/jsonl-prompt-output.ru.md b/docs/tech-specs/jsonl-prompt-output.ru.md index 48b0c0df..ee0ad0f8 100644 --- a/docs/tech-specs/jsonl-prompt-output.ru.md +++ b/docs/tech-specs/jsonl-prompt-output.ru.md @@ -1,114 +1,455 @@ -# Спецификация технической реализации JSONL для выходных данных запросов +# Техническая спецификация формата вывода JSONL для запросов ## Обзор -Эта спецификация описывает реализацию формата выходных данных JSONL (JSON Lines) для ответов на запросы в TrustGraph. JSONL позволяет надежно извлекать структурированные данные из ответов LLM, решая критические проблемы, связанные с повреждением выходных JSON-массивов при достижении LLM лимитов токенов. +Эта спецификация описывает реализацию формата вывода JSONL (JSON Lines) для ответов на запросы в TrustGraph. JSONL обеспечивает устойчивость к усечению при извлечении структурированных данных из ответов LLM, решая критические проблемы, связанные с повреждением выходных массивов JSON, когда ответы LLM достигают лимита токенов. + + + + Эта реализация поддерживает следующие сценарии использования: -1. **Надежное извлечение при обрезании**: Извлечение действительных частичных результатов даже при обрезании ответа LLM в середине запроса -2. **Масштабируемое извлечение**: Обработка извлечения множества элементов без риска полного сбоя из-за ограничений токенов -3. **Извлечение нескольких типов**: Поддержка извлечения нескольких типов сущностей (определения, взаимосвязи, сущности, атрибуты) в одном запросе -4. **Вывод, совместимый со стримингом**: Обеспечение возможности последующего стриминга/инкрементной обработки результатов извлечения +1. **Извлечение, устойчивое к усечению**: Извлекайте допустимые частичные результаты, даже когда + вывод LLM усекается в середине ответа. +2. **Извлечение в больших масштабах**: Обрабатывайте извлечение большого количества элементов без риска + полной сбоя из-за ограничений на количество токенов. +3. **Извлечение данных разных типов**: Поддерживайте извлечение нескольких типов сущностей + (определения, отношения, сущности, атрибуты) в одном запросе. +4. **Вывод, совместимый со стримингом**: Обеспечьте возможность будущей потоковой/инкрементной + обработки результатов извлечения. ## Цели -- **Совместимость с предыдущими версиями**: Существующие запросы, использующие `response-type: "text"` и `response-type: "json"`, продолжают работать без изменений -- **Надежное извлечение при обрезании**: Частичные ответы LLM дают частичные валидные результаты вместо полного сбоя -- **Валидация схемы**: Поддержка валидации JSON Schema для отдельных объектов -- **Гибкость**: Поддержка различных сценариев извлечения, включая извлечение нескольких типов сущностей и использование стриминга +**Обратная совместимость**: Существующие запросы, использующие `response-type: "text"` и + `response-type: "json"`, продолжают работать без изменений. +**Устойчивость к усечению**: Частичные выходные данные LLM приводят к частичным, но допустимым результатам, + а не к полному сбою. +**Проверка схемы**: Поддержка проверки JSON-схемы для отдельных объектов. +**Дискриминированные объединения**: Поддержка выходных данных смешанных типов с использованием поля `type` + в качестве дискриминатора. +**Минимальные изменения API**: Расширение существующей конфигурации запросов с добавлением нового + типа ответа и ключа схемы. -## Реализация +## Обзор -* **Обработка JSONL**: Метод `parse_jsonl` парсит входные данные JSONL построчно, обрабатывая ошибки при обнаружении невалидного JSON. Он возвращает список словарей, где каждый словарь представляет собой успешно обработанный объект. -* **Обработка JSON**: Метод `parse_json` парсит входные данные JSON, используя стандартную библиотеку `json`. Он возвращает объект Python, соответствующий структуре JSON. -* **Валидация схемы**: Функция `validate` проверяет, соответствует ли объект заданным требованиям JSON Schema. -* **Формат вывода**: Метод `PromptManager.invoke` возвращает список словарей Python, где каждый словарь представляет собой успешно обработанный объект. -* **Обработка ошибок**: - * Если входные данные JSONL не валидны или результат обрезания, метод возвращает пустой список (`[]`). - * Если при валидации схемы произошла ошибка, метод возвращает пустой список (`[]`) и выводит предупреждающие сообщения в лог. - * Если произошла ошибка парсинга JSON, метод выводит ошибку и выбрасывает исключение. -* **Совместимость**: - * Клиентский код, ожидающий список в качестве результата извлечения, не требует изменений при переходе на JSONL. - * Формат вывода для `response-type: "json"` (массив) и `response-type: "jsonl"` (список) одинаковый: Python `list` -* **API изменения**: - * **Клиентская перспектива**: Разбор JSONL выполняется на стороне сервера в сервисе запросов, и результат возвращается через стандартное поле `PromptResponse.object` в виде сериализованного JSON-массива. - * **Формат возвращаемого значения**: Для `response-type: "jsonl"`, метод `PromptManager.invoke()` возвращает `list[dict]`, содержащий все успешно обработанные объекты. Этот список сериализуется в JSON для поля `PromptResponse.object`. - * **Обработка ошибок**: - * Пустой результат: возвращает пустой список `[]` с сообщением в логе - * Частичная ошибка парсинга: возвращает список успешно обработанных объектов с сообщениями об ошибках - * Полная ошибка парсинга: возвращает пустой список `[]` с сообщениями об ошибках -* **Пример конфигурации**: +### Текущая архитектура - ```json - { - "prompt": "Извлеките все сущности и их определения из следующего текста. Выведите один JSON объект на строку.\n\nТекст:\n{{text}}\n\nФормат вывода на строку:\n{\"entity\": \"\", \"definition\": \"\"}", - "response-type": "jsonl", - "schema": { +Сервис запросов поддерживает два типа ответов: + +1. `response-type: "text"` - Необработанный текстовый ответ, возвращаемый как есть. +2. `response-type: "json"` - JSON, полученный из ответа и проверенный на соответствие + необязательной `schema`. + +Текущая реализация в `trustgraph-flow/trustgraph/template/prompt_manager.py`: + +```python +class Prompt: + def __init__(self, template, response_type = "text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema +``` + +### Текущие ограничения + +Когда запросы извлечения требуют вывод в виде массивов JSON (`[{...}, {...}, ...]`): + +**Повреждение из-за усечения**: Если языковая модель достигает лимита выходных токенов в середине массива, + весь ответ становится недействительным JSON и не может быть проанализирован. +**Анализ "все или ничего"**: Необходимо получить полный вывод перед анализом. +**Нет частичных результатов**: Усеченный ответ дает нулевые полезные данные. +**Ненадежно для больших извлечений**: Чем больше извлеченных элементов, тем выше риск сбоя. + +Данная спецификация решает эти ограничения, вводя формат JSONL для +запросов извлечения, где каждый извлеченный элемент является полным JSON-объектом на своей +строке. + +## Техническое проектирование + +### Расширение типа ответа + +Добавьте новый тип ответа `"jsonl"` наряду с существующими типами `"text"` и `"json"`. + +#### Изменения конфигурации + +**Новое значение типа ответа:** + +``` +"response-type": "jsonl" +``` + +**Интерпретация схемы:** + +Существующий ключ `"schema"` используется как для `"json"`, так и для `"jsonl"` типов ответов. +Интерпретация зависит от типа ответа: + +`"json"`: Схема описывает весь ответ (обычно массив или объект). +`"jsonl"`: Схема описывает каждую отдельную строку/объект. + +```json +{ + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["entity", "definition"] + } +} +``` + +Это позволяет избежать изменений в инструментах и редакторах конфигурации подсказок. + +### Спецификация формата JSONL + +#### Простое извлечение + +Для подсказок, извлекающих один тип объекта (определения, отношения, +темы, строки), вывод представляет собой один объект JSON на строку без обертки: + +**Формат вывода подсказки:** +``` +{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"} +{"entity": "chlorophyll", "definition": "Green pigment in plants"} +{"entity": "mitochondria", "definition": "Powerhouse of the cell"} +``` + +**Контраст с предыдущим форматом JSON-массива:** +```json +[ + {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, + {"entity": "chlorophyll", "definition": "Green pigment in plants"}, + {"entity": "mitochondria", "definition": "Powerhouse of the cell"} +] +``` + +Если LLM обрезает текст после строки 2, формат массива JSON приводит к недействительному JSON, +в то время как JSONL дает два допустимых объекта. + +#### Извлечение данных смешанных типов (дискриминированные объединения) + +Для запросов, извлекающих несколько типов объектов (например, определения и +отношения, или сущности, отношения и атрибуты), используйте поле `"type"` +в качестве дискриминатора: + +**Формат вывода запроса:** +``` +{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"} +{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true} +{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"} +{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true} +``` + +**Схема для дискриминированных объединений использует `oneOf`:** +```json +{ + "response-type": "jsonl", + "schema": { + "oneOf": [ + { "type": "object", "properties": { - "entity": { - "type": "string", - "description": "Имя сущности" - }, - "definition": { - "type": "string", - "description": "Четкое определение сущности" - } + "type": { "const": "definition" }, + "entity": { "type": "string" }, + "definition": { "type": "string" } }, - "required": ["entity", "definition"] + "required": ["type", "entity", "definition"] + }, + { + "type": "object", + "properties": { + "type": { "const": "relationship" }, + "subject": { "type": "string" }, + "predicate": { "type": "string" }, + "object": { "type": "string" }, + "object-entity": { "type": "boolean" } + }, + "required": ["type", "subject", "predicate", "object", "object-entity"] } + ] + } +} +``` + +#### Извлечение онтологии + +Для извлечения онтологии на основе сущностей, связей и атрибутов: + +**Формат вывода запроса:** +``` +{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"} +{"type": "entity", "entity": "beef", "entity_type": "fo/Food"} +{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"} +{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"} +``` + +### Детали реализации + +#### Класс Prompt + +Существующий класс `Prompt` не требует изменений. Поле `schema` используется повторно +для JSONL, а его интерпретация определяется `response_type`: + +```python +class Prompt: + def __init__(self, template, response_type="text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema # Interpretation depends on response_type +``` + +#### PromptManager.load_config + +Изменения не требуются - существующая загрузка конфигурации уже обрабатывает +ключ `schema`. + +#### Разбор JSONL + +Добавлен новый метод разбора ответов в формате JSONL: + +```python +def parse_jsonl(self, text): + """ + Parse JSONL response, returning list of valid objects. + + Invalid lines (malformed JSON, empty lines) are skipped with warnings. + This provides truncation resilience - partial output yields partial results. + """ + results = [] + + for line_num, line in enumerate(text.strip().split('\n'), 1): + line = line.strip() + + # Skip empty lines + if not line: + continue + + # Skip markdown code fence markers if present + if line.startswith('```'): + continue + + try: + obj = json.loads(line) + results.append(obj) + except json.JSONDecodeError as e: + # Log warning but continue - this provides truncation resilience + logger.warning(f"JSONL parse error on line {line_num}: {e}") + + return results +``` + +#### Изменения в PromptManager.invoke + +Расширить метод invoke для обработки нового типа ответа: + +```python +async def invoke(self, id, input, llm): + logger.debug("Invoking prompt template...") + + terms = self.terms | self.prompts[id].terms | input + resp_type = self.prompts[id].response_type + + prompt = { + "system": self.system_template.render(terms), + "prompt": self.render(id, input) } - ``` -* **Изменения в запросах**: -| ID запроса | Описание | Поле типа | -|---|---|---| -| `extract-definitions` | Извлечение всех сущностей и их определений из следующего текста. Выведите один JSON объект на строку. | Нет (один тип) | -| `extract-relationships` | Извлечение взаимосвязей | Нет (один тип) | -| `extract-topics` | Извлечение темы и определений | Нет (один тип) | + resp = await llm(**prompt) + + if resp_type == "text": + return resp + + if resp_type == "json": + try: + obj = self.parse_json(resp) + except: + logger.error(f"JSON parse failed: {resp}") + raise RuntimeError("JSON parse fail") + + if self.prompts[id].schema: + try: + validate(instance=obj, schema=self.prompts[id].schema) + logger.debug("Schema validation successful") + except Exception as e: + raise RuntimeError(f"Schema validation fail: {e}") + + return obj + + if resp_type == "jsonl": + objects = self.parse_jsonl(resp) + + if not objects: + logger.warning("JSONL parse returned no valid objects") + return [] + + # Validate each object against schema if provided + if self.prompts[id].schema: + validated = [] + for i, obj in enumerate(objects): + try: + validate(instance=obj, schema=self.prompts[id].schema) + validated.append(obj) + except Exception as e: + logger.warning(f"Object {i} failed schema validation: {e}") + return validated + + return objects + + raise RuntimeError(f"Response type {resp_type} not known") +``` + +### Затронутые запросы + +Следующие запросы должны быть перенесены в формат JSONL: + +| Идентификатор запроса | Описание | Тип поля | +|-----------|-------------|------------| +| `extract-definitions` | Извлечение сущностей/определений | Нет (один тип) | +| `extract-relationships` | Извлечение отношений | Нет (один тип) | +| `extract-topics` | Извлечение темы/определения | Нет (один тип) | | `extract-rows` | Извлечение структурированных строк | Нет (один тип) | -| `agent-kg-extract` | Совместное извлечение определения и взаимосвязи | Да: `"definition"`, `"relationship"` | -| `extract-with-ontologies` / `ontology-extract` | Извлечение на основе онтологий | Да: `"entity"`, `"relationship"`, `"attribute"` | +| `agent-kg-extract` | Комбинированное извлечение определений + отношений | Да: `"definition"`, `"relationship"` | +| `extract-with-ontologies` / `ontology-extract` | Извлечение на основе онтологии | Да: `"entity"`, `"relationship"`, `"attribute"` | -## Безопасность +### Изменения API -* **Валидация входных данных**: Используется стандартная библиотека `json.loads()` для парсинга, что безопасно от возможных атак внедрением. -* **Валидация схемы**: Используется `jsonschema.validate()` для проверки соответствия схемы. -* **Отсутствие новых уязвимостей**: Разбор JSONL безопаснее, чем разбор JSON-массивов, из-за построчной обработки. +#### Точка зрения клиента -## Производительность +Разбор JSONL прозрачен для вызывающих API сервиса запросов. Разбор происходит +на стороне сервера в сервисе запросов, и ответ возвращается через стандартное +поле `PromptResponse.object` в виде сериализованного массива JSON. -* **Память**: Построчный разбор требует меньше памяти, чем загрузка всего JSON-массива. -* **Задержка**: Производительность парсинга сопоставима с разбором JSON-массивов. -* **Валидация**: Валидация объекта происходит для каждого объекта, что может привести к накладным расходам, но обеспечивает частичную валидацию при ошибках. +Когда клиенты вызывают сервис запросов (через `PromptClient.prompt()` или аналогично): + +**`response-type: "json"`** с схемой массива → клиент получает Python `list` +**`response-type: "jsonl"`** → клиент получает Python `list` + +С точки зрения клиента, оба возвращают идентичные структуры данных. Разница заключается только в том, как вывод LLM разбирается на стороне сервера: + + +Формат массива JSON: Один вызов `json.loads()`; полностью завершается с ошибкой, если усечен +Формат JSONL: Разбор построчно; дает частичные результаты, если усечен + +Это означает, что существующий клиентский код, ожидающий список от запросов извлечения, +не требует изменений при переносе запросов из формата JSON в формат JSONL. + +#### Возвращаемое значение сервера + +Для `response-type: "jsonl"` метод `PromptManager.invoke()` возвращает +`list[dict]`, содержащий все успешно разобранные и проверенные объекты. Этот +список затем сериализуется в JSON для поля `PromptResponse.object`. + +### Обработка ошибок + +Пустые результаты: Возвращает пустой список `[]` с предупреждением в журнале +Частная ошибка разбора: Возвращает список успешно разобранных объектов с + предупреждениями в журналах об ошибках +Полная ошибка разбора: Возвращает пустой список `[]` с предупреждениями в журналах + +Это отличается от `response-type: "json"`, который вызывает `RuntimeError` при +ошибке разбора. Легкое поведение для JSONL намеренно, чтобы обеспечить +устойчивость к усечению. + +### Пример конфигурации + +Полный пример конфигурации запроса: + +```json +{ + "prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"\", \"definition\": \"\"}", + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "The entity name" + }, + "definition": { + "type": "string", + "description": "A clear definition of the entity" + } + }, + "required": ["entity", "definition"] + } +} +``` + +## Соображения безопасности + +**Проверка входных данных**: Разбор JSON использует стандартную `json.loads()`, что безопасно + от атак внедрения. +**Проверка схемы**: Используется `jsonschema.validate()` для обеспечения соответствия схеме. +**Отсутствие новых уязвимостей**: Разбор JSONL значительно безопаснее, чем разбор JSON-массивов, + благодаря обработке построчно. + +## Соображения производительности + +**Память**: Построчный разбор использует меньше пиковой памяти, чем загрузка полных + JSON-массивов. +**Задержка**: Производительность разбора сопоставима с разбором JSON-массивов. +**Проверка**: Проверка схемы выполняется для каждого объекта, что добавляет накладные + расходы, но позволяет получать частичные результаты в случае сбоя проверки. ## Стратегия тестирования -* **Юнит-тесты**: - * Разбор JSONL с валидными данными - * Разбор JSONL с пустыми строками - * Разбор JSONL с маркерами markdown - * Разбор JSONL с обрезаными последними строками - * Разбор JSONL с невалидным JSON - * Валидация схемы с использованием `oneOf` - * Совместимость: существующие запросы `"text"` и `"json"` не изменяются -* **Интеграционные тесты**: - * Извлечение с JSONL-запросами - * Симулированное обрезание ответа LLM (искусственно ограниченный ответ) - * Извлечение нескольких типов сущностей с использованием поля типа - * Извлечение на основе онтологий -* **Тесты качества извлечения**: - * Сравнение результатов извлечения: JSONL vs JSON - * Проверка на надежное извлечение при обрезании: JSONL дает частичные результаты, где JSON не работает +### Юнит-тесты -## Вопросы +Разбор JSONL с допустимыми входными данными. +Разбор JSONL с пустыми строками. +Разбор JSONL с блоками форматированного текста Markdown. +Разбор JSONL с обрезанной последней строкой. +Разбор JSONL со строками, содержащими недопустимый JSON. +Проверка схемы с использованием `oneOf` для дискриминируемых объединений. +Обратная совместимость: существующие `"text"` и `"json"` подсказки не изменены. -В настоящее время вопросов нет. +### Интеграционные тесты + +Комплексная извлечение данных с использованием подсказок JSONL. +Извлечение данных с имитацией усечения (искусственно ограниченный ответ). +Извлечение данных смешанных типов с использованием дискриминатора типов. +Извлечение данных онтологии со всеми тремя типами. + +### Тесты качества извлечения данных. + +Сравнение результатов извлечения: формат JSONL против массива JSON. +Проверка устойчивости к усечению: JSONL возвращает частичные результаты, в то время как JSON - нет. + +## План миграции + +### Этап 1: Реализация + +1. Реализовать метод `parse_jsonl()` в `PromptManager`. +2. Расширить `invoke()` для обработки `response-type: "jsonl"`. +3. Добавить модульные тесты. + +### Этап 2: Миграция подсказок + +1. Обновить подсказку `extract-definitions` и конфигурацию. +2. Обновить подсказку `extract-relationships` и конфигурацию. +3. Обновить подсказку `extract-topics` и конфигурацию. +4. Обновить подсказку `extract-rows` и конфигурацию. +5. Обновить подсказку `agent-kg-extract` и конфигурацию. +6. Обновить подсказку `extract-with-ontologies` и конфигурацию. + +### Этап 3: Обновления для последующих этапов + +1. Обновить любой код, использующий результаты извлечения, чтобы он мог обрабатывать возвращаемый тип списка. +2. Обновить код, который категоризует извлечения смешанных типов, используя поле `type`. +3. Обновить тесты, которые проверяют формат выходных данных извлечения. + +## Открытые вопросы + +На данный момент нет. ## Ссылки -* Реализация: `trustgraph-flow/trustgraph/template/prompt_manager.py` -* Спецификация JSON Lines: https://jsonlines.org/ -* Спецификация JSON Schema `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof -* Связанная спецификация: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file +Текущая реализация: `trustgraph-flow/trustgraph/template/prompt_manager.py` +Спецификация JSON Lines: https://jsonlines.org/ +Схема JSON `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof +Связанная спецификация: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`) diff --git a/docs/tech-specs/jsonl-prompt-output.tr.md b/docs/tech-specs/jsonl-prompt-output.tr.md new file mode 100644 index 00000000..92eef3a0 --- /dev/null +++ b/docs/tech-specs/jsonl-prompt-output.tr.md @@ -0,0 +1,455 @@ +# JSONL İstek Çıktısı Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph'ta istek yanıtları için JSONL (JSON Lines) çıktı biçiminin uygulanmasını tanımlar. JSONL, LLM yanıtlarından yapılandırılmış verilerin, LLM yanıtları çıktı belirteç sınırlarına ulaştığında JSON dizisi çıktıları bozulduğunda ortaya çıkan kritik sorunları ele alarak, kesme hatalarına karşı dayanıklı bir şekilde çıkarılmasını sağlar. + + + + + +Bu uygulama, aşağıdaki kullanım senaryolarını destekler: + +1. **Kesintiye Dayanıklı Çıkarma**: LLM çıktısı yanıtın ortasında kesildiğinde bile geçerli kısmi sonuçları çıkarın. + +2. **Büyük Ölçekli Çıkarma**: Token limitleri nedeniyle tam bir başarısızlık riski olmadan birçok öğenin çıkarılmasını işleyin. + +3. **Karma Tip Çıkarma**: Tek bir istemde birden fazla varlık türünün (tanımlar, ilişkiler, varlıklar, özellikler) çıkarılmasını destekleyin. + +4. **Akışla Uyumlu Çıktı**: Çıkarma sonuçlarının gelecekteki akış/artımlı + işlenmesini sağlayın. + +## Hedefler + +**Geriye Dönük Uyumluluk**: `response-type: "text"` kullanan mevcut istemler ve + `response-type: "json"`, herhangi bir değişiklik yapılmadan çalışmaya devam eder. +**Kesinti Dayanıklılığı**: Kısmi LLM çıktıları, tam bir başarısızlık yerine kısmi, geçerli sonuçlar üretir. + +**Şema Doğrulama**: Bireysel nesneler için JSON şema doğrulamasını destekler. +**Ayırıcı Birleşimler**: `type` alanını kullanarak karma türlü çıktıları destekler. + +**Minimum API Değişiklikleri**: Mevcut istem yapılandırmasını, yeni + yanıt türü ve şema anahtarıyla genişletir. + +## Arka Plan + +### Mevcut Mimari + +İstek hizmeti, iki tür yanıtı destekler: + +1. `response-type: "text"` - Ham metin yanıtı, olduğu gibi döndürülür. +2. `response-type: "json"` - Yanıttan ayrıştırılan JSON, isteğe bağlı `response-type: "json"`'a göre doğrulanır. + isteğe bağlı `schema` + +`trustgraph-flow/trustgraph/template/prompt_manager.py`'daki mevcut uygulama: + +```python +class Prompt: + def __init__(self, template, response_type = "text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema +``` + +### Mevcut Sınırlamalar + +Çıkarma komutları, çıktıyı JSON dizileri (`[{...}, {...}, ...]`) olarak istediğinde: + +**Kesme nedeniyle oluşan bozulma**: Eğer LLM, dizi ortasında çıktı belirteç sınırlarına ulaştığında, + tüm yanıt geçersiz bir JSON haline gelir ve işlenemez. +**Tümünü veya hiçbirini işleme**: İşlemeye başlamadan önce tam çıktıyı almanız gerekir. +**Kısmi sonuçlar yok**: Kesilmiş bir yanıt, kullanılabilir veri olarak sıfır veri verir. +**Büyük çıkarmalar için güvenilir değil**: Çıkarılan öğe sayısı arttıkça, başarısızlık riski daha yüksektir. + +Bu özellik, her çıkarılan öğenin kendi satırında bulunan tam bir JSON nesnesi olduğu JSONL formatını kullanarak, bu sınırlamaları ele alır. + + + +## Teknik Tasarım + +### Yanıt Tipi Genişletmesi + +Mevcut `"text"` ve `"json"` türlerinin yanı sıra yeni bir yanıt türü `"jsonl"` ekleyin. + + +#### Yapılandırma Değişiklikleri + + +``` +"response-type": "jsonl" +``` + +**Şema yorumlaması:** + +Mevcut `"schema"` anahtarı, hem `"json"` hem de `"jsonl"` yanıtları için kullanılmaktadır. +Yorumlama, yanıt türüne bağlıdır: + +`"json"`: Şema, tüm yanıtı (genellikle bir dizi veya nesne) tanımlar. +`"jsonl"`: Şema, her bir satırı/nesneyi ayrı ayrı tanımlar. + +```json +{ + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["entity", "definition"] + } +} +``` + +Bu, istem yapılandırma araçlarına ve düzenleyicilere yapılan değişiklikleri önler. + +### JSONL Biçim Özellikleri + +#### Basit Çıkarma + +Tek bir nesne türünü (tanımlar, ilişkiler, +konular, satırlar) çıkaran istemler için, çıktı her satırda bir JSON nesnesidir ve herhangi bir sarma bulunmaz: + +**İstem çıktı biçimi:** +``` +{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"} +{"entity": "chlorophyll", "definition": "Green pigment in plants"} +{"entity": "mitochondria", "definition": "Powerhouse of the cell"} +``` + +**Önceki JSON dizi formatıyla karşılaştırma:** +```json +[ + {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, + {"entity": "chlorophyll", "definition": "Green pigment in plants"}, + {"entity": "mitochondria", "definition": "Powerhouse of the cell"} +] +``` + +Eğer LLM, 2. satırdan sonra kesilirse, JSON dizisi formatı geçersiz bir JSON oluşturur, +ancak JSONL iki geçerli nesne üretir. + +#### Karışık Tip Çıkarımı (Ayırıcı Birleşimler) + +Birden fazla nesne türünü çıkaran (örneğin, hem tanımları hem de +ilişkileri, veya varlıklar, ilişkiler ve özellikler) istemler için, bir `"type"` +alanını ayırıcı olarak kullanın: + +**İstem çıktısı formatı:** +``` +{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"} +{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true} +{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"} +{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true} +``` + +**Ayırıcı birleşimler için şema, `oneOf` kullanır:** +```json +{ + "response-type": "jsonl", + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { "const": "definition" }, + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["type", "entity", "definition"] + }, + { + "type": "object", + "properties": { + "type": { "const": "relationship" }, + "subject": { "type": "string" }, + "predicate": { "type": "string" }, + "object": { "type": "string" }, + "object-entity": { "type": "boolean" } + }, + "required": ["type", "subject", "predicate", "object", "object-entity"] + } + ] + } +} +``` + +#### Ontoloji Çıkarımı + +Varlıklar, ilişkiler ve özelliklerle ontoloji tabanlı çıkarım için: + +**İstenen çıktı formatı:** +``` +{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"} +{"type": "entity", "entity": "beef", "entity_type": "fo/Food"} +{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"} +{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"} +``` + +### Uygulama Detayları + +#### İstek Sınıfı + +Mevcut `Prompt` sınıfı herhangi bir değişiklik gerektirmiyor. `schema` alanı yeniden kullanılıyor. +JSONL formatı için, yorumlanması `response_type` ile belirlenir: + +```python +class Prompt: + def __init__(self, template, response_type="text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema # Interpretation depends on response_type +``` + +#### PromptManager.load_config + +Herhangi bir değişiklik gerekli değil - mevcut yapılandırma yüklemesi zaten +`schema` anahtarını işlemektedir. + +#### JSONL Ayrıştırma + +JSONL yanıtları için yeni bir ayrıştırma yöntemi ekleyin: + +```python +def parse_jsonl(self, text): + """ + Parse JSONL response, returning list of valid objects. + + Invalid lines (malformed JSON, empty lines) are skipped with warnings. + This provides truncation resilience - partial output yields partial results. + """ + results = [] + + for line_num, line in enumerate(text.strip().split('\n'), 1): + line = line.strip() + + # Skip empty lines + if not line: + continue + + # Skip markdown code fence markers if present + if line.startswith('```'): + continue + + try: + obj = json.loads(line) + results.append(obj) + except json.JSONDecodeError as e: + # Log warning but continue - this provides truncation resilience + logger.warning(f"JSONL parse error on line {line_num}: {e}") + + return results +``` + +#### PromptManager.invoke Değişiklikleri + +Yeni yanıt türünü işleyebilmek için invoke yöntemini genişletin: + +```python +async def invoke(self, id, input, llm): + logger.debug("Invoking prompt template...") + + terms = self.terms | self.prompts[id].terms | input + resp_type = self.prompts[id].response_type + + prompt = { + "system": self.system_template.render(terms), + "prompt": self.render(id, input) + } + + resp = await llm(**prompt) + + if resp_type == "text": + return resp + + if resp_type == "json": + try: + obj = self.parse_json(resp) + except: + logger.error(f"JSON parse failed: {resp}") + raise RuntimeError("JSON parse fail") + + if self.prompts[id].schema: + try: + validate(instance=obj, schema=self.prompts[id].schema) + logger.debug("Schema validation successful") + except Exception as e: + raise RuntimeError(f"Schema validation fail: {e}") + + return obj + + if resp_type == "jsonl": + objects = self.parse_jsonl(resp) + + if not objects: + logger.warning("JSONL parse returned no valid objects") + return [] + + # Validate each object against schema if provided + if self.prompts[id].schema: + validated = [] + for i, obj in enumerate(objects): + try: + validate(instance=obj, schema=self.prompts[id].schema) + validated.append(obj) + except Exception as e: + logger.warning(f"Object {i} failed schema validation: {e}") + return validated + + return objects + + raise RuntimeError(f"Response type {resp_type} not known") +``` + +### Etkilenen İstekler + +Aşağıdaki istekler JSONL formatına aktarılmalıdır: + +| İstek Kimliği | Açıklama | Tür Alanı | +|-----------|-------------|------------| +| `extract-definitions` | Varlık/tanım çıkarma | Hayır (tek tür) | +| `extract-relationships` | İlişki çıkarma | Hayır (tek tür) | +| `extract-topics` | Konu/tanım çıkarma | Hayır (tek tür) | +| `extract-rows` | Yapılandırılmış satır çıkarma | Hayır (tek tür) | +| `agent-kg-extract` | Birleştirilmiş tanım + ilişki çıkarma | Evet: `"definition"`, `"relationship"` | +| `extract-with-ontologies` / `ontology-extract` | Ontoloji tabanlı çıkarma | Evet: `"entity"`, `"relationship"`, `"attribute"` | + +### API Değişiklikleri + +#### Müşteri Perspektifi + +JSONL ayrıştırması, istem hizmeti API'sini kullananlar için şeffaftır. Ayrıştırma, istem hizmetinde sunucu tarafında gerçekleşir ve yanıt standart +bir şekilde döndürülür. +`PromptResponse.object` alanını seri hale edilmiş bir JSON dizisi olarak. + +Müşteriler, istem hizmetini (`PromptClient.prompt()` veya benzeri bir yöntemle) kullandığında: + +**`response-type: "json"`** (dizi şeması ile) → müşteri, Python `list` alır. +**`response-type: "jsonl"`** → müşteri, Python `list` alır. + +Müşterinin bakış açısıyla, her iki yöntem de aynı veri yapılarını döndürür. +Fark, tamamen LLM çıktısının sunucu tarafında nasıl işlendiğindedir: + +JSON dizisi formatı: Tek `json.loads()` çağrısı; kısaltılırsa tamamen başarısız olur. +JSONL formatı: Satır satır ayrıştırma; kısaltılırsa kısmi sonuçlar verir. + +Bu, çıkarma istemlerinden bir liste bekleyen mevcut istemci kodunun, istemleri JSON'dan JSONL formatına geçirirken herhangi bir değişikliğe ihtiyaç duymamasını sağlar. + + +#### Sunucu Dönüş Değeri + +`response-type: "jsonl"` için, `PromptManager.invoke()` metodu, +başarıyla ayrıştırılmış ve doğrulanmış tüm nesneleri içeren bir `list[dict]` döndürür. Bu +liste, daha sonra `PromptResponse.object` alanı için JSON'a dönüştürülür. + +#### Hata Yönetimi + +Boş sonuçlar: Uyarı günlüğü ile boş bir liste `[]` döndürür. +Kısmi ayrıştırma hatası: Başarıyla ayrıştırılmış nesnelerin bir listesini ve + hatalar için uyarı günlüklerini döndürür. +Tam ayrıştırma hatası: Uyarı günlükleriyle boş bir liste `[]` döndürür. + +Bu, `response-type: "json"`'den farklıdır, çünkü `RuntimeError` ayrıştırma hatası durumunda `RuntimeError` hatası oluşturur. +JSONL için daha hoşgörülü davranış, kesintilere karşı dayanıklılık sağlamak amacıyla kasıtlıdır. + + +### Yapılandırma Örneği + +Tam istem yapılandırma örneği: + +```json +{ + "prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"\", \"definition\": \"\"}", + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "The entity name" + }, + "definition": { + "type": "string", + "description": "A clear definition of the entity" + } + }, + "required": ["entity", "definition"] + } +} +``` + +## Güvenlik Hususları + +**Girdi Doğrulama**: JSON ayrıştırması, standart `json.loads()`'ı kullanır ve bu, enjeksiyon saldırılarına karşı güvenlidir. + **Şema Doğrulama**: Şema zorlaması için ⟦CODE_0⟧ kullanılır. +**Şema Doğrulama**: Şema uyumluluğunu sağlamak için `jsonschema.validate()` kullanılır. +**Yeni Bir Saldırı Yüzeyi Yok**: JSONL ayrıştırması, satır satır işlenmesi nedeniyle JSON dizisi ayrıştırmasından çok daha güvenlidir. + + +## Performans Hususları + +**Bellek**: Satır satır ayrıştırma, tam JSON dizilerini yüklemekten daha az bellek kullanır. + **Gecikme**: Ayrıştırma performansı, JSON dizisi ayrıştırmasıyla karşılaştırılabilir. +**Doğrulama**: Şema doğrulaması, her bir nesne için yapılır, bu da ek yük getirir ancak +doğrulama başarısız olduğunda kısmi sonuçlar elde etmeyi sağlar. + +## Test Stratejisi + + +### Birim Testleri + +Geçerli giriş ile JSONL ayrıştırma +Boş satırlarla JSONL ayrıştırma +Markdown kod bloklarıyla JSONL ayrıştırma +Kesilmiş son satırla JSONL ayrıştırma +Geçersiz JSON satırlarının arasına serpiştirilmiş JSONL ayrıştırma +`oneOf` ayrımcı birleşimlerle şema doğrulaması +Geriye dönük uyumluluk: Mevcut `"text"` ve `"json"` istemleri değişmeden kalır + +### Entegrasyon Testleri + +JSONL istemleriyle uçtan uca çıkarma +Simüle edilmiş kesme ile çıkarma (yapay olarak sınırlı yanıt) +Tür ayrımcısı ile karma tür çıkarma +Üç türün tamamıyla ontoloji çıkarma + +### Çıkarma Kalitesi Testleri + +Çıkarma sonuçlarını karşılaştırın: JSONL ile JSON dizisi formatı +Kesme dayanıklılığını doğrulayın: JSONL, JSON'un başarısız olduğu durumlarda kısmi sonuçlar verir + +## Geçiş Planı + +### 1. Aşama: Uygulama + +1. `parse_jsonl()` yöntemini `PromptManager` içinde uygulayın +2. `invoke()`'ı `response-type: "jsonl"`'i işleyebilecek şekilde genişletin +3. Birim testleri ekleyin + +### 2. Aşama: İstek Geçişi + +1. `extract-definitions` isteğini ve yapılandırmasını güncelleyin +2. `extract-relationships` isteğini ve yapılandırmasını güncelleyin +3. `extract-topics` isteğini ve yapılandırmasını güncelleyin +4. `extract-rows` isteğini ve yapılandırmasını güncelleyin +5. `agent-kg-extract` isteğini ve yapılandırmasını güncelleyin +6. `extract-with-ontologies` isteğini ve yapılandırmasını güncelleyin + +### 3. Aşama: Aşağı Akış Güncellemeleri + +1. Çıkarma sonuçlarını kullanan tüm kodu, liste dönüş türünü işleyebilecek şekilde güncelleyin +2. `type` alanına göre karma türdeki çıkarma sonuçlarını kategorize eden kodu güncelleyin +3. Çıkarma çıktısı formatı hakkında doğrulama yapan testleri güncelleyin + +## Açık Sorular + +Şu anda yok. + +## Referanslar + +Mevcut uygulama: `trustgraph-flow/trustgraph/template/prompt_manager.py` +JSON Lines belirtimi: https://jsonlines.org/ +JSON Şeması `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof +İlgili belirtim: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`) diff --git a/docs/tech-specs/jsonl-prompt-output.zh-cn.md b/docs/tech-specs/jsonl-prompt-output.zh-cn.md index 2e8e5b6f..14d86082 100644 --- a/docs/tech-specs/jsonl-prompt-output.zh-cn.md +++ b/docs/tech-specs/jsonl-prompt-output.zh-cn.md @@ -1,23 +1,35 @@ -## JSONL 提示输出技术规范 +# JSONL 提示输出技术规范 ## 概述 -本规范描述了在 TrustGraph 中实现 JSONL (JSON Lines) 输出格式的提示响应。JSONL 允许以容错的方式从 LLM 响应中提取结构化数据,从而解决了 JSON 数组输出在 LLM 响应达到输出令牌限制时发生损坏的问题。 +本规范描述了在 TrustGraph 中,用于提示响应的 JSONL(JSON Lines)输出格式的实现。JSONL 允许在大型语言模型(LLM)的响应中,以一种能够抵抗截断的方式提取结构化数据,从而解决了当 LLM 响应达到输出令牌限制时,JSON 数组输出可能被损坏的关键问题。 -此实现支持以下用例: -1. **容错提取**: 即使 LLM 输出被截断,仍可提取有效的部分结果 -2. **大规模提取**: 能够在不因令牌限制而完全失败的情况下,处理大量项的提取 -3. **混合类型提取**: 支持在单个提示中提取多种实体类型(定义、关系、实体、属性) -4. **流兼容输出**: 启用提取结果的未来流式/增量处理 + + + +本实现支持以下用例: + +1. **抗截断提取**: 即使当 + LLM 输出在响应过程中被截断时,也能提取有效的中间结果。 +2. **大规模提取**: 能够处理大量项的提取,而不会因 token 限制导致完全失败的风险。 + 3. **混合类型提取**: 支持在单个提示中提取多种实体类型(定义、关系、实体、属性)。 +4. **支持流式输出**: 允许对提取结果进行未来的流式/增量处理。 + +## 目标 + ## 目标 -- **向后兼容性**: 使用 `response-type: "text"` 和 `response-type: "json"` 的现有提示无需修改即可继续工作 -- **容错提取**: 部分 LLM 输出产生部分有效的结果,而不是完全失败 -- **模式验证**: 支持对单个对象进行 JSON 模式验证 -- **区分联合**: 使用 `type` 字段作为区分器,支持混合类型输出 -- **最小的 API 更改**: 通过添加新的响应类型和模式键来扩展现有提示配置 +**向后兼容性**: 仍然可以使用 `response-type: "text"` 和 + `response-type: "json"` 的现有提示,无需修改即可继续工作。 +**截断恢复能力**: 即使是部分 LLM 输出,也能产生部分有效的结果, + 而不是完全失败。 +**模式验证**: 支持对单个对象进行 JSON 模式验证。 +**区分联合类型**: 支持使用 `type` 字段作为区分器的混合类型输出。 + **最小的 API 变更**: 通过新的 +响应类型和模式键来扩展现有的提示配置。 + ## 背景 @@ -25,148 +37,419 @@ 提示服务支持两种响应类型: -1. `response-type: "text"` - 原始文本响应作为是返回 -2. `response-type: "json"` - 从响应中解析,并根据可选的 `schema` 进行验证 +1. `response-type: "text"` - 原始文本响应,按原样返回。 +2. `response-type: "json"` - 从响应中解析的 JSON 数据,并根据 + 可选的 `schema` 进行验证。 -### 影响的提示 +当前在 `trustgraph-flow/trustgraph/template/prompt_manager.py` 中的实现: -以下提示应迁移到 JSONL 格式: +```python +class Prompt: + def __init__(self, template, response_type = "text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema +``` -| 提示 ID | 描述 | 类型字段 | -|---|---|---| -| `extract-definitions` | 提取所有实体及其定义 | 无 (单个类型) | -| `extract-relationships` | 提取关系 | 无 (单个类型) | -| `extract-topics` | 提取主题/定义 | 无 (单个类型) | -| `extract-rows` | 提取结构化行 | 无 (单个类型) | -| `agent-kg-extract` | 组合定义 + 关系提取 | 是: `"definition"`, `"relationship"` | -| `extract-with-ontologies` / `ontology-extract` | 提取本体 | 是: `"entity"`, `"relationship"`, `"attribute"` | +### 当前限制 -### API 更改 +当提取提示要求输出为 JSON 数组 (`[{...}, {...}, ...]`) 时: + +**截断损坏:** 如果 LLM 在数组中间达到输出令牌限制,则整个响应变为无效的 JSON,无法解析。 + **全或无解析:** 必须接收完整的输出才能进行解析。 +**没有部分结果:** 截断的响应会产生零可用数据。 +**不适用于大型提取:** 提取的项目越多,失败的风险越高。 + + +此规范通过引入 JSONL 格式来解决这些限制,其中每个提取的项目都是一个完整的 JSON 对象,位于其自己的行上。 + + + +## 技术设计 + +### 响应类型扩展 + +添加一个新的响应类型 `"jsonl"`,与现有的 `"text"` 和 `"json"` 类型并列。 + +#### 配置更改 + +**新的响应类型值:** + +``` +"response-type": "jsonl" +``` + +**模式解释:** + +现有的 `"schema"` 键同时用于 `"json"` 和 `"jsonl"` 响应类型。 +解释取决于响应类型: + +`"json"`:模式描述整个响应(通常是数组或对象)。 +`"jsonl"`:模式描述每个单独的行/对象。 + +```json +{ + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["entity", "definition"] + } +} +``` + +这避免了对提示配置工具和编辑器的修改。 + +### JSONL 格式规范 + +#### 简单提取 + +对于提取单一类型对象(定义、关系、 +主题、行)的提示,输出为每行一个 JSON 对象,没有包装: + +**提示输出格式:** +``` +{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"} +{"entity": "chlorophyll", "definition": "Green pigment in plants"} +{"entity": "mitochondria", "definition": "Powerhouse of the cell"} +``` + +**与之前的 JSON 数组格式对比:** +```json +[ + {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, + {"entity": "chlorophyll", "definition": "Green pigment in plants"}, + {"entity": "mitochondria", "definition": "Powerhouse of the cell"} +] +``` + +如果大型语言模型在第2行之后截断,JSON数组格式会产生无效的JSON, +而JSONL会产生两个有效的对象。 + +#### 混合类型提取(区分联合) + +对于需要提取多种类型对象(例如,定义和 +关系,或者实体、关系和属性)的提示,请使用一个 `"type"` +字段作为区分器: + +**提示输出格式:** +``` +{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"} +{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true} +{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"} +{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true} +``` + +**区分联合的模式使用 `oneOf`:** +```json +{ + "response-type": "jsonl", + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { "const": "definition" }, + "entity": { "type": "string" }, + "definition": { "type": "string" } + }, + "required": ["type", "entity", "definition"] + }, + { + "type": "object", + "properties": { + "type": { "const": "relationship" }, + "subject": { "type": "string" }, + "predicate": { "type": "string" }, + "object": { "type": "string" }, + "object-entity": { "type": "boolean" } + }, + "required": ["type", "subject", "predicate", "object", "object-entity"] + } + ] + } +} +``` + +#### 本体抽取 + +对于基于本体的抽取,涉及实体、关系和属性: + +**提示输出格式:** +``` +{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"} +{"type": "entity", "entity": "beef", "entity_type": "fo/Food"} +{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"} +{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"} +``` + +### 实现细节 + +#### 提示类 + +现有的`Prompt`类不需要进行任何更改。 `schema`字段将被重用。 +用于 JSONL 格式,其解释由 `response_type` 决定: + +```python +class Prompt: + def __init__(self, template, response_type="text", terms=None, schema=None): + self.template = template + self.response_type = response_type + self.terms = terms + self.schema = schema # Interpretation depends on response_type +``` + +#### PromptManager.load_config + +无需修改 - 现有的配置加载已经处理了 +`schema` 键。 + +#### JSONL 解析 + +添加一种新的解析方法,用于解析 JSONL 格式的响应: + +```python +def parse_jsonl(self, text): + """ + Parse JSONL response, returning list of valid objects. + + Invalid lines (malformed JSON, empty lines) are skipped with warnings. + This provides truncation resilience - partial output yields partial results. + """ + results = [] + + for line_num, line in enumerate(text.strip().split('\n'), 1): + line = line.strip() + + # Skip empty lines + if not line: + continue + + # Skip markdown code fence markers if present + if line.startswith('```'): + continue + + try: + obj = json.loads(line) + results.append(obj) + except json.JSONDecodeError as e: + # Log warning but continue - this provides truncation resilience + logger.warning(f"JSONL parse error on line {line_num}: {e}") + + return results +``` + +#### PromptManager.invoke 变更 + +扩展 invoke 方法以处理新的响应类型: + +```python +async def invoke(self, id, input, llm): + logger.debug("Invoking prompt template...") + + terms = self.terms | self.prompts[id].terms | input + resp_type = self.prompts[id].response_type + + prompt = { + "system": self.system_template.render(terms), + "prompt": self.render(id, input) + } + + resp = await llm(**prompt) + + if resp_type == "text": + return resp + + if resp_type == "json": + try: + obj = self.parse_json(resp) + except: + logger.error(f"JSON parse failed: {resp}") + raise RuntimeError("JSON parse fail") + + if self.prompts[id].schema: + try: + validate(instance=obj, schema=self.prompts[id].schema) + logger.debug("Schema validation successful") + except Exception as e: + raise RuntimeError(f"Schema validation fail: {e}") + + return obj + + if resp_type == "jsonl": + objects = self.parse_jsonl(resp) + + if not objects: + logger.warning("JSONL parse returned no valid objects") + return [] + + # Validate each object against schema if provided + if self.prompts[id].schema: + validated = [] + for i, obj in enumerate(objects): + try: + validate(instance=obj, schema=self.prompts[id].schema) + validated.append(obj) + except Exception as e: + logger.warning(f"Object {i} failed schema validation: {e}") + return validated + + return objects + + raise RuntimeError(f"Response type {resp_type} not known") +``` + +### 受影响的提示语 + +以下提示语应迁移到 JSONL 格式: + +| 提示语 ID | 描述 | 类型字段 | +|-----------|-------------|------------| +| `extract-definitions` | 实体/定义提取 | 否(单个类型)| +| `extract-relationships` | 关系提取 | 否(单个类型)| +| `extract-topics` | 主题/定义提取 | 否(单个类型)| +| `extract-rows` | 结构化行提取 | 否(单个类型)| +| `agent-kg-extract` | 组合定义 + 关系提取 | 是:`"definition"`, `"relationship"` | +| `extract-with-ontologies` / `ontology-extract` | 基于本体的提取 | 是:`"entity"`, `"relationship"`, `"attribute"` | + +### API 变更 #### 客户端视角 -JSONL 解析对提示服务调用者透明。解析发生在提示服务内部,响应通过标准 `PromptResponse.object` 字段作为序列化的 JSON 数组返回。 +JSONL 解析对提示服务 API 的调用者是透明的。解析过程 +在提示服务的服务器端进行,响应通过标准的 +`PromptResponse.object` 字段以序列化的 JSON 数组形式返回。 -当客户端调用提示服务(通过 `PromptClient.prompt()` 或类似方法)时: +当客户端调用提示服务(通过 `PromptClient.prompt()` 或类似方式时): -- `response-type: "json"` (带数组模式) → 客户端接收 Python `list` -- `response-type: "jsonl"` → 客户端接收 Python `list` +**`response-type: "json"`**(带有数组模式)→ 客户端接收 Python `list` +**`response-type: "jsonl"`** → 客户端接收 Python `list` -从客户端的视角来看,两者都返回相同的数据结构。 区别在于 LLM 响应如何在服务器端进行解析: +从客户端的角度来看,两者都返回相同的的数据结构。 +区别完全在于服务器端如何解析 LLM 的输出: -- JSON 数组格式:执行一个 `json.loads()` 调用;如果被截断则完全失败 -- JSONL 格式:逐行解析;如果被截断则产生部分结果 +JSON 数组格式:单个 `json.loads()` 调用;如果被截断,则完全失败。 +JSONL 格式:逐行解析;如果被截断,则产生部分结果。 -这意味着预期的以 JSON 格式返回提取结果的代码,无需在迁移到 JSONL 格式的提示时进行更改。 +这意味着,现有的客户端代码期望从提取提示中获得列表, +在将提示从 JSON 迁移到 JSONL 格式时,不需要进行任何更改。 #### 服务器返回值 -对于 `response-type: "jsonl"`,`PromptManager.invoke()` 方法返回一个 `list[dict]`,其中包含成功解析和验证的对象。 此列表随后通过 `PromptResponse.object` 字段作为 JSON 序列化。 +对于 `response-type: "jsonl"`,`PromptManager.invoke()` 方法返回一个 +`list[dict]`,其中包含所有成功解析和验证的对象。 此 +列表随后被序列化为 JSON,用于 `PromptResponse.object` 字段。 #### 错误处理 -- 无结果: 返回空列表 `[]`,带有警告日志 -- 部分解析失败: 返回成功解析对象的列表,带有失败的警告日志 -- 完全解析失败: 返回空列表 `[]`,带有警告日志 +空结果:返回一个空列表 `[]`,并带有警告日志。 +部分解析失败:返回成功解析的对象列表, + 并为解析失败的情况记录警告日志。 +完全解析失败:返回一个空列表 `[]`,并带有警告日志。 -与 `response-type: "json"` 相比,这种行为是故意的,旨在提供容错性。 +这与 `response-type: "json"` 不同,后者会在解析失败时引发 `RuntimeError`。 +对于 JSONL 的宽松处理是故意的,目的是为了提供截断恢复能力。 -### 性能考虑 -- 内存:逐行解析比加载完整的 JSON 数组使用更少的峰值内存 -- 延迟:解析的性能与 JSON 数组解析相似 -- 验证:按对象运行模式验证,这会增加开销,但允许在验证失败时产生部分结果 +### 配置示例 +完整的提示配置示例: + +```json +{ + "prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"\", \"definition\": \"\"}", + "response-type": "jsonl", + "schema": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "The entity name" + }, + "definition": { + "type": "string", + "description": "A clear definition of the entity" + } + }, + "required": ["entity", "definition"] + } +} +``` + +## 安全注意事项 + +**输入验证**: JSON 解析使用标准的 `json.loads()`,这可以防止注入攻击。 + **模式验证**: 使用 ⟦CODE_0⟧ 来强制执行模式。 +**模式验证**: 使用 `jsonschema.validate()` 进行模式强制。 +**没有新的攻击面:** JSONL 解析比 JSON 数组解析更安全,因为它采用逐行处理的方式。 + parsing due to line-by-line processing + +## 性能考量 + +**内存**: 逐行解析比加载完整的 JSON 数组消耗更少的峰值内存。 + **延迟**: 解析性能与 JSON 数组解析相当。 +**验证**: 模式验证按对象进行,这会增加开销,但 +可以在验证失败时提供部分结果。 + ## 测试策略 + ### 单元测试 -- JSONL 格式的有效输入解析 -- 空行的 JSONL 解析 -- Markdown 代码块的 JSONL 解析 -- 最后的行被截断的 JSONL 解析 -- 无效 JSON 行的 JSONL 解析 -- 带有 `oneOf` 的区分联合的模式验证 -- 现有 `"text"` 和 `"json"` 提示的向后兼容性 +使用有效输入的 JSONL 解析 +使用空行的 JSONL 解析 +使用 Markdown 代码块的 JSONL 解析 +使用截断的最终行的 JSONL 解析 +包含穿插无效 JSON 行的 JSONL 解析 +使用 `oneOf` 区分联合的模式验证 +向后兼容性:现有的 `"text"` 和 `"json"` 提示词保持不变 ### 集成测试 -- 使用 JSONL 提示的端到端提取 -- 模拟截断响应(人为限制响应) -- 使用类型区分器的混合类型提取 -- 使用所有三种类型的本体提取 +使用 JSONL 提示词的端到端提取 +使用模拟截断的提取(人为限制响应) +使用类型区分器的混合类型提取 +使用所有三种类型的本体提取 ### 提取质量测试 -- 比较 JSONL 和 JSON 数组格式的提取结果 -- 验证容错性: JSONL 在被截断时产生部分结果,而 JSON 失败 -- 验证混合类型提取的类型字段 - -### 迁移计划 - -### 阶段 1:实现 - -1. 在 `PromptManager` 中实现 `parse_jsonl()` 方法 -2. 扩展 `invoke()` 以处理 `response-type: "jsonl"` -3. 添加单元测试 - -### 阶段 2:提示迁移 - -1. 迁移 `extract-definitions` 提示和配置 -2. 迁移 `extract-relationships` 提示和配置 -3. 迁移 `extract-topics` 提示和配置 -4. 迁移 `extract-rows` 提示和配置 -5. 迁移 `agent-kg-extract` 提示和配置 -6. 迁移 `extract-with-ontologies` 提示和配置 - -### 阶段 3:下游更新 - -1. 更新消费提取结果的代码以处理列表返回类型 -2. 更新对按 `type` 字段对混合类型提取进行分类的代码 -3. 更新断言提取结果格式的测试 - -## 安全考虑 - -- 输入验证:使用标准 `json.loads()` 进行 JSON 解析,这可以防止注入攻击 -- 模式验证:使用 `jsonschema.validate()` 进行模式强制 -- 无新攻击面:逐行解析比 JSON 数组解析更安全,因为它不会导致问题 - -## 性能考虑 - -- 内存:逐行解析使用更少的峰值内存,而不是加载完整的 JSON 数组 -- 延迟:解析性能与 JSON 数组解析相似 -- 验证:按对象运行模式验证,这会增加开销,但允许在验证失败时产生部分结果 +比较提取结果:JSONL 与 JSON 数组格式 +验证截断恢复能力:JSONL 在 JSON 失败的情况下,可以产生部分结果 ## 迁移计划 -### 阶段 1:实现 +### 第一阶段:实施 -1. 在 `PromptManager` 中实现 `parse_jsonl()` 方法 +1. 在 `parse_jsonl()` 中实现 `PromptManager` 方法 2. 扩展 `invoke()` 以处理 `response-type: "jsonl"` 3. 添加单元测试 -### 阶段 2:提示迁移 +### 第二阶段:提示词迁移 -1. 迁移 `extract-definitions` 提示和配置 -2. 迁移 `extract-relationships` 提示和配置 -3. 迁移 `extract-topics` 提示和配置 -4. 迁移 `extract-rows` 提示和配置 -5. 迁移 `agent-kg-extract` 提示和配置 -6. 迁移 `extract-with-ontologies` 提示和配置 +1. 更新 `extract-definitions` 提示词和配置 +2. 更新 `extract-relationships` 提示词和配置 +3. 更新 `extract-topics` 提示词和配置 +4. 更新 `extract-rows` 提示词和配置 +5. 更新 `agent-kg-extract` 提示词和配置 +6. 更新 `extract-with-ontologies` 提示词和配置 -### 阶段 3:下游更新 +### 第三阶段:下游更新 -1. 更新消费提取结果的代码以处理列表返回类型 -2. 更新对按 `type` 字段对混合类型提取进行分类的代码 -3. 更新断言提取结果格式的测试 +1. 更新任何使用提取结果的代码,使其能够处理列表返回类型。 +2. 更新根据 `type` 字段对混合类型提取进行分类的代码。 +3. 更新用于断言提取输出格式的测试。 -## 开放问题 +## 待解决问题 目前没有。 -## 参考 +## 参考文献 -- 当前实现:`trustgraph-flow/trustgraph/template/prompt_manager.py` -- JSON Lines 规范:https://jsonlines.org/ -- JSON Schema `oneOf`:https://json-schema.org/understanding-json-schema/reference/combining.html#oneof -- 相关规范:流式 LLM 响应 (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file +当前实现:`trustgraph-flow/trustgraph/template/prompt_manager.py` +JSON Lines 规范:https://jsonlines.org/ +JSON Schema `oneOf`:https://json-schema.org/understanding-json-schema/reference/combining.html#oneof +相关规范:Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`) diff --git a/docs/tech-specs/large-document-loading.es.md b/docs/tech-specs/large-document-loading.es.md new file mode 100644 index 00000000..b55a61ed --- /dev/null +++ b/docs/tech-specs/large-document-loading.es.md @@ -0,0 +1,984 @@ +# Especificación Técnica de Carga de Documentos Grandes + +## Resumen + +Esta especificación aborda los problemas de escalabilidad y la experiencia del usuario al cargar +documentos grandes en TrustGraph. La arquitectura actual trata la carga de documentos +como una operación atómica única, lo que provoca una alta carga de memoria en varios puntos del +proceso y no proporciona ninguna indicación de progreso ni opciones de recuperación a los usuarios. + +Esta implementación tiene como objetivo los siguientes casos de uso: + +1. **Procesamiento de PDF Grandes**: Cargar y procesar archivos PDF de varios cientos de megabytes + sin agotar la memoria. +2. **Cargas Reanudables**: Permitir que las cargas interrumpidas continúen desde donde + se detuvieron en lugar de reiniciarse. +3. **Indicación de Progreso**: Proporcionar a los usuarios visibilidad en tiempo real del + progreso de la carga y el procesamiento. +4. **Procesamiento Eficiente en Memoria**: Procesar documentos de forma continua + sin mantener archivos completos en la memoria. + +## Objetivos + +**Carga Incremental**: Soporte para la carga de documentos en fragmentos a través de REST y WebSocket. +**Transferencias Reanudables**: Permitir la recuperación de cargas interrumpidas. +**Visibilidad del Progreso**: Proporcionar retroalimentación de carga/procesamiento a los clientes. +**Eficiencia de Memoria**: Eliminar el almacenamiento en búfer de documentos completos en todo el proceso. +**Compatibilidad con Versiones Anteriores**: Los flujos de trabajo existentes para documentos pequeños continúan sin cambios. +**Procesamiento por Flujo Continuo**: La decodificación de PDF y el fragmentado de texto operan en flujos. + +## Antecedentes + +### Arquitectura Actual + +El flujo de envío de documentos sigue la siguiente ruta: + +1. El **cliente** envía el documento a través de REST (`POST /api/v1/librarian`) o WebSocket. +2. La **API Gateway** recibe la solicitud completa con el contenido del documento codificado en base64. +3. El **LibrarianRequestor** traduce la solicitud a un mensaje Pulsar. +4. El **Librarian Service** recibe el mensaje, decodifica el documento en la memoria. +5. **BlobStore** carga el documento en Garage/S3. +6. **Cassandra** almacena los metadatos con la referencia del objeto. +7. Para el procesamiento: el documento se recupera de S3, se decodifica y se divide en fragmentos, todo en la memoria. + +Archivos clave: +Punto de entrada REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` +Núcleo de Librarian: `trustgraph-flow/trustgraph/librarian/librarian.py` +Almacenamiento de blobs: `trustgraph-flow/trustgraph/librarian/blob_store.py` +Tablas de Cassandra: `trustgraph-flow/trustgraph/tables/library.py` +Esquema de la API: `trustgraph-base/trustgraph/schema/services/library.py` + +### Limitaciones Actuales + +El diseño actual tiene varios problemas de memoria y experiencia de usuario que se agravan: + +1. **Operación de Carga Atómica**: Se debe transmitir todo el documento en una + solicitud única. Los documentos grandes requieren solicitudes de larga duración sin + indicación de progreso ni mecanismo de reintento si la conexión falla. + +2. **Diseño de la API**: Tanto las API REST como WebSocket esperan el documento + completo en un solo mensaje. El esquema (`LibrarianRequest`) tiene un campo `content` + que contiene todo el documento codificado en base64. + +3. **Memoria del Librarian**: El servicio librarian decodifica todo el documento + en la memoria antes de cargarlo en S3. Para un PDF de 500 MB, esto significa mantener + 500 MB+ en la memoria del proceso. + +4. **Memoria del Decodificador de PDF**: Cuando comienza el procesamiento, el decodificador de PDF carga + todo el PDF en la memoria para extraer el texto. Las bibliotecas como PyPDF y similares + típicamente requieren acceso a todo el documento. + +5. **Memoria del Fragmentador**: El fragmentador de texto recibe todo el texto extraído + y lo mantiene en la memoria mientras produce fragmentos. + +**Ejemplo de Impacto en la Memoria** (PDF de 500 MB): +Gateway: ~700 MB (sobrecarga de codificación base64) +Librarian: ~500 MB (bytes decodificados) +Decodificador de PDF: ~500 MB + búferes de extracción +Fragmentador: texto extraído (variable, potencialmente 100 MB+) + +El pico total de memoria puede exceder los 2 GB para un solo documento grande. + +## Diseño Técnico + +### Principios de Diseño + +1. **Fachada de la API**: Toda la interacción del cliente pasa por la API de librarian. Los clientes + no tienen acceso directo ni conocimiento del almacenamiento subyacente de S3/Garage. + +2. **Carga Multipart de S3**: Utilice la carga multipart estándar de S3. + Esto está ampliamente soportado en sistemas compatibles con S3 (AWS S3, MinIO, Garage, + Ceph, DigitalOcean Spaces, Backblaze B2, etc.), lo que garantiza la portabilidad. + +3. **Completación Atómica**: Las cargas multipart de S3 son inherentemente atómicas: las partes cargadas + son invisibles hasta que se llama a `CompleteMultipartUpload`. No se necesitan archivos temporales ni + operaciones de renombrado. + +4. **Estado Rastreable**: Las sesiones de carga se rastrean en Cassandra, lo que proporciona + visibilidad de las cargas incompletas y permite la capacidad de reanudación. + +### Flujo de Carga Fragmentada + +``` +Client Librarian API S3/Garage + │ │ │ + │── begin-upload ───────────►│ │ + │ (metadata, size) │── CreateMultipartUpload ────►│ + │ │◄── s3_upload_id ─────────────│ + │◄── upload_id ──────────────│ (store session in │ + │ │ Cassandra) │ + │ │ │ + │── upload-chunk ───────────►│ │ + │ (upload_id, index, data) │── UploadPart ───────────────►│ + │ │◄── etag ─────────────────────│ + │◄── ack + progress ─────────│ (store etag in session) │ + │ ⋮ │ ⋮ │ + │ (repeat for all chunks) │ │ + │ │ │ + │── complete-upload ────────►│ │ + │ (upload_id) │── CompleteMultipartUpload ──►│ + │ │ (parts coalesced by S3) │ + │ │── store doc metadata ───────►│ Cassandra + │◄── document_id ────────────│ (delete session) │ +``` + +El cliente nunca interactúa directamente con S3. El "librarian" (bibliotecario) traduce entre +nuestra API de carga por partes y las operaciones multipart de S3 internamente. + +### Operaciones de la API del "Librarian" + +#### `begin-upload` + +Inicializar una sesión de carga por partes. + +Solicitud: +```json +{ + "operation": "begin-upload", + "document-metadata": { + "id": "doc-123", + "kind": "application/pdf", + "title": "Large Document", + "user": "user-id", + "tags": ["tag1", "tag2"] + }, + "total-size": 524288000, + "chunk-size": 5242880 +} +``` + +Respuesta: +```json +{ + "upload-id": "upload-abc-123", + "chunk-size": 5242880, + "total-chunks": 100 +} +``` + +El bibliotecario: +1. Genera un `upload_id` y un `object_id` únicos (UUID para almacenamiento de blobs). +2. Llama a S3 `CreateMultipartUpload`, recibe `s3_upload_id`. +3. Crea un registro de sesión en Cassandra. +4. Devuelve `upload_id` al cliente. + +#### `upload-chunk` + +Cargar un único fragmento. + +Solicitud: +```json +{ + "operation": "upload-chunk", + "upload-id": "upload-abc-123", + "chunk-index": 0, + "content": "" +} +``` + +Respuesta: +```json +{ + "upload-id": "upload-abc-123", + "chunk-index": 0, + "chunks-received": 1, + "total-chunks": 100, + "bytes-received": 5242880, + "total-bytes": 524288000 +} +``` + +El bibliotecario: +1. Busca la sesión por `upload_id` +2. Valida la propiedad (el usuario debe coincidir con el creador de la sesión) +3. Llama a S3 `UploadPart` con los datos del fragmento, recibe `etag` +4. Actualiza el registro de la sesión con el índice del fragmento y la etiqueta (etag) +5. Devuelve el progreso al cliente + +Los fragmentos fallidos se pueden reintentar; simplemente envía el mismo `chunk-index` nuevamente. + +#### `complete-upload` + +Finaliza la carga y crea el documento. + +Solicitud: +```json +{ + "operation": "complete-upload", + "upload-id": "upload-abc-123" +} +``` + +Respuesta: +```json +{ + "document-id": "doc-123", + "object-id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +El bibliotecario: +1. Busca la sesión, verifica que se hayan recibido todos los fragmentos. +2. Llama a S3 `CompleteMultipartUpload` con los ETags de las partes (S3 combina las partes + internamente, sin costo de memoria para el bibliotecario). +3. Crea un registro de documento en Cassandra con metadatos y referencia al objeto. +4. Elimina el registro de la sesión de carga. +5. Devuelve el ID del documento al cliente. + +#### `abort-upload` + +Cancelar una carga en curso. + +Solicitud: +```json +{ + "operation": "abort-upload", + "upload-id": "upload-abc-123" +} +``` + +El bibliotecario: +1. Llama a S3 `AbortMultipartUpload` para limpiar partes. +2. Elimina el registro de sesión de Cassandra. + +#### `get-upload-status` + +Consulta el estado de una carga (para la capacidad de reanudación). + +Solicitud: +```json +{ + "operation": "get-upload-status", + "upload-id": "upload-abc-123" +} +``` + +Respuesta: +```json +{ + "upload-id": "upload-abc-123", + "state": "in-progress", + "chunks-received": [0, 1, 2, 5, 6], + "missing-chunks": [3, 4, 7, 8], + "total-chunks": 100, + "bytes-received": 36700160, + "total-bytes": 524288000 +} +``` + +#### `list-uploads` + +Listar las subidas incompletas para un usuario. + +Solicitud: +```json +{ + "operation": "list-uploads" +} +``` + +Respuesta: +```json +{ + "uploads": [ + { + "upload-id": "upload-abc-123", + "document-metadata": { "title": "Large Document", ... }, + "progress": { "chunks-received": 43, "total-chunks": 100 }, + "created-at": "2024-01-15T10:30:00Z" + } + ] +} +``` + +### Almacenamiento de Sesión de Carga + +Realizar un seguimiento de las cargas en curso en Cassandra: + +```sql +CREATE TABLE upload_session ( + upload_id text PRIMARY KEY, + user text, + document_id text, + document_metadata text, -- JSON: title, kind, tags, comments, etc. + s3_upload_id text, -- internal, for S3 operations + object_id uuid, -- target blob ID + total_size bigint, + chunk_size int, + total_chunks int, + chunks_received map, -- chunk_index → etag + created_at timestamp, + updated_at timestamp +) WITH default_time_to_live = 86400; -- 24 hour TTL + +CREATE INDEX upload_session_user ON upload_session (user); +``` + +**Comportamiento de TTL:** +Las sesiones expiran después de 24 horas si no se completan. +Cuando expira el TTL de Cassandra, se elimina el registro de la sesión. +Las partes de S3 huérfanas se eliminan mediante la política de ciclo de vida de S3 (configurar en el bucket). + +### Manejo de errores y atomicidad + +**Fallo en la carga de fragmentos:** +El cliente reintenta el fragmento fallido (mismo `upload_id` y `chunk-index`). +`UploadPart` de S3 es idempotente para el mismo número de parte. +La sesión realiza un seguimiento de qué fragmentos tuvieron éxito. + +**Desconexión del cliente durante la carga:** +La sesión permanece en Cassandra con los fragmentos recibidos registrados. +El cliente puede llamar a `get-upload-status` para ver qué falta. +Reanudar cargando solo los fragmentos faltantes, luego `complete-upload`. + +**Fallo en la carga completa:** +`CompleteMultipartUpload` de S3 es atómico: o tiene éxito por completo o falla. +En caso de fallo, las partes permanecen y el cliente puede reintentar `complete-upload`. +Nunca se muestra un documento parcial. + +**Vencimiento de la sesión:** +El TTL de Cassandra elimina el registro de la sesión después de 24 horas. +La política de ciclo de vida del bucket de S3 limpia las cargas multipartes incompletas. +No se requiere limpieza manual. + +### Atomicidad de las cargas multipartes de S3 + +Las cargas multipartes de S3 proporcionan atomicidad integrada: + +1. **Las partes son invisibles:** Las partes cargadas no se pueden acceder como objetos. + Solo existen como partes de una carga multipartes incompleta. + +2. **Finalización atómica:** `CompleteMultipartUpload` tiene éxito (el objeto + aparece de forma atómica) o falla (no se crea ningún objeto). No hay estado parcial. + +3. **No se necesita renombrar:** La clave de objeto final se especifica en + el momento de `CreateMultipartUpload`. Las partes se combinan directamente en esa clave. + +4. **Combinación del lado del servidor:** S3 combina las partes internamente. El bibliotecario + nunca lee las partes de nuevo: cero sobrecarga de memoria independientemente del tamaño del documento. + +### Extensiones de BlobStore + +**Archivo:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +Agregar métodos de carga multipartes: + +```python +class BlobStore: + # Existing methods... + + def create_multipart_upload(self, object_id: UUID, kind: str) -> str: + """Initialize multipart upload, return s3_upload_id.""" + # minio client: create_multipart_upload() + + def upload_part( + self, object_id: UUID, s3_upload_id: str, + part_number: int, data: bytes + ) -> str: + """Upload a single part, return etag.""" + # minio client: upload_part() + # Note: S3 part numbers are 1-indexed + + def complete_multipart_upload( + self, object_id: UUID, s3_upload_id: str, + parts: List[Tuple[int, str]] # [(part_number, etag), ...] + ) -> None: + """Finalize multipart upload.""" + # minio client: complete_multipart_upload() + + def abort_multipart_upload( + self, object_id: UUID, s3_upload_id: str + ) -> None: + """Cancel multipart upload, clean up parts.""" + # minio client: abort_multipart_upload() +``` + +### Consideraciones sobre el tamaño de los bloques + +**Mínimo de S3**: 5 MB por parte (excepto la última parte) +**Máximo de S3**: 10,000 partes por carga +**Valor predeterminado práctico**: bloques de 5 MB + Documento de 500 MB = 100 bloques + Documento de 5 GB = 1000 bloques +**Granularidad del progreso**: Bloques más pequeños = actualizaciones de progreso más detalladas +**Eficiencia de la red**: Bloques más grandes = menos viajes de ida y vuelta + +El tamaño del bloque podría ser configurable por el cliente dentro de un rango (5 MB - 100 MB). + +### Procesamiento de documentos: Recuperación en streaming + +El flujo de carga se ocupa de almacenar documentos de manera eficiente. El flujo de procesamiento se ocupa de extraer y dividir documentos sin cargarlos +por completo en la memoria. + + +#### Principio de diseño: Identificador, no contenido + +Actualmente, cuando se inicia el procesamiento, el contenido del documento fluye a través de mensajes de Pulsar. Esto carga documentos completos en la memoria. En cambio: + + +Los mensajes de Pulsar solo contienen el **identificador del documento** +Los procesadores recuperan el contenido del documento directamente de la biblioteca. +La recuperación se realiza como un **flujo a un archivo temporal** +El análisis específico del documento (PDF, texto, etc.) funciona con archivos, no con búferes de memoria. + +Esto mantiene a la biblioteca independiente de la estructura del documento. El análisis de PDF, la extracción de texto y otras lógicas específicas del formato permanecen en los decodificadores correspondientes. + + +#### Flujo de procesamiento + +``` +Pulsar PDF Decoder Librarian S3 + │ │ │ │ + │── doc-id ───────────►│ │ │ + │ (processing msg) │ │ │ + │ │ │ │ + │ │── stream-document ──────►│ │ + │ │ (doc-id) │── GetObject ────►│ + │ │ │ │ + │ │◄── chunk ────────────────│◄── stream ───────│ + │ │ (write to temp file) │ │ + │ │◄── chunk ────────────────│◄── stream ───────│ + │ │ (append to temp file) │ │ + │ │ ⋮ │ ⋮ │ + │ │◄── EOF ──────────────────│ │ + │ │ │ │ + │ │ ┌──────────────────────────┐ │ + │ │ │ temp file on disk │ │ + │ │ │ (memory stays bounded) │ │ + │ │ └────────────┬─────────────┘ │ + │ │ │ │ + │ │ PDF library opens file │ + │ │ extract page 1 text ──► chunker │ + │ │ extract page 2 text ──► chunker │ + │ │ ⋮ │ + │ │ close file │ + │ │ delete temp file │ +``` + +#### API de flujo de trabajo del bibliotecario + +Agregar una operación de recuperación de documentos en flujo continuo: + +**`stream-document`** + +Solicitud: +```json +{ + "operation": "stream-document", + "document-id": "doc-123" +} +``` + +Respuesta: Fragmentos binarios transmitidos (no una respuesta única). + +Para la API REST, esto devuelve una respuesta transmitida con `Transfer-Encoding: chunked`. + +Para llamadas internas de servicio a servicio (del procesador al bibliotecario), esto podría ser: +Transmisión directa de S3 a través de una URL prefirmada (si la red interna lo permite). +Respuestas fragmentadas a través del protocolo del servicio. +Un punto final de transmisión dedicado. + +El requisito clave: los datos fluyen en fragmentos, nunca completamente almacenados en búfer en el bibliotecario. + +#### Cambios en el decodificador de PDF + +**Implementación actual** (que consume mucha memoria): + +```python +def decode_pdf(document_content: bytes) -> str: + reader = PdfReader(BytesIO(document_content)) # full doc in memory + text = "" + for page in reader.pages: + text += page.extract_text() # accumulating + return text # full text in memory +``` + +**Nueva implementación** (archivo temporal, incremental): + +```python +def decode_pdf_streaming(doc_id: str, librarian_client) -> Iterator[str]: + """Yield extracted text page by page.""" + + with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp: + # Stream document to temp file + for chunk in librarian_client.stream_document(doc_id): + tmp.write(chunk) + tmp.flush() + + # Open PDF from file (not memory) + reader = PdfReader(tmp.name) + + # Yield pages incrementally + for page in reader.pages: + yield page.extract_text() + + # tmp file auto-deleted on context exit +``` + +Perfil de memoria: +Archivo temporal en disco: tamaño del PDF (el disco es barato). +En memoria: una página de texto a la vez. +Memoria máxima: limitada, independiente del tamaño del documento. + +#### Cambios en el decodificador de documentos de texto. + +Para documentos de texto plano, aún más simple: no se necesita archivo temporal. + +```python +def decode_text_streaming(doc_id: str, librarian_client) -> Iterator[str]: + """Yield text in chunks as it streams from storage.""" + + buffer = "" + for chunk in librarian_client.stream_document(doc_id): + buffer += chunk.decode('utf-8') + + # Yield complete lines/paragraphs as they arrive + while '\n\n' in buffer: + paragraph, buffer = buffer.split('\n\n', 1) + yield paragraph + '\n\n' + + # Yield remaining buffer + if buffer: + yield buffer +``` + +Los documentos de texto pueden transmitirse directamente sin un archivo temporal, ya que están +estructurados linealmente. + +#### Integración del Fragmentador (Chunker) + +El fragmentador recibe un iterador de texto (páginas o párrafos) y produce +fragmentos de forma incremental: + +```python +class StreamingChunker: + def __init__(self, chunk_size: int, overlap: int): + self.chunk_size = chunk_size + self.overlap = overlap + + def process(self, text_stream: Iterator[str]) -> Iterator[str]: + """Yield chunks as text arrives.""" + buffer = "" + + for text_segment in text_stream: + buffer += text_segment + + while len(buffer) >= self.chunk_size: + chunk = buffer[:self.chunk_size] + yield chunk + # Keep overlap for context continuity + buffer = buffer[self.chunk_size - self.overlap:] + + # Yield remaining buffer as final chunk + if buffer.strip(): + yield buffer +``` + +#### Canalización de procesamiento de extremo a extremo + +```python +async def process_document(doc_id: str, librarian_client, embedder): + """Process document with bounded memory.""" + + # Get document metadata to determine type + metadata = await librarian_client.get_document_metadata(doc_id) + + # Select decoder based on document type + if metadata.kind == 'application/pdf': + text_stream = decode_pdf_streaming(doc_id, librarian_client) + elif metadata.kind == 'text/plain': + text_stream = decode_text_streaming(doc_id, librarian_client) + else: + raise UnsupportedDocumentType(metadata.kind) + + # Chunk incrementally + chunker = StreamingChunker(chunk_size=1000, overlap=100) + + # Process each chunk as it's produced + for chunk in chunker.process(text_stream): + # Generate embeddings, store in vector DB, etc. + embedding = await embedder.embed(chunk) + await store_chunk(doc_id, chunk, embedding) +``` + +En ningún momento, se mantiene en memoria el documento completo o el texto extraído completo. + +#### Consideraciones sobre archivos temporales + +**Ubicación**: Utilice el directorio temporal del sistema (`/tmp` o equivalente). Para +implementaciones en contenedores, asegúrese de que el directorio temporal tenga suficiente espacio +y que esté en un almacenamiento rápido (no montado en red, si es posible). + +**Limpieza**: Utilice administradores de contexto (`with tempfile...`) para garantizar la limpieza +incluso en caso de excepciones. + +**Procesamiento concurrente**: Cada trabajo de procesamiento obtiene su propio archivo temporal. +No hay conflictos entre el procesamiento paralelo de documentos. + +**Espacio en disco**: Los archivos temporales son de corta duración (duración del procesamiento). Para +un archivo PDF de 500 MB, se necesitan 500 MB de espacio temporal durante el procesamiento. El límite de tamaño podría +aplicarse en el momento de la carga si el espacio en disco es limitado. + +### Interfaz de procesamiento unificada: Documentos secundarios + +La extracción de PDF y el procesamiento de documentos de texto deben integrarse en la misma +canalización descendente (fragmentación → incrustaciones → almacenamiento). Para lograr esto con una interfaz "recuperación por ID" consistente, los bloques de texto extraídos se almacenan de nuevo +en el sistema de gestión de documentos como documentos secundarios. + +#### Flujo de procesamiento con documentos secundarios + +Después de la última línea traducida, incluir una línea final que contenga exactamente: [[__END_OF_TRANSLATION__]] +``` +PDF Document Text Document + │ │ + ▼ │ +pdf-extractor │ + │ │ + │ (stream PDF from librarian) │ + │ (extract page 1 text) │ + │ (store as child doc → librarian) │ + │ (extract page 2 text) │ + │ (store as child doc → librarian) │ + │ ⋮ │ + ▼ ▼ +[child-doc-id, child-doc-id, ...] [doc-id] + │ │ + └─────────────────────┬───────────────────────────────┘ + ▼ + chunker + │ + │ (receives document ID) + │ (streams content from librarian) + │ (chunks incrementally) + ▼ + [chunks → embedding → storage] +``` + +El componente de segmentación tiene una interfaz uniforme: +Recibir un ID de documento (a través de Pulsar) +Obtener el contenido del bibliotecario +Segmentarlo + +No sabe ni le importa si el ID se refiere a: +Un documento de texto subido por un usuario +Un fragmento de texto extraído de una página de PDF +Cualquier tipo de documento futuro + +#### Metadatos del Documento Hijo + +Extender el esquema del documento para rastrear las relaciones padre/hijo: + +```sql +-- Add columns to document table +ALTER TABLE document ADD parent_id text; +ALTER TABLE document ADD document_type text; + +-- Index for finding children of a parent +CREATE INDEX document_parent ON document (parent_id); +``` + +**Tipos de documentos:** + +| `document_type` | Descripción | +|-----------------|-------------| +| `source` | Documento subido por el usuario (PDF, texto, etc.) | +| `extracted` | Derivado de un documento fuente (por ejemplo, texto de una página PDF) | + +**Campos de metadatos:** + +| Campo | Documento fuente | Documento hijo extraído | +|-------|-----------------|-----------------| +| `id` | proporcionado por el usuario o generado | generado (por ejemplo, `{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | ID del documento padre | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf`, etc. | `text/plain` | +| `title` | proporcionado por el usuario | generado (por ejemplo, "Página 3 del Informe.pdf") | +| `user` | usuario autenticado | igual que el padre | + +#### API de Librarian para documentos hijos + +**Creación de documentos hijos** (interno, utilizado por pdf-extractor): + +```json +{ + "operation": "add-child-document", + "parent-id": "doc-123", + "document-metadata": { + "id": "doc-123-page-1", + "kind": "text/plain", + "title": "Page 1" + }, + "content": "" +} +``` + +Para textos pequeños extraídos (el texto típico de una página es menor a 100 KB), la carga en una sola operación es aceptable. Para extracciones de texto muy grandes, se podría utilizar la carga por bloques. + +**Listado de documentos secundarios** (para depuración/administración): + +**Listado de documentos secundarios** (para depuración/administración): + +```json +{ + "operation": "list-children", + "parent-id": "doc-123" +} +``` + +Respuesta: +```json +{ + "children": [ + { "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" }, + { "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" }, + ... + ] +} +``` + +#### Comportamiento visible para el usuario + +**`list-documents` comportamiento predeterminado:** + +```sql +SELECT * FROM document WHERE user = ? AND parent_id IS NULL; +``` + +Solo los documentos de nivel superior (fuente) aparecen en la lista de documentos del usuario. +Los documentos secundarios se filtran de forma predeterminada. + +**Opción de incluir subdocumentos** (para administradores/depuración): + +```json +{ + "operation": "list-documents", + "include-children": true +} +``` + +#### Eliminación en cascada + +Cuando se elimina un documento padre, todos los documentos hijos deben ser eliminados: + +```python +def delete_document(doc_id: str): + # Find all children + children = query("SELECT id, object_id FROM document WHERE parent_id = ?", doc_id) + + # Delete child blobs from S3 + for child in children: + blob_store.delete(child.object_id) + + # Delete child metadata from Cassandra + execute("DELETE FROM document WHERE parent_id = ?", doc_id) + + # Delete parent blob and metadata + parent = get_document(doc_id) + blob_store.delete(parent.object_id) + execute("DELETE FROM document WHERE id = ? AND user = ?", doc_id, user) +``` + +#### Consideraciones de almacenamiento + +Los bloques de texto extraídos duplican el contenido: +El PDF original se almacena en Garage. +El texto extraído por página también se almacena en Garage. + +Este compromiso permite: +**Interfaz de fragmentación uniforme**: El fragmentador siempre recupera por ID. +**Reanudación/reintento**: Se puede reiniciar en la etapa del fragmentador sin volver a extraer el PDF. +**Depuración**: El texto extraído es inspeccionable. +**Separación de responsabilidades**: El extractor de PDF y el fragmentador son servicios independientes. + +Para un PDF de 500 MB con 200 páginas que promedian 5 KB de texto por página: +Almacenamiento del PDF: 500 MB. +Almacenamiento del texto extraído: ~1 MB en total. +Sobrecarga: insignificante. + +#### Salida del extractor de PDF + +El extractor de PDF, después de procesar un documento: + +1. Transmite el PDF desde el bibliotecario a un archivo temporal. +2. Extrae el texto página por página. +3. Para cada página, almacena el texto extraído como un documento secundario a través del bibliotecario. +4. Envía los ID de los documentos secundarios a la cola del fragmentador. +Después de la última línea traducida, incluir una línea final que contenga exactamente: [[__END_OF_TRANSLATION__]] +```python +async def extract_pdf(doc_id: str, librarian_client, output_queue): + """Extract PDF pages and store as child documents.""" + + with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp: + # Stream PDF to temp file + for chunk in librarian_client.stream_document(doc_id): + tmp.write(chunk) + tmp.flush() + + # Extract pages + reader = PdfReader(tmp.name) + for page_num, page in enumerate(reader.pages, start=1): + text = page.extract_text() + + # Store as child document + child_id = f"{doc_id}-page-{page_num}" + await librarian_client.add_child_document( + parent_id=doc_id, + document_id=child_id, + kind="text/plain", + title=f"Page {page_num}", + content=text.encode('utf-8') + ) + + # Send to chunker queue + await output_queue.send(child_id) +``` + +El componente de segmentación recibe estos ID de elementos secundarios y los procesa de la misma manera que procesaría un documento de texto subido por el usuario. + +### Actualizaciones del cliente + +#### SDK de Python + + +El SDK de Python (`trustgraph-base/trustgraph/api/library.py`) debe manejar +las cargas fragmentadas de forma transparente. La interfaz pública permanece sin cambios: + +```python +# Existing interface - no change for users +library.add_document( + id="doc-123", + title="Large Report", + kind="application/pdf", + content=large_pdf_bytes, # Can be hundreds of MB + tags=["reports"] +) +``` + +Internamente, el SDK detecta el tamaño del documento y cambia de estrategia: + +```python +class Library: + CHUNKED_UPLOAD_THRESHOLD = 2 * 1024 * 1024 # 2MB + + def add_document(self, id, title, kind, content, tags=None, ...): + if len(content) < self.CHUNKED_UPLOAD_THRESHOLD: + # Small document: single operation (existing behavior) + return self._add_document_single(id, title, kind, content, tags) + else: + # Large document: chunked upload + return self._add_document_chunked(id, title, kind, content, tags) + + def _add_document_chunked(self, id, title, kind, content, tags): + # 1. begin-upload + session = self._begin_upload( + document_metadata={...}, + total_size=len(content), + chunk_size=5 * 1024 * 1024 + ) + + # 2. upload-chunk for each chunk + for i, chunk in enumerate(self._chunk_bytes(content, session.chunk_size)): + self._upload_chunk(session.upload_id, i, chunk) + + # 3. complete-upload + return self._complete_upload(session.upload_id) +``` + +**Callbacks de progreso** (mejora opcional): + +```python +def add_document(self, ..., on_progress=None): + """ + on_progress: Optional callback(bytes_sent, total_bytes) + """ +``` + +Esto permite que las interfaces de usuario muestren el progreso de la carga sin cambiar la API básica. + +#### Herramientas de línea de comandos + +**`tg-add-library-document`** continúa funcionando sin cambios: + +```bash +# Works transparently for any size - SDK handles chunking internally +tg-add-library-document --file large-report.pdf --title "Large Report" +``` + +Se podría agregar una visualización opcional del progreso: + +```bash +tg-add-library-document --file large-report.pdf --title "Large Report" --progress +# Output: +# Uploading: 45% (225MB / 500MB) +``` + +**Herramientas heredadas eliminadas:** + +`tg-load-pdf` - obsoleto, usar `tg-add-library-document` +`tg-load-text` - obsoleto, usar `tg-add-library-document` + +**Comandos de administración/depuración** (opcional, baja prioridad): + +```bash +# List incomplete uploads (admin troubleshooting) +tg-add-library-document --list-pending + +# Resume specific upload (recovery scenario) +tg-add-library-document --resume upload-abc-123 --file large-report.pdf +``` + +Estas podrían ser banderas en el comando existente en lugar de herramientas separadas. + +#### Actualizaciones de la Especificación de la API + +La especificación OpenAPI (`specs/api/paths/librarian.yaml`) necesita actualizaciones para: + +**Nuevas operaciones:** + +`begin-upload` - Inicializar sesión de carga por partes +`upload-chunk` - Cargar parte individual +`complete-upload` - Finalizar carga +`abort-upload` - Cancelar carga +`get-upload-status` - Consultar el progreso de la carga +`list-uploads` - Listar cargas incompletas para el usuario +`stream-document` - Recuperación de documentos en streaming +`add-child-document` - Almacenar texto extraído (interno) +`list-children` - Listar documentos secundarios (administrador) + +**Operaciones modificadas:** + +`list-documents` - Agregar parámetro `include-children` + +**Nuevos esquemas:** + +`ChunkedUploadBeginRequest` +`ChunkedUploadBeginResponse` +`ChunkedUploadChunkRequest` +`ChunkedUploadChunkResponse` +`UploadSession` +`UploadProgress` + +**Actualizaciones de la especificación WebSocket** (`specs/websocket/`): + +Reflejar las operaciones REST para clientes WebSocket, lo que permite actualizaciones de progreso en tiempo real +durante la carga. + +#### Consideraciones de la Experiencia de Usuario + +Las actualizaciones de la especificación de la API permiten mejoras en la interfaz de usuario: + +**Interfaz de usuario del progreso de la carga:** +Barra de progreso que muestra las partes cargadas +Tiempo estimado restante +Capacidad de pausa/reanudación + +**Recuperación de errores:** +Opción de "reintentar la carga" para cargas interrumpidas +Lista de cargas pendientes al reconectar + +**Manejo de archivos grandes:** +Detección del tamaño del archivo en el lado del cliente +Carga automática por partes para archivos grandes +Retroalimentación clara durante cargas largas + +Estas mejoras en la experiencia de usuario requieren trabajo en la interfaz de usuario, guiado por la especificación de la API actualizada. diff --git a/docs/tech-specs/large-document-loading.pt.md b/docs/tech-specs/large-document-loading.pt.md new file mode 100644 index 00000000..58d17e3d --- /dev/null +++ b/docs/tech-specs/large-document-loading.pt.md @@ -0,0 +1,984 @@ +# Especificação Técnica de Carregamento de Documentos Grandes + +## Visão Geral + +Esta especificação aborda problemas de escalabilidade e experiência do usuário ao carregar +documentos grandes no TrustGraph. A arquitetura atual trata o upload de documentos +como uma operação atômica única, causando pressão de memória em vários pontos do +pipeline e não fornecendo feedback ou opções de recuperação aos usuários. + +Esta implementação visa os seguintes casos de uso: + +1. **Processamento de PDF Grandes**: Fazer upload e processar arquivos PDF de centenas de megabytes + sem esgotar a memória +2. **Uploads Retomáveis**: Permitir que uploads interrompidos continuem de onde + pararam, em vez de reiniciar +3. **Feedback de Progresso**: Fornecer aos usuários visibilidade em tempo real do upload + e do progresso do processamento +4. **Processamento Eficiente em Memória**: Processar documentos de forma streaming + sem manter arquivos inteiros na memória + +## Objetivos + +**Upload Incremental**: Suportar upload de documentos em partes via REST e WebSocket +**Transferências Retomáveis**: Permitir a recuperação de uploads interrompidos +**Visibilidade do Progresso**: Fornecer feedback de upload/processamento aos clientes +**Eficiência de Memória**: Eliminar o buffer de documentos completos em todo o pipeline +**Compatibilidade com Versões Anteriores**: Os fluxos de trabalho existentes de documentos pequenos continuam inalterados +**Processamento em Streaming**: A decodificação de PDF e o particionamento de texto operam em streams + +## Contexto + +### Arquitetura Atual + +O fluxo de envio de documentos passa pelo seguinte caminho: + +1. **Cliente** envia o documento via REST (`POST /api/v1/librarian`) ou WebSocket +2. **API Gateway** recebe a solicitação completa com o conteúdo do documento codificado em base64 +3. **LibrarianRequestor** traduz a solicitação para uma mensagem Pulsar +4. **Librarian Service** recebe a mensagem, decodifica o documento na memória +5. **BlobStore** faz upload do documento para Garage/S3 +6. **Cassandra** armazena metadados com a referência do objeto +7. Para processamento: o documento é recuperado do S3, decodificado, particionado - tudo na memória + +Arquivos chave: +Ponto de entrada REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` +Núcleo do Librarian: `trustgraph-flow/trustgraph/librarian/librarian.py` +Armazenamento de blobs: `trustgraph-flow/trustgraph/librarian/blob_store.py` +Tabelas do Cassandra: `trustgraph-flow/trustgraph/tables/library.py` +Esquema da API: `trustgraph-base/trustgraph/schema/services/library.py` + +### Limitações Atuais + +O design atual apresenta vários problemas de memória e UX que se agravam: + +1. **Operação de Upload Atômica**: O documento inteiro deve ser transmitido em um + único pedido. Documentos grandes exigem solicitações de longa duração sem + indicação de progresso e sem mecanismo de repetição se a conexão falhar. + +2. **Design da API**: As APIs REST e WebSocket esperam o documento completo + em uma única mensagem. O esquema (`LibrarianRequest`) tem um campo `content` + contendo o documento inteiro codificado em base64. + +3. **Memória do Librarian**: O serviço librarian decodifica o documento inteiro + na memória antes de fazer upload para o S3. Para um PDF de 500 MB, isso significa manter + 500 MB+ na memória do processo. + +4. **Memória do Decodificador de PDF**: Quando o processamento começa, o decodificador de PDF carrega + o PDF inteiro na memória para extrair o texto. Bibliotecas como PyPDF normalmente + exigem acesso ao documento completo. + +5. **Memória do Particionador**: O particionador de texto recebe o texto extraído completo + e o mantém na memória enquanto produz os chunks. + +**Exemplo de Impacto na Memória** (PDF de 500 MB): +Gateway: ~700 MB (overhead de codificação base64) +Librarian: ~500 MB (bytes decodificados) +Decodificador de PDF: ~500 MB + buffers de extração +Particionador: texto extraído (variável, potencialmente 100 MB+) + +A memória máxima pode exceder 2 GB para um único documento grande. + +## Design Técnico + +### Princípios de Design + +1. **API Facade**: Toda a interação do cliente passa pela API do librarian. Os clientes + não têm acesso direto ou conhecimento do armazenamento subjacente S3/Garage. + +2. **Upload Multipart do S3**: Use o upload multipart padrão do S3 internamente. + Isso é amplamente suportado em sistemas compatíveis com S3 (AWS S3, MinIO, Garage, + Ceph, DigitalOcean Spaces, Backblaze B2, etc.), garantindo a portabilidade. + +3. **Conclusão Atômica**: Os uploads multipart do S3 são inerentemente atômicos - as partes carregadas + são invisíveis até que `CompleteMultipartUpload` seja chamado. Nenhum arquivo temporário ou operação de renomeação necessária. + +4. **Estado Rastreável**: As sessões de upload são rastreadas no Cassandra, fornecendo +visibilidade para uploads incompletos e permitindo a capacidade de retomada. + +### Fluxo de Upload em Partes + + +``` +Client Librarian API S3/Garage + │ │ │ + │── begin-upload ───────────►│ │ + │ (metadata, size) │── CreateMultipartUpload ────►│ + │ │◄── s3_upload_id ─────────────│ + │◄── upload_id ──────────────│ (store session in │ + │ │ Cassandra) │ + │ │ │ + │── upload-chunk ───────────►│ │ + │ (upload_id, index, data) │── UploadPart ───────────────►│ + │ │◄── etag ─────────────────────│ + │◄── ack + progress ─────────│ (store etag in session) │ + │ ⋮ │ ⋮ │ + │ (repeat for all chunks) │ │ + │ │ │ + │── complete-upload ────────►│ │ + │ (upload_id) │── CompleteMultipartUpload ──►│ + │ │ (parts coalesced by S3) │ + │ │── store doc metadata ───────►│ Cassandra + │◄── document_id ────────────│ (delete session) │ +``` + +O cliente nunca interage diretamente com o S3. O "librarian" traduz entre +nossa API de upload em partes e as operações multipart do S3 internamente. + +### Operações da API do "Librarian" + +#### `begin-upload` + +Inicializar uma sessão de upload em partes. + +Requisição: +```json +{ + "operation": "begin-upload", + "document-metadata": { + "id": "doc-123", + "kind": "application/pdf", + "title": "Large Document", + "user": "user-id", + "tags": ["tag1", "tag2"] + }, + "total-size": 524288000, + "chunk-size": 5242880 +} +``` + +Resposta: +```json +{ + "upload-id": "upload-abc-123", + "chunk-size": 5242880, + "total-chunks": 100 +} +``` + +O bibliotecário: +1. Gera um `upload_id` e `object_id` únicos (UUID para armazenamento de blobs). +2. Chama o S3 `CreateMultipartUpload`, recebe `s3_upload_id`. +3. Cria um registro de sessão no Cassandra. +4. Retorna `upload_id` para o cliente. + +#### `upload-chunk` + +Envie um único bloco. + +Requisição: +```json +{ + "operation": "upload-chunk", + "upload-id": "upload-abc-123", + "chunk-index": 0, + "content": "" +} +``` + +Resposta: +```json +{ + "upload-id": "upload-abc-123", + "chunk-index": 0, + "chunks-received": 1, + "total-chunks": 100, + "bytes-received": 5242880, + "total-bytes": 524288000 +} +``` + +O bibliotecário: +1. Busca a sessão por `upload_id` +2. Valida a propriedade (o usuário deve corresponder ao criador da sessão) +3. Chama o S3 `UploadPart` com os dados do chunk, recebe `etag` +4. Atualiza o registro da sessão com o índice do chunk e o etag +5. Retorna o progresso para o cliente + +Os chunks com falha podem ser retentados - basta enviar o mesmo `chunk-index` novamente. + +#### `complete-upload` + +Finalize o upload e crie o documento. + +Requisição: +```json +{ + "operation": "complete-upload", + "upload-id": "upload-abc-123" +} +``` + +Resposta: +```json +{ + "document-id": "doc-123", + "object-id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +O bibliotecário: +1. Consulta a sessão, verifica se todos os fragmentos foram recebidos. +2. Chama o S3 `CompleteMultipartUpload` com as etiquetas de parte (S3 combina as partes + internamente - custo de memória zero para o bibliotecário). +3. Cria um registro de documento no Cassandra com metadados e referência ao objeto. +4. Exclui o registro da sessão de upload. +5. Retorna o ID do documento para o cliente. + +#### `abort-upload` + +Cancelar um upload em andamento. + +Requisição: +```json +{ + "operation": "abort-upload", + "upload-id": "upload-abc-123" +} +``` + +O bibliotecário: +1. Chama o S3 `AbortMultipartUpload` para limpar partes. +2. Exclui o registro da sessão do Cassandra. + +#### `get-upload-status` + +Consulta o status de um upload (para a capacidade de retomada). + +Requisição: +```json +{ + "operation": "get-upload-status", + "upload-id": "upload-abc-123" +} +``` + +Resposta: +```json +{ + "upload-id": "upload-abc-123", + "state": "in-progress", + "chunks-received": [0, 1, 2, 5, 6], + "missing-chunks": [3, 4, 7, 8], + "total-chunks": 100, + "bytes-received": 36700160, + "total-bytes": 524288000 +} +``` + +#### `list-uploads` + +Listar uploads incompletos para um usuário. + +Requisição: +```json +{ + "operation": "list-uploads" +} +``` + +Resposta: +```json +{ + "uploads": [ + { + "upload-id": "upload-abc-123", + "document-metadata": { "title": "Large Document", ... }, + "progress": { "chunks-received": 43, "total-chunks": 100 }, + "created-at": "2024-01-15T10:30:00Z" + } + ] +} +``` + +### Upload de Sessão de Armazenamento + +Acompanhe uploads em andamento no Cassandra: + +```sql +CREATE TABLE upload_session ( + upload_id text PRIMARY KEY, + user text, + document_id text, + document_metadata text, -- JSON: title, kind, tags, comments, etc. + s3_upload_id text, -- internal, for S3 operations + object_id uuid, -- target blob ID + total_size bigint, + chunk_size int, + total_chunks int, + chunks_received map, -- chunk_index → etag + created_at timestamp, + updated_at timestamp +) WITH default_time_to_live = 86400; -- 24 hour TTL + +CREATE INDEX upload_session_user ON upload_session (user); +``` + +**Comportamento do TTL:** +As sessões expiram após 24 horas se não forem concluídas. +Quando o TTL do Cassandra expira, o registro da sessão é excluído. +Partes S3 órfãs são limpas pela política de ciclo de vida do S3 (configure no bucket). + +### Tratamento de Falhas e Atomicidade + +**Falha no upload de chunks:** +O cliente tenta novamente o chunk com falha (mesmo `upload_id` e `chunk-index`). +O `UploadPart` do S3 é idempotente para o mesmo número de parte. +A sessão rastreia quais chunks foram bem-sucedidos. + +**Desconexão do cliente durante o upload:** +A sessão permanece no Cassandra com os chunks recebidos registrados. +O cliente pode chamar `get-upload-status` para ver o que está faltando. +Retomar enviando apenas os chunks ausentes e, em seguida, `complete-upload`. + +**Falha no upload completo:** +O `CompleteMultipartUpload` do S3 é atômico - ou tem sucesso total ou falha. +Em caso de falha, as partes permanecem e o cliente pode tentar novamente `complete-upload`. +Nenhum documento parcial é visível. + +**Expiração da sessão:** +O TTL do Cassandra exclui o registro da sessão após 24 horas. +A política de ciclo de vida do bucket S3 limpa uploads multipartes incompletos. +Não é necessário nenhum processo de limpeza manual. + +### Atomicidade Multipart do S3 + +Os uploads multipart do S3 fornecem atomicidade integrada: + +1. **As partes são invisíveis:** As partes carregadas não podem ser acessadas como objetos. + Elas existem apenas como partes de um upload multipart incompleto. + +2. **Conclusão atômica:** `CompleteMultipartUpload` ou tem sucesso (o objeto + aparece atomicamente) ou falha (nenhum objeto é criado). Nenhum estado parcial. + +3. **Não é necessário renomear:** A chave do objeto final é especificada em + `CreateMultipartUpload`. As partes são combinadas diretamente para essa chave. + +4. **Coalescência no lado do servidor:** O S3 combina as partes internamente. O bibliotecário + nunca lê as partes de volta - nenhuma sobrecarga de memória, independentemente do tamanho do documento. + +### Extensões BlobStore + +**Arquivo:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +Adicionar métodos de upload multipart: + +```python +class BlobStore: + # Existing methods... + + def create_multipart_upload(self, object_id: UUID, kind: str) -> str: + """Initialize multipart upload, return s3_upload_id.""" + # minio client: create_multipart_upload() + + def upload_part( + self, object_id: UUID, s3_upload_id: str, + part_number: int, data: bytes + ) -> str: + """Upload a single part, return etag.""" + # minio client: upload_part() + # Note: S3 part numbers are 1-indexed + + def complete_multipart_upload( + self, object_id: UUID, s3_upload_id: str, + parts: List[Tuple[int, str]] # [(part_number, etag), ...] + ) -> None: + """Finalize multipart upload.""" + # minio client: complete_multipart_upload() + + def abort_multipart_upload( + self, object_id: UUID, s3_upload_id: str + ) -> None: + """Cancel multipart upload, clean up parts.""" + # minio client: abort_multipart_upload() +``` + +### Considerações sobre o Tamanho do Chunk + +**Mínimo do S3**: 5MB por parte (exceto a última parte) +**Máximo do S3**: 10.000 partes por upload +**Valor padrão prático**: chunks de 5MB + Documento de 500MB = 100 chunks + Documento de 5GB = 1.000 chunks +**Granularidade do progresso**: Chunks menores = atualizações de progresso mais detalhadas +**Eficiência da rede**: Chunks maiores = menos viagens de ida e volta + +O tamanho do chunk pode ser configurável pelo cliente dentro de limites (5MB - 100MB). + +### Processamento de Documentos: Recuperação em Streaming + +O fluxo de upload visa colocar documentos no armazenamento de forma eficiente. O fluxo de processamento visa extrair e dividir documentos sem carregá-los inteiramente na memória. + +#### Princípio de Design: Identificador, Não Conteúdo + + +Atualmente, quando o processamento é acionado, o conteúdo do documento flui através de mensagens Pulsar. Isso carrega documentos inteiros na memória. Em vez disso: + +As mensagens Pulsar carregam apenas o **identificador do documento** +Os processadores buscam o conteúdo do documento diretamente do "librarian" +A busca ocorre como um **stream para um arquivo temporário** +A análise específica do documento (PDF, texto, etc.) funciona com arquivos, não com buffers de memória + +Isso mantém o "librarian" independente da estrutura do documento. A análise de PDF, a extração de texto e outras lógicas específicas do formato permanecem nos decodificadores respectivos. + +#### Fluxo de Processamento + + +#### Fluxo de Processamento + +``` +Pulsar PDF Decoder Librarian S3 + │ │ │ │ + │── doc-id ───────────►│ │ │ + │ (processing msg) │ │ │ + │ │ │ │ + │ │── stream-document ──────►│ │ + │ │ (doc-id) │── GetObject ────►│ + │ │ │ │ + │ │◄── chunk ────────────────│◄── stream ───────│ + │ │ (write to temp file) │ │ + │ │◄── chunk ────────────────│◄── stream ───────│ + │ │ (append to temp file) │ │ + │ │ ⋮ │ ⋮ │ + │ │◄── EOF ──────────────────│ │ + │ │ │ │ + │ │ ┌──────────────────────────┐ │ + │ │ │ temp file on disk │ │ + │ │ │ (memory stays bounded) │ │ + │ │ └────────────┬─────────────┘ │ + │ │ │ │ + │ │ PDF library opens file │ + │ │ extract page 1 text ──► chunker │ + │ │ extract page 2 text ──► chunker │ + │ │ ⋮ │ + │ │ close file │ + │ │ delete temp file │ +``` + +#### API de fluxo do Bibliotecário + +Adicionar uma operação de recuperação de documentos em fluxo: + +**`stream-document`** + +Requisição: +```json +{ + "operation": "stream-document", + "document-id": "doc-123" +} +``` + +Resposta: Blocos binários transmitidos (não uma única resposta). + +Para a API REST, isso retorna uma resposta transmitida com `Transfer-Encoding: chunked`. + +Para chamadas internas de serviço a serviço (do processador para o bibliotecário), isso pode ser: +Transmissão direta do S3 via URL pré-assinada (se a rede interna permitir) +Respostas em blocos sobre o protocolo do serviço +Um endpoint de transmissão dedicado + +O requisito principal: os dados fluem em blocos, nunca totalmente armazenados em buffer no bibliotecário. + +#### Alterações no Decodificador PDF + +**Implementação atual** (que consome muita memória): + +```python +def decode_pdf(document_content: bytes) -> str: + reader = PdfReader(BytesIO(document_content)) # full doc in memory + text = "" + for page in reader.pages: + text += page.extract_text() # accumulating + return text # full text in memory +``` + +**Nova implementação** (arquivo temporário, incremental): + +```python +def decode_pdf_streaming(doc_id: str, librarian_client) -> Iterator[str]: + """Yield extracted text page by page.""" + + with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp: + # Stream document to temp file + for chunk in librarian_client.stream_document(doc_id): + tmp.write(chunk) + tmp.flush() + + # Open PDF from file (not memory) + reader = PdfReader(tmp.name) + + # Yield pages incrementally + for page in reader.pages: + yield page.extract_text() + + # tmp file auto-deleted on context exit +``` + +Perfil de memória: +Arquivo temporário no disco: tamanho do PDF (o disco é barato) +Na memória: uma página de texto por vez +Memória máxima: limitada, independente do tamanho do documento + +#### Alterações no decodificador de documentos de texto + +Para documentos de texto simples, ainda mais simples - nenhum arquivo temporário necessário: + +```python +def decode_text_streaming(doc_id: str, librarian_client) -> Iterator[str]: + """Yield text in chunks as it streams from storage.""" + + buffer = "" + for chunk in librarian_client.stream_document(doc_id): + buffer += chunk.decode('utf-8') + + # Yield complete lines/paragraphs as they arrive + while '\n\n' in buffer: + paragraph, buffer = buffer.split('\n\n', 1) + yield paragraph + '\n\n' + + # Yield remaining buffer + if buffer: + yield buffer +``` + +Documentos de texto podem ser transmitidos diretamente sem um arquivo temporário, pois são +estruturados linearmente. + +#### Integração com o Chunker (Fragmentador) + +O fragmentador recebe um iterador de texto (páginas ou parágrafos) e produz +fragmentos incrementalmente: + +```python +class StreamingChunker: + def __init__(self, chunk_size: int, overlap: int): + self.chunk_size = chunk_size + self.overlap = overlap + + def process(self, text_stream: Iterator[str]) -> Iterator[str]: + """Yield chunks as text arrives.""" + buffer = "" + + for text_segment in text_stream: + buffer += text_segment + + while len(buffer) >= self.chunk_size: + chunk = buffer[:self.chunk_size] + yield chunk + # Keep overlap for context continuity + buffer = buffer[self.chunk_size - self.overlap:] + + # Yield remaining buffer as final chunk + if buffer.strip(): + yield buffer +``` + +#### Pipeline de Processamento de Ponta a Ponta + +```python +async def process_document(doc_id: str, librarian_client, embedder): + """Process document with bounded memory.""" + + # Get document metadata to determine type + metadata = await librarian_client.get_document_metadata(doc_id) + + # Select decoder based on document type + if metadata.kind == 'application/pdf': + text_stream = decode_pdf_streaming(doc_id, librarian_client) + elif metadata.kind == 'text/plain': + text_stream = decode_text_streaming(doc_id, librarian_client) + else: + raise UnsupportedDocumentType(metadata.kind) + + # Chunk incrementally + chunker = StreamingChunker(chunk_size=1000, overlap=100) + + # Process each chunk as it's produced + for chunk in chunker.process(text_stream): + # Generate embeddings, store in vector DB, etc. + embedding = await embedder.embed(chunk) + await store_chunk(doc_id, chunk, embedding) +``` + +Em nenhum momento, o documento completo ou o texto extraído completo são mantidos na memória. + +#### Considerações sobre Arquivos Temporários + +**Localização**: Utilize o diretório temporário do sistema (`/tmp` ou equivalente). Para +implantações em contêineres, certifique-se de que o diretório temporário tenha espaço suficiente +e esteja em armazenamento rápido (não montado em rede, se possível). + +**Limpeza**: Utilize gerenciadores de contexto (`with tempfile...`) para garantir a limpeza +mesmo em caso de exceções. + +**Processamento concorrente**: Cada tarefa de processamento recebe seu próprio arquivo temporário. +Não há conflitos entre o processamento paralelo de documentos. + +**Espaço em disco**: Os arquivos temporários são de curta duração (duração do processamento). Para +um arquivo PDF de 500 MB, são necessários 500 MB de espaço temporário durante o processamento. O limite de tamanho pode +ser imposto no momento do upload, caso o espaço em disco seja limitado. + +### Interface de Processamento Unificada: Documentos Filhos + +A extração de PDF e o processamento de documentos de texto precisam ser integrados ao mesmo +pipeline downstream (divisão em partes → incorporações → armazenamento). Para alcançar isso com uma interface consistente de "busca por ID", os blocos de texto extraídos são armazenados de volta +no sistema de gerenciamento de documentos como documentos filhos. + +#### Fluxo de Processamento com Documentos Filhos + +Saída do contrato (deve seguir exatamente o formato abaixo). +``` +PDF Document Text Document + │ │ + ▼ │ +pdf-extractor │ + │ │ + │ (stream PDF from librarian) │ + │ (extract page 1 text) │ + │ (store as child doc → librarian) │ + │ (extract page 2 text) │ + │ (store as child doc → librarian) │ + │ ⋮ │ + ▼ ▼ +[child-doc-id, child-doc-id, ...] [doc-id] + │ │ + └─────────────────────┬───────────────────────────────┘ + ▼ + chunker + │ + │ (receives document ID) + │ (streams content from librarian) + │ (chunks incrementally) + ▼ + [chunks → embedding → storage] +``` + +O componente de divisão em partes (chunker) possui uma interface uniforme: +Recebe um ID de documento (via Pulsar) +Transmite o conteúdo do "bibliotecário" +Divide em partes + +Ele não sabe nem se importa se o ID se refere a: +Um documento de texto carregado por um usuário +Um trecho de texto extraído de uma página PDF +Qualquer tipo de documento futuro + +#### Metadados do Documento Filho + +Estenda o esquema do documento para rastrear relacionamentos pai/filho: + +```sql +-- Add columns to document table +ALTER TABLE document ADD parent_id text; +ALTER TABLE document ADD document_type text; + +-- Index for finding children of a parent +CREATE INDEX document_parent ON document (parent_id); +``` + +**Tipos de documentos:** + +| `document_type` | Descrição | +|-----------------|-------------| +| `source` | Documento carregado pelo usuário (PDF, texto, etc.) | +| `extracted` | Derivado de um documento de origem (por exemplo, texto da página de um PDF) | + +**Campos de metadados:** + +| Campo | Documento de Origem | Filho Extraído | +|-------|-----------------|-----------------| +| `id` | fornecido pelo usuário ou gerado | gerado (por exemplo, `{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | ID do documento pai | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf`, etc. | `text/plain` | +| `title` | fornecido pelo usuário | gerado (por exemplo, "Página 3 do Relatório.pdf") | +| `user` | usuário autenticado | o mesmo que o pai | + +#### API do Bibliotecário para Documentos Filhos + +**Criando documentos filhos** (interno, usado por pdf-extractor): + +```json +{ + "operation": "add-child-document", + "parent-id": "doc-123", + "document-metadata": { + "id": "doc-123-page-1", + "kind": "text/plain", + "title": "Page 1" + }, + "content": "" +} +``` + +Para pequenas extrações de texto (o texto de uma página típica é menor que 100 KB), o upload em uma única operação é aceitável. Para extrações de texto muito grandes, um upload em partes pode ser usado. + +**Listando documentos filhos** (para depuração/administração): + +**Listagem de documentos filhos** (para depuração/administração): + +```json +{ + "operation": "list-children", + "parent-id": "doc-123" +} +``` + +Resposta: +```json +{ + "children": [ + { "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" }, + { "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" }, + ... + ] +} +``` + +#### Comportamento visível ao usuário + +**`list-documents` comportamento padrão:** + +```sql +SELECT * FROM document WHERE user = ? AND parent_id IS NULL; +``` + +Apenas os documentos de nível superior (originais) aparecem na lista de documentos do usuário. +Os documentos filhos são filtrados por padrão. + +**Flag opcional "incluir_filhos"** (para administração/depuração): + +```json +{ + "operation": "list-documents", + "include-children": true +} +``` + +#### Exclusão em Cadeia + +Quando um documento pai é excluído, todos os filhos devem ser excluídos: + +```python +def delete_document(doc_id: str): + # Find all children + children = query("SELECT id, object_id FROM document WHERE parent_id = ?", doc_id) + + # Delete child blobs from S3 + for child in children: + blob_store.delete(child.object_id) + + # Delete child metadata from Cassandra + execute("DELETE FROM document WHERE parent_id = ?", doc_id) + + # Delete parent blob and metadata + parent = get_document(doc_id) + blob_store.delete(parent.object_id) + execute("DELETE FROM document WHERE id = ? AND user = ?", doc_id, user) +``` + +#### Considerações sobre Armazenamento + +Blocos de texto extraídos duplicam conteúdo: +O PDF original é armazenado no "Garage" (espaço de armazenamento). +O texto extraído por página também é armazenado no "Garage". + +Este compromisso permite: +**Interface de "chunker" uniforme**: O "chunker" sempre busca por ID. +**Retomada/repetição**: É possível reiniciar no estágio do "chunker" sem reextrair o PDF. +**Depuração**: O texto extraído pode ser inspecionado. +**Separação de responsabilidades**: O extrator de PDF e o "chunker" são serviços independentes. + +Para um PDF de 500MB com 200 páginas, com uma média de 5KB de texto por página: +Armazenamento do PDF: 500MB +Armazenamento do texto extraído: ~1MB no total +Sobrecarga: insignificante + +#### Saída do Extrator de PDF + +O extrator de PDF, após processar um documento: + +1. Transfere o PDF do "librarian" para um arquivo temporário. +2. Extrai o texto página por página. +3. Para cada página, armazena o texto extraído como um documento filho através do "librarian". +4. Envia os IDs dos documentos filhos para a fila do "chunker". +Após a última linha traduzida, fornecer uma linha final contendo exatamente: [[__END_OF_TRANSLATION__]] +```python +async def extract_pdf(doc_id: str, librarian_client, output_queue): + """Extract PDF pages and store as child documents.""" + + with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp: + # Stream PDF to temp file + for chunk in librarian_client.stream_document(doc_id): + tmp.write(chunk) + tmp.flush() + + # Extract pages + reader = PdfReader(tmp.name) + for page_num, page in enumerate(reader.pages, start=1): + text = page.extract_text() + + # Store as child document + child_id = f"{doc_id}-page-{page_num}" + await librarian_client.add_child_document( + parent_id=doc_id, + document_id=child_id, + kind="text/plain", + title=f"Page {page_num}", + content=text.encode('utf-8') + ) + + # Send to chunker queue + await output_queue.send(child_id) +``` + +O componente de divisão recebe esses IDs de elementos filhos e os processa da mesma forma que processaria um documento de texto carregado por um usuário. + +### Atualizações do Cliente + +#### SDK Python + + +O SDK Python (`trustgraph-base/trustgraph/api/library.py`) deve lidar com uploads divididos de forma transparente. A interface pública permanece inalterada: + + +```python +# Existing interface - no change for users +library.add_document( + id="doc-123", + title="Large Report", + kind="application/pdf", + content=large_pdf_bytes, # Can be hundreds of MB + tags=["reports"] +) +``` + +Internamente, o SDK detecta o tamanho do documento e alterna a estratégia: + +```python +class Library: + CHUNKED_UPLOAD_THRESHOLD = 2 * 1024 * 1024 # 2MB + + def add_document(self, id, title, kind, content, tags=None, ...): + if len(content) < self.CHUNKED_UPLOAD_THRESHOLD: + # Small document: single operation (existing behavior) + return self._add_document_single(id, title, kind, content, tags) + else: + # Large document: chunked upload + return self._add_document_chunked(id, title, kind, content, tags) + + def _add_document_chunked(self, id, title, kind, content, tags): + # 1. begin-upload + session = self._begin_upload( + document_metadata={...}, + total_size=len(content), + chunk_size=5 * 1024 * 1024 + ) + + # 2. upload-chunk for each chunk + for i, chunk in enumerate(self._chunk_bytes(content, session.chunk_size)): + self._upload_chunk(session.upload_id, i, chunk) + + # 3. complete-upload + return self._complete_upload(session.upload_id) +``` + +**Callbacks de progresso** (melhoria opcional): + +```python +def add_document(self, ..., on_progress=None): + """ + on_progress: Optional callback(bytes_sent, total_bytes) + """ +``` + +Isso permite que as interfaces de usuário exibam o progresso do upload sem alterar a API básica. + +#### Ferramentas de Linha de Comando (CLI) + +**`tg-add-library-document`** continua a funcionar inalterado: + +```bash +# Works transparently for any size - SDK handles chunking internally +tg-add-library-document --file large-report.pdf --title "Large Report" +``` + +Uma exibição de progresso opcional pode ser adicionada: + +```bash +tg-add-library-document --file large-report.pdf --title "Large Report" --progress +# Output: +# Uploading: 45% (225MB / 500MB) +``` + +**Ferramentas legadas removidas:** + +`tg-load-pdf` - descontinuado, use `tg-add-library-document` +`tg-load-text` - descontinuado, use `tg-add-library-document` + +**Comandos de administração/depuração** (opcional, baixa prioridade): + +```bash +# List incomplete uploads (admin troubleshooting) +tg-add-library-document --list-pending + +# Resume specific upload (recovery scenario) +tg-add-library-document --resume upload-abc-123 --file large-report.pdf +``` + +Estes poderiam ser flags no comando existente, em vez de ferramentas separadas. + +#### Atualizações da Especificação da API + +A especificação OpenAPI (`specs/api/paths/librarian.yaml`) precisa de atualizações para: + +**Novas operações:** + +`begin-upload` - Inicializar sessão de upload em partes +`upload-chunk` - Enviar parte individual +`complete-upload` - Finalizar upload +`abort-upload` - Cancelar upload +`get-upload-status` - Consultar o progresso do upload +`list-uploads` - Listar uploads incompletos para o usuário +`stream-document` - Recuperação de documentos em streaming +`add-child-document` - Armazenar texto extraído (interno) +`list-children` - Listar documentos filhos (administrador) + +**Operações modificadas:** + +`list-documents` - Adicionar parâmetro `include-children` + +**Novos esquemas:** + +`ChunkedUploadBeginRequest` +`ChunkedUploadBeginResponse` +`ChunkedUploadChunkRequest` +`ChunkedUploadChunkResponse` +`UploadSession` +`UploadProgress` + +**Atualizações da especificação WebSocket** (`specs/websocket/`): + +Espelhe as operações REST para clientes WebSocket, permitindo atualizações de progresso em tempo real +durante o upload. + +#### Considerações de UX + +As atualizações da especificação da API permitem melhorias na interface do usuário: + +**Interface do usuário de progresso do upload:** +Barra de progresso mostrando as partes enviadas +Tempo estimado restante +Capacidade de pausar/retomar + +**Recuperação de erros:** +Opção "retomar upload" para uploads interrompidos +Lista de uploads pendentes na reconexão + +**Tratamento de arquivos grandes:** +Detecção do tamanho do arquivo no lado do cliente +Upload automático em partes para arquivos grandes +Feedback claro durante uploads longos + +Essas melhorias de UX exigem trabalho na interface do usuário, guiado pela especificação da API atualizada. diff --git a/docs/tech-specs/large-document-loading.sw.md b/docs/tech-specs/large-document-loading.sw.md new file mode 100644 index 00000000..abd88a17 --- /dev/null +++ b/docs/tech-specs/large-document-loading.sw.md @@ -0,0 +1,984 @@ +# Vipimo vya Utekelezaji wa Teknolojia ya Kupakia Hati Kubwa + +## Muhtasari + +Maelekezo haya yanaeleza masuala ya uwezo wa kufanya kazi na uzoefu wa mtumiaji wakati wa kupakia +hati kubwa katika TrustGraph. Muundo wa sasa hutumia kupakia hati kama operesheni moja, na kusababisha +shinikizo la kumbukumbu katika hatua nyingi za mchakato na kutoa maelezo au chaguo za kurejesha kwa watumiaji. + + +Utaratibu huu unalenga matumizi yafuatayo: + +1. **Uchakataji wa Hati za PDF Kubwa**: Kupakia na kuchakata faili za PDF zenye mamia ya megabytes + bila kutumia kumbukumbu yote. +2. **Kupakia Ambayo Inaweza Kuendelea**: Kuruhusu kupakia ambacho kimetokea kukatika kuendelea kutoka + ambapo kilisimama badala ya kuanza tena. +3. **Maelezo ya Maendeleo**: Kutoa kwa watumiaji maelezo ya muda halisi kuhusu maendeleo ya + kupakia na uchakataji. +4. **Uchakataji Wenye Ufanisi wa Kumbukumbu**: Kuchakata hati kwa njia ya mtiririko + bila kuhifadhi faili zilizokamilika katika kumbukumbu. + +## Lengo + +**Kupakia kwa Awamu**: Kusaidia kupakia hati kwa sehemu kupitia REST na WebSocket +**Uhamisho Unaoweza Kuendelea**: Kuruhusu kurejesha kutoka kupakia ambacho kimetokea kukatika +**Uonekana wa Maendeleo**: Kutoa maelezo ya maendeleo ya kupakia/uchakataji kwa wateja +**Ufanisi wa Kumbukumbu**: Kuondoa uhifadhi wa hati zilizokamilika katika mchakato wote +**Ulinganifu na Mifumo ya Zamani**: Mchakato wa sasa wa hati ndogo unaendelea bila mabadiliko +**Uchakataji wa Mtiririko**: Ufichuzi na uainishaji wa maandishi hufanywa kwa kutumia mitiririko + +## Asili + +### Muundo wa Sasa + +Hati zinatumiwa kupitia njia ifuatayo: + +1. **Mteja** hutuma hati kupitia REST (`POST /api/v1/librarian`) au WebSocket +2. **Lango la API** linapokea ombi kamili lenye maudhui ya hati yaliyokuzwa kwa msingi 64 +3. **LibrarianRequestor** huongeza ombi kwenye ujumbe wa Pulsar +4. **Huduma ya Librarian** inapokea ujumbe, huondoa maudhui ya hati katika kumbukumbu +5. **BlobStore** huhamisha hati kwenye Garage/S3 +6. **Cassandra** huhifadhi metadata pamoja na rejea ya kitu +7. Kwa uchakataji: hati inavyolewa kutoka S3, huondoa maudhui, huainishwa—yote katika kumbukumbu + +Faili muhimu: +Ingizo la REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` +Msingi wa Librarian: `trustgraph-flow/trustgraph/librarian/librarian.py` +Uhifadhi wa blob: `trustgraph-flow/trustgraph/librarian/blob_store.py` +Jedwali la Cassandra: `trustgraph-flow/trustgraph/tables/library.py` +Mpango wa API: `trustgraph-base/trustgraph/schema/services/library.py` + +### Mapungufu ya Sasa + +Muundo wa sasa una masuala kadhaa ambayo huathiri kumbukumbu na uzoefu wa mtumiaji: + +1. **Operesheni ya Kupakia ya Atomiki**: Hati nzima lazima ihamishwe katika + ombi moja. Hati kubwa zinahitaji ombi linalodumu kwa muda mrefu bila + maelezo ya maendeleo na hakuna njia ya kujaribu tena ikiwa muunganisho utakatika. + +2. **Muundo wa API**: API za REST na WebSocket zinatarajia hati + nzima katika ujumbe mmoja. Mpango (`LibrarianRequest`) una `content` + ambayo ina maudhui ya hati nzima yaliyokuzwa kwa msingi 64. + +3. **Kumbukumbu ya Librarian**: Huduma ya librarian huondoa maudhui ya hati + katika kumbukumbu kabla ya kuihamisha kwenye S3. Kwa PDF ya 500MB, hii inamaanisha + kuhifadhi 500MB+ katika kumbukumbu ya mchakato. + +4. **Kumbukumbu ya Kufichua PDF**: Wakati wa uchakataji, programu ya kufichua PDF + huhamisha hati nzima katika kumbukumbu ili kuchimbua maandishi. Maktaba kama vile PyPDF + zinaweza kuhitaji upataji wa hati nzima. + +5. **Kumbukumbu ya Kifaa cha Kuchakata**: Kifaa cha kuchakata maandishi hupokea maandishi + yaliyochimbuliwa na kuhifadhi katika kumbukumbu huku huchakata na kuunda sehemu. + +**Mfano wa Athari ya Kumbukumbu** (PDF ya 500MB): +Lango: ~700MB (maudhui yaliyokuzwa) +Librarian: ~500MB (bytes zilizofichuliwa) +Kifaa cha Kufichua PDF: ~500MB + buffers za uchimbaji +Kifaa cha Kuchakata: maandishi yaliyochimbuliwa (hubadilika, inaweza kuwa 100MB+) + +Kumbukumbu ya juu inaweza kuzidi 2GB kwa hati kubwa moja. + +## Muundo wa Kiufundi + +### Kanuni za Muundo + +1. **Uhusiano wa API**: Mwingiliano wote wa mteja hupitia API ya librarian. Wateja + hawana upataji wa moja kwa moja au kujua kuhusu uhifadhi wa S3/Garage. + +2. **Kupakia kwa Sehemu ya S3**: Tumia kupakia kwa sehemu ya S3. + Hii inasaidiwa kwa mfumo wowote unaolingana na S3 (AWS S3, MinIO, Garage, + Ceph, DigitalOcean Spaces, Backblaze B2, n.k.) kuhakikisha uwezekano wa kuhamishwa. + +3. **Kukamilika kwa Atomiki**: Kupakia kwa sehemu ya S3 kunaweza kukamilika kwa atomiki - sehemu + zilizopakiwa hazionekani hadi `CompleteMultipartUpload` itakapopigwa. + Hakuna faili za muda au operesheni za kubadilisha. + +4. **Hali Inayoweza Kufuatiliwa**: Vipindi vya kupakia hufuatiliwa katika Cassandra, kutoa + uonevu kuhusu kupakia ambacho hakikamilika na kuruhusu uwezo wa kuanza tena. + +### Mchakato wa Kupakia kwa Sehemu + +``` +Client Librarian API S3/Garage + │ │ │ + │── begin-upload ───────────►│ │ + │ (metadata, size) │── CreateMultipartUpload ────►│ + │ │◄── s3_upload_id ─────────────│ + │◄── upload_id ──────────────│ (store session in │ + │ │ Cassandra) │ + │ │ │ + │── upload-chunk ───────────►│ │ + │ (upload_id, index, data) │── UploadPart ───────────────►│ + │ │◄── etag ─────────────────────│ + │◄── ack + progress ─────────│ (store etag in session) │ + │ ⋮ │ ⋮ │ + │ (repeat for all chunks) │ │ + │ │ │ + │── complete-upload ────────►│ │ + │ (upload_id) │── CompleteMultipartUpload ──►│ + │ │ (parts coalesced by S3) │ + │ │── store doc metadata ───────►│ Cassandra + │◄── document_id ────────────│ (delete session) │ +``` + +Mteja hawezi kuwasiliana na S3 moja kwa moja. Msimamizi (librarian) hutafsiri kati ya +API yetu ya kupakia vipande na operesheni za S3 za sehemu nyingi (multipart) kwa ndani. + +### Operesheni za API ya Msimamizi (Librarian) + +#### `begin-upload` + +Anzisha kipindi cha kupakia vipande. + +Ombi: +```json +{ + "operation": "begin-upload", + "document-metadata": { + "id": "doc-123", + "kind": "application/pdf", + "title": "Large Document", + "user": "user-id", + "tags": ["tag1", "tag2"] + }, + "total-size": 524288000, + "chunk-size": 5242880 +} +``` + +Jibu: +```json +{ + "upload-id": "upload-abc-123", + "chunk-size": 5242880, + "total-chunks": 100 +} +``` + +Msimamizi wa maktaba: +1. Huunda nambari ya kipekee `upload_id` na `object_id` (UUID kwa uhifadhi wa data). +2. Huita `CreateMultipartUpload` ya S3, na kupokea `s3_upload_id`. +3. Huunda rekodi ya kikao katika Cassandra. +4. Hurudisha `upload_id` kwa mteja. + +#### `upload-chunk` + +Pakia kipande kimoja. + +Ombi: +```json +{ + "operation": "upload-chunk", + "upload-id": "upload-abc-123", + "chunk-index": 0, + "content": "" +} +``` + +Jibu: +```json +{ + "upload-id": "upload-abc-123", + "chunk-index": 0, + "chunks-received": 1, + "total-chunks": 100, + "bytes-received": 5242880, + "total-bytes": 524288000 +} +``` + +Msimamizi wa maktaba: +1. Tafuta kikao kwa kutumia `upload_id` +2. Thibitisha umiliki (mtumiaji lazima awe yule aliyeunda kikao) +3. Piga simu kwa S3 `UploadPart` pamoja na data ya sehemu, na upokee `etag` +4. Sasisha rekodi ya kikao na fahirisi ya sehemu na etag +5. Rejesha maelezo ya maendeleo kwa mteja + +Sehemu ambazo hazijafaulu zinaweza kujaribiwa tena - tuma tu `chunk-index` tena. + +#### `complete-upload` + +Hakisha upakiaji na uunde hati. + +Ombi: +```json +{ + "operation": "complete-upload", + "upload-id": "upload-abc-123" +} +``` + +Jibu: +```json +{ + "document-id": "doc-123", + "object-id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +Msimamizi wa maktaba: +1. Tafuta kikao, thibitisha kwamba vipande vyote vimepokelewa +2. Anapiga S3 `CompleteMultipartUpload` na etags za sehemu (S3 huunganisha sehemu + ndani - hakuna gharama ya kumbukumbu kwa msimamizi) +3. Huunda rekodi ya hati katika Cassandra na metadata na rejeleo la kitu +4. Huondoa rekodi ya kikao cha kupakia +5. Hurudisha kitambulisho cha hati kwa mteja + +#### `abort-upload` + +Kuacha kupakia ambacho kinaendelea. + +Ombi: +```json +{ + "operation": "abort-upload", + "upload-id": "upload-abc-123" +} +``` + +Msimamizi wa maktaba: +1. Anapiga simu kwa S3 `AbortMultipartUpload` ili kusafisha sehemu. +2. Anafuta rekodi ya kikao kutoka Cassandra. + +#### `get-upload-status` + +Angalia hali ya kupakia (kwa uwezo wa kuendelea). + +Ombi: +```json +{ + "operation": "get-upload-status", + "upload-id": "upload-abc-123" +} +``` + +Jibu: +```json +{ + "upload-id": "upload-abc-123", + "state": "in-progress", + "chunks-received": [0, 1, 2, 5, 6], + "missing-chunks": [3, 4, 7, 8], + "total-chunks": 100, + "bytes-received": 36700160, + "total-bytes": 524288000 +} +``` + +#### `list-uploads` + +Orodha ya vipakuliwa ambavyo havijakamilika kwa mtumiaji. + +Ombi: +```json +{ + "operation": "list-uploads" +} +``` + +Jibu: +```json +{ + "uploads": [ + { + "upload-id": "upload-abc-123", + "document-metadata": { "title": "Large Document", ... }, + "progress": { "chunks-received": 43, "total-chunks": 100 }, + "created-at": "2024-01-15T10:30:00Z" + } + ] +} +``` + +### Hifadhi ya Kipindi cha Uipakaji + +Fuatilia uipakaji unaoendelea katika Cassandra: + +```sql +CREATE TABLE upload_session ( + upload_id text PRIMARY KEY, + user text, + document_id text, + document_metadata text, -- JSON: title, kind, tags, comments, etc. + s3_upload_id text, -- internal, for S3 operations + object_id uuid, -- target blob ID + total_size bigint, + chunk_size int, + total_chunks int, + chunks_received map, -- chunk_index → etag + created_at timestamp, + updated_at timestamp +) WITH default_time_to_live = 86400; -- 24 hour TTL + +CREATE INDEX upload_session_user ON upload_session (user); +``` + +**Tabia ya TTL:** +Vikao hupotea baada ya saa 24 ikiwa havijakamilika. +Wakati TTL ya Cassandra inapita, rekodi ya kikao inafutwa. +Sehemu zisizo na uhusiano za S3 huondolewa na sera ya maisha ya S3 (sanidi kwenye ndoo). + +### Usimamizi wa Hitilafu na Uadilifu + +**Hitilafu ya kupakia sehemu:** +Mteja hurudia kupakia sehemu iliyoshindwa (na `upload_id` na `chunk-index` sawa). +`UploadPart` ya S3 ni sawa kwa nambari sawa ya sehemu. +Kikao kinafuatilia sehemu zipi zilizofanikiwa. + +**Mteja hukatika wakati wa kupakia:** +Kikao kinaendelea katika Cassandra na sehemu zilizopokelewa zimeandikwa. +Mteja anaweza kupiga `get-upload-status` ili kuona nini kinakosekana. +Anza tena kwa kupakia sehemu ambazo hazijapakiwa, kisha `complete-upload`. + +**Hitilafu ya kupakia kikamilifu:** +`CompleteMultipartUpload` ya S3 ni ya uadilifu - inaweza kufanikiwa kikamilifu au kushindwa. +Katika hali ya kushindwa, sehemu zinaendelea na mteja anaweza kujaribu tena `complete-upload`. +Hati yoyote ya nusu haionekani. + +**Kumalizika kwa kikao:** +TTL ya Cassandra inafuta rekodi ya kikao baada ya saa 24. +Sera ya maisha ya ndoo ya S3 husafisha kupakia kwa sehemu nyingi ambazo hazijakamilika. +Hakuna usafishaji wa mwongozo unaohitajika. + +### Uadilifu wa Sehemu Nyingi za S3 + +Kupakia kwa sehemu nyingi za S3 hutoa uadilifu uliopo: + +1. **Sehemu hazionekani:** Sehemu zilizopakuliwa haziwezi kupatikana kama vitu. + Zipo tu kama sehemu za kupakia kwa sehemu nyingi ambazo hazijakamilika. + +2. **Kukamilisha kwa uadilifu:** `CompleteMultipartUpload` inaweza kufanikiwa (kitu + kinaonekana kwa uadilifu) au kushindwa (hakuna kitu kilichoanzishwa). Hakuna hali ya nusu. + +3. **Hakuna jina tena linalohitajika:** Ufunguo wa mwisho wa kitu unaonyeshwa wakati + `CreateMultipartUpload`. Sehemu huunganishwa moja kwa moja kwenye ufunguo huo. + +4. **Uunganishaji wa upande wa seva:** S3 inaunganisha sehemu ndani. Msimamizi + haisomi sehemu - hakuna gharama ya kumbukumbu bila kujali ukubwa wa hati. + +### Upanuzi wa BlobStore + +**Faili:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +Ongeza mbinu za kupakia sehemu nyingi: + +```python +class BlobStore: + # Existing methods... + + def create_multipart_upload(self, object_id: UUID, kind: str) -> str: + """Initialize multipart upload, return s3_upload_id.""" + # minio client: create_multipart_upload() + + def upload_part( + self, object_id: UUID, s3_upload_id: str, + part_number: int, data: bytes + ) -> str: + """Upload a single part, return etag.""" + # minio client: upload_part() + # Note: S3 part numbers are 1-indexed + + def complete_multipart_upload( + self, object_id: UUID, s3_upload_id: str, + parts: List[Tuple[int, str]] # [(part_number, etag), ...] + ) -> None: + """Finalize multipart upload.""" + # minio client: complete_multipart_upload() + + def abort_multipart_upload( + self, object_id: UUID, s3_upload_id: str + ) -> None: + """Cancel multipart upload, clean up parts.""" + # minio client: abort_multipart_upload() +``` + +### Mambo Yanayohusiana na Ukubwa wa Sehemu + +**Kiwango cha chini cha S3**: 5MB kwa kila sehemu (isipokuwa sehemu ya mwisho) +**Kiwango cha juu cha S3**: Sehemu 10,000 kwa kila upakiaji +**Kiwango cha kawaida kinachopendekezwa**: Sehemu za 5MB + Hati ya 500MB = sehemu 100 + Hati ya 5GB = sehemu 1,000 +**Ufuatiliaji wa maendeleo**: Sehemu ndogo = taarifa za maendeleo bora +**Ufanisi wa mtandao**: Sehemu kubwa = safari ndogo + +Ukubwa wa sehemu unaweza kupangwa na mtumiaji ndani ya mipaka (5MB - 100MB). + +### Ufuatiliaji wa Hati: Upakiaji wa Kiasi + +Mchakato wa upakiaji unalenga kuweka hati kwenye hifadhi kwa ufanisi. Mchakato +wa ufuatiliaji unalenga kuchuja na kugawanya hati bila kuzipakia +zote kwenye kumbukumbu. + +#### Kanuni ya Ubunifu: Kitambulisho, Sio Yaliyomo + +Kwa sasa, wakati mchakato unaanza, yaliyomo kwenye hati huhamishwa kupitia +ujumbe wa Pulsar. Hii inapakia hati zote kwenye kumbukumbu. Badala yake: + +Ujumbe wa Pulsar unaonyesha tu **kitambulisho cha hati** +Vifaa vya ufuatiliaji hupata yaliyomo kwenye hati moja kwa moja kutoka kwa mfumo +Kupata hufanyika kama **mtiririko kwenye faili ya muda** +Ufuatiliaji maalum wa hati (PDF, maandishi, n.k.) hufanya kazi na faili, sio +mipaka ya kumbukumbu + +Hii inahakikisha kwamba mfumo wa hati hautegemei muundo wa hati. Ufuatiliaji +wa PDF, ufuatiliaji wa maandishi, na mantiki nyingine maalum ya muundo +inabaki katika vichujio husika. + +``` +Pulsar PDF Decoder Librarian S3 + │ │ │ │ + │── doc-id ───────────►│ │ │ + │ (processing msg) │ │ │ + │ │ │ │ + │ │── stream-document ──────►│ │ + │ │ (doc-id) │── GetObject ────►│ + │ │ │ │ + │ │◄── chunk ────────────────│◄── stream ───────│ + │ │ (write to temp file) │ │ + │ │◄── chunk ────────────────│◄── stream ───────│ + │ │ (append to temp file) │ │ + │ │ ⋮ │ ⋮ │ + │ │◄── EOF ──────────────────│ │ + │ │ │ │ + │ │ ┌──────────────────────────┐ │ + │ │ │ temp file on disk │ │ + │ │ │ (memory stays bounded) │ │ + │ │ └────────────┬─────────────┘ │ + │ │ │ │ + │ │ PDF library opens file │ + │ │ extract page 1 text ──► chunker │ + │ │ extract page 2 text ──► chunker │ + │ │ ⋮ │ + │ │ close file │ + │ │ delete temp file │ +``` + +#### API ya Mfumo wa Maktaba + +Ongeza operesheni ya upataji wa hati kwa njia ya mtiririko: + +**`stream-document`** + +Ombi: +```json +{ + "operation": "stream-document", + "document-id": "doc-123" +} +``` + +Jibu: Vipande vya binary vilivyotumwa (si jibu moja). + +Kwa API ya REST, hii hurudisha jibu linaloendelea kwa kutumia `Transfer-Encoding: chunked`. + +Kwa simu za ndani kati ya huduma (kwa mfumo wa uprosesa hadi mfumo wa kumbukumbu), hii inaweza kuwa: +Uhamisho wa moja kwa moja wa S3 kupitia URL iliyosainiwa (ikiwa mtandao wa ndani unaruhusu). +Majibu yaliyogawanywa kupitia itifaki ya huduma. +Kituo maalum cha utumaji wa data. + +Mahitaji muhimu: data inatiririka kwa vipande, haijahifadhiwa kikamilifu katika mfumo wa kumbukumbu. + +#### Mabadiliko ya Kipanguli cha PDF + +**Utendaji wa sasa** (unaotumia kumbukumbu nyingi): + +```python +def decode_pdf(document_content: bytes) -> str: + reader = PdfReader(BytesIO(document_content)) # full doc in memory + text = "" + for page in reader.pages: + text += page.extract_text() # accumulating + return text # full text in memory +``` + +**Utekelezaji mpya** (faili ya muda, hatua kwa hatua): + +```python +def decode_pdf_streaming(doc_id: str, librarian_client) -> Iterator[str]: + """Yield extracted text page by page.""" + + with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp: + # Stream document to temp file + for chunk in librarian_client.stream_document(doc_id): + tmp.write(chunk) + tmp.flush() + + # Open PDF from file (not memory) + reader = PdfReader(tmp.name) + + # Yield pages incrementally + for page in reader.pages: + yield page.extract_text() + + # tmp file auto-deleted on context exit +``` + +Profaili ya kumbukumbu: +Faili ya muda kwenye diski: ukubwa wa faili ya PDF (diski ni rahisi). +Katika kumbukumbu: ukurasa mmoja wa maandishi kwa wakati. +Kumbukumbu ya juu: imepunguzwa, haitegemei saizi ya hati. + +#### Mabadiliko ya Kipanguli cha Hati za Nakshata + +Kwa hati za nakshata, rahisi zaidi - hakuna faili ya muda inayohitajika: + +```python +def decode_text_streaming(doc_id: str, librarian_client) -> Iterator[str]: + """Yield text in chunks as it streams from storage.""" + + buffer = "" + for chunk in librarian_client.stream_document(doc_id): + buffer += chunk.decode('utf-8') + + # Yield complete lines/paragraphs as they arrive + while '\n\n' in buffer: + paragraph, buffer = buffer.split('\n\n', 1) + yield paragraph + '\n\n' + + # Yield remaining buffer + if buffer: + yield buffer +``` + +Hati za maandishi zinaweza kutiririka moja kwa moja bila faili ya muda kwa sababu zina +muundo wa mstari. + +#### Jumuisho la Kifaa cha Kugawa (Chunker) + +Kifaa cha kugawa hupokea mfuatiliaji wa maandishi (kurasa au aya) na hutoa +vipande kwa hatua kwa hatua: + +```python +class StreamingChunker: + def __init__(self, chunk_size: int, overlap: int): + self.chunk_size = chunk_size + self.overlap = overlap + + def process(self, text_stream: Iterator[str]) -> Iterator[str]: + """Yield chunks as text arrives.""" + buffer = "" + + for text_segment in text_stream: + buffer += text_segment + + while len(buffer) >= self.chunk_size: + chunk = buffer[:self.chunk_size] + yield chunk + # Keep overlap for context continuity + buffer = buffer[self.chunk_size - self.overlap:] + + # Yield remaining buffer as final chunk + if buffer.strip(): + yield buffer +``` + +#### Mchakato Kamili wa Uendeshaji + +```python +async def process_document(doc_id: str, librarian_client, embedder): + """Process document with bounded memory.""" + + # Get document metadata to determine type + metadata = await librarian_client.get_document_metadata(doc_id) + + # Select decoder based on document type + if metadata.kind == 'application/pdf': + text_stream = decode_pdf_streaming(doc_id, librarian_client) + elif metadata.kind == 'text/plain': + text_stream = decode_text_streaming(doc_id, librarian_client) + else: + raise UnsupportedDocumentType(metadata.kind) + + # Chunk incrementally + chunker = StreamingChunker(chunk_size=1000, overlap=100) + + # Process each chunk as it's produced + for chunk in chunker.process(text_stream): + # Generate embeddings, store in vector DB, etc. + embedding = await embedder.embed(chunk) + await store_chunk(doc_id, chunk, embedding) +``` + +Katika hakuna hatua, hati kamili au maandishi yaliyotolewa kamili hayahifadhiwi kwenye kumbukumbu. + +#### Mambo Yanayohusiana na Faili za Muda + +**Mahali:** Tumia saraka ya muda ya mfumo (`/tmp` au sawa). Kwa +matumizi yaliyojumuishwa, hakikisha saraka ya muda ina nafasi ya kutosha +na iko kwenye uhifadhi wa haraka (si iliyounganishwa kwenye mtandao, ikiwezekana). + +**Usafishaji:** Tumia menejeria wa muktadha (`with tempfile...`) ili kuhakikisha usafishaji +hata wakati wa hitilafu. + +**Uchakataji sambamba:** Kazi kila moja ya uchakataji hupata faili yake ya muda. +Hakuna migogoro kati ya uchakataji wa hati sambamba. + +**Nafasi ya diski:** Faili za muda zina muda mfupi (muda wa uchakataji). Kwa +hati ya PDF ya 500MB, inahitaji nafasi ya muda ya 500MB wakati wa uchakataji. Kikomo cha ukubwa +kinaweza kutekelezwa wakati wa kupakia ikiwa nafasi ya diski ni mdogo. + +### Kiolesura Kimoja cha Uchakataji: Hati za Mtoto + +Uchimbaji wa hati za PDF na uchakataji wa hati za maandishi lazima ziingie katika +mstari mmoja wa baadaye (kugawanya → embeddings → uhifadhi). Ili kufanikisha hili kwa +"kupata kwa ID" kiolesura, vipande vya maandishi vilivyochimbwa huhifadhiwa tena +kwenye mfumo kama hati za mtoto. + +#### Mchakato wa Uchakataji na Hati za Mtoto + +``` +PDF Document Text Document + │ │ + ▼ │ +pdf-extractor │ + │ │ + │ (stream PDF from librarian) │ + │ (extract page 1 text) │ + │ (store as child doc → librarian) │ + │ (extract page 2 text) │ + │ (store as child doc → librarian) │ + │ ⋮ │ + ▼ ▼ +[child-doc-id, child-doc-id, ...] [doc-id] + │ │ + └─────────────────────┬───────────────────────────────┘ + ▼ + chunker + │ + │ (receives document ID) + │ (streams content from librarian) + │ (chunks incrementally) + ▼ + [chunks → embedding → storage] +``` + +Kifaa cha kuainisha (chunker) kina muundo mmoja wa kiungo: +Pokea kitambulisho cha hati (kupitia Pulsar) +Pumua yaliyomo kutoka kwa mfumo wa kumbukumbu (librarian) +Igawanye katika sehemu ndogo + +Haijulishi au hajali kama kitambulisho kinarejelea: +Hati ya maandishi iliyopakiwa na mtumiaji +Sehemu ya maandishi iliyochimbwa kutoka kwa ukurasa wa PDF +Aina yoyote ya hati ya siku zijazo + +#### Meta-data ya Hati Ndogo + +Panua muundo wa hati ili kufuatilia uhusiano wa mzazi/mtoto: + +```sql +-- Add columns to document table +ALTER TABLE document ADD parent_id text; +ALTER TABLE document ADD document_type text; + +-- Index for finding children of a parent +CREATE INDEX document_parent ON document (parent_id); +``` + +**Aina za nyaraka:** + +| `document_type` | Maelezo | +|-----------------|-------------| +| `source` | Nyaraka zilizopakiwa na mtumiaji (PDF, maandishi, n.k.) | +| `extracted` | Zilizotokana na nyaraka asili (k.m., maandishi ya ukurasa wa PDF) | + +**Nafasi za metadata:** + +| Nafasi | Nyaraka Asili | Nyaraka Zilizotokana | +|-------|-----------------|-----------------| +| `id` | Zilizotolewa na mtumiaji au zilizoundwa | Zilizoundwa (k.m., `{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | Kitambulisho cha nyaraka asili | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf`, n.k. | `text/plain` | +| `title` | Zilizotolewa na mtumiaji | Zilizoundwa (k.m., "Ukurasa wa 3 wa Ripoti.pdf") | +| `user` | Mtumiaji aliyeidhinishwa | Sawa na nyaraka asili | + +#### API ya Maktaba kwa Nyaraka Zilizotokana + +**Kuunda nyaraka zilizotokana** (ya ndani, hutumiwa na pdf-extractor): + +```json +{ + "operation": "add-child-document", + "parent-id": "doc-123", + "document-metadata": { + "id": "doc-123-page-1", + "kind": "text/plain", + "title": "Page 1" + }, + "content": "" +} +``` + +Kwa maandishi madogo ambayo yamechukuliwa (maandishi ya kawaida ya ukurasa ni chini ya 100KB), kupakia kwa operesheni moja ni sawa. Kwa matamshi makubwa sana ya maandishi, kupakia kwa sehemu kunaweza kutumika. + +**Orodha ya hati za watoto** (kwa ajili ya utatuzi/utawala): + + + +```json +{ + "operation": "list-children", + "parent-id": "doc-123" +} +``` + +Jibu: +```json +{ + "children": [ + { "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" }, + { "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" }, + ... + ] +} +``` + +#### Tabia inayoonwa na mtumiaji + +**Tabia ya kawaida ya `list-documents`:** + +```sql +SELECT * FROM document WHERE user = ? AND parent_id IS NULL; +``` + +Tuandishi kuu (vyanzo) pekee ndivyo yanavyoonekana kwenye orodha ya vyanzo vya mtumiaji. +Vyanzo vidogo huondolewa kwa chaguo-msingi. + +**Bendera ya hiari ya kujumuisha-vyanzo-vidogo** (kwa wasimamizi/uchunguzi): + +```json +{ + "operation": "list-documents", + "include-children": true +} +``` + +#### Ufutilishaji wa Kuondoa Data kwa Kadirio + +Wakati hati mama inapoondolewa, watoto wote lazima waondolewe: + +```python +def delete_document(doc_id: str): + # Find all children + children = query("SELECT id, object_id FROM document WHERE parent_id = ?", doc_id) + + # Delete child blobs from S3 + for child in children: + blob_store.delete(child.object_id) + + # Delete child metadata from Cassandra + execute("DELETE FROM document WHERE parent_id = ?", doc_id) + + # Delete parent blob and metadata + parent = get_document(doc_id) + blob_store.delete(parent.object_id) + execute("DELETE FROM document WHERE id = ? AND user = ?", doc_id, user) +``` + +#### Mawazo Kuhusu Uhifadhi + +Matini yaliyotolewa yana nakala sawa: +Nakala asili ya PDF inahifadhiwa katika "Garage" +Nakala iliyotolewa kwa kila ukurasa pia inahifadhiwa katika "Garage" + +Hii inaruhusu: +**Kiolesura sawa cha "chunker"**: "Chunker" daima hupata data kwa kutumia kitambulisho +**Uendelezaji/jaribio tena**: Inaweza kuanza tena katika hatua ya "chunker" bila kuhariri tena PDF +**Urekebishaji**: Nakala iliyotolewa inaweza kuchunguzwa +**Tofauti ya majukumu**: Huduma ya kuchimbua PDF na "chunker" ni huduma tofauti + +Kwa PDF ya 500MB yenye kurasa 200, kwa wastani ya matini ya 5KB kwa kila ukurasa: +Uhifadhi wa PDF: 500MB +Uhifadhi wa matini iliyotolewa: ~1MB jumla +Gharama ya ziada: ndogo sana + +#### Matokeo ya Kuchimbua PDF + +Kichunguzi cha kuchimbua PDF, baada ya kuchakata hati: + +1. Hupata PDF kutoka kwa "librarian" hadi kwenye faili ya muda +2. Huchimbua matini ukurasa kwa ukurasa +3. Kwa kila ukurasa, huhifadhi matini iliyotolewa kama hati ndogo kupitia "librarian" +4. Hutuma kitambulisho cha hati ndogo kwa folyo ya "chunker" + +```python +async def extract_pdf(doc_id: str, librarian_client, output_queue): + """Extract PDF pages and store as child documents.""" + + with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp: + # Stream PDF to temp file + for chunk in librarian_client.stream_document(doc_id): + tmp.write(chunk) + tmp.flush() + + # Extract pages + reader = PdfReader(tmp.name) + for page_num, page in enumerate(reader.pages, start=1): + text = page.extract_text() + + # Store as child document + child_id = f"{doc_id}-page-{page_num}" + await librarian_client.add_child_document( + parent_id=doc_id, + document_id=child_id, + kind="text/plain", + title=f"Page {page_num}", + content=text.encode('utf-8') + ) + + # Send to chunker queue + await output_queue.send(child_id) +``` + +Kifaa cha kuainisha vitapokea kitambulisho hivi vya watoto na vitawatumia kwa njia ile ile +ambayo kingetumia hati ya maandishi iliyopakiwa na mtumiaji. + +### Sasizi za Mteja + +#### SDK ya Python + +SDK ya Python (`trustgraph-base/trustgraph/api/library.py`) inapaswa kushughulikia +vipakio vilivyogawanywa kwa njia ya moja kwa moja. Muundo wa umma haubadiliki: + +```python +# Existing interface - no change for users +library.add_document( + id="doc-123", + title="Large Report", + kind="application/pdf", + content=large_pdf_bytes, # Can be hundreds of MB + tags=["reports"] +) +``` + +Kwa ndani, SDK hugundua ukubwa wa hati na hubadilisha mkakati: + +```python +class Library: + CHUNKED_UPLOAD_THRESHOLD = 2 * 1024 * 1024 # 2MB + + def add_document(self, id, title, kind, content, tags=None, ...): + if len(content) < self.CHUNKED_UPLOAD_THRESHOLD: + # Small document: single operation (existing behavior) + return self._add_document_single(id, title, kind, content, tags) + else: + # Large document: chunked upload + return self._add_document_chunked(id, title, kind, content, tags) + + def _add_document_chunked(self, id, title, kind, content, tags): + # 1. begin-upload + session = self._begin_upload( + document_metadata={...}, + total_size=len(content), + chunk_size=5 * 1024 * 1024 + ) + + # 2. upload-chunk for each chunk + for i, chunk in enumerate(self._chunk_bytes(content, session.chunk_size)): + self._upload_chunk(session.upload_id, i, chunk) + + # 3. complete-upload + return self._complete_upload(session.upload_id) +``` + +**Arifa za maendeleo** (ongezeko la hiari): + +```python +def add_document(self, ..., on_progress=None): + """ + on_progress: Optional callback(bytes_sent, total_bytes) + """ +``` + +Hii inaruhusu programu za kiutengenezaji kuonyesha maendeleo ya kupakia bila kubadilisha API ya msingi. + +#### Zana za CLI (Command Line Interface) + +**`tg-add-library-document`** inaendelea kufanya kazi bila kubadilika: + +```bash +# Works transparently for any size - SDK handles chunking internally +tg-add-library-document --file large-report.pdf --title "Large Report" +``` + +Onyesho la maendeleo la hiari linaweza kuongezwa: + +```bash +tg-add-library-document --file large-report.pdf --title "Large Report" --progress +# Output: +# Uploading: 45% (225MB / 500MB) +``` + +**Vifaa vya zamani vimetoolewa:** + +`tg-load-pdf` - imepitwa na wakati, tumia `tg-add-library-document` +`tg-load-text` - imepitwa na wakati, tumia `tg-add-library-document` + +**Amri za utawala/uchunguzi** (hiari, kipaumbele cha chini): + +```bash +# List incomplete uploads (admin troubleshooting) +tg-add-library-document --list-pending + +# Resume specific upload (recovery scenario) +tg-add-library-document --resume upload-abc-123 --file large-report.pdf +``` + +Haya yanaweza kuwa maboresho kwenye amri iliyopo badala ya zana tofauti. + +#### Masuala ya Mabadiliko ya Vipimo vya API + +Vipimo vya OpenAPI (`specs/api/paths/librarian.yaml`) vinahitaji mabadiliko kwa: + +**Utendaji mpya:** + +`begin-upload` - Anzisha kipindi cha kupakia kwa sehemu +`upload-chunk` - Pakia sehemu moja +`complete-upload` - Kamilisha kupakia +`abort-upload` - Ghairi kupakia +`get-upload-status` - Angalia maendeleo ya kupakia +`list-uploads` - Orodha ya kupakia ambayo hayaja kamili kwa mtumiaji +`stream-document` - Kuchukua hati kwa njia ya utiririshaji +`add-child-document` - Hifadhi maandishi yaliyotolewa (ya ndani) +`list-children` - Orodha ya hati za chini (ya msimamizi) + +**Utendaji uliorekebishwa:** + +`list-documents` - Ongeza parameter `include-children` + +**Muundo mpya:** + +`ChunkedUploadBeginRequest` +`ChunkedUploadBeginResponse` +`ChunkedUploadChunkRequest` +`ChunkedUploadChunkResponse` +`UploadSession` +`UploadProgress` + +**Mabadiliko ya vipimo vya WebSocket** (`specs/websocket/`): + +Nakala utendaji wa REST kwa wateja wa WebSocket, na kuwezesha +maendeleo ya muda halisi wakati wa kupakia. + +#### Mambo ya Kuzingatia ya Uzoefu wa Mtumiaji + +Mabadiliko ya vipimo vya API yanawezesha maboresho ya upande wa mbele: + +**Kiolesura cha maendeleo ya kupakia:** +Pampu ya maendeleo ya kuonyesha sehemu zilizopakwa +Muda uliokadiri wa kupakia +Uwezo wa kusitisha/kuendeleza + +**Kupona kwa makosa:** +Chaguo la "Endeleza kupakia" kwa kupakia ambacho kimekatika +Orodha ya kupakia ambayo hayaja kamili wakati wa kuunganisha tena + +**Ushughulikiaji wa faili kubwa:** +Uchunguzi wa ukubwa wa faili kwenye upande wa mteja +Kupakia kwa sehemu kiotomatiki kwa faili kubwa +Maelezo wazi wakati wa kupakia kwa muda mrefu + +Maboresho haya ya uzoefu wa mtumiaji yanahitaji kazi ya upande wa mbele inayong'wa na vipimo vya API vilivyoboreshwa. diff --git a/translate_docs.py b/translate_docs.py index b814e010..6a41de96 100755 --- a/translate_docs.py +++ b/translate_docs.py @@ -4,6 +4,7 @@ import json import math import os import re +import subprocess import sys from dataclasses import dataclass from pathlib import Path @@ -18,7 +19,7 @@ import requests DEFAULT_OLLAMA_URL = os.getenv("OLLAMA_URL", "http://localhost:11434/api/generate") DEFAULT_OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "translategemma:12b") -DEFAULT_DOCS_DIR = os.getenv("DOCS_DIR", "docs/tech-specs") +DEFAULT_DOCS_DIR = os.getenv("DOCS_DIR", "docs") # With chunked translation, a smaller ctx is usually faster and more reliable. DEFAULT_NUM_CTX = int(os.getenv("OLLAMA_NUM_CTX", "4096")) @@ -754,6 +755,31 @@ def looks_incomplete(existing_translation: str, source: str) -> bool: # ---------------------------- +def get_git_mtime(filepath: str) -> int: + """Return the modification time of a file based on git history. + If the file has local uncommitted changes, returns its filesystem mtime. + If git is unavailable, falls back to filesystem mtime. + """ + try: + # Check for uncommitted changes first + status = subprocess.check_output(["git", "status", "--porcelain", filepath], text=True).strip() + if status: + return int(os.path.getmtime(filepath)) + + # Get the timestamp of the last commit that modified this file + out = subprocess.check_output(["git", "log", "-1", "--format=%ct", filepath], text=True).strip() + if out: + return int(out) + except Exception: + pass + + # Fallback to local filesystem mtime + try: + return int(os.path.getmtime(filepath)) + except OSError: + return 0 + + def _parse_langs(arg: Optional[str]) -> Dict[str, str]: if not arg: return dict(LANGUAGES) @@ -841,10 +867,21 @@ def main() -> None: if os.path.exists(out_filepath) and os.path.getsize(out_filepath) > 0 and not args.force: with open(out_filepath, "r", encoding="utf-8") as existing_f: existing = existing_f.read() - if not looks_incomplete(existing, content): - print(f" [-] Skipping {lang_name} ({out_filename}) - already exists.") + + source_mtime = get_git_mtime(filepath) + dest_mtime = get_git_mtime(out_filepath) + + is_outdated = source_mtime > dest_mtime + is_inc = looks_incomplete(existing, content) + + if not is_outdated and not is_inc: + print(f" [-] Skipping {lang_name} ({out_filename}) - already exists and up to date.") continue - print(f" [!] Existing {lang_name} looks incomplete; re-translating...") + + if is_outdated: + print(f" [!] Source file is newer than existing {lang_name} translation; re-translating...") + elif is_inc: + print(f" [!] Existing {lang_name} looks incomplete; re-translating...") print(f" [+] Translating to {lang_name}...") translated = translate_markdown_document( diff --git a/updates.md b/updates.md new file mode 100644 index 00000000..451f323c --- /dev/null +++ b/updates.md @@ -0,0 +1,21 @@ +# TrustGraph i18n & Documentation Translation Updates + +The TrustGraph project has recently introduced comprehensive internationalization (i18n) support alongside powerful automated documentation translation capabilities. This update brings native language localization directly into the TrustGraph Command Line Interface (CLI) and includes an intelligent script designed to keep multi-language repository documentation fully synchronized with upstream changes. + +## How the Translation & i18n Works + +* **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 LLM Translation**: The repository includes `translate_docs.py`, a script that leverages local Ollama models (such as `translategemma:12b`) to autonomously translate Markdown documentation into several target languages, including Spanish, Swahili, Portuguese, Turkish, Hindi, Hebrew, Arabic, Simplified Chinese, and Russian. +* **Intelligent Git-Aware Syncing**: The doc translator uses `git status` and `git log` modification timestamps to detect out-of-sync files. If a source file (like a core English `.md` file) receives newer commits or local edits, the script automatically flags the outdated translations and re-translates them to match the latest base version. +* **Safe Markdown Parsing**: To prevent the LLM from destroying technical formatting, the translation script chunks the text at safe boundaries, protects code fences, and uses placeholder tokens for inline code and URLs to ensure precision. + +## Updated Documents + +Because of the Git-aware translation capabilities, several core documents in the `docs/` folder have been successfully updated to parity across all supported languages, including: +* `python-api.md` +* API Gateway changelogs +* CLI changelogs +* Contributor License Agreements (CLAs) +* Assorted technical READMEs + +*Note: The `translate_docs.py` translation engine will be moved out of the core TrustGraph repository into its own dedicated standalone repository in the near future.* \ No newline at end of file